blume 1.5.2 → 1.6.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.
Files changed (194) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/dist/cli/index.js +3639 -1377
  3. package/dist/cli/index.js.map +103 -91
  4. package/dist/types/ai/component-markdown.d.ts +79 -0
  5. package/dist/types/components/layout/nav-utils.d.ts +60 -0
  6. package/dist/types/core/base-path.d.ts +9 -0
  7. package/dist/types/core/config-input.d.ts +206 -4
  8. package/dist/types/core/config.d.ts +6 -4
  9. package/dist/types/core/data.d.ts +23 -1
  10. package/dist/types/core/github.d.ts +35 -0
  11. package/dist/types/core/i18n-ui.d.ts +8 -0
  12. package/dist/types/core/navigation.d.ts +69 -0
  13. package/dist/types/core/schema.d.ts +117 -1
  14. package/dist/types/core/sources/types.d.ts +31 -6
  15. package/dist/types/core/types.d.ts +23 -2
  16. package/dist/types/markdown/features.d.ts +21 -0
  17. package/dist/types/openapi/references.d.ts +21 -1
  18. package/dist/types/seo/jsonld.d.ts +105 -0
  19. package/dist/types/theme/fonts.d.ts +34 -4
  20. package/docs/_snippets/include-demo.mdx +7 -0
  21. package/docs/advanced/api-reference.mdx +3 -3
  22. package/docs/advanced/custom-pages.mdx +1 -1
  23. package/docs/advanced/graphql.mdx +84 -0
  24. package/docs/advanced/meta.ts +8 -1
  25. package/docs/configuration/ai.mdx +21 -3
  26. package/docs/configuration/index.mdx +24 -0
  27. package/docs/configuration/search.mdx +13 -1
  28. package/docs/configuration/seo.mdx +27 -0
  29. package/docs/configuration/theming.mdx +17 -0
  30. package/docs/content/components.mdx +7 -0
  31. package/docs/content/includes.mdx +68 -0
  32. package/docs/content/meta.ts +1 -0
  33. package/docs/content/navigation.mdx +25 -0
  34. package/docs/content/sources.mdx +42 -1
  35. package/docs/content/syntax.mdx +69 -1
  36. package/docs/content/versioning.mdx +15 -9
  37. package/docs/reference/cli.mdx +2 -1
  38. package/package.json +23 -14
  39. package/skills/blume-migrate/SKILL.md +16 -7
  40. package/skills/blume-migrate/references/docusaurus.md +5 -3
  41. package/skills/blume-migrate/references/fumadocs.md +10 -2
  42. package/skills/blume-migrate/references/mintlify.md +3 -2
  43. package/skills/blume-migrate/references/nextra.md +2 -2
  44. package/skills/blume-migrate/references/starlight.md +1 -1
  45. package/src/ai/agent-readability.ts +2 -1
  46. package/src/ai/ask-data.ts +2 -1
  47. package/src/ai/component-markdown.ts +199 -36
  48. package/src/ai/llms.ts +93 -6
  49. package/src/ai/markdown.ts +2 -2
  50. package/src/ai/mcp/discovery.ts +10 -2
  51. package/src/ai/mcp/server.ts +74 -2
  52. package/src/astro/generate.ts +183 -116
  53. package/src/astro/include-hmr.ts +81 -0
  54. package/src/astro/include-refresh.ts +0 -0
  55. package/src/astro/index.ts +3 -5
  56. package/src/astro/templates.ts +125 -76
  57. package/src/cli/commands/build.ts +84 -15
  58. package/src/cli/init/questions.ts +1 -0
  59. package/src/cli/init/scaffold.ts +27 -4
  60. package/src/components/colors.ts +142 -0
  61. package/src/components/content/Badge.astro +5 -12
  62. package/src/components/content/Callout.astro +19 -36
  63. package/src/components/content/Card.astro +15 -21
  64. package/src/components/content/Component.astro +10 -1
  65. package/src/components/content/GithubInfo.astro +28 -9
  66. package/src/components/content/Tabs.astro +27 -5
  67. package/src/components/content/github-info.ts +20 -5
  68. package/src/components/dropdown-dismiss.ts +122 -0
  69. package/src/components/layout/Fonts.astro +15 -8
  70. package/src/components/layout/Header.astro +44 -0
  71. package/src/components/layout/LanguageSwitcher.astro +9 -1
  72. package/src/components/layout/NavSelector.astro +12 -3
  73. package/src/components/layout/NavTree.astro +6 -18
  74. package/src/components/layout/PageActions.astro +29 -8
  75. package/src/components/layout/PageLayout.astro +10 -1
  76. package/src/components/layout/ReferenceLayout.astro +6 -1
  77. package/src/components/layout/RootLayout.astro +46 -15
  78. package/src/components/layout/Search.astro +36 -4
  79. package/src/components/layout/TableOfContents.astro +8 -2
  80. package/src/components/layout/head-scripts.ts +53 -1
  81. package/src/components/openapi/ApiOverview.astro +13 -3
  82. package/src/components/openapi/AsyncApiOperation.astro +7 -14
  83. package/src/components/openapi/GraphqlChip.astro +33 -0
  84. package/src/components/openapi/GraphqlFieldsTable.astro +111 -0
  85. package/src/components/openapi/GraphqlOperation.astro +186 -0
  86. package/src/components/openapi/GraphqlType.astro +154 -0
  87. package/src/components/openapi/MethodBadge.astro +3 -14
  88. package/src/components/openapi/Operation.astro +12 -5
  89. package/src/components/openapi/OperationPanel.astro +43 -0
  90. package/src/components/openapi/RequestPanel.astro +5 -10
  91. package/src/components/openapi/Responses.astro +1 -16
  92. package/src/components/openapi/graphql-helpers.ts +466 -0
  93. package/src/components/openapi/playground-client.ts +15 -0
  94. package/src/components/openapi/sample-panels.ts +45 -0
  95. package/src/components/openapi/snippets.ts +13 -35
  96. package/src/core/base-path.ts +11 -0
  97. package/src/core/config-input.ts +209 -2
  98. package/src/core/config.ts +6 -4
  99. package/src/core/content-assets.ts +15 -4
  100. package/src/core/data.ts +18 -2
  101. package/src/core/diagnostics.ts +8 -0
  102. package/src/core/frontmatter.ts +20 -8
  103. package/src/core/github.ts +71 -0
  104. package/src/core/graph.ts +22 -8
  105. package/src/core/heading-markers.ts +96 -0
  106. package/src/core/i18n-ui.ts +11 -0
  107. package/src/core/includes.ts +632 -0
  108. package/src/core/last-modified.ts +36 -11
  109. package/src/core/links.ts +79 -13
  110. package/src/core/meta.ts +2 -1
  111. package/src/core/nav-diagnostics.ts +11 -2
  112. package/src/core/navigation.ts +27 -6
  113. package/src/core/project-graph.ts +61 -9
  114. package/src/core/schema.ts +226 -35
  115. package/src/core/server-features.ts +5 -9
  116. package/src/core/sources/github-releases.ts +2 -2
  117. package/src/core/sources/normalize.ts +502 -115
  118. package/src/core/sources/notion.ts +43 -8
  119. package/src/core/sources/obsidian.ts +1038 -0
  120. package/src/core/sources/read.ts +36 -1
  121. package/src/core/sources/resolve.ts +34 -1
  122. package/src/core/sources/types.ts +28 -6
  123. package/src/core/sources/watch.ts +12 -8
  124. package/src/core/tsconfig-aliases.ts +48 -35
  125. package/src/core/types.ts +25 -2
  126. package/src/core/ui-packs/ar.ts +1 -0
  127. package/src/core/ui-packs/bg.ts +2 -0
  128. package/src/core/ui-packs/bn.ts +1 -0
  129. package/src/core/ui-packs/ca.ts +2 -0
  130. package/src/core/ui-packs/cs.ts +1 -0
  131. package/src/core/ui-packs/da.ts +1 -0
  132. package/src/core/ui-packs/de.ts +2 -0
  133. package/src/core/ui-packs/el.ts +2 -0
  134. package/src/core/ui-packs/es.ts +2 -0
  135. package/src/core/ui-packs/fa.ts +1 -0
  136. package/src/core/ui-packs/fi.ts +1 -0
  137. package/src/core/ui-packs/fr.ts +2 -0
  138. package/src/core/ui-packs/he.ts +1 -0
  139. package/src/core/ui-packs/hi.ts +1 -0
  140. package/src/core/ui-packs/hr.ts +2 -0
  141. package/src/core/ui-packs/hu.ts +2 -0
  142. package/src/core/ui-packs/id.ts +2 -0
  143. package/src/core/ui-packs/it.ts +1 -0
  144. package/src/core/ui-packs/ja.ts +2 -0
  145. package/src/core/ui-packs/ko.ts +2 -0
  146. package/src/core/ui-packs/nl.ts +2 -0
  147. package/src/core/ui-packs/no.ts +2 -0
  148. package/src/core/ui-packs/pl.ts +2 -0
  149. package/src/core/ui-packs/pt-br.ts +2 -0
  150. package/src/core/ui-packs/pt.ts +2 -0
  151. package/src/core/ui-packs/ro.ts +2 -0
  152. package/src/core/ui-packs/ru.ts +2 -0
  153. package/src/core/ui-packs/sk.ts +1 -0
  154. package/src/core/ui-packs/sr.ts +1 -0
  155. package/src/core/ui-packs/sv.ts +2 -0
  156. package/src/core/ui-packs/th.ts +1 -0
  157. package/src/core/ui-packs/tr.ts +2 -0
  158. package/src/core/ui-packs/uk.ts +2 -0
  159. package/src/core/ui-packs/vi.ts +1 -0
  160. package/src/core/ui-packs/zh-tw.ts +1 -0
  161. package/src/core/ui-packs/zh.ts +1 -0
  162. package/src/core/version-cut.ts +21 -3
  163. package/src/core/yaml.ts +26 -0
  164. package/src/deploy/function-bundle.ts +251 -0
  165. package/src/eval/schema.ts +3 -1
  166. package/src/markdown/code-title.ts +22 -16
  167. package/src/markdown/features.ts +21 -0
  168. package/src/markdown/fence-meta.ts +50 -0
  169. package/src/markdown/heading-anchors.ts +198 -37
  170. package/src/markdown/include.ts +247 -0
  171. package/src/markdown/index.ts +43 -34
  172. package/src/markdown/language-icon.ts +2 -2
  173. package/src/markdown/mdast.ts +7 -3
  174. package/src/markdown/ts2js.ts +264 -0
  175. package/src/openapi/asyncapi.ts +4 -1
  176. package/src/openapi/graphql-build.ts +293 -0
  177. package/src/openapi/graphql.ts +212 -0
  178. package/src/openapi/model.ts +38 -5
  179. package/src/openapi/parse.ts +34 -0
  180. package/src/openapi/proxy.ts +30 -5
  181. package/src/openapi/references.ts +89 -13
  182. package/src/openapi/render-mdx.ts +48 -8
  183. package/src/openapi/scalar.ts +5 -12
  184. package/src/openapi/source.ts +91 -23
  185. package/src/registry/eject.ts +11 -0
  186. package/src/search/documents.ts +229 -37
  187. package/src/search/orama-index.ts +9 -5
  188. package/src/seo/jsonld.ts +293 -51
  189. package/src/theme/code-block-padding.ts +16 -0
  190. package/src/theme/entry.ts +65 -11
  191. package/src/theme/fonts.ts +189 -16
  192. package/src/translate/prompts.ts +2 -0
  193. package/src/translate/run.ts +7 -0
  194. package/src/translate/work-list.ts +0 -0
@@ -1,4 +1,43 @@
1
1
  import type { ExampleLookup } from "../core/types.ts";
2
+ /**
3
+ * Downlevel Blume's MDX components to plain Markdown for agent-facing output
4
+ * (the `/<route>.md` mirror, llms-full.txt, MCP `get_page`). Each supported
5
+ * component has a serializer — its "toString" — that renders the same
6
+ * information as the Astro component, but as portable Markdown: `<TypeTable>`
7
+ * becomes a GFM table, `<Callout>` a blockquote, `<Steps>` an ordered list,
8
+ * `<Tabs>` labeled sections, `<YouTube>` a link.
9
+ *
10
+ * The transform is a position splice, not a re-stringify: the MDX source is
11
+ * parsed to MDAST (via Satteri, which stamps byte offsets on every node) and
12
+ * only the matched component ranges are replaced, so all surrounding Markdown
13
+ * stays byte-identical to what the author wrote. Anything the serializers
14
+ * can't faithfully convert — an unknown component, a prop bound to an import —
15
+ * is left as JSX, and fenced code that merely *shows* component markup is
16
+ * naturally untouched because it parses as a `code` node.
17
+ */
18
+ /** Minimal structural MDAST types — we model only what this module reads. */
19
+ interface Offset {
20
+ offset: number;
21
+ }
22
+ /** The structural slice of an mdast node the downlevel walk reads. */
23
+ export interface MdastNode {
24
+ attributes?: MdxAttribute[];
25
+ children?: MdastNode[];
26
+ name?: string;
27
+ position?: {
28
+ end: Offset;
29
+ start: Offset;
30
+ };
31
+ type: string;
32
+ }
33
+ interface MdxAttribute {
34
+ name?: string;
35
+ type: string;
36
+ value?: string | {
37
+ type: string;
38
+ value: string;
39
+ } | null;
40
+ }
2
41
  /**
3
42
  * A statically-recovered data value. Parsed front matter and evaluated
4
43
  * attribute literals are both plain data — scalars, dates, arrays, and
@@ -17,8 +56,27 @@ export interface ComponentMarkdownChild extends EvaluatedProps {
17
56
  /** The child's body, downleveled and dedented. */
18
57
  children: string;
19
58
  }
59
+ /** One direct child of a component — a child component or prose — as Markdown. */
60
+ export interface ComponentMarkdownBlock {
61
+ /**
62
+ * The child downleveled: a serializable component's rendering (through the
63
+ * registry, so a user override of that component applies), or — for prose,
64
+ * a component with no serializer, or one that declined — its source with
65
+ * any serializable descendants downleveled in place.
66
+ */
67
+ markdown: string;
68
+ /** The JSX name of a child component; `undefined` for prose. */
69
+ name?: string;
70
+ }
20
71
  /** What a serializer receives for one component usage. */
21
72
  export interface ComponentMarkdownContext extends EvaluatedProps {
73
+ /**
74
+ * Every direct child of the element in document order, components and
75
+ * prose alike, each as a block of Markdown. For a container that is nothing
76
+ * but its contents — `<CardGroup>` — joining these with blank lines is the
77
+ * whole serializer.
78
+ */
79
+ childBlocks: () => ComponentMarkdownBlock[];
22
80
  /** Direct child components of `name`, each with evaluated props and body. */
23
81
  childComponents: (name: string) => ComponentMarkdownChild[];
24
82
  /** The element's body, downleveled and dedented (empty if self-closing). */
@@ -47,6 +105,27 @@ export type ComponentMarkdown = (context: ComponentMarkdownContext) => string |
47
105
  export declare const exampleComponentSerializers: (examples: ExampleLookup) => {
48
106
  Component: ({ props }: ComponentMarkdownContext) => string | null;
49
107
  };
108
+ /** One downlevel pass's inputs: the source, registry, and page metadata. */
109
+ /** What a downlevel walk needs: the serializers, the page's front matter, and the source its nodes were parsed from. */
110
+ export interface DownlevelWalk {
111
+ frontmatter: Record<string, EvaluatedValue> | undefined;
112
+ registry: Record<string, ComponentMarkdown>;
113
+ source: string;
114
+ }
115
+ /** The serializer registry for a site: built-ins under a user's `ai.markdownComponents`. */
116
+ export declare const componentRegistry: (components?: Record<string, ComponentMarkdown>) => Record<string, ComponentMarkdown>;
117
+ /**
118
+ * Walk the tree collecting replacements. A replaced element's subtree is
119
+ * owned by its serializer (which downlevels its own children), so the walk
120
+ * doesn't descend into it; when a serializer declines, the walk continues
121
+ * inside so nested serializable components still convert.
122
+ */
123
+ /**
124
+ * Downlevel one parsed component to the Markdown its serializer emits, or
125
+ * `null` when the node isn't a component, has no serializer, or its
126
+ * serializer declines. `walk.source` must be the text `node` was parsed from.
127
+ */
128
+ export declare const downlevelComponentNode: (node: MdastNode, walk: DownlevelWalk) => string | null;
50
129
  /**
51
130
  * Downlevel supported components in an MDX source to plain Markdown. Sources
52
131
  * with no supported components — and sources Satteri can't parse as MDX, e.g.
@@ -0,0 +1,60 @@
1
+ import type { NavNode, NavTab } from "../../core/types.ts";
2
+ /** A flat, ordered page reference used for previous/next pagination. */
3
+ export interface FlatPage {
4
+ route: string;
5
+ label: string;
6
+ deprecated?: boolean;
7
+ }
8
+ /** A breadcrumb segment; `route` is absent for non-clickable group ancestors. */
9
+ export interface Crumb {
10
+ label: string;
11
+ route?: string;
12
+ }
13
+ /** Flatten the sidebar tree into ordered internal page links. */
14
+ export declare const flattenPages: (nodes: NavNode[]) => FlatPage[];
15
+ /** Find the breadcrumb trail (group ancestors + page) for a route. */
16
+ export declare const findBreadcrumbs: (nodes: NavNode[], route: string) => Crumb[];
17
+ /**
18
+ * The tab whose `path` is the longest prefix of `route`. The root tab (`/`)
19
+ * acts as the fallback when no more specific tab matches.
20
+ */
21
+ export declare const activeTabForRoute: (tabs: NavTab[], route: string) => NavTab | null;
22
+ /**
23
+ * The tab to mark as the current one (`aria-current`) for `route`. Same
24
+ * longest-prefix match as {@link activeTabForRoute}, except inside an archived
25
+ * version tree: the root tab claims every archived route through its
26
+ * spans-everything fallback while its link points back at the current docs, so
27
+ * no tab is genuinely current there.
28
+ */
29
+ export declare const currentTabForRoute: (tabs: NavTab[], route: string, root?: string) => NavTab | null;
30
+ /**
31
+ * Scope the sidebar to the active tab's section. With tabs configured, a route
32
+ * under one tab shows only that tab's group — so a multi-section site (e.g.
33
+ * Adapters / API / AI tabs) drills each tab into its own pages instead of one
34
+ * global tree, the way Fumadocs' root folders do. On a route under no tab (or
35
+ * the root tab), the tab-owned groups are hidden so the root sidebar shows
36
+ * only pages that don't belong to a tab.
37
+ *
38
+ * `root` is the tree root (`Navigation.root`), localized and based like tab
39
+ * paths — under i18n or a `basePath` the root tab sits at `/en` or `/docs`,
40
+ * not `/`, and a bare-`/` comparison would misread it as a section tab (a
41
+ * root-level `(group)` folder's path is exactly that prefix, so the sidebar
42
+ * collapsed to that one group or blanked entirely). In an archived version
43
+ * tree the root is versionized (`/v1.0`) while tab paths stay in current-docs
44
+ * space, so root-tab checks use {@link isRootTab} containment, not equality:
45
+ * the root tab owns no group in a snapshot, and misreading it as a section
46
+ * tab blanked the archived sidebar.
47
+ *
48
+ * When a matched tab owns no sidebar group — a standalone page like the
49
+ * generated changelog timeline (`/changelog`), or a tab whose source produced
50
+ * no pages — the sidebar is empty. It must not fall back to the full tree: that
51
+ * would leak every *other* tab's section (e.g. the OpenAPI operations) onto the
52
+ * page. On a route under no tab, hiding the tab sections falls back to the full
53
+ * sidebar only when it would otherwise blank, so an un-tabbed route stays full.
54
+ */
55
+ export declare const sidebarForRoute: (sidebar: NavNode[], tabs: NavTab[], route: string, root?: string) => NavNode[];
56
+ /** Resolve previous/next pages around the current route. */
57
+ export declare const getPagination: (flat: FlatPage[], route: string) => {
58
+ next: FlatPage | null;
59
+ prev: FlatPage | null;
60
+ };
@@ -36,6 +36,15 @@ export declare const normalizeRoute: (input: string) => string;
36
36
  * other schemes (`mailto:`), fragments (`#x`), and relative paths are excluded.
37
37
  */
38
38
  export declare const isInternalPath: (target: string) => boolean;
39
+ /**
40
+ * Whether a rendered link should open in a new tab: an absolute http(s) URL or
41
+ * a protocol-relative one (`//host/path`). Other schemes (`mailto:`, `tel:`)
42
+ * also leave the site but hand off to another application, where a `_blank`
43
+ * target only opens an empty tab beside it. The one predicate behind every
44
+ * chrome link, so a header action and a sidebar featured link treat the same
45
+ * href alike.
46
+ */
47
+ export declare const isExternalUrl: (target: string) => boolean;
39
48
  /**
40
49
  * Idempotently prepend `basePath` to a root-relative route. A route already
41
50
  * equal to or nested under the base is returned unchanged, so authors who write
@@ -2,7 +2,7 @@ import type { AstroIntegration } from "astro";
2
2
  import type { ComponentMarkdown } from "../ai/component-markdown.ts";
3
3
  import type { CodeTheme } from "../markdown/themes.ts";
4
4
  import type { FontSlug } from "../theme/fonts.ts";
5
- import type { OpenApiSource, OpenInChatProvider, SearchProvider, SidebarDisplay, SidebarItemConfig } from "./schema.ts";
5
+ import type { GraphqlSource, OpenApiSource, OpenInChatProvider, SearchProvider, SidebarDisplay, SidebarItemConfig } from "./schema.ts";
6
6
  import type { ContentSource } from "./sources/types.ts";
7
7
  import type { StandardSchema } from "./standard-schema.ts";
8
8
  /**
@@ -195,6 +195,20 @@ export interface NotionSource {
195
195
  /** Status value treated as published; others map to `draft`. Defaults to `Published`. */
196
196
  publishedValue?: string;
197
197
  }
198
+ /**
199
+ * An Obsidian vault, read in place. Wikilinks become route links and
200
+ * `%%comments%%` are stripped at load time, so the vault stays the source of
201
+ * truth — no export step and no generated notes in the repo.
202
+ */
203
+ export interface ObsidianSource {
204
+ type: "obsidian";
205
+ /** Vault folder names to skip at any depth, in addition to dot-folders. */
206
+ exclude?: string[];
207
+ /** Namespaces this source's routes under `/<prefix>/`; e.g. `vault`. */
208
+ prefix?: string;
209
+ /** Vault directory, absolute or relative to the project root. */
210
+ vault: string;
211
+ }
198
212
  /**
199
213
  * A user-provided {@link ContentSource} instance, passed straight through. This
200
214
  * is the extension point for adapters with custom serializers or any other
@@ -206,7 +220,7 @@ export interface CustomSource {
206
220
  source: ContentSource;
207
221
  }
208
222
  /** A single configured content source, discriminated by `type`. */
209
- export type ContentSourceInput = FilesystemSource | MdxRemoteSource | GithubReleasesSource | SanitySource | NotionSource | CustomSource;
223
+ export type ContentSourceInput = FilesystemSource | MdxRemoteSource | GithubReleasesSource | SanitySource | NotionSource | ObsidianSource | CustomSource;
210
224
  /**
211
225
  * Where content lives and how it's discovered. When `sources` is omitted, the
212
226
  * top-level `root`/`include`/`exclude` desugar to one implicit filesystem
@@ -385,12 +399,27 @@ export type SidebarConfig = SidebarItemConfig[] | {
385
399
  /** Explicit sidebar nodes; omit to auto-generate from content. */
386
400
  items?: SidebarItemConfig[];
387
401
  };
402
+ /** A plain header link, or the header's single call to action. */
403
+ export interface HeaderAction {
404
+ /** Link target. An external href opens in a new tab. */
405
+ href: string;
406
+ /** Link label. */
407
+ label: string;
408
+ }
388
409
  /** Header, sidebar, tabs, and switcher configuration. */
389
410
  export interface NavigationConfig {
411
+ /** Plain links in the header, left of the icon buttons. */
412
+ actions?: HeaderAction[];
413
+ /** The single primary call to action in the header, as a filled button. */
414
+ cta?: HeaderAction;
390
415
  /** Pinned links shown above the generated sidebar sections. */
391
416
  featured?: FeaturedLink[];
392
- /** Show a GitHub repo link in the header (requires `github` configured). */
393
- repo?: boolean;
417
+ /**
418
+ * The GitHub link in the header. `true` derives it from `github` (the
419
+ * default), `false` hides it, and an absolute URL points it anywhere on
420
+ * GitHub — an organization, say, when the docs repo itself is private.
421
+ */
422
+ repo?: boolean | string;
394
423
  /** Context switchers shown in the header (versions, languages, …). */
395
424
  selectors?: NavSelector[];
396
425
  /** Sidebar behavior and (optionally) an explicit sidebar tree. */
@@ -411,6 +440,11 @@ export interface RemoteFontInput {
411
440
  name: string;
412
441
  /** Which provider serves the family. Defaults to `google`. */
413
442
  provider?: "google" | "fontsource" | "bunny" | "fontshare";
443
+ /**
444
+ * Character subsets to load (`"latin"`, `"vietnamese"`, `"cyrillic"`, …).
445
+ * Defaults to `latin` plus whatever the configured locales need.
446
+ */
447
+ subsets?: string[];
414
448
  /** Weights (or variable ranges like `"100..900"`) to load. Defaults to `[400, 500, 600, 700]`. */
415
449
  weights?: (number | string)[];
416
450
  }
@@ -520,6 +554,12 @@ export interface SearchConfig {
520
554
  algolia?: AlgoliaSearch;
521
555
  /** Indexing behavior. */
522
556
  indexing?: {
557
+ /**
558
+ * Index fenced code (body and title) in the source-built search indexes —
559
+ * the client index, hosted syncs, and the MCP `search_docs` index.
560
+ * Defaults to `false`; Pagefind and Mixedbread index code regardless.
561
+ */
562
+ includeCodeBlocks?: boolean;
523
563
  /** Include pages marked `hidden` in the search index. Defaults to `false`. */
524
564
  includeHiddenPages?: boolean;
525
565
  };
@@ -609,6 +649,22 @@ export interface AskConfig {
609
649
  }
610
650
  /** What the `llms.txt`/`llms-full.txt` files include. */
611
651
  export interface LlmsTxtConfig {
652
+ /**
653
+ * Markdown placed after the title and summary in `llms.txt`, before the
654
+ * page sections — the llms.txt spec's "details" block. Use it to tell
655
+ * agents when to reach for the product and how to call it (a "When to use"
656
+ * heading, the install command, the package name). Blank values are
657
+ * dropped.
658
+ *
659
+ * ```ts
660
+ * ai: {
661
+ * llmsTxt: {
662
+ * details: "## When to use Acme\n\nUse Acme when…",
663
+ * },
664
+ * }
665
+ * ```
666
+ */
667
+ details?: string;
612
668
  /** Emit `llms.txt` and `llms-full.txt`. Defaults to `true`. */
613
669
  enabled?: boolean;
614
670
  /**
@@ -969,6 +1025,65 @@ export interface OgConfig {
969
1025
  */
970
1026
  titles?: Record<string, string>;
971
1027
  }
1028
+ /** A schema.org `PostalAddress`; give whichever parts apply. */
1029
+ export interface PostalAddressConfig {
1030
+ /** Country name or ISO 3166-1 alpha-2 code (`"US"`). */
1031
+ addressCountry?: string;
1032
+ /** City or locality. */
1033
+ addressLocality?: string;
1034
+ /** State, province, or region. */
1035
+ addressRegion?: string;
1036
+ postalCode?: string;
1037
+ streetAddress?: string;
1038
+ }
1039
+ /**
1040
+ * The organization behind the site, emitted in every page's JSON-LD as an
1041
+ * `Organization` node that the WebSite and article nodes cite as publisher.
1042
+ * Contact details become a `ContactPoint` and the address a `PostalAddress` —
1043
+ * the fields AI agents check to verify a business before recommending it.
1044
+ * Requires `deployment.site` (the node needs an absolute identifier).
1045
+ */
1046
+ export interface OrganizationConfig {
1047
+ /** Postal address, emitted as a `PostalAddress` when any part is given. */
1048
+ address?: PostalAddressConfig;
1049
+ /** `ContactPoint.contactType` for the email/telephone. Defaults to `"customer support"`. */
1050
+ contactType?: string;
1051
+ /** Public contact email. */
1052
+ email?: string;
1053
+ /** Logo: an absolute URL or a root-relative path (`"/logo.svg"`). */
1054
+ logo?: string;
1055
+ /** Organization name. Defaults to the site title. */
1056
+ name?: string;
1057
+ /** Profile URLs that identify the organization (GitHub, X, LinkedIn, …). */
1058
+ sameAs?: string[];
1059
+ /** Public contact telephone number. */
1060
+ telephone?: string;
1061
+ /** Organization website. Defaults to the site origin. */
1062
+ url?: string;
1063
+ }
1064
+ /**
1065
+ * The product the site documents, emitted on the homepage as a
1066
+ * `SoftwareApplication` JSON-LD node — the identity type that tells agents
1067
+ * what the site is about. Requires `deployment.site`.
1068
+ */
1069
+ export interface SoftwareConfig {
1070
+ /** schema.org application category. Defaults to `"DeveloperApplication"`. */
1071
+ applicationCategory?: string;
1072
+ /** Product description. Defaults to the site description. */
1073
+ description?: string;
1074
+ /** License URL or SPDX identifier (`"MIT"`). */
1075
+ license?: string;
1076
+ /** Product name. Defaults to the site title. */
1077
+ name?: string;
1078
+ /** Supported platform(s), e.g. `"Node.js 22+"`. */
1079
+ operatingSystem?: string;
1080
+ /** Price, emitted as an `Offer`; `0` marks the software free. */
1081
+ price?: number | string;
1082
+ /** Currency of `price` (ISO 4217). Defaults to `"USD"`. */
1083
+ priceCurrency?: string;
1084
+ /** Package registry, repository, and profile URLs for the product. */
1085
+ sameAs?: string[];
1086
+ }
972
1087
  /** Discoverability: OG images, feeds, sitemap, robots, and structured data. */
973
1088
  export interface SeoConfig {
974
1089
  /**
@@ -980,12 +1095,39 @@ export interface SeoConfig {
980
1095
  contentSignals?: ContentSignalsConfig;
981
1096
  /** Per-page Open Graph image generation. */
982
1097
  og?: OgConfig;
1098
+ /**
1099
+ * The organization behind the site, added to every page's JSON-LD as an
1100
+ * `Organization` node with contact point and address.
1101
+ *
1102
+ * ```ts
1103
+ * seo: {
1104
+ * organization: {
1105
+ * email: "hello@acme.com",
1106
+ * logo: "/logo.svg",
1107
+ * sameAs: ["https://github.com/acme", "https://x.com/acme"],
1108
+ * },
1109
+ * }
1110
+ * ```
1111
+ */
1112
+ organization?: OrganizationConfig;
983
1113
  /** Generate robots.txt (with a Sitemap reference when available). Defaults to `true`. */
984
1114
  robots?: boolean;
985
1115
  /** RSS/Atom feeds. */
986
1116
  rss?: RssConfig;
987
1117
  /** Generate sitemap.xml (requires `deployment.site`). Defaults to `true`. */
988
1118
  sitemap?: boolean;
1119
+ /**
1120
+ * The documented product, added to the homepage's JSON-LD as a
1121
+ * `SoftwareApplication` node. `true` takes every default (name and
1122
+ * description from the site); the object form fills in the rest.
1123
+ *
1124
+ * ```ts
1125
+ * seo: {
1126
+ * software: { license: "MIT", operatingSystem: "Node.js 22+", price: 0 },
1127
+ * }
1128
+ * ```
1129
+ */
1130
+ software?: boolean | SoftwareConfig;
989
1131
  /** Emit schema.org JSON-LD in each page's `<head>`. Defaults to `true`. */
990
1132
  structuredData?: boolean;
991
1133
  /**
@@ -1002,10 +1144,27 @@ export interface SeoConfig {
1002
1144
  }
1003
1145
  /** Source repository, powering "Edit this page" links and the header repo link. */
1004
1146
  export interface GithubConfig {
1147
+ /**
1148
+ * REST API base, for a `<GithubInfo>` card against an Enterprise instance.
1149
+ * Derived from `host` when unset: `api.github.com` for github.com, an `api.`
1150
+ * subdomain for an Enterprise Cloud data-residency tenant, and `/api/v3` for
1151
+ * Enterprise Server. Must be an HTTP(S) URL, and is reduced to an origin plus
1152
+ * its path — the repository route is appended to it.
1153
+ */
1154
+ api?: string;
1005
1155
  /** Default branch. Defaults to `main`. */
1006
1156
  branch?: string;
1007
1157
  /** Path from the repo root to the project root (for monorepos). */
1008
1158
  dir?: string;
1159
+ /**
1160
+ * Origin of the GitHub instance the repo lives on. Defaults to
1161
+ * `https://github.com`; set it to an Enterprise host (for example
1162
+ * `https://github.acme.com` or `https://acme.ghe.com`) so the header link,
1163
+ * edit links, and the agent manifest point at that instance. Must be an
1164
+ * HTTP(S) URL, and is reduced to its origin — every repo URL is built by
1165
+ * appending to it.
1166
+ */
1167
+ host?: string;
1009
1168
  /** Repository owner (user or org). */
1010
1169
  owner: string;
1011
1170
  /** Repository name. */
@@ -1121,6 +1280,47 @@ export interface AsyncApiConfig extends ReferenceConfig {
1121
1280
  /** Where the reference mounts. Defaults to `/events`. */
1122
1281
  route?: string;
1123
1282
  }
1283
+ /**
1284
+ * GraphQL reference. Blume lowers the schema — SDL text or an introspection
1285
+ * JSON result, local or remote — into one real page per root field (grouped
1286
+ * as Queries/Mutations/Subscriptions) plus one page per named type (Objects,
1287
+ * Input Objects, Enums, Interfaces, Unions, Scalars), all in the sidebar,
1288
+ * search, llms.txt, and OG. Always Blume-rendered — the embedded Scalar SPA
1289
+ * reads OpenAPI documents only — so unlike the other reference blocks there
1290
+ * is no `renderer` opt-out.
1291
+ */
1292
+ export interface GraphqlConfig {
1293
+ /**
1294
+ * Code-sample languages shown per operation. Defaults to
1295
+ * `["curl", "js", "python"]`.
1296
+ */
1297
+ codeSamples?: string[];
1298
+ /** Turn the reference on. Defaults to `false`. */
1299
+ enabled?: boolean;
1300
+ /**
1301
+ * URL of the live GraphQL endpoint the playground and code samples target —
1302
+ * a schema, unlike an OpenAPI document, names no server. Applies to every
1303
+ * source in the block; a per-source `endpoint` wins.
1304
+ */
1305
+ endpoint?: string;
1306
+ /**
1307
+ * The interactive "Try it" panel on operation pages. On by default; `false`
1308
+ * hides it. The object form keeps it on and sets `proxy`, the CORS escape
1309
+ * hatch the Send button routes requests through: a proxy URL, or `true` for
1310
+ * the built-in `/_api-proxy` endpoint (which requires
1311
+ * `deployment.output: "server"`).
1312
+ */
1313
+ playground?: boolean | {
1314
+ enabled?: boolean;
1315
+ proxy?: boolean | string;
1316
+ };
1317
+ /** Where the reference mounts. Defaults to `/graphql`. */
1318
+ route?: string;
1319
+ /** One or more schemas; each renders on its own route by default. */
1320
+ sources?: GraphqlSource[];
1321
+ /** Shorthand for a single source: `sources: [{ spec }]`. */
1322
+ spec?: string;
1323
+ }
1124
1324
  /** `<Component />` example previews (the object form of `examples`). */
1125
1325
  export interface ExamplesConfig {
1126
1326
  /**
@@ -1279,6 +1479,8 @@ export interface BlumeConfig {
1279
1479
  frontmatter?: FrontmatterConfig;
1280
1480
  /** Source repository (Edit-this-page links and the header repo link). */
1281
1481
  github?: GithubConfig;
1482
+ /** Native GraphQL reference (root fields and named types as real pages). */
1483
+ graphql?: GraphqlConfig;
1282
1484
  /** Internationalization (opt-in multi-locale). */
1283
1485
  i18n?: I18nConfig;
1284
1486
  /** Image optimization: remote-host authorization for the image service. */
@@ -40,11 +40,13 @@ import type { Diagnostic } from "./types.ts";
40
40
  * custom `ContentSource`). Omit `sources` and the top-level `root` becomes one
41
41
  * implicit filesystem source.
42
42
  * - `navigation` — sidebar, header `tabs`, `selectors` (version/language/product
43
- * switchers), pinned `featured` links, and the `repo` link toggle. Omit
44
- * `sidebar` to generate it from the content tree.
43
+ * switchers), pinned `featured` links, header `actions` and the one `cta`,
44
+ * and the `repo` link (a toggle, or a URL). Omit `sidebar` to generate it
45
+ * from the content tree.
45
46
  * - `redirects` — `{ from, to, status }` rules (301 by default).
46
- * - `github` — `{ owner, repo, branch, dir }`, powering "Edit this page" links
47
- * and the header repo link.
47
+ * - `github` — `{ owner, repo, branch, dir, host, api }`, powering "Edit this
48
+ * page" links and the header repo link; `host` points them at a GitHub
49
+ * Enterprise instance, `api` overrides the REST base derived from it.
48
50
  *
49
51
  * **Appearance**
50
52
  * - `theme` — `accent` color, `fonts` (curated slugs, any provider family, or
@@ -1,3 +1,4 @@
1
+ import type { StructuredDataIdentity } from "../seo/jsonld.ts";
1
2
  import type { FontHead } from "../theme/fonts.ts";
2
3
  import type { UIStrings } from "./i18n-ui.ts";
3
4
  import type { ResolvedConfig, SearchProvider } from "./schema.ts";
@@ -131,15 +132,36 @@ export interface BlumeDataConfig {
131
132
  * Which agent-discovery resources exist for the layout to advertise in every
132
133
  * page's `<head>` (`seo.agentReadability`, `ai.llmsTxt.enabled`) — the HTML
133
134
  * counterpart of the homepage-only HTTP `Link` header, for agents that enter
134
- * on a deep page (see `ai/link-headers.ts`).
135
+ * on a deep page (see `ai/link-headers.ts`). `sitemap` (`seo.sitemap` with a
136
+ * `deployment.site`, the condition under which one is emitted) feeds the
137
+ * 404 page's recovery links rather than the head.
135
138
  */
136
139
  discovery: {
137
140
  agentReadability: boolean;
138
141
  llmsTxt: boolean;
142
+ sitemap: boolean;
139
143
  };
140
144
  favicon: BlumeFavicon;
141
145
  feedback: boolean;
146
+ /**
147
+ * Repo coordinates for content components that address the API or build
148
+ * their own repo links (`<GithubInfo>`, the OG card's footer slug), carrying
149
+ * `host`/`api` so an Enterprise instance is reachable; `null` when `github`
150
+ * is unset. The plain repository URL stays on `repoUrl`.
151
+ */
152
+ github: {
153
+ api: string;
154
+ host: string;
155
+ owner: string;
156
+ repo: string;
157
+ } | null;
142
158
  i18n: BlumeDataI18n | null;
159
+ /**
160
+ * Site identity for JSON-LD (`seo.organization`, `seo.software`), read by
161
+ * the layouts straight from the snapshot so custom pages get it without
162
+ * threading a prop; `null` when neither is configured.
163
+ */
164
+ identity: StructuredDataIdentity | null;
143
165
  /** `markdown.imageZoom`: click-to-zoom content images. */
144
166
  imageZoom: boolean;
145
167
  logo: BlumeLogo | null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Repository URL derivation for `config.github`.
3
+ *
4
+ * Every repo-derived link — the header mark, per-page edit links, the agent
5
+ * manifest's `repository` — is built from `host`, which defaults to github.com
6
+ * but accepts a GitHub Enterprise origin so self-hosted and data-resident
7
+ * installations get working links instead of ones pointing at the public site.
8
+ *
9
+ * The REST base is derived from the host unless `api` is set explicitly, since
10
+ * the two Enterprise flavors expose it differently: Enterprise Cloud with data
11
+ * residency serves it from an `api.` subdomain of the same host, Enterprise
12
+ * Server from `/api/v3` on the host itself.
13
+ *
14
+ * `host` arrives as a bare origin and `api` as an origin plus path, both with
15
+ * no trailing slash — the config schema normalizes them — so nothing here
16
+ * re-trims user input.
17
+ */
18
+ import type { ResolvedConfig } from "./schema.ts";
19
+ /** The resolved `github` block, which the config leaves optional. */
20
+ export type GithubTarget = NonNullable<ResolvedConfig["github"]>;
21
+ /** The public instance every `host` defaults to. */
22
+ export declare const PUBLIC_HOST_URL = "https://github.com";
23
+ /** The public instance's REST base. */
24
+ export declare const PUBLIC_API_URL = "https://api.github.com";
25
+ /** The repository's web URL, e.g. `https://github.com/acme/docs`. */
26
+ export declare const repoUrl: (github: Pick<GithubTarget, "host" | "owner" | "repo">) => string;
27
+ /** The base every edit link extends with a repo-relative path. */
28
+ export declare const editBaseUrl: (github: Pick<GithubTarget, "branch" | "host" | "owner" | "repo">) => string;
29
+ /**
30
+ * The REST API base for `host`. An explicit `api` always wins; otherwise
31
+ * github.com (and any subdomain of it, `www.` say) maps to api.github.com, a
32
+ * data-residency tenant to its `api.` subdomain, and anything else is treated
33
+ * as Enterprise Server (`/api/v3`).
34
+ */
35
+ export declare const apiUrl: (github: Pick<GithubTarget, "api" | "host">) => string;
@@ -26,6 +26,7 @@ declare const uiStringsObject: z.ZodObject<{
26
26
  generating: z.ZodDefault<z.ZodString>;
27
27
  openIn: z.ZodDefault<z.ZodString>;
28
28
  openInChat: z.ZodDefault<z.ZodString>;
29
+ openInChatPrompt: z.ZodDefault<z.ZodString>;
29
30
  scrollToTop: z.ZodDefault<z.ZodString>;
30
31
  }, z.core.$strip>>;
31
32
  ask: z.ZodPrefault<z.ZodObject<{
@@ -79,6 +80,9 @@ declare const uiStringsObject: z.ZodObject<{
79
80
  notFound: z.ZodPrefault<z.ZodObject<{
80
81
  description: z.ZodDefault<z.ZodString>;
81
82
  home: z.ZodDefault<z.ZodString>;
83
+ llms: z.ZodDefault<z.ZodString>;
84
+ sitemap: z.ZodDefault<z.ZodString>;
85
+ suggestions: z.ZodDefault<z.ZodString>;
82
86
  title: z.ZodDefault<z.ZodString>;
83
87
  }, z.core.$strip>>;
84
88
  page: z.ZodPrefault<z.ZodObject<{
@@ -134,6 +138,7 @@ export declare const uiStringsSchema: z.ZodPrefault<z.ZodObject<{
134
138
  generating: z.ZodDefault<z.ZodString>;
135
139
  openIn: z.ZodDefault<z.ZodString>;
136
140
  openInChat: z.ZodDefault<z.ZodString>;
141
+ openInChatPrompt: z.ZodDefault<z.ZodString>;
137
142
  scrollToTop: z.ZodDefault<z.ZodString>;
138
143
  }, z.core.$strip>>;
139
144
  ask: z.ZodPrefault<z.ZodObject<{
@@ -187,6 +192,9 @@ export declare const uiStringsSchema: z.ZodPrefault<z.ZodObject<{
187
192
  notFound: z.ZodPrefault<z.ZodObject<{
188
193
  description: z.ZodDefault<z.ZodString>;
189
194
  home: z.ZodDefault<z.ZodString>;
195
+ llms: z.ZodDefault<z.ZodString>;
196
+ sitemap: z.ZodDefault<z.ZodString>;
197
+ suggestions: z.ZodDefault<z.ZodString>;
190
198
  title: z.ZodDefault<z.ZodString>;
191
199
  }, z.core.$strip>>;
192
200
  page: z.ZodPrefault<z.ZodObject<{