blume 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/cli/index.js +1170 -820
  2. package/dist/cli/index.js.map +32 -27
  3. package/dist/types/core/data.d.ts +2 -0
  4. package/dist/types/core/project.d.ts +12 -2
  5. package/dist/types/core/schema.d.ts +154 -41
  6. package/dist/types/core/types.d.ts +7 -6
  7. package/dist/types/migrate/mintlify/config.d.ts +14 -0
  8. package/docs/01-quickstart.mdx +6 -2
  9. package/docs/02-deployment.mdx +3 -1
  10. package/docs/advanced/api-reference.mdx +37 -23
  11. package/docs/advanced/bridge.mdx +76 -0
  12. package/docs/advanced/custom-pages.mdx +3 -1
  13. package/docs/advanced/meta.ts +8 -1
  14. package/docs/advanced/migrate.mdx +123 -0
  15. package/docs/configuration/ai.mdx +3 -1
  16. package/docs/configuration/analytics.mdx +3 -1
  17. package/docs/configuration/export.mdx +6 -2
  18. package/docs/configuration/index.mdx +1 -1
  19. package/docs/configuration/seo.mdx +3 -1
  20. package/docs/content/components.mdx +55 -2
  21. package/docs/content/i18n.mdx +6 -2
  22. package/docs/content/islands.mdx +6 -2
  23. package/docs/content/meta.mdx +3 -1
  24. package/docs/content/syntax.mdx +40 -14
  25. package/docs/index.mdx +2 -2
  26. package/docs/reference/cli.mdx +29 -1
  27. package/docs/reference/frontmatter.mdx +5 -0
  28. package/package.json +11 -1
  29. package/src/astro/generate.ts +18 -9
  30. package/src/astro/templates.ts +28 -4
  31. package/src/cli/commands/build.ts +107 -63
  32. package/src/cli/commands/check.ts +20 -0
  33. package/src/cli/dev-lock.ts +13 -5
  34. package/src/cli/prepare.ts +3 -0
  35. package/src/components/BlumePage.astro +6 -0
  36. package/src/components/Icon.astro +13 -10
  37. package/src/components/content/ApiField.astro +75 -0
  38. package/src/components/content/ParamField.astro +39 -0
  39. package/src/components/content/RequestField.astro +23 -0
  40. package/src/components/content/ResponseField.astro +23 -0
  41. package/src/components/content/Step.astro +1 -1
  42. package/src/components/layout/Breadcrumbs.astro +7 -2
  43. package/src/components/layout/NavTree.astro +24 -8
  44. package/src/components/layout/RootLayout.astro +56 -34
  45. package/src/components/layout/Search.astro +1 -1
  46. package/src/components/openapi/ApiOverview.astro +84 -0
  47. package/src/components/openapi/MethodBadge.astro +28 -0
  48. package/src/components/openapi/Operation.astro +140 -0
  49. package/src/components/openapi/ParametersTable.astro +97 -0
  50. package/src/components/openapi/RequestBody.astro +58 -0
  51. package/src/components/openapi/RequestPanel.astro +169 -0
  52. package/src/components/openapi/Responses.astro +91 -0
  53. package/src/components/openapi/SchemaProperty.astro +118 -0
  54. package/src/components/openapi/SchemaTable.astro +86 -0
  55. package/src/components/openapi/helpers.ts +238 -0
  56. package/src/components/openapi/panel.ts +59 -0
  57. package/src/components/openapi/snippets.ts +201 -0
  58. package/src/core/builtin-tags.ts +5 -0
  59. package/src/core/data.ts +2 -0
  60. package/src/core/graph.ts +0 -3
  61. package/src/core/nav-diagnostics.ts +2 -12
  62. package/src/core/navigation.ts +0 -10
  63. package/src/core/project-graph.ts +5 -1
  64. package/src/core/project.ts +25 -3
  65. package/src/core/schema.ts +47 -14
  66. package/src/core/sources/mintlify.ts +1 -1
  67. package/src/core/sources/resolve.ts +28 -6
  68. package/src/core/types.ts +7 -7
  69. package/src/migrate/mintlify/config.ts +190 -97
  70. package/src/migrate/mintlify/content.ts +24 -2
  71. package/src/migrate/mintlify/index.ts +76 -2
  72. package/src/migrate/mintlify/transform.ts +2 -0
  73. package/src/openapi/model.ts +174 -0
  74. package/src/openapi/parse.ts +48 -0
  75. package/src/openapi/references.ts +164 -0
  76. package/src/openapi/render-mdx.ts +76 -0
  77. package/src/openapi/scalar.ts +15 -103
  78. package/src/openapi/source.ts +140 -0
  79. package/src/registry/eject.ts +15 -2
  80. package/src/theme/chrome-icons.ts +22 -0
  81. package/src/theme/icons.ts +151 -161
@@ -87,6 +87,8 @@ export interface BlumeDataConfig {
87
87
  favicon: BlumeFavicon;
88
88
  feedback: boolean;
89
89
  i18n: BlumeDataI18n | null;
90
+ /** Default icon library for bare `icon` names. */
91
+ icons: ResolvedConfig["icons"];
90
92
  /** `markdown.imageZoom`: click-to-zoom content images. */
91
93
  imageZoom: boolean;
92
94
  logo: BlumeLogo | null;
@@ -2,8 +2,18 @@ import type { ResolvedConfig } from "./schema.ts";
2
2
  import type { ProjectContext } from "./types.ts";
3
3
  /** Locate the Blume config file for a project root, if any. */
4
4
  export declare const findConfigFile: (root: string) => string | null;
5
+ /**
6
+ * Resolve the generated runtime directory for a project. Defaults to
7
+ * `<root>/.blume`; an override (e.g. `.blume-verify` for an isolated build that
8
+ * runs alongside a live `blume dev`) may be relative to the root or absolute.
9
+ */
10
+ export declare const resolveRuntimeDir: (root: string, runtimeDir?: string) => string;
5
11
  /**
6
12
  * Resolve every path Blume needs from a project root and its resolved config.
7
- * Paths are absolute and normalized.
13
+ * Paths are absolute and normalized. `options.runtimeDir` relocates the whole
14
+ * generated runtime (and its build output) so a verify build/check can run
15
+ * without touching a live dev server's `.blume/` or the real `dist/`.
8
16
  */
9
- export declare const resolveProjectContext: (root: string, config: ResolvedConfig) => ProjectContext;
17
+ export declare const resolveProjectContext: (root: string, config: ResolvedConfig, options?: {
18
+ runtimeDir?: string;
19
+ }) => ProjectContext;
@@ -4,6 +4,38 @@ declare const hydrationMode: z.ZodEnum<["load", "idle", "visible", "media", "onl
4
4
  export type HydrationMode = z.infer<typeof hydrationMode>;
5
5
  /** Frontmatter accepted on any content page. */
6
6
  declare const pageMetaBaseSchema: z.ZodObject<{
7
+ /** Post author(s) for blog/changelog content; preserved, not yet rendered. */
8
+ authors: z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodObject<{
9
+ avatar: z.ZodOptional<z.ZodString>;
10
+ image: z.ZodOptional<z.ZodString>;
11
+ name: z.ZodString;
12
+ url: z.ZodOptional<z.ZodString>;
13
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
14
+ avatar: z.ZodOptional<z.ZodString>;
15
+ image: z.ZodOptional<z.ZodString>;
16
+ name: z.ZodString;
17
+ url: z.ZodOptional<z.ZodString>;
18
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
19
+ avatar: z.ZodOptional<z.ZodString>;
20
+ image: z.ZodOptional<z.ZodString>;
21
+ name: z.ZodString;
22
+ url: z.ZodOptional<z.ZodString>;
23
+ }, z.ZodTypeAny, "passthrough">>]>, z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
24
+ avatar: z.ZodOptional<z.ZodString>;
25
+ image: z.ZodOptional<z.ZodString>;
26
+ name: z.ZodString;
27
+ url: z.ZodOptional<z.ZodString>;
28
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
29
+ avatar: z.ZodOptional<z.ZodString>;
30
+ image: z.ZodOptional<z.ZodString>;
31
+ name: z.ZodString;
32
+ url: z.ZodOptional<z.ZodString>;
33
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
34
+ avatar: z.ZodOptional<z.ZodString>;
35
+ image: z.ZodOptional<z.ZodString>;
36
+ name: z.ZodString;
37
+ url: z.ZodOptional<z.ZodString>;
38
+ }, z.ZodTypeAny, "passthrough">>]>, "many">]>>;
7
39
  changelog: z.ZodOptional<z.ZodObject<{
8
40
  category: z.ZodOptional<z.ZodString>;
9
41
  date: z.ZodOptional<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodDate]>, string, string | Date>>;
@@ -58,14 +90,14 @@ declare const pageMetaBaseSchema: z.ZodObject<{
58
90
  noindex: boolean;
59
91
  title?: string | undefined;
60
92
  description?: string | undefined;
61
- canonical?: string | undefined;
62
93
  image?: string | undefined;
94
+ canonical?: string | undefined;
63
95
  }, {
64
96
  title?: string | undefined;
65
97
  description?: string | undefined;
98
+ image?: string | undefined;
66
99
  noindex?: boolean | undefined;
67
100
  canonical?: string | undefined;
68
- image?: string | undefined;
69
101
  }>>;
70
102
  sidebar: z.ZodDefault<z.ZodObject<{
71
103
  badge: z.ZodOptional<z.ZodString>;
@@ -107,8 +139,8 @@ declare const pageMetaBaseSchema: z.ZodObject<{
107
139
  noindex: boolean;
108
140
  title?: string | undefined;
109
141
  description?: string | undefined;
110
- canonical?: string | undefined;
111
142
  image?: string | undefined;
143
+ canonical?: string | undefined;
112
144
  };
113
145
  sidebar: {
114
146
  hidden: boolean;
@@ -120,6 +152,17 @@ declare const pageMetaBaseSchema: z.ZodObject<{
120
152
  date?: string | undefined;
121
153
  title?: string | undefined;
122
154
  description?: string | undefined;
155
+ authors?: string | z.objectOutputType<{
156
+ avatar: z.ZodOptional<z.ZodString>;
157
+ image: z.ZodOptional<z.ZodString>;
158
+ name: z.ZodString;
159
+ url: z.ZodOptional<z.ZodString>;
160
+ }, z.ZodTypeAny, "passthrough"> | (string | z.objectOutputType<{
161
+ avatar: z.ZodOptional<z.ZodString>;
162
+ image: z.ZodOptional<z.ZodString>;
163
+ name: z.ZodString;
164
+ url: z.ZodOptional<z.ZodString>;
165
+ }, z.ZodTypeAny, "passthrough">)[] | undefined;
123
166
  changelog?: {
124
167
  date?: string | undefined;
125
168
  category?: string | undefined;
@@ -147,6 +190,17 @@ declare const pageMetaBaseSchema: z.ZodObject<{
147
190
  tags?: string[] | undefined;
148
191
  } | undefined;
149
192
  description?: string | undefined;
193
+ authors?: string | z.objectInputType<{
194
+ avatar: z.ZodOptional<z.ZodString>;
195
+ image: z.ZodOptional<z.ZodString>;
196
+ name: z.ZodString;
197
+ url: z.ZodOptional<z.ZodString>;
198
+ }, z.ZodTypeAny, "passthrough"> | (string | z.objectInputType<{
199
+ avatar: z.ZodOptional<z.ZodString>;
200
+ image: z.ZodOptional<z.ZodString>;
201
+ name: z.ZodString;
202
+ url: z.ZodOptional<z.ZodString>;
203
+ }, z.ZodTypeAny, "passthrough">)[] | undefined;
150
204
  changelog?: {
151
205
  date?: string | Date | undefined;
152
206
  category?: string | undefined;
@@ -169,9 +223,9 @@ declare const pageMetaBaseSchema: z.ZodObject<{
169
223
  seo?: {
170
224
  title?: string | undefined;
171
225
  description?: string | undefined;
226
+ image?: string | undefined;
172
227
  noindex?: boolean | undefined;
173
228
  canonical?: string | undefined;
174
- image?: string | undefined;
175
229
  } | undefined;
176
230
  sidebar?: {
177
231
  label?: string | undefined;
@@ -185,6 +239,38 @@ declare const pageMetaBaseSchema: z.ZodObject<{
185
239
  tag?: string | undefined;
186
240
  }>;
187
241
  export declare const pageMetaSchema: z.ZodObject<{
242
+ /** Post author(s) for blog/changelog content; preserved, not yet rendered. */
243
+ authors: z.ZodOptional<z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodObject<{
244
+ avatar: z.ZodOptional<z.ZodString>;
245
+ image: z.ZodOptional<z.ZodString>;
246
+ name: z.ZodString;
247
+ url: z.ZodOptional<z.ZodString>;
248
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
249
+ avatar: z.ZodOptional<z.ZodString>;
250
+ image: z.ZodOptional<z.ZodString>;
251
+ name: z.ZodString;
252
+ url: z.ZodOptional<z.ZodString>;
253
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
254
+ avatar: z.ZodOptional<z.ZodString>;
255
+ image: z.ZodOptional<z.ZodString>;
256
+ name: z.ZodString;
257
+ url: z.ZodOptional<z.ZodString>;
258
+ }, z.ZodTypeAny, "passthrough">>]>, z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodObject<{
259
+ avatar: z.ZodOptional<z.ZodString>;
260
+ image: z.ZodOptional<z.ZodString>;
261
+ name: z.ZodString;
262
+ url: z.ZodOptional<z.ZodString>;
263
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
264
+ avatar: z.ZodOptional<z.ZodString>;
265
+ image: z.ZodOptional<z.ZodString>;
266
+ name: z.ZodString;
267
+ url: z.ZodOptional<z.ZodString>;
268
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
269
+ avatar: z.ZodOptional<z.ZodString>;
270
+ image: z.ZodOptional<z.ZodString>;
271
+ name: z.ZodString;
272
+ url: z.ZodOptional<z.ZodString>;
273
+ }, z.ZodTypeAny, "passthrough">>]>, "many">]>>;
188
274
  changelog: z.ZodOptional<z.ZodObject<{
189
275
  category: z.ZodOptional<z.ZodString>;
190
276
  date: z.ZodOptional<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodDate]>, string, string | Date>>;
@@ -239,14 +325,14 @@ export declare const pageMetaSchema: z.ZodObject<{
239
325
  noindex: boolean;
240
326
  title?: string | undefined;
241
327
  description?: string | undefined;
242
- canonical?: string | undefined;
243
328
  image?: string | undefined;
329
+ canonical?: string | undefined;
244
330
  }, {
245
331
  title?: string | undefined;
246
332
  description?: string | undefined;
333
+ image?: string | undefined;
247
334
  noindex?: boolean | undefined;
248
335
  canonical?: string | undefined;
249
- image?: string | undefined;
250
336
  }>>;
251
337
  sidebar: z.ZodDefault<z.ZodObject<{
252
338
  badge: z.ZodOptional<z.ZodString>;
@@ -288,8 +374,8 @@ export declare const pageMetaSchema: z.ZodObject<{
288
374
  noindex: boolean;
289
375
  title?: string | undefined;
290
376
  description?: string | undefined;
291
- canonical?: string | undefined;
292
377
  image?: string | undefined;
378
+ canonical?: string | undefined;
293
379
  };
294
380
  sidebar: {
295
381
  hidden: boolean;
@@ -301,6 +387,17 @@ export declare const pageMetaSchema: z.ZodObject<{
301
387
  date?: string | undefined;
302
388
  title?: string | undefined;
303
389
  description?: string | undefined;
390
+ authors?: string | z.objectOutputType<{
391
+ avatar: z.ZodOptional<z.ZodString>;
392
+ image: z.ZodOptional<z.ZodString>;
393
+ name: z.ZodString;
394
+ url: z.ZodOptional<z.ZodString>;
395
+ }, z.ZodTypeAny, "passthrough"> | (string | z.objectOutputType<{
396
+ avatar: z.ZodOptional<z.ZodString>;
397
+ image: z.ZodOptional<z.ZodString>;
398
+ name: z.ZodString;
399
+ url: z.ZodOptional<z.ZodString>;
400
+ }, z.ZodTypeAny, "passthrough">)[] | undefined;
304
401
  changelog?: {
305
402
  date?: string | undefined;
306
403
  category?: string | undefined;
@@ -328,6 +425,17 @@ export declare const pageMetaSchema: z.ZodObject<{
328
425
  tags?: string[] | undefined;
329
426
  } | undefined;
330
427
  description?: string | undefined;
428
+ authors?: string | z.objectInputType<{
429
+ avatar: z.ZodOptional<z.ZodString>;
430
+ image: z.ZodOptional<z.ZodString>;
431
+ name: z.ZodString;
432
+ url: z.ZodOptional<z.ZodString>;
433
+ }, z.ZodTypeAny, "passthrough"> | (string | z.objectInputType<{
434
+ avatar: z.ZodOptional<z.ZodString>;
435
+ image: z.ZodOptional<z.ZodString>;
436
+ name: z.ZodString;
437
+ url: z.ZodOptional<z.ZodString>;
438
+ }, z.ZodTypeAny, "passthrough">)[] | undefined;
331
439
  changelog?: {
332
440
  date?: string | Date | undefined;
333
441
  category?: string | undefined;
@@ -350,9 +458,9 @@ export declare const pageMetaSchema: z.ZodObject<{
350
458
  seo?: {
351
459
  title?: string | undefined;
352
460
  description?: string | undefined;
461
+ image?: string | undefined;
353
462
  noindex?: boolean | undefined;
354
463
  canonical?: string | undefined;
355
- image?: string | undefined;
356
464
  } | undefined;
357
465
  sidebar?: {
358
466
  label?: string | undefined;
@@ -827,8 +935,8 @@ declare const i18nConfigSchema: z.ZodEffects<z.ZodObject<{
827
935
  ui?: Record<string, Record<string, Record<string, string>>> | undefined;
828
936
  }>;
829
937
  /**
830
- * A single spec rendered by the API reference (Scalar). `spec` is a local path
831
- * or an `http(s)` URL; Scalar auto-detects OpenAPI vs AsyncAPI documents.
938
+ * A single spec rendered by the API reference. `spec` is a local path or an
939
+ * `http(s)` URL (OpenAPI for the Blume renderer; OpenAPI or AsyncAPI for Scalar).
832
940
  */
833
941
  declare const openapiSourceSchema: z.ZodObject<{
834
942
  /** Nav/section label for this source. */
@@ -1643,6 +1751,13 @@ export declare const blumeConfigSchema: z.ZodObject<{
1643
1751
  parser?: "dir" | "dot" | undefined;
1644
1752
  ui?: Record<string, Record<string, Record<string, string>>> | undefined;
1645
1753
  }>>;
1754
+ icons: z.ZodDefault<z.ZodObject<{
1755
+ library: z.ZodDefault<z.ZodEnum<["lucide", "fontawesome", "tabler"]>>;
1756
+ }, "strict", z.ZodTypeAny, {
1757
+ library: "lucide" | "fontawesome" | "tabler";
1758
+ }, {
1759
+ library?: "lucide" | "fontawesome" | "tabler" | undefined;
1760
+ }>>;
1646
1761
  lastModified: z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodObject<{
1647
1762
  type: z.ZodDefault<z.ZodEnum<["git", "frontmatter"]>>;
1648
1763
  }, "strict", z.ZodTypeAny, {
@@ -1773,13 +1888,13 @@ export declare const blumeConfigSchema: z.ZodObject<{
1773
1888
  }, "strict", z.ZodTypeAny, {
1774
1889
  enabled: boolean;
1775
1890
  route: string;
1776
- instructions?: string | undefined;
1777
1891
  name?: string | undefined;
1892
+ instructions?: string | undefined;
1778
1893
  }, {
1894
+ name?: string | undefined;
1779
1895
  enabled?: boolean | undefined;
1780
1896
  route?: string | undefined;
1781
1897
  instructions?: string | undefined;
1782
- name?: string | undefined;
1783
1898
  }>>;
1784
1899
  navigation: z.ZodDefault<z.ZodObject<{
1785
1900
  chromeVariants: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -1926,16 +2041,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
1926
2041
  }>, "many">>;
1927
2042
  /** Explicit sidebar override; when omitted the sidebar is generated. */
1928
2043
  sidebar: z.ZodOptional<z.ZodArray<z.ZodType<SidebarItemConfig, z.ZodTypeDef, SidebarItemConfig>, "many">>;
1929
- sidebarVariants: z.ZodDefault<z.ZodArray<z.ZodObject<{
1930
- items: z.ZodDefault<z.ZodArray<z.ZodType<SidebarItemConfig, z.ZodTypeDef, SidebarItemConfig>, "many">>;
1931
- path: z.ZodString;
1932
- }, "strict", z.ZodTypeAny, {
1933
- path: string;
1934
- items: SidebarItemConfig[];
1935
- }, {
1936
- path: string;
1937
- items?: SidebarItemConfig[] | undefined;
1938
- }>, "many">>;
1939
2044
  tabs: z.ZodOptional<z.ZodArray<z.ZodObject<{
1940
2045
  icon: z.ZodOptional<z.ZodString>;
1941
2046
  items: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -2012,10 +2117,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
2012
2117
  }[];
2013
2118
  kind: "version" | "dropdown" | "language" | "product";
2014
2119
  }[];
2015
- sidebarVariants: {
2016
- path: string;
2017
- items: SidebarItemConfig[];
2018
- }[];
2019
2120
  sidebar?: SidebarItemConfig[] | undefined;
2020
2121
  tabs?: {
2021
2122
  path: string;
@@ -2060,10 +2161,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
2060
2161
  tag?: string | undefined;
2061
2162
  }[] | undefined;
2062
2163
  }[] | undefined;
2063
- sidebarVariants?: {
2064
- path: string;
2065
- items?: SidebarItemConfig[] | undefined;
2066
- }[] | undefined;
2067
2164
  tabs?: {
2068
2165
  path: string;
2069
2166
  label: string;
@@ -2078,7 +2175,13 @@ export declare const blumeConfigSchema: z.ZodObject<{
2078
2175
  }[] | undefined;
2079
2176
  }>>;
2080
2177
  openapi: z.ZodDefault<z.ZodObject<{
2178
+ /** Code-sample languages shown per operation (Blume renderer). */
2179
+ codeSamples: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
2081
2180
  enabled: z.ZodDefault<z.ZodBoolean>;
2181
+ /** Start nested schema rows expanded rather than collapsed (Blume renderer). */
2182
+ expandSchemas: z.ZodDefault<z.ZodBoolean>;
2183
+ /** Who renders the reference: Blume's own UI, or the embedded Scalar SPA. */
2184
+ renderer: z.ZodDefault<z.ZodEnum<["blume", "scalar"]>>;
2082
2185
  /** Where the reference mounts. */
2083
2186
  route: z.ZodDefault<z.ZodString>;
2084
2187
  /** One or more specs; each renders on its own route by default. */
@@ -2100,7 +2203,7 @@ export declare const blumeConfigSchema: z.ZodObject<{
2100
2203
  }>, "many">>;
2101
2204
  /** Shorthand for a single source: `sources: [{ spec }]`. */
2102
2205
  spec: z.ZodOptional<z.ZodString>;
2103
- /** Scalar theme name; defaults to a Blume-derived accent override. */
2206
+ /** Scalar theme name (Scalar renderer only). */
2104
2207
  theme: z.ZodOptional<z.ZodString>;
2105
2208
  }, "strict", z.ZodTypeAny, {
2106
2209
  enabled: boolean;
@@ -2110,6 +2213,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
2110
2213
  label?: string | undefined;
2111
2214
  route?: string | undefined;
2112
2215
  }[];
2216
+ codeSamples: string[];
2217
+ expandSchemas: boolean;
2218
+ renderer: "blume" | "scalar";
2113
2219
  spec?: string | undefined;
2114
2220
  theme?: string | undefined;
2115
2221
  }, {
@@ -2122,6 +2228,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
2122
2228
  route?: string | undefined;
2123
2229
  }[] | undefined;
2124
2230
  theme?: string | undefined;
2231
+ codeSamples?: string[] | undefined;
2232
+ expandSchemas?: boolean | undefined;
2233
+ renderer?: "blume" | "scalar" | undefined;
2125
2234
  }>>;
2126
2235
  redirects: z.ZodDefault<z.ZodArray<z.ZodObject<{
2127
2236
  from: z.ZodString;
@@ -2629,6 +2738,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
2629
2738
  epub: boolean;
2630
2739
  pdf: boolean;
2631
2740
  };
2741
+ icons: {
2742
+ library: "lucide" | "fontawesome" | "tabler";
2743
+ };
2632
2744
  markdown: {
2633
2745
  code: {
2634
2746
  icons: boolean;
@@ -2648,8 +2760,8 @@ export declare const blumeConfigSchema: z.ZodObject<{
2648
2760
  mcp: {
2649
2761
  enabled: boolean;
2650
2762
  route: string;
2651
- instructions?: string | undefined;
2652
2763
  name?: string | undefined;
2764
+ instructions?: string | undefined;
2653
2765
  };
2654
2766
  navigation: {
2655
2767
  repo: boolean;
@@ -2681,10 +2793,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
2681
2793
  }[];
2682
2794
  kind: "version" | "dropdown" | "language" | "product";
2683
2795
  }[];
2684
- sidebarVariants: {
2685
- path: string;
2686
- items: SidebarItemConfig[];
2687
- }[];
2688
2796
  sidebar?: SidebarItemConfig[] | undefined;
2689
2797
  tabs?: {
2690
2798
  path: string;
@@ -2707,6 +2815,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
2707
2815
  label?: string | undefined;
2708
2816
  route?: string | undefined;
2709
2817
  }[];
2818
+ codeSamples: string[];
2819
+ expandSchemas: boolean;
2820
+ renderer: "blume" | "scalar";
2710
2821
  spec?: string | undefined;
2711
2822
  theme?: string | undefined;
2712
2823
  };
@@ -3000,6 +3111,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
3000
3111
  parser?: "dir" | "dot" | undefined;
3001
3112
  ui?: Record<string, Record<string, Record<string, string>>> | undefined;
3002
3113
  } | undefined;
3114
+ icons?: {
3115
+ library?: "lucide" | "fontawesome" | "tabler" | undefined;
3116
+ } | undefined;
3003
3117
  logo?: string | {
3004
3118
  dark?: string | undefined;
3005
3119
  light?: string | undefined;
@@ -3023,10 +3137,10 @@ export declare const blumeConfigSchema: z.ZodObject<{
3023
3137
  math?: boolean | undefined;
3024
3138
  } | undefined;
3025
3139
  mcp?: {
3140
+ name?: string | undefined;
3026
3141
  enabled?: boolean | undefined;
3027
3142
  route?: string | undefined;
3028
3143
  instructions?: string | undefined;
3029
- name?: string | undefined;
3030
3144
  } | undefined;
3031
3145
  navigation?: {
3032
3146
  sidebar?: SidebarItemConfig[] | undefined;
@@ -3059,10 +3173,6 @@ export declare const blumeConfigSchema: z.ZodObject<{
3059
3173
  tag?: string | undefined;
3060
3174
  }[] | undefined;
3061
3175
  }[] | undefined;
3062
- sidebarVariants?: {
3063
- path: string;
3064
- items?: SidebarItemConfig[] | undefined;
3065
- }[] | undefined;
3066
3176
  tabs?: {
3067
3177
  path: string;
3068
3178
  label: string;
@@ -3086,6 +3196,9 @@ export declare const blumeConfigSchema: z.ZodObject<{
3086
3196
  route?: string | undefined;
3087
3197
  }[] | undefined;
3088
3198
  theme?: string | undefined;
3199
+ codeSamples?: string[] | undefined;
3200
+ expandSchemas?: boolean | undefined;
3201
+ renderer?: "blume" | "scalar" | undefined;
3089
3202
  } | undefined;
3090
3203
  redirects?: {
3091
3204
  from: string;
@@ -44,6 +44,13 @@ export interface ProjectContext {
44
44
  pagesRoot: string | null;
45
45
  /** Absolute path to the generated runtime (`<root>/.blume`). */
46
46
  outDir: string;
47
+ /**
48
+ * Absolute path to the Astro build output. `<root>/dist` normally; for a
49
+ * relocated runtime (isolated verify build) it lives under the runtime dir so
50
+ * it never empties the real `dist/`. Optional so hand-built test contexts and
51
+ * older callers still typecheck; `resolveProjectContext` always sets it.
52
+ */
53
+ distDir?: string;
47
54
  /** Absolute path to the user `theme.css`, if present. */
48
55
  themeFile: string | null;
49
56
  /** Absolute path to the user `components.ts`/`.tsx`, if present. */
@@ -161,11 +168,6 @@ export interface NavSelector {
161
168
  kind: "dropdown" | "language" | "product" | "version";
162
169
  items: NavSelectorItem[];
163
170
  }
164
- /** Sidebar tree used when the current route belongs to a nav partition. */
165
- export interface NavSidebarVariant {
166
- path: string;
167
- sidebar: NavNode[];
168
- }
169
171
  /** Chrome overrides used when the current route belongs to a nav partition. */
170
172
  export interface NavChromeVariant {
171
173
  path: string;
@@ -177,7 +179,6 @@ export interface Navigation {
177
179
  selectors: NavSelector[];
178
180
  chromeVariants: NavChromeVariant[];
179
181
  sidebar: NavNode[];
180
- sidebarVariants: NavSidebarVariant[];
181
182
  /** Repo URL for the header link, or null when hidden (`navigation.repo`). */
182
183
  repoUrl?: string | null;
183
184
  }
@@ -1,2 +1,16 @@
1
1
  import type { BlumeConfig } from "../../core/schema.ts";
2
+ type JsonObject = Record<string, unknown>;
3
+ export interface MintlifyRedirectPartition {
4
+ /** Static redirects Blume can honor, translated to Blume's `from`/`to` shape. */
5
+ kept: NonNullable<BlumeConfig["redirects"]>;
6
+ /** Source paths of dynamic redirects dropped because Blume can't model them. */
7
+ dropped: string[];
8
+ }
9
+ /**
10
+ * Split a spec's redirects into the static ones Blume emits and the dynamic
11
+ * (wildcard/param) ones it drops. Keeping a dynamic redirect crashes the Astro
12
+ * build, so the migrator surfaces the dropped sources as a warning instead.
13
+ */
14
+ export declare const partitionMintlifyRedirects: (spec: JsonObject) => MintlifyRedirectPartition;
2
15
  export declare const loadMintlifyConfig: (root: string, file: string) => Promise<BlumeConfig>;
16
+ export {};
@@ -51,7 +51,9 @@ Go from an empty folder to a running docs site in a few commands. Blume needs **
51
51
  </Step>
52
52
  </Steps>
53
53
 
54
- :::tip Blume works with any package manager and never requires you to set up Astro or Tailwind yourself. :::
54
+ :::tip
55
+ Blume works with any package manager and never requires you to set up Astro or Tailwind yourself.
56
+ :::
55
57
 
56
58
  ## Write your first page
57
59
 
@@ -65,7 +67,9 @@ description: Welcome to my docs.
65
67
 
66
68
  Welcome! Use **Markdown** and built-in components — no imports required:
67
69
 
68
- :::note Blume ships callouts, cards, tabs, steps, and more. :::
70
+ :::note
71
+ Blume ships callouts, cards, tabs, steps, and more.
72
+ :::
69
73
  ```
70
74
 
71
75
  Save it, and the dev server reloads instantly. Navigation, search, and page metadata are inferred from your files as you add them — keep writing, and the site keeps up.
@@ -86,7 +86,9 @@ On **Vercel**, **Netlify**, and **Cloudflare Pages**, Blume picks the matching a
86
86
 
87
87
  A server build includes everything a static build does, plus any Astro endpoints or middleware you add. The `node` adapter produces a standalone server you can run directly.
88
88
 
89
- :::note Server features have their own configuration — for example, Ask AI needs a model API key. See the [AI guide](/docs/configuration/ai) for setup. :::
89
+ :::note
90
+ Server features have their own configuration — for example, Ask AI needs a model API key. See the [AI guide](/docs/configuration/ai) for setup.
91
+ :::
90
92
 
91
93
  ## Redirects
92
94
 
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  title: OpenAPI / AsyncAPI
3
- description: Drop in an OpenAPI or AsyncAPI spec and get an interactive reference, rendered by Scalar.
3
+ description: Drop in an OpenAPI spec and get a native API reference — one real page per operation, in your sidebar and search.
4
4
  ---
5
5
 
6
- Point Blume at an OpenAPI or AsyncAPI spec and it generates an interactive API reference schemas, authentication, examples, and a request playground on its own route. The reference is rendered by [Scalar](https://scalar.com), not by Blume: API reference isn't core to Blume, so the whole surface is delegated to a tool that has already solved its large edge-case space.
6
+ Point Blume at an OpenAPI spec and it generates a native API reference: one **real page per operation**, grouped by tag in a tab-scoped sidebar, with schema tables, request/response examples, and generated code samples. Because each operation is a genuine Blume page, it gets its own URL, shows up in **site search** and `llms.txt`, and gets an Open Graph image the same as any hand-written doc.
7
7
 
8
8
  ```ts blume.config.ts lineNumbers
9
9
  openapi: {
@@ -12,13 +12,15 @@ openapi: {
12
12
  }
13
13
  ```
14
14
 
15
- That mounts the reference at `/reference` and adds a header link to it. The `spec` is either an `http(s)` URL or a path to a local file in your project.
15
+ That mounts the reference at `/reference` (an overview page) with each operation at `/reference/<tag>/<operation>`, and adds a header tab. The `spec` is either an `http(s)` URL or a path to a local file in your project. Blume parses it with [Scalar's OpenAPI parser](https://github.com/scalar/scalar) — Swagger 2.0 and OpenAPI 3.0 specs are upgraded to 3.1 automatically.
16
16
 
17
- :::note The reference mounts inside Blume's shell — your navbar stays on top — but the body is a **self-contained Scalar embed** with its own sidebar, search, and theme. By design it doesn't weave into Blume's content sidebar, site search, or `llms.txt`. :::
17
+ :::note
18
+ Operations are indexed for search by their **summary and tag**. The rendered schema tables and code samples aren't full-text indexed; search matches an operation's title and section, then links to its own page.
19
+ :::
18
20
 
19
21
  ## A local spec
20
22
 
21
- A relative path is resolved from your project root and inlined at build time, so nothing is copied into your source tree and the page works offline:
23
+ A relative path is resolved from your project root and read at build time. Both JSON and YAML work:
22
24
 
23
25
  ```ts blume.config.ts lineNumbers
24
26
  openapi: {
@@ -27,23 +29,34 @@ openapi: {
27
29
  }
28
30
  ```
29
31
 
30
- Both JSON and YAML specs work; Scalar auto-detects the format.
31
-
32
32
  ## Route
33
33
 
34
- `route` controls where the reference mounts (and the header link's target):
34
+ `route` controls where the reference mounts — the overview page and the prefix for every operation route (and the header tab's target):
35
35
 
36
36
  ```ts blume.config.ts lineNumbers
37
37
  openapi: {
38
38
  enabled: true,
39
- route: "/api",
39
+ route: "/api", // overview at /api, operations at /api/<tag>/<operation>
40
40
  spec: "./openapi.yaml",
41
41
  }
42
42
  ```
43
43
 
44
+ ## Code samples and schemas
45
+
46
+ `codeSamples` picks which languages render per operation (built in: `curl`, `js`, `python`); `expandSchemas` starts nested schema rows expanded rather than collapsed:
47
+
48
+ ```ts blume.config.ts lineNumbers
49
+ openapi: {
50
+ enabled: true,
51
+ spec: "./openapi.yaml",
52
+ codeSamples: ["curl", "js"],
53
+ expandSchemas: true,
54
+ }
55
+ ```
56
+
44
57
  ## Multiple specs
45
58
 
46
- Use `sources` to publish more than one spec. Each source gets its own route and header link. Give each a `label` (used for the link and to derive its route), or set an explicit `route`:
59
+ Use `sources` to publish more than one spec. Each source gets its own overview route, operation pages, and header tab. Give each a `label` (used for the tab and to derive its route), or set an explicit `route`:
47
60
 
48
61
  ```ts blume.config.ts lineNumbers
49
62
  openapi: {
@@ -57,31 +70,32 @@ openapi: {
57
70
 
58
71
  `spec` is shorthand for a single-entry `sources`, so you only reach for `sources` when you have more than one.
59
72
 
60
- ## AsyncAPI
73
+ ## The Scalar renderer
61
74
 
62
- Event-driven APIs use a sibling `asyncapi` block with the **same shape**Scalar renders AsyncAPI through the same component. Only the default route differs (`/events`):
75
+ The native renderer is the default. If you'd rather embed [Scalar](https://scalar.com)'s self-contained API reference its own sidebar, search, theme, and "Try it" playground on a single route set `renderer: "scalar"`:
63
76
 
64
77
  ```ts blume.config.ts lineNumbers
65
- asyncapi: {
78
+ openapi: {
66
79
  enabled: true,
67
- spec: "./asyncapi.yaml",
80
+ renderer: "scalar",
81
+ spec: "./openapi.yaml",
82
+ theme: "purple", // a Scalar theme name (Scalar renderer only)
68
83
  }
69
84
  ```
70
85
 
71
- :::warning Scalar's AsyncAPI support is still a work in progress — it renders channels, operations, messages, and a Models section, but there's **no interactive playground** for events yet. It improves upstream over time. :::
86
+ A Scalar-rendered reference is a self-contained embed on its own route — it doesn't weave into Blume's sidebar, search, or `llms.txt`. Its "Try it" playground calls your **target API directly from the browser** (Blume doesn't proxy), so the API must allow cross-origin requests from the docs site (`Access-Control-Allow-Origin`). `theme` and the playground apply to the Scalar renderer only.
72
87
 
73
- ## Theming
88
+ ## AsyncAPI
74
89
 
75
- By default Blume layers your [accent and radius](/docs/configuration/theming) onto Scalar's theme so the reference doesn't feel jarring. It's best-effort, not pixel-identical Scalar carries its own design system. To pick a specific [Scalar theme](https://github.com/scalar/scalar) instead, set `theme`:
90
+ Event-driven APIs use a sibling `asyncapi` block with the same shape. AsyncAPI is rendered by Scalar (the native renderer is OpenAPI-only for now); only the default route differs (`/events`):
76
91
 
77
92
  ```ts blume.config.ts lineNumbers
78
- openapi: {
93
+ asyncapi: {
79
94
  enabled: true,
80
- spec: "./openapi.yaml",
81
- theme: "purple",
95
+ spec: "./asyncapi.yaml",
82
96
  }
83
97
  ```
84
98
 
85
- ## The playground and CORS
86
-
87
- Scalar's "Try it" playground calls your **target API directly from the browser** — Blume doesn't proxy the request. For it to succeed, the API must allow cross-origin requests from the docs site (send the appropriate `Access-Control-Allow-Origin` headers). This is a property of the API being documented, not of Blume.
99
+ :::warning
100
+ Scalar's AsyncAPI support is still a work in progress — it renders channels, operations, messages, and a Models section, but there's **no interactive playground** for events yet. It improves upstream over time.
101
+ :::