blume 1.6.6 → 1.7.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 (99) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/cli/{chunk-etsqspj6.js → chunk-12dzsn9b.js} +140 -23
  3. package/dist/cli/{chunk-etsqspj6.js.map → chunk-12dzsn9b.js.map} +6 -5
  4. package/dist/cli/{chunk-aerwpe14.js → chunk-4ae4f395.js} +164 -51
  5. package/dist/cli/chunk-4ae4f395.js.map +15 -0
  6. package/dist/cli/{chunk-m3p3wahd.js → chunk-52cwcqvp.js} +4 -4
  7. package/dist/cli/{chunk-j00ezcg5.js → chunk-5gfw0q4j.js} +9 -9
  8. package/dist/cli/{chunk-bawgnt8x.js → chunk-6mq7qkve.js} +3 -3
  9. package/dist/cli/{chunk-nyqzjdhj.js → chunk-82atea4k.js} +5 -5
  10. package/dist/cli/{chunk-tc89yh2r.js → chunk-8p3xe5jv.js} +2 -2
  11. package/dist/cli/{chunk-s4k1pnvf.js → chunk-90pdhkpm.js} +11 -11
  12. package/dist/cli/{chunk-n0y172hf.js → chunk-aqjvpd03.js} +4 -4
  13. package/dist/cli/{chunk-x1vrdjyk.js → chunk-h9ekmtz7.js} +5 -5
  14. package/dist/cli/{chunk-f75cqye8.js → chunk-he2zfgah.js} +10 -10
  15. package/dist/cli/{chunk-s4jn7f1q.js → chunk-j5f2wrj5.js} +2 -2
  16. package/dist/cli/{chunk-wkq5tbtq.js → chunk-k0v1f8bb.js} +3 -3
  17. package/dist/cli/{chunk-n4qjabmt.js → chunk-ka5k7cz9.js} +6 -19
  18. package/dist/cli/{chunk-n4qjabmt.js.map → chunk-ka5k7cz9.js.map} +3 -4
  19. package/dist/cli/{chunk-5yvt556e.js → chunk-kmx2mydj.js} +2 -2
  20. package/dist/cli/{chunk-ag1zyr5x.js → chunk-mfm4sjwx.js} +11 -11
  21. package/dist/cli/{chunk-0ewz4trd.js → chunk-np8dmfb0.js} +6 -6
  22. package/dist/cli/{chunk-cnvm6k3e.js → chunk-pdwg3q9g.js} +11 -11
  23. package/dist/cli/{chunk-vv237fp3.js → chunk-q56730e0.js} +26 -12
  24. package/dist/cli/{chunk-vv237fp3.js.map → chunk-q56730e0.js.map} +3 -3
  25. package/dist/cli/{chunk-3k0kzs6d.js → chunk-qvvpnwaz.js} +2 -2
  26. package/dist/cli/{chunk-vv3f8mb6.js → chunk-r99hynxh.js} +25 -24
  27. package/dist/cli/{chunk-vv3f8mb6.js.map → chunk-r99hynxh.js.map} +4 -4
  28. package/dist/cli/{chunk-wb067mv3.js → chunk-vyqj481z.js} +19 -7
  29. package/dist/cli/chunk-vyqj481z.js.map +13 -0
  30. package/dist/cli/{chunk-62qsssnh.js → chunk-x1wvw7a8.js} +411 -145
  31. package/dist/cli/chunk-x1wvw7a8.js.map +40 -0
  32. package/dist/cli/{chunk-9sh49q0h.js → chunk-ywn7t0pb.js} +2 -2
  33. package/dist/cli/index.js +13 -13
  34. package/dist/types/components/layout/nav-utils.d.ts +46 -1
  35. package/dist/types/core/config-input.d.ts +7 -0
  36. package/dist/types/core/schema.d.ts +2 -0
  37. package/dist/types/theme/fonts.d.ts +22 -22
  38. package/docs/02-deployment.mdx +21 -0
  39. package/docs/08-faq.mdx +21 -0
  40. package/docs/configuration/ask-ai.mdx +16 -0
  41. package/docs/content/navigation.mdx +2 -0
  42. package/docs/content/sources.mdx +2 -2
  43. package/docs/content/syntax.mdx +1 -1
  44. package/docs/discoverability/open-graph.mdx +4 -0
  45. package/package.json +1 -1
  46. package/src/ai/ask.ts +31 -4
  47. package/src/astro/generate.ts +142 -5
  48. package/src/astro/integration.ts +12 -1
  49. package/src/astro/module-types.ts +9 -0
  50. package/src/astro/templates.ts +260 -56
  51. package/src/cli/commands/build.ts +28 -0
  52. package/src/components/Icon.astro +24 -0
  53. package/src/components/content/YouTube.astro +1 -1
  54. package/src/components/icon-sprite-middleware.ts +41 -0
  55. package/src/components/icon-sprite.ts +93 -0
  56. package/src/components/layout/Header.astro +1 -1
  57. package/src/components/layout/IconSprite.astro +11 -0
  58. package/src/components/layout/NavTree.astro +156 -188
  59. package/src/components/layout/NavTreeCache.astro +45 -0
  60. package/src/components/layout/NavTreeScript.astro +256 -0
  61. package/src/components/layout/PageActions.astro +11 -5
  62. package/src/components/layout/PageLayout.astro +7 -0
  63. package/src/components/layout/ReferenceLayout.astro +7 -0
  64. package/src/components/layout/RootLayout.astro +30 -2
  65. package/src/components/layout/Search.astro +11 -0
  66. package/src/components/layout/nav-cache.ts +49 -0
  67. package/src/components/layout/nav-utils.ts +87 -1
  68. package/src/core/config-input.ts +7 -0
  69. package/src/core/schema.ts +5 -0
  70. package/src/core/sources/assets.ts +162 -26
  71. package/src/core/sources/notion.ts +60 -1
  72. package/src/markdown/language-icon.ts +64 -20
  73. package/src/markdown/mermaid.ts +11 -0
  74. package/src/og/cache.ts +236 -0
  75. package/src/og/card.ts +12 -4
  76. package/src/og/index.ts +8 -1
  77. package/src/registry/eject.ts +24 -8
  78. package/src/theme/entry.ts +50 -7
  79. package/src/theme/fonts.ts +30 -23
  80. package/dist/cli/chunk-62qsssnh.js.map +0 -36
  81. package/dist/cli/chunk-aerwpe14.js.map +0 -15
  82. package/dist/cli/chunk-wb067mv3.js.map +0 -13
  83. /package/dist/cli/{chunk-m3p3wahd.js.map → chunk-52cwcqvp.js.map} +0 -0
  84. /package/dist/cli/{chunk-j00ezcg5.js.map → chunk-5gfw0q4j.js.map} +0 -0
  85. /package/dist/cli/{chunk-bawgnt8x.js.map → chunk-6mq7qkve.js.map} +0 -0
  86. /package/dist/cli/{chunk-nyqzjdhj.js.map → chunk-82atea4k.js.map} +0 -0
  87. /package/dist/cli/{chunk-tc89yh2r.js.map → chunk-8p3xe5jv.js.map} +0 -0
  88. /package/dist/cli/{chunk-s4k1pnvf.js.map → chunk-90pdhkpm.js.map} +0 -0
  89. /package/dist/cli/{chunk-n0y172hf.js.map → chunk-aqjvpd03.js.map} +0 -0
  90. /package/dist/cli/{chunk-x1vrdjyk.js.map → chunk-h9ekmtz7.js.map} +0 -0
  91. /package/dist/cli/{chunk-f75cqye8.js.map → chunk-he2zfgah.js.map} +0 -0
  92. /package/dist/cli/{chunk-s4jn7f1q.js.map → chunk-j5f2wrj5.js.map} +0 -0
  93. /package/dist/cli/{chunk-wkq5tbtq.js.map → chunk-k0v1f8bb.js.map} +0 -0
  94. /package/dist/cli/{chunk-5yvt556e.js.map → chunk-kmx2mydj.js.map} +0 -0
  95. /package/dist/cli/{chunk-ag1zyr5x.js.map → chunk-mfm4sjwx.js.map} +0 -0
  96. /package/dist/cli/{chunk-0ewz4trd.js.map → chunk-np8dmfb0.js.map} +0 -0
  97. /package/dist/cli/{chunk-cnvm6k3e.js.map → chunk-pdwg3q9g.js.map} +0 -0
  98. /package/dist/cli/{chunk-3k0kzs6d.js.map → chunk-qvvpnwaz.js.map} +0 -0
  99. /package/dist/cli/{chunk-9sh49q0h.js.map → chunk-ywn7t0pb.js.map} +0 -0
@@ -3,19 +3,19 @@ import {
3
3
  API_CATALOG_PATH,
4
4
  OPENAPI_PATH,
5
5
  hasApiCatalog
6
- } from "./chunk-3k0kzs6d.js";
6
+ } from "./chunk-qvvpnwaz.js";
7
7
  import {
8
8
  searchProviderMeta
9
9
  } from "./chunk-wd27zjcz.js";
10
10
  import {
11
11
  BLUME_IGNORE_DIRS,
12
12
  TOC_HIDDEN_KEY
13
- } from "./chunk-etsqspj6.js";
13
+ } from "./chunk-12dzsn9b.js";
14
14
  import {
15
15
  buildFontEntries,
16
16
  fontLocaleCodes,
17
17
  hasScalarReferences
18
- } from "./chunk-vv3f8mb6.js";
18
+ } from "./chunk-r99hynxh.js";
19
19
  import {
20
20
  normalizeBasePath,
21
21
  trimChar,
@@ -134,20 +134,23 @@ var ASK_PRESETS = {
134
134
  }
135
135
  };
136
136
  var DEFAULT_MODEL = "openai/gpt-5.5";
137
+ var askHeadersField = (ask) => ask?.headers && Object.keys(ask.headers).length > 0 ? { headers: ask.headers } : {};
137
138
  var resolveAskBackend = (ask) => {
138
139
  const provider = ask?.provider ?? "gateway";
139
140
  const model = ask?.model ?? DEFAULT_MODEL;
141
+ const headers = askHeadersField(ask);
140
142
  if (provider === "gateway") {
141
- return { kind: "gateway", model };
143
+ return { ...headers, kind: "gateway", model };
142
144
  }
143
145
  const preset = ASK_PRESETS[provider];
144
146
  const apiKeyEnv = ask?.apiKeyEnv ?? preset?.apiKeyEnv ?? "API_KEY";
145
147
  if (provider === "openrouter") {
146
- return { apiKeyEnv, kind: "openrouter", model };
148
+ return { apiKeyEnv, ...headers, kind: "openrouter", model };
147
149
  }
148
150
  return {
149
151
  apiKeyEnv,
150
152
  baseUrl: ask?.baseUrl ?? preset?.baseUrl ?? "",
153
+ ...headers,
151
154
  kind: OPENAI_COMPATIBLE,
152
155
  model,
153
156
  name: preset?.name ?? OPENAI_COMPATIBLE
@@ -279,6 +282,7 @@ var resolveCloudflareAdapterArgs = (context) => {
279
282
  };
280
283
  var resolveSessionOption = (deployment) => deployment.output === "server" && deployment.adapter === "cloudflare" ? `
281
284
  session: false,` : "";
285
+ var astroFontWeights = (weights) => JSON.stringify(weights).replaceAll(/(?<min>\d+)\.\.(?<max>\d+)/gu, "$<min> $<max>");
282
286
  var astroConfigImportLine = (options) => {
283
287
  const names = ["defineConfig"];
284
288
  if (options.hasFonts) {
@@ -374,16 +378,17 @@ const blumeConfig = await loadBlumeConfig(resolve(dirname(fileURLToPath(import.m
374
378
  };
375
379
  var renderImageOption = (config) => config.image.domains.length > 0 || config.image.remotePatterns.length > 0 ? `
376
380
  image: ${JSON.stringify(config.image)},` : "";
381
+ var ALL_CLIENT_FEATURES = { epub: true, mermaid: true };
377
382
  var resolveOptimizeDeps = (options) => {
378
- const { context } = options;
383
+ const { context, features } = options;
379
384
  const optimizeDepsEntries = [
380
385
  ...context.pagesRoot ? [`${context.pagesRoot}/**/*.astro`] : [],
381
386
  `${context.root}/islands/**/*.{jsx,svelte,tsx,vue}`,
382
387
  ...[...new Set(Object.values(options.aliases ?? {}))].toSorted().map((dir) => `${dir}/**/*.{astro,jsx,svelte,tsx,vue}`)
383
388
  ];
384
389
  const optimizeDepsInclude = [
385
- "blume > mermaid",
386
- "blume > epub-gen-memory/bundle",
390
+ ...features.mermaid ? ["blume > mermaid"] : [],
391
+ ...features.epub ? ["blume > epub-gen-memory/bundle"] : [],
387
392
  ...options.needsReact && options.reactCompilerPath ? ["react/compiler-runtime"] : []
388
393
  ];
389
394
  return { optimizeDepsEntries, optimizeDepsInclude };
@@ -414,6 +419,8 @@ var astroConfigTemplate = (options) => {
414
419
  contentRoutes,
415
420
  examplesPath,
416
421
  examplesThemePath,
422
+ features = ALL_CLIENT_FEATURES,
423
+ featuresPath,
417
424
  generatedModulesDir,
418
425
  needsSvelte,
419
426
  needsVue,
@@ -431,6 +438,7 @@ var astroConfigTemplate = (options) => {
431
438
  const { optimizeDepsEntries, optimizeDepsInclude } = resolveOptimizeDeps({
432
439
  aliases: options.aliases,
433
440
  context,
441
+ features,
434
442
  needsReact,
435
443
  reactCompilerPath: options.reactCompilerPath
436
444
  });
@@ -484,7 +492,7 @@ var astroConfigTemplate = (options) => {
484
492
  isAbsolute(variant.src) ? variant.src : join2(context.root, variant.src)
485
493
  ]
486
494
  };
487
- }))} } }` : `{ provider: fontProviders.${font.provider}(), name: ${JSON.stringify(font.name)}, cssVariable: ${JSON.stringify(font.cssVariable)}, weights: ${JSON.stringify(font.weights)}, subsets: ${JSON.stringify(font.subsets)}, fallbacks: ${JSON.stringify(font.fallbacks)} }`).join(", ")}],` : "";
495
+ }))} } }` : `{ provider: fontProviders.${font.provider}(), name: ${JSON.stringify(font.name)}, cssVariable: ${JSON.stringify(font.cssVariable)}, weights: ${astroFontWeights(font.weights)}, subsets: ${JSON.stringify(font.subsets)}, fallbacks: ${JSON.stringify(font.fallbacks)} }`).join(", ")}],` : "";
488
496
  const defineConfigImport = astroConfigImportLine({
489
497
  hasFonts: fontEntries.length > 0
490
498
  });
@@ -536,7 +544,8 @@ var astroConfigTemplate = (options) => {
536
544
  userIntegrationSpread
537
545
  } = renderIntegrationBridge(options.integrationBridge);
538
546
  return `// Generated by Blume. Do not edit; this file is recreated on each run.
539
- ${configSourceMarker}${userConfigImports}${defineConfigImport}
547
+ ${configSourceMarker}${userConfigImports}import { availableParallelism } from "node:os";
548
+ ${defineConfigImport}
540
549
  import mdx from "@astrojs/mdx";
541
550
  import tailwindcss from "@tailwindcss/vite";
542
551
  import { blumeMarkdownProcessor, blumeMdxProcessor, blumeShikiTransformers, blumeTwoslashTransformer } from "blume/markdown";
@@ -579,6 +588,12 @@ ${userConfigSetup}export default defineConfig({
579
588
  // request latency behind the user's intent, so most navigations swap
580
589
  // instantly.
581
590
  prefetch: { prefetchAll: true },
591
+ // Prerender several pages at once. Rendering is single-threaded, but a
592
+ // page's OG card renders on a native thread and its HTML is written
593
+ // asynchronously, so the main thread would otherwise idle behind each
594
+ // page's off-thread work. Capped at 8: the gain flattens there and beyond it
595
+ // the overlap only adds memory.
596
+ build: { concurrency: Math.min(8, availableParallelism()) },
582
597
  vite: {${viteCacheOption}
583
598
  plugins: [${runtimeModulesPluginEntry}tailwindcss(), includeHmrPlugin(${JSON.stringify(`${context.outDir}/src/generated/includes.json`)}), prerenderDepsPlugin()],
584
599
  // Everything hydration can reach must be part of the dev dep optimizer's
@@ -629,6 +644,7 @@ ${userConfigSetup}export default defineConfig({
629
644
  "blume:ask": ${JSON.stringify(askPath)},
630
645
  "blume:examples": ${JSON.stringify(examplesPath)},
631
646
  "blume:examples-theme": ${JSON.stringify(examplesThemePath)},
647
+ "blume:features": ${JSON.stringify(featuresPath)},
632
648
  "blume:search-client": ${JSON.stringify(searchClientPath)},
633
649
  "blume:theme": ${JSON.stringify(themePath)},${runtimeModuleAliasLines}${userAliasLines}
634
650
  },
@@ -711,15 +727,21 @@ ${instructions}` : ASK_FALLBACK_PROMPT;
711
727
  ];
712
728
  let setup = "";
713
729
  let modelExpr = JSON.stringify(backend.model);
730
+ const headersField = backend.headers ? `
731
+ headers: ${JSON.stringify(backend.headers)},` : "";
714
732
  if (backend.kind === "gateway") {
715
733
  setup = `
716
- const gateway = createGateway({ apiKey: getSecret("AI_GATEWAY_API_KEY") });
734
+ const gateway = createGateway({
735
+ apiKey: getSecret("AI_GATEWAY_API_KEY"),${headersField}
736
+ });
717
737
  `;
718
738
  modelExpr = `gateway(${JSON.stringify(backend.model)})`;
719
739
  } else if (backend.kind === "openrouter") {
720
740
  imports.push('import { createOpenRouter } from "@openrouter/ai-sdk-provider";');
721
741
  setup = `
722
- const openrouter = createOpenRouter({ apiKey: getSecret(${JSON.stringify(backend.apiKeyEnv)}) });
742
+ const openrouter = createOpenRouter({
743
+ apiKey: getSecret(${JSON.stringify(backend.apiKeyEnv)}),${headersField}
744
+ });
723
745
  `;
724
746
  modelExpr = `openrouter(${JSON.stringify(backend.model)})`;
725
747
  } else if (backend.kind === "openai-compatible") {
@@ -727,7 +749,7 @@ const openrouter = createOpenRouter({ apiKey: getSecret(${JSON.stringify(backend
727
749
  setup = `
728
750
  const provider = createOpenAICompatible({
729
751
  apiKey: getSecret(${JSON.stringify(backend.apiKeyEnv)}),
730
- baseURL: ${JSON.stringify(backend.baseUrl)},
752
+ baseURL: ${JSON.stringify(backend.baseUrl)},${headersField}
731
753
  name: ${JSON.stringify(backend.name)},
732
754
  });
733
755
  `;
@@ -888,6 +910,20 @@ var hostedSearchOptions = (search) => {
888
910
  }
889
911
  }
890
912
  };
913
+ var featuresTemplate = (features) => `// Generated by Blume. Do not edit.
914
+ //
915
+ // The client features this site uses. A feature no page needs stays out of
916
+ // the module graph entirely: its loader is null and its library never enters
917
+ // the client bundle.
918
+
919
+ /** Registers the <blume-mermaid> element; null when no page has a mermaid fence. */
920
+ export const loadMermaid: (() => Promise<unknown>) | null = ${features.mermaid ? '() => import("blume/components/content/mermaid-element.ts")' : "null"};
921
+
922
+ /** The EPUB generator's browser bundle; null when export.epub is off. */
923
+ export const loadEpub:
924
+ | (() => Promise<typeof import("epub-gen-memory/bundle")>)
925
+ | null = ${features.epub ? '() => import("epub-gen-memory/bundle")' : "null"};
926
+ `;
891
927
  var searchClientTemplate = (config) => {
892
928
  const { search } = config;
893
929
  if (search.provider === "orama" || search.provider === "flexsearch") {
@@ -1116,9 +1152,63 @@ export function GET({ props }: { props: { section: string } }) {
1116
1152
  });
1117
1153
  }
1118
1154
  `;
1155
+ var navFragmentTemplate = () => `---
1156
+ // Generated by Blume. Do not edit.
1157
+ import NavTree from "blume/components/layout/NavTree.astro";
1158
+ import { withBase } from "blume/components/islands/base-path.ts";
1159
+ import {
1160
+ hiddenDefaultLocale,
1161
+ navGroupIds,
1162
+ navVariants,
1163
+ } from "blume/components/layout/nav-utils.ts";
1164
+ import type { NavNode } from "blume/core/types.ts";
1165
+ import data from "blume:data";
1166
+
1167
+ export const prerender = true;
1168
+ // A partial: no doctype, head, or script/style injection — the rows only.
1169
+ export const partial = true;
1170
+
1171
+ // Only imports are in scope here (Astro hoists getStaticPaths), which is why
1172
+ // the variant walk lives in nav-utils.
1173
+ export function getStaticPaths() {
1174
+ return navVariants(data, hiddenDefaultLocale(data.config.i18n)).flatMap(
1175
+ ({ locale, navigation, version }) =>
1176
+ [...navGroupIds(navigation.sidebar)]
1177
+ .filter(([node]) => (node.display ?? "flat") !== "flat")
1178
+ .map(([, id]) => ({ params: { id, locale, version } }))
1179
+ );
1180
+ }
1181
+
1182
+ const { id, locale, version } = Astro.params;
1183
+ const variant = navVariants(data, hiddenDefaultLocale(data.config.i18n)).find(
1184
+ (entry) => entry.version === version && entry.locale === locale
1185
+ );
1186
+ const ids = variant
1187
+ ? navGroupIds(variant.navigation.sidebar)
1188
+ : new Map<NavNode, string>();
1189
+ const node = [...ids].find(([, groupId]) => groupId === id)?.[0];
1190
+ if (!(variant && node && node.kind === "group")) {
1191
+ return new Response(null, { status: 404 });
1192
+ }
1193
+ const strings =
1194
+ locale === "default" ? data.ui.nav : (data.uiByLocale[locale] ?? data.ui).nav;
1195
+ const fragmentBase = withBase(\`/blume-nav/\${version}/\${locale}\`);
1196
+ ---
1197
+
1198
+ <NavTree
1199
+ currentRoute=""
1200
+ depth={1}
1201
+ fragmentBase={fragmentBase}
1202
+ idPrefix={id}
1203
+ ids={ids}
1204
+ items={node.children}
1205
+ root={false}
1206
+ strings={strings}
1207
+ />
1208
+ `;
1119
1209
  var ogEndpointTemplate = (customRoutes = [], og = {}, includeChangelog = false) => `// Generated by Blume. Do not edit.
1120
- import { renderOgImage } from "blume/og";
1121
- import type { OgFont, OgFontFamilies } from "blume/og";
1210
+ import { cachedOgImage } from "blume/og";
1211
+ import type { OgCache, OgFont, OgFontFamilies } from "blume/og";
1122
1212
  import data from "blume:data";
1123
1213
 
1124
1214
  export const prerender = true;
@@ -1135,6 +1225,12 @@ const customRoutes: { slug: string; title: string }[] = ${JSON.stringify(customR
1135
1225
  const fonts: OgFont[] = ${JSON.stringify(og.fonts ?? [])};
1136
1226
  const families: OgFontFamilies | undefined = ${og.families ? JSON.stringify(og.families) : "undefined"};
1137
1227
 
1228
+ // Rendered cards are kept on disk between builds, keyed by everything that
1229
+ // decides their pixels, so a rebuild renders only the cards whose title,
1230
+ // description, branding, or fonts changed. The directory is a build-machine
1231
+ // path, baked in for the same reason as the local font paths above.
1232
+ const cache: OgCache | undefined = ${og.cache ? JSON.stringify(og.cache) : "undefined"};
1233
+
1138
1234
  // A page's own description (its \`seo.description\`, else \`description\`) is
1139
1235
  // the card subtitle, so the image says what the page's og:description says.
1140
1236
  // Pages without one fall back to the site-wide subtitle at render time.
@@ -1190,7 +1286,7 @@ const repoSlug = data.config.github
1190
1286
  : undefined;
1191
1287
 
1192
1288
  export async function GET({ props }: { props: CardProps }) {
1193
- const png = await renderOgImage({
1289
+ const png = await cachedOgImage(cache, {
1194
1290
  accent: data.config.og.palette?.accent ?? data.config.theme.accent.light,
1195
1291
  brand: data.config.title,
1196
1292
  description: props.description ?? data.config.og.description,
@@ -1252,22 +1348,13 @@ const htmlLang = i18n ? i18n.defaultLocale : "en";
1252
1348
  <ScalarComponent configuration={configuration} renderMode="client" />
1253
1349
  </ReferenceLayout>
1254
1350
  `;
1255
- var catchAllPageTemplate = (options) => {
1256
- const mathImport = options.mathEnabled ? `import Math from "blume/components/content/Math.astro";
1351
+ var contentComponentsSource = (mathEnabled) => {
1352
+ const mathImport = mathEnabled ? `import Math from "blume/components/content/Math.astro";
1257
1353
  ` : "";
1258
- const mathEntry = options.mathEnabled ? `Math,
1354
+ const mathEntry = mathEnabled ? `Math,
1259
1355
  ` : "";
1260
- const clientData = options.needsReact ? `
1261
- clientData={{ config: data.config, navigation, page: { route, title: seo.title ?? title } }}` : "";
1262
- return `---
1263
- // Generated by Blume. Do not edit.
1264
- import { getEntry, render } from "astro:content";
1265
- import type { CollectionKey } from "astro:content";
1266
- import RootLayout from "blume/components/layout/RootLayout.astro";
1267
- import { withBase } from "blume/components/islands/base-path.ts";
1268
- import { stripBasePath, withBasePath } from "blume/core/base-path.ts";
1269
- import { resolveSlot } from "blume/components/layout/overrides.ts";
1270
- import Accordion from "blume/components/content/Accordion.astro";
1356
+ return {
1357
+ imports: `import Accordion from "blume/components/content/Accordion.astro";
1271
1358
  import AccordionItem from "blume/components/content/AccordionItem.astro";
1272
1359
  import AutoTypeTable from "blume/components/content/AutoTypeTable.astro";
1273
1360
  import Badge from "blume/components/content/Badge.astro";
@@ -1307,19 +1394,8 @@ import ApiOverview from "blume/components/openapi/ApiOverview.astro";
1307
1394
  import ApiTagOperations from "blume/components/openapi/ApiTagOperations.astro";
1308
1395
  import Operation from "blume/components/openapi/Operation.astro";
1309
1396
  ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../generated/components.ts";
1310
- import { islandComponents } from "../generated/islands.ts";
1311
- import data from "blume:data";
1312
-
1313
- const Color = Object.assign(ColorRoot, { Item: ColorItem, Row: ColorRow });
1314
- const Tree = Object.assign(TreeRoot, { File: TreeFile, Folder: TreeFolder });
1315
-
1316
- // Docs content is file-based and always prerendered, even in server output
1317
- // (where only endpoints like /api/ask render on demand). Without this, server
1318
- // builds would render this route on demand and ignore getStaticPaths, leaving
1319
- // the entry id undefined.
1320
- export const prerender = true;
1321
-
1322
- const components = {
1397
+ import { islandComponents } from "../generated/islands.ts";`,
1398
+ map: `{
1323
1399
  Accordion,
1324
1400
  AccordionItem,
1325
1401
  ApiOverview,
@@ -1356,7 +1432,34 @@ const components = {
1356
1432
  YouTube,
1357
1433
  ${mathEntry}...islandComponents,
1358
1434
  ...userMdx,
1435
+ }`
1436
+ };
1359
1437
  };
1438
+ var catchAllPageTemplate = (options) => {
1439
+ const { imports: componentImports, map: componentMap } = contentComponentsSource(options.mathEnabled);
1440
+ const clientData = options.needsReact ? `
1441
+ clientData={{ config: data.config, navigation, page: { route, title: seo.title ?? title } }}` : "";
1442
+ return `---
1443
+ // Generated by Blume. Do not edit.
1444
+ import { getEntry, render } from "astro:content";
1445
+ import type { CollectionKey } from "astro:content";
1446
+ import RootLayout from "blume/components/layout/RootLayout.astro";
1447
+ import { withBase } from "blume/components/islands/base-path.ts";
1448
+ import { stripBasePath, withBasePath } from "blume/core/base-path.ts";
1449
+ import { resolveSlot } from "blume/components/layout/overrides.ts";
1450
+ ${componentImports}
1451
+ import data from "blume:data";
1452
+
1453
+ const Color = Object.assign(ColorRoot, { Item: ColorItem, Row: ColorRow });
1454
+ const Tree = Object.assign(TreeRoot, { File: TreeFile, Folder: TreeFolder });
1455
+
1456
+ // Docs content is file-based and always prerendered, even in server output
1457
+ // (where only endpoints like /api/ask render on demand). Without this, server
1458
+ // builds would render this route on demand and ignore getStaticPaths, leaving
1459
+ // the entry id undefined.
1460
+ export const prerender = true;
1461
+
1462
+ const components = ${componentMap};
1360
1463
 
1361
1464
  export function getStaticPaths() {
1362
1465
  return data.routes.map((route) => ({
@@ -1625,7 +1728,8 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1625
1728
  editUrl={editUrl}
1626
1729
  feedback={data.config.feedback}
1627
1730
  exportPdf={${options.exportPdf}}
1628
- exportEpub={${options.exportEpub}}
1731
+ exportEpub={${options.exportEpub}}${options.navFragments ? `
1732
+ navFragmentBase={withBase(\`/blume-nav/\${version || "current"}/\${i18n && localePrefix(locale) ? locale : "default"}\`)}` : ""}
1629
1733
  openInChat={data.config.openInChat}
1630
1734
  feeds={data.feeds}
1631
1735
  discovery={data.config.discovery}
@@ -1649,6 +1753,7 @@ var changelogIndexTemplate = (options) => {
1649
1753
  clientData={{ config: data.config, navigation: data.navigation, page: { route: "/changelog", title: pageTitle } }}` : "";
1650
1754
  const stagedSpread = options.staged ? `
1651
1755
  ...(await getCollection("staged")),` : "";
1756
+ const { imports: componentImports, map: componentMap } = contentComponentsSource(options.mathEnabled);
1652
1757
  return `---
1653
1758
  // Generated by Blume. Do not edit.
1654
1759
  import { getCollection, render } from "astro:content";
@@ -1657,11 +1762,19 @@ import Update from "blume/components/content/Update.astro";
1657
1762
  import { withBase } from "blume/components/islands/base-path.ts";
1658
1763
  import { resolveSlot } from "blume/components/layout/overrides.ts";
1659
1764
  import { resolveDateFormatOptions } from "blume/core/date-format.ts";
1660
- import { layoutOverrides } from "../generated/components.ts";
1765
+ ${componentImports}
1661
1766
  import data from "blume:data";
1662
1767
 
1768
+ const Color = Object.assign(ColorRoot, { Item: ColorItem, Row: ColorRow });
1769
+ const Tree = Object.assign(TreeRoot, { File: TreeFile, Folder: TreeFolder });
1770
+
1663
1771
  export const prerender = true;
1664
1772
 
1773
+ // Entry bodies are MDX rendered outside the catch-all, so they need the same
1774
+ // component map: a \`:::\` callout or \`<Steps>\` in a release note otherwise
1775
+ // throws "Expected component ... to be defined" at build time.
1776
+ const components = ${componentMap};
1777
+
1665
1778
  const entryDate = (entry: {
1666
1779
  data: { date?: string | null; changelog?: { date?: string | null } | null };
1667
1780
  }) => entry.data.date ?? entry.data.changelog?.date ?? null;
@@ -1860,7 +1973,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1860
1973
  >
1861
1974
  {majorGroups[0].items.map(({ Content, href, id, label, date, tags }) => (
1862
1975
  <Update description={date} href={href} id={id} label={label} tags={tags}>
1863
- <Content />
1976
+ <Content components={components} />
1864
1977
  </Update>
1865
1978
  ))}
1866
1979
  {majorGroups.slice(1).map((group) => (
@@ -1871,7 +1984,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1871
1984
  >
1872
1985
  {group.items.map(({ Content, href, id, label, date, tags }) => (
1873
1986
  <Update description={date} href={href} id={id} label={label} tags={tags}>
1874
- <Content />
1987
+ <Content components={components} />
1875
1988
  </Update>
1876
1989
  ))}
1877
1990
  </section>
@@ -1891,7 +2004,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1891
2004
  <div class="not-prose mt-8">
1892
2005
  {items.map(({ Content, href, id, label, date, tags }) => (
1893
2006
  <Update description={date} href={href} id={id} label={label} tags={tags}>
1894
- <Content />
2007
+ <Content components={components} />
1895
2008
  </Update>
1896
2009
  ))}
1897
2010
  </div>
@@ -2364,7 +2477,7 @@ var runtimeTsconfigTemplate = () => `${JSON.stringify({
2364
2477
  }, null, 2)}
2365
2478
  `;
2366
2479
 
2367
- export { ADAPTER_IGNORE_DIRS, servesClientSubdir, deployStaticDir, surfaceAdapterOutput, resolveAskBackend, askBackendRuntimeDep, buildHomeLinkHeader, platformRedirects, publishRuntimeModules, runtimeDependencies, astroConfigTemplate, stagedContentDir, contentConfigTemplate, askEndpointTemplate, askComponentTemplate, searchEndpointTemplate, searchClientTemplate, mixedbreadSearchEndpointTemplate, rawMarkdownEndpointTemplate, contentAssetsEndpointTemplate, mcpPageFile, mcpEndpointTemplate, playgroundProxyTemplate, staticJsonEndpointTemplate, rssEndpointTemplate, ogEndpointTemplate, scalarReferenceTemplate, catchAllPageTemplate, changelogIndexTemplate, notFoundPageTemplate, notFoundMarkdownTemplate, notFoundJsonTemplate, apiPagesIndexTemplate, apiPageTemplate, apiNavigationTemplate, apiSearchTemplate, apiNotFoundTemplate, islandWrapperTemplate, islandMapTemplate, exampleSlug, exampleWrapperTemplate, examplesRouteBase, exampleMapTemplate, examplesPageTemplate, runtimePackageTemplate, runtimeTsconfigTemplate };
2480
+ export { ADAPTER_IGNORE_DIRS, servesClientSubdir, deployStaticDir, surfaceAdapterOutput, resolveAskBackend, askBackendRuntimeDep, buildHomeLinkHeader, platformRedirects, publishRuntimeModules, runtimeDependencies, astroConfigTemplate, stagedContentDir, contentConfigTemplate, askEndpointTemplate, askComponentTemplate, searchEndpointTemplate, featuresTemplate, searchClientTemplate, mixedbreadSearchEndpointTemplate, rawMarkdownEndpointTemplate, contentAssetsEndpointTemplate, mcpPageFile, mcpEndpointTemplate, playgroundProxyTemplate, staticJsonEndpointTemplate, rssEndpointTemplate, navFragmentTemplate, ogEndpointTemplate, scalarReferenceTemplate, catchAllPageTemplate, changelogIndexTemplate, notFoundPageTemplate, notFoundMarkdownTemplate, notFoundJsonTemplate, apiPagesIndexTemplate, apiPageTemplate, apiNavigationTemplate, apiSearchTemplate, apiNotFoundTemplate, islandWrapperTemplate, islandMapTemplate, exampleSlug, exampleWrapperTemplate, examplesRouteBase, exampleMapTemplate, examplesPageTemplate, runtimePackageTemplate, runtimeTsconfigTemplate };
2368
2481
 
2369
- //# debugId=1666B85D4E0F438E64756E2164756E21
2370
- //# sourceMappingURL=chunk-aerwpe14.js.map
2482
+ //# debugId=5A77D8072A1C21F564756E2164756E21
2483
+ //# sourceMappingURL=chunk-4ae4f395.js.map