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/astro/templates.ts
CHANGED
|
@@ -6,22 +6,34 @@ import { dirname, isAbsolute, join, relative } from "pathe";
|
|
|
6
6
|
import type { AskRetrievalOptions } from "../ai/ask-context.ts";
|
|
7
7
|
import type { AskBackend } from "../ai/ask.ts";
|
|
8
8
|
import { buildHomeLinkHeader } from "../ai/link-headers.ts";
|
|
9
|
+
import type { CaptchaAdapter } from "../captcha/schema.ts";
|
|
10
|
+
import { CONSENT_CLIENT_MODULES } from "../consent/clients.ts";
|
|
9
11
|
import { normalizeBasePath } from "../core/base-path.ts";
|
|
10
12
|
import { TOC_HIDDEN_KEY } from "../core/heading-markers.ts";
|
|
13
|
+
import { compileRedirects, isPatternPath } from "../core/redirect-patterns.ts";
|
|
14
|
+
import type { CompiledRedirect } from "../core/redirect-patterns.ts";
|
|
11
15
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
12
16
|
import { resolveDocsCollection } from "../core/sources/collection.ts";
|
|
13
17
|
import { BLUME_IGNORE_DIRS } from "../core/sources/watch.ts";
|
|
14
18
|
import { trimChar } from "../core/trim.ts";
|
|
15
19
|
import type { ProjectContext } from "../core/types.ts";
|
|
20
|
+
import { hasVariables } from "../core/variables.ts";
|
|
16
21
|
import { deployPassthrough } from "../deploy/adapters/types.ts";
|
|
17
22
|
import { SVG_ASSET_HEADERS } from "../deploy/headers.ts";
|
|
18
23
|
import { deployPlatform } from "../deploy/platforms/index.ts";
|
|
19
24
|
import { adapterRoot, distDir } from "../deploy/platforms/paths.ts";
|
|
20
25
|
import { applyBaseToAstroRedirects } from "../deploy/redirects.ts";
|
|
26
|
+
import { API_RAIL_KEY } from "../markdown/api-rail.ts";
|
|
27
|
+
import { VIEWS_KEY } from "../markdown/views.ts";
|
|
21
28
|
import type { OgCache } from "../og/cache.ts";
|
|
22
|
-
import type { OgFont, OgFontFamilies } from "../og/card.ts";
|
|
29
|
+
import type { OgFont, OgFontFamilies, OgGoogleFont } from "../og/card.ts";
|
|
30
|
+
import { RATE_LIMIT_BINDING } from "../ratelimit/cloudflare.ts";
|
|
31
|
+
import type { RateLimitAdapter } from "../ratelimit/schema.ts";
|
|
23
32
|
import type { MixedbreadOptions } from "../search/adapters/mixedbread.ts";
|
|
24
|
-
import type {
|
|
33
|
+
import type {
|
|
34
|
+
ResolvedSearchAdapter,
|
|
35
|
+
SearchAdapterKind,
|
|
36
|
+
} from "../search/adapters/registry.ts";
|
|
25
37
|
import { buildFontEntries, fontLocaleCodes } from "../theme/fonts.ts";
|
|
26
38
|
import { importSpecifier, wrapperPropsType } from "./component-slots.ts";
|
|
27
39
|
import type { ExampleSpec } from "./examples.ts";
|
|
@@ -185,7 +197,8 @@ export const runtimeDependencies = (options: {
|
|
|
185
197
|
deps.push(
|
|
186
198
|
...new Set(config.reference.flatMap((adapter) => adapter.runtimeDeps)),
|
|
187
199
|
...config.search.provider.runtimeDeps,
|
|
188
|
-
...config.analytics.flatMap((adapter) => adapter.runtimeDeps)
|
|
200
|
+
...config.analytics.flatMap((adapter) => adapter.runtimeDeps),
|
|
201
|
+
...(config.consent?.runtimeDeps ?? [])
|
|
189
202
|
);
|
|
190
203
|
// Each content source adapter declares the SDK its fetch imports (Notion,
|
|
191
204
|
// Sanity); the descriptor is the one place that knows.
|
|
@@ -398,14 +411,32 @@ export interface ClientFeatures {
|
|
|
398
411
|
/** Every feature on: what a checkout that predates the detection shipped. */
|
|
399
412
|
const ALL_CLIENT_FEATURES: ClientFeatures = { epub: true, mermaid: true };
|
|
400
413
|
|
|
414
|
+
/**
|
|
415
|
+
* The npm module each browser-queried search adapter's client imports (see
|
|
416
|
+
* `components/layout/search/`). The `<Search>` dialog lazy-imports that client
|
|
417
|
+
* on first open, after the dev dep optimizer's startup run, so the first
|
|
418
|
+
* search of a fresh `blume dev` session discovered the library, re-ran the
|
|
419
|
+
* optimizer, and reloaded the page. Pagefind loads its script from the build
|
|
420
|
+
* output and Mixedbread queries through the server, so neither has one.
|
|
421
|
+
*/
|
|
422
|
+
const SEARCH_CLIENT_DEPS: Partial<Record<SearchAdapterKind, string>> = {
|
|
423
|
+
algolia: "algoliasearch/lite",
|
|
424
|
+
flexsearch: "flexsearch",
|
|
425
|
+
orama: "@orama/orama",
|
|
426
|
+
"orama-cloud": "@oramacloud/client",
|
|
427
|
+
typesense: "typesense",
|
|
428
|
+
};
|
|
429
|
+
|
|
401
430
|
const resolveOptimizeDeps = (options: {
|
|
402
431
|
aliases: Record<string, string> | undefined;
|
|
403
432
|
context: ProjectContext;
|
|
404
433
|
features: ClientFeatures;
|
|
405
434
|
needsReact: boolean;
|
|
406
435
|
reactCompilerPath: string | null | undefined;
|
|
436
|
+
searchKind: SearchAdapterKind;
|
|
407
437
|
}): OptimizeDepsConfig => {
|
|
408
438
|
const { context, features } = options;
|
|
439
|
+
const searchDep = SEARCH_CLIENT_DEPS[options.searchKind];
|
|
409
440
|
const optimizeDepsEntries = [
|
|
410
441
|
...(context.pagesRoot ? [`${context.pagesRoot}/**/*.astro`] : []),
|
|
411
442
|
`${context.root}/islands/**/*.{jsx,svelte,tsx,vue}`,
|
|
@@ -418,6 +449,8 @@ const resolveOptimizeDeps = (options: {
|
|
|
418
449
|
// Mermaid costs the dev server seconds at startup for nothing otherwise.
|
|
419
450
|
...(features.mermaid ? ["blume > mermaid"] : []),
|
|
420
451
|
...(features.epub ? ["blume > epub-gen-memory/bundle"] : []),
|
|
452
|
+
// Only the configured search adapter's client library.
|
|
453
|
+
...(searchDep ? [`blume > ${searchDep}`] : []),
|
|
421
454
|
// Astro's own client-router/prefetch virtual modules are deliberately NOT
|
|
422
455
|
// forced in here: they read Vite `define`-injected constants
|
|
423
456
|
// (__PREFETCH_PREFETCH_ALL__ and friends) that a pre-bundled copy loses,
|
|
@@ -532,17 +565,23 @@ const blumeIntegrationOptions = (options: {
|
|
|
532
565
|
contentRoutes: string[];
|
|
533
566
|
ejected: boolean;
|
|
534
567
|
pages: BlumePageRoute[];
|
|
535
|
-
|
|
536
|
-
|
|
568
|
+
redirects: CompiledRedirect[];
|
|
569
|
+
}): BlumeIntegrationOptions => {
|
|
570
|
+
const shared: BlumeIntegrationOptions = { pages: options.pages };
|
|
571
|
+
if (options.redirects.length > 0) {
|
|
572
|
+
shared.redirects = options.redirects;
|
|
573
|
+
}
|
|
574
|
+
return options.ejected
|
|
537
575
|
? {
|
|
576
|
+
...shared,
|
|
538
577
|
buildArtifactsRoot: ".",
|
|
539
578
|
contentRoutes: options.contentRoutes,
|
|
540
579
|
homeLinkHeader:
|
|
541
|
-
buildHomeLinkHeader(options.config, options.contentRoutes) ??
|
|
580
|
+
buildHomeLinkHeader(options.config, options.contentRoutes, "dev") ??
|
|
542
581
|
undefined,
|
|
543
|
-
pages: options.pages,
|
|
544
582
|
}
|
|
545
|
-
:
|
|
583
|
+
: shared;
|
|
584
|
+
};
|
|
546
585
|
|
|
547
586
|
export const astroConfigTemplate = (options: {
|
|
548
587
|
context: ProjectContext;
|
|
@@ -558,6 +597,8 @@ export const astroConfigTemplate = (options: {
|
|
|
558
597
|
/** The example-preview Tailwind entry (`blume:examples-theme`). */
|
|
559
598
|
examplesThemePath: string;
|
|
560
599
|
themePath: string;
|
|
600
|
+
/** The configured consent adapter's browser module (`blume:consent-client`). */
|
|
601
|
+
consentClientPath: string;
|
|
561
602
|
searchClientPath: string;
|
|
562
603
|
/** The generated client-feature loaders (`blume:features`). */
|
|
563
604
|
featuresPath: string;
|
|
@@ -594,6 +635,7 @@ export const astroConfigTemplate = (options: {
|
|
|
594
635
|
);
|
|
595
636
|
const {
|
|
596
637
|
askPath,
|
|
638
|
+
consentClientPath,
|
|
597
639
|
contentRoutes,
|
|
598
640
|
examplesPath,
|
|
599
641
|
examplesThemePath,
|
|
@@ -623,6 +665,7 @@ export const astroConfigTemplate = (options: {
|
|
|
623
665
|
features,
|
|
624
666
|
needsReact,
|
|
625
667
|
reactCompilerPath: options.reactCompilerPath,
|
|
668
|
+
searchKind: config.search.provider.kind,
|
|
626
669
|
});
|
|
627
670
|
|
|
628
671
|
const {
|
|
@@ -660,13 +703,20 @@ export const astroConfigTemplate = (options: {
|
|
|
660
703
|
const basedRedirects = applyBaseToAstroRedirects(
|
|
661
704
|
config.redirects,
|
|
662
705
|
config.basePath,
|
|
663
|
-
deployment.options.base ?? ""
|
|
706
|
+
deployment.options.base ?? "",
|
|
707
|
+
new Set(contentRoutes)
|
|
708
|
+
);
|
|
709
|
+
// Only exact redirects: Astro can't prerender a pattern's redirect pages
|
|
710
|
+
// (it would need every path the pattern covers), so a pattern reaches the
|
|
711
|
+
// dev server through the integration and each host through its own rules.
|
|
712
|
+
const exactRedirects = basedRedirects.filter(
|
|
713
|
+
(redirect) => !isPatternPath(redirect.from)
|
|
664
714
|
);
|
|
665
715
|
const redirectsOption =
|
|
666
|
-
|
|
716
|
+
exactRedirects.length > 0
|
|
667
717
|
? `\n redirects: ${JSON.stringify(
|
|
668
718
|
Object.fromEntries(
|
|
669
|
-
|
|
719
|
+
exactRedirects.map((redirect) => [
|
|
670
720
|
redirect.from,
|
|
671
721
|
{ destination: redirect.to, status: redirect.status },
|
|
672
722
|
])
|
|
@@ -734,12 +784,19 @@ export const astroConfigTemplate = (options: {
|
|
|
734
784
|
const svelteImport = needsSvelte
|
|
735
785
|
? `import svelte from "@astrojs/svelte";\n`
|
|
736
786
|
: "";
|
|
787
|
+
// Content variables in `.mdx` are replaced before the MDX compiler parses
|
|
788
|
+
// the source, which reads `{{name}}` as a JavaScript expression.
|
|
789
|
+
const substitutesVariables = hasVariables(config.variables);
|
|
790
|
+
const variablesPluginEntry = substitutesVariables
|
|
791
|
+
? `variablesVitePlugin(${JSON.stringify(config.variables)}), `
|
|
792
|
+
: "";
|
|
737
793
|
const blumeImports = [
|
|
738
794
|
"blumeIntegration",
|
|
739
795
|
"includeHmrPlugin",
|
|
740
796
|
"prerenderDepsPlugin",
|
|
741
797
|
...runtimeModuleImports,
|
|
742
798
|
...(adapterOption.includes("withAdapterRoot") ? ["withAdapterRoot"] : []),
|
|
799
|
+
...(substitutesVariables ? ["variablesVitePlugin"] : []),
|
|
743
800
|
];
|
|
744
801
|
const blumeImport = `import { ${blumeImports.join(", ")} } from "blume/astro";\n`;
|
|
745
802
|
|
|
@@ -769,6 +826,7 @@ export const astroConfigTemplate = (options: {
|
|
|
769
826
|
deployBase,
|
|
770
827
|
externalLinks: config.markdown.externalLinks,
|
|
771
828
|
headingAnchors: config.markdown.headingAnchors,
|
|
829
|
+
variables: config.variables,
|
|
772
830
|
});
|
|
773
831
|
const processorOptions =
|
|
774
832
|
options.generatedModulesDir === undefined
|
|
@@ -797,6 +855,7 @@ export const astroConfigTemplate = (options: {
|
|
|
797
855
|
contentRoutes,
|
|
798
856
|
ejected,
|
|
799
857
|
pages,
|
|
858
|
+
redirects: compileRedirects(basedRedirects),
|
|
800
859
|
})
|
|
801
860
|
)})`
|
|
802
861
|
);
|
|
@@ -860,7 +919,7 @@ ${userConfigSetup}export default defineConfig({
|
|
|
860
919
|
// the overlap only adds memory.
|
|
861
920
|
build: { concurrency: Math.min(8, availableParallelism()) },
|
|
862
921
|
vite: {${viteCacheOption}
|
|
863
|
-
plugins: [${runtimeModulesPluginEntry}tailwindcss(), includeHmrPlugin(${configPath(
|
|
922
|
+
plugins: [${runtimeModulesPluginEntry}${variablesPluginEntry}tailwindcss(), includeHmrPlugin(${configPath(
|
|
864
923
|
`${context.outDir}/src/generated/includes.json`,
|
|
865
924
|
ejected
|
|
866
925
|
)}), prerenderDepsPlugin()],
|
|
@@ -892,6 +951,10 @@ ${userConfigSetup}export default defineConfig({
|
|
|
892
951
|
// \`/bundle\` subpath that is actually imported: optimizing the package
|
|
893
952
|
// root leaves that entry out. Production (Rollup) already handles the
|
|
894
953
|
// interop, so all of this only affects dev.
|
|
954
|
+
//
|
|
955
|
+
// The search adapter's client library rides the list for the same reason
|
|
956
|
+
// as the compiler runtime: the search dialog lazy-imports it on first
|
|
957
|
+
// open, and discovering it then re-optimizes and reloads the page.
|
|
895
958
|
optimizeDeps: {
|
|
896
959
|
entries: ${JSON.stringify(optimizeDepsEntries)},
|
|
897
960
|
include: ${JSON.stringify(optimizeDepsInclude)},
|
|
@@ -915,6 +978,7 @@ ${userConfigSetup}export default defineConfig({
|
|
|
915
978
|
resolve: {
|
|
916
979
|
alias: {
|
|
917
980
|
"blume:ask": ${configPath(askPath, ejected)},
|
|
981
|
+
"blume:consent-client": ${configPath(consentClientPath, ejected)},
|
|
918
982
|
"blume:examples": ${configPath(examplesPath, ejected)},
|
|
919
983
|
"blume:examples-theme": ${configPath(examplesThemePath, ejected)},
|
|
920
984
|
"blume:features": ${configPath(featuresPath, ejected)},
|
|
@@ -1066,12 +1130,21 @@ const ASK_FALLBACK_PROMPT =
|
|
|
1066
1130
|
|
|
1067
1131
|
/** The `ai.assistant` values the generated endpoint has to carry with it. */
|
|
1068
1132
|
export interface AskEndpointOptions {
|
|
1133
|
+
/** `ai.assistant.captcha` — the bot check the route verifies first. */
|
|
1134
|
+
captcha?: CaptchaAdapter;
|
|
1069
1135
|
/** `ai.assistant.cors` — origins allowed to call the route from another site. */
|
|
1070
1136
|
cors?: string[];
|
|
1137
|
+
/** `rateLimit` — the limiter the route checks before any work. */
|
|
1138
|
+
rateLimit?: RateLimitAdapter | null;
|
|
1071
1139
|
/** `ai.assistant.instructions` — extra system-prompt text. */
|
|
1072
1140
|
instructions?: string;
|
|
1073
1141
|
/** `ai.assistant.retrieval` — how much documentation each question carries. */
|
|
1074
1142
|
retrieval?: AskRetrievalOptions;
|
|
1143
|
+
/**
|
|
1144
|
+
* `ai.assistant.tools`, resolved against the adapter's default: give the
|
|
1145
|
+
* model the docs search and read-page tools.
|
|
1146
|
+
*/
|
|
1147
|
+
tools?: boolean;
|
|
1075
1148
|
}
|
|
1076
1149
|
|
|
1077
1150
|
/** The pieces `askEndpointTemplate` splices in for `ai.assistant.cors`. */
|
|
@@ -1103,7 +1176,7 @@ const askCorsTemplate = (cors: readonly string[] = []): AskCorsTemplate =>
|
|
|
1103
1176
|
imports: [
|
|
1104
1177
|
'import { preflightResponse, withCors } from "blume/ai/cors.ts";',
|
|
1105
1178
|
],
|
|
1106
|
-
open: "withCors(ALLOWED_ORIGINS, async (
|
|
1179
|
+
open: "withCors(ALLOWED_ORIGINS, async (context) => {",
|
|
1107
1180
|
setup: `
|
|
1108
1181
|
const ALLOWED_ORIGINS = ${JSON.stringify(cors)};
|
|
1109
1182
|
|
|
@@ -1111,7 +1184,89 @@ export const OPTIONS: APIRoute = ({ request }) =>
|
|
|
1111
1184
|
preflightResponse(request, ALLOWED_ORIGINS);
|
|
1112
1185
|
`,
|
|
1113
1186
|
}
|
|
1114
|
-
: { close: "};", imports: [], open: "async (
|
|
1187
|
+
: { close: "};", imports: [], open: "async (context) => {", setup: "" };
|
|
1188
|
+
|
|
1189
|
+
/** The pieces a server route splices in to check `rateLimit` first. */
|
|
1190
|
+
interface RateLimitTemplate {
|
|
1191
|
+
/** The check at the top of the handler; reads `context`. */
|
|
1192
|
+
check: string;
|
|
1193
|
+
/** The runtime import, plus what the adapter's store needs. */
|
|
1194
|
+
imports: string[];
|
|
1195
|
+
/** The route's limiter, built once at module scope. */
|
|
1196
|
+
setup: string;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* `rateLimit` for one server route: a limiter built at module scope from the
|
|
1201
|
+
* configured adapter, checked against every request, keyed by the reader's
|
|
1202
|
+
* address and `scope` so each route keeps its own budget (see
|
|
1203
|
+
* `ratelimit/runtime.ts`). Upstash reads its secrets through `getSecret`;
|
|
1204
|
+
* Cloudflare's binding comes from the Worker's env. Nothing at all when
|
|
1205
|
+
* rate limiting is off.
|
|
1206
|
+
*/
|
|
1207
|
+
export const rateLimitTemplate = (
|
|
1208
|
+
adapter: RateLimitAdapter | null | undefined,
|
|
1209
|
+
scope: string
|
|
1210
|
+
): RateLimitTemplate => {
|
|
1211
|
+
if (!adapter) {
|
|
1212
|
+
return { check: "", imports: [], setup: "" };
|
|
1213
|
+
}
|
|
1214
|
+
const imports = [
|
|
1215
|
+
'import { createLimiter, rateLimited } from "blume/ratelimit/runtime.ts";',
|
|
1216
|
+
];
|
|
1217
|
+
let runtime = "";
|
|
1218
|
+
if (adapter.kind === "upstash") {
|
|
1219
|
+
imports.push('import { getSecret } from "astro:env/server";');
|
|
1220
|
+
runtime = ", { secret: getSecret }";
|
|
1221
|
+
} else if (adapter.kind === "cloudflare") {
|
|
1222
|
+
imports.push(
|
|
1223
|
+
"// @ts-ignore `cloudflare:workers` is typed once `wrangler types` has run.",
|
|
1224
|
+
'import { env } from "cloudflare:workers";'
|
|
1225
|
+
);
|
|
1226
|
+
runtime = `, { binding: Reflect.get(env, ${JSON.stringify(RATE_LIMIT_BINDING)}) }`;
|
|
1227
|
+
}
|
|
1228
|
+
return {
|
|
1229
|
+
check: ` const limited = await rateLimited(limiter, context, ${JSON.stringify(scope)});
|
|
1230
|
+
if (limited) {
|
|
1231
|
+
return limited;
|
|
1232
|
+
}
|
|
1233
|
+
`,
|
|
1234
|
+
imports,
|
|
1235
|
+
setup: `\nconst limiter = createLimiter(${JSON.stringify(adapter)}${runtime});\n`,
|
|
1236
|
+
};
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* `ai.assistant.captcha` for the ask route: verify the question's token with
|
|
1241
|
+
* the provider before the model runs (see `captcha/verify.ts`). A missing
|
|
1242
|
+
* secret answers with the same "not configured" notice as a missing
|
|
1243
|
+
* provider key, which the panel shows as is; a failed check answers `403`.
|
|
1244
|
+
*/
|
|
1245
|
+
const askCaptchaTemplate = (adapter?: CaptchaAdapter): RateLimitTemplate => {
|
|
1246
|
+
if (!adapter) {
|
|
1247
|
+
return { check: "", imports: [], setup: "" };
|
|
1248
|
+
}
|
|
1249
|
+
const [secret = ""] = adapter.requiredSecrets;
|
|
1250
|
+
return {
|
|
1251
|
+
check: ` const captchaSecret = getSecret(${JSON.stringify(secret)});
|
|
1252
|
+
if (!captchaSecret) {
|
|
1253
|
+
return new Response(
|
|
1254
|
+
${JSON.stringify(`The assistant is not configured: set ${secret}.`)},
|
|
1255
|
+
{ status: 503 }
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
const captchaToken =
|
|
1259
|
+
typeof body.captcha === "string" ? body.captcha : undefined;
|
|
1260
|
+
if (!(await verifyCaptcha(CAPTCHA, captchaToken, context, { secret: captchaSecret }))) {
|
|
1261
|
+
return new Response("Verification failed: the bot check didn't pass.", {
|
|
1262
|
+
status: 403,
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
`,
|
|
1266
|
+
imports: ['import { verifyCaptcha } from "blume/captcha/verify.ts";'],
|
|
1267
|
+
setup: `\nconst CAPTCHA = ${JSON.stringify(adapter)};\n`,
|
|
1268
|
+
};
|
|
1269
|
+
};
|
|
1115
1270
|
|
|
1116
1271
|
/**
|
|
1117
1272
|
* Largest request body the assistant route reads: 64 KB, well above the
|
|
@@ -1145,6 +1300,8 @@ export const askEndpointTemplate = (
|
|
|
1145
1300
|
): string => {
|
|
1146
1301
|
const { instructions, retrieval } = options ?? {};
|
|
1147
1302
|
const { grounded } = backend;
|
|
1303
|
+
// The tools read the grounding snapshot, so an ungrounded backend has none.
|
|
1304
|
+
const tools = grounded && Boolean(options?.tools);
|
|
1148
1305
|
const fallbackPrompt = instructions
|
|
1149
1306
|
? `${ASK_FALLBACK_PROMPT}\n\n${instructions}`
|
|
1150
1307
|
: ASK_FALLBACK_PROMPT;
|
|
@@ -1172,12 +1329,32 @@ export const askEndpointTemplate = (
|
|
|
1172
1329
|
if (retrieval) {
|
|
1173
1330
|
groundFields.push(`retrieval: ${JSON.stringify(retrieval)}`);
|
|
1174
1331
|
}
|
|
1332
|
+
if (tools) {
|
|
1333
|
+
groundFields.push("tools: true");
|
|
1334
|
+
}
|
|
1175
1335
|
const groundOptions =
|
|
1176
1336
|
groundFields.length > 0 ? `, { ${groundFields.join(", ")} }` : "";
|
|
1177
1337
|
setup += `\nconst ground = createAskContext(askData${groundOptions});\n`;
|
|
1338
|
+
if (tools) {
|
|
1339
|
+
imports.push(
|
|
1340
|
+
'import { stepCountIs } from "ai";',
|
|
1341
|
+
'import { ASK_MAX_STEPS, createAskTools } from "blume/ai/ask-tools.ts";'
|
|
1342
|
+
);
|
|
1343
|
+
setup += "const askTools = createAskTools(askData);\n";
|
|
1344
|
+
}
|
|
1178
1345
|
}
|
|
1179
1346
|
const cors = askCorsTemplate(options?.cors);
|
|
1180
1347
|
imports.push(...cors.imports);
|
|
1348
|
+
const limit = rateLimitTemplate(options?.rateLimit, "ask");
|
|
1349
|
+
for (const line of limit.imports) {
|
|
1350
|
+
if (!imports.includes(line)) {
|
|
1351
|
+
imports.push(line);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
setup += limit.setup;
|
|
1355
|
+
const captcha = askCaptchaTemplate(options?.captcha);
|
|
1356
|
+
imports.push(...captcha.imports);
|
|
1357
|
+
setup += captcha.setup;
|
|
1181
1358
|
// Validate the client-supplied body and cap its size. The endpoint is
|
|
1182
1359
|
// unauthenticated, so bounding message count/length limits how much a caller
|
|
1183
1360
|
// can spend against the model per request, and restricting roles to
|
|
@@ -1186,7 +1363,8 @@ export const askEndpointTemplate = (
|
|
|
1186
1363
|
// limiter (or your provider's limits) for stronger protection. The body is
|
|
1187
1364
|
// read under a 64 KB cap before any parsing, since a self-hosted Node server
|
|
1188
1365
|
// would otherwise buffer an arbitrarily large POST in memory first.
|
|
1189
|
-
const validate = ` const
|
|
1366
|
+
const validate = ` const { request } = context;
|
|
1367
|
+
${limit.check} const text = await readCappedText(request, ${ASK_BODY_LIMIT_BYTES});
|
|
1190
1368
|
if (text === undefined) {
|
|
1191
1369
|
return new Response("Request too large: the body must be at most 64 KB.", {
|
|
1192
1370
|
status: 413,
|
|
@@ -1244,11 +1422,22 @@ export const askEndpointTemplate = (
|
|
|
1244
1422
|
? "instructions"
|
|
1245
1423
|
: `instructions:\n ${JSON.stringify(fallbackPrompt)}`,
|
|
1246
1424
|
"messages",
|
|
1425
|
+
// The model may search and read pages, then answer, within one request:
|
|
1426
|
+
// tool calls run here on the server and only the text reaches the reader.
|
|
1427
|
+
...(tools
|
|
1428
|
+
? ["tools: askTools(body.page)", "stopWhen: stepCountIs(ASK_MAX_STEPS)"]
|
|
1429
|
+
: []),
|
|
1247
1430
|
...backend.template.fields,
|
|
1248
1431
|
];
|
|
1432
|
+
// The request's signal aborts when the reader closes the panel mid-answer
|
|
1433
|
+
// (the client drops the connection): passing it on stops the model call,
|
|
1434
|
+
// which otherwise kept generating, and billing, to completion into a closed
|
|
1435
|
+
// connection. `streamText` ends an aborted call through its abort path, not
|
|
1436
|
+
// `onError`, so the reader leaving is never logged as a provider error.
|
|
1249
1437
|
const call = ` const result = streamText({
|
|
1250
1438
|
${streamFields.join(",\n ")},
|
|
1251
1439
|
${onError}
|
|
1440
|
+
abortSignal: request.signal,
|
|
1252
1441
|
});`;
|
|
1253
1442
|
const stream = grounded
|
|
1254
1443
|
? ` const instructions =
|
|
@@ -1259,7 +1448,7 @@ ${call}`
|
|
|
1259
1448
|
const handler = `export const POST: APIRoute = ${cors.open}
|
|
1260
1449
|
${validate}
|
|
1261
1450
|
${keyCheck}
|
|
1262
|
-
try {
|
|
1451
|
+
${captcha.check} try {
|
|
1263
1452
|
${stream}
|
|
1264
1453
|
return createTextStreamResponse({
|
|
1265
1454
|
stream: toTextStream({ stream: result.stream }),
|
|
@@ -1304,9 +1493,11 @@ const { strings } = Astro.props;
|
|
|
1304
1493
|
---
|
|
1305
1494
|
|
|
1306
1495
|
<Assistant
|
|
1496
|
+
captcha={data.config.assistant?.captcha ?? undefined}
|
|
1307
1497
|
endpoint={data.config.assistant?.endpoint ?? undefined}
|
|
1308
1498
|
strings={strings ?? data.ui.assistant}
|
|
1309
1499
|
suggestions={data.config.assistant?.suggestions ?? []}
|
|
1500
|
+
support={data.config.assistant?.support ?? undefined}
|
|
1310
1501
|
/>
|
|
1311
1502
|
`
|
|
1312
1503
|
: `---
|
|
@@ -1406,6 +1597,36 @@ ${
|
|
|
1406
1597
|
}
|
|
1407
1598
|
`;
|
|
1408
1599
|
|
|
1600
|
+
/**
|
|
1601
|
+
* Generate `.blume/src/generated/consent-client.ts`, behind the
|
|
1602
|
+
* `blume:consent-client` alias: the configured consent adapter's browser
|
|
1603
|
+
* module (see `consent/clients.ts`), started by `ConsentHead.astro` with the
|
|
1604
|
+
* adapter's options baked in. Only that adapter's module is referenced, so a
|
|
1605
|
+
* site bundles no other adapter's code. An adapter without one (a hosted
|
|
1606
|
+
* manager), or no `consent` at all, gets a no-op so the alias always resolves.
|
|
1607
|
+
*/
|
|
1608
|
+
export const consentClientTemplate = (
|
|
1609
|
+
consent: ResolvedConfig["consent"]
|
|
1610
|
+
): string => {
|
|
1611
|
+
const module = consent ? CONSENT_CLIENT_MODULES.get(consent.kind) : undefined;
|
|
1612
|
+
if (!(consent && module)) {
|
|
1613
|
+
return `// Generated by Blume. Do not edit.
|
|
1614
|
+
// The consent adapter has no browser module, or consent is off.
|
|
1615
|
+
export const startConsentClient = (): void => {};
|
|
1616
|
+
`;
|
|
1617
|
+
}
|
|
1618
|
+
return `// Generated by Blume. Do not edit.
|
|
1619
|
+
// The \`${consent.kind}\` consent adapter's browser module, with its options.
|
|
1620
|
+
import { start } from ${JSON.stringify(module)};
|
|
1621
|
+
|
|
1622
|
+
export const startConsentClient = (
|
|
1623
|
+
consent: Parameters<typeof start>[0]
|
|
1624
|
+
): void => {
|
|
1625
|
+
start(consent, ${JSON.stringify(consent.options)});
|
|
1626
|
+
};
|
|
1627
|
+
`;
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1409
1630
|
/**
|
|
1410
1631
|
* Generate `.blume/src/generated/search-client.ts` — the provider-specific
|
|
1411
1632
|
* loader the `<Search>` component lazy-imports via the `blume:search-client`
|
|
@@ -1458,13 +1679,19 @@ export const createSearch = () => create({ url });
|
|
|
1458
1679
|
* content was synced (see the Mixedbread sync step / \`mxbai vs sync\`).
|
|
1459
1680
|
*/
|
|
1460
1681
|
export const mixedbreadSearchEndpointTemplate = (
|
|
1461
|
-
options: MixedbreadOptions
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
import
|
|
1467
|
-
import {
|
|
1682
|
+
options: MixedbreadOptions,
|
|
1683
|
+
rateLimit?: RateLimitAdapter | null
|
|
1684
|
+
): string => {
|
|
1685
|
+
const limit = rateLimitTemplate(rateLimit, "search");
|
|
1686
|
+
const imports = [
|
|
1687
|
+
'import type { APIRoute } from "astro";',
|
|
1688
|
+
'import { getSecret } from "astro:env/server";',
|
|
1689
|
+
'import Mixedbread from "@mixedbread/sdk";',
|
|
1690
|
+
'import { readCappedText } from "blume/core/request-body.ts";',
|
|
1691
|
+
...limit.imports.filter((line) => !line.includes('"astro:env/server"')),
|
|
1692
|
+
];
|
|
1693
|
+
return `// Generated by Blume. Do not edit.
|
|
1694
|
+
${imports.join("\n")}
|
|
1468
1695
|
|
|
1469
1696
|
export const prerender = false;
|
|
1470
1697
|
|
|
@@ -1472,9 +1699,10 @@ const client = new Mixedbread({ apiKey: getSecret("MIXEDBREAD_API_KEY") ?? "" })
|
|
|
1472
1699
|
const OPTIONS = ${JSON.stringify(options)};
|
|
1473
1700
|
// Every option besides the store reaches the search call verbatim.
|
|
1474
1701
|
const { storeId: STORE_ID, ...SEARCH_OPTIONS } = OPTIONS;
|
|
1475
|
-
|
|
1476
|
-
export const POST: APIRoute = async (
|
|
1477
|
-
|
|
1702
|
+
${limit.setup}
|
|
1703
|
+
export const POST: APIRoute = async (context) => {
|
|
1704
|
+
const { request } = context;
|
|
1705
|
+
${limit.check} // A search body is one short query: read it under a 16 KB cap, so a
|
|
1478
1706
|
// self-hosted server never buffers an arbitrarily large POST first.
|
|
1479
1707
|
const text = await readCappedText(request, 16_384);
|
|
1480
1708
|
if (text === undefined) {
|
|
@@ -1519,6 +1747,7 @@ export const POST: APIRoute = async ({ request }) => {
|
|
|
1519
1747
|
});
|
|
1520
1748
|
};
|
|
1521
1749
|
`;
|
|
1750
|
+
};
|
|
1522
1751
|
|
|
1523
1752
|
/**
|
|
1524
1753
|
* Generate the raw-Markdown endpoints (`[...slug].md.ts` and `[...slug].mdx.ts`).
|
|
@@ -1721,17 +1950,26 @@ export const ALL: APIRoute = ({ request }) => handler(request);
|
|
|
1721
1950
|
* client-side data: that is the whole trust boundary keeping the endpoint from
|
|
1722
1951
|
* being an open proxy onto the deployment's own network.
|
|
1723
1952
|
*/
|
|
1724
|
-
export const playgroundProxyTemplate = (
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1953
|
+
export const playgroundProxyTemplate = (
|
|
1954
|
+
origins: string[],
|
|
1955
|
+
rateLimit?: RateLimitAdapter | null
|
|
1956
|
+
): string => {
|
|
1957
|
+
const limit = rateLimitTemplate(rateLimit, "api-proxy");
|
|
1958
|
+
const route = limit.check
|
|
1959
|
+
? `export const ALL: APIRoute = async (context) => {
|
|
1960
|
+
${limit.check} return handler(context.request);
|
|
1961
|
+
};`
|
|
1962
|
+
: "export const ALL: APIRoute = ({ request }) => handler(request);";
|
|
1963
|
+
return `// Generated by Blume. Do not edit.
|
|
1964
|
+
${['import type { APIRoute } from "astro";', 'import { createPlaygroundProxyHandler } from "blume/openapi/proxy.ts";', ...limit.imports].join("\n")}
|
|
1728
1965
|
|
|
1729
1966
|
export const prerender = false;
|
|
1730
1967
|
|
|
1731
1968
|
const handler = createPlaygroundProxyHandler(${JSON.stringify(origins)});
|
|
1732
|
-
|
|
1733
|
-
|
|
1969
|
+
${limit.setup}
|
|
1970
|
+
${route}
|
|
1734
1971
|
`;
|
|
1972
|
+
};
|
|
1735
1973
|
|
|
1736
1974
|
/** Generate a prerendered endpoint that serves a fixed JSON payload. */
|
|
1737
1975
|
export const staticJsonEndpointTemplate = <Payload extends object>(
|
|
@@ -1792,7 +2030,7 @@ export const navFragmentTemplate = (): string =>
|
|
|
1792
2030
|
`---
|
|
1793
2031
|
// Generated by Blume. Do not edit.
|
|
1794
2032
|
import NavTree from "blume/components/layout/NavTree.astro";
|
|
1795
|
-
import {
|
|
2033
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
1796
2034
|
import {
|
|
1797
2035
|
hiddenDefaultLocale,
|
|
1798
2036
|
navGroupIds,
|
|
@@ -1831,7 +2069,7 @@ if (!(variant && node && node.kind === "group")) {
|
|
|
1831
2069
|
}
|
|
1832
2070
|
const strings =
|
|
1833
2071
|
locale === "default" ? data.ui.nav : (data.uiByLocale[locale] ?? data.ui).nav;
|
|
1834
|
-
const fragmentBase =
|
|
2072
|
+
const fragmentBase = withMountedBase(\`/blume-nav/\${version}/\${locale}\`);
|
|
1835
2073
|
---
|
|
1836
2074
|
|
|
1837
2075
|
<NavTree
|
|
@@ -1855,6 +2093,7 @@ export const ogEndpointTemplate = (
|
|
|
1855
2093
|
* Absent, every card renders on every build.
|
|
1856
2094
|
*/
|
|
1857
2095
|
cache?: OgCache;
|
|
2096
|
+
fallbacks?: OgGoogleFont[];
|
|
1858
2097
|
families?: OgFontFamilies;
|
|
1859
2098
|
fonts?: OgFont[];
|
|
1860
2099
|
/**
|
|
@@ -1868,7 +2107,7 @@ export const ogEndpointTemplate = (
|
|
|
1868
2107
|
): string =>
|
|
1869
2108
|
`// Generated by Blume. Do not edit.
|
|
1870
2109
|
import { cachedOgImage } from "blume/og";
|
|
1871
|
-
import type { OgCache, OgFont, OgFontFamilies } from "blume/og";
|
|
2110
|
+
import type { OgCache, OgFont, OgFontFamilies, OgGoogleFont } from "blume/og";
|
|
1872
2111
|
import data from "blume:data";
|
|
1873
2112
|
|
|
1874
2113
|
export const prerender = true;
|
|
@@ -1886,6 +2125,9 @@ const fonts: OgFont[] = ${JSON.stringify(og.fonts ?? [])};
|
|
|
1886
2125
|
const families: OgFontFamilies | undefined = ${
|
|
1887
2126
|
og.families ? JSON.stringify(og.families) : "undefined"
|
|
1888
2127
|
};
|
|
2128
|
+
// Script fallbacks (Noto families, the configured locales' first). A card
|
|
2129
|
+
// fetches them only when its text has a glyph Takumi's built-in font lacks.
|
|
2130
|
+
const fallbacks: OgGoogleFont[] = ${JSON.stringify(og.fallbacks ?? [])};
|
|
1889
2131
|
|
|
1890
2132
|
// Rendered cards are kept on disk between builds, keyed by everything that
|
|
1891
2133
|
// decides their pixels, so a rebuild renders only the cards whose title,
|
|
@@ -1958,6 +2200,7 @@ export async function GET({ props }: { props: CardProps }) {
|
|
|
1958
2200
|
accent: data.config.og.palette?.accent ?? data.config.theme.accent.light,
|
|
1959
2201
|
brand: data.config.title,
|
|
1960
2202
|
description: props.description ?? data.config.og.description,
|
|
2203
|
+
fallbacks,
|
|
1961
2204
|
families,
|
|
1962
2205
|
fonts,
|
|
1963
2206
|
logo: data.config.og.logo,
|
|
@@ -2050,6 +2293,9 @@ const contentComponentsSource = (mathEnabled: boolean) => {
|
|
|
2050
2293
|
return {
|
|
2051
2294
|
imports: `import Accordion from "blume/components/content/Accordion.astro";
|
|
2052
2295
|
import AccordionItem from "blume/components/content/AccordionItem.astro";
|
|
2296
|
+
import ApiEndpoint from "blume/components/content/ApiEndpoint.astro";
|
|
2297
|
+
import ApiPlayground from "blume/components/content/ApiPlayground.astro";
|
|
2298
|
+
import ApiRail from "blume/components/content/ApiRail.astro";
|
|
2053
2299
|
import AutoTypeTable from "blume/components/content/AutoTypeTable.astro";
|
|
2054
2300
|
import Badge from "blume/components/content/Badge.astro";
|
|
2055
2301
|
import Callout from "blume/components/content/Callout.astro";
|
|
@@ -2069,7 +2315,11 @@ import FileTree from "blume/components/content/FileTree.astro";
|
|
|
2069
2315
|
import Frame from "blume/components/content/Frame.astro";
|
|
2070
2316
|
import GithubInfo from "blume/components/content/GithubInfo.astro";
|
|
2071
2317
|
import Panel from "blume/components/content/Panel.astro";
|
|
2318
|
+
import ParamField from "blume/components/content/ParamField.astro";
|
|
2072
2319
|
import Prompt from "blume/components/content/Prompt.astro";
|
|
2320
|
+
import RequestExample from "blume/components/content/RequestExample.astro";
|
|
2321
|
+
import ResponseExample from "blume/components/content/ResponseExample.astro";
|
|
2322
|
+
import ResponseField from "blume/components/content/ResponseField.astro";
|
|
2073
2323
|
import Step from "blume/components/content/Step.astro";
|
|
2074
2324
|
import Steps from "blume/components/content/Steps.astro";
|
|
2075
2325
|
import Tab from "blume/components/content/Tab.astro";
|
|
@@ -2080,10 +2330,13 @@ import TreeRoot from "blume/components/content/Tree.astro";
|
|
|
2080
2330
|
import TreeFile from "blume/components/content/TreeFile.astro";
|
|
2081
2331
|
import TreeFolder from "blume/components/content/TreeFolder.astro";
|
|
2082
2332
|
import TypeTable from "blume/components/content/TypeTable.astro";
|
|
2333
|
+
import View from "blume/components/content/View.astro";
|
|
2083
2334
|
import Visibility from "blume/components/content/Visibility.astro";
|
|
2084
2335
|
import YouTube from "blume/components/content/YouTube.astro";
|
|
2085
2336
|
import Icon from "blume/components/Icon.astro";
|
|
2086
2337
|
import LocaleLinks from "blume/components/layout/LocaleLinks.astro";
|
|
2338
|
+
import NarrationPlayer from "blume/components/layout/NarrationPlayer.astro";
|
|
2339
|
+
import ViewSwitcher from "blume/components/content/ViewSwitcher.astro";
|
|
2087
2340
|
import ApiOverview from "blume/components/openapi/ApiOverview.astro";
|
|
2088
2341
|
import ApiTagOperations from "blume/components/openapi/ApiTagOperations.astro";
|
|
2089
2342
|
import Operation from "blume/components/openapi/Operation.astro";
|
|
@@ -2091,7 +2344,10 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
|
|
|
2091
2344
|
map: `{
|
|
2092
2345
|
Accordion,
|
|
2093
2346
|
AccordionItem,
|
|
2347
|
+
ApiEndpoint,
|
|
2094
2348
|
ApiOverview,
|
|
2349
|
+
ApiPlayground,
|
|
2350
|
+
ApiRail,
|
|
2095
2351
|
ApiTagOperations,
|
|
2096
2352
|
AutoTypeTable,
|
|
2097
2353
|
Badge,
|
|
@@ -2112,7 +2368,11 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
|
|
|
2112
2368
|
Icon,
|
|
2113
2369
|
Operation,
|
|
2114
2370
|
Panel,
|
|
2371
|
+
ParamField,
|
|
2115
2372
|
Prompt,
|
|
2373
|
+
RequestExample,
|
|
2374
|
+
ResponseExample,
|
|
2375
|
+
ResponseField,
|
|
2116
2376
|
Step,
|
|
2117
2377
|
Steps,
|
|
2118
2378
|
Tab,
|
|
@@ -2121,6 +2381,7 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
|
|
|
2121
2381
|
Tooltip,
|
|
2122
2382
|
Tree,
|
|
2123
2383
|
TypeTable,
|
|
2384
|
+
View,
|
|
2124
2385
|
Visibility,
|
|
2125
2386
|
YouTube,
|
|
2126
2387
|
${mathEntry}...userMdx,
|
|
@@ -2151,10 +2412,11 @@ export const catchAllPageTemplate = (options: {
|
|
|
2151
2412
|
return `---
|
|
2152
2413
|
// Generated by Blume. Do not edit.
|
|
2153
2414
|
import { getEntry, render } from "astro:content";
|
|
2415
|
+
import { pageModeLayout } from "blume/core/page-modes.ts";
|
|
2154
2416
|
import type { CollectionKey } from "astro:content";
|
|
2155
2417
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
2156
|
-
import { withBase } from "blume/components/islands/base-path.ts";
|
|
2157
|
-
import {
|
|
2418
|
+
import { withBase, withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2419
|
+
import { mountBasePath, stripBasePath } from "blume/core/base-path.ts";
|
|
2158
2420
|
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
2159
2421
|
${componentImports}
|
|
2160
2422
|
import data from "blume:data";
|
|
@@ -2202,6 +2464,13 @@ const { Content, headings: allHeadings, remarkPluginFrontmatter } = await render
|
|
|
2202
2464
|
// frontmatter (see markdown/heading-anchors.ts). Only the plugin's array
|
|
2203
2465
|
// counts: \`frontmatter.extend\` can declare the same key, and on a page with
|
|
2204
2466
|
// no headings that user-supplied value would pass straight through.
|
|
2467
|
+
// A page written in \`<View>\` blocks gets their picker above the content;
|
|
2468
|
+
// the views plugin lists them through the render's frontmatter (see
|
|
2469
|
+
// markdown/views.ts), and only a list of titled entries counts.
|
|
2470
|
+
const viewsRaw = remarkPluginFrontmatter?.${VIEWS_KEY};
|
|
2471
|
+
const views = Array.isArray(viewsRaw)
|
|
2472
|
+
? viewsRaw.filter((view) => typeof view?.title === "string")
|
|
2473
|
+
: [];
|
|
2205
2474
|
const tocHiddenRaw = remarkPluginFrontmatter?.${TOC_HIDDEN_KEY};
|
|
2206
2475
|
const tocHidden = new Set(Array.isArray(tocHiddenRaw) ? tocHiddenRaw : []);
|
|
2207
2476
|
const headings =
|
|
@@ -2219,12 +2488,16 @@ const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
|
2219
2488
|
const ogPath = data.config.og.enabled
|
|
2220
2489
|
? encodeURI(\`/og/\${route === "/" ? "index" : route.slice(1)}.png\`)
|
|
2221
2490
|
: null;
|
|
2222
|
-
const ogRel = seo.image ?? ogPath;
|
|
2223
2491
|
// Absolute URLs also carry the deployment base (the page is served under it):
|
|
2224
2492
|
// \`site + base + path\`. Only absolutize root-relative paths: \`seo.image\` may be
|
|
2225
|
-
// an external URL, which passes through verbatim (mirrors PageLayout).
|
|
2226
|
-
|
|
2227
|
-
|
|
2493
|
+
// an external URL, which passes through verbatim (mirrors PageLayout). An
|
|
2494
|
+
// authored \`seo.image\` keeps a base written by hand; the generated card is
|
|
2495
|
+
// always mounted under it.
|
|
2496
|
+
const absoluteOg = (path: string, based: (path: string) => string) =>
|
|
2497
|
+
base && path.startsWith("/") ? \`\${base}\${based(path)}\` : path;
|
|
2498
|
+
const ogImage = seo.image
|
|
2499
|
+
? absoluteOg(seo.image, withBase)
|
|
2500
|
+
: ogPath && absoluteOg(ogPath, withMountedBase);
|
|
2228
2501
|
// Blume's generated card has known dimensions the layout can declare; a user's
|
|
2229
2502
|
// \`seo.image\` could be any size or format, so it gets none.
|
|
2230
2503
|
const ogGenerated = !seo.image && Boolean(ogPath);
|
|
@@ -2233,7 +2506,7 @@ const ogGenerated = !seo.image && Boolean(ogPath);
|
|
|
2233
2506
|
// itself (a guest post crediting its own author) over the configured default.
|
|
2234
2507
|
const x = { ...data.config.x, ...(seo.x?.creator ? { creator: seo.x.creator } : {}) };
|
|
2235
2508
|
|
|
2236
|
-
const basedRoute =
|
|
2509
|
+
const basedRoute = withMountedBase(route);
|
|
2237
2510
|
|
|
2238
2511
|
// Locale resolution. With i18n on, pick the active locale's nav + dictionary,
|
|
2239
2512
|
// build hreflang alternates, and derive the language-switcher targets.
|
|
@@ -2276,12 +2549,20 @@ const htmlLang = i18n ? locale : "en";
|
|
|
2276
2549
|
// follows that language — not the (mirrored) page locale.
|
|
2277
2550
|
const contentLocale =
|
|
2278
2551
|
fallback && i18n?.fallbackLocale ? i18n.fallbackLocale : locale;
|
|
2552
|
+
// "Listen to this page", unless the page opts out. The spoken cues are read
|
|
2553
|
+
// between the content's own sentences, so they come from the content's
|
|
2554
|
+
// language (a fallback page's), while the player's labels follow the page.
|
|
2555
|
+
// A \`custom\` or \`frame\` page brings its own heading: no title, description,
|
|
2556
|
+
// or narration player above its content.
|
|
2557
|
+
const pageChrome = pageModeLayout(frontmatter.mode).chrome;
|
|
2558
|
+
const narration = pageChrome && frontmatter.narration ? data.config.narration : null;
|
|
2559
|
+
const narrationCues = (i18n ? (data.uiByLocale[contentLocale] ?? data.ui) : data.ui).narration;
|
|
2279
2560
|
const contentDir = i18n
|
|
2280
2561
|
? (i18n.locales.find((l) => l.code === contentLocale)?.dir ?? "ltr")
|
|
2281
2562
|
: "ltr";
|
|
2282
2563
|
// The root route keeps its trailing slash (\`https://site/\`) so canonical and
|
|
2283
2564
|
// hreflang URLs byte-match the sitemap's <loc> for the home page.
|
|
2284
|
-
const absolute = (path: string) => base +
|
|
2565
|
+
const absolute = (path: string) => base + withMountedBase(path);
|
|
2285
2566
|
|
|
2286
2567
|
// A fallback page renders the fallback locale's page at this locale's URL, so
|
|
2287
2568
|
// its canonical names the page it copies, and search engines never rank the
|
|
@@ -2326,7 +2607,7 @@ const xDefault = defaultAlt && base ? absolute(defaultAlt.path) : null;
|
|
|
2326
2607
|
// carries sits *after* the base (\`/docs/ja/guide\`), while \`localePrefix\` is
|
|
2327
2608
|
// base-less (\`/ja\`). Stripping and re-adding a locale therefore happen in
|
|
2328
2609
|
// base-less space, with the base re-applied at the end — the same
|
|
2329
|
-
// \`
|
|
2610
|
+
// \`mountBasePath(basePath, localizeRoute(...))\` composition the manifest uses to
|
|
2330
2611
|
// build every real route. Done in based space, \`stripLocale\` matches nothing
|
|
2331
2612
|
// and \`localizeRoute\` prepends a second prefix (\`/ja/docs/ja/guide\`). Only a
|
|
2332
2613
|
// switcher entry for a locale with no real translation reaches this fallback:
|
|
@@ -2334,7 +2615,7 @@ const xDefault = defaultAlt && base ? absolute(defaultAlt.path) : null;
|
|
|
2334
2615
|
// generated reference (which has no \`alternates\` at all) for every locale
|
|
2335
2616
|
// but its own.
|
|
2336
2617
|
const mountLocalized = (logical: string, codeArg: string) =>
|
|
2337
|
-
|
|
2618
|
+
mountBasePath(data.config.basePath, localizeRoute(logical, codeArg));
|
|
2338
2619
|
const logicalRoute = i18n
|
|
2339
2620
|
? stripLocale(stripBasePath(data.config.basePath, route), locale)
|
|
2340
2621
|
: route;
|
|
@@ -2363,7 +2644,7 @@ const versionRootFor = (id: string) => {
|
|
|
2363
2644
|
const logical = id ? \`/\${id}\` : "/";
|
|
2364
2645
|
return i18n
|
|
2365
2646
|
? mountLocalized(logical, locale)
|
|
2366
|
-
:
|
|
2647
|
+
: mountBasePath(data.config.basePath, logical);
|
|
2367
2648
|
};
|
|
2368
2649
|
const samePageSwitch = versionsConfig
|
|
2369
2650
|
? versionsConfig.switcher.redirect === "same-page"
|
|
@@ -2459,11 +2740,15 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
2459
2740
|
canonical={canonical}
|
|
2460
2741
|
editUrl={editUrl}
|
|
2461
2742
|
feedback={data.config.feedback}
|
|
2743
|
+
feedbackComments={data.config.feedbackComments}
|
|
2744
|
+
pagination={frontmatter.pagination}
|
|
2745
|
+
related={frontmatter.related}
|
|
2746
|
+
search={frontmatter.search}
|
|
2462
2747
|
exportPdf={${options.exportPdf}}
|
|
2463
2748
|
exportEpub={${options.exportEpub}}${
|
|
2464
2749
|
options.navFragments
|
|
2465
2750
|
? `
|
|
2466
|
-
navFragmentBase={
|
|
2751
|
+
navFragmentBase={withMountedBase(\`/blume-nav/\${version || "current"}/\${i18n && localePrefix(locale) ? locale : "default"}\`)}`
|
|
2467
2752
|
: ""
|
|
2468
2753
|
}
|
|
2469
2754
|
openInChat={data.config.openInChat}
|
|
@@ -2471,13 +2756,25 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
2471
2756
|
discovery={data.config.discovery}
|
|
2472
2757
|
siteUrl={data.config.site}
|
|
2473
2758
|
pageType={frontmatter.type}
|
|
2759
|
+
apiRail={remarkPluginFrontmatter?.${API_RAIL_KEY} === true}
|
|
2760
|
+
pageMode={frontmatter.mode}
|
|
2474
2761
|
published={frontmatter.date ?? frontmatter.changelog?.date ?? null}
|
|
2475
2762
|
lastModified={lastModified}
|
|
2476
2763
|
noindex={effectiveNoindex}
|
|
2477
2764
|
structuredDataEnabled={data.config.structuredData}
|
|
2478
2765
|
>
|
|
2479
|
-
<h1>{title}</h1>
|
|
2480
|
-
{frontmatter.description && <p class="text-lg text-muted-foreground">{frontmatter.description}</p>}
|
|
2766
|
+
{pageChrome && <h1>{title}</h1>}
|
|
2767
|
+
{pageChrome && frontmatter.description && <p class="text-lg text-muted-foreground">{frontmatter.description}</p>}
|
|
2768
|
+
{narration && (
|
|
2769
|
+
<NarrationPlayer
|
|
2770
|
+
audioBase={narration.generated ? withMountedBase("/blume-narration/audio/") : undefined}
|
|
2771
|
+
cues={narrationCues}
|
|
2772
|
+
lang={i18n ? contentLocale : htmlLang}
|
|
2773
|
+
manifest={narration.generated ? withMountedBase(encodeURI(\`/blume-narration/\${route === "/" ? "index" : route.slice(1)}.json\`)) : undefined}
|
|
2774
|
+
strings={ui.narration}
|
|
2775
|
+
/>
|
|
2776
|
+
)}
|
|
2777
|
+
{views.length > 1 && <ViewSwitcher label={ui.content.selectView} views={views} />}
|
|
2481
2778
|
<LocaleLinks locale={locale}>
|
|
2482
2779
|
<Content components={components} />
|
|
2483
2780
|
</LocaleLinks>
|
|
@@ -2516,7 +2813,7 @@ export const changelogIndexTemplate = (options: {
|
|
|
2516
2813
|
// Generated by Blume. Do not edit.
|
|
2517
2814
|
import { getCollection } from "astro:content";
|
|
2518
2815
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
2519
|
-
import {
|
|
2816
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2520
2817
|
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
2521
2818
|
import { resolveDateFormatOptions } from "blume/core/date-format.ts";
|
|
2522
2819
|
import { layoutOverrides } from "../generated/components.ts";
|
|
@@ -2615,7 +2912,7 @@ const items = changelogEntries.map((entry) => {
|
|
|
2615
2912
|
return {
|
|
2616
2913
|
date: date ? formatRowDate(date) : null,
|
|
2617
2914
|
dateTime: date ? date.toISOString().slice(0, 10) : null,
|
|
2618
|
-
href: route ?
|
|
2915
|
+
href: route ? withMountedBase(route) : null,
|
|
2619
2916
|
id: slugify(label),
|
|
2620
2917
|
label,
|
|
2621
2918
|
tag: entry.data.changelog?.category ?? null,
|
|
@@ -2651,14 +2948,14 @@ for (const item of items) {
|
|
|
2651
2948
|
|
|
2652
2949
|
const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
2653
2950
|
// The canonical URL carries the deployment base (the page is served under it),
|
|
2654
|
-
// matching how the catch-all canonicalizes via \`
|
|
2655
|
-
const basedRoute =
|
|
2951
|
+
// matching how the catch-all canonicalizes via \`withMountedBase(route)\`.
|
|
2952
|
+
const basedRoute = withMountedBase("/changelog");
|
|
2656
2953
|
const canonical = base ? base + basedRoute : null;
|
|
2657
2954
|
|
|
2658
2955
|
// The generated OG card for this route (the /og endpoint emits it alongside
|
|
2659
2956
|
// the content-route cards), absolutized like the catch-all's so crawlers get
|
|
2660
2957
|
// a full URL when the site is known.
|
|
2661
|
-
const ogPath = data.config.og.enabled ?
|
|
2958
|
+
const ogPath = data.config.og.enabled ? withMountedBase("/og/changelog.png") : null;
|
|
2662
2959
|
const ogImage = ogPath && base ? base + ogPath : ogPath;
|
|
2663
2960
|
|
|
2664
2961
|
// The page chrome (h1, title, description) comes from the translatable
|
|
@@ -2780,8 +3077,8 @@ export const notFoundPageTemplate = (): string => `---
|
|
|
2780
3077
|
// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
2781
3078
|
import Icon from "blume/components/Icon.astro";
|
|
2782
3079
|
import PageLayout from "blume/components/layout/PageLayout.astro";
|
|
2783
|
-
import {
|
|
2784
|
-
import {
|
|
3080
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
3081
|
+
import { mountBasePath } from "blume/core/base-path.ts";
|
|
2785
3082
|
import data from "blume:data";
|
|
2786
3083
|
|
|
2787
3084
|
export const prerender = true;
|
|
@@ -2805,14 +3102,14 @@ const htmlLang = i18n ? i18n.defaultLocale : "en";
|
|
|
2805
3102
|
// their resolved target when the section has no index page of its own.
|
|
2806
3103
|
const suggestions = [
|
|
2807
3104
|
...data.navigation.tabs.map((tab) => ({
|
|
2808
|
-
href:
|
|
3105
|
+
href: withMountedBase(tab.href ?? tab.path),
|
|
2809
3106
|
label: tab.label,
|
|
2810
3107
|
})),
|
|
2811
3108
|
...(data.config.discovery.sitemap
|
|
2812
|
-
? [{ href:
|
|
3109
|
+
? [{ href: withMountedBase("/sitemap.xml"), label: nf.sitemap }]
|
|
2813
3110
|
: []),
|
|
2814
3111
|
...(data.config.discovery.llmsTxt
|
|
2815
|
-
? [{ href:
|
|
3112
|
+
? [{ href: withMountedBase("/llms.txt"), label: nf.llms }]
|
|
2816
3113
|
: []),
|
|
2817
3114
|
];
|
|
2818
3115
|
|
|
@@ -2824,7 +3121,7 @@ const suggestions = [
|
|
|
2824
3121
|
// Localized routes sit under both bases (\`{deployment.base}/{basePath}/ar/…\`),
|
|
2825
3122
|
// so the script strips the two together, trailing slash included.
|
|
2826
3123
|
const { basePath } = data.config;
|
|
2827
|
-
const siteRoot =
|
|
3124
|
+
const siteRoot = withMountedBase(mountBasePath(basePath, "/"));
|
|
2828
3125
|
const localeBase = siteRoot.endsWith("/") ? siteRoot : siteRoot + "/";
|
|
2829
3126
|
const localized = Object.fromEntries(
|
|
2830
3127
|
(i18n?.locales ?? [])
|
|
@@ -2837,7 +3134,7 @@ const localized = Object.fromEntries(
|
|
|
2837
3134
|
description: strings.description,
|
|
2838
3135
|
dir: l.dir ?? "ltr",
|
|
2839
3136
|
home: strings.home,
|
|
2840
|
-
homeHref:
|
|
3137
|
+
homeHref: withMountedBase(mountBasePath(basePath, "/" + l.code)),
|
|
2841
3138
|
suggestions: strings.suggestions,
|
|
2842
3139
|
title: strings.title,
|
|
2843
3140
|
},
|
|
@@ -2887,7 +3184,7 @@ const localizedJson = JSON.stringify(localized).replaceAll("<", "\\\\u003c");
|
|
|
2887
3184
|
<a
|
|
2888
3185
|
class="mt-8 inline-flex items-center gap-1.5 rounded-full bg-accent py-2 pe-4 ps-3.5 text-sm font-medium text-accent-foreground transition-opacity hover:opacity-90"
|
|
2889
3186
|
data-nf-home
|
|
2890
|
-
href={
|
|
3187
|
+
href={withMountedBase("/")}
|
|
2891
3188
|
>
|
|
2892
3189
|
<Icon class="rtl:-scale-x-100" name="arrow-left" size={14} />
|
|
2893
3190
|
<span data-nf="home">{nf.home}</span>
|
|
@@ -2969,7 +3266,7 @@ const localizedJson = JSON.stringify(localized).replaceAll("<", "\\\\u003c");
|
|
|
2969
3266
|
*/
|
|
2970
3267
|
export const notFoundMarkdownTemplate =
|
|
2971
3268
|
(): string => `// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
2972
|
-
import {
|
|
3269
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2973
3270
|
import { absoluteUrl } from "blume/core/site-url.ts";
|
|
2974
3271
|
import data from "blume:data";
|
|
2975
3272
|
|
|
@@ -2980,7 +3277,7 @@ const nf = data.ui.notFound;
|
|
|
2980
3277
|
// Absolute for internal routes when the site is known; an external tab href
|
|
2981
3278
|
// passes through untouched.
|
|
2982
3279
|
const href = (path: string): string => {
|
|
2983
|
-
const based =
|
|
3280
|
+
const based = withMountedBase(path);
|
|
2984
3281
|
return data.config.site && based.startsWith("/") && !based.startsWith("//")
|
|
2985
3282
|
? absoluteUrl(data.config.site, based)
|
|
2986
3283
|
: based;
|
|
@@ -3039,7 +3336,7 @@ export function GET() {
|
|
|
3039
3336
|
export const notFoundJsonTemplate =
|
|
3040
3337
|
(): string => `// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
3041
3338
|
import { problem } from "blume/ai/api/problem.ts";
|
|
3042
|
-
import {
|
|
3339
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
3043
3340
|
import { absoluteUrl } from "blume/core/site-url.ts";
|
|
3044
3341
|
import data from "blume:data";
|
|
3045
3342
|
|
|
@@ -3050,7 +3347,7 @@ const nf = data.ui.notFound;
|
|
|
3050
3347
|
// Absolute for internal routes when the site is known; an external tab href
|
|
3051
3348
|
// passes through untouched.
|
|
3052
3349
|
const href = (path: string): string => {
|
|
3053
|
-
const based =
|
|
3350
|
+
const based = withMountedBase(path);
|
|
3054
3351
|
return data.config.site && based.startsWith("/") && !based.startsWith("//")
|
|
3055
3352
|
? absoluteUrl(data.config.site, based)
|
|
3056
3353
|
: based;
|
|
@@ -3225,7 +3522,7 @@ ${wrapperPropsType("Example")}
|
|
|
3225
3522
|
/**
|
|
3226
3523
|
* The route prefix `<Component />` preview frames are served under:
|
|
3227
3524
|
* `{basePath}/blume-examples/<example path>`. `deployment.base` is layered on
|
|
3228
|
-
* top by Astro (components apply it with `
|
|
3525
|
+
* top by Astro (components apply it with `withMountedBase`).
|
|
3229
3526
|
*/
|
|
3230
3527
|
export const examplesRouteBase = (basePath: string): string =>
|
|
3231
3528
|
`${basePath}/blume-examples`;
|