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
|
@@ -4,10 +4,14 @@ import { useEffect, useRef, useState } from "react";
|
|
|
4
4
|
import type { FormEvent, KeyboardEvent as ReactKeyboardEvent } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
6
|
|
|
7
|
+
import type { CaptchaSettings } from "../../captcha/schema.ts";
|
|
7
8
|
import type { UIStrings } from "../../core/i18n-ui.ts";
|
|
8
9
|
import { copyText } from "../copy-feedback.ts";
|
|
9
|
-
import { joinBase,
|
|
10
|
+
import { joinBase, mountBase } from "./base-path.ts";
|
|
11
|
+
import { splitCode, withCode } from "./code-question.ts";
|
|
12
|
+
import type { CodeAttachment } from "./code-question.ts";
|
|
10
13
|
import { useAssistant } from "./hooks.ts";
|
|
14
|
+
import { supportHref } from "./support-link.ts";
|
|
11
15
|
|
|
12
16
|
/** A resolved empty-state prompt; `icon` is ready-to-inline SVG (or null). */
|
|
13
17
|
interface Suggestion {
|
|
@@ -25,6 +29,8 @@ interface AssistantIcons {
|
|
|
25
29
|
clear: string;
|
|
26
30
|
close: string;
|
|
27
31
|
copy: string;
|
|
32
|
+
/** The attached code chip's dismiss glyph. */
|
|
33
|
+
remove?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
// Empty bodies so the island still renders (iconless) if instantiated without
|
|
@@ -45,11 +51,18 @@ const DEFAULT_ASK: UIStrings["assistant"] = {
|
|
|
45
51
|
copy: "Copy conversation",
|
|
46
52
|
empty: "Ask a question about the docs.",
|
|
47
53
|
error: "Sorry, something went wrong.",
|
|
54
|
+
explainCode: "Explain this code.",
|
|
48
55
|
label: "Ask a question",
|
|
56
|
+
open: "Open assistant",
|
|
49
57
|
placeholder: "Ask a question…",
|
|
58
|
+
rateLimited: "You've asked a lot of questions. Try again in a few minutes.",
|
|
59
|
+
removeCode: "Remove code",
|
|
50
60
|
send: "Send",
|
|
61
|
+
support: "Contact support",
|
|
62
|
+
supportSubject: "Question from the docs",
|
|
51
63
|
tip: "Tip: You can open and close chat with",
|
|
52
64
|
title: "Assistant",
|
|
65
|
+
verifyFailed: "We couldn't check that you're human. Try again.",
|
|
53
66
|
you: "You",
|
|
54
67
|
};
|
|
55
68
|
|
|
@@ -65,11 +78,12 @@ const markdown = new Marked({
|
|
|
65
78
|
breaks: true,
|
|
66
79
|
gfm: true,
|
|
67
80
|
// The model cites pages as base-less logical routes (`[Title](/route)`); rewrite
|
|
68
|
-
// link targets to served URLs so citations resolve under `deployment.base
|
|
69
|
-
//
|
|
81
|
+
// link targets to served URLs so citations resolve under `deployment.base`,
|
|
82
|
+
// even a route that starts with the base's own name. `mountBase` leaves
|
|
83
|
+
// external URLs and fragments untouched.
|
|
70
84
|
walkTokens: (token) => {
|
|
71
85
|
if (token.type === "link") {
|
|
72
|
-
token.href =
|
|
86
|
+
token.href = mountBase(import.meta.env.BASE_URL, token.href);
|
|
73
87
|
}
|
|
74
88
|
},
|
|
75
89
|
});
|
|
@@ -139,22 +153,54 @@ const ICON_BUTTON_CLASS =
|
|
|
139
153
|
const ANSWER_CLASS =
|
|
140
154
|
"prose prose-sm max-w-none text-foreground [&_a]:inline-flex [&_a]:items-center [&_a]:gap-1 [&_a]:rounded-full [&_a]:bg-muted [&_a]:px-2 [&_a]:py-1 [&_a]:align-middle [&_a]:font-medium [&_a]:text-[0.7rem] [&_a]:leading-none [&_a]:text-muted-foreground! [&_a]:no-underline! [&_a:hover]:text-foreground!";
|
|
141
155
|
|
|
156
|
+
/** A reader's message bubble. */
|
|
157
|
+
const USER_MESSAGE_CLASS =
|
|
158
|
+
"rounded-blume bg-muted text-foreground max-w-[85%] self-end px-3 py-2 text-sm whitespace-pre-wrap";
|
|
159
|
+
|
|
160
|
+
/** What `blume:open-assistant` may carry. */
|
|
161
|
+
interface OpenAssistantDetail {
|
|
162
|
+
code?: CodeAttachment;
|
|
163
|
+
query?: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** A reader's message, with any code they asked about shown as a block. */
|
|
167
|
+
const UserMessage = ({ content }: { content: string }) => {
|
|
168
|
+
const { code, text } = splitCode(content);
|
|
169
|
+
if (!code) {
|
|
170
|
+
return <div className={USER_MESSAGE_CLASS}>{text}</div>;
|
|
171
|
+
}
|
|
172
|
+
return (
|
|
173
|
+
<div className={USER_MESSAGE_CLASS}>
|
|
174
|
+
{text}
|
|
175
|
+
<pre className="bg-background mt-2 max-h-40 overflow-auto rounded-md p-2 font-mono text-xs whitespace-pre">
|
|
176
|
+
{code.source}
|
|
177
|
+
</pre>
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
|
|
142
182
|
const Assistant = ({
|
|
183
|
+
captcha,
|
|
143
184
|
endpoint = DEFAULT_ASK_ENDPOINT,
|
|
144
185
|
icons = EMPTY_ICONS,
|
|
145
186
|
strings,
|
|
146
187
|
suggestions = EMPTY_SUGGESTIONS,
|
|
188
|
+
support,
|
|
147
189
|
}: {
|
|
190
|
+
captcha?: CaptchaSettings;
|
|
148
191
|
endpoint?: string;
|
|
149
192
|
icons?: AssistantIcons;
|
|
150
193
|
strings?: UIStrings["assistant"];
|
|
151
194
|
suggestions?: Suggestion[];
|
|
195
|
+
support?: string;
|
|
152
196
|
}) => {
|
|
153
197
|
// Merge per key (not `strings ?? …`) so a dictionary from a stale snapshot
|
|
154
198
|
// that predates newer keys still resolves every label to its English default.
|
|
155
199
|
const t = { ...DEFAULT_ASK, ...strings };
|
|
156
200
|
const [open, setOpen] = useState(false);
|
|
157
201
|
const [input, setInput] = useState("");
|
|
202
|
+
// A code block the reader is asking about, sent with the next question.
|
|
203
|
+
const [code, setCode] = useState<CodeAttachment | null>(null);
|
|
158
204
|
// The streaming client — request shaping, optimistic assistant bubble,
|
|
159
205
|
// stale-stream/abort guards, error-body handling — is the public useAssistant
|
|
160
206
|
// hook, so the built-in panel and custom UIs share one implementation.
|
|
@@ -163,7 +209,14 @@ const Assistant = ({
|
|
|
163
209
|
loading: busy,
|
|
164
210
|
messages,
|
|
165
211
|
reset,
|
|
166
|
-
|
|
212
|
+
thread,
|
|
213
|
+
} = useAssistant({
|
|
214
|
+
captcha,
|
|
215
|
+
endpoint,
|
|
216
|
+
errorMessage: t.error,
|
|
217
|
+
rateLimitMessage: t.rateLimited,
|
|
218
|
+
verifyMessage: t.verifyFailed,
|
|
219
|
+
});
|
|
167
220
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
168
221
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
169
222
|
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
@@ -192,14 +245,18 @@ const Assistant = ({
|
|
|
192
245
|
return () => document.removeEventListener("astro:after-swap", onSwap);
|
|
193
246
|
}, []);
|
|
194
247
|
|
|
195
|
-
// The search modal forwards its query so "Assistant: <query>" carries
|
|
248
|
+
// The search modal forwards its query so "Assistant: <query>" carries
|
|
249
|
+
// straight in, and a code block's Ask button attaches its code.
|
|
196
250
|
useEffect(() => {
|
|
197
251
|
const handler = (event: Event) => {
|
|
198
252
|
// SAFETY: `blume:open-assistant` is only ever dispatched as a CustomEvent
|
|
199
|
-
// whose optional detail carries the search query.
|
|
200
|
-
const
|
|
201
|
-
if (query) {
|
|
202
|
-
setInput(query);
|
|
253
|
+
// whose optional detail carries the search query or a code block.
|
|
254
|
+
const { detail } = event as CustomEvent<OpenAssistantDetail | null>;
|
|
255
|
+
if (detail?.query) {
|
|
256
|
+
setInput(detail.query);
|
|
257
|
+
}
|
|
258
|
+
if (detail?.code) {
|
|
259
|
+
setCode(detail.code);
|
|
203
260
|
}
|
|
204
261
|
setOpen(true);
|
|
205
262
|
};
|
|
@@ -262,6 +319,22 @@ const Assistant = ({
|
|
|
262
319
|
};
|
|
263
320
|
}, [open]);
|
|
264
321
|
|
|
322
|
+
// Stamp the incoming body before the swap installs it, as the theme and
|
|
323
|
+
// banner scripts do for <html>. Stamped only after the swap (below, in a
|
|
324
|
+
// passive effect), the new body would first paint without the push padding,
|
|
325
|
+
// replaying its transition on every navigation with the panel docked.
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
if (!open) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const onBeforeSwap = (event: DocumentEventMap["astro:before-swap"]) => {
|
|
331
|
+
event.newDocument.body.dataset.blumeAssistant = "open";
|
|
332
|
+
};
|
|
333
|
+
document.addEventListener("astro:before-swap", onBeforeSwap);
|
|
334
|
+
return () =>
|
|
335
|
+
document.removeEventListener("astro:before-swap", onBeforeSwap);
|
|
336
|
+
}, [open]);
|
|
337
|
+
|
|
265
338
|
// Re-stamp the push attribute after a swap while the panel is open — the new
|
|
266
339
|
// body arrives without it. Deliberately separate from the effect above: a
|
|
267
340
|
// navigation must not re-run the focus handling and yank focus out of the
|
|
@@ -349,12 +422,14 @@ const Assistant = ({
|
|
|
349
422
|
}, [messages, portalTarget]);
|
|
350
423
|
|
|
351
424
|
const runQuestion = (raw: string) => {
|
|
352
|
-
|
|
425
|
+
// A question about attached code may leave the words to us.
|
|
426
|
+
const question = raw.trim() || (code ? t.explainCode : "");
|
|
353
427
|
if (!question || busy) {
|
|
354
428
|
return;
|
|
355
429
|
}
|
|
356
|
-
void ask(question);
|
|
430
|
+
void ask(code ? withCode(question, code) : question);
|
|
357
431
|
setInput("");
|
|
432
|
+
setCode(null);
|
|
358
433
|
};
|
|
359
434
|
|
|
360
435
|
const clearConversation = () => {
|
|
@@ -447,13 +522,11 @@ const Assistant = ({
|
|
|
447
522
|
last entry while streaming, or clears wholesale on reset. */}
|
|
448
523
|
{messages.map((message, index) =>
|
|
449
524
|
message.role === "user" ? (
|
|
450
|
-
<
|
|
451
|
-
|
|
525
|
+
<UserMessage
|
|
526
|
+
content={message.content}
|
|
452
527
|
// oxlint-disable-next-line react/no-array-index-key -- append-only list, see above
|
|
453
528
|
key={index}
|
|
454
|
-
|
|
455
|
-
{message.content}
|
|
456
|
-
</div>
|
|
529
|
+
/>
|
|
457
530
|
) : (
|
|
458
531
|
// oxlint-disable-next-line react/no-array-index-key -- append-only list, see above
|
|
459
532
|
<div className={ANSWER_CLASS} key={index}>
|
|
@@ -474,6 +547,23 @@ const Assistant = ({
|
|
|
474
547
|
</div>
|
|
475
548
|
)
|
|
476
549
|
)}
|
|
550
|
+
{support && !busy && (
|
|
551
|
+
<a
|
|
552
|
+
className="text-muted-foreground hover:text-foreground self-start text-xs underline underline-offset-2 transition-colors"
|
|
553
|
+
href={supportHref(support, {
|
|
554
|
+
ai: t.ai,
|
|
555
|
+
messages,
|
|
556
|
+
subject: t.supportSubject,
|
|
557
|
+
thread,
|
|
558
|
+
you: t.you,
|
|
559
|
+
})}
|
|
560
|
+
{...(support.startsWith("mailto:") || support.startsWith("/")
|
|
561
|
+
? {}
|
|
562
|
+
: { rel: "noopener noreferrer", target: "_blank" })}
|
|
563
|
+
>
|
|
564
|
+
{t.support}
|
|
565
|
+
</a>
|
|
566
|
+
)}
|
|
477
567
|
</div>
|
|
478
568
|
) : (
|
|
479
569
|
<div className="mt-auto flex flex-col gap-0.5 p-4">
|
|
@@ -514,6 +604,21 @@ const Assistant = ({
|
|
|
514
604
|
className="border-border relative shrink-0 border-t"
|
|
515
605
|
onSubmit={onSubmit}
|
|
516
606
|
>
|
|
607
|
+
{code && (
|
|
608
|
+
<div className="flex items-center gap-1.5 px-4 pt-3">
|
|
609
|
+
<span className="rounded-blume bg-muted text-muted-foreground max-w-full truncate px-2 py-1 font-mono text-xs">
|
|
610
|
+
{code.title || code.language || t.explainCode}
|
|
611
|
+
</span>
|
|
612
|
+
<button
|
|
613
|
+
aria-label={t.removeCode}
|
|
614
|
+
className={ICON_BUTTON_CLASS}
|
|
615
|
+
onClick={() => setCode(null)}
|
|
616
|
+
type="button"
|
|
617
|
+
>
|
|
618
|
+
<Glyph path={icons.remove ?? ""} size={14} />
|
|
619
|
+
</button>
|
|
620
|
+
</div>
|
|
621
|
+
)}
|
|
517
622
|
<textarea
|
|
518
623
|
aria-label={t.label}
|
|
519
624
|
className="text-foreground placeholder:text-muted-foreground max-h-48 min-h-[5rem] w-full resize-none bg-transparent px-4 py-3.5 pe-14 text-sm outline-none pointer-coarse:text-base"
|
|
@@ -527,7 +632,7 @@ const Assistant = ({
|
|
|
527
632
|
<button
|
|
528
633
|
aria-label={t.send}
|
|
529
634
|
className="rounded-blume bg-foreground text-background absolute end-3 bottom-3 inline-flex h-8 w-8 cursor-pointer items-center justify-center transition-opacity disabled:cursor-not-allowed disabled:opacity-40"
|
|
530
|
-
disabled={busy || input.trim().length === 0}
|
|
635
|
+
disabled={busy || (input.trim().length === 0 && !code)}
|
|
531
636
|
type="submit"
|
|
532
637
|
>
|
|
533
638
|
<Glyph path={icons.arrowUp} />
|
|
@@ -542,6 +647,8 @@ const Assistant = ({
|
|
|
542
647
|
aria-expanded={open}
|
|
543
648
|
aria-label={t.title}
|
|
544
649
|
className={TRIGGER_CLASS}
|
|
650
|
+
// Named by the header's tooltip, like the buttons beside it.
|
|
651
|
+
data-blume-tooltip={t.open}
|
|
545
652
|
onClick={() => setOpen((value) => !value)}
|
|
546
653
|
ref={triggerRef}
|
|
547
654
|
type="button"
|
|
@@ -13,20 +13,50 @@ export const withTrailingSlash = (base: string): string =>
|
|
|
13
13
|
export const joinBase = (base: string, path: string): string =>
|
|
14
14
|
`${withTrailingSlash(base)}${path}`;
|
|
15
15
|
|
|
16
|
+
/** A root-relative internal target (`/x`) — never `//host` or a URL. */
|
|
17
|
+
const isRootRelative = (route: string): boolean =>
|
|
18
|
+
route.startsWith("/") && !route.startsWith("//");
|
|
19
|
+
|
|
20
|
+
/** A target's path, without its `?query` or `#fragment`. */
|
|
21
|
+
const pathOf = (route: string): string => {
|
|
22
|
+
const at = route.search(/[#?]/u);
|
|
23
|
+
return at === -1 ? route : route.slice(0, at);
|
|
24
|
+
};
|
|
25
|
+
|
|
16
26
|
/**
|
|
17
|
-
* Prefix a root-relative internal
|
|
18
|
-
* (`/guide` under base `/sub` -> `/sub/guide`), so
|
|
27
|
+
* Prefix a root-relative internal link an author wrote with the deployment
|
|
28
|
+
* base (`/guide` under base `/sub` -> `/sub/guide`), so it points at the
|
|
19
29
|
* page's real served URL. External URLs, protocol-relative URLs, and fragments
|
|
20
|
-
* pass through untouched, and it's idempotent
|
|
21
|
-
*
|
|
22
|
-
*
|
|
30
|
+
* pass through untouched, and it's idempotent: a link whose path is already
|
|
31
|
+
* under the base (`/sub/guide`, `/sub#install`) is returned unchanged, so a
|
|
32
|
+
* base written by hand isn't doubled. A route Blume generates takes
|
|
33
|
+
* {@link mountBase} instead. This is applied only where a URL is *emitted* —
|
|
34
|
+
* the navigation model and active-route matching stay in base-less logical
|
|
35
|
+
* space.
|
|
23
36
|
*/
|
|
24
37
|
export const prefixBase = (base: string, route: string): string => {
|
|
25
|
-
if (!
|
|
38
|
+
if (!isRootRelative(route)) {
|
|
26
39
|
return route;
|
|
27
40
|
}
|
|
28
41
|
const trimmed = base.replace(/\/+$/u, "");
|
|
29
|
-
|
|
42
|
+
const path = pathOf(route);
|
|
43
|
+
if (!trimmed || path === trimmed || path.startsWith(`${trimmed}/`)) {
|
|
44
|
+
return route;
|
|
45
|
+
}
|
|
46
|
+
return route === "/" ? trimmed : `${trimmed}${route}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Prefix a route Blume generates (a page, a sidebar entry, a Markdown mirror,
|
|
51
|
+
* an agent artifact) with the deployment base, unconditionally. Unlike
|
|
52
|
+
* {@link prefixBase}, a route whose first segment matches the base is still
|
|
53
|
+
* prefixed: under base `/guides`, the page `guides/setup.md` is served at
|
|
54
|
+
* `/guides/guides/setup`, not at `/guides/setup`. External and
|
|
55
|
+
* protocol-relative URLs pass through untouched.
|
|
56
|
+
*/
|
|
57
|
+
export const mountBase = (base: string, route: string): string => {
|
|
58
|
+
const trimmed = base.replace(/\/+$/u, "");
|
|
59
|
+
if (!(trimmed && isRootRelative(route))) {
|
|
30
60
|
return route;
|
|
31
61
|
}
|
|
32
62
|
return route === "/" ? trimmed : `${trimmed}${route}`;
|
|
@@ -34,13 +64,20 @@ export const prefixBase = (base: string, route: string): string => {
|
|
|
34
64
|
|
|
35
65
|
/**
|
|
36
66
|
* {@link prefixBase} bound to the build-time `BASE_URL` (the resolved
|
|
37
|
-
* `deployment.base`). The ergonomic form for
|
|
38
|
-
* withBase(
|
|
39
|
-
* is bundled into the site.
|
|
67
|
+
* `deployment.base`), for links an author wrote. The ergonomic form for
|
|
68
|
+
* `.astro` templates — `href={withBase(href)}` — since `BASE_URL` is inlined
|
|
69
|
+
* by Vite wherever this module is bundled into the site.
|
|
40
70
|
*/
|
|
41
71
|
export const withBase = (route: string): string =>
|
|
42
72
|
prefixBase(import.meta.env.BASE_URL ?? "/", route);
|
|
43
73
|
|
|
74
|
+
/**
|
|
75
|
+
* {@link mountBase} bound to the build-time `BASE_URL`, for routes Blume
|
|
76
|
+
* generates: `href={withMountedBase(page.route)}`.
|
|
77
|
+
*/
|
|
78
|
+
export const withMountedBase = (route: string): string =>
|
|
79
|
+
mountBase(import.meta.env.BASE_URL ?? "/", route);
|
|
80
|
+
|
|
44
81
|
/**
|
|
45
82
|
* A pathname with the deployment base stripped (`/docs/guide` -> `/guide`),
|
|
46
83
|
* for page-context lookups against base-less document routes.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Questions about a code block. A code block's Ask button opens the assistant
|
|
3
|
+
* with the block attached (`blume:open-assistant` with `detail.code`); the
|
|
4
|
+
* question goes out with the code folded in as a fenced block after the
|
|
5
|
+
* reader's words, which is how the model sees it, and the conversation shows
|
|
6
|
+
* the two apart again.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** A code block the reader asked about. */
|
|
10
|
+
export interface CodeAttachment {
|
|
11
|
+
/** The fence language (`ts`), or empty when the block has none. */
|
|
12
|
+
language: string;
|
|
13
|
+
source: string;
|
|
14
|
+
/** The block's title (`server.ts`), when it has one. */
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The most code one question carries, well inside the route's budget. */
|
|
19
|
+
export const MAX_ATTACHED_CODE = 6000;
|
|
20
|
+
|
|
21
|
+
/** A user message, split into the reader's words and any attached code. */
|
|
22
|
+
export interface SplitQuestion {
|
|
23
|
+
code?: { language: string; source: string };
|
|
24
|
+
text: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** A fence longer than any backtick run in the code, so the code can't close it. */
|
|
28
|
+
const fenceFor = (source: string): string => {
|
|
29
|
+
const longest = Math.max(
|
|
30
|
+
2,
|
|
31
|
+
...[...source.matchAll(/`+/gu)].map(([run]) => run.length)
|
|
32
|
+
);
|
|
33
|
+
return "`".repeat(longest + 1);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** The question as sent: the reader's words, then the code as a fenced block. */
|
|
37
|
+
export const withCode = (question: string, code: CodeAttachment): string => {
|
|
38
|
+
const source =
|
|
39
|
+
code.source.length > MAX_ATTACHED_CODE
|
|
40
|
+
? `${code.source.slice(0, MAX_ATTACHED_CODE)}\n…`
|
|
41
|
+
: code.source.replace(/\n+$/u, "");
|
|
42
|
+
const fence = fenceFor(source);
|
|
43
|
+
return `${question}\n\n${fence}${code.language}\n${source}\n${fence}`;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const TRAILING_FENCE =
|
|
47
|
+
/\n\n(?<fence>`{3,})(?<language>[^\n`]*)\n(?<source>[\s\S]*)\n\k<fence>$/u;
|
|
48
|
+
|
|
49
|
+
/** A user message split back into the words and the attached code. */
|
|
50
|
+
export const splitCode = (content: string): SplitQuestion => {
|
|
51
|
+
const match = TRAILING_FENCE.exec(content);
|
|
52
|
+
if (!match?.groups) {
|
|
53
|
+
return { text: content };
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
code: {
|
|
57
|
+
language: match.groups.language ?? "",
|
|
58
|
+
source: match.groups.source ?? "",
|
|
59
|
+
},
|
|
60
|
+
text: content.slice(0, match.index),
|
|
61
|
+
};
|
|
62
|
+
};
|