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
@@ -6,7 +6,7 @@ import {
6
6
  buildSearchDocuments,
7
7
  markdownRoutePaths,
8
8
  renderRssFeed
9
- } from "./chunk-n4qjabmt.js";
9
+ } from "./chunk-ka5k7cz9.js";
10
10
  import {
11
11
  MCP_TOOLS
12
12
  } from "./chunk-pxj10x8y.js";
@@ -19,7 +19,7 @@ import {
19
19
  import {
20
20
  collectContentAssets,
21
21
  rewriteRelativeImages
22
- } from "./chunk-5yvt556e.js";
22
+ } from "./chunk-kmx2mydj.js";
23
23
  import {
24
24
  writeTextAtomic
25
25
  } from "./chunk-ev67ycx0.js";
@@ -45,11 +45,13 @@ import {
45
45
  exampleSlug,
46
46
  exampleWrapperTemplate,
47
47
  examplesPageTemplate,
48
+ featuresTemplate,
48
49
  islandMapTemplate,
49
50
  islandWrapperTemplate,
50
51
  mcpEndpointTemplate,
51
52
  mcpPageFile,
52
53
  mixedbreadSearchEndpointTemplate,
54
+ navFragmentTemplate,
53
55
  notFoundJsonTemplate,
54
56
  notFoundMarkdownTemplate,
55
57
  notFoundPageTemplate,
@@ -67,14 +69,14 @@ import {
67
69
  searchEndpointTemplate,
68
70
  stagedContentDir,
69
71
  staticJsonEndpointTemplate
70
- } from "./chunk-aerwpe14.js";
72
+ } from "./chunk-4ae4f395.js";
71
73
  import {
72
74
  API_NAVIGATION_PATH,
73
75
  API_PAGES_PATH,
74
76
  API_PAGE_PATH,
75
77
  API_SEARCH_PATH,
76
78
  OPENAPI_PATH
77
- } from "./chunk-3k0kzs6d.js";
79
+ } from "./chunk-qvvpnwaz.js";
78
80
  import {
79
81
  absoluteUrl,
80
82
  siteRoot
@@ -91,7 +93,7 @@ import {
91
93
  resolveFallbackLocale,
92
94
  validateNavTargets,
93
95
  validateSearchPopularIcons
94
- } from "./chunk-etsqspj6.js";
96
+ } from "./chunk-12dzsn9b.js";
95
97
  import {
96
98
  EN_UI,
97
99
  GOOGLE_FONTS,
@@ -108,12 +110,15 @@ import {
108
110
  repoUrl,
109
111
  resolveReferences,
110
112
  resolveUIStrings
111
- } from "./chunk-vv3f8mb6.js";
113
+ } from "./chunk-r99hynxh.js";
112
114
  import {
113
115
  normalizeBasePath,
114
116
  trimChar,
115
117
  withBasePath
116
118
  } from "./chunk-27gtm2ym.js";
119
+ import {
120
+ getBlumeVersion
121
+ } from "./chunk-4xyggvgf.js";
117
122
  import {
118
123
  packageRoot
119
124
  } from "./chunk-6kzzpsx8.js";
@@ -208,16 +213,53 @@ ${body}`,
208
213
  });
209
214
  };
210
215
 
216
+ // src/og/cache.ts
217
+ import { existsSync } from "node:fs";
218
+ import {
219
+ mkdir,
220
+ readdir,
221
+ readFile,
222
+ rename,
223
+ rm,
224
+ writeFile
225
+ } from "node:fs/promises";
226
+ import { dirname as dirname2, join as join4 } from "pathe";
227
+ var ogCacheDir = (context) => existsSync(join4(context.root, "node_modules")) ? join4(context.root, "node_modules", ".cache", "blume", "og") : join4(context.outDir, ".cache", "og");
228
+ var REGISTRY_KEY2 = Symbol.for("blume.og-cache");
229
+ var registry3 = () => {
230
+ const host = globalThis;
231
+ host[REGISTRY_KEY2] ??= { hits: 0, misses: 0, used: new Set };
232
+ return host[REGISTRY_KEY2];
233
+ };
234
+ var localFontDigests = new Map;
235
+ var inflight = new Map;
236
+ var pruneCardCache = async (dir) => {
237
+ const { used } = registry3();
238
+ let entries;
239
+ try {
240
+ entries = await readdir(dir);
241
+ } catch {
242
+ return 0;
243
+ }
244
+ const stale = entries.filter((name) => name.endsWith(".tmp") || name.endsWith(".png") && !used.has(name.slice(0, -".png".length)));
245
+ await Promise.all(stale.map((name) => rm(join4(dir, name), { force: true })));
246
+ return stale.length;
247
+ };
248
+ var cardCacheTally = () => {
249
+ const { hits, misses } = registry3();
250
+ return hits + misses === 0 ? null : { hits, misses };
251
+ };
252
+
211
253
  // src/astro/generate.ts
212
254
  import { createHash } from "node:crypto";
213
- import { existsSync as existsSync5, readFileSync as readFileSync3, realpathSync } from "node:fs";
255
+ import { existsSync as existsSync6, readFileSync as readFileSync3, realpathSync } from "node:fs";
214
256
  import {
215
257
  lstat,
216
- mkdir,
217
- readFile as readFile4,
258
+ mkdir as mkdir2,
259
+ readFile as readFile5,
218
260
  readlink,
219
261
  realpath,
220
- rm,
262
+ rm as rm2,
221
263
  symlink
222
264
  } from "node:fs/promises";
223
265
  import { createRequire as createRequire2 } from "node:module";
@@ -225,9 +267,9 @@ import { pathToFileURL } from "node:url";
225
267
  import pMap3 from "p-map";
226
268
  import {
227
269
  basename as basename2,
228
- dirname as dirname5,
270
+ dirname as dirname6,
229
271
  isAbsolute as isAbsolute6,
230
- join as join10,
272
+ join as join11,
231
273
  normalize,
232
274
  relative as relative4,
233
275
  resolve as resolve6
@@ -829,6 +871,22 @@ var buildMcpServerCard = (input) => {
829
871
  return card;
830
872
  };
831
873
 
874
+ // src/components/layout/nav-utils.ts
875
+ var hasDeferrableGroups = (sidebar) => sidebar.some((node) => node.kind === "group" && ((node.display ?? "flat") !== "flat" || hasDeferrableGroups(node.children)));
876
+ var navVariants = (data, hiddenDefault = null) => [
877
+ { locale: "default", navigation: data.navigation, version: "current" },
878
+ ...Object.entries(data.navigationByLocale).filter(([locale]) => locale !== hiddenDefault).map(([locale, navigation]) => ({
879
+ locale,
880
+ navigation,
881
+ version: "current"
882
+ })),
883
+ ...Object.entries(data.navigationByVersion).flatMap(([version, byLocale]) => Object.entries(byLocale).map(([locale, navigation]) => ({
884
+ locale: locale && locale !== hiddenDefault ? locale : "default",
885
+ navigation,
886
+ version
887
+ })))
888
+ ];
889
+
832
890
  // src/core/builtin-tags.ts
833
891
  var BUILTIN_MDX_TAGS = new Set([
834
892
  "Accordion",
@@ -894,8 +952,8 @@ var validateUsedComponents = (pages, extraTags, registryNames) => {
894
952
  };
895
953
 
896
954
  // src/core/component-overrides.ts
897
- import { existsSync } from "node:fs";
898
- import { dirname as dirname2, extname, isAbsolute, resolve as resolve3 } from "pathe";
955
+ import { existsSync as existsSync2 } from "node:fs";
956
+ import { dirname as dirname3, extname, isAbsolute, resolve as resolve3 } from "pathe";
899
957
  import ts from "typescript";
900
958
  var GROUPS = ["mdx", "layout", "islands"];
901
959
  var GROUP_SET = new Set(GROUPS);
@@ -989,7 +1047,7 @@ var findDefaultExportObject = (sourceFile) => {
989
1047
  var probeExtension = (base) => {
990
1048
  for (const extension of COMPONENT_EXTS) {
991
1049
  const candidate = `${base}.${extension}`;
992
- if (existsSync(candidate)) {
1050
+ if (existsSync2(candidate)) {
993
1051
  return candidate;
994
1052
  }
995
1053
  }
@@ -1151,7 +1209,7 @@ var analyzeComponentOverrides = (source, filePath) => {
1151
1209
  return result;
1152
1210
  }
1153
1211
  const imports = collectImports(sourceFile);
1154
- const dir = dirname2(filePath);
1212
+ const dir = dirname3(filePath);
1155
1213
  for (const property of object.properties) {
1156
1214
  collectGroupOverrides(property, imports, dir, result);
1157
1215
  }
@@ -1222,8 +1280,8 @@ var svgDimensions = (svg) => {
1222
1280
  };
1223
1281
 
1224
1282
  // src/core/tsconfig-aliases.ts
1225
- import { existsSync as existsSync2 } from "node:fs";
1226
- import { dirname as dirname3, join as join4, resolve as resolve4 } from "pathe";
1283
+ import { existsSync as existsSync3 } from "node:fs";
1284
+ import { dirname as dirname4, join as join5, resolve as resolve4 } from "pathe";
1227
1285
  import ts2 from "typescript";
1228
1286
  var PARSE_HOST = {
1229
1287
  fileExists: ts2.sys.fileExists,
@@ -1245,7 +1303,7 @@ var toAlias = (key, value, baseDir) => {
1245
1303
  return { find, replacement: resolve4(baseDir, target) };
1246
1304
  };
1247
1305
  var resolveTsconfigAliases = (root) => {
1248
- const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join4(root, name)).find((file) => existsSync2(file));
1306
+ const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join5(root, name)).find((file) => existsSync3(file));
1249
1307
  if (!entry) {
1250
1308
  return {};
1251
1309
  }
@@ -1253,7 +1311,7 @@ var resolveTsconfigAliases = (root) => {
1253
1311
  if (error) {
1254
1312
  return {};
1255
1313
  }
1256
- const configDir = dirname3(entry);
1314
+ const configDir = dirname4(entry);
1257
1315
  const { options } = ts2.parseJsonConfigFileContent(config, PARSE_HOST, configDir, undefined, entry);
1258
1316
  const { paths } = options;
1259
1317
  if (!paths) {
@@ -1271,11 +1329,144 @@ var resolveTsconfigAliases = (root) => {
1271
1329
  return Object.fromEntries(entries);
1272
1330
  };
1273
1331
 
1332
+ // src/markdown/language-icon.ts
1333
+ import {
1334
+ siAstro,
1335
+ siC,
1336
+ siCplusplus,
1337
+ siCss,
1338
+ siDart,
1339
+ siDocker,
1340
+ siGnubash,
1341
+ siGo,
1342
+ siGraphql,
1343
+ siHtml5,
1344
+ siJavascript,
1345
+ siJson,
1346
+ siKotlin,
1347
+ siLess,
1348
+ siLua,
1349
+ siMarkdown,
1350
+ siMdx,
1351
+ siMysql,
1352
+ siNextdotjs,
1353
+ siPhp,
1354
+ siPrisma,
1355
+ siPython,
1356
+ siReact,
1357
+ siRuby,
1358
+ siRust,
1359
+ siSass,
1360
+ siScala,
1361
+ siSvelte,
1362
+ siSvg,
1363
+ siSwift,
1364
+ siToml,
1365
+ siTypescript,
1366
+ siVuedotjs,
1367
+ siWebassembly,
1368
+ siYaml
1369
+ } from "simple-icons";
1370
+ var LANGUAGE_ICONS = {
1371
+ astro: siAstro,
1372
+ bash: siGnubash,
1373
+ c: siC,
1374
+ "c++": siCplusplus,
1375
+ cjs: siJavascript,
1376
+ cpp: siCplusplus,
1377
+ css: siCss,
1378
+ cts: siTypescript,
1379
+ dart: siDart,
1380
+ docker: siDocker,
1381
+ dockerfile: siDocker,
1382
+ go: siGo,
1383
+ gql: siGraphql,
1384
+ graphql: siGraphql,
1385
+ html: siHtml5,
1386
+ javascript: siJavascript,
1387
+ js: siJavascript,
1388
+ json: siJson,
1389
+ json5: siJson,
1390
+ jsonc: siJson,
1391
+ jsx: siReact,
1392
+ kotlin: siKotlin,
1393
+ kt: siKotlin,
1394
+ less: siLess,
1395
+ lua: siLua,
1396
+ markdown: siMarkdown,
1397
+ md: siMarkdown,
1398
+ mdx: siMdx,
1399
+ mjs: siJavascript,
1400
+ mts: siTypescript,
1401
+ nextjs: siNextdotjs,
1402
+ php: siPhp,
1403
+ prisma: siPrisma,
1404
+ py: siPython,
1405
+ python: siPython,
1406
+ rb: siRuby,
1407
+ react: siReact,
1408
+ rs: siRust,
1409
+ ruby: siRuby,
1410
+ rust: siRust,
1411
+ sass: siSass,
1412
+ scala: siScala,
1413
+ scss: siSass,
1414
+ sh: siGnubash,
1415
+ shell: siGnubash,
1416
+ sql: siMysql,
1417
+ svelte: siSvelte,
1418
+ svg: siSvg,
1419
+ swift: siSwift,
1420
+ toml: siToml,
1421
+ ts: siTypescript,
1422
+ tsx: siReact,
1423
+ typescript: siTypescript,
1424
+ vue: siVuedotjs,
1425
+ wasm: siWebassembly,
1426
+ yaml: siYaml,
1427
+ yml: siYaml,
1428
+ zsh: siGnubash
1429
+ };
1430
+ var languageIconSlug = (language) => LANGUAGE_ICONS[language.toLowerCase()]?.slug ?? null;
1431
+ var FENCE_LANGUAGE = /^[ \t]*(?:`{3,}|~{3,})[ \t]*(?<lang>[\w+#.-]+)/gmu;
1432
+ var PROP_LANGUAGE = /\blang(?:uage)?=["'](?<lang>[\w+#.-]+)["']/gu;
1433
+ var languageIconSlugsIn = (markdown) => {
1434
+ const slugs = new Set;
1435
+ for (const pattern of [FENCE_LANGUAGE, PROP_LANGUAGE]) {
1436
+ for (const match of markdown.matchAll(pattern)) {
1437
+ const slug = languageIconSlug(match.groups?.lang ?? "");
1438
+ if (slug) {
1439
+ slugs.add(slug);
1440
+ }
1441
+ }
1442
+ }
1443
+ return [...slugs].toSorted();
1444
+ };
1445
+ var iconBySlug = (slug) => Object.values(LANGUAGE_ICONS).find((icon) => icon.slug === slug);
1446
+ var maskUri = (path) => `url("data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="${path}"/></svg>`)}")`;
1447
+ var languageIconCss = (slugs) => slugs.map((slug) => {
1448
+ const icon = iconBySlug(slug);
1449
+ if (!icon) {
1450
+ return "";
1451
+ }
1452
+ const mask = maskUri(icon.path);
1453
+ return `.prose > :where(pre[data-language][data-icon="${slug}"])::after {
1454
+ background-color: var(--blume-muted-foreground);
1455
+ -webkit-mask-image: ${mask};
1456
+ mask-image: ${mask};
1457
+ }`;
1458
+ }).filter((rule) => rule !== "").join(`
1459
+ `);
1460
+
1461
+ // src/markdown/mermaid.ts
1462
+ var MERMAID_FENCE = /^[ \t]*(?:`{3,}|~{3,})[ \t]*mermaid\b/mu;
1463
+ var hasMermaidFence = (text) => MERMAID_FENCE.test(text);
1464
+
1274
1465
  // src/og/derive.ts
1275
- import { existsSync as existsSync3 } from "node:fs";
1276
- import { isAbsolute as isAbsolute2, join as join5 } from "pathe";
1466
+ import { existsSync as existsSync4 } from "node:fs";
1467
+ import { isAbsolute as isAbsolute2, join as join6 } from "pathe";
1277
1468
  var CARD_WEIGHTS = [400, 600];
1278
- var absoluteSrc = (root, src) => isAbsolute2(src) ? src : join5(root, src);
1469
+ var absoluteSrc = (root, src) => isAbsolute2(src) ? src : join6(root, src);
1279
1470
  var isNumericWeight = (weight) => typeof weight === "number";
1280
1471
  var isRangeWeight = (weight) => typeof weight === "string";
1281
1472
  var isFontName = (value) => typeof value === "string";
@@ -1376,27 +1567,27 @@ var missingFontFiles = (options, root) => {
1376
1567
  sources.push(absoluteSrc(root, font.src));
1377
1568
  }
1378
1569
  }
1379
- return [...new Set(sources)].filter((path) => !existsSync3(path));
1570
+ return [...new Set(sources)].filter((path) => !existsSync4(path));
1380
1571
  };
1381
1572
 
1382
1573
  // src/og/logo.ts
1383
- import { existsSync as existsSync4, readFileSync } from "node:fs";
1384
- import { join as join6 } from "pathe";
1574
+ import { existsSync as existsSync5, readFileSync } from "node:fs";
1575
+ import { join as join7 } from "pathe";
1385
1576
  var resolveOgLogo = (project, source) => {
1386
1577
  if (!source?.toLowerCase().endsWith(".svg")) {
1387
1578
  return;
1388
1579
  }
1389
1580
  const relative2 = source.replace(/^\//u, "");
1390
1581
  const file = [
1391
- join6(project.context.root, "public", relative2),
1392
- join6(project.context.root, relative2)
1393
- ].find((path) => existsSync4(path));
1582
+ join7(project.context.root, "public", relative2),
1583
+ join7(project.context.root, relative2)
1584
+ ].find((path) => existsSync5(path));
1394
1585
  return file ? readFileSync(file, "utf-8") : undefined;
1395
1586
  };
1396
1587
 
1397
1588
  // src/openapi/scalar.ts
1398
- import { readFile } from "node:fs/promises";
1399
- import { isAbsolute as isAbsolute3, join as join7 } from "pathe";
1589
+ import { readFile as readFile2 } from "node:fs/promises";
1590
+ import { isAbsolute as isAbsolute3, join as join8 } from "pathe";
1400
1591
 
1401
1592
  // src/theme/palette.ts
1402
1593
  var FALLBACK_ACCENT = "oklch(0.62 0.16 250)";
@@ -1492,9 +1683,9 @@ var specConfiguration = async (spec, root) => {
1492
1683
  if (URL_SPEC.test(spec)) {
1493
1684
  return { config: { url: spec } };
1494
1685
  }
1495
- const absolute = isAbsolute3(spec) ? spec : join7(root, spec);
1686
+ const absolute = isAbsolute3(spec) ? spec : join8(root, spec);
1496
1687
  try {
1497
- return { config: { content: await readFile(absolute, "utf-8") } };
1688
+ return { config: { content: await readFile2(absolute, "utf-8") } };
1498
1689
  } catch {
1499
1690
  return {
1500
1691
  config: { url: spec },
@@ -1718,6 +1909,15 @@ ${THEME_MAPPING}
1718
1909
  scroll-padding-top: 4.5rem;
1719
1910
  text-rendering: optimizeLegibility;
1720
1911
  }
1912
+ /* Modal surfaces coordinate through independent root attributes. The lock
1913
+ remains until every owner releases its attribute, while !important lets it
1914
+ temporarily override (and therefore preserve) an authored inline value.
1915
+ Classic (non-overlay) scrollbars would otherwise vanish while locked and
1916
+ shift the page and the centered dialog sideways, so keep their gutter. */
1917
+ html:where([data-blume-nav-open], [data-blume-search-dialog-open]) {
1918
+ overflow: hidden !important;
1919
+ scrollbar-gutter: stable;
1920
+ }
1721
1921
  /* Headings use the display font (defaults to the body font when unset).
1722
1922
  The tightened tracking is part of the theme, not the font: display-tuned
1723
1923
  families bake it into their metrics, but a text family promoted to
@@ -1770,6 +1970,31 @@ ${THEME_MAPPING}
1770
1970
  unicode-bidi: isolate;
1771
1971
  }
1772
1972
 
1973
+ /* The sidebar's rows. A docs site renders every sidebar row on every page,
1974
+ so a large site's HTML is mostly this markup — one utility per row kind
1975
+ instead of the dozen classes each expands to keeps every page (and the
1976
+ build's HTML output) small. Kept in sync with NavTree.astro: a page row,
1977
+ a page-mode group's drill-in button, a collapsible group's summary and
1978
+ the link inside it, and a flat group's heading and the link inside it. */
1979
+ @utility blume-nav-link {
1980
+ @apply block rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:font-medium aria-[current=page]:text-foreground;
1981
+ }
1982
+ @utility blume-nav-drill {
1983
+ @apply flex w-full items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 text-left font-medium text-foreground text-sm transition-colors hover:bg-muted;
1984
+ }
1985
+ @utility blume-nav-summary {
1986
+ @apply flex cursor-pointer list-none items-center gap-1.5 rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden;
1987
+ }
1988
+ @utility blume-nav-summary-link {
1989
+ @apply -my-1 flex flex-1 items-center gap-1.5 rounded py-1 transition-colors aria-[current=page]:text-foreground aria-[current=page]:font-semibold;
1990
+ }
1991
+ @utility blume-nav-heading {
1992
+ @apply mb-2 flex items-center gap-1.5 px-2.5 font-medium text-foreground text-sm;
1993
+ }
1994
+ @utility blume-nav-heading-link {
1995
+ @apply -ml-1 flex flex-1 items-center gap-1.5 rounded-[0.65rem] px-1 py-0.5 text-foreground transition-colors hover:bg-muted aria-[current=page]:bg-muted;
1996
+ }
1997
+
1773
1998
  /* Theme Tailwind Typography (prose) with Blume tokens. */
1774
1999
  .prose {
1775
2000
  --tw-prose-body: var(--blume-foreground);
@@ -1985,15 +2210,17 @@ blume-diff {
1985
2210
  CodeBlock (no title) never gets data-language, so without this gate the
1986
2211
  absolutely-positioned icon would overlap the first code line. Fenced code
1987
2212
  and titled blocks always have a header, so the icon shows there. */
1988
- .blume-lang-icon {
1989
- display: none;
1990
- }
1991
-
1992
- .prose > :where(pre[data-language][data-icon]) > .blume-lang-icon {
1993
- color: var(--blume-muted-foreground);
1994
- display: block;
2213
+ .prose > :where(pre[data-language][data-icon])::after {
2214
+ content: "";
1995
2215
  height: 0.875rem;
1996
2216
  left: 1rem;
2217
+ -webkit-mask-position: center;
2218
+ -webkit-mask-repeat: no-repeat;
2219
+ -webkit-mask-size: contain;
2220
+ mask-position: center;
2221
+ mask-repeat: no-repeat;
2222
+ mask-size: contain;
2223
+ pointer-events: none;
1997
2224
  position: absolute;
1998
2225
  top: 0.875rem;
1999
2226
  width: 0.875rem;
@@ -2003,6 +2230,11 @@ blume-diff {
2003
2230
  padding-left: 2.5rem;
2004
2231
  }
2005
2232
 
2233
+ /* One mask rule per language the site's Markdown uses (see
2234
+ markdown/language-icon.ts); the ::after above only gets a color and a mask
2235
+ from these, so a block whose language has no rule paints nothing. */
2236
+ ${options.languageIcons ?? ""}
2237
+
2006
2238
  .prose :where(pre code) {
2007
2239
  background: transparent;
2008
2240
  border-radius: 0;
@@ -2401,10 +2633,10 @@ ${options.userCss}
2401
2633
  `;
2402
2634
 
2403
2635
  // src/theme/sources.ts
2404
- import { dirname as dirname4, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve5 } from "pathe";
2636
+ import { dirname as dirname5, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve5 } from "pathe";
2405
2637
  var SOURCE_DIRECTIVE = /@source(?<not>\s+not)?\s+(?<quote>["'])(?<path>[^"']+)\k<quote>/gu;
2406
2638
  var rebaseSourceDirectives = (css, options) => {
2407
- const base = dirname4(options.from);
2639
+ const base = dirname5(options.from);
2408
2640
  return css.replace(SOURCE_DIRECTIVE, (directive, not, quote, path) => {
2409
2641
  if (isAbsolute4(path)) {
2410
2642
  return directive;
@@ -2597,15 +2829,15 @@ export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.leng
2597
2829
  };
2598
2830
 
2599
2831
  // src/astro/examples.ts
2600
- import { readFile as readFile3 } from "node:fs/promises";
2832
+ import { readFile as readFile4 } from "node:fs/promises";
2601
2833
  import pMap2 from "p-map";
2602
- import { isAbsolute as isAbsolute5, join as join9, relative as relative3 } from "pathe";
2834
+ import { isAbsolute as isAbsolute5, join as join10, relative as relative3 } from "pathe";
2603
2835
  import { glob as glob2 } from "tinyglobby";
2604
2836
 
2605
2837
  // src/astro/islands.ts
2606
- import { readFile as readFile2 } from "node:fs/promises";
2838
+ import { readFile as readFile3 } from "node:fs/promises";
2607
2839
  import pMap from "p-map";
2608
- import { basename, join as join8 } from "pathe";
2840
+ import { basename, join as join9 } from "pathe";
2609
2841
  import { glob } from "tinyglobby";
2610
2842
  var DEFAULT_CLIENT = "visible";
2611
2843
  var READ_CONCURRENCY = 16;
@@ -2636,14 +2868,14 @@ var readClientMode = (source, file, warnings) => {
2636
2868
  return mode;
2637
2869
  };
2638
2870
  var discoverIslands = async (root) => {
2639
- const dir = join8(root, "islands");
2871
+ const dir = join9(root, "islands");
2640
2872
  const matches = await glob(["**/*"], {
2641
2873
  absolute: true,
2642
2874
  cwd: dir,
2643
2875
  onlyFiles: true
2644
2876
  });
2645
2877
  const files = matches.toSorted();
2646
- const sources = await pMap(files, (file) => readFile2(file, "utf-8"), {
2878
+ const sources = await pMap(files, (file) => readFile3(file, "utf-8"), {
2647
2879
  concurrency: READ_CONCURRENCY
2648
2880
  });
2649
2881
  const islands = [];
@@ -2708,14 +2940,14 @@ var splitGlobBase = (pattern) => {
2708
2940
  };
2709
2941
  var discoverExamples = async (root, pattern = "examples") => {
2710
2942
  const { base, rest } = GLOB_MAGIC.test(pattern) ? splitGlobBase(pattern) : { base: pattern, rest: DEFAULT_EXAMPLE_GLOB };
2711
- const dir = join9(root, base);
2943
+ const dir = join10(root, base);
2712
2944
  const matches = await glob2([rest], {
2713
2945
  absolute: true,
2714
2946
  cwd: dir,
2715
2947
  onlyFiles: true
2716
2948
  });
2717
2949
  const files = matches.toSorted();
2718
- const sources = await pMap2(files, (file) => readFile3(file, "utf-8"), {
2950
+ const sources = await pMap2(files, (file) => readFile4(file, "utf-8"), {
2719
2951
  concurrency: READ_CONCURRENCY2
2720
2952
  });
2721
2953
  const examples = [];
@@ -2754,10 +2986,10 @@ var exampleMarkdownLookup = (examples) => Object.fromEntries(examples.map((examp
2754
2986
  ]));
2755
2987
 
2756
2988
  // src/astro/generate.ts
2757
- var BLUME_SRC = join10(packageRoot(), "src");
2989
+ var BLUME_SRC = join11(packageRoot(), "src");
2758
2990
  var canResolveFrom = (fromDir, spec) => {
2759
2991
  try {
2760
- createRequire2(pathToFileURL(join10(fromDir, "_.js")).href).resolve(spec);
2992
+ createRequire2(pathToFileURL(join11(fromDir, "_.js")).href).resolve(spec);
2761
2993
  return true;
2762
2994
  } catch {
2763
2995
  return false;
@@ -2768,7 +3000,7 @@ var resolveReactCompiler = (config, needsReact, pkgDir = packageRoot()) => {
2768
3000
  return null;
2769
3001
  }
2770
3002
  try {
2771
- return createRequire2(pathToFileURL(join10(pkgDir, "_.js")).href).resolve("babel-plugin-react-compiler");
3003
+ return createRequire2(pathToFileURL(join11(pkgDir, "_.js")).href).resolve("babel-plugin-react-compiler");
2772
3004
  } catch {
2773
3005
  return null;
2774
3006
  }
@@ -2778,7 +3010,7 @@ var reactCompilerWarnings = (config, needsReact, compilerPath) => needsReact &&
2778
3010
  ] : [];
2779
3011
  var resolveAstroPackageJson = (modulesDir) => {
2780
3012
  try {
2781
- return realpathSync(join10(modulesDir, "astro", "package.json"));
3013
+ return realpathSync(join11(modulesDir, "astro", "package.json"));
2782
3014
  } catch {
2783
3015
  return null;
2784
3016
  }
@@ -2786,12 +3018,12 @@ var resolveAstroPackageJson = (modulesDir) => {
2786
3018
  var resolvedAstroHit = (fromDir) => {
2787
3019
  let dir = normalize(fromDir);
2788
3020
  while (true) {
2789
- const modulesDir = join10(dir, "node_modules");
3021
+ const modulesDir = join11(dir, "node_modules");
2790
3022
  const pkg = resolveAstroPackageJson(modulesDir);
2791
3023
  if (pkg) {
2792
3024
  return { modulesDir, pkg };
2793
3025
  }
2794
- const parent = dirname5(dir);
3026
+ const parent = dirname6(dir);
2795
3027
  if (parent === dir) {
2796
3028
  return null;
2797
3029
  }
@@ -2806,10 +3038,17 @@ var sameRealDir = (a, b) => {
2806
3038
  }
2807
3039
  };
2808
3040
  var depsCandidates = (pkgDir) => [
2809
- join10(pkgDir, "node_modules"),
2810
- dirname5(pkgDir)
3041
+ join11(pkgDir, "node_modules"),
3042
+ dirname6(pkgDir)
2811
3043
  ];
2812
- var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync5(join10(dir, ...segments))) ?? null;
3044
+ var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync6(join11(dir, ...segments))) ?? null;
3045
+ var symlinkDir = async (target, link) => {
3046
+ try {
3047
+ await symlink(target, link, "dir");
3048
+ } catch {
3049
+ await symlink(target, link, "junction");
3050
+ }
3051
+ };
2813
3052
  var linkDepsJunction = async (link, depsDir) => {
2814
3053
  let existing;
2815
3054
  try {
@@ -2822,14 +3061,14 @@ var linkDepsJunction = async (link, depsDir) => {
2822
3061
  return;
2823
3062
  }
2824
3063
  try {
2825
- if (resolve6(dirname5(link), await readlink(link)) === resolve6(depsDir)) {
3064
+ if (resolve6(dirname6(link), await readlink(link)) === resolve6(depsDir)) {
2826
3065
  return;
2827
3066
  }
2828
3067
  } catch {}
2829
- await rm(link, { force: true });
3068
+ await rm2(link, { force: true });
2830
3069
  }
2831
- await mkdir(dirname5(link), { recursive: true });
2832
- await symlink(depsDir, link, "junction");
3070
+ await mkdir2(dirname6(link), { recursive: true });
3071
+ await symlinkDir(depsDir, link);
2833
3072
  };
2834
3073
  var readPkgVersion = (pkgJsonPath) => {
2835
3074
  if (!pkgJsonPath) {
@@ -2861,13 +3100,13 @@ var dropStaleDepsLink = async (link, pkgDir) => {
2861
3100
  let linkedBlume;
2862
3101
  let runningBlume;
2863
3102
  try {
2864
- linkedBlume = await realpath(join10(link, "blume"));
3103
+ linkedBlume = await realpath(join11(link, "blume"));
2865
3104
  runningBlume = await realpath(pkgDir);
2866
3105
  } catch {
2867
3106
  return;
2868
3107
  }
2869
3108
  if (linkedBlume !== runningBlume) {
2870
- await rm(link, { force: true });
3109
+ await rm2(link, { force: true });
2871
3110
  }
2872
3111
  };
2873
3112
  var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
@@ -2877,7 +3116,7 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
2877
3116
  }
2878
3117
  const mdxDir = candidateHolding(pkgDir, "@astrojs", "mdx");
2879
3118
  const blumeAstro = resolveAstroPackageJson(astroDir);
2880
- await dropStaleDepsLink(join10(outDir, "node_modules"), pkgDir);
3119
+ await dropStaleDepsLink(join11(outDir, "node_modules"), pkgDir);
2881
3120
  const outDirHit = resolvedAstroHit(outDir);
2882
3121
  const astroCorrect = blumeAstro !== null && outDirHit?.pkg === blumeAstro;
2883
3122
  const walkLandsInDeps = astroCorrect && outDirHit !== null && sameRealDir(outDirHit.modulesDir, astroDir);
@@ -2885,7 +3124,7 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
2885
3124
  return null;
2886
3125
  }
2887
3126
  if (mdxDir && (mdxDir === astroDir || astroCorrect)) {
2888
- await linkDepsJunction(join10(outDir, "node_modules"), mdxDir);
3127
+ await linkDepsJunction(join11(outDir, "node_modules"), mdxDir);
2889
3128
  return null;
2890
3129
  }
2891
3130
  return astroConflictWarning(blumeAstro, outDirHit?.pkg ?? null);
@@ -2938,14 +3177,14 @@ var askProviderWarnings = (ask, root, pkgDir = packageRoot()) => {
2938
3177
  `Ask AI provider "${ask.provider}" needs "${dep}", which isn't installed. Run \`npm install ${dep}\` (or your package manager's equivalent).`
2939
3178
  ];
2940
3179
  };
2941
- var examplesCssFile = (root, config) => config.examples.css ? join10(root, config.examples.css) : null;
3180
+ var examplesCssFile = (root, config) => config.examples.css ? join11(root, config.examples.css) : null;
2942
3181
  var writeExamplesPreview = async (options) => {
2943
3182
  const { config, hasExamples, root, srcDir, write } = options;
2944
3183
  if (hasExamples) {
2945
- await write(join10(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
3184
+ await write(join11(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
2946
3185
  }
2947
3186
  const cssFile = examplesCssFile(root, config);
2948
- return cssFile && !existsSync5(cssFile) ? [
3187
+ return cssFile && !existsSync6(cssFile) ? [
2949
3188
  `examples.css points at "${config.examples.css}", which doesn't exist; previews render without it.`
2950
3189
  ] : [];
2951
3190
  };
@@ -2954,7 +3193,7 @@ var readOptional = async (path) => {
2954
3193
  return "";
2955
3194
  }
2956
3195
  try {
2957
- return await readFile4(path, "utf-8");
3196
+ return await readFile5(path, "utf-8");
2958
3197
  } catch {
2959
3198
  return "";
2960
3199
  }
@@ -2979,7 +3218,7 @@ var detectUsesMath = async (root, staged = []) => {
2979
3218
  ignore: ["**/node_modules/**", "**/.blume/**", "**/dist/**"],
2980
3219
  onlyFiles: true
2981
3220
  });
2982
- const contents = await pMap3(files, (file) => readOptional(join10(root, file)), {
3221
+ const contents = await pMap3(files, (file) => readOptional(join11(root, file)), {
2983
3222
  concurrency: READ_CONCURRENCY3
2984
3223
  });
2985
3224
  return [...contents, ...staged].some(containsMath);
@@ -2997,7 +3236,7 @@ var loadIntegrationBridge = async (config, context) => {
2997
3236
  var writeIfChanged = async (path, content) => {
2998
3237
  let existing = null;
2999
3238
  try {
3000
- existing = await readFile4(path, "utf-8");
3239
+ existing = await readFile5(path, "utf-8");
3001
3240
  } catch {
3002
3241
  existing = null;
3003
3242
  }
@@ -3017,7 +3256,7 @@ var pruneOrphans = async (srcDir, written) => {
3017
3256
  for (const path of existing) {
3018
3257
  const normalized = normalize(path);
3019
3258
  if (!written.has(normalized)) {
3020
- removals.push(rm(normalized, { force: true }));
3259
+ removals.push(rm2(normalized, { force: true }));
3021
3260
  }
3022
3261
  }
3023
3262
  await Promise.all(removals);
@@ -3041,11 +3280,11 @@ var writeStagedContent = async (out, staged) => {
3041
3280
  const contentDir = stagedContentDir(out);
3042
3281
  const written = new Set;
3043
3282
  await Promise.all([...staged].map(async ([entryId, text]) => {
3044
- const path = join10(contentDir, entryId);
3283
+ const path = join11(contentDir, entryId);
3045
3284
  written.add(normalize(path));
3046
3285
  await writeIfChanged(path, text);
3047
3286
  }));
3048
- if (existsSync5(contentDir)) {
3287
+ if (existsSync6(contentDir)) {
3049
3288
  await pruneOrphans(contentDir, written);
3050
3289
  }
3051
3290
  };
@@ -3056,9 +3295,9 @@ var readLogoSvg = (project, source) => {
3056
3295
  }
3057
3296
  const rel = source.replace(/^\//u, "");
3058
3297
  const file = [
3059
- join10(project.context.root, "public", rel),
3060
- join10(project.context.root, rel)
3061
- ].find((path) => existsSync5(path));
3298
+ join11(project.context.root, "public", rel),
3299
+ join11(project.context.root, rel)
3300
+ ].find((path) => existsSync6(path));
3062
3301
  return file ? readFileSync3(file, "utf-8") : undefined;
3063
3302
  };
3064
3303
  var isStringShorthand = (value) => typeof value === "string";
@@ -3113,10 +3352,10 @@ var faviconType = (name) => {
3113
3352
  var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync3(file).toString("base64")}`;
3114
3353
  var defaultFavicon = () => ({
3115
3354
  dark: {
3116
- href: inlineDataUri(join10(BLUME_SRC, "assets", "icon-dark.png"), "image/png"),
3355
+ href: inlineDataUri(join11(BLUME_SRC, "assets", "icon-dark.png"), "image/png"),
3117
3356
  type: "image/png"
3118
3357
  },
3119
- href: inlineDataUri(join10(BLUME_SRC, "assets", "icon.png"), "image/png"),
3358
+ href: inlineDataUri(join11(BLUME_SRC, "assets", "icon.png"), "image/png"),
3120
3359
  type: "image/png"
3121
3360
  });
3122
3361
  var APPLE_ICON_CANDIDATES = [
@@ -3128,13 +3367,13 @@ var APPLE_ICON_CANDIDATES = [
3128
3367
  var resolveIconFile = (project, candidates) => {
3129
3368
  const { root } = project.context;
3130
3369
  for (const name of candidates) {
3131
- if (existsSync5(join10(root, "public", name))) {
3370
+ if (existsSync6(join11(root, "public", name))) {
3132
3371
  return { href: `/${name}`, type: faviconType(name) };
3133
3372
  }
3134
3373
  }
3135
3374
  for (const name of candidates) {
3136
- const file = join10(root, name);
3137
- if (existsSync5(file)) {
3375
+ const file = join11(root, name);
3376
+ if (existsSync6(file)) {
3138
3377
  const type = faviconType(name);
3139
3378
  return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
3140
3379
  }
@@ -3144,19 +3383,19 @@ var resolveIconFile = (project, candidates) => {
3144
3383
  var resolveFavicon = (project) => {
3145
3384
  const { root } = project.context;
3146
3385
  for (const name of FAVICON_CANDIDATES) {
3147
- if (existsSync5(join10(root, "public", name))) {
3386
+ if (existsSync6(join11(root, "public", name))) {
3148
3387
  const type = faviconType(name);
3149
3388
  const sibling = darkSibling(name);
3150
- return existsSync5(join10(root, "public", sibling)) ? { dark: { href: `/${sibling}`, type }, href: `/${name}`, type } : { href: `/${name}`, type };
3389
+ return existsSync6(join11(root, "public", sibling)) ? { dark: { href: `/${sibling}`, type }, href: `/${name}`, type } : { href: `/${name}`, type };
3151
3390
  }
3152
3391
  }
3153
3392
  for (const name of FAVICON_CANDIDATES) {
3154
- const file = join10(root, name);
3155
- if (existsSync5(file)) {
3393
+ const file = join11(root, name);
3394
+ if (existsSync6(file)) {
3156
3395
  const type = faviconType(name);
3157
3396
  const mime = type ?? "image/x-icon";
3158
- const siblingFile = join10(root, darkSibling(name));
3159
- return existsSync5(siblingFile) ? {
3397
+ const siblingFile = join11(root, darkSibling(name));
3398
+ return existsSync6(siblingFile) ? {
3160
3399
  dark: { href: inlineDataUri(siblingFile, mime), type },
3161
3400
  href: inlineDataUri(file, mime),
3162
3401
  type
@@ -3227,7 +3466,7 @@ var buildRuntimeData = (project) => {
3227
3466
  }
3228
3467
  const rel = relative4(context.root, sourcePath).split("\\").join("/");
3229
3468
  const editDir = trimChar(github?.dir ?? "", "/");
3230
- const editPath = normalize(editDir ? join10(editDir, rel) : rel);
3469
+ const editPath = normalize(editDir ? join11(editDir, rel) : rel);
3231
3470
  if (editPath.startsWith("..") || isAbsolute6(editPath)) {
3232
3471
  return null;
3233
3472
  }
@@ -3371,7 +3610,7 @@ var buildRuntimeData = (project) => {
3371
3610
  var planMcp = (project, srcDir, userPages) => {
3372
3611
  const { config } = project;
3373
3612
  const { route } = config.ai.mcp;
3374
- const dir = join10(srcDir, "blume-mcp");
3613
+ const dir = join11(srcDir, "blume-mcp");
3375
3614
  const base = {
3376
3615
  dir,
3377
3616
  discoveryPages: [],
@@ -3395,11 +3634,11 @@ var planMcp = (project, srcDir, userPages) => {
3395
3634
  ...base,
3396
3635
  discoveryPages: [
3397
3636
  {
3398
- entrypoint: join10(dir, "discovery.ts"),
3637
+ entrypoint: join11(dir, "discovery.ts"),
3399
3638
  pattern: "/.well-known/mcp.json"
3400
3639
  },
3401
3640
  {
3402
- entrypoint: join10(dir, "server-card.ts"),
3641
+ entrypoint: join11(dir, "server-card.ts"),
3403
3642
  pattern: "/.well-known/mcp/server-card.json"
3404
3643
  }
3405
3644
  ],
@@ -3426,9 +3665,9 @@ var writeMcpFiles = async (plan, write, data) => {
3426
3665
  version: data.version
3427
3666
  };
3428
3667
  await Promise.all([
3429
- write(join10(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate()),
3430
- write(join10(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
3431
- write(join10(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
3668
+ write(join11(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate()),
3669
+ write(join11(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
3670
+ write(join11(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
3432
3671
  ]);
3433
3672
  };
3434
3673
  var ownsApiRest = (page) => page.pattern.startsWith("/api/[");
@@ -3440,7 +3679,7 @@ var planApi = (project, srcDir, userPages) => {
3440
3679
  catchAll: server && !userPages.some(ownsApiRest) && !project.graph.pages.some(contentUnderApi),
3441
3680
  enabled: config.ai.api,
3442
3681
  server,
3443
- spec: !routeIsTaken(userPages, project.graph.pages, OPENAPI_PATH) && !existsSync5(join10(context.root, "public", "openapi.json")),
3682
+ spec: !routeIsTaken(userPages, project.graph.pages, OPENAPI_PATH) && !existsSync6(join11(context.root, "public", "openapi.json")),
3444
3683
  srcDir
3445
3684
  };
3446
3685
  };
@@ -3450,20 +3689,20 @@ var writeApiFiles = async (project, plan, write, data, mcp) => {
3450
3689
  }
3451
3690
  const { config } = project;
3452
3691
  const mcpRoute = mcp.enabled ? mcp.route : null;
3453
- const apiDir = join10(plan.srcDir, "pages", "api");
3692
+ const apiDir = join11(plan.srcDir, "pages", "api");
3454
3693
  const writes = [
3455
- write(join10(apiDir, "docs", "pages.json.ts"), apiPagesIndexTemplate()),
3456
- write(join10(apiDir, "docs", "pages", "[...route].json.ts"), apiPageTemplate()),
3457
- write(join10(apiDir, "docs", "navigation.json.ts"), apiNavigationTemplate())
3694
+ write(join11(apiDir, "docs", "pages.json.ts"), apiPagesIndexTemplate()),
3695
+ write(join11(apiDir, "docs", "pages", "[...route].json.ts"), apiPageTemplate()),
3696
+ write(join11(apiDir, "docs", "navigation.json.ts"), apiNavigationTemplate())
3458
3697
  ];
3459
3698
  if (plan.server) {
3460
- writes.push(write(join10(apiDir, "docs", "search.ts"), apiSearchTemplate()));
3699
+ writes.push(write(join11(apiDir, "docs", "search.ts"), apiSearchTemplate()));
3461
3700
  }
3462
3701
  if (plan.catchAll) {
3463
- writes.push(write(join10(apiDir, "[...path].ts"), apiNotFoundTemplate({ base: data.base, site: data.site })));
3702
+ writes.push(write(join11(apiDir, "[...path].ts"), apiNotFoundTemplate({ base: data.base, site: data.site })));
3464
3703
  }
3465
3704
  if (plan.spec) {
3466
- writes.push(write(join10(plan.srcDir, "pages", "openapi.json.ts"), staticJsonEndpointTemplate(buildApiSpec({
3705
+ writes.push(write(join11(plan.srcDir, "pages", "openapi.json.ts"), staticJsonEndpointTemplate(buildApiSpec({
3467
3706
  agentReadability: config.seo.agentReadability,
3468
3707
  base: data.base,
3469
3708
  description: config.description,
@@ -3479,7 +3718,7 @@ var writeApiFiles = async (project, plan, write, data, mcp) => {
3479
3718
  };
3480
3719
  var planPlaygroundProxy = (config, srcDir) => ({
3481
3720
  enabled: needsPlaygroundProxy(config),
3482
- entrypoint: join10(srcDir, "blume-openapi", "api-proxy.ts"),
3721
+ entrypoint: join11(srcDir, "blume-openapi", "api-proxy.ts"),
3483
3722
  pattern: "/_api-proxy"
3484
3723
  });
3485
3724
  var specOriginsOf = (spec) => {
@@ -3522,7 +3761,7 @@ var writeAskFiles = async (project, srcDir, write, modules) => {
3522
3761
  if (grounded) {
3523
3762
  modules.set("blume:ask-data", JSON.stringify(await buildAskData(project)));
3524
3763
  }
3525
- await write(join10(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded, {
3764
+ await write(join11(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded, {
3526
3765
  instructions: ask.instructions,
3527
3766
  retrieval: ask.retrieval
3528
3767
  }));
@@ -3532,14 +3771,14 @@ var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
3532
3771
  return;
3533
3772
  }
3534
3773
  await Promise.all([
3535
- write(join10(srcDir, "pages", "404.astro"), notFoundPageTemplate()),
3536
- write(join10(srcDir, "pages", "404.md.ts"), notFoundMarkdownTemplate()),
3537
- write(join10(srcDir, "pages", "404.json.ts"), notFoundJsonTemplate())
3774
+ write(join11(srcDir, "pages", "404.astro"), notFoundPageTemplate()),
3775
+ write(join11(srcDir, "pages", "404.md.ts"), notFoundMarkdownTemplate()),
3776
+ write(join11(srcDir, "pages", "404.json.ts"), notFoundJsonTemplate())
3538
3777
  ]);
3539
3778
  };
3540
3779
  var diagnosticWarning = (diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message;
3541
3780
  var buildComponentSlots = async (componentsFile) => {
3542
- const analysis = componentsFile ? analyzeComponentOverrides(await readFile4(componentsFile, "utf-8"), componentsFile) : null;
3781
+ const analysis = componentsFile ? analyzeComponentOverrides(await readFile5(componentsFile, "utf-8"), componentsFile) : null;
3543
3782
  return {
3544
3783
  plan: planComponentSlots(componentsFile, analysis),
3545
3784
  tags: analysis ? [...analysis.mdx, ...analysis.islands].map((entry) => entry.key) : [],
@@ -3562,17 +3801,30 @@ var assertFontFilesExist = (project) => {
3562
3801
  });
3563
3802
  }
3564
3803
  };
3804
+ var clientFeaturesFrom = (project, rawMarkdown) => ({
3805
+ epub: project.config.export.epub,
3806
+ mermaid: Object.values(rawMarkdown).some((entry) => hasMermaidFence(entry.mdx ?? entry.md ?? "")) || project.graph.pages.some((page) => page.body !== undefined && hasMermaidFence(page.body.text))
3807
+ });
3808
+ var languageIconCssFrom = (project, rawMarkdown) => languageIconCss(languageIconSlugsIn([
3809
+ ...Object.values(rawMarkdown).map((entry) => entry.mdx ?? entry.md ?? ""),
3810
+ ...project.graph.pages.map((page) => page.body?.text ?? "")
3811
+ ].join(`
3812
+ `)));
3813
+ var languageIconCssFor = async (project) => languageIconCssFrom(project, await buildRawMarkdown(project));
3814
+ var writeNavFragments = (write, srcDir, navFragments) => navFragments ? write(join11(srcDir, "pages", "blume-nav", "[version]", "[locale]", "[id].astro"), navFragmentTemplate()) : Promise.resolve(false);
3815
+ var clientFeaturesFor = async (project) => clientFeaturesFrom(project, await buildRawMarkdown(project));
3565
3816
  var generateRuntime = async (project) => {
3566
3817
  const { context, config } = project;
3567
3818
  assertFontFilesExist(project);
3568
3819
  const out = context.outDir;
3569
- const srcDir = join10(out, "src");
3570
- const generatedDir = join10(srcDir, "generated");
3571
- const askPath = join10(srcDir, "generated", "Ask.astro");
3572
- const themePath = join10(srcDir, "generated", "app.css");
3573
- const searchClientPath = join10(srcDir, "generated", "search-client.ts");
3574
- const examplesPath = join10(srcDir, "generated", "examples.ts");
3575
- const examplesThemePath = join10(srcDir, "generated", "examples.css");
3820
+ const srcDir = join11(out, "src");
3821
+ const generatedDir = join11(srcDir, "generated");
3822
+ const askPath = join11(srcDir, "generated", "Ask.astro");
3823
+ const themePath = join11(srcDir, "generated", "app.css");
3824
+ const searchClientPath = join11(srcDir, "generated", "search-client.ts");
3825
+ const featuresPath = join11(srcDir, "generated", "features.ts");
3826
+ const examplesPath = join11(srcDir, "generated", "examples.ts");
3827
+ const examplesThemePath = join11(srcDir, "generated", "examples.css");
3576
3828
  const written = new Set;
3577
3829
  const write = (path, content) => {
3578
3830
  written.add(normalize(path));
@@ -3585,6 +3837,10 @@ var generateRuntime = async (project) => {
3585
3837
  const askEnabled = config.ai.ask?.enabled ?? false;
3586
3838
  const exportPdf = config.export.pdf;
3587
3839
  const exportEpub = config.export.epub;
3840
+ const rawMarkdown = await buildRawMarkdown(project);
3841
+ const clientFeatures = clientFeaturesFrom(project, rawMarkdown);
3842
+ const navFragments = navVariants(project.graph).some(({ navigation }) => hasDeferrableGroups(navigation.sidebar));
3843
+ const languageIcons = languageIconCssFrom(project, rawMarkdown);
3588
3844
  const staged = collectStaged(project);
3589
3845
  const [
3590
3846
  pages,
@@ -3643,7 +3899,7 @@ var generateRuntime = async (project) => {
3643
3899
  const docsCollection = resolveDocsCollection(config, context);
3644
3900
  const [structural] = await Promise.all([
3645
3901
  Promise.all([
3646
- write(join10(out, "astro.config.mjs"), astroConfigTemplate({
3902
+ write(join11(out, "astro.config.mjs"), astroConfigTemplate({
3647
3903
  aliases: resolveTsconfigAliases(context.root),
3648
3904
  askPath,
3649
3905
  config,
@@ -3652,6 +3908,8 @@ var generateRuntime = async (project) => {
3652
3908
  context,
3653
3909
  examplesPath,
3654
3910
  examplesThemePath,
3911
+ features: clientFeatures,
3912
+ featuresPath,
3655
3913
  integrationBridge,
3656
3914
  needsReact,
3657
3915
  needsSvelte,
@@ -3661,25 +3919,27 @@ var generateRuntime = async (project) => {
3661
3919
  searchClientPath,
3662
3920
  themePath
3663
3921
  })),
3664
- write(join10(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
3665
- write(join10(out, "tsconfig.json"), runtimeTsconfigTemplate()),
3666
- write(join10(srcDir, "content.config.ts"), contentConfigTemplate({
3922
+ write(join11(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
3923
+ write(join11(out, "tsconfig.json"), runtimeTsconfigTemplate()),
3924
+ write(join11(srcDir, "content.config.ts"), contentConfigTemplate({
3667
3925
  collection: docsCollection,
3668
3926
  config,
3669
3927
  context,
3670
3928
  filesystem: hasFilesystemSource,
3671
3929
  staged: hasStaged
3672
3930
  })),
3673
- write(join10(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
3931
+ write(join11(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
3674
3932
  exportEpub,
3675
3933
  exportPdf,
3676
3934
  mathEnabled: usesMath,
3935
+ navFragments,
3677
3936
  needsReact
3678
3937
  })),
3938
+ writeNavFragments(write, srcDir, navFragments),
3679
3939
  write(askPath, askComponentTemplate(askEnabled)),
3680
- write(join10(srcDir, "generated", "components.ts"), slotPlan.module),
3681
- write(join10(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
3682
- write(join10(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
3940
+ write(join11(srcDir, "generated", "components.ts"), slotPlan.module),
3941
+ write(join11(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
3942
+ write(join11(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
3683
3943
  write(examplesThemePath, examplesEntryTemplate({
3684
3944
  configTokens: buildThemeCss(config.theme),
3685
3945
  sources: exampleScanRoots(context.root, exampleDiscovery.dir).map((dir) => `${dir}/${EXAMPLE_SCAN_GLOB}`),
@@ -3687,6 +3947,7 @@ var generateRuntime = async (project) => {
3687
3947
  })),
3688
3948
  write(themePath, tailwindEntryTemplate({
3689
3949
  configTokens: `${buildThemeCss(config.theme)}${buildFontsCss(config.theme.fonts)}`,
3950
+ languageIcons,
3690
3951
  sources: [
3691
3952
  `${BLUME_SRC}/**/*.{astro,ts,tsx}`,
3692
3953
  `${context.root}/**/*.{astro,mdx,ts,tsx}`
@@ -3695,24 +3956,29 @@ var generateRuntime = async (project) => {
3695
3956
  userTheme
3696
3957
  }))
3697
3958
  ]),
3698
- Promise.all(islandDiscovery.islands.map((island) => write(join10(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island)))),
3699
- Promise.all(slotPlan.wrappers.map((wrapper) => write(join10(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
3700
- Promise.all(exampleDiscovery.examples.map((example) => write(join10(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
3959
+ Promise.all(islandDiscovery.islands.map((island) => write(join11(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island)))),
3960
+ Promise.all(slotPlan.wrappers.map((wrapper) => write(join11(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
3961
+ Promise.all(exampleDiscovery.examples.map((example) => write(join11(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
3701
3962
  writeAskFiles(project, srcDir, write, modules),
3702
3963
  writeMcpFiles(mcp, write, agentData),
3703
3964
  writeApiFiles(project, api, write, agentData, mcp),
3704
3965
  playgroundProxy.enabled ? write(playgroundProxy.entrypoint, playgroundProxyTemplate(proxyOrigins)) : Promise.resolve(false)
3705
3966
  ]);
3706
3967
  if (config.seo.og.enabled) {
3707
- await write(join10(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, {
3968
+ await write(join11(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, {
3708
3969
  ...projectOgFonts(project),
3970
+ cache: {
3971
+ dir: ogCacheDir(project.context),
3972
+ version: getBlumeVersion()
3973
+ },
3709
3974
  pageDescriptions: config.seo.og.description !== false
3710
3975
  }, changelogIndex));
3711
3976
  }
3712
3977
  if (changelogIndex) {
3713
- await write(join10(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
3978
+ await write(join11(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
3714
3979
  exportEpub,
3715
3980
  exportPdf,
3981
+ mathEnabled: usesMath,
3716
3982
  needsReact,
3717
3983
  staged: hasStaged
3718
3984
  }));
@@ -3726,32 +3992,32 @@ var generateRuntime = async (project) => {
3726
3992
  write
3727
3993
  }),
3728
3994
  writeNotFoundPage(write, srcDir, pages, project.graph.pages),
3729
- write(searchClientPath, searchClientTemplate(config))
3995
+ write(searchClientPath, searchClientTemplate(config)),
3996
+ write(featuresPath, featuresTemplate(clientFeatures))
3730
3997
  ]);
3731
3998
  if (servesStaticIndex(config.search.provider)) {
3732
3999
  const documents = await buildSearchDocuments(project);
3733
4000
  modules.set("blume:search-index", JSON.stringify(documents));
3734
- await write(join10(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
4001
+ await write(join11(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
3735
4002
  }
3736
4003
  if (config.search.provider === "mixedbread") {
3737
- await write(join10(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
4004
+ await write(join11(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
3738
4005
  }
3739
- await write(join10(srcDir, "generated", "includes.json"), `${JSON.stringify(buildIncludeGraph(project.graph.pages))}
4006
+ await write(join11(srcDir, "generated", "includes.json"), `${JSON.stringify(buildIncludeGraph(project.graph.pages))}
3740
4007
  `);
3741
- const rawMarkdown = await buildRawMarkdown(project);
3742
4008
  modules.set("blume:raw-markdown", JSON.stringify(rawMarkdown));
3743
4009
  const contentAssets = await collectContentAssets(project);
3744
4010
  modules.set("blume:content-assets", JSON.stringify(contentAssets));
3745
4011
  await Promise.all([
3746
- write(join10(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
3747
- write(join10(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx")),
3748
- write(join10(srcDir, "pages", "blume-assets", "[...asset].ts"), contentAssetsEndpointTemplate(join10(project.context.outDir, "public", "blume-assets")))
4012
+ write(join11(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
4013
+ write(join11(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx")),
4014
+ write(join11(srcDir, "pages", "blume-assets", "[...asset].ts"), contentAssetsEndpointTemplate(join11(project.context.outDir, "public", "blume-assets")))
3749
4015
  ]);
3750
4016
  const feeds = buildRssFeeds(project);
3751
4017
  if (feeds.length > 0) {
3752
4018
  const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
3753
4019
  modules.set("blume:rss", JSON.stringify(feedXml));
3754
- await write(join10(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate());
4020
+ await write(join11(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate());
3755
4021
  }
3756
4022
  const warnings = [
3757
4023
  ...depsLinkWarning ? [depsLinkWarning] : [],
@@ -3787,12 +4053,12 @@ var generateRuntime = async (project) => {
3787
4053
  root: context.root
3788
4054
  });
3789
4055
  warnings.push(...references.warnings);
3790
- await Promise.all(references.files.map((file) => write(join10(srcDir, "pages", file.pagePath), file.content)));
4056
+ await Promise.all(references.files.map((file) => write(join11(srcDir, "pages", file.pagePath), file.content)));
3791
4057
  }
3792
4058
  modules.set("blume:data", buildRuntimeData(project));
3793
4059
  modules.set("blume:openapi", JSON.stringify(openApiData));
3794
4060
  await Promise.all([
3795
- write(join10(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
4061
+ write(join11(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
3796
4062
  `),
3797
4063
  writeStagedContent(out, staged)
3798
4064
  ]);
@@ -3802,7 +4068,7 @@ var generateRuntime = async (project) => {
3802
4068
  return { structuralChange: structural.some(Boolean), warnings };
3803
4069
  };
3804
4070
 
3805
- export { SIGNATURES_DIRECTORY_PATH, SIGNATURES_DIRECTORY_TYPE, publishBuildProject, refreshBlumeContent, showBlumeErrorOverlay, buildAskData, buildMcpDiscovery, buildMcpServerCard, buildThemeCss, buildReferenceFiles, tailwindEntryTemplate, examplesEntryTemplate, rebaseSourceDirectives, twoslashCss, planComponentSlots, discoverIslands, EXAMPLE_SCAN_GLOB, exampleScanRoots, discoverExamples, exampleMarkdownLookup, detectNeedsReact, detectUsesMath, collectStaged, buildRuntimeData, generateRuntime };
4071
+ export { SIGNATURES_DIRECTORY_PATH, SIGNATURES_DIRECTORY_TYPE, publishBuildProject, refreshBlumeContent, showBlumeErrorOverlay, ogCacheDir, pruneCardCache, cardCacheTally, buildAskData, buildMcpDiscovery, buildMcpServerCard, buildThemeCss, buildReferenceFiles, tailwindEntryTemplate, examplesEntryTemplate, rebaseSourceDirectives, twoslashCss, planComponentSlots, discoverIslands, EXAMPLE_SCAN_GLOB, exampleScanRoots, discoverExamples, exampleMarkdownLookup, detectNeedsReact, detectUsesMath, collectStaged, buildRuntimeData, languageIconCssFor, clientFeaturesFor, generateRuntime };
3806
4072
 
3807
- //# debugId=39608A54607A739D64756E2164756E21
3808
- //# sourceMappingURL=chunk-62qsssnh.js.map
4073
+ //# debugId=29D4FE8449AF429964756E2164756E21
4074
+ //# sourceMappingURL=chunk-x1wvw7a8.js.map