blume 0.6.7 → 0.8.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/CHANGELOG.md +618 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/cli/index.js +2609 -1041
- package/dist/cli/index.js.map +110 -103
- package/dist/types/ai/component-markdown.d.ts +34 -0
- package/dist/types/components/content/youtube.d.ts +18 -0
- package/dist/types/core/base-path.d.ts +47 -0
- package/dist/types/core/config-input.d.ts +110 -12
- package/dist/types/core/config.d.ts +6 -4
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +477 -135
- package/dist/types/core/schema.d.ts +309 -195
- package/dist/types/core/sources/types.d.ts +2 -0
- package/dist/types/core/types.d.ts +6 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/openapi/references.d.ts +60 -0
- package/docs/01-quickstart.mdx +5 -2
- package/docs/02-deployment.mdx +24 -9
- package/docs/03-faq.mdx +46 -16
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/configuration/ai.mdx +49 -10
- package/docs/configuration/customization.mdx +11 -0
- package/docs/configuration/index.mdx +33 -3
- package/docs/configuration/seo.mdx +2 -2
- package/docs/content/components.mdx +30 -3
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/islands.mdx +8 -0
- package/docs/content/navigation.mdx +3 -3
- package/docs/content/sources.mdx +1 -1
- package/docs/content/syntax.mdx +17 -2
- package/docs/index.mdx +2 -2
- package/docs/reference/cli.mdx +8 -6
- package/package.json +15 -4
- package/skills/blume/SKILL.md +5 -3
- package/skills/blume-update-docs/SKILL.md +3 -2
- package/src/ai/agent-readability.ts +11 -5
- package/src/ai/ask-context.ts +7 -2
- package/src/ai/ask-data.ts +3 -0
- package/src/ai/ask.ts +12 -7
- package/src/ai/component-markdown.ts +461 -0
- package/src/ai/llms.ts +143 -23
- package/src/ai/markdown.ts +35 -6
- package/src/ai/mcp/data.ts +33 -8
- package/src/ai/mcp/discovery.ts +10 -3
- package/src/ai/mcp/server.ts +24 -7
- package/src/ai/visibility.ts +74 -0
- package/src/astro/component-slots.ts +16 -4
- package/src/astro/examples.ts +12 -7
- package/src/astro/generate.ts +393 -189
- package/src/astro/index.ts +5 -1
- package/src/astro/integration.ts +9 -5
- package/src/astro/islands.ts +11 -5
- package/src/astro/markdown-negotiation.ts +2 -2
- package/src/astro/pages.ts +89 -22
- package/src/astro/templates.ts +259 -25
- package/src/blume-modules.d.ts +8 -0
- package/src/cli/commands/build.ts +131 -38
- package/src/cli/commands/check.ts +1 -1
- package/src/cli/commands/dev.ts +71 -17
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/eject.ts +47 -19
- package/src/cli/commands/init.ts +120 -180
- package/src/cli/commands/preview.ts +4 -1
- package/src/cli/commands/validate.ts +44 -2
- package/src/cli/dev-lock.ts +34 -19
- package/src/cli/eject-scripts.ts +72 -0
- package/src/cli/env.ts +15 -5
- package/src/cli/init/questions.ts +158 -0
- package/src/cli/init/scaffold.ts +380 -0
- package/src/cli/required-secrets.ts +2 -1
- package/src/components/content/AccordionItem.astro +23 -4
- package/src/components/content/Badge.astro +3 -1
- package/src/components/content/Card.astro +4 -2
- package/src/components/content/CodeBlock.astro +3 -0
- package/src/components/content/Component.astro +30 -16
- package/src/components/content/Diff.astro +3 -1
- package/src/components/content/Step.astro +10 -1
- package/src/components/content/Tabs.astro +15 -3
- package/src/components/content/Tile.astro +2 -1
- package/src/components/content/Tooltip.astro +3 -1
- package/src/components/content/Update.astro +9 -2
- package/src/components/content/auto-type-table.ts +25 -9
- package/src/components/content/base-href.ts +33 -0
- package/src/components/content/changelog-element.ts +9 -2
- package/src/components/content/diff.ts +12 -6
- package/src/components/content/mermaid-element.ts +10 -2
- package/src/components/index.ts +23 -1
- package/src/components/islands/AskAI.astro +5 -2
- package/src/components/islands/ask-ai.tsx +68 -12
- package/src/components/islands/base-path.ts +28 -0
- package/src/components/islands/hooks.ts +44 -9
- package/src/components/layout/Banner.astro +12 -3
- package/src/components/layout/Breadcrumbs.astro +2 -1
- package/src/components/layout/Favicon.astro +3 -2
- package/src/components/layout/Header.astro +15 -5
- package/src/components/layout/LanguageSwitcher.astro +2 -1
- package/src/components/layout/Logo.astro +13 -4
- package/src/components/layout/NavSelector.astro +2 -1
- package/src/components/layout/NavTree.astro +22 -7
- package/src/components/layout/PageActions.astro +25 -10
- package/src/components/layout/PageFeedback.astro +4 -1
- package/src/components/layout/PageLayout.astro +51 -9
- package/src/components/layout/Pagination.astro +3 -2
- package/src/components/layout/ReferenceLayout.astro +8 -1
- package/src/components/layout/RootLayout.astro +74 -13
- package/src/components/layout/Search.astro +107 -27
- package/src/components/layout/nav-utils.ts +18 -10
- package/src/components/layout/search/algolia.ts +11 -2
- package/src/components/layout/search/endpoint.ts +11 -5
- package/src/components/layout/search/orama-cloud.ts +8 -2
- package/src/components/layout/search/pagefind.ts +3 -0
- package/src/components/layout/search/types.ts +5 -1
- package/src/components/layout/search/typesense.ts +4 -1
- package/src/components/layout/toc-element.ts +8 -2
- package/src/components/openapi/ApiTagOperations.astro +2 -1
- package/src/components/openapi/Operation.astro +47 -40
- package/src/components/openapi/RequestPanel.astro +8 -2
- package/src/components/openapi/helpers.ts +71 -3
- package/src/components/openapi/panel.ts +1 -1
- package/src/components/openapi/snippets.ts +25 -11
- package/src/core/base-path.ts +94 -0
- package/src/core/builtin-tags.ts +2 -0
- package/src/core/component-overrides.ts +103 -74
- package/src/core/config-input.ts +118 -17
- package/src/core/config.ts +8 -5
- package/src/core/content.ts +2 -0
- package/src/core/data.ts +4 -0
- package/src/core/diagnostics.ts +54 -34
- package/src/core/gitignore.ts +4 -1
- package/src/core/graph.ts +166 -88
- package/src/core/i18n-ui.ts +63 -3
- package/src/core/last-modified.ts +15 -6
- package/src/core/links.ts +69 -25
- package/src/core/manifest.ts +62 -45
- package/src/core/nav-diagnostics.ts +1 -1
- package/src/core/navigation.ts +144 -58
- package/src/core/package-json.ts +17 -2
- package/src/core/project-graph.ts +25 -15
- package/src/core/schema.ts +605 -620
- package/src/core/sources/assets.ts +6 -1
- package/src/core/sources/filesystem.ts +4 -0
- package/src/core/sources/github-releases.ts +2 -1
- package/src/core/sources/mdx-remote.ts +76 -63
- package/src/core/sources/normalize.ts +236 -91
- package/src/core/sources/notion.ts +27 -18
- package/src/core/sources/types.ts +2 -0
- package/src/core/tsconfig-aliases.ts +59 -30
- package/src/core/types.ts +6 -1
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +2 -1
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -0
- package/src/deploy/adapter-output.ts +18 -8
- package/src/deploy/redirects.ts +25 -2
- package/src/deploy/robots.ts +6 -1
- package/src/deploy/rss.ts +10 -3
- package/src/deploy/sitemap.ts +59 -13
- package/src/index.ts +5 -0
- package/src/markdown/base-links.ts +60 -0
- package/src/markdown/code-title.ts +11 -14
- package/src/markdown/index.ts +46 -9
- package/src/markdown/inline-code.ts +14 -4
- package/src/markdown/package-commands.ts +10 -4
- package/src/markdown/themes.ts +24 -0
- package/src/openapi/model.ts +15 -5
- package/src/openapi/parse.ts +21 -0
- package/src/openapi/references.ts +75 -21
- package/src/openapi/render-mdx.ts +11 -6
- package/src/openapi/scalar.ts +32 -16
- package/src/openapi/source.ts +59 -10
- package/src/registry/eject.ts +247 -19
- package/src/registry/registry.ts +0 -3
- package/src/search/build.ts +3 -0
- package/src/search/documents.ts +36 -4
- package/src/search/sync/typesense.ts +6 -4
- package/src/seo/jsonld.ts +28 -17
- package/src/theme/entry.ts +85 -20
package/src/core/config-input.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
|
|
3
|
+
import type { ComponentMarkdown } from "../ai/component-markdown.ts";
|
|
3
4
|
import type { FontSlug } from "../theme/fonts.ts";
|
|
4
5
|
import type {
|
|
5
6
|
blumeConfigSchema,
|
|
@@ -315,11 +316,16 @@ export interface NavSelectorItem {
|
|
|
315
316
|
* A header dropdown for switching context — versions, languages, products, or a
|
|
316
317
|
* generic dropdown. `kind` drives the icon and a11y labeling.
|
|
317
318
|
*/
|
|
319
|
+
/** Context-partition selector kinds (a versioned/localized/multi-product site). */
|
|
320
|
+
type NavSelectorContextKind = "product" | "version";
|
|
321
|
+
/** What a header selector switches between. */
|
|
322
|
+
type NavSelectorKind = "dropdown" | "language" | NavSelectorContextKind;
|
|
323
|
+
|
|
318
324
|
export interface NavSelector {
|
|
319
325
|
/** The options shown in the dropdown. */
|
|
320
326
|
items?: NavSelectorItem[];
|
|
321
327
|
/** What the selector switches between. */
|
|
322
|
-
kind:
|
|
328
|
+
kind: NavSelectorKind;
|
|
323
329
|
/** Selector label / current value. */
|
|
324
330
|
label: string;
|
|
325
331
|
}
|
|
@@ -385,6 +391,11 @@ export interface FontsConfig {
|
|
|
385
391
|
}
|
|
386
392
|
|
|
387
393
|
/** Colors, fonts, radius, and color-mode behavior. */
|
|
394
|
+
/** Corner radius scale (`none`/`sm` tighter, `md`/`lg` rounder). */
|
|
395
|
+
type RadiusScaleTight = "none" | "sm";
|
|
396
|
+
type RadiusScaleRound = "md" | "lg";
|
|
397
|
+
type RadiusScale = RadiusScaleTight | RadiusScaleRound;
|
|
398
|
+
|
|
388
399
|
export interface ThemeConfig {
|
|
389
400
|
/**
|
|
390
401
|
* Accent color. A palette name (`blue`, `violet`, `green`, …) or any CSS
|
|
@@ -405,7 +416,7 @@ export interface ThemeConfig {
|
|
|
405
416
|
/** Initial color mode. Defaults to `system`. */
|
|
406
417
|
mode?: "system" | "light" | "dark";
|
|
407
418
|
/** Corner radius scale. Defaults to `md`. */
|
|
408
|
-
radius?:
|
|
419
|
+
radius?: RadiusScale;
|
|
409
420
|
}
|
|
410
421
|
|
|
411
422
|
// ---------------------------------------------------------------------------
|
|
@@ -477,6 +488,10 @@ export interface AskSuggestion {
|
|
|
477
488
|
}
|
|
478
489
|
|
|
479
490
|
/** The Ask AI chat assistant. */
|
|
491
|
+
/** Backends that can route an Ask AI request. */
|
|
492
|
+
type AskProviderGateway = "gateway" | "openrouter" | "llmgateway";
|
|
493
|
+
type AskProvider = AskProviderGateway | "inkeep" | "openai-compatible";
|
|
494
|
+
|
|
480
495
|
export interface AskConfig {
|
|
481
496
|
/**
|
|
482
497
|
* Name of the env var holding the provider API key. Each provider has a
|
|
@@ -493,22 +508,51 @@ export interface AskConfig {
|
|
|
493
508
|
/** Model id to use. Defaults to `openai/gpt-5.5`. */
|
|
494
509
|
model?: string;
|
|
495
510
|
/** Which backend routes the request. Defaults to `gateway`. */
|
|
496
|
-
provider?:
|
|
497
|
-
| "gateway"
|
|
498
|
-
| "openrouter"
|
|
499
|
-
| "llmgateway"
|
|
500
|
-
| "inkeep"
|
|
501
|
-
| "openai-compatible";
|
|
511
|
+
provider?: AskProvider;
|
|
502
512
|
/** Starter prompts shown before the first question. */
|
|
503
513
|
suggestions?: AskSuggestion[];
|
|
504
514
|
}
|
|
505
515
|
|
|
516
|
+
/** What the `llms.txt`/`llms-full.txt` files include. */
|
|
517
|
+
export interface LlmsTxtConfig {
|
|
518
|
+
/** Emit `llms.txt` and `llms-full.txt`. Defaults to `true`. */
|
|
519
|
+
enabled?: boolean;
|
|
520
|
+
/**
|
|
521
|
+
* Include the generated API reference pages (OpenAPI/AsyncAPI). Defaults to
|
|
522
|
+
* `true`; set `false` to keep a placeholder or example spec's pages out of
|
|
523
|
+
* the LLM-facing files.
|
|
524
|
+
*/
|
|
525
|
+
openapi?: boolean;
|
|
526
|
+
}
|
|
527
|
+
|
|
506
528
|
/** AI-facing features: the Ask AI assistant and an `llms.txt` manifest. */
|
|
507
529
|
export interface AiConfig {
|
|
508
530
|
/** The Ask AI chat assistant. */
|
|
509
531
|
ask?: AskConfig;
|
|
510
|
-
/**
|
|
511
|
-
|
|
532
|
+
/**
|
|
533
|
+
* Emit `llms.txt` (an index of the docs for LLMs). Defaults to `true`.
|
|
534
|
+
* The object form adds knobs for what the files include.
|
|
535
|
+
*/
|
|
536
|
+
llmsTxt?: boolean | LlmsTxtConfig;
|
|
537
|
+
/**
|
|
538
|
+
* Markdown serializers for custom components in agent-facing output (the
|
|
539
|
+
* `.md` mirror, `llms-full.txt`, MCP `get_page`), keyed by JSX name. Each
|
|
540
|
+
* receives the component's statically-evaluated `props` and downleveled
|
|
541
|
+
* `children` and returns replacement Markdown — or `null` to leave the JSX
|
|
542
|
+
* verbatim. A same-name entry replaces a built-in serializer.
|
|
543
|
+
*
|
|
544
|
+
* These live in `blume.config.ts` (which is executed at build time), not in
|
|
545
|
+
* `components.tsx` (which is only statically analyzed, never run).
|
|
546
|
+
*
|
|
547
|
+
* ```ts
|
|
548
|
+
* ai: {
|
|
549
|
+
* markdownComponents: {
|
|
550
|
+
* Chart: ({ props }) => ``,
|
|
551
|
+
* },
|
|
552
|
+
* }
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
markdownComponents?: Record<string, ComponentMarkdown>;
|
|
512
556
|
}
|
|
513
557
|
|
|
514
558
|
// ---------------------------------------------------------------------------
|
|
@@ -603,9 +647,13 @@ export interface I18nConfig {
|
|
|
603
647
|
* Where and how the site deploys. `site` (and `adapter`) are auto-detected from
|
|
604
648
|
* the platform env on Vercel, Netlify, and Cloudflare.
|
|
605
649
|
*/
|
|
650
|
+
/** Astro server-output adapters, by hosting platform. */
|
|
651
|
+
type CloudDeploymentAdapter = "netlify" | "cloudflare";
|
|
652
|
+
type DeploymentAdapter = "vercel" | "node" | CloudDeploymentAdapter;
|
|
653
|
+
|
|
606
654
|
export interface DeploymentConfig {
|
|
607
655
|
/** Astro adapter for server output. `null` (default) keeps a static build. */
|
|
608
|
-
adapter?:
|
|
656
|
+
adapter?: DeploymentAdapter | null;
|
|
609
657
|
/** Base path when the site is served from a subdirectory. */
|
|
610
658
|
base?: string;
|
|
611
659
|
/** Build output mode. Defaults to `static`. */
|
|
@@ -617,12 +665,17 @@ export interface DeploymentConfig {
|
|
|
617
665
|
site?: string;
|
|
618
666
|
}
|
|
619
667
|
|
|
668
|
+
/** HTTP redirect status codes: permanent (301/308) and temporary (302/307). */
|
|
669
|
+
type RedirectStatusPermanent = 301 | 308;
|
|
670
|
+
type RedirectStatusTemporary = 302 | 307;
|
|
671
|
+
type RedirectStatus = RedirectStatusPermanent | RedirectStatusTemporary;
|
|
672
|
+
|
|
620
673
|
/** A URL redirect rule. */
|
|
621
674
|
export interface RedirectConfig {
|
|
622
675
|
/** Path to redirect from. */
|
|
623
676
|
from: string;
|
|
624
677
|
/** HTTP status. Defaults to `301`. */
|
|
625
|
-
status?:
|
|
678
|
+
status?: RedirectStatus;
|
|
626
679
|
/** Path or URL to redirect to. */
|
|
627
680
|
to: string;
|
|
628
681
|
}
|
|
@@ -717,7 +770,10 @@ export interface CodeConfig {
|
|
|
717
770
|
export interface MarkdownConfig {
|
|
718
771
|
/** Code-block rendering: language icons, line wrap. */
|
|
719
772
|
code?: CodeConfig;
|
|
720
|
-
/**
|
|
773
|
+
/**
|
|
774
|
+
* Syntax-highlighting themes for every code surface — fenced blocks, inline
|
|
775
|
+
* `` `code`{:lang} ``, `<CodeBlock>`, and `<Diff>`.
|
|
776
|
+
*/
|
|
721
777
|
codeBlocks?: {
|
|
722
778
|
/** Shiki theme names per color mode. */
|
|
723
779
|
theme?: {
|
|
@@ -736,6 +792,16 @@ export interface MarkdownConfig {
|
|
|
736
792
|
imageZoom?: boolean;
|
|
737
793
|
}
|
|
738
794
|
|
|
795
|
+
/** React island behavior. */
|
|
796
|
+
export interface ReactConfig {
|
|
797
|
+
/**
|
|
798
|
+
* Auto-memoize React components/hooks with the React Compiler
|
|
799
|
+
* (`babel-plugin-react-compiler`). On by default whenever React is enabled;
|
|
800
|
+
* set to `false` to skip the compiler's babel pass. Defaults to `true`.
|
|
801
|
+
*/
|
|
802
|
+
compiler?: boolean;
|
|
803
|
+
}
|
|
804
|
+
|
|
739
805
|
// ---------------------------------------------------------------------------
|
|
740
806
|
// OpenAPI / AsyncAPI
|
|
741
807
|
// ---------------------------------------------------------------------------
|
|
@@ -787,6 +853,25 @@ export interface AsyncApiConfig {
|
|
|
787
853
|
// Misc top-level unions
|
|
788
854
|
// ---------------------------------------------------------------------------
|
|
789
855
|
|
|
856
|
+
/** `<Component />` example previews (the object form of `examples`). */
|
|
857
|
+
export interface ExamplesConfig {
|
|
858
|
+
/**
|
|
859
|
+
* A stylesheet, relative to the project root, injected into every preview
|
|
860
|
+
* frame after Blume's default tokens. Previews render inside an isolated
|
|
861
|
+
* iframe the docs styles never reach, so design tokens for the previewed
|
|
862
|
+
* components — shadcn variables, `@theme` mappings, custom fonts — live
|
|
863
|
+
* here. Tailwind is already provided in the frame; the file should hold
|
|
864
|
+
* tokens and styles, not another `@import "tailwindcss"`.
|
|
865
|
+
*/
|
|
866
|
+
css?: string;
|
|
867
|
+
/**
|
|
868
|
+
* Where example files live, relative to the project root. Defaults to
|
|
869
|
+
* `examples`; may be a glob to target a registry that colocates component
|
|
870
|
+
* sources with their examples (e.g. `registry/<pkg>/**\/examples/*`).
|
|
871
|
+
*/
|
|
872
|
+
source?: string;
|
|
873
|
+
}
|
|
874
|
+
|
|
790
875
|
/**
|
|
791
876
|
* Reader-facing "Export" page actions. A boolean toggles both formats; the
|
|
792
877
|
* object form enables each individually. Defaults to `false`.
|
|
@@ -843,6 +928,16 @@ export interface BlumeConfig {
|
|
|
843
928
|
asyncapi?: AsyncApiConfig;
|
|
844
929
|
/** Site-wide announcement banner shown above the header. */
|
|
845
930
|
banner?: BannerConfig;
|
|
931
|
+
/**
|
|
932
|
+
* Site-wide mount point prepended to every generated route (e.g. `/docs`) —
|
|
933
|
+
* pages, links, redirects, sitemap, OG images, `llms.txt`, and the search
|
|
934
|
+
* index — while staying invisible to the sidebar/nav tree (no wrapper group).
|
|
935
|
+
* Distinct from a per-source `prefix` (which namespaces one source *and*
|
|
936
|
+
* creates a group) and from `deployment.base` (Astro's host-subdirectory
|
|
937
|
+
* base, for serving the whole site — root included — from a subpath). The two
|
|
938
|
+
* compose: with both set, a page lands at `{deployment.base}/{basePath}/page`.
|
|
939
|
+
*/
|
|
940
|
+
basePath?: string;
|
|
846
941
|
/** Where content lives and how it's discovered. */
|
|
847
942
|
content?: ContentConfig;
|
|
848
943
|
/** Where and how the site deploys (site URL, adapter, output mode). */
|
|
@@ -850,11 +945,15 @@ export interface BlumeConfig {
|
|
|
850
945
|
/** Default meta description, used where a page sets none. */
|
|
851
946
|
description?: string;
|
|
852
947
|
/**
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* target a registry that colocates
|
|
948
|
+
* `<Component path>` example previews. A string is shorthand for
|
|
949
|
+
* `{ source }`: where examples live, relative to the project root (defaults
|
|
950
|
+
* to `examples`; may be a glob to target a registry that colocates
|
|
951
|
+
* component sources with their examples). The object form adds `css` — a
|
|
952
|
+
* stylesheet injected into every preview frame (previews render in an
|
|
953
|
+
* iframe the docs theme never reaches), for the previewed components'
|
|
954
|
+
* design tokens, e.g. shadcn variables.
|
|
856
955
|
*/
|
|
857
|
-
examples?: string;
|
|
956
|
+
examples?: string | ExamplesConfig;
|
|
858
957
|
/** Reader-facing PDF/EPUB export actions. Defaults to `false`. */
|
|
859
958
|
export?: ExportConfig;
|
|
860
959
|
/** Show the per-page "Was this helpful?" widget. Defaults to `true`. */
|
|
@@ -875,6 +974,8 @@ export interface BlumeConfig {
|
|
|
875
974
|
navigation?: NavigationConfig;
|
|
876
975
|
/** Native OpenAPI reference. */
|
|
877
976
|
openapi?: OpenApiConfig;
|
|
977
|
+
/** React island behavior (compiler auto-memoization). */
|
|
978
|
+
react?: ReactConfig;
|
|
878
979
|
/** URL redirect rules. */
|
|
879
980
|
redirects?: RedirectConfig[];
|
|
880
981
|
/** Search backend and credentials. */
|
package/src/core/config.ts
CHANGED
|
@@ -73,8 +73,9 @@ import type { Diagnostic } from "./types.ts";
|
|
|
73
73
|
* - `search` — search backend `provider` (`orama` by default; `pagefind`,
|
|
74
74
|
* `algolia`, `typesense`, `orama-cloud`, `mixedbread`, or `none`) plus its
|
|
75
75
|
* credential block.
|
|
76
|
-
* - `ai` — `ask` (the Ask AI chat endpoint and its provider/model)
|
|
77
|
-
* (emit `llms.txt`)
|
|
76
|
+
* - `ai` — `ask` (the Ask AI chat endpoint and its provider/model), `llmsTxt`
|
|
77
|
+
* (emit `llms.txt`), and `markdownComponents` (Markdown serializers for
|
|
78
|
+
* custom components in agent-facing output).
|
|
78
79
|
* - `mcp` — expose the docs as an MCP server for connecting agents.
|
|
79
80
|
*
|
|
80
81
|
* **SEO, feeds & analytics**
|
|
@@ -91,8 +92,9 @@ import type { Diagnostic } from "./types.ts";
|
|
|
91
92
|
* - `i18n` — opt-in multi-locale: `locales`, `defaultLocale`, `parser`
|
|
92
93
|
* (`dir` vs filename `dot` suffix), and per-locale UI overrides.
|
|
93
94
|
*
|
|
94
|
-
* - `examples` —
|
|
95
|
-
*
|
|
95
|
+
* - `examples` — `<Component path>` previews: `source` (default `examples/`;
|
|
96
|
+
* supports a glob for colocated registries) and `css`, a stylesheet injected
|
|
97
|
+
* into the isolated preview frames (e.g. shadcn variables).
|
|
96
98
|
*
|
|
97
99
|
* @example Zero-config — just render the Markdown under `docs/`.
|
|
98
100
|
* ```ts
|
|
@@ -197,11 +199,12 @@ export const loadConfig = async (
|
|
|
197
199
|
};
|
|
198
200
|
// Surface every issue in one failing run — reporting only the first turns
|
|
199
201
|
// a three-mistake config into three fix-rerun-fail loops.
|
|
202
|
+
const moreIssues = rest.map((d) => ` - ${d.message}`).join("\n");
|
|
200
203
|
throw new BlumeError(
|
|
201
204
|
rest.length > 0
|
|
202
205
|
? {
|
|
203
206
|
...primary,
|
|
204
|
-
message: `${primary.message}\n${rest.length} more config issue(s):\n${
|
|
207
|
+
message: `${primary.message}\n${rest.length} more config issue(s):\n${moreIssues}`,
|
|
205
208
|
}
|
|
206
209
|
: primary
|
|
207
210
|
);
|
package/src/core/content.ts
CHANGED
|
@@ -22,6 +22,7 @@ export const discoverContent = async (options: {
|
|
|
22
22
|
include: string[];
|
|
23
23
|
exclude: string[];
|
|
24
24
|
defaultType: string;
|
|
25
|
+
basePath?: string;
|
|
25
26
|
i18n?: ResolvedI18nConfig;
|
|
26
27
|
}): Promise<{ pages: PageRecord[]; diagnostics: Diagnostic[] }> => {
|
|
27
28
|
const source = filesystemSource({
|
|
@@ -38,6 +39,7 @@ export const discoverContent = async (options: {
|
|
|
38
39
|
|
|
39
40
|
for (const entry of entries) {
|
|
40
41
|
const normalized = normalizeEntry(entry, {
|
|
42
|
+
basePath: options.basePath ?? "",
|
|
41
43
|
defaultType: options.defaultType,
|
|
42
44
|
i18n: options.i18n,
|
|
43
45
|
source: { name: source.name, prefix: source.prefix, staged: false },
|
package/src/core/data.ts
CHANGED
|
@@ -93,6 +93,10 @@ export interface BlumeDataConfig {
|
|
|
93
93
|
suggestions: NonNullable<ResolvedConfig["ai"]["ask"]>["suggestions"];
|
|
94
94
|
} | null;
|
|
95
95
|
banner: BlumeBanner | null;
|
|
96
|
+
/** Site-wide route mount point, normalized to `""` or `/seg` (see config). */
|
|
97
|
+
basePath: string;
|
|
98
|
+
/** `markdown.codeBlocks.theme`: light/dark Shiki themes for code surfaces. */
|
|
99
|
+
codeThemes: ResolvedConfig["markdown"]["codeBlocks"]["theme"];
|
|
96
100
|
/** `markdown.code.wrap`: wrap long code lines instead of scrolling. */
|
|
97
101
|
codeWrap: boolean;
|
|
98
102
|
description: string | undefined;
|
package/src/core/diagnostics.ts
CHANGED
|
@@ -20,35 +20,40 @@ export const createDiagnostic = (diagnostic: Diagnostic): Diagnostic =>
|
|
|
20
20
|
/** Docs site base; diagnostic help links resolve against it. */
|
|
21
21
|
const DOCS_BASE = "https://useblume.dev";
|
|
22
22
|
|
|
23
|
+
const DOCS_DEPLOYMENT = "/docs/deployment";
|
|
24
|
+
const DOCS_REFERENCE_CLI = "/docs/reference/cli";
|
|
25
|
+
const DOCS_CONTENT_SOURCES = "/docs/content/sources";
|
|
26
|
+
const DOCS_CONTENT_NAVIGATION = "/docs/content/navigation";
|
|
27
|
+
|
|
23
28
|
/** Diagnostic code → the docs page that explains it. */
|
|
24
29
|
const DOCS_PATHS: Record<string, string> = {
|
|
25
|
-
BLUME_ADAPTER_REQUIRED:
|
|
26
|
-
BLUME_ASSETS_UNCHECKED:
|
|
27
|
-
BLUME_ASSET_FETCH_FAILED:
|
|
28
|
-
BLUME_BROKEN_ANCHOR:
|
|
29
|
-
BLUME_BROKEN_ASSET:
|
|
30
|
-
BLUME_BROKEN_LINK:
|
|
30
|
+
BLUME_ADAPTER_REQUIRED: DOCS_DEPLOYMENT,
|
|
31
|
+
BLUME_ASSETS_UNCHECKED: DOCS_REFERENCE_CLI,
|
|
32
|
+
BLUME_ASSET_FETCH_FAILED: DOCS_CONTENT_SOURCES,
|
|
33
|
+
BLUME_BROKEN_ANCHOR: DOCS_REFERENCE_CLI,
|
|
34
|
+
BLUME_BROKEN_ASSET: DOCS_REFERENCE_CLI,
|
|
35
|
+
BLUME_BROKEN_LINK: DOCS_REFERENCE_CLI,
|
|
31
36
|
BLUME_CONFIG_INVALID: "/docs/configuration",
|
|
32
37
|
BLUME_CONFIG_LOAD_FAILED: "/docs/configuration",
|
|
33
|
-
BLUME_CONTENT_ROOT_MISSING:
|
|
34
|
-
BLUME_DEAD_LINK:
|
|
35
|
-
BLUME_DUPLICATE_ROUTE:
|
|
38
|
+
BLUME_CONTENT_ROOT_MISSING: DOCS_CONTENT_SOURCES,
|
|
39
|
+
BLUME_DEAD_LINK: DOCS_REFERENCE_CLI,
|
|
40
|
+
BLUME_DUPLICATE_ROUTE: DOCS_CONTENT_NAVIGATION,
|
|
36
41
|
BLUME_FRONTMATTER_INVALID: "/docs/reference/frontmatter",
|
|
37
42
|
BLUME_META_INVALID: "/docs/content/meta",
|
|
38
43
|
BLUME_META_LOAD_FAILED: "/docs/content/meta",
|
|
39
|
-
BLUME_MISSING_SECRET:
|
|
40
|
-
BLUME_NAV_DUPLICATE_LABEL:
|
|
41
|
-
BLUME_NAV_HIDDEN_IN_SIDEBAR:
|
|
42
|
-
BLUME_NAV_MISSING_PAGE:
|
|
44
|
+
BLUME_MISSING_SECRET: DOCS_DEPLOYMENT,
|
|
45
|
+
BLUME_NAV_DUPLICATE_LABEL: DOCS_CONTENT_NAVIGATION,
|
|
46
|
+
BLUME_NAV_HIDDEN_IN_SIDEBAR: DOCS_CONTENT_NAVIGATION,
|
|
47
|
+
BLUME_NAV_MISSING_PAGE: DOCS_CONTENT_NAVIGATION,
|
|
43
48
|
BLUME_NODE_VERSION: "/docs/quickstart",
|
|
44
|
-
BLUME_SERVER_FEATURE_REQUIRED:
|
|
45
|
-
BLUME_SOURCE_FETCH_FAILED:
|
|
46
|
-
BLUME_SOURCE_MISCONFIGURED:
|
|
47
|
-
BLUME_SOURCE_OFFLINE:
|
|
48
|
-
BLUME_SOURCE_SDK_MISSING:
|
|
49
|
-
BLUME_SOURCE_UNAVAILABLE:
|
|
49
|
+
BLUME_SERVER_FEATURE_REQUIRED: DOCS_DEPLOYMENT,
|
|
50
|
+
BLUME_SOURCE_FETCH_FAILED: DOCS_CONTENT_SOURCES,
|
|
51
|
+
BLUME_SOURCE_MISCONFIGURED: DOCS_CONTENT_SOURCES,
|
|
52
|
+
BLUME_SOURCE_OFFLINE: DOCS_CONTENT_SOURCES,
|
|
53
|
+
BLUME_SOURCE_SDK_MISSING: DOCS_CONTENT_SOURCES,
|
|
54
|
+
BLUME_SOURCE_UNAVAILABLE: DOCS_CONTENT_SOURCES,
|
|
50
55
|
BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
|
|
51
|
-
BLUME_UNKNOWN_ICON:
|
|
56
|
+
BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,
|
|
52
57
|
};
|
|
53
58
|
|
|
54
59
|
/** The docs URL that explains a diagnostic code, if one is mapped. */
|
|
@@ -74,6 +79,29 @@ const escapeRegExp = (value: string): string =>
|
|
|
74
79
|
* lands under its parent. Array indices are skipped. Returns 1-based line/column,
|
|
75
80
|
* or undefined when nothing matches.
|
|
76
81
|
*/
|
|
82
|
+
const stepSegment = (
|
|
83
|
+
source: string,
|
|
84
|
+
segment: string | number,
|
|
85
|
+
cursor: number
|
|
86
|
+
): { index: number; next: number; stop: boolean } => {
|
|
87
|
+
// A non-string path segment (array index) is skipped without moving on.
|
|
88
|
+
if (typeof segment !== "string") {
|
|
89
|
+
return { index: -1, next: cursor, stop: false };
|
|
90
|
+
}
|
|
91
|
+
// The negative lookbehind keeps a segment like `title` from matching the
|
|
92
|
+
// tail of an unrelated key such as `subtitle:`.
|
|
93
|
+
const matcher = new RegExp(
|
|
94
|
+
`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`,
|
|
95
|
+
"gu"
|
|
96
|
+
);
|
|
97
|
+
matcher.lastIndex = cursor;
|
|
98
|
+
const match = matcher.exec(source);
|
|
99
|
+
if (!match) {
|
|
100
|
+
return { index: -1, next: cursor, stop: true };
|
|
101
|
+
}
|
|
102
|
+
return { index: match.index, next: matcher.lastIndex, stop: false };
|
|
103
|
+
};
|
|
104
|
+
|
|
77
105
|
const locatePath = (
|
|
78
106
|
source: string,
|
|
79
107
|
path: readonly (string | number)[]
|
|
@@ -81,22 +109,14 @@ const locatePath = (
|
|
|
81
109
|
let cursor = 0;
|
|
82
110
|
let found = -1;
|
|
83
111
|
for (const segment of path) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
// The negative lookbehind keeps a segment like `title` from matching the
|
|
88
|
-
// tail of an unrelated key such as `subtitle:`.
|
|
89
|
-
const matcher = new RegExp(
|
|
90
|
-
`(?<![\\w$])${escapeRegExp(segment)}\\s*[:=]`,
|
|
91
|
-
"gu"
|
|
92
|
-
);
|
|
93
|
-
matcher.lastIndex = cursor;
|
|
94
|
-
const match = matcher.exec(source);
|
|
95
|
-
if (!match) {
|
|
112
|
+
const step = stepSegment(source, segment, cursor);
|
|
113
|
+
if (step.stop) {
|
|
96
114
|
break;
|
|
97
115
|
}
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
cursor = step.next;
|
|
117
|
+
if (step.index >= 0) {
|
|
118
|
+
found = step.index;
|
|
119
|
+
}
|
|
100
120
|
}
|
|
101
121
|
if (found < 0) {
|
|
102
122
|
return;
|
package/src/core/gitignore.ts
CHANGED
|
@@ -18,7 +18,10 @@ export const ensureGitignore = async (
|
|
|
18
18
|
const path = join(root, ".gitignore");
|
|
19
19
|
const existing = existsSync(path) ? await readFile(path, "utf-8") : "";
|
|
20
20
|
const present = new Set(
|
|
21
|
-
existing.split("\n").
|
|
21
|
+
existing.split("\n").flatMap((line) => {
|
|
22
|
+
const key = gitignoreKey(line);
|
|
23
|
+
return key ? [key] : [];
|
|
24
|
+
})
|
|
22
25
|
);
|
|
23
26
|
const added = entries.filter((entry) => !present.has(gitignoreKey(entry)));
|
|
24
27
|
if (added.length === 0) {
|