blume 1.0.3 → 1.0.4

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 (51) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cli/index.js +441 -259
  3. package/dist/cli/index.js.map +12 -11
  4. package/dist/types/core/config-input.d.ts +27 -8
  5. package/dist/types/core/data.d.ts +12 -0
  6. package/dist/types/core/i18n-ui.d.ts +136 -136
  7. package/dist/types/core/schema.d.ts +420 -350
  8. package/dist/types/core/types.d.ts +10 -0
  9. package/dist/types/openapi/references.d.ts +12 -7
  10. package/docs/advanced/api-reference.mdx +11 -3
  11. package/docs/configuration/seo.mdx +20 -1
  12. package/docs/content/components.mdx +1 -2
  13. package/docs/content/navigation.mdx +10 -0
  14. package/docs/content/syntax.mdx +116 -4
  15. package/package.json +1 -1
  16. package/skills/blume-migrate/SKILL.md +170 -0
  17. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +20 -0
  18. package/skills/blume-migrate/references/docusaurus.md +95 -0
  19. package/skills/blume-migrate/references/fumadocs.md +95 -0
  20. package/skills/blume-migrate/references/mintlify.md +155 -0
  21. package/skills/blume-migrate/references/monorepo.md +224 -0
  22. package/skills/blume-migrate/references/nextra.md +76 -0
  23. package/skills/blume-migrate/references/starlight.md +116 -0
  24. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +466 -0
  25. package/src/astro/component-slots.ts +3 -2
  26. package/src/astro/generate.ts +82 -23
  27. package/src/astro/templates.ts +93 -34
  28. package/src/components/content/Callout.astro +8 -2
  29. package/src/components/content/Prompt.astro +25 -13
  30. package/src/components/layout/Header.astro +4 -8
  31. package/src/components/layout/Logo.astro +13 -1
  32. package/src/components/layout/PageFeedback.astro +1 -1
  33. package/src/components/layout/PageLayout.astro +4 -8
  34. package/src/components/layout/Pagination.astro +6 -6
  35. package/src/components/layout/RootLayout.astro +4 -8
  36. package/src/components/layout/Search.astro +1 -1
  37. package/src/components/layout/nav-utils.ts +9 -7
  38. package/src/core/config-input.ts +29 -8
  39. package/src/core/data.ts +9 -1
  40. package/src/core/navigation.ts +55 -13
  41. package/src/core/schema.ts +17 -1
  42. package/src/core/sources/watch.ts +5 -0
  43. package/src/core/types.ts +10 -0
  44. package/src/markdown/index.ts +2 -0
  45. package/src/markdown/language-icon.ts +2 -1
  46. package/src/markdown/table-wrap.ts +43 -0
  47. package/src/og/card.ts +39 -12
  48. package/src/og/index.ts +1 -1
  49. package/src/og/logo.ts +21 -0
  50. package/src/openapi/references.ts +19 -16
  51. package/src/theme/entry.ts +50 -5
package/dist/cli/index.js CHANGED
@@ -525,11 +525,11 @@ Next steps:
525
525
  });
526
526
 
527
527
  // src/cli/commands/build.ts
528
- import { existsSync as existsSync15 } from "node:fs";
528
+ import { existsSync as existsSync16 } from "node:fs";
529
529
  import { readdir, stat, writeFile as writeFile7 } from "node:fs/promises";
530
530
  import { build } from "astro";
531
531
  import { defineCommand as defineCommand2 } from "citty";
532
- import { join as join24 } from "pathe";
532
+ import { join as join25 } from "pathe";
533
533
 
534
534
  // src/core/base-path.ts
535
535
  var normalizeBasePath = (input) => {
@@ -3972,7 +3972,7 @@ var refuseIfDevRunning = (root, action, options = {}) => {
3972
3972
  };
3973
3973
 
3974
3974
  // src/astro/generate.ts
3975
- import { existsSync as existsSync12, readFileSync as readFileSync7, realpathSync } from "node:fs";
3975
+ import { existsSync as existsSync13, readFileSync as readFileSync8, realpathSync } from "node:fs";
3976
3976
  import {
3977
3977
  lstat,
3978
3978
  mkdir as mkdir6,
@@ -3984,7 +3984,7 @@ import {
3984
3984
  } from "node:fs/promises";
3985
3985
  import { createRequire as createRequire5 } from "node:module";
3986
3986
  import { pathToFileURL as pathToFileURL3 } from "node:url";
3987
- import { basename as basename2, dirname as dirname8, join as join22, normalize as normalize3, relative as relative8 } from "pathe";
3987
+ import { basename as basename2, dirname as dirname8, join as join23, normalize as normalize3, relative as relative8 } from "pathe";
3988
3988
  import { glob as glob5 } from "tinyglobby";
3989
3989
 
3990
3990
  // src/ai/ask-data.ts
@@ -4899,10 +4899,7 @@ var resolveReferences = (config) => [
4899
4899
  }, config.basePath),
4900
4900
  ...referencesFor("asyncapi", config.asyncapi, "Events", "scalar", NO_DISPLAY, config.basePath)
4901
4901
  ];
4902
- var referenceTabs = (config) => resolveReferences(config).map((ref) => ({
4903
- label: ref.label,
4904
- path: ref.renderer === "blume" ? withBasePath(config.basePath, ref.route) : ref.route
4905
- }));
4902
+ var referenceRoutes = (config) => resolveReferences(config).map((ref) => ref.renderer === "blume" ? withBasePath(config.basePath, ref.route) : ref.route);
4906
4903
  var blumeReferenceOf = (ref, seen, usedSlugs) => {
4907
4904
  if (ref.kind !== "openapi" || ref.renderer !== "blume") {
4908
4905
  return null;
@@ -5480,6 +5477,7 @@ import { glob as glob2 } from "tinyglobby";
5480
5477
  // src/core/sources/watch.ts
5481
5478
  var BLUME_IGNORE_DIRS = [
5482
5479
  ".blume",
5480
+ ".blume-verify",
5483
5481
  ".cache",
5484
5482
  ".git",
5485
5483
  ".next",
@@ -6431,7 +6429,7 @@ var navigationConfigSchema = z2.strictObject({
6431
6429
  items: z2.array(sidebarItemSchema).optional()
6432
6430
  })
6433
6431
  ]).default({}).transform((value) => Array.isArray(value) ? { display: "flat", items: value } : value),
6434
- tabs: z2.array(navTabSchema).optional()
6432
+ tabs: z2.array(navTabSchema).default([])
6435
6433
  });
6436
6434
  var exportConfigSchema = z2.union([
6437
6435
  z2.boolean(),
@@ -6500,8 +6498,18 @@ var xConfigSchema = z2.strictObject({
6500
6498
  creator: xHandleSchema,
6501
6499
  handle: xHandleSchema
6502
6500
  });
6501
+ var ogColorSchema = z2.string().regex(/^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/iu);
6502
+ var ogPaletteSchema = z2.strictObject({
6503
+ accent: ogColorSchema.optional(),
6504
+ background: ogColorSchema.optional(),
6505
+ border: ogColorSchema.optional(),
6506
+ foreground: ogColorSchema.optional(),
6507
+ muted: ogColorSchema.optional()
6508
+ });
6503
6509
  var ogConfigSchema = z2.strictObject({
6504
- enabled: z2.boolean().optional()
6510
+ enabled: z2.boolean().optional(),
6511
+ logo: z2.string().optional(),
6512
+ palette: ogPaletteSchema.optional()
6505
6513
  });
6506
6514
  var rssConfigSchema = z2.strictObject({
6507
6515
  enabled: z2.boolean().default(true),
@@ -7646,14 +7654,29 @@ var resolveTsconfigAliases = (root) => {
7646
7654
  return aliases;
7647
7655
  };
7648
7656
 
7657
+ // src/og/logo.ts
7658
+ import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
7659
+ import { join as join18 } from "pathe";
7660
+ var resolveOgLogo = (project, source) => {
7661
+ if (!source?.toLowerCase().endsWith(".svg")) {
7662
+ return;
7663
+ }
7664
+ const relative6 = source.replace(/^\//u, "");
7665
+ const file = [
7666
+ join18(project.context.root, "public", relative6),
7667
+ join18(project.context.root, relative6)
7668
+ ].find((path) => existsSync11(path));
7669
+ return file ? readFileSync5(file, "utf-8") : undefined;
7670
+ };
7671
+
7649
7672
  // src/openapi/scalar.ts
7650
7673
  import { readFile as readFile8 } from "node:fs/promises";
7651
- import { isAbsolute as isAbsolute8, join as join19 } from "pathe";
7674
+ import { isAbsolute as isAbsolute8, join as join20 } from "pathe";
7652
7675
 
7653
7676
  // src/astro/templates.ts
7654
- import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
7677
+ import { existsSync as existsSync12, readFileSync as readFileSync6 } from "node:fs";
7655
7678
  import { pathToFileURL as pathToFileURL2 } from "node:url";
7656
- import { dirname as dirname7, isAbsolute as isAbsolute7, join as join18, relative as relative6 } from "pathe";
7679
+ import { dirname as dirname7, isAbsolute as isAbsolute7, join as join19, relative as relative6 } from "pathe";
7657
7680
  var WORKSPACE_MARKERS = [
7658
7681
  ".git",
7659
7682
  "bun.lock",
@@ -7664,17 +7687,17 @@ var WORKSPACE_MARKERS = [
7664
7687
  "yarn.lock"
7665
7688
  ];
7666
7689
  var hasWorkspacesField = (pkgPath) => {
7667
- if (!existsSync11(pkgPath)) {
7690
+ if (!existsSync12(pkgPath)) {
7668
7691
  return false;
7669
7692
  }
7670
7693
  try {
7671
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
7694
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
7672
7695
  return pkg.workspaces !== undefined;
7673
7696
  } catch {
7674
7697
  return false;
7675
7698
  }
7676
7699
  };
7677
- var hasWorkspaceMarker = (dir) => hasWorkspacesField(join18(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) => existsSync11(join18(dir, marker)));
7700
+ var hasWorkspaceMarker = (dir) => hasWorkspacesField(join19(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) => existsSync12(join19(dir, marker)));
7678
7701
  var findWorkspaceRoot = (start) => {
7679
7702
  let dir = start;
7680
7703
  for (;; ) {
@@ -7697,6 +7720,23 @@ var ADAPTER_IMPORTS = {
7697
7720
  var ADAPTER_OPTIONS = {
7698
7721
  node: '{ mode: "standalone" }'
7699
7722
  };
7723
+ var WRANGLER_CONFIG_FILES = [
7724
+ "wrangler.jsonc",
7725
+ "wrangler.json",
7726
+ "wrangler.toml"
7727
+ ];
7728
+ var resolveCloudflareAdapterArgs = (context) => {
7729
+ const args = ['prerenderEnvironment: "node"'];
7730
+ const wranglerPath = WRANGLER_CONFIG_FILES.map((file) => join19(context.root, file)).find((file) => existsSync12(file));
7731
+ if (wranglerPath) {
7732
+ let configPath = relative6(context.outDir, wranglerPath);
7733
+ if (!configPath.startsWith(".") && !configPath.startsWith("/")) {
7734
+ configPath = `./${configPath}`;
7735
+ }
7736
+ args.push(`configPath: ${JSON.stringify(configPath)}`);
7737
+ }
7738
+ return `{ ${args.join(", ")} }`;
7739
+ };
7700
7740
  var runtimeDependencies = (options) => {
7701
7741
  const { config, needsReact, needsSvelte, needsVue } = options;
7702
7742
  const deps = ["@astrojs/mdx"];
@@ -7763,7 +7803,15 @@ var astroConfigTemplate = (options) => {
7763
7803
  const fsAllow = [...new Set([findWorkspaceRoot(context.root), context.root])];
7764
7804
  const adapterImport = server && deployment.adapter ? `import adapter from "${ADAPTER_IMPORTS[deployment.adapter]}";
7765
7805
  ` : "";
7766
- const adapterArgs = server && deployment.adapter ? ADAPTER_OPTIONS[deployment.adapter] ?? "" : "";
7806
+ const adapterArgs = (() => {
7807
+ if (!server || !deployment.adapter) {
7808
+ return "";
7809
+ }
7810
+ if (deployment.adapter === "cloudflare") {
7811
+ return resolveCloudflareAdapterArgs(context);
7812
+ }
7813
+ return ADAPTER_OPTIONS[deployment.adapter] ?? "";
7814
+ })();
7767
7815
  const adapterOption = server && deployment.adapter ? `
7768
7816
  adapter: adapter(${adapterArgs}),` : "";
7769
7817
  const siteOption = deployment.site ? `
@@ -7850,6 +7898,18 @@ export default defineConfig({
7850
7898
  devToolbar: { enabled: false },
7851
7899
  vite: {
7852
7900
  plugins: [tailwindcss(), prerenderDepsPlugin(), serverAppResolvePlugin()],
7901
+ // Mermaid (lazy-loaded client-side for diagrams) statically imports dayjs as
7902
+ // CJS (\`dayjs/dayjs.min.js\`). In dev, an un-pre-bundled dependency is served
7903
+ // as raw ESM, and that UMD file exposes no \`default\` export, so mermaid
7904
+ // throws on load and diagrams render blank. Forcing mermaid through the dep
7905
+ // optimizer bundles dayjs with correct CJS interop. In a standalone install
7906
+ // Blume's dynamic \`import("mermaid")\` lives inside \`node_modules/blume\`,
7907
+ // which Vite's optimizer scan doesn't crawl, so mermaid is never discovered
7908
+ // on its own — hence the explicit include. mermaid resolves through the
7909
+ // \`blume\` package (it isn't a direct dep of the generated project), so the
7910
+ // nested \`blume > mermaid\` form is required. Production (Rollup) already
7911
+ // handles the interop, so this only affects dev.
7912
+ optimizeDeps: { include: ["blume > mermaid"] },
7853
7913
  // Blume's render-time deps are forced external on both build environments so
7854
7914
  // native bindings resolve at runtime and isolated linkers don't bundle
7855
7915
  // symlinked store copies (which would surface their children as unresolvable
@@ -7888,14 +7948,14 @@ export default defineConfig({
7888
7948
  // self-hosted fonts) -- pure noise the loader logs as "No entry type
7889
7949
  // found". Vite appends this to its default ignores.
7890
7950
  watch: {
7891
- ignored: ${JSON.stringify([join18(context.outDir, ".astro", "**")])},
7951
+ ignored: ${JSON.stringify([join19(context.outDir, ".astro", "**")])},
7892
7952
  },
7893
7953
  },
7894
7954
  },
7895
7955
  });
7896
7956
  `;
7897
7957
  };
7898
- var stagedContentDir = (outDir) => join18(outDir, "content");
7958
+ var stagedContentDir = (outDir) => join19(outDir, "content");
7899
7959
  var astroGlobBase = (base) => isAbsolute7(base) ? pathToFileURL2(base).href : base;
7900
7960
  var contentConfigTemplate = (options) => {
7901
7961
  const { context, config } = options;
@@ -8178,9 +8238,10 @@ export function getStaticPaths() {
8178
8238
  }));
8179
8239
  }
8180
8240
 
8181
- export function GET({ props }) {
8182
- const entry = raw[props.route];
8183
- return new Response(entry ? ${kind === "md" ? "(entry.md ?? entry.mdx)" : "entry.mdx"} : "", {
8241
+ export function GET({ props }: { props: { route: string } }) {
8242
+ const entries = raw as Record<string, { md?: string; mdx?: string }>;
8243
+ const entry = entries[props.route];
8244
+ return new Response(entry ? ${kind === "md" ? '(entry.md ?? entry.mdx ?? "")' : '(entry.mdx ?? "")'} : "", {
8184
8245
  headers: { "Content-Type": "text/markdown; charset=utf-8" },
8185
8246
  });
8186
8247
  }
@@ -8224,15 +8285,16 @@ export function getStaticPaths() {
8224
8285
  }));
8225
8286
  }
8226
8287
 
8227
- export function GET({ props }) {
8228
- return new Response(feeds[props.section] ?? "", {
8288
+ export function GET({ props }: { props: { section: string } }) {
8289
+ const bySection = feeds as Record<string, string>;
8290
+ return new Response(bySection[props.section] ?? "", {
8229
8291
  headers: { "Content-Type": "application/rss+xml; charset=utf-8" },
8230
8292
  });
8231
8293
  }
8232
8294
  `;
8233
8295
  var ogEndpointTemplate = (customRoutes = []) => `// Generated by Blume. Do not edit.
8234
8296
  import { renderOgImage } from "blume/og";
8235
- import data from "../../generated/data.json";
8297
+ import data from "blume:data";
8236
8298
 
8237
8299
  export const prerender = true;
8238
8300
 
@@ -8240,9 +8302,9 @@ export const prerender = true;
8240
8302
  const customRoutes = ${JSON.stringify(customRoutes)};
8241
8303
 
8242
8304
  export function getStaticPaths() {
8243
- const seen = new Set();
8244
- const paths = [];
8245
- const add = (slug, title) => {
8305
+ const seen = new Set<string>();
8306
+ const paths: { params: { slug: string }; props: { title: string } }[] = [];
8307
+ const add = (slug: string, title: string) => {
8246
8308
  if (seen.has(slug)) {
8247
8309
  return;
8248
8310
  }
@@ -8275,17 +8337,18 @@ const siteHost = (() => {
8275
8337
  }
8276
8338
  })();
8277
8339
 
8278
- export async function GET({ props }) {
8340
+ export async function GET({ props }: { props: { title: string } }) {
8279
8341
  const png = await renderOgImage({
8280
- accent: data.config.theme.accent.light,
8342
+ accent: data.config.og.palette?.accent ?? data.config.theme.accent.light,
8281
8343
  brand: data.config.title,
8282
8344
  description: data.config.description,
8283
- logo: data.config.logo?.svg,
8345
+ logo: data.config.og.logo,
8346
+ palette: data.config.og.palette,
8284
8347
  repo: repoSlug,
8285
8348
  site: siteHost,
8286
8349
  title: props.title,
8287
8350
  });
8288
- return new Response(png, {
8351
+ return new Response(new Uint8Array(png), {
8289
8352
  headers: {
8290
8353
  "Cache-Control": "public, max-age=31536000, immutable",
8291
8354
  "Content-Type": "image/png",
@@ -8344,6 +8407,7 @@ var catchAllPageTemplate = (options) => {
8344
8407
  return `---
8345
8408
  // Generated by Blume. Do not edit.
8346
8409
  import { getEntry, render } from "astro:content";
8410
+ import type { CollectionKey } from "astro:content";
8347
8411
  import RootLayout from "blume/components/layout/RootLayout.astro";
8348
8412
  import { withBase } from "blume/components/islands/base-path.ts";
8349
8413
  import { resolveSlot } from "blume/components/layout/overrides.ts";
@@ -8387,7 +8451,7 @@ import ApiTagOperations from "blume/components/openapi/ApiTagOperations.astro";
8387
8451
  import Operation from "blume/components/openapi/Operation.astro";
8388
8452
  ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../generated/components.ts";
8389
8453
  import { islandComponents } from "../generated/islands.ts";
8390
- import data from "../generated/data.json";
8454
+ import data from "blume:data";
8391
8455
 
8392
8456
  const Color = Object.assign(ColorRoot, { Item: ColorItem, Row: ColorRow });
8393
8457
  const Tree = Object.assign(TreeRoot, { File: TreeFile, Folder: TreeFolder });
@@ -8456,7 +8520,7 @@ export function getStaticPaths() {
8456
8520
  }
8457
8521
 
8458
8522
  const { entryId, collection, route, title, indexable, editUrl, lastModified, locale, alternates, fallback } = Astro.props;
8459
- const entry = await getEntry(collection, entryId);
8523
+ const entry = await getEntry(collection as CollectionKey, entryId);
8460
8524
  if (!entry) {
8461
8525
  return new Response(null, { status: 404 });
8462
8526
  }
@@ -8491,18 +8555,18 @@ const canonical =
8491
8555
  // Locale resolution. With i18n on, pick the active locale's nav + dictionary,
8492
8556
  // build hreflang alternates, and derive the language-switcher targets.
8493
8557
  const i18n = data.config.i18n;
8494
- const localePrefix = (codeArg) =>
8558
+ const localePrefix = (codeArg: string) =>
8495
8559
  i18n && codeArg === i18n.defaultLocale && i18n.hideDefaultLocalePrefix
8496
8560
  ? ""
8497
8561
  : \`/\${codeArg}\`;
8498
- const localizeRoute = (logical, codeArg) => {
8562
+ const localizeRoute = (logical: string, codeArg: string) => {
8499
8563
  const prefix = localePrefix(codeArg);
8500
8564
  if (!prefix) {
8501
8565
  return logical;
8502
8566
  }
8503
8567
  return logical === "/" ? prefix : \`\${prefix}\${logical}\`;
8504
8568
  };
8505
- const stripLocale = (path, codeArg) => {
8569
+ const stripLocale = (path: string, codeArg: string) => {
8506
8570
  const prefix = localePrefix(codeArg);
8507
8571
  return prefix && path.startsWith(prefix) ? path.slice(prefix.length) || "/" : path;
8508
8572
  };
@@ -8519,7 +8583,7 @@ const contentLocale =
8519
8583
  const contentDir = i18n
8520
8584
  ? (i18n.locales.find((l) => l.code === contentLocale)?.dir ?? "ltr")
8521
8585
  : "ltr";
8522
- const absolute = (path) => {
8586
+ const absolute = (path: string) => {
8523
8587
  const p = withBase(path);
8524
8588
  return base + (p === "/" ? "" : p);
8525
8589
  };
@@ -8612,14 +8676,15 @@ import Update from "blume/components/content/Update.astro";
8612
8676
  import { withBase } from "blume/components/islands/base-path.ts";
8613
8677
  import { resolveSlot } from "blume/components/layout/overrides.ts";
8614
8678
  import { layoutOverrides } from "../generated/components.ts";
8615
- import data from "../generated/data.json";
8679
+ import data from "blume:data";
8616
8680
 
8617
8681
  export const prerender = true;
8618
8682
 
8619
- const entryDate = (entry) =>
8620
- entry.data.date ?? entry.data.changelog?.date ?? null;
8683
+ const entryDate = (entry: {
8684
+ data: { date?: string | null; changelog?: { date?: string | null } | null };
8685
+ }) => entry.data.date ?? entry.data.changelog?.date ?? null;
8621
8686
 
8622
- const toTime = (value) => {
8687
+ const toTime = (value: string | null | undefined) => {
8623
8688
  if (!value) {
8624
8689
  return 0;
8625
8690
  }
@@ -8627,7 +8692,7 @@ const toTime = (value) => {
8627
8692
  return Number.isNaN(date.getTime()) ? 0 : date.getTime();
8628
8693
  };
8629
8694
 
8630
- const formatDate = (value) => {
8695
+ const formatDate = (value: string | null | undefined) => {
8631
8696
  if (!value) {
8632
8697
  return;
8633
8698
  }
@@ -8640,14 +8705,14 @@ const formatDate = (value) => {
8640
8705
  }).format(date);
8641
8706
  };
8642
8707
 
8643
- const slugify = (text) =>
8708
+ const slugify = (text: string) =>
8644
8709
  text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") ||
8645
8710
  "update";
8646
8711
 
8647
8712
  // The major of a version's embedded semver (\`1.2.3\` -> 1, \`pkg@2.0.0\` -> 2), or
8648
8713
  // null when there is no full major.minor.patch to key on. Drives the changelog's
8649
8714
  // group-by-major pagination, so it tolerates the scoped tags monorepos publish.
8650
- const majorVersion = (version) => {
8715
+ const majorVersion = (version: string | null | undefined) => {
8651
8716
  const match = /(\\d+)\\.\\d+\\.\\d+/.exec(String(version ?? ""));
8652
8717
  return match ? Number(match[1]) : null;
8653
8718
  };
@@ -8679,7 +8744,7 @@ const items = await Promise.all(
8679
8744
  return {
8680
8745
  Content: (await render(entry)).Content,
8681
8746
  date: formatDate(entryDate(entry)),
8682
- href: routeByEntry.get(entry.id) ?? null,
8747
+ href: routeByEntry.get(entry.id) ?? undefined,
8683
8748
  id: slugify(label),
8684
8749
  label,
8685
8750
  major: majorVersion(entry.data.changelog?.version),
@@ -8708,7 +8773,9 @@ for (const item of items) {
8708
8773
  // semver and they span more than one major line. Older majors then collapse
8709
8774
  // into groups the reader reveals one at a time; otherwise the timeline is flat.
8710
8775
  const majors = items.every((item) => item.major !== null)
8711
- ? [...new Set(items.map((item) => item.major))].toSorted((a, b) => b - a)
8776
+ ? [...new Set(items.map((item) => item.major))]
8777
+ .filter((major): major is number => major !== null)
8778
+ .toSorted((a, b) => b - a)
8712
8779
  : [];
8713
8780
  const paginate = majors.length > 1;
8714
8781
  const majorGroups = majors.map((major) => ({
@@ -8846,7 +8913,7 @@ var notFoundPageTemplate = () => `---
8846
8913
  // Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
8847
8914
  import PageLayout from "blume/components/layout/PageLayout.astro";
8848
8915
  import { withBase } from "blume/components/islands/base-path.ts";
8849
- import data from "../generated/data.json";
8916
+ import data from "blume:data";
8850
8917
 
8851
8918
  export const prerender = true;
8852
8919
 
@@ -8963,7 +9030,10 @@ export const getStaticPaths = () =>
8963
9030
  Object.keys(examples).map((path) => ({ params: { path } }));
8964
9031
 
8965
9032
  const { path } = Astro.params;
8966
- const entry = examples[path];
9033
+ const entry = path ? examples[path] : undefined;
9034
+ if (!entry) {
9035
+ return new Response(null, { status: 404 });
9036
+ }
8967
9037
  const Example = entry.Component;
8968
9038
  ---
8969
9039
 
@@ -9017,6 +9087,14 @@ declare module "blume:data" {
9017
9087
  export default data;
9018
9088
  }
9019
9089
 
9090
+ declare module "blume:examples" {
9091
+ type Examples = typeof import("./generated/examples.ts").examples;
9092
+ export const examples: Record<string, Examples[keyof Examples]>;
9093
+ export const examplesBase: string;
9094
+ }
9095
+
9096
+ declare module "blume:examples-theme";
9097
+
9020
9098
  declare module "blume:openapi" {
9021
9099
  const specs: import("blume/openapi/model.ts").OpenApiData;
9022
9100
  export default specs;
@@ -9147,7 +9225,7 @@ var specConfiguration = async (spec, root) => {
9147
9225
  if (URL_SPEC2.test(spec)) {
9148
9226
  return { config: { url: spec } };
9149
9227
  }
9150
- const absolute = isAbsolute8(spec) ? spec : join19(root, spec);
9228
+ const absolute = isAbsolute8(spec) ? spec : join20(root, spec);
9151
9229
  try {
9152
9230
  return { config: { content: await readFile8(absolute, "utf-8") } };
9153
9231
  } catch {
@@ -9213,6 +9291,13 @@ var buildReferenceFiles = async (options) => {
9213
9291
  // src/theme/entry.ts
9214
9292
  var DARK_VARIANT = `/* Dark mode is driven by data-theme on the <html> element. */
9215
9293
  @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));`;
9294
+ var COLOR_SCHEME_DEFAULTS = `:root {
9295
+ color-scheme: light;
9296
+ }
9297
+
9298
+ :root[data-theme="dark"] {
9299
+ color-scheme: dark;
9300
+ }`;
9216
9301
  var TOKEN_DEFAULTS = `:root {
9217
9302
  --blume-background: oklch(1 0 0);
9218
9303
  --blume-background-image: none;
@@ -9318,6 +9403,8 @@ ${options.sources.map((source) => `@source "${source}";`).join(`
9318
9403
 
9319
9404
  ${DARK_VARIANT}
9320
9405
 
9406
+ ${COLOR_SCHEME_DEFAULTS}
9407
+
9321
9408
  ${TOKEN_DEFAULTS}
9322
9409
 
9323
9410
  ${THEME_MAPPING}
@@ -9563,13 +9650,16 @@ blume-diff {
9563
9650
 
9564
9651
  /* Language icon (simple-icons) sits at the header's left edge; the label shifts
9565
9652
  right to make room. Injected at build time by the language-icon transformer.
9566
- Shown only for top-level prose blocks, which have a header flush code in
9567
- tabs and API panels is nested deeper, so the child combinator skips it. */
9653
+ The icon is gated on data-language (the header bar), not just data-icon: the
9654
+ transformer runs whenever icons are on, but a header-less standalone
9655
+ CodeBlock (no title) never gets data-language, so without this gate the
9656
+ absolutely-positioned icon would overlap the first code line. Fenced code
9657
+ and titled blocks always have a header, so the icon shows there. */
9568
9658
  .blume-lang-icon {
9569
9659
  display: none;
9570
9660
  }
9571
9661
 
9572
- .prose > :where(pre[data-icon]) > .blume-lang-icon {
9662
+ .prose > :where(pre[data-language][data-icon]) > .blume-lang-icon {
9573
9663
  color: var(--blume-muted-foreground);
9574
9664
  display: block;
9575
9665
  height: 0.875rem;
@@ -9579,7 +9669,7 @@ blume-diff {
9579
9669
  width: 0.875rem;
9580
9670
  }
9581
9671
 
9582
- .prose > :where(pre[data-icon])::before {
9672
+ .prose > :where(pre[data-language][data-icon])::before {
9583
9673
  padding-left: 2.5rem;
9584
9674
  }
9585
9675
 
@@ -9630,11 +9720,40 @@ blume-diff {
9630
9720
  font-size: 0.8125rem;
9631
9721
  }
9632
9722
 
9723
+ /* Scroll wide tables in place; the wrapper is added by the blume:table-wrap hast
9724
+ plugin. The border+radius frames the scroll viewport so a clipped wide table
9725
+ reads as scrollable rather than cut off, and carries the table's vertical
9726
+ rhythm (the inner table's own margin is zeroed so it fills the frame). */
9727
+ .blume-table-scroll {
9728
+ overflow-x: auto;
9729
+ -webkit-overflow-scrolling: touch;
9730
+ margin: 1.5rem 0;
9731
+ border: 1px solid var(--blume-border);
9732
+ border-radius: var(--blume-radius);
9733
+ }
9734
+ .blume-table-scroll > table {
9735
+ margin: 0;
9736
+ }
9737
+ /* Restore inner padding on every cell. Typography zeroes the first/last cell's
9738
+ inline padding so a borderless table aligns to the prose margin; inside the
9739
+ framed wrapper that leaves edge text touching the border. The :is() selector
9740
+ outweighs Typography's :where()-scoped rules so the outer columns get it too. */
9741
+ .blume-table-scroll :is(th, td) {
9742
+ padding: 0.5rem 0.75rem;
9743
+ }
9744
+ /* Keep column labels on one line so a two-word header does not wrap into a
9745
+ ragged stack; the table just scrolls a little wider instead. Body cells keep
9746
+ wrapping so a wide table stays a scroll away, not an endless horizontal run. */
9747
+ .blume-table-scroll th {
9748
+ white-space: nowrap;
9749
+ }
9750
+
9633
9751
  /* GFM renders cells as <td><code> directly, which the descendant form alone
9634
9752
  never matches (a cell is not its own descendant). */
9635
9753
  .prose :where(td, th) > code,
9636
9754
  .prose :where(td, th) :not(pre) > code {
9637
- white-space: nowrap;
9755
+ overflow-wrap: break-word;
9756
+ white-space: normal;
9638
9757
  }
9639
9758
 
9640
9759
  blume-tabs pre,
@@ -9874,6 +9993,8 @@ ${options.sources.map((source) => `@source "${source}";`).join(`
9874
9993
 
9875
9994
  ${DARK_VARIANT}
9876
9995
 
9996
+ ${COLOR_SCHEME_DEFAULTS}
9997
+
9877
9998
  ${TOKEN_DEFAULTS}
9878
9999
 
9879
10000
  ${THEME_MAPPING}
@@ -9894,7 +10015,7 @@ ${options.userCss}
9894
10015
  `;
9895
10016
 
9896
10017
  // src/theme/twoslash.ts
9897
- import { readFileSync as readFileSync6 } from "node:fs";
10018
+ import { readFileSync as readFileSync7 } from "node:fs";
9898
10019
  import { createRequire as createRequire4 } from "node:module";
9899
10020
  var require2 = createRequire4(import.meta.url);
9900
10021
  var OVERRIDES = `
@@ -9961,14 +10082,15 @@ var OVERRIDES = `
9961
10082
  `;
9962
10083
  var twoslashCss = () => {
9963
10084
  const file = require2.resolve("@shikijs/twoslash/style-rich.css");
9964
- return `${readFileSync6(file, "utf-8")}
10085
+ return `${readFileSync7(file, "utf-8")}
9965
10086
  ${OVERRIDES}`;
9966
10087
  };
9967
10088
 
9968
10089
  // src/astro/component-slots.ts
9969
10090
  var EMPTY_MODULE = `// Generated by Blume. Do not edit.
9970
- export const mdxComponents = {};
9971
- export const layoutOverrides = {};
10091
+ import type { ComponentOverride } from "blume/core/define-components.ts";
10092
+ export const mdxComponents: Record<string, ComponentOverride> = {};
10093
+ export const layoutOverrides: Record<string, ComponentOverride> = {};
9972
10094
  `;
9973
10095
  var attributeValue = (value) => value.replaceAll(/["\n\r]/gu, " ").trim();
9974
10096
  var CLIENT_LOAD = "client:load";
@@ -10066,12 +10188,12 @@ export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.leng
10066
10188
 
10067
10189
  // src/astro/examples.ts
10068
10190
  import { readFile as readFile10 } from "node:fs/promises";
10069
- import { join as join21, relative as relative7 } from "pathe";
10191
+ import { join as join22, relative as relative7 } from "pathe";
10070
10192
  import { glob as glob4 } from "tinyglobby";
10071
10193
 
10072
10194
  // src/astro/islands.ts
10073
10195
  import { readFile as readFile9 } from "node:fs/promises";
10074
- import { basename, join as join20 } from "pathe";
10196
+ import { basename, join as join21 } from "pathe";
10075
10197
  import { glob as glob3 } from "tinyglobby";
10076
10198
  var DEFAULT_CLIENT = "visible";
10077
10199
  var VALID_MODES = new Set([
@@ -10100,7 +10222,7 @@ var readClientMode = (source, file, warnings) => {
10100
10222
  return mode;
10101
10223
  };
10102
10224
  var discoverIslands = async (root) => {
10103
- const dir = join20(root, "islands");
10225
+ const dir = join21(root, "islands");
10104
10226
  const matches = await glob3(["**/*.{jsx,svelte,tsx,vue}"], {
10105
10227
  absolute: true,
10106
10228
  cwd: dir,
@@ -10163,7 +10285,7 @@ var splitGlobBase = (pattern) => {
10163
10285
  };
10164
10286
  var discoverExamples = async (root, pattern = "examples") => {
10165
10287
  const { base, rest } = GLOB_MAGIC.test(pattern) ? splitGlobBase(pattern) : { base: pattern, rest: DEFAULT_EXAMPLE_GLOB };
10166
- const dir = join21(root, base);
10288
+ const dir = join22(root, base);
10167
10289
  const matches = await glob4([rest], {
10168
10290
  absolute: true,
10169
10291
  cwd: dir,
@@ -10203,10 +10325,10 @@ var discoverExamples = async (root, pattern = "examples") => {
10203
10325
  };
10204
10326
 
10205
10327
  // src/astro/generate.ts
10206
- var BLUME_SRC = join22(packageRoot(), "src");
10328
+ var BLUME_SRC = join23(packageRoot(), "src");
10207
10329
  var canResolveFrom = (fromDir, spec) => {
10208
10330
  try {
10209
- createRequire5(pathToFileURL3(join22(fromDir, "_.js")).href).resolve(spec);
10331
+ createRequire5(pathToFileURL3(join23(fromDir, "_.js")).href).resolve(spec);
10210
10332
  return true;
10211
10333
  } catch {
10212
10334
  return false;
@@ -10217,7 +10339,7 @@ var resolveReactCompiler = (config, needsReact) => {
10217
10339
  return null;
10218
10340
  }
10219
10341
  try {
10220
- return createRequire5(pathToFileURL3(join22(packageRoot(), "_.js")).href).resolve("babel-plugin-react-compiler");
10342
+ return createRequire5(pathToFileURL3(join23(packageRoot(), "_.js")).href).resolve("babel-plugin-react-compiler");
10221
10343
  } catch {
10222
10344
  return null;
10223
10345
  }
@@ -10227,15 +10349,15 @@ var reactCompilerWarnings = (config, needsReact, compilerPath) => needsReact &&
10227
10349
  ] : [];
10228
10350
  var resolvedAstroPath = (fromDir) => {
10229
10351
  try {
10230
- const pkg = createRequire5(pathToFileURL3(join22(fromDir, "_.js")).href).resolve("astro/package.json");
10352
+ const pkg = createRequire5(pathToFileURL3(join23(fromDir, "_.js")).href).resolve("astro/package.json");
10231
10353
  return realpathSync(pkg);
10232
10354
  } catch {
10233
10355
  return null;
10234
10356
  }
10235
10357
  };
10236
10358
  var blumeDepsDir = (pkgDir = packageRoot()) => {
10237
- const candidates = [join22(pkgDir, "node_modules"), dirname8(pkgDir)];
10238
- return candidates.find((dir) => existsSync12(join22(dir, "astro"))) ?? null;
10359
+ const candidates = [join23(pkgDir, "node_modules"), dirname8(pkgDir)];
10360
+ return candidates.find((dir) => existsSync13(join23(dir, "astro"))) ?? null;
10239
10361
  };
10240
10362
  var linkDepsJunction = async (link, depsDir) => {
10241
10363
  let existing;
@@ -10258,7 +10380,7 @@ var readPkgVersion = (pkgJsonPath) => {
10258
10380
  return null;
10259
10381
  }
10260
10382
  try {
10261
- return JSON.parse(readFileSync7(pkgJsonPath, "utf-8")).version ?? null;
10383
+ return JSON.parse(readFileSync8(pkgJsonPath, "utf-8")).version ?? null;
10262
10384
  } catch {
10263
10385
  return null;
10264
10386
  }
@@ -10280,8 +10402,8 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
10280
10402
  if (blumeAstro && outDirAstro === blumeAstro) {
10281
10403
  return null;
10282
10404
  }
10283
- if (existsSync12(join22(depsDir, "@astrojs", "mdx"))) {
10284
- await linkDepsJunction(join22(outDir, "node_modules"), depsDir);
10405
+ if (existsSync13(join23(depsDir, "@astrojs", "mdx"))) {
10406
+ await linkDepsJunction(join23(outDir, "node_modules"), depsDir);
10285
10407
  return null;
10286
10408
  }
10287
10409
  return astroConflictWarning(blumeAstro, outDirAstro);
@@ -10313,14 +10435,14 @@ var deploymentAdapterWarnings = (deployment, root) => {
10313
10435
  }
10314
10436
  return [];
10315
10437
  };
10316
- var examplesCssFile = (root, config) => config.examples.css ? join22(root, config.examples.css) : null;
10438
+ var examplesCssFile = (root, config) => config.examples.css ? join23(root, config.examples.css) : null;
10317
10439
  var writeExamplesPreview = async (options) => {
10318
10440
  const { config, hasExamples, root, srcDir, write } = options;
10319
10441
  if (hasExamples) {
10320
- await write(join22(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
10442
+ await write(join23(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
10321
10443
  }
10322
10444
  const cssFile = examplesCssFile(root, config);
10323
- return cssFile && !existsSync12(cssFile) ? [
10445
+ return cssFile && !existsSync13(cssFile) ? [
10324
10446
  `examples.css points at "${config.examples.css}", which doesn't exist; previews render without it.`
10325
10447
  ] : [];
10326
10448
  };
@@ -10349,7 +10471,7 @@ var detectUsesMath = async (root, staged = []) => {
10349
10471
  ignore: ["**/node_modules/**", "**/.blume/**", "**/dist/**"],
10350
10472
  onlyFiles: true
10351
10473
  });
10352
- const contents = await Promise.all(files.map((file) => readOptional(join22(root, file))));
10474
+ const contents = await Promise.all(files.map((file) => readOptional(join23(root, file))));
10353
10475
  return [...contents, ...staged].some(containsMath);
10354
10476
  };
10355
10477
  var writeIfChanged = async (path, content) => {
@@ -10401,14 +10523,46 @@ var writeStagedContent = async (out, staged) => {
10401
10523
  const contentDir = stagedContentDir(out);
10402
10524
  const written = new Set;
10403
10525
  await Promise.all([...staged].map(async ([entryId, text]) => {
10404
- const path = join22(contentDir, entryId);
10526
+ const path = join23(contentDir, entryId);
10405
10527
  written.add(normalize3(path));
10406
10528
  await writeIfChanged(path, text);
10407
10529
  }));
10408
- if (existsSync12(contentDir)) {
10530
+ if (existsSync13(contentDir)) {
10409
10531
  await pruneOrphans(contentDir, written);
10410
10532
  }
10411
10533
  };
10534
+ var SVG_ROOT = /<svg\b(?<attributes>[^>]*)>/u;
10535
+ var SVG_WIDTH = /\bwidth\s*=\s*["'](?<value>[^"']+)["']/u;
10536
+ var SVG_HEIGHT = /\bheight\s*=\s*["'](?<value>[^"']+)["']/u;
10537
+ var SVG_LENGTH = /^\s*(?<value>[\d.]+)(?:px)?\s*$/u;
10538
+ var SVG_VIEW_BOX = /\bviewBox\s*=\s*["'][\d.-]+[\s,]+[\d.-]+[\s,]+(?<width>[\d.]+)[\s,]+(?<height>[\d.]+)["']/u;
10539
+ var parseSvgLength = (value) => {
10540
+ const length = Number(value?.match(SVG_LENGTH)?.groups?.value);
10541
+ return length > 0 ? length : undefined;
10542
+ };
10543
+ var svgDimensions = (svg) => {
10544
+ const attributes = svg?.match(SVG_ROOT)?.groups?.attributes;
10545
+ const width = parseSvgLength(attributes?.match(SVG_WIDTH)?.groups?.value);
10546
+ const height = parseSvgLength(attributes?.match(SVG_HEIGHT)?.groups?.value);
10547
+ if (width && height) {
10548
+ return { height, width };
10549
+ }
10550
+ const viewBox = attributes?.match(SVG_VIEW_BOX);
10551
+ const viewBoxWidth = Number(viewBox?.groups?.width);
10552
+ const viewBoxHeight = Number(viewBox?.groups?.height);
10553
+ return viewBoxWidth > 0 && viewBoxHeight > 0 ? { height: viewBoxHeight, width: viewBoxWidth } : undefined;
10554
+ };
10555
+ var readLogoSvg = (project, source) => {
10556
+ if (!source?.toLowerCase().endsWith(".svg")) {
10557
+ return;
10558
+ }
10559
+ const rel = source.replace(/^\//u, "");
10560
+ const file = [
10561
+ join23(project.context.root, "public", rel),
10562
+ join23(project.context.root, rel)
10563
+ ].find((path) => existsSync13(path));
10564
+ return file ? readFileSync8(file, "utf-8") : undefined;
10565
+ };
10412
10566
  var resolveLogo = (project) => {
10413
10567
  const { logo } = project.config;
10414
10568
  if (!logo) {
@@ -10421,17 +10575,15 @@ var resolveLogo = (project) => {
10421
10575
  const dark = image?.dark ?? image?.light;
10422
10576
  const alt = image?.alt ?? "";
10423
10577
  const brandHref = href ?? "/";
10424
- if (light && light === dark && light.toLowerCase().endsWith(".svg")) {
10425
- const rel = light.replace(/^\//u, "");
10426
- const file = [
10427
- join22(project.context.root, "public", rel),
10428
- join22(project.context.root, rel)
10429
- ].find((path) => existsSync12(path));
10430
- if (file) {
10431
- return { alt, href: brandHref, svg: readFileSync7(file, "utf-8"), text };
10432
- }
10578
+ const lightSvg = readLogoSvg(project, light);
10579
+ const darkSvg = dark === light ? lightSvg : readLogoSvg(project, dark);
10580
+ if (light && light === dark && lightSvg) {
10581
+ return { alt, href: brandHref, svg: lightSvg, text };
10433
10582
  }
10434
- return { alt, dark, href: brandHref, light, text };
10583
+ const lightDimensions = svgDimensions(lightSvg);
10584
+ const darkDimensions = svgDimensions(darkSvg);
10585
+ const dimensions = lightDimensions || darkDimensions ? { dark: darkDimensions, light: lightDimensions } : undefined;
10586
+ return { alt, dark, dimensions, href: brandHref, light, text };
10435
10587
  };
10436
10588
  var FAVICON_CANDIDATES = [
10437
10589
  "icon.svg",
@@ -10452,9 +10604,9 @@ var faviconType = (name) => {
10452
10604
  const ext = name.split(".").pop()?.toLowerCase();
10453
10605
  return ext ? FAVICON_TYPES[ext] : undefined;
10454
10606
  };
10455
- var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync7(file).toString("base64")}`;
10607
+ var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync8(file).toString("base64")}`;
10456
10608
  var defaultFavicon = () => ({
10457
- href: inlineDataUri(join22(BLUME_SRC, "assets", "icon.png"), "image/png"),
10609
+ href: inlineDataUri(join23(BLUME_SRC, "assets", "icon.png"), "image/png"),
10458
10610
  type: "image/png"
10459
10611
  });
10460
10612
  var APPLE_ICON_CANDIDATES = [
@@ -10466,13 +10618,13 @@ var APPLE_ICON_CANDIDATES = [
10466
10618
  var resolveIconFile = (project, candidates) => {
10467
10619
  const { root } = project.context;
10468
10620
  for (const name of candidates) {
10469
- if (existsSync12(join22(root, "public", name))) {
10621
+ if (existsSync13(join23(root, "public", name))) {
10470
10622
  return { href: `/${name}`, type: faviconType(name) };
10471
10623
  }
10472
10624
  }
10473
10625
  for (const name of candidates) {
10474
- const file = join22(root, name);
10475
- if (existsSync12(file)) {
10626
+ const file = join23(root, name);
10627
+ if (existsSync13(file)) {
10476
10628
  const type = faviconType(name);
10477
10629
  return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
10478
10630
  }
@@ -10501,6 +10653,8 @@ var buildRuntimeData = (project) => {
10501
10653
  const { github } = config;
10502
10654
  const repoUrl = github ? `https://github.com/${github.owner}/${github.repo}` : null;
10503
10655
  const editBase = github ? `${repoUrl}/edit/${github.branch}` : null;
10656
+ const logo = resolveLogo(project);
10657
+ const ogLogo = config.seo.og.logo ? resolveOgLogo(project, config.seo.og.logo) : logo?.svg;
10504
10658
  const editUrlFor = (sourcePath) => {
10505
10659
  if (!(editBase && sourcePath)) {
10506
10660
  return null;
@@ -10510,10 +10664,9 @@ var buildRuntimeData = (project) => {
10510
10664
  return `${editBase}/${editPath}`;
10511
10665
  };
10512
10666
  const { i18n } = config;
10513
- const withReferenceTabs = (nav) => ({
10667
+ const withRepoUrl = (nav) => ({
10514
10668
  ...nav,
10515
- repoUrl: config.navigation.repo && repoUrl ? repoUrl : null,
10516
- tabs: [...nav.tabs, ...referenceTabs(config)]
10669
+ repoUrl: config.navigation.repo && repoUrl ? repoUrl : null
10517
10670
  });
10518
10671
  const uiByLocale = i18n ? Object.fromEntries(i18n.locales.map(({ code }) => [
10519
10672
  code,
@@ -10528,7 +10681,7 @@ var buildRuntimeData = (project) => {
10528
10681
  }) : EN_UI;
10529
10682
  const navigationByLocale = i18n ? Object.fromEntries(i18n.locales.map(({ code }) => [
10530
10683
  code,
10531
- withReferenceTabs(graph.navigationByLocale[code] ?? {
10684
+ withRepoUrl(graph.navigationByLocale[code] ?? {
10532
10685
  featured: [],
10533
10686
  selectors: [],
10534
10687
  sidebar: [],
@@ -10558,12 +10711,16 @@ var buildRuntimeData = (project) => {
10558
10711
  }))
10559
10712
  } : null,
10560
10713
  imageZoom: config.markdown.imageZoom,
10561
- logo: resolveLogo(project),
10714
+ logo,
10562
10715
  mcp: config.ai.mcp.enabled ? {
10563
10716
  name: config.ai.mcp.name ?? config.title,
10564
10717
  route: config.ai.mcp.route
10565
10718
  } : null,
10566
- og: { enabled: config.seo.og.enabled ?? false },
10719
+ og: {
10720
+ enabled: config.seo.og.enabled ?? false,
10721
+ logo: ogLogo,
10722
+ palette: config.seo.og.palette
10723
+ },
10567
10724
  repoUrl,
10568
10725
  search: {
10569
10726
  enabled: config.search.provider !== "none",
@@ -10581,7 +10738,7 @@ var buildRuntimeData = (project) => {
10581
10738
  title: feed.title
10582
10739
  })),
10583
10740
  fontCssVars: configuredCssVars(config.theme.fonts),
10584
- navigation: withReferenceTabs(graph.navigation),
10741
+ navigation: withRepoUrl(graph.navigation),
10585
10742
  navigationByLocale,
10586
10743
  routes: manifest.routes.map((route) => ({
10587
10744
  alternates: route.alternates,
@@ -10607,7 +10764,7 @@ var buildRuntimeData = (project) => {
10607
10764
  var planMcp = (project, srcDir, userPages) => {
10608
10765
  const { config } = project;
10609
10766
  const { route } = config.ai.mcp;
10610
- const dir = join22(srcDir, "blume-mcp");
10767
+ const dir = join23(srcDir, "blume-mcp");
10611
10768
  const base = {
10612
10769
  dir,
10613
10770
  discoveryPages: [],
@@ -10631,11 +10788,11 @@ var planMcp = (project, srcDir, userPages) => {
10631
10788
  ...base,
10632
10789
  discoveryPages: [
10633
10790
  {
10634
- entrypoint: join22(dir, "discovery.ts"),
10791
+ entrypoint: join23(dir, "discovery.ts"),
10635
10792
  pattern: "/.well-known/mcp.json"
10636
10793
  },
10637
10794
  {
10638
- entrypoint: join22(dir, "server-card.ts"),
10795
+ entrypoint: join23(dir, "server-card.ts"),
10639
10796
  pattern: "/.well-known/mcp/server-card.json"
10640
10797
  }
10641
10798
  ],
@@ -10655,11 +10812,11 @@ var writeMcpFiles = async (project, plan, write) => {
10655
10812
  version: data.version
10656
10813
  };
10657
10814
  await Promise.all([
10658
- write(join22(plan.srcDir, "generated", "mcp-data.json"), `${JSON.stringify(data)}
10815
+ write(join23(plan.srcDir, "generated", "mcp-data.json"), `${JSON.stringify(data)}
10659
10816
  `),
10660
- write(join22(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate(plan.route)),
10661
- write(join22(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
10662
- write(join22(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
10817
+ write(join23(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate(plan.route)),
10818
+ write(join23(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
10819
+ write(join23(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
10663
10820
  ]);
10664
10821
  };
10665
10822
  var writeAskFiles = async (project, srcDir, write) => {
@@ -10669,16 +10826,16 @@ var writeAskFiles = async (project, srcDir, write) => {
10669
10826
  }
10670
10827
  const grounded = ask.provider !== "inkeep";
10671
10828
  if (grounded) {
10672
- await write(join22(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
10829
+ await write(join23(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
10673
10830
  `);
10674
10831
  }
10675
- await write(join22(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded));
10832
+ await write(join23(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded));
10676
10833
  };
10677
10834
  var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
10678
10835
  if (routeIsTaken(pages, contentPages, "/404")) {
10679
10836
  return;
10680
10837
  }
10681
- await write(join22(srcDir, "pages", "404.astro"), notFoundPageTemplate());
10838
+ await write(join23(srcDir, "pages", "404.astro"), notFoundPageTemplate());
10682
10839
  };
10683
10840
  var buildComponentSlots = async (componentsFile) => {
10684
10841
  const analysis = componentsFile ? analyzeComponentOverrides(await readFile11(componentsFile, "utf-8"), componentsFile) : null;
@@ -10691,14 +10848,14 @@ var buildComponentSlots = async (componentsFile) => {
10691
10848
  var generateRuntime = async (project) => {
10692
10849
  const { context, config } = project;
10693
10850
  const out = context.outDir;
10694
- const srcDir = join22(out, "src");
10695
- const askPath = join22(srcDir, "generated", "Ask.astro");
10696
- const dataPath = join22(srcDir, "generated", "data.json");
10697
- const themePath = join22(srcDir, "generated", "app.css");
10698
- const searchClientPath = join22(srcDir, "generated", "search-client.ts");
10699
- const examplesPath = join22(srcDir, "generated", "examples.ts");
10700
- const examplesThemePath = join22(srcDir, "generated", "examples.css");
10701
- const openapiPath = join22(srcDir, "generated", "openapi.json");
10851
+ const srcDir = join23(out, "src");
10852
+ const askPath = join23(srcDir, "generated", "Ask.astro");
10853
+ const dataPath = join23(srcDir, "generated", "data.json");
10854
+ const themePath = join23(srcDir, "generated", "app.css");
10855
+ const searchClientPath = join23(srcDir, "generated", "search-client.ts");
10856
+ const examplesPath = join23(srcDir, "generated", "examples.ts");
10857
+ const examplesThemePath = join23(srcDir, "generated", "examples.css");
10858
+ const openapiPath = join23(srcDir, "generated", "openapi.json");
10702
10859
  const written = new Set;
10703
10860
  const write = (path, content) => {
10704
10861
  written.add(normalize3(path));
@@ -10749,7 +10906,7 @@ var generateRuntime = async (project) => {
10749
10906
  const hasFilesystemSource = project.sources.some((source) => !source.staged);
10750
10907
  const [structural] = await Promise.all([
10751
10908
  Promise.all([
10752
- write(join22(out, "astro.config.mjs"), astroConfigTemplate({
10909
+ write(join23(out, "astro.config.mjs"), astroConfigTemplate({
10753
10910
  aliases: resolveTsconfigAliases(context.root),
10754
10911
  askPath,
10755
10912
  config,
@@ -10767,26 +10924,26 @@ var generateRuntime = async (project) => {
10767
10924
  searchClientPath,
10768
10925
  themePath
10769
10926
  })),
10770
- write(join22(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
10771
- write(join22(out, "tsconfig.json"), runtimeTsconfigTemplate()),
10772
- write(join22(srcDir, "env.d.ts"), envTemplate()),
10773
- write(join22(srcDir, "content.config.ts"), contentConfigTemplate({
10927
+ write(join23(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
10928
+ write(join23(out, "tsconfig.json"), runtimeTsconfigTemplate()),
10929
+ write(join23(srcDir, "env.d.ts"), envTemplate()),
10930
+ write(join23(srcDir, "content.config.ts"), contentConfigTemplate({
10774
10931
  collection: resolveDocsCollection(config, context),
10775
10932
  config,
10776
10933
  context,
10777
10934
  filesystem: hasFilesystemSource,
10778
10935
  staged: hasStaged
10779
10936
  })),
10780
- write(join22(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
10937
+ write(join23(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
10781
10938
  exportEpub,
10782
10939
  exportPdf,
10783
10940
  mathEnabled: usesMath,
10784
10941
  needsReact
10785
10942
  })),
10786
10943
  write(askPath, askComponentTemplate(askEnabled)),
10787
- write(join22(srcDir, "generated", "components.ts"), slotPlan.module),
10788
- write(join22(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
10789
- write(join22(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
10944
+ write(join23(srcDir, "generated", "components.ts"), slotPlan.module),
10945
+ write(join23(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
10946
+ write(join23(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
10790
10947
  write(examplesThemePath, examplesEntryTemplate({
10791
10948
  configTokens: buildThemeCss(config.theme),
10792
10949
  sources: [`${context.root}/**/*.{astro,jsx,svelte,ts,tsx,vue}`],
@@ -10802,17 +10959,17 @@ var generateRuntime = async (project) => {
10802
10959
  userTheme
10803
10960
  }))
10804
10961
  ]),
10805
- Promise.all(islandDiscovery.islands.map((island) => write(join22(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island)))),
10806
- Promise.all(slotPlan.wrappers.map((wrapper) => write(join22(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
10807
- Promise.all(exampleDiscovery.examples.map((example) => write(join22(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
10962
+ Promise.all(islandDiscovery.islands.map((island) => write(join23(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island)))),
10963
+ Promise.all(slotPlan.wrappers.map((wrapper) => write(join23(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
10964
+ Promise.all(exampleDiscovery.examples.map((example) => write(join23(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
10808
10965
  writeAskFiles(project, srcDir, write),
10809
10966
  writeMcpFiles(project, mcp, write)
10810
10967
  ]);
10811
10968
  if (config.seo.og.enabled) {
10812
- await write(join22(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
10969
+ await write(join23(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
10813
10970
  }
10814
10971
  if (hasGeneratedChangelog(project, pages)) {
10815
- await write(join22(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
10972
+ await write(join23(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
10816
10973
  exportEpub,
10817
10974
  exportPdf,
10818
10975
  needsReact,
@@ -10832,27 +10989,27 @@ var generateRuntime = async (project) => {
10832
10989
  ]);
10833
10990
  if (servesStaticIndex(config.search.provider)) {
10834
10991
  const documents = await buildSearchDocuments(project);
10835
- await write(join22(srcDir, "generated", "search.json"), `${JSON.stringify(documents)}
10992
+ await write(join23(srcDir, "generated", "search.json"), `${JSON.stringify(documents)}
10836
10993
  `);
10837
- await write(join22(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
10994
+ await write(join23(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
10838
10995
  }
10839
10996
  if (config.search.provider === "mixedbread") {
10840
- await write(join22(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
10997
+ await write(join23(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
10841
10998
  }
10842
10999
  const rawMarkdown = await buildRawMarkdown(project);
10843
11000
  await Promise.all([
10844
- write(join22(srcDir, "generated", "raw-markdown.json"), `${JSON.stringify(rawMarkdown)}
11001
+ write(join23(srcDir, "generated", "raw-markdown.json"), `${JSON.stringify(rawMarkdown)}
10845
11002
  `),
10846
- write(join22(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
10847
- write(join22(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx"))
11003
+ write(join23(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
11004
+ write(join23(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx"))
10848
11005
  ]);
10849
11006
  const feeds = buildRssFeeds(project);
10850
11007
  if (feeds.length > 0) {
10851
11008
  const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
10852
11009
  await Promise.all([
10853
- write(join22(srcDir, "generated", "rss.json"), `${JSON.stringify(feedXml)}
11010
+ write(join23(srcDir, "generated", "rss.json"), `${JSON.stringify(feedXml)}
10854
11011
  `),
10855
- write(join22(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate())
11012
+ write(join23(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate())
10856
11013
  ]);
10857
11014
  }
10858
11015
  const warnings = [
@@ -10867,7 +11024,7 @@ var generateRuntime = async (project) => {
10867
11024
  const navTargetRoutes = new Set([
10868
11025
  ...project.graph.routes.keys(),
10869
11026
  ...pages.map((page) => page.pattern),
10870
- ...referenceTabs(config).map((tab) => tab.path)
11027
+ ...referenceRoutes(config)
10871
11028
  ]);
10872
11029
  if (hasGeneratedChangelog(project, pages)) {
10873
11030
  navTargetRoutes.add("/changelog");
@@ -10891,14 +11048,14 @@ var generateRuntime = async (project) => {
10891
11048
  root: context.root
10892
11049
  });
10893
11050
  warnings.push(...references.warnings);
10894
- await Promise.all(references.files.map((file) => write(join22(srcDir, "pages", file.pagePath), file.content)));
11051
+ await Promise.all(references.files.map((file) => write(join23(srcDir, "pages", file.pagePath), file.content)));
10895
11052
  }
10896
11053
  const openApiSource2 = project.sources.find(isOpenApiSource);
10897
11054
  await Promise.all([
10898
- write(join22(srcDir, "generated", "data.json"), buildRuntimeData(project)),
11055
+ write(join23(srcDir, "generated", "data.json"), buildRuntimeData(project)),
10899
11056
  write(openapiPath, `${JSON.stringify(openApiSource2 ? openApiSource2.openApiData() : {})}
10900
11057
  `),
10901
- write(join22(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
11058
+ write(join23(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
10902
11059
  `),
10903
11060
  writeStagedContent(out, staged)
10904
11061
  ]);
@@ -10910,7 +11067,7 @@ var generateRuntime = async (project) => {
10910
11067
  import { relative as relative11 } from "pathe";
10911
11068
 
10912
11069
  // src/core/config.ts
10913
- import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
11070
+ import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
10914
11071
 
10915
11072
  // src/core/deployment-env.ts
10916
11073
  var toUrl = (value) => {
@@ -10980,7 +11137,7 @@ var loadConfig = async (root, options = {}) => {
10980
11137
  }
10981
11138
  const parsed = blumeConfigSchema.safeParse(raw ?? {});
10982
11139
  if (!parsed.success) {
10983
- const source = configFile && existsSync13(configFile) ? readFileSync8(configFile, "utf-8") : undefined;
11140
+ const source = configFile && existsSync14(configFile) ? readFileSync9(configFile, "utf-8") : undefined;
10984
11141
  const diagnostics = diagnosticsFromZod(parsed.error, {
10985
11142
  code: "BLUME_CONFIG_INVALID",
10986
11143
  file: configFile ?? undefined,
@@ -11275,6 +11432,29 @@ var buildConfigSidebar = (items, byRoute, display, basePath) => {
11275
11432
  }
11276
11433
  return nodes;
11277
11434
  };
11435
+ var resolveTabHref = (sidebar, path) => {
11436
+ let first;
11437
+ const walk = (nodes) => {
11438
+ for (const node of nodes) {
11439
+ const { route } = node;
11440
+ if (route === path) {
11441
+ return true;
11442
+ }
11443
+ if (first === undefined && route !== undefined && route.startsWith(`${path}/`)) {
11444
+ first = route;
11445
+ }
11446
+ if (node.kind === "group" && walk(node.children)) {
11447
+ return true;
11448
+ }
11449
+ }
11450
+ return false;
11451
+ };
11452
+ return walk(sidebar) ? path : first ?? path;
11453
+ };
11454
+ var withTabHrefs = (tabs2, sidebar) => tabs2.map((tab) => {
11455
+ const href = resolveTabHref(sidebar, tab.path);
11456
+ return href === tab.path ? tab : { ...tab, href };
11457
+ });
11278
11458
  var buildNavigation = (pages, options) => {
11279
11459
  const basePath = options.basePath ?? "";
11280
11460
  const display = options.display ?? "flat";
@@ -11310,19 +11490,21 @@ var buildNavigation = (pages, options) => {
11310
11490
  }
11311
11491
  }
11312
11492
  if (options.sidebar) {
11493
+ const sidebar2 = buildConfigSidebar(options.sidebar, byRoute, display, basePath);
11313
11494
  return {
11314
11495
  featured,
11315
11496
  selectors,
11316
- sidebar: buildConfigSidebar(options.sidebar, byRoute, display, basePath),
11317
- tabs: tabs2
11497
+ sidebar: sidebar2,
11498
+ tabs: withTabHrefs(tabs2, sidebar2)
11318
11499
  };
11319
11500
  }
11320
11501
  const rootTabPath = withBasePath(basePath, options.localizedRoot ?? "/");
11502
+ const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display, new Set(tabs2.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path])));
11321
11503
  return {
11322
11504
  featured,
11323
11505
  selectors,
11324
- sidebar: buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display, new Set(tabs2.flatMap((tab) => tab.path === rootTabPath ? [] : [tab.path]))),
11325
- tabs: tabs2
11506
+ sidebar,
11507
+ tabs: withTabHrefs(tabs2, sidebar)
11326
11508
  };
11327
11509
  };
11328
11510
 
@@ -11691,8 +11873,8 @@ var scanProject = async (root, options = {}) => {
11691
11873
  };
11692
11874
 
11693
11875
  // src/cli/env.ts
11694
- import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
11695
- import { dirname as dirname10, join as join23, resolve as resolve7 } from "pathe";
11876
+ import { existsSync as existsSync15, readFileSync as readFileSync10 } from "node:fs";
11877
+ import { dirname as dirname10, join as join24, resolve as resolve7 } from "pathe";
11696
11878
  var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
11697
11879
  var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
11698
11880
  var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
@@ -11738,8 +11920,8 @@ var applyEnv = (parsed) => {
11738
11920
  };
11739
11921
  var loadFile = (path) => {
11740
11922
  try {
11741
- if (existsSync14(path)) {
11742
- applyEnv(parseEnv(readFileSync9(path, "utf-8")));
11923
+ if (existsSync15(path)) {
11924
+ applyEnv(parseEnv(readFileSync10(path, "utf-8")));
11743
11925
  }
11744
11926
  } catch {}
11745
11927
  };
@@ -11747,10 +11929,10 @@ var loadEnvFiles = (startDir) => {
11747
11929
  let dir = resolve7(startDir);
11748
11930
  let done = false;
11749
11931
  while (!done) {
11750
- loadFile(join23(dir, ".env.local"));
11751
- loadFile(join23(dir, ".env"));
11932
+ loadFile(join24(dir, ".env.local"));
11933
+ loadFile(join24(dir, ".env"));
11752
11934
  const parent = dirname10(dir);
11753
- done = existsSync14(join23(dir, ".git")) || parent === dir;
11935
+ done = existsSync15(join24(dir, ".git")) || parent === dir;
11754
11936
  dir = parent;
11755
11937
  }
11756
11938
  };
@@ -11885,12 +12067,12 @@ var emitRedirectFiles = async (config, distDir) => {
11885
12067
  if (redirects.length === 0 || config.deployment.output !== "static") {
11886
12068
  return;
11887
12069
  }
11888
- await writeFile7(join24(distDir, "blume-redirects.json"), buildRedirectManifest(redirects), "utf-8");
12070
+ await writeFile7(join25(distDir, "blume-redirects.json"), buildRedirectManifest(redirects), "utf-8");
11889
12071
  const platformFiles = [
11890
12072
  { content: buildNetlifyRedirects(redirects), name: "_redirects" },
11891
12073
  { content: buildVercelConfig(redirects), name: "vercel.json" }
11892
12074
  ];
11893
- await Promise.all(platformFiles.map((file) => existsSync15(join24(distDir, file.name)) ? Promise.resolve() : writeFile7(join24(distDir, file.name), file.content, "utf-8")));
12075
+ await Promise.all(platformFiles.map((file) => existsSync16(join25(distDir, file.name)) ? Promise.resolve() : writeFile7(join25(distDir, file.name), file.content, "utf-8")));
11894
12076
  logger.success(`Emitted redirect files for ${redirects.length} redirect(s)`);
11895
12077
  };
11896
12078
  var formatBytes = (bytes) => {
@@ -11901,14 +12083,14 @@ var formatBytes = (bytes) => {
11901
12083
  return `${(bytes / 1024).toFixed(digits)} kB`;
11902
12084
  };
11903
12085
  var astroAssets = async (distDir, ext) => {
11904
- const astroDir = join24(distDir, "_astro");
11905
- if (!existsSync15(astroDir)) {
12086
+ const astroDir = join25(distDir, "_astro");
12087
+ if (!existsSync16(astroDir)) {
11906
12088
  return [];
11907
12089
  }
11908
12090
  const entries = await readdir(astroDir);
11909
12091
  const files = entries.filter((name) => name.endsWith(`.${ext}`));
11910
12092
  const sized = await Promise.all(files.map(async (name) => {
11911
- const info = await stat(join24(astroDir, name));
12093
+ const info = await stat(join25(astroDir, name));
11912
12094
  return { name, size: info.size };
11913
12095
  }));
11914
12096
  return sized.toSorted((a, b) => b.size - a.size);
@@ -11961,26 +12143,26 @@ var runClientAssetChecks = async (staticDir, args) => {
11961
12143
  var isolatedOutputDir = (config, context) => {
11962
12144
  const { adapter, output } = config.deployment;
11963
12145
  if (output === "server" && adapter === "vercel") {
11964
- return join24(context.outDir, ".vercel", "output");
12146
+ return join25(context.outDir, ".vercel", "output");
11965
12147
  }
11966
- return context.distDir ?? join24(context.outDir, "dist");
12148
+ return context.distDir ?? join25(context.outDir, "dist");
11967
12149
  };
11968
12150
  var isolatedStaticDir = (config, context) => {
11969
12151
  const { adapter, output } = config.deployment;
11970
12152
  const outputDir = isolatedOutputDir(config, context);
11971
12153
  if (output === "server" && adapter === "vercel") {
11972
- return join24(outputDir, "static");
12154
+ return join25(outputDir, "static");
11973
12155
  }
11974
12156
  if (output === "server" && adapter === "node") {
11975
- return join24(outputDir, "client");
12157
+ return join25(outputDir, "client");
11976
12158
  }
11977
12159
  return outputDir;
11978
12160
  };
11979
12161
  var publishLlmsFiles = async (project, distDir) => {
11980
- const indexPath = join24(distDir, "llms.txt");
11981
- const fullPath = join24(distDir, "llms-full.txt");
11982
- const writeIndex = !existsSync15(indexPath);
11983
- const writeFull = !existsSync15(fullPath);
12162
+ const indexPath = join25(distDir, "llms.txt");
12163
+ const fullPath = join25(distDir, "llms-full.txt");
12164
+ const writeIndex = !existsSync16(indexPath);
12165
+ const writeFull = !existsSync16(fullPath);
11984
12166
  if (!(writeIndex || writeFull)) {
11985
12167
  return;
11986
12168
  }
@@ -12013,18 +12195,18 @@ var publishBuildArtifacts = async (project, distDir, args) => {
12013
12195
  await publishLlmsFiles(project, distDir);
12014
12196
  }
12015
12197
  const sitemap = buildSitemap(project);
12016
- if (sitemap && !existsSync15(join24(distDir, "sitemap.xml"))) {
12017
- await writeFile7(join24(distDir, "sitemap.xml"), sitemap, "utf-8");
12198
+ if (sitemap && !existsSync16(join25(distDir, "sitemap.xml"))) {
12199
+ await writeFile7(join25(distDir, "sitemap.xml"), sitemap, "utf-8");
12018
12200
  logger.success("Generated sitemap.xml");
12019
12201
  }
12020
12202
  const robots = buildRobots(project);
12021
- if (robots && !existsSync15(join24(distDir, "robots.txt"))) {
12022
- await writeFile7(join24(distDir, "robots.txt"), robots, "utf-8");
12203
+ if (robots && !existsSync16(join25(distDir, "robots.txt"))) {
12204
+ await writeFile7(join25(distDir, "robots.txt"), robots, "utf-8");
12023
12205
  logger.success("Generated robots.txt");
12024
12206
  }
12025
12207
  const agentReadability = buildAgentReadability(project);
12026
- if (agentReadability && !existsSync15(join24(distDir, "agent-readability.json"))) {
12027
- await writeFile7(join24(distDir, "agent-readability.json"), `${JSON.stringify(agentReadability, null, 2)}
12208
+ if (agentReadability && !existsSync16(join25(distDir, "agent-readability.json"))) {
12209
+ await writeFile7(join25(distDir, "agent-readability.json"), `${JSON.stringify(agentReadability, null, 2)}
12028
12210
  `, "utf-8");
12029
12211
  logger.success("Generated agent-readability.json");
12030
12212
  }
@@ -12136,11 +12318,11 @@ var buildCommand = defineCommand2({
12136
12318
  });
12137
12319
 
12138
12320
  // src/cli/commands/check.ts
12139
- import { existsSync as existsSync16 } from "node:fs";
12321
+ import { existsSync as existsSync17 } from "node:fs";
12140
12322
  import { check } from "@astrojs/check";
12141
12323
  import { sync } from "astro";
12142
12324
  import { defineCommand as defineCommand3 } from "citty";
12143
- import { join as join25 } from "pathe";
12325
+ import { join as join26 } from "pathe";
12144
12326
  var checkCommand = defineCommand3({
12145
12327
  args: {
12146
12328
  isolated: {
@@ -12176,13 +12358,13 @@ var checkCommand = defineCommand3({
12176
12358
  });
12177
12359
  const { outDir } = project.context;
12178
12360
  await sync({ logLevel: "warn", root: outDir });
12179
- const tsconfig = join25(root, "tsconfig.json");
12361
+ const tsconfig = join26(root, "tsconfig.json");
12180
12362
  logger.start(`Type-checking ${project.graph.pages.length} page(s)`);
12181
12363
  const failed = await check({
12182
12364
  minimumFailingSeverity: "error",
12183
12365
  minimumSeverity: "hint",
12184
12366
  root: outDir,
12185
- tsconfig: existsSync16(tsconfig) ? tsconfig : undefined,
12367
+ tsconfig: existsSync17(tsconfig) ? tsconfig : undefined,
12186
12368
  watch: false
12187
12369
  });
12188
12370
  if (failed) {
@@ -12402,14 +12584,14 @@ var devCommand = defineCommand4({
12402
12584
  });
12403
12585
 
12404
12586
  // src/cli/commands/doctor.ts
12405
- import { readFileSync as readFileSync10 } from "node:fs";
12587
+ import { readFileSync as readFileSync11 } from "node:fs";
12406
12588
  import { defineCommand as defineCommand5 } from "citty";
12407
- import { join as join26 } from "pathe";
12589
+ import { join as join27 } from "pathe";
12408
12590
  var FALLBACK_MIN_NODE = "22.12.0";
12409
12591
  var LEADING_RANGE = /^[^\d]*/u;
12410
12592
  var minSupportedNode = () => {
12411
12593
  try {
12412
- const pkg = JSON.parse(readFileSync10(join26(packageRoot(), "package.json"), "utf-8"));
12594
+ const pkg = JSON.parse(readFileSync11(join27(packageRoot(), "package.json"), "utf-8"));
12413
12595
  const range = pkg.engines?.node ?? "";
12414
12596
  return range.replace(LEADING_RANGE, "") || FALLBACK_MIN_NODE;
12415
12597
  } catch {
@@ -12505,17 +12687,17 @@ import { defineCommand as defineCommand6 } from "citty";
12505
12687
  import { relative as relative14 } from "pathe";
12506
12688
 
12507
12689
  // src/registry/eject.ts
12508
- import { existsSync as existsSync17 } from "node:fs";
12690
+ import { existsSync as existsSync18 } from "node:fs";
12509
12691
  import { cp as cp2, mkdir as mkdir7, readFile as readFile12, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
12510
- import { join as join27, relative as relative12 } from "pathe";
12692
+ import { join as join28, relative as relative12 } from "pathe";
12511
12693
  var toPosix = (path) => path.split("\\").join("/");
12512
12694
  var LOCAL_BLUME_SOURCE = "../../node_modules/blume/src/**/*.{astro,ts,tsx}";
12513
12695
  var blumeSourceGlob = (root, genDir, resolveBlumeRoot = packageRoot) => {
12514
- if (existsSync17(join27(root, "node_modules", "blume"))) {
12696
+ if (existsSync18(join28(root, "node_modules", "blume"))) {
12515
12697
  return LOCAL_BLUME_SOURCE;
12516
12698
  }
12517
12699
  try {
12518
- const src = join27(resolveBlumeRoot(), "src");
12700
+ const src = join28(resolveBlumeRoot(), "src");
12519
12701
  return `${toPosix(relative12(genDir, src))}/**/*.{astro,ts,tsx}`;
12520
12702
  } catch {
12521
12703
  console.warn('blume: could not locate the installed blume package; src/generated/app.css keeps its default `@source "../../node_modules/blume/..."` glob. If blume is hoisted elsewhere, point that glob at its install location or Blume\'s utility classes will be missing.');
@@ -12535,14 +12717,14 @@ var askFiles = async (project, srcDir, genDir) => {
12535
12717
  const files = [
12536
12718
  {
12537
12719
  content: askEndpointTemplate(resolveAskBackend(ask), grounded),
12538
- path: join27(srcDir, "pages", "api", "ask.ts")
12720
+ path: join28(srcDir, "pages", "api", "ask.ts")
12539
12721
  }
12540
12722
  ];
12541
12723
  if (grounded) {
12542
12724
  files.push({
12543
12725
  content: `${JSON.stringify(await buildAskData(project))}
12544
12726
  `,
12545
- path: join27(genDir, "ask-data.json")
12727
+ path: join28(genDir, "ask-data.json")
12546
12728
  });
12547
12729
  }
12548
12730
  return files;
@@ -12575,19 +12757,19 @@ var mcpFiles = async (project, userPages, srcDir, genDir) => {
12575
12757
  {
12576
12758
  content: `${JSON.stringify(data)}
12577
12759
  `,
12578
- path: join27(genDir, "mcp-data.json")
12760
+ path: join28(genDir, "mcp-data.json")
12579
12761
  },
12580
12762
  {
12581
12763
  content: mcpEndpointTemplate(route),
12582
- path: join27(srcDir, "pages", mcpPageFile(route))
12764
+ path: join28(srcDir, "pages", mcpPageFile(route))
12583
12765
  },
12584
12766
  {
12585
12767
  content: staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput)),
12586
- path: join27(srcDir, "blume-mcp", "discovery.ts")
12768
+ path: join28(srcDir, "blume-mcp", "discovery.ts")
12587
12769
  },
12588
12770
  {
12589
12771
  content: staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)),
12590
- path: join27(srcDir, "blume-mcp", "server-card.ts")
12772
+ path: join28(srcDir, "blume-mcp", "server-card.ts")
12591
12773
  }
12592
12774
  ];
12593
12775
  };
@@ -12600,22 +12782,22 @@ var changelogFiles = (project, userPages, srcDir, options) => {
12600
12782
  return [
12601
12783
  {
12602
12784
  content: changelogIndexTemplate(options),
12603
- path: join27(srcDir, "pages", "changelog.astro")
12785
+ path: join28(srcDir, "pages", "changelog.astro")
12604
12786
  }
12605
12787
  ];
12606
12788
  };
12607
- var readExamplesCss = (root, css) => css && existsSync17(join27(root, css)) ? readFile12(join27(root, css), "utf-8") : Promise.resolve("");
12789
+ var readExamplesCss = (root, css) => css && existsSync18(join28(root, css)) ? readFile12(join28(root, css), "utf-8") : Promise.resolve("");
12608
12790
  var examplesPreviewFiles = (srcDir, basePath, hasExamples) => hasExamples ? [
12609
12791
  {
12610
12792
  content: examplesPageTemplate(),
12611
- path: join27(srcDir, "pages", ...basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro")
12793
+ path: join28(srcDir, "pages", ...basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro")
12612
12794
  }
12613
12795
  ] : [];
12614
12796
  var eject = async (root) => {
12615
12797
  const project = await scanProject(root, { mode: "build" });
12616
12798
  const { context, config } = project;
12617
- const srcDir = join27(root, "src");
12618
- const genDir = join27(srcDir, "generated");
12799
+ const srcDir = join28(root, "src");
12800
+ const genDir = join28(srcDir, "generated");
12619
12801
  const askEnabled = config.ai.ask?.enabled ?? false;
12620
12802
  const exportPdf = config.export.pdf;
12621
12803
  const exportEpub = config.export.epub;
@@ -12680,14 +12862,14 @@ var eject = async (root) => {
12680
12862
  searchClientPath: "./src/generated/search-client.ts",
12681
12863
  themePath: "./src/generated/app.css"
12682
12864
  }),
12683
- path: join27(root, "astro.config.mjs")
12865
+ path: join28(root, "astro.config.mjs")
12684
12866
  },
12685
12867
  {
12686
12868
  content: runtimeTsconfigTemplate(),
12687
- path: join27(root, "tsconfig.json"),
12869
+ path: join28(root, "tsconfig.json"),
12688
12870
  skipIfExists: true
12689
12871
  },
12690
- { content: envTemplate(), path: join27(srcDir, "env.d.ts") },
12872
+ { content: envTemplate(), path: join28(srcDir, "env.d.ts") },
12691
12873
  {
12692
12874
  content: contentConfigTemplate({
12693
12875
  config,
@@ -12695,7 +12877,7 @@ var eject = async (root) => {
12695
12877
  staged: hasStaged,
12696
12878
  stagedBase: stagedDir
12697
12879
  }),
12698
- path: join27(srcDir, "content.config.ts")
12880
+ path: join28(srcDir, "content.config.ts")
12699
12881
  },
12700
12882
  {
12701
12883
  content: catchAllPageTemplate({
@@ -12704,19 +12886,19 @@ var eject = async (root) => {
12704
12886
  mathEnabled: usesMath,
12705
12887
  needsReact
12706
12888
  }),
12707
- path: join27(srcDir, "pages", "[...slug].astro")
12889
+ path: join28(srcDir, "pages", "[...slug].astro")
12708
12890
  },
12709
12891
  {
12710
12892
  content: planComponentSlots(componentsImport, null).module,
12711
- path: join27(genDir, "components.ts")
12893
+ path: join28(genDir, "components.ts")
12712
12894
  },
12713
12895
  {
12714
12896
  content: islandMapTemplate(islands.islands),
12715
- path: join27(genDir, "islands.ts")
12897
+ path: join28(genDir, "islands.ts")
12716
12898
  },
12717
12899
  {
12718
12900
  content: exampleMapTemplate(examples.examples, config.basePath),
12719
- path: join27(genDir, "examples.ts")
12901
+ path: join28(genDir, "examples.ts")
12720
12902
  },
12721
12903
  {
12722
12904
  content: examplesEntryTemplate({
@@ -12724,7 +12906,7 @@ var eject = async (root) => {
12724
12906
  sources: ["../../**/*.{astro,jsx,svelte,ts,tsx,vue}"],
12725
12907
  userCss: userExamplesCss
12726
12908
  }),
12727
- path: join27(genDir, "examples.css")
12909
+ path: join28(genDir, "examples.css")
12728
12910
  },
12729
12911
  {
12730
12912
  content: tailwindEntryTemplate({
@@ -12736,30 +12918,30 @@ var eject = async (root) => {
12736
12918
  twoslashCss: twoslashCss(),
12737
12919
  userTheme
12738
12920
  }),
12739
- path: join27(genDir, "app.css")
12921
+ path: join28(genDir, "app.css")
12740
12922
  },
12741
- { content: buildRuntimeData(project), path: join27(genDir, "data.json") },
12923
+ { content: buildRuntimeData(project), path: join28(genDir, "data.json") },
12742
12924
  {
12743
12925
  content: askComponentTemplate(askEnabled),
12744
- path: join27(genDir, "Ask.astro")
12926
+ path: join28(genDir, "Ask.astro")
12745
12927
  },
12746
12928
  {
12747
12929
  content: `${JSON.stringify(ejectOpenApiData(project))}
12748
12930
  `,
12749
- path: join27(genDir, "openapi.json")
12931
+ path: join28(genDir, "openapi.json")
12750
12932
  },
12751
12933
  {
12752
12934
  content: `${JSON.stringify(rawMarkdown)}
12753
12935
  `,
12754
- path: join27(genDir, "raw-markdown.json")
12936
+ path: join28(genDir, "raw-markdown.json")
12755
12937
  },
12756
12938
  {
12757
12939
  content: rawMarkdownEndpointTemplate("md"),
12758
- path: join27(srcDir, "pages", "[...slug].md.ts")
12940
+ path: join28(srcDir, "pages", "[...slug].md.ts")
12759
12941
  },
12760
12942
  {
12761
12943
  content: rawMarkdownEndpointTemplate("mdx"),
12762
- path: join27(srcDir, "pages", "[...slug].mdx.ts")
12944
+ path: join28(srcDir, "pages", "[...slug].mdx.ts")
12763
12945
  }
12764
12946
  ];
12765
12947
  if (askEnabled) {
@@ -12768,7 +12950,7 @@ var eject = async (root) => {
12768
12950
  if (config.seo.og.enabled) {
12769
12951
  files.push({
12770
12952
  content: ogEndpointTemplate(customOgRoutes(pages, config.title)),
12771
- path: join27(srcDir, "pages", "og", "[...slug].png.ts")
12953
+ path: join28(srcDir, "pages", "og", "[...slug].png.ts")
12772
12954
  });
12773
12955
  }
12774
12956
  files.push(...await mcpFiles(project, pages, srcDir, genDir), ...changelogFiles(project, pages, srcDir, {
@@ -12780,28 +12962,28 @@ var eject = async (root) => {
12780
12962
  if (!routeIsTaken(pages, project.graph.pages, "/404")) {
12781
12963
  files.push({
12782
12964
  content: notFoundPageTemplate(),
12783
- path: join27(srcDir, "pages", "404.astro")
12965
+ path: join28(srcDir, "pages", "404.astro")
12784
12966
  });
12785
12967
  }
12786
12968
  files.push({
12787
12969
  content: searchClientTemplate(config),
12788
- path: join27(genDir, "search-client.ts")
12970
+ path: join28(genDir, "search-client.ts")
12789
12971
  });
12790
12972
  if (servesStaticIndex(config.search.provider)) {
12791
12973
  const documents = await buildSearchDocuments(project);
12792
12974
  files.push({
12793
12975
  content: `${JSON.stringify(documents)}
12794
12976
  `,
12795
- path: join27(genDir, "search.json")
12977
+ path: join28(genDir, "search.json")
12796
12978
  }, {
12797
12979
  content: searchEndpointTemplate(),
12798
- path: join27(srcDir, "pages", "blume-search.json.ts")
12980
+ path: join28(srcDir, "pages", "blume-search.json.ts")
12799
12981
  });
12800
12982
  }
12801
12983
  if (config.search.provider === "mixedbread") {
12802
12984
  files.push({
12803
12985
  content: mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""),
12804
- path: join27(srcDir, "pages", "api", "search.ts")
12986
+ path: join28(srcDir, "pages", "api", "search.ts")
12805
12987
  });
12806
12988
  }
12807
12989
  const feeds = buildRssFeeds(project);
@@ -12810,10 +12992,10 @@ var eject = async (root) => {
12810
12992
  files.push({
12811
12993
  content: `${JSON.stringify(feedXml)}
12812
12994
  `,
12813
- path: join27(genDir, "rss.json")
12995
+ path: join28(genDir, "rss.json")
12814
12996
  }, {
12815
12997
  content: rssEndpointTemplate(),
12816
- path: join27(srcDir, "pages", "[section]", "rss.xml.ts")
12998
+ path: join28(srcDir, "pages", "[section]", "rss.xml.ts")
12817
12999
  });
12818
13000
  }
12819
13001
  const warnings = [];
@@ -12827,28 +13009,28 @@ var eject = async (root) => {
12827
13009
  for (const file of references.files) {
12828
13010
  files.push({
12829
13011
  content: file.content,
12830
- path: join27(srcDir, "pages", file.pagePath)
13012
+ path: join28(srcDir, "pages", file.pagePath)
12831
13013
  });
12832
13014
  }
12833
13015
  }
12834
13016
  files.push(...islands.islands.map((island) => ({
12835
13017
  content: islandWrapperTemplate(island),
12836
- path: join27(genDir, "islands", `${island.name}.astro`)
13018
+ path: join28(genDir, "islands", `${island.name}.astro`)
12837
13019
  })), ...examples.examples.map((example) => ({
12838
13020
  content: exampleWrapperTemplate(example),
12839
- path: join27(genDir, "examples", `${exampleSlug(example.path)}.astro`)
13021
+ path: join28(genDir, "examples", `${exampleSlug(example.path)}.astro`)
12840
13022
  })), ...examplesPreviewFiles(srcDir, config.basePath, examples.examples.length > 0));
12841
13023
  for (const [entryId, content] of staged) {
12842
- files.push({ content, path: join27(root, stagedDir, entryId) });
13024
+ files.push({ content, path: join28(root, stagedDir, entryId) });
12843
13025
  }
12844
- const written = files.filter((file) => !(file.skipIfExists && existsSync17(file.path)));
13026
+ const written = files.filter((file) => !(file.skipIfExists && existsSync18(file.path)));
12845
13027
  await Promise.all(written.map(async (file) => {
12846
- await mkdir7(join27(file.path, ".."), { recursive: true });
13028
+ await mkdir7(join28(file.path, ".."), { recursive: true });
12847
13029
  await writeFile8(file.path, file.content, "utf-8");
12848
13030
  }));
12849
- const assetsSrc = join27(context.outDir, "public", "blume-assets");
12850
- if (existsSync17(assetsSrc)) {
12851
- await cp2(assetsSrc, join27(root, "public", "blume-assets"), {
13031
+ const assetsSrc = join28(context.outDir, "public", "blume-assets");
13032
+ if (existsSync18(assetsSrc)) {
13033
+ await cp2(assetsSrc, join28(root, "public", "blume-assets"), {
12852
13034
  recursive: true
12853
13035
  });
12854
13036
  }
@@ -12858,7 +13040,7 @@ var eject = async (root) => {
12858
13040
 
12859
13041
  // src/cli/eject-scripts.ts
12860
13042
  import { readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
12861
- import { join as join28 } from "pathe";
13043
+ import { join as join29 } from "pathe";
12862
13044
  var droppedArtifactNotices = (config) => {
12863
13045
  const notices = [];
12864
13046
  if (config.search.provider === "pagefind") {
@@ -12885,7 +13067,7 @@ var droppedArtifactNotices = (config) => {
12885
13067
  return notices;
12886
13068
  };
12887
13069
  var updatePackageScripts = async (root) => {
12888
- const pkgPath = join28(root, "package.json");
13070
+ const pkgPath = join29(root, "package.json");
12889
13071
  let pkg;
12890
13072
  try {
12891
13073
  pkg = JSON.parse(await readFile13(pkgPath, "utf-8"));
@@ -12904,9 +13086,9 @@ var updatePackageScripts = async (root) => {
12904
13086
  };
12905
13087
 
12906
13088
  // src/cli/init/scaffold.ts
12907
- import { existsSync as existsSync18 } from "node:fs";
13089
+ import { existsSync as existsSync19 } from "node:fs";
12908
13090
  import { mkdir as mkdir8, writeFile as writeFile10 } from "node:fs/promises";
12909
- import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute9, join as join29, relative as relative13 } from "pathe";
13091
+ import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute9, join as join30, relative as relative13 } from "pathe";
12910
13092
 
12911
13093
  // src/core/package-json.ts
12912
13094
  var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
@@ -12965,7 +13147,7 @@ var STARTERS = {
12965
13147
  files: (dir) => [
12966
13148
  {
12967
13149
  content: page("API Reference", "Explore the API.", "# API Reference\n\nYour OpenAPI spec renders at [`/api`](/api). Point `openapi.sources` at your own spec in `blume.config.ts`."),
12968
- path: join29(dir, "index.mdx")
13150
+ path: join30(dir, "index.mdx")
12969
13151
  }
12970
13152
  ]
12971
13153
  },
@@ -12980,7 +13162,7 @@ var STARTERS = {
12980
13162
  files: (dir) => [
12981
13163
  {
12982
13164
  content: page("Introduction", "Welcome to your new Blume docs.", "# Introduction\n\nWrite your docs here, and log releases under `changelog/`."),
12983
- path: join29(dir, "index.mdx")
13165
+ path: join30(dir, "index.mdx")
12984
13166
  },
12985
13167
  {
12986
13168
  content: `---
@@ -12991,7 +13173,7 @@ date: 2026-01-01
12991
13173
 
12992
13174
  The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.
12993
13175
  `,
12994
- path: join29(dir, "changelog", "v1-0-0.mdx")
13176
+ path: join30(dir, "changelog", "v1-0-0.mdx")
12995
13177
  }
12996
13178
  ]
12997
13179
  },
@@ -13004,7 +13186,7 @@ The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries besid
13004
13186
  Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
13005
13187
 
13006
13188
  Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
13007
- path: join29(dir, "index.mdx")
13189
+ path: join30(dir, "index.mdx")
13008
13190
  }
13009
13191
  ]
13010
13192
  },
@@ -13015,11 +13197,11 @@ Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
13015
13197
  content: page("Introduction", "Get started with the SDK.", `# Introduction
13016
13198
 
13017
13199
  Install the SDK and make your first call. See [Installation](/installation).`),
13018
- path: join29(dir, "index.mdx")
13200
+ path: join30(dir, "index.mdx")
13019
13201
  },
13020
13202
  {
13021
13203
  content: page("Installation", "Install the SDK.", "# Installation\n\n```package-install\nyour-sdk\n```"),
13022
- path: join29(dir, "installation.mdx")
13204
+ path: join30(dir, "installation.mdx")
13023
13205
  }
13024
13206
  ]
13025
13207
  }
@@ -13034,7 +13216,7 @@ var detectPackageManager = (userAgent) => {
13034
13216
  const name = userAgent?.split("/")[0];
13035
13217
  return name !== undefined && PACKAGE_MANAGERS.includes(name) ? name : "npm";
13036
13218
  };
13037
- var validateContentDir = (root, dir) => isAbsolute9(dir) || relative13(root, join29(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
13219
+ var validateContentDir = (root, dir) => isAbsolute9(dir) || relative13(root, join30(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
13038
13220
  var titleize = (raw) => {
13039
13221
  const words = raw.replaceAll(/[-_.]+/gu, " ").split(/\s+/u).filter(Boolean);
13040
13222
  return words.length === 0 ? "My Docs" : words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
@@ -13117,17 +13299,17 @@ var buildPlan = (root, answers) => {
13117
13299
  const files = [
13118
13300
  {
13119
13301
  content: blumePackageJson(toPackageName(basename4(root)), extraDepsFor(answers.sources)),
13120
- path: join29(root, "package.json")
13302
+ path: join30(root, "package.json")
13121
13303
  },
13122
- { content: buildConfig(answers), path: join29(root, "blume.config.ts") }
13304
+ { content: buildConfig(answers), path: join30(root, "blume.config.ts") }
13123
13305
  ];
13124
13306
  if (answers.sources.length === 0 || answers.sources.includes("filesystem")) {
13125
- files.push(...STARTERS[answers.template].files(answers.contentDir).map((file) => ({ ...file, path: join29(root, file.path) })));
13307
+ files.push(...STARTERS[answers.template].files(answers.contentDir).map((file) => ({ ...file, path: join30(root, file.path) })));
13126
13308
  }
13127
13309
  return files;
13128
13310
  };
13129
13311
  var writeFileSafe = async (file, log) => {
13130
- if (existsSync18(file.path)) {
13312
+ if (existsSync19(file.path)) {
13131
13313
  log.info(`Skipped existing ${file.path}`);
13132
13314
  return false;
13133
13315
  }
@@ -13434,10 +13616,10 @@ var initCommand = defineCommand7({
13434
13616
  });
13435
13617
 
13436
13618
  // src/cli/commands/preview.ts
13437
- import { existsSync as existsSync19 } from "node:fs";
13619
+ import { existsSync as existsSync20 } from "node:fs";
13438
13620
  import { preview } from "astro";
13439
13621
  import { defineCommand as defineCommand8 } from "citty";
13440
- import { join as join30 } from "pathe";
13622
+ import { join as join31 } from "pathe";
13441
13623
  var previewCommand = defineCommand8({
13442
13624
  args: {
13443
13625
  host: { description: "Network host to bind.", type: "string" },
@@ -13451,7 +13633,7 @@ var previewCommand = defineCommand8({
13451
13633
  const root = process.cwd();
13452
13634
  const { config } = await loadConfig(root);
13453
13635
  const context = resolveProjectContext(root, config);
13454
- if (!existsSync19(join30(context.outDir, "astro.config.mjs"))) {
13636
+ if (!existsSync20(join31(context.outDir, "astro.config.mjs"))) {
13455
13637
  logger.error("No build found. Run `blume build` first.");
13456
13638
  process.exit(1);
13457
13639
  }
@@ -13469,7 +13651,7 @@ var previewCommand = defineCommand8({
13469
13651
  // src/cli/commands/sync.ts
13470
13652
  import { rm as rm4 } from "node:fs/promises";
13471
13653
  import { defineCommand as defineCommand9 } from "citty";
13472
- import { join as join31 } from "pathe";
13654
+ import { join as join32 } from "pathe";
13473
13655
  var syncCommand = defineCommand9({
13474
13656
  args: {
13475
13657
  force: {
@@ -13491,7 +13673,7 @@ var syncCommand = defineCommand9({
13491
13673
  if (args.force) {
13492
13674
  const { config } = await loadConfig(root);
13493
13675
  const context = resolveProjectContext(root, config);
13494
- await rm4(join31(context.outDir, "cache"), { force: true, recursive: true });
13676
+ await rm4(join32(context.outDir, "cache"), { force: true, recursive: true });
13495
13677
  logger.info("Cleared source cache.");
13496
13678
  }
13497
13679
  const lock = readDevLock(resolveRuntimeDir(root));
@@ -13509,13 +13691,13 @@ var syncCommand = defineCommand9({
13509
13691
  });
13510
13692
 
13511
13693
  // src/cli/commands/validate.ts
13512
- import { existsSync as existsSync21 } from "node:fs";
13694
+ import { existsSync as existsSync22 } from "node:fs";
13513
13695
  import { defineCommand as defineCommand10 } from "citty";
13514
- import { join as join33 } from "pathe";
13696
+ import { join as join34 } from "pathe";
13515
13697
 
13516
13698
  // src/core/links.ts
13517
- import { existsSync as existsSync20 } from "node:fs";
13518
- import { basename as basename6, join as join32 } from "pathe";
13699
+ import { existsSync as existsSync21 } from "node:fs";
13700
+ import { basename as basename6, join as join33 } from "pathe";
13519
13701
  var HTTP = /^https?:\/\//iu;
13520
13702
  var PROTOCOL_RELATIVE = /^\/\//u;
13521
13703
  var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
@@ -13534,7 +13716,7 @@ var STATUS_NOT_FOUND = 404;
13534
13716
  var STATUS_GONE = 410;
13535
13717
  var STATUS_METHOD_NOT_ALLOWED = 405;
13536
13718
  var STATUS_NOT_IMPLEMENTED = 501;
13537
- var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync20(join32(ctx.publicDir, resolved));
13719
+ var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync21(join33(ctx.publicDir, resolved));
13538
13720
  var NUMERIC_PREFIX3 = /^\d+[-_.]/u;
13539
13721
  var isIndexPage = (page2) => /^index\.(?:md|mdx)$/iu.test(basename6(page2.navPath).replace(NUMERIC_PREFIX3, ""));
13540
13722
  var applyRelativePart = (segments, part) => {
@@ -13800,12 +13982,12 @@ var validateCommand = defineCommand10({
13800
13982
  });
13801
13983
  extraRoutes.push(...manifest.routes.flatMap((route) => route.fallback ? [route.path] : []));
13802
13984
  }
13803
- const publicDir = join33(root, "public");
13985
+ const publicDir = join34(root, "public");
13804
13986
  diagnostics.push(...await validateLinks(project.graph, {
13805
13987
  basePath: project.config.basePath,
13806
13988
  checkExternal: Boolean(args.external),
13807
13989
  extraRoutes,
13808
- publicDir: existsSync21(publicDir) ? publicDir : null,
13990
+ publicDir: existsSync22(publicDir) ? publicDir : null,
13809
13991
  redirects: project.config.redirects
13810
13992
  }));
13811
13993
  } catch (error) {
@@ -13866,5 +14048,5 @@ process.on("unhandledRejection", (error) => {
13866
14048
  });
13867
14049
  runMain(main);
13868
14050
 
13869
- //# debugId=C36C25DD63079AEA64756E2164756E21
14051
+ //# debugId=E383A1CFB1E8864864756E2164756E21
13870
14052
  //# sourceMappingURL=index.js.map