blume 2.0.3 → 2.1.1
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 +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -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 +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- 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/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -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/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- 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/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -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 +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -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 +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -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 +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- 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 +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- 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 +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- 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/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 +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- 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 +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- 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/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- 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/head-scripts.ts +6 -1
- 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/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- 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/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- 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 +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- 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 +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import type { JsonValue } from "../core/adapter.ts";
|
|
4
|
+
import { isJsonObject } from "../core/sources/json.ts";
|
|
5
|
+
import { RATE_LIMIT_BINDING } from "./cloudflare.ts";
|
|
6
|
+
import type { CloudflareRateLimitAdapter } from "./cloudflare.ts";
|
|
7
|
+
|
|
8
|
+
/** The Workers rate limiting binding, as the Worker's config declares it. */
|
|
9
|
+
export interface RateLimitBindingConfig {
|
|
10
|
+
name: string;
|
|
11
|
+
namespace_id: string;
|
|
12
|
+
simple: { limit: number; period: 10 | 60 };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A namespace id for a Worker that sets none: a positive integer derived from
|
|
17
|
+
* its name, so two Blume sites on one account don't share one.
|
|
18
|
+
*/
|
|
19
|
+
export const rateLimitNamespace = (workerName: string): string => {
|
|
20
|
+
const digest = createHash("sha256").update(workerName).digest("hex");
|
|
21
|
+
return String((Number.parseInt(digest.slice(0, 8), 16) % 2_000_000_000) + 1);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const isText = <Value>(value: Value): value is Value & string =>
|
|
25
|
+
typeof value === "string";
|
|
26
|
+
|
|
27
|
+
/** The binding `cloudflare()` asks for, on the Worker named `workerName`. */
|
|
28
|
+
export const rateLimitBinding = (
|
|
29
|
+
adapter: CloudflareRateLimitAdapter,
|
|
30
|
+
workerName: string
|
|
31
|
+
): RateLimitBindingConfig => ({
|
|
32
|
+
name: RATE_LIMIT_BINDING,
|
|
33
|
+
namespace_id: adapter.options.namespaceId ?? rateLimitNamespace(workerName),
|
|
34
|
+
simple: {
|
|
35
|
+
limit: adapter.options.requests ?? 10,
|
|
36
|
+
period: adapter.options.window ?? 60,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The built Worker's config (`dist/server/wrangler.json`) with Blume's rate
|
|
42
|
+
* limiting binding in `ratelimits`, replacing an earlier one of the same name
|
|
43
|
+
* and keeping any others. `null` when the config isn't a JSON object.
|
|
44
|
+
*/
|
|
45
|
+
export const withRateLimitBinding = (
|
|
46
|
+
wranglerText: string,
|
|
47
|
+
adapter: CloudflareRateLimitAdapter
|
|
48
|
+
): string | null => {
|
|
49
|
+
let config: JsonValue;
|
|
50
|
+
try {
|
|
51
|
+
config = JSON.parse(wranglerText);
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (!isJsonObject(config) || Array.isArray(config)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const { name, ratelimits } = config;
|
|
59
|
+
const others = Array.isArray(ratelimits)
|
|
60
|
+
? ratelimits.filter(
|
|
61
|
+
(entry) => !(isJsonObject(entry) && entry.name === RATE_LIMIT_BINDING)
|
|
62
|
+
)
|
|
63
|
+
: [];
|
|
64
|
+
const binding = rateLimitBinding(adapter, isText(name) ? name : "");
|
|
65
|
+
config.ratelimits = [
|
|
66
|
+
...others,
|
|
67
|
+
{ ...binding, simple: { ...binding.simple } },
|
|
68
|
+
];
|
|
69
|
+
return JSON.stringify(config);
|
|
70
|
+
};
|
|
@@ -16,9 +16,9 @@ import type { PlaygroundOptions, ReferenceSourceOptions } from "./options.ts";
|
|
|
16
16
|
export interface AsyncApiOptions {
|
|
17
17
|
/**
|
|
18
18
|
* Code-sample tools shown per operation (Blume renderer). Defaults to every
|
|
19
|
-
* tool appropriate to the operation's protocol binding.
|
|
19
|
+
* tool appropriate to the operation's protocol binding; `false` shows none.
|
|
20
20
|
*/
|
|
21
|
-
codeSamples?: string[];
|
|
21
|
+
codeSamples?: string[] | false;
|
|
22
22
|
/** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */
|
|
23
23
|
expandSchemas?: boolean;
|
|
24
24
|
/**
|
package/src/reference/graphql.ts
CHANGED
|
@@ -3,18 +3,33 @@ import { z } from "zod";
|
|
|
3
3
|
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
4
4
|
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
5
|
import {
|
|
6
|
+
graphqlAuthSchema,
|
|
6
7
|
graphqlSourceSchema,
|
|
7
8
|
liftSpec,
|
|
8
9
|
hasSources,
|
|
9
10
|
missingSourcesIssue,
|
|
10
11
|
sharedOptions,
|
|
11
12
|
} from "./options.ts";
|
|
12
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
GraphqlAuthOptions,
|
|
15
|
+
GraphqlSourceOptions,
|
|
16
|
+
PlaygroundOptions,
|
|
17
|
+
} from "./options.ts";
|
|
13
18
|
|
|
14
19
|
/** Options for {@link graphql}. */
|
|
15
20
|
export interface GraphqlOptions {
|
|
16
|
-
/**
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* How the endpoint authenticates, like the site's `api.auth`: `bearer`,
|
|
23
|
+
* `basic`, or `key` (sent in the `name` header, `x-api-key` by default).
|
|
24
|
+
* The Try it panel gets a field for the credential and the code samples
|
|
25
|
+
* send a placeholder. Applies to every source; a per-source `auth` wins.
|
|
26
|
+
*/
|
|
27
|
+
auth?: GraphqlAuthOptions;
|
|
28
|
+
/**
|
|
29
|
+
* Code-sample languages shown per operation, in order. Defaults to
|
|
30
|
+
* `["curl", "js", "python"]`; `false` shows none.
|
|
31
|
+
*/
|
|
32
|
+
codeSamples?: string[] | false;
|
|
18
33
|
/**
|
|
19
34
|
* URL of the live GraphQL endpoint the playground and code samples target —
|
|
20
35
|
* a schema, unlike an OpenAPI document, names no server. Applies to every
|
|
@@ -49,6 +64,8 @@ export const graphqlOptionsSchema = z
|
|
|
49
64
|
codeSamples: ["curl", "js", "python"],
|
|
50
65
|
route: "/graphql",
|
|
51
66
|
}),
|
|
67
|
+
/** Default endpoint auth for every source (per-source `auth` wins). */
|
|
68
|
+
auth: graphqlAuthSchema.optional(),
|
|
52
69
|
/** Default live endpoint URL for every source (per-source `endpoint` wins). */
|
|
53
70
|
endpoint: z.string().optional(),
|
|
54
71
|
/** One or more schemas; each renders on its own route by default. */
|
package/src/reference/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type { GraphqlAdapter, GraphqlOptions } from "./graphql.ts";
|
|
|
27
27
|
export { openapi } from "./openapi.ts";
|
|
28
28
|
export type { OpenApiAdapter, OpenApiOptions } from "./openapi.ts";
|
|
29
29
|
export type {
|
|
30
|
+
GraphqlAuthOptions,
|
|
30
31
|
GraphqlSourceOptions,
|
|
31
32
|
PlaygroundOptions,
|
|
32
33
|
ReferenceSourceOptions,
|
package/src/reference/openapi.ts
CHANGED
|
@@ -4,18 +4,24 @@ import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
|
4
4
|
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
5
|
import {
|
|
6
6
|
liftSpec,
|
|
7
|
-
|
|
7
|
+
openapiSourceSchema,
|
|
8
|
+
overlaysHaveSpec,
|
|
9
|
+
overlaysNeedSpecIssue,
|
|
8
10
|
hasSources,
|
|
9
11
|
missingSourcesIssue,
|
|
10
12
|
rendererRemovedHint,
|
|
11
13
|
sharedOptions,
|
|
12
14
|
} from "./options.ts";
|
|
13
|
-
import type {
|
|
15
|
+
import type { OpenApiSourceOptions, PlaygroundOptions } from "./options.ts";
|
|
14
16
|
|
|
15
17
|
/** Options for {@link openapi}. */
|
|
16
18
|
export interface OpenApiOptions {
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Code-sample languages generated per operation (Blume renderer), in
|
|
21
|
+
* order. Defaults to `["curl", "js", "python"]`; `false` (or an empty list)
|
|
22
|
+
* generates none, so only the spec's own `x-codeSamples` show.
|
|
23
|
+
*/
|
|
24
|
+
codeSamples?: string[] | false;
|
|
19
25
|
/** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */
|
|
20
26
|
expandSchemas?: boolean;
|
|
21
27
|
/**
|
|
@@ -26,10 +32,15 @@ export interface OpenApiOptions {
|
|
|
26
32
|
* `vercel()` in `deployment`).
|
|
27
33
|
*/
|
|
28
34
|
playground?: PlaygroundOptions;
|
|
35
|
+
/**
|
|
36
|
+
* OpenAPI Overlay documents for `spec`, applied in order before it renders.
|
|
37
|
+
* With `sources`, each source takes its own `overlays`.
|
|
38
|
+
*/
|
|
39
|
+
overlays?: string[];
|
|
29
40
|
/** Where the reference mounts. Defaults to `/reference`. */
|
|
30
41
|
route?: string;
|
|
31
42
|
/** One or more specs; each renders on its own route by default. */
|
|
32
|
-
sources?:
|
|
43
|
+
sources?: OpenApiSourceOptions[];
|
|
33
44
|
/** Shorthand for a single source: `sources: [{ spec }]`. */
|
|
34
45
|
spec?: string;
|
|
35
46
|
}
|
|
@@ -43,12 +54,15 @@ export const openapiOptionsSchema = z
|
|
|
43
54
|
}),
|
|
44
55
|
/** Start nested schema rows expanded rather than collapsed (Blume renderer). */
|
|
45
56
|
expandSchemas: z.boolean().default(false),
|
|
57
|
+
/** Overlays for the `spec` shorthand. */
|
|
58
|
+
overlays: z.array(z.string()).optional(),
|
|
46
59
|
/** One or more specs; each renders on its own route by default. */
|
|
47
|
-
sources: z.array(
|
|
60
|
+
sources: z.array(openapiSourceSchema).default([]),
|
|
48
61
|
},
|
|
49
62
|
rendererRemovedHint
|
|
50
63
|
)
|
|
51
|
-
.
|
|
64
|
+
.refine(overlaysHaveSpec, overlaysNeedSpecIssue)
|
|
65
|
+
.transform(liftSpec(openapiSourceSchema))
|
|
52
66
|
.refine(hasSources, missingSourcesIssue("openapi"));
|
|
53
67
|
|
|
54
68
|
/** `openapi()` options with every default applied and `spec` folded into `sources`. */
|
package/src/reference/options.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
import { AUTH_METHODS } from "../components/content/api-page.ts";
|
|
4
|
+
import type { AuthMethod } from "../components/content/api-page.ts";
|
|
3
5
|
import { unrecognizedKeysMessage } from "../core/unrecognized-keys.ts";
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -65,18 +67,78 @@ export interface ReferenceSourceOptions {
|
|
|
65
67
|
/** A spec source with every default applied. */
|
|
66
68
|
export type ResolvedReferenceSource = z.output<typeof referenceSourceSchema>;
|
|
67
69
|
|
|
70
|
+
/**
|
|
71
|
+
* [OpenAPI Overlay](https://spec.openapis.org/overlay/latest.html) documents
|
|
72
|
+
* (local paths or `http(s)` URLs) applied in order to an OpenAPI spec before
|
|
73
|
+
* it renders: changes to a spec you don't edit by hand.
|
|
74
|
+
*/
|
|
75
|
+
export const overlaysSchema = z.array(z.string()).default([]);
|
|
76
|
+
|
|
77
|
+
/** Whether adapter-level `overlays` has the `spec` it belongs to. */
|
|
78
|
+
export const overlaysHaveSpec = (options: {
|
|
79
|
+
overlays?: string[];
|
|
80
|
+
spec?: string;
|
|
81
|
+
}): boolean => !options.overlays || options.spec !== undefined;
|
|
82
|
+
|
|
83
|
+
/** The refinement issue for `overlays` set beside `sources` instead of `spec`. */
|
|
84
|
+
export const overlaysNeedSpecIssue = {
|
|
85
|
+
message:
|
|
86
|
+
"`overlays` belongs to the `spec` shorthand; with `sources`, give each source its own `overlays`.",
|
|
87
|
+
path: ["overlays"],
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/** An OpenAPI spec source: the shared shape plus its `overlays`. */
|
|
91
|
+
export const openapiSourceSchema = referenceSourceSchema.extend({
|
|
92
|
+
overlays: overlaysSchema,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/** One OpenAPI spec source, as `openapi()` accepts it. */
|
|
96
|
+
export interface OpenApiSourceOptions extends ReferenceSourceOptions {
|
|
97
|
+
/**
|
|
98
|
+
* OpenAPI Overlay documents (local paths or `http(s)` URLs) applied in
|
|
99
|
+
* order to the spec before it renders.
|
|
100
|
+
*/
|
|
101
|
+
overlays?: string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* How a GraphQL endpoint authenticates, in the shape the site's `api.auth`
|
|
106
|
+
* takes for hand-written endpoints: `bearer`, `basic`, or `key` (sent in the
|
|
107
|
+
* `name` header, `x-api-key` by default). A schema, unlike an OpenAPI
|
|
108
|
+
* document, declares no security schemes, so this is what gives the Try it
|
|
109
|
+
* panel its credential field.
|
|
110
|
+
*/
|
|
111
|
+
export const graphqlAuthSchema = z.strictObject({
|
|
112
|
+
method: z.enum(AUTH_METHODS),
|
|
113
|
+
/** The header an API key goes in. Defaults to `x-api-key`. */
|
|
114
|
+
name: z.string().optional(),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/** The `auth` option of `graphql()` and its sources. */
|
|
118
|
+
export interface GraphqlAuthOptions {
|
|
119
|
+
/** `bearer`, `basic`, `key`, or `none`. */
|
|
120
|
+
method: AuthMethod;
|
|
121
|
+
/** The header an API key goes in. Defaults to `x-api-key`. */
|
|
122
|
+
name?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
68
125
|
/**
|
|
69
126
|
* A single GraphQL schema: the shared source shape plus `endpoint`, the live
|
|
70
127
|
* GraphQL API URL the playground and code samples target (a schema, unlike an
|
|
71
|
-
* OpenAPI document, names no server)
|
|
128
|
+
* OpenAPI document, names no server), and `auth`, how that endpoint
|
|
129
|
+
* authenticates.
|
|
72
130
|
*/
|
|
73
131
|
export const graphqlSourceSchema = referenceSourceSchema.extend({
|
|
132
|
+
/** How the endpoint authenticates (playground + code samples). */
|
|
133
|
+
auth: graphqlAuthSchema.optional(),
|
|
74
134
|
/** URL of the live GraphQL endpoint (playground + code samples). */
|
|
75
135
|
endpoint: z.string().optional(),
|
|
76
136
|
});
|
|
77
137
|
|
|
78
138
|
/** One schema source, as `graphql()` accepts it. */
|
|
79
139
|
export interface GraphqlSourceOptions extends ReferenceSourceOptions {
|
|
140
|
+
/** How the endpoint authenticates; wins over the adapter's `auth`. */
|
|
141
|
+
auth?: GraphqlAuthOptions;
|
|
80
142
|
/** URL of the live GraphQL endpoint (playground + code samples); wins over the adapter's `endpoint`. */
|
|
81
143
|
endpoint?: string;
|
|
82
144
|
}
|
|
@@ -157,8 +219,13 @@ export const sharedOptions = (defaults: {
|
|
|
157
219
|
codeSamples: string[];
|
|
158
220
|
route: string;
|
|
159
221
|
}) => ({
|
|
160
|
-
/**
|
|
161
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Code-sample languages/tools shown per operation (Blume renderer), or
|
|
224
|
+
* `false` for none: only the spec's own `x-codeSamples` then.
|
|
225
|
+
*/
|
|
226
|
+
codeSamples: z
|
|
227
|
+
.union([z.literal(false), z.array(z.string())])
|
|
228
|
+
.default(defaults.codeSamples),
|
|
162
229
|
/** The "Try it" panel; see {@link playgroundSchema}. */
|
|
163
230
|
playground: playgroundSchema,
|
|
164
231
|
/** Where the reference mounts. */
|
|
@@ -168,8 +235,9 @@ export const sharedOptions = (defaults: {
|
|
|
168
235
|
});
|
|
169
236
|
|
|
170
237
|
/**
|
|
171
|
-
* Resolve the `spec` shorthand
|
|
172
|
-
*
|
|
238
|
+
* Resolve the `spec` shorthand (and, on OpenAPI kinds, the `overlays` beside
|
|
239
|
+
* it) into `sources` so downstream code reads one field: the shorthand becomes
|
|
240
|
+
* the first source (with the source defaults
|
|
173
241
|
* applied through the source schema itself, so the two can never drift) and
|
|
174
242
|
* the `spec` key is dropped. An adapter with neither renders nothing, which
|
|
175
243
|
* is a config mistake rather than a choice — `refine` it away with
|
|
@@ -179,15 +247,19 @@ export const liftSpec =
|
|
|
179
247
|
<Source extends { spec: string }>(
|
|
180
248
|
sourceSchema: z.ZodType<Source, { spec: string }>
|
|
181
249
|
) =>
|
|
182
|
-
<Options extends { sources: Source[]; spec?: string }>({
|
|
250
|
+
<Options extends { sources: Source[]; spec?: string; overlays?: string[] }>({
|
|
251
|
+
overlays,
|
|
183
252
|
spec,
|
|
184
253
|
...options
|
|
185
|
-
}: Options): Omit<Options, "spec"> => ({
|
|
254
|
+
}: Options): Omit<Options, "spec" | "overlays"> => ({
|
|
186
255
|
...options,
|
|
187
256
|
sources:
|
|
188
257
|
spec === undefined
|
|
189
258
|
? options.sources
|
|
190
|
-
: [
|
|
259
|
+
: [
|
|
260
|
+
sourceSchema.parse(overlays ? { overlays, spec } : { spec }),
|
|
261
|
+
...options.sources,
|
|
262
|
+
],
|
|
191
263
|
});
|
|
192
264
|
|
|
193
265
|
/** Whether an adapter has anything to render; pairs with {@link missingSourcesIssue}. */
|
package/src/reference/scalar.ts
CHANGED
|
@@ -2,7 +2,13 @@ import { z } from "zod";
|
|
|
2
2
|
|
|
3
3
|
import type { AdapterDescriptor, JsonValue } from "../core/adapter.ts";
|
|
4
4
|
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
hasSources,
|
|
7
|
+
missingSourcesIssue,
|
|
8
|
+
overlaysHaveSpec,
|
|
9
|
+
overlaysNeedSpecIssue,
|
|
10
|
+
overlaysSchema,
|
|
11
|
+
} from "./options.ts";
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* What the generated Scalar page imports. Declared on every `scalar()`
|
|
@@ -22,6 +28,11 @@ export const scalarSourceSchema = z.strictObject({
|
|
|
22
28
|
label: z.string().optional(),
|
|
23
29
|
/** Emit noindex metadata and omit the page from the sitemap. */
|
|
24
30
|
noindex: z.boolean().default(false),
|
|
31
|
+
/**
|
|
32
|
+
* OpenAPI Overlay documents applied in order to the document before it's
|
|
33
|
+
* embedded (inlined, so a remote spec with overlays is fetched at build).
|
|
34
|
+
*/
|
|
35
|
+
overlays: overlaysSchema,
|
|
25
36
|
/** Per-source route; defaults to the adapter's `route` (or a derived path). */
|
|
26
37
|
route: z.string().optional(),
|
|
27
38
|
/** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */
|
|
@@ -34,6 +45,8 @@ export interface ScalarSourceOptions {
|
|
|
34
45
|
label?: string;
|
|
35
46
|
/** Emit noindex metadata and omit the page from the sitemap. Defaults to `false`. */
|
|
36
47
|
noindex?: boolean;
|
|
48
|
+
/** OpenAPI Overlay documents applied in order to the document before it's embedded. */
|
|
49
|
+
overlays?: string[];
|
|
37
50
|
/** Per-source route; defaults to the adapter's `route` (or a derived path). */
|
|
38
51
|
route?: string;
|
|
39
52
|
/** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */
|
|
@@ -55,6 +68,8 @@ export type ResolvedScalarOptions = {
|
|
|
55
68
|
|
|
56
69
|
/** The options {@link scalar} maps itself. */
|
|
57
70
|
export interface ScalarNamedOptions {
|
|
71
|
+
/** OpenAPI Overlay documents for `spec`; with `sources`, each takes its own. */
|
|
72
|
+
overlays?: string[];
|
|
58
73
|
/** Where the reference mounts. Defaults to `/reference`. */
|
|
59
74
|
route?: string;
|
|
60
75
|
/** One or more documents; each renders on its own route by default. */
|
|
@@ -87,6 +102,8 @@ export type ScalarOptions = ScalarNamedOptions & {
|
|
|
87
102
|
*/
|
|
88
103
|
export const scalarOptionsSchema = z
|
|
89
104
|
.object({
|
|
105
|
+
/** Overlays for the `spec` shorthand. */
|
|
106
|
+
overlays: z.array(z.string()).optional(),
|
|
90
107
|
/** Where the reference mounts. */
|
|
91
108
|
route: z.string().default("/reference"),
|
|
92
109
|
/** One or more documents; each renders on its own route by default. */
|
|
@@ -97,13 +114,21 @@ export const scalarOptionsSchema = z
|
|
|
97
114
|
theme: z.string().optional(),
|
|
98
115
|
})
|
|
99
116
|
.catchall(z.json())
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
sources:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
.refine(overlaysHaveSpec, overlaysNeedSpecIssue)
|
|
118
|
+
.transform(
|
|
119
|
+
({ overlays, spec, sources, ...options }): ResolvedScalarOptions => ({
|
|
120
|
+
...options,
|
|
121
|
+
sources:
|
|
122
|
+
spec === undefined
|
|
123
|
+
? sources
|
|
124
|
+
: [
|
|
125
|
+
scalarSourceSchema.parse(
|
|
126
|
+
overlays ? { overlays, spec } : { spec }
|
|
127
|
+
),
|
|
128
|
+
...sources,
|
|
129
|
+
],
|
|
130
|
+
})
|
|
131
|
+
)
|
|
107
132
|
.refine(hasSources, missingSourcesIssue("scalar"));
|
|
108
133
|
|
|
109
134
|
export type ScalarAdapter = AdapterDescriptor<"scalar", ScalarOptions>;
|
package/src/registry/eject.ts
CHANGED
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
rssEndpointTemplate,
|
|
64
64
|
runtimeDependencies,
|
|
65
65
|
runtimeTsconfigTemplate,
|
|
66
|
+
consentClientTemplate,
|
|
66
67
|
searchClientTemplate,
|
|
67
68
|
searchEndpointTemplate,
|
|
68
69
|
staticJsonEndpointTemplate,
|
|
@@ -87,6 +88,7 @@ import {
|
|
|
87
88
|
import { buildReferenceFiles } from "../openapi/scalar.ts";
|
|
88
89
|
import { isOpenApiSource } from "../openapi/source.ts";
|
|
89
90
|
import { buildSearchDocuments } from "../search/documents.ts";
|
|
91
|
+
import { sourcePages } from "../search/source-pages.ts";
|
|
90
92
|
import {
|
|
91
93
|
examplesEntryTemplate,
|
|
92
94
|
tailwindEntryTemplate,
|
|
@@ -162,9 +164,12 @@ const askFiles = async (
|
|
|
162
164
|
const files = [
|
|
163
165
|
{
|
|
164
166
|
content: askEndpointTemplate(backend, {
|
|
167
|
+
captcha: assistant.captcha,
|
|
165
168
|
cors: assistant.cors,
|
|
166
169
|
instructions: assistant.instructions,
|
|
170
|
+
rateLimit: project.config.rateLimit,
|
|
167
171
|
retrieval: assistant.retrieval,
|
|
172
|
+
tools: assistant.tools ?? backend.toolsByDefault,
|
|
168
173
|
}),
|
|
169
174
|
path: join(srcDir, "pages", "api", "ask.ts"),
|
|
170
175
|
},
|
|
@@ -243,7 +248,10 @@ const playgroundProxyFiles = (
|
|
|
243
248
|
needsPlaygroundProxy(config)
|
|
244
249
|
? [
|
|
245
250
|
{
|
|
246
|
-
content: playgroundProxyTemplate(
|
|
251
|
+
content: playgroundProxyTemplate(
|
|
252
|
+
specOrigins(openApiData),
|
|
253
|
+
config.rateLimit
|
|
254
|
+
),
|
|
247
255
|
path: join(srcDir, PLAYGROUND_PROXY_ENTRY),
|
|
248
256
|
},
|
|
249
257
|
]
|
|
@@ -667,6 +675,7 @@ export const eject = async (
|
|
|
667
675
|
content: astroConfigTemplate({
|
|
668
676
|
askPath: "./src/generated/Ask.astro",
|
|
669
677
|
config,
|
|
678
|
+
consentClientPath: "./src/generated/consent-client.ts",
|
|
670
679
|
contentRoot: relContext.contentRoot,
|
|
671
680
|
contentRoutes: project.manifest.routes.map((route) => route.path),
|
|
672
681
|
context: relContext,
|
|
@@ -747,7 +756,7 @@ export const eject = async (
|
|
|
747
756
|
// the package is hoisted out of the project's own node_modules.
|
|
748
757
|
sources: [
|
|
749
758
|
blumeSourceGlob(root, genDir),
|
|
750
|
-
"../../**/*.{astro,mdx,ts,tsx}",
|
|
759
|
+
"../../**/*.{astro,jsx,mdx,ts,tsx}",
|
|
751
760
|
],
|
|
752
761
|
twoslashCss: twoslashCss(),
|
|
753
762
|
userTheme,
|
|
@@ -869,8 +878,9 @@ export const eject = async (
|
|
|
869
878
|
);
|
|
870
879
|
}
|
|
871
880
|
|
|
872
|
-
// The client-feature loaders behind the `blume:features` alias,
|
|
873
|
-
// provider-specific client loader behind `blume:search-client
|
|
881
|
+
// The client-feature loaders behind the `blume:features` alias, the
|
|
882
|
+
// provider-specific client loader behind `blume:search-client`, and the
|
|
883
|
+
// consent adapter's browser module behind `blume:consent-client`.
|
|
874
884
|
files.push(
|
|
875
885
|
{
|
|
876
886
|
content: featuresTemplate(features),
|
|
@@ -879,6 +889,10 @@ export const eject = async (
|
|
|
879
889
|
{
|
|
880
890
|
content: searchClientTemplate(config),
|
|
881
891
|
path: join(genDir, "search-client.ts"),
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
content: consentClientTemplate(config.consent),
|
|
895
|
+
path: join(genDir, "consent-client.ts"),
|
|
882
896
|
}
|
|
883
897
|
);
|
|
884
898
|
|
|
@@ -899,7 +913,11 @@ export const eject = async (
|
|
|
899
913
|
|
|
900
914
|
if (searchAdapter.kind === "mixedbread") {
|
|
901
915
|
files.push({
|
|
902
|
-
content: mixedbreadSearchEndpointTemplate(
|
|
916
|
+
content: mixedbreadSearchEndpointTemplate(
|
|
917
|
+
searchAdapter.options,
|
|
918
|
+
sourcePages(project),
|
|
919
|
+
config.rateLimit
|
|
920
|
+
),
|
|
903
921
|
path: join(srcDir, "pages", "api", "search.ts"),
|
|
904
922
|
});
|
|
905
923
|
}
|
package/src/registry/registry.ts
CHANGED
|
@@ -262,6 +262,13 @@ export const registry: RegistryItem[] = [
|
|
|
262
262
|
name: "feedback",
|
|
263
263
|
slot: "Feedback",
|
|
264
264
|
}),
|
|
265
|
+
layoutComponent({
|
|
266
|
+
description:
|
|
267
|
+
"The site footer: a row of links, social icons, the theme toggle, and the Cookie settings link.",
|
|
268
|
+
file: "SiteFooter.astro",
|
|
269
|
+
name: "footer",
|
|
270
|
+
slot: "Footer",
|
|
271
|
+
}),
|
|
265
272
|
...CONTENT_COMPONENTS.map(contentComponent),
|
|
266
273
|
];
|
|
267
274
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SearchAdapterKind } from "./registry.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether each adapter's client can limit results to one language. The
|
|
5
|
+
* source-built indexes (Orama, FlexSearch) store every document's `locale`,
|
|
6
|
+
* the Algolia, Orama Cloud, and Typesense syncs upload it for their clients
|
|
7
|
+
* to filter on, and Pagefind keeps an index per language, merging the others
|
|
8
|
+
* in to search them all. The Mixedbread endpoint takes no filter, so it
|
|
9
|
+
* always searches every language. Keyed by every kind so a new adapter has
|
|
10
|
+
* to decide.
|
|
11
|
+
*/
|
|
12
|
+
const SCOPES_LOCALES = {
|
|
13
|
+
algolia: true,
|
|
14
|
+
flexsearch: true,
|
|
15
|
+
mixedbread: false,
|
|
16
|
+
none: false,
|
|
17
|
+
orama: true,
|
|
18
|
+
"orama-cloud": true,
|
|
19
|
+
pagefind: true,
|
|
20
|
+
typesense: true,
|
|
21
|
+
} satisfies Record<SearchAdapterKind, boolean>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether the configured search adapter scopes results to the page's
|
|
25
|
+
* language. The search dialog offers its "All languages" toggle only when it
|
|
26
|
+
* does: on the others the toggle would change nothing, and every query
|
|
27
|
+
* already spans all languages.
|
|
28
|
+
*/
|
|
29
|
+
export const scopesLocales = (kind: SearchAdapterKind): boolean =>
|
|
30
|
+
SCOPES_LOCALES[kind];
|
|
@@ -6,14 +6,22 @@ import type { SearchAdapter } from "./types.ts";
|
|
|
6
6
|
/**
|
|
7
7
|
* Connection details for a self-hosted or cloud Typesense node. The browser
|
|
8
8
|
* queries the collection with the search-only `apiKey`; the build-time sync
|
|
9
|
-
*
|
|
10
|
-
* the config.
|
|
9
|
+
* rebuilds it with `TYPESENSE_ADMIN_API_KEY`, which never enters the config.
|
|
11
10
|
*/
|
|
12
11
|
export interface TypesenseNamedOptions {
|
|
13
12
|
/** The search-only API key (public — it ships to the browser). */
|
|
14
13
|
apiKey: string;
|
|
14
|
+
/** The alias the sync points at each new collection, and searches read. */
|
|
15
15
|
collection: string;
|
|
16
16
|
host: string;
|
|
17
|
+
/**
|
|
18
|
+
* The language Typesense tokenizes the text fields for, as a two-letter
|
|
19
|
+
* code (`ja`, `zh`, `ko`, `th`, …). Typesense's default tokenizer splits on
|
|
20
|
+
* spaces, so text in a script written without them — Chinese, Japanese,
|
|
21
|
+
* Thai — only matches from the start of a run. Omitted, the fields keep
|
|
22
|
+
* that default.
|
|
23
|
+
*/
|
|
24
|
+
locale?: string;
|
|
17
25
|
/** Defaults to 443. */
|
|
18
26
|
port?: number;
|
|
19
27
|
/** Defaults to `https`. */
|
|
@@ -39,14 +47,16 @@ export const typesenseOptionsSchema = z
|
|
|
39
47
|
apiKey: z.string(),
|
|
40
48
|
collection: z.string(),
|
|
41
49
|
host: z.string(),
|
|
50
|
+
locale: z.string().optional(),
|
|
42
51
|
port: z.number().int().positive().optional(),
|
|
43
52
|
protocol: z.enum(["http", "https"]).optional(),
|
|
44
53
|
})
|
|
45
54
|
.catchall(z.json());
|
|
46
55
|
|
|
47
56
|
/**
|
|
48
|
-
* Hosted search on Typesense. Each `blume build`
|
|
49
|
-
* collection
|
|
57
|
+
* Hosted search on Typesense. Each `blume build` imports into a new
|
|
58
|
+
* collection and swaps the `collection` alias onto it, so deleted or renamed
|
|
59
|
+
* pages don't linger as stale hits and searches never read a partial index.
|
|
50
60
|
*/
|
|
51
61
|
export const typesense = (options: TypesenseOptions): TypesenseAdapter => ({
|
|
52
62
|
kind: "typesense",
|
package/src/search/build.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { close, createIndex } from "pagefind";
|
|
4
4
|
import { dirname, join } from "pathe";
|
|
5
5
|
|
|
6
|
+
/** The part of `pagefind-entry.json` that counts the index's pages. */
|
|
7
|
+
interface PagefindEntry {
|
|
8
|
+
languages: Record<string, { page_count: number }>;
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
/**
|
|
7
12
|
* Build a local Pagefind search index over the built site. Pagefind indexes
|
|
8
13
|
* every rendered page except those whose `<html>` carries
|
|
@@ -23,7 +28,9 @@ import { dirname, join } from "pathe";
|
|
|
23
28
|
* Pagefind/pagefind#1272; switch back to `writeFiles()` once a release ships
|
|
24
29
|
* that fix.
|
|
25
30
|
*
|
|
26
|
-
* Returns the number of pages indexed
|
|
31
|
+
* Returns the number of pages indexed: the index's own count, summed over its
|
|
32
|
+
* languages from `pagefind-entry.json`. `addDirectory`'s `page_count` counts
|
|
33
|
+
* every HTML file it read, including the ones kept out of the index.
|
|
27
34
|
*/
|
|
28
35
|
export const buildSearchIndex = async (outDir: string): Promise<number> => {
|
|
29
36
|
const { index } = await createIndex({});
|
|
@@ -34,7 +41,7 @@ export const buildSearchIndex = async (outDir: string): Promise<number> => {
|
|
|
34
41
|
// These awaits are strictly ordered, not independent: the directory must be
|
|
35
42
|
// indexed before its files are read, and the index closed only after.
|
|
36
43
|
// oxlint-disable-next-line react-doctor/async-parallel
|
|
37
|
-
|
|
44
|
+
await index.addDirectory({ path: outDir });
|
|
38
45
|
const { files } = await index.getFiles();
|
|
39
46
|
await close();
|
|
40
47
|
|
|
@@ -49,5 +56,16 @@ export const buildSearchIndex = async (outDir: string): Promise<number> => {
|
|
|
49
56
|
files.map((file) => writeFile(join(searchDir, file.path), file.content))
|
|
50
57
|
);
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
// Pagefind always writes the entry file, listing no languages when nothing
|
|
60
|
+
// was indexed.
|
|
61
|
+
const entry = files.find((file) => file.path === "pagefind-entry.json");
|
|
62
|
+
// SAFETY: the entry file is Pagefind's JSON, which counts each language's
|
|
63
|
+
// pages in `page_count`.
|
|
64
|
+
const { languages } = JSON.parse(
|
|
65
|
+
new TextDecoder().decode(entry?.content)
|
|
66
|
+
) as PagefindEntry;
|
|
67
|
+
return Object.values(languages).reduce(
|
|
68
|
+
(sum, language) => sum + language.page_count,
|
|
69
|
+
0
|
|
70
|
+
);
|
|
53
71
|
};
|