blume 0.5.4 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +759 -406
- package/dist/cli/index.js.map +27 -25
- package/dist/types/core/config-input.d.ts +759 -0
- package/dist/types/core/config.d.ts +126 -3
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +50 -0
- package/dist/types/core/schema.d.ts +334 -62
- package/dist/types/core/types.d.ts +8 -0
- package/dist/types/index.d.ts +2 -1
- package/docs/advanced/changelog.mdx +10 -2
- package/docs/configuration/ai.mdx +56 -0
- package/docs/configuration/index.mdx +0 -2
- package/docs/configuration/seo.mdx +59 -1
- package/docs/configuration/theming.mdx +14 -9
- package/docs/content/meta.mdx +3 -17
- package/docs/content/navigation.mdx +41 -4
- package/docs/content/syntax.mdx +4 -8
- package/package.json +3 -1
- package/src/ai/agent-readability.ts +97 -0
- package/src/ai/ask-context.ts +131 -8
- package/src/ai/ask-data.ts +4 -1
- package/src/astro/generate.ts +40 -11
- package/src/astro/templates.ts +90 -10
- package/src/cli/commands/build.ts +41 -1
- package/src/cli/commands/dev.ts +31 -14
- package/src/cli/dev-lock.ts +94 -21
- package/src/components/content/GithubInfo.astro +11 -10
- package/src/components/content/TypeTable.astro +8 -3
- package/src/components/content/Update.astro +12 -2
- package/src/components/content/changelog-element.ts +62 -0
- package/src/components/islands/AskAI.astro +66 -2
- package/src/components/islands/ask-ai.tsx +289 -53
- package/src/components/layout/Header.astro +1 -1
- package/src/components/layout/NavTree.astro +1 -1
- package/src/components/layout/PageActions.astro +73 -30
- package/src/components/layout/RootLayout.astro +79 -10
- package/src/core/config-input.ts +933 -0
- package/src/core/config.ts +126 -3
- package/src/core/data.ts +4 -0
- package/src/core/graph.ts +7 -2
- package/src/core/i18n-ui.ts +5 -0
- package/src/core/nav-diagnostics.ts +7 -0
- package/src/core/navigation.ts +38 -12
- package/src/core/schema.ts +130 -22
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/watch.ts +43 -12
- package/src/core/types.ts +9 -0
- package/src/deploy/adapter-output.ts +82 -0
- package/src/deploy/robots.ts +37 -4
- package/src/index.ts +1 -1
- package/src/markdown/index.ts +28 -30
- package/src/markdown/math.ts +3 -2
- package/src/openapi/scalar.ts +1 -1
- package/src/registry/eject.ts +21 -14
- package/src/search/documents.ts +9 -2
- package/src/theme/entry.ts +7 -3
- package/src/theme/palette.ts +21 -14
package/dist/cli/index.js
CHANGED
|
@@ -513,11 +513,155 @@ Next steps:
|
|
|
513
513
|
});
|
|
514
514
|
|
|
515
515
|
// src/cli/commands/build.ts
|
|
516
|
-
import { existsSync as
|
|
516
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
517
517
|
import { readdir, stat, writeFile as writeFile7 } from "node:fs/promises";
|
|
518
518
|
import { build } from "astro";
|
|
519
519
|
import { defineCommand as defineCommand2 } from "citty";
|
|
520
|
-
import { join as
|
|
520
|
+
import { join as join24 } from "pathe";
|
|
521
|
+
|
|
522
|
+
// src/deploy/xml.ts
|
|
523
|
+
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
524
|
+
|
|
525
|
+
// src/deploy/rss.ts
|
|
526
|
+
var capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1);
|
|
527
|
+
var pageDate = (page) => {
|
|
528
|
+
const raw = page.meta.date ?? page.meta.changelog?.date;
|
|
529
|
+
if (!raw) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
const date = new Date(raw);
|
|
533
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
534
|
+
};
|
|
535
|
+
var buildRssFeeds = (project) => {
|
|
536
|
+
const { config } = project;
|
|
537
|
+
const { rss } = config.seo;
|
|
538
|
+
const { site } = config.deployment;
|
|
539
|
+
if (!(rss.enabled && site)) {
|
|
540
|
+
return [];
|
|
541
|
+
}
|
|
542
|
+
const base = site.replace(/\/$/u, "");
|
|
543
|
+
const feeds = [];
|
|
544
|
+
for (const type of rss.types) {
|
|
545
|
+
const pages = project.graph.pages.filter((page) => page.contentType === type && !(page.meta.draft || page.meta.sidebar.hidden));
|
|
546
|
+
if (pages.length === 0) {
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const items = pages.map((page) => ({
|
|
550
|
+
date: pageDate(page),
|
|
551
|
+
description: page.description,
|
|
552
|
+
link: `${base}${page.route}`,
|
|
553
|
+
title: page.title
|
|
554
|
+
})).toSorted((a, b) => (b.date?.getTime() ?? 0) - (a.date?.getTime() ?? 0)).slice(0, rss.limit);
|
|
555
|
+
feeds.push({
|
|
556
|
+
description: config.description,
|
|
557
|
+
items,
|
|
558
|
+
link: base,
|
|
559
|
+
path: `/${type}/rss.xml`,
|
|
560
|
+
title: `${config.title} — ${capitalize(type)}`,
|
|
561
|
+
type
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
return feeds;
|
|
565
|
+
};
|
|
566
|
+
var renderItem = (item) => {
|
|
567
|
+
const parts = [
|
|
568
|
+
` <title>${escapeXml(item.title)}</title>`,
|
|
569
|
+
` <link>${escapeXml(item.link)}</link>`,
|
|
570
|
+
` <guid isPermaLink="true">${escapeXml(item.link)}</guid>`
|
|
571
|
+
];
|
|
572
|
+
if (item.description) {
|
|
573
|
+
parts.push(` <description>${escapeXml(item.description)}</description>`);
|
|
574
|
+
}
|
|
575
|
+
if (item.date) {
|
|
576
|
+
parts.push(` <pubDate>${item.date.toUTCString()}</pubDate>`);
|
|
577
|
+
}
|
|
578
|
+
return ` <item>
|
|
579
|
+
${parts.join(`
|
|
580
|
+
`)}
|
|
581
|
+
</item>`;
|
|
582
|
+
};
|
|
583
|
+
var renderRssFeed = (feed) => {
|
|
584
|
+
const channel = [
|
|
585
|
+
` <title>${escapeXml(feed.title)}</title>`,
|
|
586
|
+
` <link>${escapeXml(feed.link)}</link>`,
|
|
587
|
+
` <description>${escapeXml(feed.description ?? feed.title)}</description>`,
|
|
588
|
+
` <atom:link href="${escapeXml(`${feed.link}${feed.path}`)}" rel="self" type="application/rss+xml" />`
|
|
589
|
+
];
|
|
590
|
+
const items = feed.items.map(renderItem).join(`
|
|
591
|
+
`);
|
|
592
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
593
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
594
|
+
<channel>
|
|
595
|
+
${channel.join(`
|
|
596
|
+
`)}
|
|
597
|
+
${items}
|
|
598
|
+
</channel>
|
|
599
|
+
</rss>
|
|
600
|
+
`;
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
// src/ai/agent-readability.ts
|
|
604
|
+
var USAGE_TOKENS = [
|
|
605
|
+
["search", "search"],
|
|
606
|
+
["aiInput", "ai-input"],
|
|
607
|
+
["aiTrain", "ai-train"]
|
|
608
|
+
];
|
|
609
|
+
var usagePolicy = (signals) => {
|
|
610
|
+
if (!signals) {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
return Object.fromEntries(USAGE_TOKENS.map(([key, token]) => [token, signals[key]]));
|
|
614
|
+
};
|
|
615
|
+
var buildAgentReadability = (project) => {
|
|
616
|
+
const { config } = project;
|
|
617
|
+
if (!config.seo.agentReadability) {
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
const site = config.deployment.site ?? null;
|
|
621
|
+
const abs = (path) => site ? `${site.replace(/\/+$/u, "")}${path}` : path;
|
|
622
|
+
const artifacts = {
|
|
623
|
+
markdown: {
|
|
624
|
+
contentNegotiation: "text/markdown",
|
|
625
|
+
pattern: abs("/{route}.md")
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
if (config.ai.llmsTxt) {
|
|
629
|
+
artifacts.llmsFullTxt = abs("/llms-full.txt");
|
|
630
|
+
artifacts.llmsTxt = abs("/llms.txt");
|
|
631
|
+
}
|
|
632
|
+
if (config.mcp.enabled) {
|
|
633
|
+
artifacts.mcp = {
|
|
634
|
+
discovery: abs("/.well-known/mcp.json"),
|
|
635
|
+
url: abs(config.mcp.route)
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
if (config.ai.ask?.enabled) {
|
|
639
|
+
artifacts.askApi = abs("/api/ask");
|
|
640
|
+
}
|
|
641
|
+
if (site && config.seo.sitemap) {
|
|
642
|
+
artifacts.sitemap = abs("/sitemap.xml");
|
|
643
|
+
}
|
|
644
|
+
const feeds = site && config.seo.rss.enabled ? buildRssFeeds(project).map((feed) => abs(feed.path)) : [];
|
|
645
|
+
if (feeds.length > 0) {
|
|
646
|
+
artifacts.feeds = feeds;
|
|
647
|
+
}
|
|
648
|
+
const version = project.manifest?.blumeVersion;
|
|
649
|
+
const manifest = {
|
|
650
|
+
artifacts,
|
|
651
|
+
description: config.description,
|
|
652
|
+
generator: version ? `blume@${version}` : undefined,
|
|
653
|
+
name: config.mcp.name ?? config.title,
|
|
654
|
+
site
|
|
655
|
+
};
|
|
656
|
+
const usage = usagePolicy(config.seo.contentSignals);
|
|
657
|
+
if (usage) {
|
|
658
|
+
manifest.contentUsage = usage;
|
|
659
|
+
}
|
|
660
|
+
if (config.github) {
|
|
661
|
+
manifest.repository = `https://github.com/${config.github.owner}/${config.github.repo}`;
|
|
662
|
+
}
|
|
663
|
+
return manifest;
|
|
664
|
+
};
|
|
521
665
|
|
|
522
666
|
// src/core/frontmatter.ts
|
|
523
667
|
import baseMatter from "gray-matter";
|
|
@@ -700,6 +844,42 @@ var serverFeatures = (config) => {
|
|
|
700
844
|
return features;
|
|
701
845
|
};
|
|
702
846
|
|
|
847
|
+
// src/deploy/adapter-output.ts
|
|
848
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
849
|
+
import { cp, mkdir as mkdir2, rm } from "node:fs/promises";
|
|
850
|
+
import { dirname as dirname4, join as join6 } from "pathe";
|
|
851
|
+
var ADAPTER_OUTPUT_PATHS = {
|
|
852
|
+
netlify: ".netlify",
|
|
853
|
+
vercel: ".vercel/output"
|
|
854
|
+
};
|
|
855
|
+
var deployStaticDir = (config, context) => {
|
|
856
|
+
const { adapter, output } = config.deployment;
|
|
857
|
+
if (output === "server" && adapter === "vercel") {
|
|
858
|
+
return join6(context.root, ".vercel", "output", "static");
|
|
859
|
+
}
|
|
860
|
+
return context.distDir ?? join6(context.root, "dist");
|
|
861
|
+
};
|
|
862
|
+
var surfaceAdapterOutput = async (config, context) => {
|
|
863
|
+
const { adapter, output } = config.deployment;
|
|
864
|
+
if (output !== "server" || !adapter) {
|
|
865
|
+
return { moved: false };
|
|
866
|
+
}
|
|
867
|
+
const rel = ADAPTER_OUTPUT_PATHS[adapter];
|
|
868
|
+
if (!rel) {
|
|
869
|
+
return { moved: false };
|
|
870
|
+
}
|
|
871
|
+
const from = join6(context.outDir, rel);
|
|
872
|
+
const to = join6(context.root, rel);
|
|
873
|
+
if (!existsSync4(from)) {
|
|
874
|
+
return { moved: false };
|
|
875
|
+
}
|
|
876
|
+
await mkdir2(dirname4(to), { recursive: true });
|
|
877
|
+
await rm(to, { force: true, recursive: true });
|
|
878
|
+
await cp(from, to, { recursive: true });
|
|
879
|
+
await rm(from, { force: true, recursive: true });
|
|
880
|
+
return { from, ignore: `${rel.split("/")[0]}/`, moved: true, to };
|
|
881
|
+
};
|
|
882
|
+
|
|
703
883
|
// src/deploy/redirects.ts
|
|
704
884
|
var buildNetlifyRedirects = (redirects) => `${redirects.map((redirect) => `${redirect.from} ${redirect.to} ${redirect.status}`).join(`
|
|
705
885
|
`)}
|
|
@@ -720,12 +900,29 @@ var buildRedirectManifest = (redirects) => `${JSON.stringify(redirects.map((redi
|
|
|
720
900
|
`;
|
|
721
901
|
|
|
722
902
|
// src/deploy/robots.ts
|
|
903
|
+
var SIGNAL_TOKENS = [
|
|
904
|
+
["search", "search"],
|
|
905
|
+
["aiInput", "ai-input"],
|
|
906
|
+
["aiTrain", "ai-train"]
|
|
907
|
+
];
|
|
908
|
+
var contentSignalLine = (signals) => {
|
|
909
|
+
if (!signals) {
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
const tokens = SIGNAL_TOKENS.map(([key, token]) => `${token}=${signals[key] ? "yes" : "no"}`);
|
|
913
|
+
return `Content-Signal: ${tokens.join(", ")}`;
|
|
914
|
+
};
|
|
723
915
|
var buildRobots = (project) => {
|
|
724
916
|
const { config } = project;
|
|
725
917
|
if (!config.seo.robots) {
|
|
726
918
|
return null;
|
|
727
919
|
}
|
|
728
|
-
const lines = ["User-agent: *"
|
|
920
|
+
const lines = ["User-agent: *"];
|
|
921
|
+
const signal = contentSignalLine(config.seo.contentSignals);
|
|
922
|
+
if (signal) {
|
|
923
|
+
lines.push(signal);
|
|
924
|
+
}
|
|
925
|
+
lines.push("Allow: /");
|
|
729
926
|
const { site } = config.deployment;
|
|
730
927
|
if (site && config.seo.sitemap) {
|
|
731
928
|
lines.push("", `Sitemap: ${site.replace(/\/$/u, "")}/sitemap.xml`);
|
|
@@ -735,9 +932,6 @@ var buildRobots = (project) => {
|
|
|
735
932
|
`;
|
|
736
933
|
};
|
|
737
934
|
|
|
738
|
-
// src/deploy/xml.ts
|
|
739
|
-
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
740
|
-
|
|
741
935
|
// src/deploy/sitemap.ts
|
|
742
936
|
var lastmodTag = (value) => {
|
|
743
937
|
if (!value) {
|
|
@@ -762,7 +956,7 @@ ${urls.join(`
|
|
|
762
956
|
};
|
|
763
957
|
|
|
764
958
|
// src/search/build.ts
|
|
765
|
-
import { join as
|
|
959
|
+
import { join as join7 } from "pathe";
|
|
766
960
|
var buildSearchIndex = async (outDir) => {
|
|
767
961
|
const pagefind = await import("pagefind");
|
|
768
962
|
const { index } = await pagefind.createIndex({});
|
|
@@ -770,7 +964,7 @@ var buildSearchIndex = async (outDir) => {
|
|
|
770
964
|
throw new Error("Failed to create Pagefind index.");
|
|
771
965
|
}
|
|
772
966
|
const result = await index.addDirectory({ path: outDir });
|
|
773
|
-
await index.writeFiles({ outputPath:
|
|
967
|
+
await index.writeFiles({ outputPath: join7(outDir, "pagefind") });
|
|
774
968
|
await pagefind.close();
|
|
775
969
|
return result.page_count;
|
|
776
970
|
};
|
|
@@ -2676,7 +2870,8 @@ var buildSearchDocuments = async (project, options) => {
|
|
|
2676
2870
|
return await Promise.all(indexable.map(async (route) => {
|
|
2677
2871
|
const page = pageById.get(route.id);
|
|
2678
2872
|
const raw = page ? await readEntryText(project, page) : "";
|
|
2679
|
-
const
|
|
2873
|
+
const source = raw ? frontmatter_default(raw).content : "";
|
|
2874
|
+
const body = options?.content === "markdown" ? source.trim() : toPlainText(source);
|
|
2680
2875
|
const tags = page?.meta?.search?.tags;
|
|
2681
2876
|
const crumb = crumbs.get(route.path);
|
|
2682
2877
|
return {
|
|
@@ -2817,17 +3012,17 @@ var syncSearchProvider = async (project, reporter) => {
|
|
|
2817
3012
|
|
|
2818
3013
|
// src/cli/dev-lock.ts
|
|
2819
3014
|
import {
|
|
2820
|
-
existsSync as
|
|
3015
|
+
existsSync as existsSync6,
|
|
2821
3016
|
mkdirSync,
|
|
2822
3017
|
readFileSync as readFileSync2,
|
|
2823
3018
|
rmSync,
|
|
2824
3019
|
writeFileSync
|
|
2825
3020
|
} from "node:fs";
|
|
2826
|
-
import { join as
|
|
3021
|
+
import { join as join9 } from "pathe";
|
|
2827
3022
|
|
|
2828
3023
|
// src/core/project.ts
|
|
2829
|
-
import { existsSync as
|
|
2830
|
-
import { isAbsolute, join as
|
|
3024
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
3025
|
+
import { isAbsolute, join as join8, resolve as resolve2 } from "pathe";
|
|
2831
3026
|
var CONFIG_FILENAMES = [
|
|
2832
3027
|
"blume.config.ts",
|
|
2833
3028
|
"blume.config.mjs",
|
|
@@ -2837,22 +3032,22 @@ var THEME_FILENAMES = ["theme.css"];
|
|
|
2837
3032
|
var COMPONENTS_FILENAMES = ["components.tsx", "components.ts"];
|
|
2838
3033
|
var firstExisting = (root, names) => {
|
|
2839
3034
|
for (const name of names) {
|
|
2840
|
-
const candidate =
|
|
2841
|
-
if (
|
|
3035
|
+
const candidate = join8(root, name);
|
|
3036
|
+
if (existsSync5(candidate)) {
|
|
2842
3037
|
return candidate;
|
|
2843
3038
|
}
|
|
2844
3039
|
}
|
|
2845
3040
|
return null;
|
|
2846
3041
|
};
|
|
2847
3042
|
var findConfigFile = (root) => firstExisting(root, CONFIG_FILENAMES);
|
|
2848
|
-
var resolveRuntimeDir = (root, runtimeDir = ".blume") => isAbsolute(runtimeDir) ? runtimeDir :
|
|
3043
|
+
var resolveRuntimeDir = (root, runtimeDir = ".blume") => isAbsolute(runtimeDir) ? runtimeDir : join8(resolve2(root), runtimeDir);
|
|
2849
3044
|
var resolveProjectContext = (root, config, options) => {
|
|
2850
3045
|
const absoluteRoot = resolve2(root);
|
|
2851
|
-
const contentRoot = isAbsolute(config.content.root) ? config.content.root :
|
|
2852
|
-
const pagesPath =
|
|
2853
|
-
const pagesRoot =
|
|
3046
|
+
const contentRoot = isAbsolute(config.content.root) ? config.content.root : join8(absoluteRoot, config.content.root);
|
|
3047
|
+
const pagesPath = join8(absoluteRoot, config.content.pages);
|
|
3048
|
+
const pagesRoot = existsSync5(pagesPath) ? pagesPath : null;
|
|
2854
3049
|
const outDir = resolveRuntimeDir(absoluteRoot, options?.runtimeDir);
|
|
2855
|
-
const distDir = options?.runtimeDir ?
|
|
3050
|
+
const distDir = options?.runtimeDir ? join8(outDir, "dist") : join8(absoluteRoot, "dist");
|
|
2856
3051
|
return {
|
|
2857
3052
|
componentsFile: firstExisting(absoluteRoot, COMPONENTS_FILENAMES),
|
|
2858
3053
|
configFile: findConfigFile(absoluteRoot),
|
|
@@ -2866,16 +3061,27 @@ var resolveProjectContext = (root, config, options) => {
|
|
|
2866
3061
|
};
|
|
2867
3062
|
|
|
2868
3063
|
// src/cli/dev-lock.ts
|
|
2869
|
-
var lockPath = (outDir) =>
|
|
2870
|
-
var
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3064
|
+
var lockPath = (outDir) => join9(outDir, "dev.lock");
|
|
3065
|
+
var isValidPid = (pid) => typeof pid === "number" && Number.isInteger(pid) && pid > 0;
|
|
3066
|
+
var parseLock = (raw) => {
|
|
3067
|
+
let data;
|
|
3068
|
+
try {
|
|
3069
|
+
data = JSON.parse(raw.trim());
|
|
3070
|
+
} catch {
|
|
3071
|
+
return null;
|
|
2874
3072
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
return false;
|
|
3073
|
+
if (isValidPid(data)) {
|
|
3074
|
+
return { pid: data };
|
|
2878
3075
|
}
|
|
3076
|
+
if (typeof data === "object" && data !== null) {
|
|
3077
|
+
const { pid, port } = data;
|
|
3078
|
+
if (isValidPid(pid)) {
|
|
3079
|
+
return typeof port === "number" ? { pid, port } : { pid };
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
return null;
|
|
3083
|
+
};
|
|
3084
|
+
var isProcessAlive = (pid) => {
|
|
2879
3085
|
try {
|
|
2880
3086
|
process.kill(pid, 0);
|
|
2881
3087
|
return true;
|
|
@@ -2883,10 +3089,34 @@ var isDevLocked = (outDir) => {
|
|
|
2883
3089
|
return error.code === "EPERM";
|
|
2884
3090
|
}
|
|
2885
3091
|
};
|
|
2886
|
-
var
|
|
3092
|
+
var readDevLock = (outDir) => {
|
|
3093
|
+
const path = lockPath(outDir);
|
|
3094
|
+
if (!existsSync6(path)) {
|
|
3095
|
+
return null;
|
|
3096
|
+
}
|
|
3097
|
+
const lock = parseLock(readFileSync2(path, "utf-8"));
|
|
3098
|
+
return lock && isProcessAlive(lock.pid) ? lock : null;
|
|
3099
|
+
};
|
|
3100
|
+
var writeLock = (outDir, port) => {
|
|
3101
|
+
writeFileSync(lockPath(outDir), JSON.stringify({
|
|
3102
|
+
pid: process.pid,
|
|
3103
|
+
...port === undefined ? {} : { port }
|
|
3104
|
+
}));
|
|
3105
|
+
};
|
|
3106
|
+
var ownsLock = (outDir) => {
|
|
2887
3107
|
const path = lockPath(outDir);
|
|
3108
|
+
if (!existsSync6(path)) {
|
|
3109
|
+
return false;
|
|
3110
|
+
}
|
|
3111
|
+
try {
|
|
3112
|
+
return parseLock(readFileSync2(path, "utf-8"))?.pid === process.pid;
|
|
3113
|
+
} catch {
|
|
3114
|
+
return false;
|
|
3115
|
+
}
|
|
3116
|
+
};
|
|
3117
|
+
var acquireDevLock = (outDir, port) => {
|
|
2888
3118
|
mkdirSync(outDir, { recursive: true });
|
|
2889
|
-
|
|
3119
|
+
writeLock(outDir, port);
|
|
2890
3120
|
let released = false;
|
|
2891
3121
|
return () => {
|
|
2892
3122
|
if (released) {
|
|
@@ -2894,38 +3124,46 @@ var acquireDevLock = (outDir) => {
|
|
|
2894
3124
|
}
|
|
2895
3125
|
released = true;
|
|
2896
3126
|
try {
|
|
2897
|
-
if (
|
|
2898
|
-
rmSync(
|
|
3127
|
+
if (ownsLock(outDir)) {
|
|
3128
|
+
rmSync(lockPath(outDir), { force: true });
|
|
2899
3129
|
}
|
|
2900
3130
|
} catch {}
|
|
2901
3131
|
};
|
|
2902
3132
|
};
|
|
3133
|
+
var updateDevLockPort = (outDir, port) => {
|
|
3134
|
+
if (ownsLock(outDir)) {
|
|
3135
|
+
writeLock(outDir, port);
|
|
3136
|
+
}
|
|
3137
|
+
};
|
|
3138
|
+
var describeDevLock = (lock) => lock.port === undefined ? "" : ` at http://localhost:${lock.port}`;
|
|
2903
3139
|
var refuseIfDevRunning = (root, action, runtimeDir) => {
|
|
2904
|
-
|
|
2905
|
-
|
|
3140
|
+
const lock = readDevLock(resolveRuntimeDir(root, runtimeDir));
|
|
3141
|
+
if (lock) {
|
|
3142
|
+
logger.error(`A \`blume dev\` server is running${describeDevLock(lock)}; ${action} would corrupt its .blume runtime. Reuse that server, stop it first, or re-run with --isolated to build/verify against .blume-verify without touching it.`);
|
|
2906
3143
|
process.exit(1);
|
|
2907
3144
|
}
|
|
2908
3145
|
};
|
|
2909
3146
|
|
|
2910
3147
|
// src/astro/generate.ts
|
|
2911
|
-
import { existsSync as
|
|
3148
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, realpathSync } from "node:fs";
|
|
2912
3149
|
import {
|
|
2913
3150
|
lstat,
|
|
2914
|
-
mkdir as
|
|
3151
|
+
mkdir as mkdir5,
|
|
2915
3152
|
readFile as readFile10,
|
|
2916
3153
|
rename,
|
|
2917
|
-
rm,
|
|
3154
|
+
rm as rm2,
|
|
2918
3155
|
symlink,
|
|
2919
3156
|
writeFile as writeFile5
|
|
2920
3157
|
} from "node:fs/promises";
|
|
2921
3158
|
import { createRequire as createRequire5 } from "node:module";
|
|
2922
3159
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
2923
|
-
import { basename as basename2, dirname as
|
|
3160
|
+
import { basename as basename2, dirname as dirname8, join as join17, normalize as normalize3, relative as relative7 } from "pathe";
|
|
2924
3161
|
import { glob as glob4 } from "tinyglobby";
|
|
2925
3162
|
|
|
2926
3163
|
// src/ai/ask-data.ts
|
|
2927
3164
|
var buildAskData = async (project) => {
|
|
2928
3165
|
const documents = await buildSearchDocuments(project, {
|
|
3166
|
+
content: "markdown",
|
|
2929
3167
|
includeWhenDisabled: true
|
|
2930
3168
|
});
|
|
2931
3169
|
return {
|
|
@@ -3158,8 +3396,8 @@ var validateUsedComponents = (pages, extraTags, registryNames) => {
|
|
|
3158
3396
|
};
|
|
3159
3397
|
|
|
3160
3398
|
// src/core/component-overrides.ts
|
|
3161
|
-
import { existsSync as
|
|
3162
|
-
import { dirname as
|
|
3399
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
3400
|
+
import { dirname as dirname5, extname, isAbsolute as isAbsolute2, resolve as resolve3 } from "pathe";
|
|
3163
3401
|
import ts from "typescript";
|
|
3164
3402
|
var GROUPS = ["mdx", "layout", "islands"];
|
|
3165
3403
|
var FRAMEWORK_BY_EXT = {
|
|
@@ -3247,7 +3485,7 @@ var findDefaultExportObject = (sourceFile) => {
|
|
|
3247
3485
|
var probeExtension = (base) => {
|
|
3248
3486
|
for (const extension of COMPONENT_EXTS) {
|
|
3249
3487
|
const candidate = `${base}.${extension}`;
|
|
3250
|
-
if (
|
|
3488
|
+
if (existsSync7(candidate)) {
|
|
3251
3489
|
return candidate;
|
|
3252
3490
|
}
|
|
3253
3491
|
}
|
|
@@ -3394,7 +3632,7 @@ var analyzeComponentOverrides = (source, filePath) => {
|
|
|
3394
3632
|
return result;
|
|
3395
3633
|
}
|
|
3396
3634
|
const imports = collectImports(sourceFile);
|
|
3397
|
-
const dir =
|
|
3635
|
+
const dir = dirname5(filePath);
|
|
3398
3636
|
for (const property of object.properties) {
|
|
3399
3637
|
if (!ts.isPropertyAssignment(property)) {
|
|
3400
3638
|
continue;
|
|
@@ -3424,6 +3662,7 @@ var uiStringsObject = z.object({
|
|
|
3424
3662
|
connectMcp: z.string().default("Connect to MCP"),
|
|
3425
3663
|
copied: z.string().default("Copied!"),
|
|
3426
3664
|
copyClaudeCode: z.string().default("Copy Claude Code command"),
|
|
3665
|
+
copyCodex: z.string().default("Copy Codex command"),
|
|
3427
3666
|
copyMarkdown: z.string().default("Copy as Markdown"),
|
|
3428
3667
|
copyServerUrl: z.string().default("Copy server URL"),
|
|
3429
3668
|
edit: z.string().default("Edit on GitHub"),
|
|
@@ -3431,11 +3670,15 @@ var uiStringsObject = z.object({
|
|
|
3431
3670
|
scrollToTop: z.string().default("Scroll to top")
|
|
3432
3671
|
}).default({}),
|
|
3433
3672
|
ask: z.object({
|
|
3673
|
+
clear: z.string().default("Clear conversation"),
|
|
3674
|
+
close: z.string().default("Close"),
|
|
3675
|
+
copy: z.string().default("Copy conversation"),
|
|
3434
3676
|
empty: z.string().default("Ask a question about the docs."),
|
|
3435
3677
|
error: z.string().default("Sorry, something went wrong."),
|
|
3436
3678
|
label: z.string().default("Ask a question"),
|
|
3437
3679
|
placeholder: z.string().default("Ask a question…"),
|
|
3438
3680
|
send: z.string().default("Send"),
|
|
3681
|
+
tip: z.string().default("Tip: You can open and close chat with"),
|
|
3439
3682
|
title: z.string().default("Ask AI")
|
|
3440
3683
|
}).default({}),
|
|
3441
3684
|
feedback: z.object({
|
|
@@ -3568,6 +3811,9 @@ var collectIcons = (navigation) => {
|
|
|
3568
3811
|
push(item.icon, `selector "${item.label}"`);
|
|
3569
3812
|
}
|
|
3570
3813
|
}
|
|
3814
|
+
for (const link of navigation.featured) {
|
|
3815
|
+
push(link.icon, `featured link "${link.label}"`);
|
|
3816
|
+
}
|
|
3571
3817
|
const sidebars = [navigation.sidebar];
|
|
3572
3818
|
for (const sidebar of sidebars) {
|
|
3573
3819
|
for (const node of flattenNodes(sidebar)) {
|
|
@@ -3597,7 +3843,11 @@ var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((ro
|
|
|
3597
3843
|
var validateNavTargets = (navigation, routes) => {
|
|
3598
3844
|
const targets = [
|
|
3599
3845
|
...navigation.tabs.map((tab) => ({ label: tab.label, path: tab.path })),
|
|
3600
|
-
...navigation.selectors.flatMap((selector) => selector.items.map((item) => ({ label: item.label, path: item.path })))
|
|
3846
|
+
...navigation.selectors.flatMap((selector) => selector.items.map((item) => ({ label: item.label, path: item.path }))),
|
|
3847
|
+
...navigation.featured.map((link) => ({
|
|
3848
|
+
label: link.label,
|
|
3849
|
+
path: link.href
|
|
3850
|
+
}))
|
|
3601
3851
|
];
|
|
3602
3852
|
const diagnostics = [];
|
|
3603
3853
|
const seen = new Set;
|
|
@@ -3677,10 +3927,10 @@ var validateNavStructure = (navigation, pages) => [
|
|
|
3677
3927
|
];
|
|
3678
3928
|
|
|
3679
3929
|
// src/core/tsconfig-aliases.ts
|
|
3680
|
-
import { existsSync as
|
|
3930
|
+
import { existsSync as existsSync8, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
3681
3931
|
import { createRequire as createRequire3 } from "node:module";
|
|
3682
3932
|
import { pathToFileURL } from "node:url";
|
|
3683
|
-
import { dirname as
|
|
3933
|
+
import { dirname as dirname6, isAbsolute as isAbsolute3, join as join10, resolve as resolve4 } from "pathe";
|
|
3684
3934
|
var stripJsonComments = (text) => {
|
|
3685
3935
|
let out = "";
|
|
3686
3936
|
let inString = false;
|
|
@@ -3743,7 +3993,7 @@ var resolveExtends = (spec, fromDir) => {
|
|
|
3743
3993
|
return candidates.find(isFile) ?? null;
|
|
3744
3994
|
}
|
|
3745
3995
|
try {
|
|
3746
|
-
const require_ = createRequire3(pathToFileURL(
|
|
3996
|
+
const require_ = createRequire3(pathToFileURL(join10(fromDir, "_.js")).href);
|
|
3747
3997
|
for (const sub of [`${spec}/tsconfig.json`, spec]) {
|
|
3748
3998
|
try {
|
|
3749
3999
|
return require_.resolve(sub);
|
|
@@ -3753,7 +4003,7 @@ var resolveExtends = (spec, fromDir) => {
|
|
|
3753
4003
|
return null;
|
|
3754
4004
|
};
|
|
3755
4005
|
var loadPaths = (file, seen) => {
|
|
3756
|
-
if (seen.has(file) || !
|
|
4006
|
+
if (seen.has(file) || !existsSync8(file)) {
|
|
3757
4007
|
return null;
|
|
3758
4008
|
}
|
|
3759
4009
|
seen.add(file);
|
|
@@ -3765,7 +4015,7 @@ var loadPaths = (file, seen) => {
|
|
|
3765
4015
|
if (options.paths && typeof options.paths === "object") {
|
|
3766
4016
|
const baseUrl = typeof options.baseUrl === "string" ? options.baseUrl : ".";
|
|
3767
4017
|
return {
|
|
3768
|
-
baseDir: resolve4(
|
|
4018
|
+
baseDir: resolve4(dirname6(file), baseUrl),
|
|
3769
4019
|
paths: options.paths
|
|
3770
4020
|
};
|
|
3771
4021
|
}
|
|
@@ -3774,7 +4024,7 @@ var loadPaths = (file, seen) => {
|
|
|
3774
4024
|
if (typeof base !== "string") {
|
|
3775
4025
|
continue;
|
|
3776
4026
|
}
|
|
3777
|
-
const resolved = resolveExtends(base,
|
|
4027
|
+
const resolved = resolveExtends(base, dirname6(file));
|
|
3778
4028
|
const found = resolved ? loadPaths(resolved, seen) : null;
|
|
3779
4029
|
if (found) {
|
|
3780
4030
|
return found;
|
|
@@ -3795,7 +4045,7 @@ var toAlias = (key, value, baseDir) => {
|
|
|
3795
4045
|
return { find, replacement: resolve4(baseDir, target) };
|
|
3796
4046
|
};
|
|
3797
4047
|
var resolveTsconfigAliases = (root) => {
|
|
3798
|
-
const entry = ["tsconfig.json", "jsconfig.json"].map((name) =>
|
|
4048
|
+
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join10(root, name)).find((file) => existsSync8(file));
|
|
3799
4049
|
if (!entry) {
|
|
3800
4050
|
return {};
|
|
3801
4051
|
}
|
|
@@ -3813,84 +4063,6 @@ var resolveTsconfigAliases = (root) => {
|
|
|
3813
4063
|
return aliases;
|
|
3814
4064
|
};
|
|
3815
4065
|
|
|
3816
|
-
// src/deploy/rss.ts
|
|
3817
|
-
var capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1);
|
|
3818
|
-
var pageDate = (page) => {
|
|
3819
|
-
const raw = page.meta.date ?? page.meta.changelog?.date;
|
|
3820
|
-
if (!raw) {
|
|
3821
|
-
return;
|
|
3822
|
-
}
|
|
3823
|
-
const date = new Date(raw);
|
|
3824
|
-
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
3825
|
-
};
|
|
3826
|
-
var buildRssFeeds = (project) => {
|
|
3827
|
-
const { config } = project;
|
|
3828
|
-
const { rss } = config.seo;
|
|
3829
|
-
const { site } = config.deployment;
|
|
3830
|
-
if (!(rss.enabled && site)) {
|
|
3831
|
-
return [];
|
|
3832
|
-
}
|
|
3833
|
-
const base = site.replace(/\/$/u, "");
|
|
3834
|
-
const feeds = [];
|
|
3835
|
-
for (const type of rss.types) {
|
|
3836
|
-
const pages = project.graph.pages.filter((page) => page.contentType === type && !(page.meta.draft || page.meta.sidebar.hidden));
|
|
3837
|
-
if (pages.length === 0) {
|
|
3838
|
-
continue;
|
|
3839
|
-
}
|
|
3840
|
-
const items = pages.map((page) => ({
|
|
3841
|
-
date: pageDate(page),
|
|
3842
|
-
description: page.description,
|
|
3843
|
-
link: `${base}${page.route}`,
|
|
3844
|
-
title: page.title
|
|
3845
|
-
})).toSorted((a, b) => (b.date?.getTime() ?? 0) - (a.date?.getTime() ?? 0)).slice(0, rss.limit);
|
|
3846
|
-
feeds.push({
|
|
3847
|
-
description: config.description,
|
|
3848
|
-
items,
|
|
3849
|
-
link: base,
|
|
3850
|
-
path: `/${type}/rss.xml`,
|
|
3851
|
-
title: `${config.title} — ${capitalize(type)}`,
|
|
3852
|
-
type
|
|
3853
|
-
});
|
|
3854
|
-
}
|
|
3855
|
-
return feeds;
|
|
3856
|
-
};
|
|
3857
|
-
var renderItem = (item) => {
|
|
3858
|
-
const parts = [
|
|
3859
|
-
` <title>${escapeXml(item.title)}</title>`,
|
|
3860
|
-
` <link>${escapeXml(item.link)}</link>`,
|
|
3861
|
-
` <guid isPermaLink="true">${escapeXml(item.link)}</guid>`
|
|
3862
|
-
];
|
|
3863
|
-
if (item.description) {
|
|
3864
|
-
parts.push(` <description>${escapeXml(item.description)}</description>`);
|
|
3865
|
-
}
|
|
3866
|
-
if (item.date) {
|
|
3867
|
-
parts.push(` <pubDate>${item.date.toUTCString()}</pubDate>`);
|
|
3868
|
-
}
|
|
3869
|
-
return ` <item>
|
|
3870
|
-
${parts.join(`
|
|
3871
|
-
`)}
|
|
3872
|
-
</item>`;
|
|
3873
|
-
};
|
|
3874
|
-
var renderRssFeed = (feed) => {
|
|
3875
|
-
const channel = [
|
|
3876
|
-
` <title>${escapeXml(feed.title)}</title>`,
|
|
3877
|
-
` <link>${escapeXml(feed.link)}</link>`,
|
|
3878
|
-
` <description>${escapeXml(feed.description ?? feed.title)}</description>`,
|
|
3879
|
-
` <atom:link href="${escapeXml(`${feed.link}${feed.path}`)}" rel="self" type="application/rss+xml" />`
|
|
3880
|
-
];
|
|
3881
|
-
const items = feed.items.map(renderItem).join(`
|
|
3882
|
-
`);
|
|
3883
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3884
|
-
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
3885
|
-
<channel>
|
|
3886
|
-
${channel.join(`
|
|
3887
|
-
`)}
|
|
3888
|
-
${items}
|
|
3889
|
-
</channel>
|
|
3890
|
-
</rss>
|
|
3891
|
-
`;
|
|
3892
|
-
};
|
|
3893
|
-
|
|
3894
4066
|
// src/openapi/references.ts
|
|
3895
4067
|
var NON_SLUG = /[^a-z0-9]+/gu;
|
|
3896
4068
|
var SLUG_EDGES = /^-+|-+$/gu;
|
|
@@ -3971,11 +4143,35 @@ var hasScalarReferences = (config) => resolveReferences(config).some((ref) => re
|
|
|
3971
4143
|
|
|
3972
4144
|
// src/openapi/scalar.ts
|
|
3973
4145
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
3974
|
-
import { isAbsolute as isAbsolute5, join as
|
|
4146
|
+
import { isAbsolute as isAbsolute5, join as join12 } from "pathe";
|
|
3975
4147
|
|
|
3976
4148
|
// src/astro/templates.ts
|
|
3977
|
-
import { existsSync as
|
|
3978
|
-
import { dirname as
|
|
4149
|
+
import { existsSync as existsSync9, readFileSync as readFileSync4 } from "node:fs";
|
|
4150
|
+
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join11, relative as relative4 } from "pathe";
|
|
4151
|
+
|
|
4152
|
+
// src/core/sources/watch.ts
|
|
4153
|
+
var BLUME_IGNORE_DIRS = [
|
|
4154
|
+
".blume",
|
|
4155
|
+
".cache",
|
|
4156
|
+
".git",
|
|
4157
|
+
".next",
|
|
4158
|
+
".turbo",
|
|
4159
|
+
".vercel",
|
|
4160
|
+
"dist",
|
|
4161
|
+
"node_modules"
|
|
4162
|
+
];
|
|
4163
|
+
var baselineScanIgnore = () => BLUME_IGNORE_DIRS.map((dir) => `**/${dir}/**`);
|
|
4164
|
+
var BLUME_WATCH_IGNORE_DIRS = BLUME_IGNORE_DIRS;
|
|
4165
|
+
var excludeDirSegments = (patterns) => patterns.map((pattern) => /^(?<dir>[^*/]+)\/\*\*$/u.exec(pattern)?.groups?.dir).filter((dir) => dir !== undefined);
|
|
4166
|
+
var ignoringWatchListener = (onChange, ignoreDirs = BLUME_WATCH_IGNORE_DIRS) => {
|
|
4167
|
+
const ignore = new Set(ignoreDirs);
|
|
4168
|
+
return (_event, filename) => {
|
|
4169
|
+
if (typeof filename === "string" && filename.split(/[/\\]/u).some((segment) => ignore.has(segment))) {
|
|
4170
|
+
return;
|
|
4171
|
+
}
|
|
4172
|
+
onChange();
|
|
4173
|
+
};
|
|
4174
|
+
};
|
|
3979
4175
|
|
|
3980
4176
|
// src/theme/fonts.ts
|
|
3981
4177
|
var FALLBACKS = {
|
|
@@ -4133,7 +4329,7 @@ var WORKSPACE_MARKERS = [
|
|
|
4133
4329
|
"yarn.lock"
|
|
4134
4330
|
];
|
|
4135
4331
|
var hasWorkspacesField = (pkgPath) => {
|
|
4136
|
-
if (!
|
|
4332
|
+
if (!existsSync9(pkgPath)) {
|
|
4137
4333
|
return false;
|
|
4138
4334
|
}
|
|
4139
4335
|
try {
|
|
@@ -4143,14 +4339,14 @@ var hasWorkspacesField = (pkgPath) => {
|
|
|
4143
4339
|
return false;
|
|
4144
4340
|
}
|
|
4145
4341
|
};
|
|
4146
|
-
var hasWorkspaceMarker = (dir) => hasWorkspacesField(
|
|
4342
|
+
var hasWorkspaceMarker = (dir) => hasWorkspacesField(join11(dir, "package.json")) || WORKSPACE_MARKERS.some((marker) => existsSync9(join11(dir, marker)));
|
|
4147
4343
|
var findWorkspaceRoot = (start) => {
|
|
4148
4344
|
let dir = start;
|
|
4149
4345
|
for (;; ) {
|
|
4150
4346
|
if (hasWorkspaceMarker(dir)) {
|
|
4151
4347
|
return dir;
|
|
4152
4348
|
}
|
|
4153
|
-
const parent =
|
|
4349
|
+
const parent = dirname7(dir);
|
|
4154
4350
|
if (parent === dir) {
|
|
4155
4351
|
return start;
|
|
4156
4352
|
}
|
|
@@ -4265,9 +4461,7 @@ var astroConfigTemplate = (options) => {
|
|
|
4265
4461
|
const twoslashTransformer = "transformerTwoslash({ explicitTrigger: true }), ";
|
|
4266
4462
|
const integrations = [
|
|
4267
4463
|
`mdx({ processor: blumeMdxProcessor(${JSON.stringify({
|
|
4268
|
-
headingAnchors: config.markdown.headingAnchors
|
|
4269
|
-
inline: config.markdown.code.inline,
|
|
4270
|
-
math: config.markdown.math
|
|
4464
|
+
headingAnchors: config.markdown.headingAnchors
|
|
4271
4465
|
})}) })`
|
|
4272
4466
|
];
|
|
4273
4467
|
if (needsReact) {
|
|
@@ -4295,8 +4489,7 @@ export default defineConfig({
|
|
|
4295
4489
|
integrations: [${integrations.join(", ")}],
|
|
4296
4490
|
markdown: {
|
|
4297
4491
|
processor: blumeMarkdownProcessor(${JSON.stringify({
|
|
4298
|
-
headingAnchors: config.markdown.headingAnchors
|
|
4299
|
-
inline: config.markdown.code.inline
|
|
4492
|
+
headingAnchors: config.markdown.headingAnchors
|
|
4300
4493
|
})}),
|
|
4301
4494
|
shikiConfig: {
|
|
4302
4495
|
themes: {
|
|
@@ -4314,9 +4507,17 @@ export default defineConfig({
|
|
|
4314
4507
|
// native bindings resolve at runtime and isolated linkers don't bundle
|
|
4315
4508
|
// symlinked store copies (which would surface their children as unresolvable
|
|
4316
4509
|
// imports). See RENDER_EXTERNAL_DEPS / prerenderDepsPlugin.
|
|
4510
|
+
//
|
|
4511
|
+
// The SSR externals go through the legacy \`ssr.external\` key rather than
|
|
4512
|
+
// \`environments.ssr\`: defining a user-owned \`environments.ssr\` block
|
|
4513
|
+
// collides with the internal environment Astro 7 builds the server under and
|
|
4514
|
+
// detaches the adapter's server entrypoint from the rolldown input, so the
|
|
4515
|
+
// SSR entry is emitted as \`index.mjs\` instead of the \`entry.mjs\` the
|
|
4516
|
+
// Vercel adapter's \`astro:build:done\` hook then fails to find. \`prerender\`
|
|
4517
|
+
// is Astro-only and has no legacy equivalent, so it stays under \`environments\`.
|
|
4518
|
+
ssr: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} },
|
|
4317
4519
|
environments: {
|
|
4318
4520
|
prerender: { resolve: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} } },
|
|
4319
|
-
ssr: { resolve: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} } },
|
|
4320
4521
|
},
|
|
4321
4522
|
resolve: {
|
|
4322
4523
|
alias: {
|
|
@@ -4338,14 +4539,14 @@ export default defineConfig({
|
|
|
4338
4539
|
// self-hosted fonts) -- pure noise the loader logs as "No entry type
|
|
4339
4540
|
// found". Vite appends this to its default ignores.
|
|
4340
4541
|
watch: {
|
|
4341
|
-
ignored: ${JSON.stringify([
|
|
4542
|
+
ignored: ${JSON.stringify([join11(context.outDir, ".astro", "**")])},
|
|
4342
4543
|
},
|
|
4343
4544
|
},
|
|
4344
4545
|
},
|
|
4345
4546
|
});
|
|
4346
4547
|
`;
|
|
4347
4548
|
};
|
|
4348
|
-
var stagedContentDir = (outDir) =>
|
|
4549
|
+
var stagedContentDir = (outDir) => join11(outDir, "content");
|
|
4349
4550
|
var contentConfigTemplate = (options) => {
|
|
4350
4551
|
const { context, config } = options;
|
|
4351
4552
|
const stagedBase = options.stagedBase ?? stagedContentDir(context.outDir);
|
|
@@ -4355,7 +4556,7 @@ var contentConfigTemplate = (options) => {
|
|
|
4355
4556
|
const docsPattern = filesystem ? [
|
|
4356
4557
|
...config.content.include,
|
|
4357
4558
|
...(config.content.exclude ?? []).map((pattern) => `!${pattern}`),
|
|
4358
|
-
"
|
|
4559
|
+
...BLUME_IGNORE_DIRS.filter((dir) => dir !== ".blume").map((dir) => `!**/${dir}/**`),
|
|
4359
4560
|
...outDirIgnore
|
|
4360
4561
|
] : [];
|
|
4361
4562
|
const stagedBlock = options.staged ? `
|
|
@@ -4691,7 +4892,7 @@ const siteHost = (() => {
|
|
|
4691
4892
|
|
|
4692
4893
|
export async function GET({ props }) {
|
|
4693
4894
|
const png = await renderOgImage({
|
|
4694
|
-
accent: data.config.theme.accent,
|
|
4895
|
+
accent: data.config.theme.accent.light,
|
|
4695
4896
|
brand: data.config.title,
|
|
4696
4897
|
description: data.config.description,
|
|
4697
4898
|
logo: data.config.logo?.svg,
|
|
@@ -4739,7 +4940,7 @@ var catchAllPageTemplate = (options) => {
|
|
|
4739
4940
|
const askImport = options.askEnabled ? `import AskAI from "blume/components/islands/AskAI.astro";
|
|
4740
4941
|
` : "";
|
|
4741
4942
|
const askSlot = options.askEnabled ? `
|
|
4742
|
-
<AskAI slot="ask" strings={ui.ask} />` : "";
|
|
4943
|
+
<AskAI slot="ask" strings={ui.ask} suggestions={data.config.ask?.suggestions ?? []} />` : "";
|
|
4743
4944
|
const mathImport = options.mathEnabled ? `import Math from "blume/components/content/Math.astro";
|
|
4744
4945
|
` : "";
|
|
4745
4946
|
const mathEntry = options.mathEnabled ? `Math,
|
|
@@ -4991,7 +5192,7 @@ var changelogIndexTemplate = (options) => {
|
|
|
4991
5192
|
const askImport = options.askEnabled ? `import AskAI from "blume/components/islands/AskAI.astro";
|
|
4992
5193
|
` : "";
|
|
4993
5194
|
const askSlot = options.askEnabled ? `
|
|
4994
|
-
<AskAI slot="ask" />` : "";
|
|
5195
|
+
<AskAI slot="ask" strings={data.ui.ask} suggestions={data.config.ask?.suggestions ?? []} />` : "";
|
|
4995
5196
|
const clientData = options.needsReact ? `
|
|
4996
5197
|
clientData={{ config: data.config, navigation: data.navigation, page: { route: "/changelog", title: data.config.title + " changelog" } }}` : "";
|
|
4997
5198
|
const stagedSpread = options.staged ? `
|
|
@@ -5035,6 +5236,20 @@ const slugify = (text) =>
|
|
|
5035
5236
|
text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") ||
|
|
5036
5237
|
"update";
|
|
5037
5238
|
|
|
5239
|
+
// The major of a version's embedded semver (\`1.2.3\` -> 1, \`pkg@2.0.0\` -> 2), or
|
|
5240
|
+
// null when there is no full major.minor.patch to key on. Drives the changelog's
|
|
5241
|
+
// group-by-major pagination, so it tolerates the scoped tags monorepos publish.
|
|
5242
|
+
const majorVersion = (version) => {
|
|
5243
|
+
const match = /(\\d+)\\.\\d+\\.\\d+/.exec(String(version ?? ""));
|
|
5244
|
+
return match ? Number(match[1]) : null;
|
|
5245
|
+
};
|
|
5246
|
+
|
|
5247
|
+
// Map each entry to its own generated page so the timeline heading can deep-link
|
|
5248
|
+
// to it. The collection entry id matches the route manifest's \`entryId\`.
|
|
5249
|
+
const routeByEntry = new Map(
|
|
5250
|
+
data.routes.map((route) => [route.entryId, route.path])
|
|
5251
|
+
);
|
|
5252
|
+
|
|
5038
5253
|
const changelogEntries = [
|
|
5039
5254
|
...(await getCollection("docs")),${stagedSpread}
|
|
5040
5255
|
]
|
|
@@ -5056,8 +5271,10 @@ const items = await Promise.all(
|
|
|
5056
5271
|
return {
|
|
5057
5272
|
Content: (await render(entry)).Content,
|
|
5058
5273
|
date: formatDate(entryDate(entry)),
|
|
5274
|
+
href: routeByEntry.get(entry.id) ?? null,
|
|
5059
5275
|
id: slugify(label),
|
|
5060
5276
|
label,
|
|
5277
|
+
major: majorVersion(entry.data.changelog?.version),
|
|
5061
5278
|
tags: entry.data.changelog?.category
|
|
5062
5279
|
? [entry.data.changelog.category]
|
|
5063
5280
|
: [],
|
|
@@ -5065,6 +5282,19 @@ const items = await Promise.all(
|
|
|
5065
5282
|
})
|
|
5066
5283
|
);
|
|
5067
5284
|
|
|
5285
|
+
// A changelog is semver-paginated only when every visible release parses as
|
|
5286
|
+
// semver and they span more than one major line. Older majors then collapse
|
|
5287
|
+
// into groups the reader reveals one at a time; otherwise the timeline is flat.
|
|
5288
|
+
const majors = items.every((item) => item.major !== null)
|
|
5289
|
+
? [...new Set(items.map((item) => item.major))].toSorted((a, b) => b - a)
|
|
5290
|
+
: [];
|
|
5291
|
+
const paginate = majors.length > 1;
|
|
5292
|
+
const majorGroups = majors.map((major) => ({
|
|
5293
|
+
items: items.filter((item) => item.major === major),
|
|
5294
|
+
label: major + ".x",
|
|
5295
|
+
major,
|
|
5296
|
+
}));
|
|
5297
|
+
|
|
5068
5298
|
const headings = items.map((item) => ({
|
|
5069
5299
|
depth: 2,
|
|
5070
5300
|
slug: item.id,
|
|
@@ -5096,6 +5326,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
5096
5326
|
}}
|
|
5097
5327
|
headings={headings}
|
|
5098
5328
|
toc={data.config.toc}
|
|
5329
|
+
contentLayout="bare"
|
|
5099
5330
|
themeMode={data.config.theme.mode}
|
|
5100
5331
|
fontCssVars={data.fontCssVars}
|
|
5101
5332
|
searchEnabled={data.config.search.enabled}
|
|
@@ -5114,16 +5345,50 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
5114
5345
|
{
|
|
5115
5346
|
items.length === 0 ? (
|
|
5116
5347
|
<p>No changelog entries yet.</p>
|
|
5348
|
+
) : paginate ? (
|
|
5349
|
+
<blume-changelog class="not-prose mt-8 block">
|
|
5350
|
+
{majorGroups[0].items.map(({ Content, href, id, label, date, tags }) => (
|
|
5351
|
+
<Update description={date} href={href} id={id} label={label} tags={tags}>
|
|
5352
|
+
<Content />
|
|
5353
|
+
</Update>
|
|
5354
|
+
))}
|
|
5355
|
+
{majorGroups.slice(1).map((group) => (
|
|
5356
|
+
<section
|
|
5357
|
+
aria-label={group.label + " releases"}
|
|
5358
|
+
data-changelog-label={group.label}
|
|
5359
|
+
data-changelog-major={group.major}
|
|
5360
|
+
>
|
|
5361
|
+
{group.items.map(({ Content, href, id, label, date, tags }) => (
|
|
5362
|
+
<Update description={date} href={href} id={id} label={label} tags={tags}>
|
|
5363
|
+
<Content />
|
|
5364
|
+
</Update>
|
|
5365
|
+
))}
|
|
5366
|
+
</section>
|
|
5367
|
+
))}
|
|
5368
|
+
<div class="mt-10 flex justify-center">
|
|
5369
|
+
<button
|
|
5370
|
+
class="inline-flex items-center gap-2 rounded-full border border-border bg-background px-4 py-2 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground"
|
|
5371
|
+
data-changelog-more
|
|
5372
|
+
hidden
|
|
5373
|
+
type="button"
|
|
5374
|
+
>
|
|
5375
|
+
Show older releases
|
|
5376
|
+
</button>
|
|
5377
|
+
</div>
|
|
5378
|
+
</blume-changelog>
|
|
5117
5379
|
) : (
|
|
5118
5380
|
<div class="not-prose mt-8">
|
|
5119
|
-
{items.map(({ Content, id, label, date, tags }) => (
|
|
5120
|
-
<Update description={date} id={id} label={label} tags={tags}>
|
|
5381
|
+
{items.map(({ Content, href, id, label, date, tags }) => (
|
|
5382
|
+
<Update description={date} href={href} id={id} label={label} tags={tags}>
|
|
5121
5383
|
<Content />
|
|
5122
5384
|
</Update>
|
|
5123
5385
|
))}
|
|
5124
5386
|
</div>
|
|
5125
5387
|
)
|
|
5126
5388
|
}
|
|
5389
|
+
<script>
|
|
5390
|
+
import "blume/components/content/changelog-element.ts";
|
|
5391
|
+
</script>
|
|
5127
5392
|
</LayoutComponent>
|
|
5128
5393
|
`;
|
|
5129
5394
|
};
|
|
@@ -5281,8 +5546,8 @@ var themeRootCss = (theme, options) => [
|
|
|
5281
5546
|
` --blume-accent: ${options.accent};`,
|
|
5282
5547
|
...cssToken("--blume-action", options.action),
|
|
5283
5548
|
...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
|
|
5284
|
-
...cssToken("--blume-background", safeColorOrNull(theme.background)),
|
|
5285
|
-
...cssToken("--blume-background-image", theme.backgroundImage ? backgroundImageCss(theme.backgroundImage) : null),
|
|
5549
|
+
...cssToken("--blume-background", safeColorOrNull(theme.background?.light)),
|
|
5550
|
+
...cssToken("--blume-background-image", theme.backgroundImage?.light ? backgroundImageCss(theme.backgroundImage.light) : null),
|
|
5286
5551
|
` --blume-radius: ${options.radius};`
|
|
5287
5552
|
].filter(Boolean).join(`
|
|
5288
5553
|
`);
|
|
@@ -5292,8 +5557,8 @@ var themeDarkCss = (theme, options) => {
|
|
|
5292
5557
|
" --blume-accent-foreground: oklch(1 0 0);",
|
|
5293
5558
|
...cssToken("--blume-action", options.action),
|
|
5294
5559
|
...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
|
|
5295
|
-
...cssToken("--blume-background", safeColorOrNull(theme.
|
|
5296
|
-
...cssToken("--blume-background-image", theme.
|
|
5560
|
+
...cssToken("--blume-background", safeColorOrNull(theme.background?.dark)),
|
|
5561
|
+
...cssToken("--blume-background-image", theme.backgroundImage?.dark ? backgroundImageCss(theme.backgroundImage.dark) : null)
|
|
5297
5562
|
].filter(Boolean);
|
|
5298
5563
|
return `:root[data-theme="dark"] {
|
|
5299
5564
|
${tokens.join(`
|
|
@@ -5301,20 +5566,22 @@ ${tokens.join(`
|
|
|
5301
5566
|
}
|
|
5302
5567
|
`;
|
|
5303
5568
|
};
|
|
5304
|
-
var resolveAccent = (theme) =>
|
|
5569
|
+
var resolveAccent = (theme) => ({
|
|
5570
|
+
dark: presetOrColor(theme.accent.dark),
|
|
5571
|
+
light: presetOrColor(theme.accent.light)
|
|
5572
|
+
});
|
|
5305
5573
|
var resolveRadius = (theme) => RADII[theme.radius];
|
|
5306
5574
|
var buildThemeCss = (theme) => {
|
|
5307
|
-
const accent =
|
|
5308
|
-
const accentDark = theme.accentDark ? presetOrColor(theme.accentDark) : null;
|
|
5575
|
+
const accent = resolveAccent(theme);
|
|
5309
5576
|
const action = theme.action ? presetOrColor(theme.action) : null;
|
|
5310
5577
|
const radius = RADII[theme.radius];
|
|
5311
5578
|
const root = themeRootCss(theme, {
|
|
5312
|
-
accent,
|
|
5579
|
+
accent: accent.light,
|
|
5313
5580
|
action,
|
|
5314
5581
|
radius
|
|
5315
5582
|
});
|
|
5316
5583
|
const dark = themeDarkCss(theme, {
|
|
5317
|
-
accent:
|
|
5584
|
+
accent: accent.dark,
|
|
5318
5585
|
action
|
|
5319
5586
|
});
|
|
5320
5587
|
return `/* Generated by Blume from theme config. */
|
|
@@ -5347,7 +5614,7 @@ var themeConfiguration = (config, override) => {
|
|
|
5347
5614
|
const accent = resolveAccent(config.theme);
|
|
5348
5615
|
const radius = resolveRadius(config.theme);
|
|
5349
5616
|
return {
|
|
5350
|
-
customCss: `:root,.light-mode,.dark-mode{--scalar-color-accent:${accent};--scalar-radius:${radius};}`,
|
|
5617
|
+
customCss: `:root,.light-mode,.dark-mode{--scalar-color-accent:${accent.light};--scalar-radius:${radius};}.dark-mode{--scalar-color-accent:${accent.dark};}`,
|
|
5351
5618
|
...darkModeConfig(config.theme.mode)
|
|
5352
5619
|
};
|
|
5353
5620
|
};
|
|
@@ -5355,7 +5622,7 @@ var specConfiguration = async (spec, root) => {
|
|
|
5355
5622
|
if (URL_SPEC.test(spec)) {
|
|
5356
5623
|
return { config: { url: spec } };
|
|
5357
5624
|
}
|
|
5358
|
-
const absolute = isAbsolute5(spec) ? spec :
|
|
5625
|
+
const absolute = isAbsolute5(spec) ? spec : join12(root, spec);
|
|
5359
5626
|
try {
|
|
5360
5627
|
return { config: { content: await readFile5(absolute, "utf-8") } };
|
|
5361
5628
|
} catch {
|
|
@@ -5413,8 +5680,8 @@ var buildReferenceFiles = async (options) => {
|
|
|
5413
5680
|
};
|
|
5414
5681
|
|
|
5415
5682
|
// src/core/sources/cache.ts
|
|
5416
|
-
import { mkdir as
|
|
5417
|
-
import { join as
|
|
5683
|
+
import { mkdir as mkdir3, readFile as readFile6, writeFile as writeFile3 } from "node:fs/promises";
|
|
5684
|
+
import { join as join13 } from "pathe";
|
|
5418
5685
|
var hashText = (text) => {
|
|
5419
5686
|
let hash = 5381;
|
|
5420
5687
|
for (let i = 0;i < text.length; i += 1) {
|
|
@@ -5441,7 +5708,7 @@ var pollingWatch = (load2, intervalSeconds) => (onChange) => {
|
|
|
5441
5708
|
return () => clearInterval(timer);
|
|
5442
5709
|
};
|
|
5443
5710
|
var snapshotCache = (cacheDir) => {
|
|
5444
|
-
const file =
|
|
5711
|
+
const file = join13(cacheDir, "entries.json");
|
|
5445
5712
|
return {
|
|
5446
5713
|
read: async () => {
|
|
5447
5714
|
try {
|
|
@@ -5452,7 +5719,7 @@ var snapshotCache = (cacheDir) => {
|
|
|
5452
5719
|
},
|
|
5453
5720
|
write: async (entries) => {
|
|
5454
5721
|
try {
|
|
5455
|
-
await
|
|
5722
|
+
await mkdir3(cacheDir, { recursive: true });
|
|
5456
5723
|
await writeFile3(file, `${JSON.stringify(entries)}
|
|
5457
5724
|
`, "utf-8");
|
|
5458
5725
|
} catch {}
|
|
@@ -5556,10 +5823,10 @@ var extractOperations = (document, baseRoute) => {
|
|
|
5556
5823
|
};
|
|
5557
5824
|
|
|
5558
5825
|
// src/openapi/parse.ts
|
|
5559
|
-
import { mkdir as
|
|
5826
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
|
|
5560
5827
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
5561
5828
|
import { normalize as normalize2, upgrade } from "@scalar/openapi-parser";
|
|
5562
|
-
import { isAbsolute as isAbsolute6, join as
|
|
5829
|
+
import { isAbsolute as isAbsolute6, join as join14 } from "pathe";
|
|
5563
5830
|
var URL_SPEC2 = /^https?:\/\//u;
|
|
5564
5831
|
var FETCH_TIMEOUT_MS = 15000;
|
|
5565
5832
|
var MAX_ATTEMPTS = 3;
|
|
@@ -5634,7 +5901,7 @@ var fetchSpecText = async (spec) => {
|
|
|
5634
5901
|
}
|
|
5635
5902
|
throw last.error;
|
|
5636
5903
|
};
|
|
5637
|
-
var cacheFileFor = (cacheDir, spec) =>
|
|
5904
|
+
var cacheFileFor = (cacheDir, spec) => join14(cacheDir, `spec-${hashText(spec)}.cache`);
|
|
5638
5905
|
var readCache = async (file) => {
|
|
5639
5906
|
try {
|
|
5640
5907
|
return await readFile7(file, "utf-8");
|
|
@@ -5644,13 +5911,13 @@ var readCache = async (file) => {
|
|
|
5644
5911
|
};
|
|
5645
5912
|
var writeCache = async (dir, file, text) => {
|
|
5646
5913
|
try {
|
|
5647
|
-
await
|
|
5914
|
+
await mkdir4(dir, { recursive: true });
|
|
5648
5915
|
await writeFile4(file, text, "utf-8");
|
|
5649
5916
|
} catch {}
|
|
5650
5917
|
};
|
|
5651
5918
|
var readSpecText = async (spec, root, options) => {
|
|
5652
5919
|
if (!URL_SPEC2.test(spec)) {
|
|
5653
|
-
const absolute = isAbsolute6(spec) ? spec :
|
|
5920
|
+
const absolute = isAbsolute6(spec) ? spec : join14(root, spec);
|
|
5654
5921
|
return { text: await readFile7(absolute, "utf-8"), warnings: [] };
|
|
5655
5922
|
}
|
|
5656
5923
|
const cacheFile = options.cacheDir ? cacheFileFor(options.cacheDir, spec) : undefined;
|
|
@@ -6252,6 +6519,10 @@ blume-diff {
|
|
|
6252
6519
|
font-size: 0.8125rem;
|
|
6253
6520
|
}
|
|
6254
6521
|
|
|
6522
|
+
.prose :where(td, th) :not(pre) > code {
|
|
6523
|
+
white-space: nowrap;
|
|
6524
|
+
}
|
|
6525
|
+
|
|
6255
6526
|
blume-tabs pre,
|
|
6256
6527
|
.not-prose > div > pre {
|
|
6257
6528
|
background: var(--blume-code-background);
|
|
@@ -6427,9 +6698,9 @@ pre:has(.line.focused):hover .line:not(.focused) {
|
|
|
6427
6698
|
content: none;
|
|
6428
6699
|
}
|
|
6429
6700
|
|
|
6430
|
-
/* Inline code highlighting
|
|
6431
|
-
|
|
6432
|
-
|
|
6701
|
+
/* Inline code highlighting: Shiki colors the tokens of a \`code\`{:lang} snippet
|
|
6702
|
+
via the same dual-theme CSS variables as fenced blocks, keeping the inline
|
|
6703
|
+
pill background. Always on — it only fires on the trailing {:lang} marker. */
|
|
6433
6704
|
.prose code.blume-inline-code span {
|
|
6434
6705
|
color: var(--shiki-light);
|
|
6435
6706
|
}
|
|
@@ -6653,12 +6924,12 @@ export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.leng
|
|
|
6653
6924
|
|
|
6654
6925
|
// src/astro/examples.ts
|
|
6655
6926
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
6656
|
-
import { join as
|
|
6927
|
+
import { join as join16, relative as relative5 } from "pathe";
|
|
6657
6928
|
import { glob as glob2 } from "tinyglobby";
|
|
6658
6929
|
|
|
6659
6930
|
// src/astro/islands.ts
|
|
6660
6931
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
6661
|
-
import { basename, join as
|
|
6932
|
+
import { basename, join as join15 } from "pathe";
|
|
6662
6933
|
import { glob } from "tinyglobby";
|
|
6663
6934
|
var DEFAULT_CLIENT = "visible";
|
|
6664
6935
|
var VALID_MODES = new Set([
|
|
@@ -6687,7 +6958,7 @@ var readClientMode = (source, file, warnings) => {
|
|
|
6687
6958
|
return mode;
|
|
6688
6959
|
};
|
|
6689
6960
|
var discoverIslands = async (root) => {
|
|
6690
|
-
const dir =
|
|
6961
|
+
const dir = join15(root, "islands");
|
|
6691
6962
|
const matches = await glob(["**/*.{jsx,svelte,tsx,vue}"], {
|
|
6692
6963
|
absolute: true,
|
|
6693
6964
|
cwd: dir,
|
|
@@ -6750,7 +7021,7 @@ var splitGlobBase = (pattern) => {
|
|
|
6750
7021
|
};
|
|
6751
7022
|
var discoverExamples = async (root, pattern = "examples") => {
|
|
6752
7023
|
const { base, rest } = GLOB_MAGIC.test(pattern) ? splitGlobBase(pattern) : { base: pattern, rest: DEFAULT_EXAMPLE_GLOB };
|
|
6753
|
-
const dir =
|
|
7024
|
+
const dir = join16(root, base);
|
|
6754
7025
|
const matches = await glob2([rest], {
|
|
6755
7026
|
absolute: true,
|
|
6756
7027
|
cwd: dir,
|
|
@@ -6831,10 +7102,10 @@ var customOgRoutes = (pages, siteTitle) => {
|
|
|
6831
7102
|
};
|
|
6832
7103
|
|
|
6833
7104
|
// src/astro/generate.ts
|
|
6834
|
-
var BLUME_SRC =
|
|
7105
|
+
var BLUME_SRC = join17(packageRoot(), "src");
|
|
6835
7106
|
var canResolveFrom = (fromDir, spec) => {
|
|
6836
7107
|
try {
|
|
6837
|
-
createRequire5(pathToFileURL2(
|
|
7108
|
+
createRequire5(pathToFileURL2(join17(fromDir, "_.js")).href).resolve(spec);
|
|
6838
7109
|
return true;
|
|
6839
7110
|
} catch {
|
|
6840
7111
|
return false;
|
|
@@ -6842,15 +7113,15 @@ var canResolveFrom = (fromDir, spec) => {
|
|
|
6842
7113
|
};
|
|
6843
7114
|
var resolvedAstroPath = (fromDir) => {
|
|
6844
7115
|
try {
|
|
6845
|
-
const pkg = createRequire5(pathToFileURL2(
|
|
7116
|
+
const pkg = createRequire5(pathToFileURL2(join17(fromDir, "_.js")).href).resolve("astro/package.json");
|
|
6846
7117
|
return realpathSync(pkg);
|
|
6847
7118
|
} catch {
|
|
6848
7119
|
return null;
|
|
6849
7120
|
}
|
|
6850
7121
|
};
|
|
6851
7122
|
var blumeDepsDir = (pkgDir = packageRoot()) => {
|
|
6852
|
-
const candidates = [
|
|
6853
|
-
return candidates.find((dir) =>
|
|
7123
|
+
const candidates = [join17(pkgDir, "node_modules"), dirname8(pkgDir)];
|
|
7124
|
+
return candidates.find((dir) => existsSync10(join17(dir, "astro"))) ?? null;
|
|
6854
7125
|
};
|
|
6855
7126
|
var linkDepsJunction = async (link, depsDir) => {
|
|
6856
7127
|
const existing = await lstat(link).catch(() => null);
|
|
@@ -6858,9 +7129,9 @@ var linkDepsJunction = async (link, depsDir) => {
|
|
|
6858
7129
|
if (!existing.isSymbolicLink()) {
|
|
6859
7130
|
return;
|
|
6860
7131
|
}
|
|
6861
|
-
await
|
|
7132
|
+
await rm2(link, { force: true });
|
|
6862
7133
|
}
|
|
6863
|
-
await
|
|
7134
|
+
await mkdir5(dirname8(link), { recursive: true });
|
|
6864
7135
|
await symlink(depsDir, link, "junction");
|
|
6865
7136
|
};
|
|
6866
7137
|
var readPkgVersion = (pkgJsonPath) => {
|
|
@@ -6890,8 +7161,8 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
|
|
|
6890
7161
|
if (blumeAstro && outDirAstro === blumeAstro) {
|
|
6891
7162
|
return null;
|
|
6892
7163
|
}
|
|
6893
|
-
if (
|
|
6894
|
-
await linkDepsJunction(
|
|
7164
|
+
if (existsSync10(join17(depsDir, "@astrojs", "mdx"))) {
|
|
7165
|
+
await linkDepsJunction(join17(outDir, "node_modules"), depsDir);
|
|
6895
7166
|
return null;
|
|
6896
7167
|
}
|
|
6897
7168
|
return astroConflictWarning(blumeAstro, outDirAstro);
|
|
@@ -6928,6 +7199,15 @@ var detectNeedsReact = async (root) => {
|
|
|
6928
7199
|
});
|
|
6929
7200
|
return matches.length > 0;
|
|
6930
7201
|
};
|
|
7202
|
+
var detectUsesMath = async (root) => {
|
|
7203
|
+
const files = await glob4(["**/*.mdx"], {
|
|
7204
|
+
cwd: root,
|
|
7205
|
+
ignore: ["**/node_modules/**", "**/.blume/**", "**/dist/**"],
|
|
7206
|
+
onlyFiles: true
|
|
7207
|
+
});
|
|
7208
|
+
const contents = await Promise.all(files.map((file) => readOptional(join17(root, file))));
|
|
7209
|
+
return contents.some((content) => content.includes("$$"));
|
|
7210
|
+
};
|
|
6931
7211
|
var writeIfChanged = async (path, content) => {
|
|
6932
7212
|
let existing = null;
|
|
6933
7213
|
try {
|
|
@@ -6938,13 +7218,13 @@ var writeIfChanged = async (path, content) => {
|
|
|
6938
7218
|
if (existing === content) {
|
|
6939
7219
|
return false;
|
|
6940
7220
|
}
|
|
6941
|
-
await
|
|
7221
|
+
await mkdir5(dirname8(path), { recursive: true });
|
|
6942
7222
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
6943
7223
|
await writeFile5(tmp, content, "utf-8");
|
|
6944
7224
|
try {
|
|
6945
7225
|
await rename(tmp, path);
|
|
6946
7226
|
} catch (error) {
|
|
6947
|
-
await
|
|
7227
|
+
await rm2(tmp, { force: true });
|
|
6948
7228
|
throw error;
|
|
6949
7229
|
}
|
|
6950
7230
|
return true;
|
|
@@ -6955,7 +7235,7 @@ var pruneOrphans = async (srcDir, written) => {
|
|
|
6955
7235
|
cwd: srcDir,
|
|
6956
7236
|
onlyFiles: true
|
|
6957
7237
|
});
|
|
6958
|
-
await Promise.all(existing.map((path) => normalize3(path)).filter((path) => !written.has(path)).map((path) =>
|
|
7238
|
+
await Promise.all(existing.map((path) => normalize3(path)).filter((path) => !written.has(path)).map((path) => rm2(path, { force: true })));
|
|
6959
7239
|
};
|
|
6960
7240
|
var collectStaged = (project) => {
|
|
6961
7241
|
const staged = new Map;
|
|
@@ -6970,11 +7250,11 @@ var writeStagedContent = async (out, staged) => {
|
|
|
6970
7250
|
const contentDir = stagedContentDir(out);
|
|
6971
7251
|
const written = new Set;
|
|
6972
7252
|
await Promise.all([...staged].map(async ([entryId, text]) => {
|
|
6973
|
-
const path =
|
|
7253
|
+
const path = join17(contentDir, entryId);
|
|
6974
7254
|
written.add(normalize3(path));
|
|
6975
7255
|
await writeIfChanged(path, text);
|
|
6976
7256
|
}));
|
|
6977
|
-
if (
|
|
7257
|
+
if (existsSync10(contentDir)) {
|
|
6978
7258
|
await pruneOrphans(contentDir, written);
|
|
6979
7259
|
}
|
|
6980
7260
|
};
|
|
@@ -6993,9 +7273,9 @@ var resolveLogo = (project) => {
|
|
|
6993
7273
|
if (light && light === dark && light.toLowerCase().endsWith(".svg")) {
|
|
6994
7274
|
const rel = light.replace(/^\//u, "");
|
|
6995
7275
|
const file = [
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
].find((path) =>
|
|
7276
|
+
join17(project.context.root, "public", rel),
|
|
7277
|
+
join17(project.context.root, rel)
|
|
7278
|
+
].find((path) => existsSync10(path));
|
|
6999
7279
|
if (file) {
|
|
7000
7280
|
return { alt, href: brandHref, svg: readFileSync6(file, "utf-8"), text };
|
|
7001
7281
|
}
|
|
@@ -7023,7 +7303,7 @@ var faviconType = (name) => {
|
|
|
7023
7303
|
};
|
|
7024
7304
|
var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync6(file).toString("base64")}`;
|
|
7025
7305
|
var defaultFavicon = () => ({
|
|
7026
|
-
href: inlineDataUri(
|
|
7306
|
+
href: inlineDataUri(join17(BLUME_SRC, "assets", "icon.png"), "image/png"),
|
|
7027
7307
|
type: "image/png"
|
|
7028
7308
|
});
|
|
7029
7309
|
var APPLE_ICON_CANDIDATES = [
|
|
@@ -7035,13 +7315,13 @@ var APPLE_ICON_CANDIDATES = [
|
|
|
7035
7315
|
var resolveIconFile = (project, candidates) => {
|
|
7036
7316
|
const { root } = project.context;
|
|
7037
7317
|
for (const name of candidates) {
|
|
7038
|
-
if (
|
|
7318
|
+
if (existsSync10(join17(root, "public", name))) {
|
|
7039
7319
|
return { href: `/${name}`, type: faviconType(name) };
|
|
7040
7320
|
}
|
|
7041
7321
|
}
|
|
7042
7322
|
for (const name of candidates) {
|
|
7043
|
-
const file =
|
|
7044
|
-
if (
|
|
7323
|
+
const file = join17(root, name);
|
|
7324
|
+
if (existsSync10(file)) {
|
|
7045
7325
|
const type = faviconType(name);
|
|
7046
7326
|
return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
|
|
7047
7327
|
}
|
|
@@ -7097,6 +7377,7 @@ var buildRuntimeData = (project) => {
|
|
|
7097
7377
|
const navigationByLocale = i18n ? Object.fromEntries(i18n.locales.map(({ code }) => [
|
|
7098
7378
|
code,
|
|
7099
7379
|
withReferenceTabs(graph.navigationByLocale[code] ?? {
|
|
7380
|
+
featured: [],
|
|
7100
7381
|
selectors: [],
|
|
7101
7382
|
sidebar: [],
|
|
7102
7383
|
tabs: []
|
|
@@ -7106,6 +7387,7 @@ var buildRuntimeData = (project) => {
|
|
|
7106
7387
|
config: {
|
|
7107
7388
|
analytics: config.analytics ?? null,
|
|
7108
7389
|
appleIcon: resolveAppleIcon(project),
|
|
7390
|
+
ask: config.ai.ask?.enabled ? { suggestions: config.ai.ask.suggestions } : null,
|
|
7109
7391
|
banner: resolveBanner(config),
|
|
7110
7392
|
codeWrap: config.markdown.code.wrap,
|
|
7111
7393
|
description: config.description,
|
|
@@ -7167,7 +7449,7 @@ var buildRuntimeData = (project) => {
|
|
|
7167
7449
|
var planMcp = (project, srcDir) => {
|
|
7168
7450
|
const { config } = project;
|
|
7169
7451
|
const { route } = config.mcp;
|
|
7170
|
-
const dir =
|
|
7452
|
+
const dir = join17(srcDir, "blume-mcp");
|
|
7171
7453
|
const base = {
|
|
7172
7454
|
dir,
|
|
7173
7455
|
discoveryPages: [],
|
|
@@ -7191,11 +7473,11 @@ var planMcp = (project, srcDir) => {
|
|
|
7191
7473
|
...base,
|
|
7192
7474
|
discoveryPages: [
|
|
7193
7475
|
{
|
|
7194
|
-
entrypoint:
|
|
7476
|
+
entrypoint: join17(dir, "discovery.ts"),
|
|
7195
7477
|
pattern: "/.well-known/mcp.json"
|
|
7196
7478
|
},
|
|
7197
7479
|
{
|
|
7198
|
-
entrypoint:
|
|
7480
|
+
entrypoint: join17(dir, "server-card.ts"),
|
|
7199
7481
|
pattern: "/.well-known/mcp/server-card.json"
|
|
7200
7482
|
}
|
|
7201
7483
|
],
|
|
@@ -7214,11 +7496,11 @@ var writeMcpFiles = async (project, plan, write) => {
|
|
|
7214
7496
|
version: data.version
|
|
7215
7497
|
};
|
|
7216
7498
|
await Promise.all([
|
|
7217
|
-
write(
|
|
7499
|
+
write(join17(plan.srcDir, "generated", "mcp-data.json"), `${JSON.stringify(data)}
|
|
7218
7500
|
`),
|
|
7219
|
-
write(
|
|
7220
|
-
write(
|
|
7221
|
-
write(
|
|
7501
|
+
write(join17(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate(plan.route)),
|
|
7502
|
+
write(join17(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
|
|
7503
|
+
write(join17(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
|
|
7222
7504
|
]);
|
|
7223
7505
|
};
|
|
7224
7506
|
var writeAskFiles = async (project, srcDir, write) => {
|
|
@@ -7228,16 +7510,16 @@ var writeAskFiles = async (project, srcDir, write) => {
|
|
|
7228
7510
|
}
|
|
7229
7511
|
const grounded = ask.provider !== "inkeep";
|
|
7230
7512
|
if (grounded) {
|
|
7231
|
-
await write(
|
|
7513
|
+
await write(join17(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
|
|
7232
7514
|
`);
|
|
7233
7515
|
}
|
|
7234
|
-
await write(
|
|
7516
|
+
await write(join17(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded));
|
|
7235
7517
|
};
|
|
7236
7518
|
var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
|
|
7237
7519
|
if (routeIsTaken(pages, contentPages, "/404")) {
|
|
7238
7520
|
return;
|
|
7239
7521
|
}
|
|
7240
|
-
await write(
|
|
7522
|
+
await write(join17(srcDir, "pages", "404.astro"), notFoundPageTemplate());
|
|
7241
7523
|
};
|
|
7242
7524
|
var shouldGenerateChangelog = (project) => {
|
|
7243
7525
|
const hasChangelog = project.graph.pages.some((page) => page.contentType === "changelog" && !(page.meta.draft || page.meta.sidebar.hidden));
|
|
@@ -7256,12 +7538,12 @@ var buildComponentSlots = async (componentsFile) => {
|
|
|
7256
7538
|
var generateRuntime = async (project) => {
|
|
7257
7539
|
const { context, config } = project;
|
|
7258
7540
|
const out = context.outDir;
|
|
7259
|
-
const srcDir =
|
|
7260
|
-
const dataPath =
|
|
7261
|
-
const themePath =
|
|
7262
|
-
const searchClientPath =
|
|
7263
|
-
const examplesPath =
|
|
7264
|
-
const openapiPath =
|
|
7541
|
+
const srcDir = join17(out, "src");
|
|
7542
|
+
const dataPath = join17(srcDir, "generated", "data.json");
|
|
7543
|
+
const themePath = join17(srcDir, "generated", "app.css");
|
|
7544
|
+
const searchClientPath = join17(srcDir, "generated", "search-client.ts");
|
|
7545
|
+
const examplesPath = join17(srcDir, "generated", "examples.ts");
|
|
7546
|
+
const openapiPath = join17(srcDir, "generated", "openapi.json");
|
|
7265
7547
|
const written = new Set;
|
|
7266
7548
|
const write = (path, content) => {
|
|
7267
7549
|
written.add(normalize3(path));
|
|
@@ -7271,9 +7553,17 @@ var generateRuntime = async (project) => {
|
|
|
7271
7553
|
const askEnabled = config.ai.ask?.enabled ?? false;
|
|
7272
7554
|
const exportPdf = config.export.pdf;
|
|
7273
7555
|
const exportEpub = config.export.epub;
|
|
7274
|
-
const [
|
|
7556
|
+
const [
|
|
7557
|
+
pages,
|
|
7558
|
+
detectedReact,
|
|
7559
|
+
usesMath,
|
|
7560
|
+
userTheme,
|
|
7561
|
+
islandDiscovery,
|
|
7562
|
+
exampleDiscovery
|
|
7563
|
+
] = await Promise.all([
|
|
7275
7564
|
context.pagesRoot ? discoverPages(context.pagesRoot) : Promise.resolve([]),
|
|
7276
7565
|
detectNeedsReact(context.root),
|
|
7566
|
+
detectUsesMath(context.root),
|
|
7277
7567
|
readOptional(context.themeFile),
|
|
7278
7568
|
discoverIslands(context.root),
|
|
7279
7569
|
discoverExamples(context.root, config.examples)
|
|
@@ -7298,7 +7588,7 @@ var generateRuntime = async (project) => {
|
|
|
7298
7588
|
const hasStaged = staged.size > 0;
|
|
7299
7589
|
const hasFilesystemSource = project.sources.some((source) => !source.staged);
|
|
7300
7590
|
const structural = await Promise.all([
|
|
7301
|
-
write(
|
|
7591
|
+
write(join17(out, "astro.config.mjs"), astroConfigTemplate({
|
|
7302
7592
|
aliases: resolveTsconfigAliases(context.root),
|
|
7303
7593
|
config,
|
|
7304
7594
|
contentRoutes: project.manifest.routes.map((route) => route.path),
|
|
@@ -7313,25 +7603,25 @@ var generateRuntime = async (project) => {
|
|
|
7313
7603
|
searchClientPath,
|
|
7314
7604
|
themePath
|
|
7315
7605
|
})),
|
|
7316
|
-
write(
|
|
7317
|
-
write(
|
|
7318
|
-
write(
|
|
7319
|
-
write(
|
|
7606
|
+
write(join17(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
|
|
7607
|
+
write(join17(out, "tsconfig.json"), runtimeTsconfigTemplate()),
|
|
7608
|
+
write(join17(srcDir, "env.d.ts"), envTemplate()),
|
|
7609
|
+
write(join17(srcDir, "content.config.ts"), contentConfigTemplate({
|
|
7320
7610
|
config,
|
|
7321
7611
|
context,
|
|
7322
7612
|
filesystem: hasFilesystemSource,
|
|
7323
7613
|
staged: hasStaged
|
|
7324
7614
|
})),
|
|
7325
|
-
write(
|
|
7615
|
+
write(join17(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
|
|
7326
7616
|
askEnabled,
|
|
7327
7617
|
exportEpub,
|
|
7328
7618
|
exportPdf,
|
|
7329
|
-
mathEnabled:
|
|
7619
|
+
mathEnabled: usesMath,
|
|
7330
7620
|
needsReact
|
|
7331
7621
|
})),
|
|
7332
|
-
write(
|
|
7333
|
-
write(
|
|
7334
|
-
write(
|
|
7622
|
+
write(join17(srcDir, "generated", "components.ts"), slotPlan.module),
|
|
7623
|
+
write(join17(srcDir, "generated", "islands.ts"), islandMapTemplate(islandDiscovery.islands)),
|
|
7624
|
+
write(join17(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples)),
|
|
7335
7625
|
write(themePath, tailwindEntryTemplate({
|
|
7336
7626
|
configTokens: `${buildThemeCss(config.theme)}${buildFontsCss(config.theme.fonts)}`,
|
|
7337
7627
|
sources: [
|
|
@@ -7342,16 +7632,16 @@ var generateRuntime = async (project) => {
|
|
|
7342
7632
|
userTheme
|
|
7343
7633
|
}))
|
|
7344
7634
|
]);
|
|
7345
|
-
await Promise.all(islandDiscovery.islands.map((island) => write(
|
|
7346
|
-
await Promise.all(slotPlan.wrappers.map((wrapper) => write(
|
|
7347
|
-
await Promise.all(exampleDiscovery.examples.map((example) => write(
|
|
7635
|
+
await Promise.all(islandDiscovery.islands.map((island) => write(join17(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island))));
|
|
7636
|
+
await Promise.all(slotPlan.wrappers.map((wrapper) => write(join17(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content)));
|
|
7637
|
+
await Promise.all(exampleDiscovery.examples.map((example) => write(join17(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example))));
|
|
7348
7638
|
await writeAskFiles(project, srcDir, write);
|
|
7349
7639
|
await writeMcpFiles(project, mcp, write);
|
|
7350
7640
|
if (config.seo.og.enabled) {
|
|
7351
|
-
await write(
|
|
7641
|
+
await write(join17(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes));
|
|
7352
7642
|
}
|
|
7353
7643
|
if (shouldGenerateChangelog(project)) {
|
|
7354
|
-
await write(
|
|
7644
|
+
await write(join17(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
|
|
7355
7645
|
askEnabled,
|
|
7356
7646
|
exportEpub,
|
|
7357
7647
|
exportPdf,
|
|
@@ -7363,27 +7653,27 @@ var generateRuntime = async (project) => {
|
|
|
7363
7653
|
await write(searchClientPath, searchClientTemplate(config));
|
|
7364
7654
|
if (servesStaticIndex(config.search.provider)) {
|
|
7365
7655
|
const documents = await buildSearchDocuments(project);
|
|
7366
|
-
await write(
|
|
7656
|
+
await write(join17(srcDir, "generated", "search.json"), `${JSON.stringify(documents)}
|
|
7367
7657
|
`);
|
|
7368
|
-
await write(
|
|
7658
|
+
await write(join17(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
|
|
7369
7659
|
}
|
|
7370
7660
|
if (config.search.provider === "mixedbread") {
|
|
7371
|
-
await write(
|
|
7661
|
+
await write(join17(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""));
|
|
7372
7662
|
}
|
|
7373
7663
|
const rawMarkdown = await buildRawMarkdown(project);
|
|
7374
7664
|
await Promise.all([
|
|
7375
|
-
write(
|
|
7665
|
+
write(join17(srcDir, "generated", "raw-markdown.json"), `${JSON.stringify(rawMarkdown)}
|
|
7376
7666
|
`),
|
|
7377
|
-
write(
|
|
7378
|
-
write(
|
|
7667
|
+
write(join17(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate()),
|
|
7668
|
+
write(join17(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate())
|
|
7379
7669
|
]);
|
|
7380
7670
|
const feeds = buildRssFeeds(project);
|
|
7381
7671
|
if (feeds.length > 0) {
|
|
7382
7672
|
const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
|
|
7383
7673
|
await Promise.all([
|
|
7384
|
-
write(
|
|
7674
|
+
write(join17(srcDir, "generated", "rss.json"), `${JSON.stringify(feedXml)}
|
|
7385
7675
|
`),
|
|
7386
|
-
write(
|
|
7676
|
+
write(join17(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate())
|
|
7387
7677
|
]);
|
|
7388
7678
|
}
|
|
7389
7679
|
const warnings = [
|
|
@@ -7420,13 +7710,13 @@ var generateRuntime = async (project) => {
|
|
|
7420
7710
|
root: context.root
|
|
7421
7711
|
});
|
|
7422
7712
|
warnings.push(...references.warnings);
|
|
7423
|
-
await Promise.all(references.files.map((file) => write(
|
|
7713
|
+
await Promise.all(references.files.map((file) => write(join17(srcDir, "pages", file.pagePath), file.content)));
|
|
7424
7714
|
}
|
|
7425
|
-
await write(
|
|
7715
|
+
await write(join17(srcDir, "generated", "data.json"), buildRuntimeData(project));
|
|
7426
7716
|
const openApiSource2 = project.sources.find(isOpenApiSource);
|
|
7427
7717
|
await write(openapiPath, `${JSON.stringify(openApiSource2 ? openApiSource2.openApiData() : {})}
|
|
7428
7718
|
`);
|
|
7429
|
-
await write(
|
|
7719
|
+
await write(join17(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
|
|
7430
7720
|
`);
|
|
7431
7721
|
await writeStagedContent(out, staged);
|
|
7432
7722
|
await pruneOrphans(srcDir, written);
|
|
@@ -7434,7 +7724,7 @@ var generateRuntime = async (project) => {
|
|
|
7434
7724
|
};
|
|
7435
7725
|
|
|
7436
7726
|
// src/core/config.ts
|
|
7437
|
-
import { existsSync as
|
|
7727
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
|
|
7438
7728
|
|
|
7439
7729
|
// src/core/deployment-env.ts
|
|
7440
7730
|
var toUrl = (value) => {
|
|
@@ -7545,7 +7835,6 @@ var pageMetaSchema = pageMetaBaseSchema;
|
|
|
7545
7835
|
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
7546
7836
|
var folderMetaSchema = z2.object({
|
|
7547
7837
|
collapsed: z2.boolean().optional(),
|
|
7548
|
-
display: sidebarDisplaySchema.optional(),
|
|
7549
7838
|
icon: iconName.optional(),
|
|
7550
7839
|
order: z2.number().optional(),
|
|
7551
7840
|
pages: z2.array(z2.string()).optional(),
|
|
@@ -7699,14 +7988,18 @@ var sidebarItemSchema = z2.lazy(() => z2.union([
|
|
|
7699
7988
|
var fontSlug = z2.string().refine(isFontSlug, (value) => ({
|
|
7700
7989
|
message: `Unknown font "${value}". Supported fonts: ${FONT_SLUGS.join(", ")}.`
|
|
7701
7990
|
}));
|
|
7991
|
+
var perModeValueSchema = z2.union([
|
|
7992
|
+
z2.string(),
|
|
7993
|
+
z2.object({ dark: z2.string().optional(), light: z2.string().optional() }).strict()
|
|
7994
|
+
]).optional().transform((value) => typeof value === "string" ? { dark: value, light: value } : value);
|
|
7702
7995
|
var themeConfigSchema = z2.object({
|
|
7703
|
-
accent: z2.
|
|
7704
|
-
|
|
7996
|
+
accent: z2.union([
|
|
7997
|
+
z2.string(),
|
|
7998
|
+
z2.object({ dark: z2.string(), light: z2.string() }).strict()
|
|
7999
|
+
]).default("blue").transform((value) => typeof value === "string" ? { dark: value, light: value } : value),
|
|
7705
8000
|
action: z2.string().optional(),
|
|
7706
|
-
background:
|
|
7707
|
-
|
|
7708
|
-
backgroundImage: z2.string().optional(),
|
|
7709
|
-
backgroundImageDark: z2.string().optional(),
|
|
8001
|
+
background: perModeValueSchema,
|
|
8002
|
+
backgroundImage: perModeValueSchema,
|
|
7710
8003
|
fonts: z2.object({
|
|
7711
8004
|
body: fontSlug.default("inter"),
|
|
7712
8005
|
display: fontSlug.default("inter-tight"),
|
|
@@ -7785,7 +8078,11 @@ var aiConfigSchema = z2.object({
|
|
|
7785
8078
|
baseUrl: z2.string().url().optional(),
|
|
7786
8079
|
enabled: z2.boolean().default(false),
|
|
7787
8080
|
model: z2.string().default("openai/gpt-5.5"),
|
|
7788
|
-
provider: z2.enum(askAiProviders).default("gateway")
|
|
8081
|
+
provider: z2.enum(askAiProviders).default("gateway"),
|
|
8082
|
+
suggestions: z2.array(z2.object({
|
|
8083
|
+
icon: iconName.optional(),
|
|
8084
|
+
label: z2.string().min(1)
|
|
8085
|
+
}).strict()).default([])
|
|
7789
8086
|
}).strict().superRefine((value, ctx) => {
|
|
7790
8087
|
if (value.provider === "openai-compatible" && !value.baseUrl) {
|
|
7791
8088
|
ctx.addIssue({
|
|
@@ -7797,10 +8094,22 @@ var aiConfigSchema = z2.object({
|
|
|
7797
8094
|
}).optional(),
|
|
7798
8095
|
llmsTxt: z2.boolean().default(false)
|
|
7799
8096
|
}).strict();
|
|
8097
|
+
var featuredLinkSchema = z2.object({
|
|
8098
|
+
href: z2.string(),
|
|
8099
|
+
icon: iconName.optional(),
|
|
8100
|
+
label: z2.string()
|
|
8101
|
+
}).strict();
|
|
7800
8102
|
var navigationConfigSchema = z2.object({
|
|
8103
|
+
featured: z2.array(featuredLinkSchema).default([]),
|
|
7801
8104
|
repo: z2.boolean().default(true),
|
|
7802
8105
|
selectors: z2.array(navSelectorSchema).default([]),
|
|
7803
|
-
sidebar: z2.
|
|
8106
|
+
sidebar: z2.union([
|
|
8107
|
+
z2.array(sidebarItemSchema),
|
|
8108
|
+
z2.object({
|
|
8109
|
+
display: sidebarDisplaySchema.default("flat"),
|
|
8110
|
+
items: z2.array(sidebarItemSchema).optional()
|
|
8111
|
+
}).strict()
|
|
8112
|
+
]).default({}).transform((value) => Array.isArray(value) ? { display: "flat", items: value } : value),
|
|
7804
8113
|
tabs: z2.array(navTabSchema).optional()
|
|
7805
8114
|
}).strict();
|
|
7806
8115
|
var exportConfigSchema = z2.union([
|
|
@@ -7880,7 +8189,23 @@ var rssConfigSchema = z2.object({
|
|
|
7880
8189
|
limit: z2.number().int().positive().default(50),
|
|
7881
8190
|
types: z2.array(z2.string()).default(["blog", "changelog"])
|
|
7882
8191
|
}).strict();
|
|
8192
|
+
var contentSignalsObjectSchema = z2.object({
|
|
8193
|
+
aiInput: z2.boolean().default(true),
|
|
8194
|
+
aiTrain: z2.boolean().default(true),
|
|
8195
|
+
search: z2.boolean().default(true)
|
|
8196
|
+
}).strict();
|
|
8197
|
+
var contentSignalsSchema = z2.union([z2.boolean(), contentSignalsObjectSchema]).transform((value) => {
|
|
8198
|
+
if (value === true) {
|
|
8199
|
+
return contentSignalsObjectSchema.parse({});
|
|
8200
|
+
}
|
|
8201
|
+
if (value === false) {
|
|
8202
|
+
return null;
|
|
8203
|
+
}
|
|
8204
|
+
return value;
|
|
8205
|
+
});
|
|
7883
8206
|
var seoConfigSchema = z2.object({
|
|
8207
|
+
agentReadability: z2.boolean().default(true),
|
|
8208
|
+
contentSignals: contentSignalsSchema.default(true),
|
|
7884
8209
|
og: ogConfigSchema.default({}),
|
|
7885
8210
|
robots: z2.boolean().default(true),
|
|
7886
8211
|
rss: rssConfigSchema.default({}),
|
|
@@ -7906,15 +8231,13 @@ var lastModifiedConfigSchema = z2.union([
|
|
|
7906
8231
|
]);
|
|
7907
8232
|
var codeConfigSchema = z2.object({
|
|
7908
8233
|
icons: z2.boolean().default(true),
|
|
7909
|
-
inline: z2.boolean().default(false),
|
|
7910
8234
|
wrap: z2.boolean().default(false)
|
|
7911
8235
|
}).strict();
|
|
7912
8236
|
var markdownConfigSchema = z2.object({
|
|
7913
8237
|
code: codeConfigSchema.default({}),
|
|
7914
8238
|
codeBlocks: codeBlocksConfigSchema.default({}),
|
|
7915
8239
|
headingAnchors: z2.boolean().default(true),
|
|
7916
|
-
imageZoom: z2.boolean().default(true)
|
|
7917
|
-
math: z2.boolean().default(false)
|
|
8240
|
+
imageZoom: z2.boolean().default(true)
|
|
7918
8241
|
}).strict();
|
|
7919
8242
|
var openapiSourceSchema = z2.object({
|
|
7920
8243
|
label: z2.string().optional(),
|
|
@@ -8000,7 +8323,7 @@ var loadConfig = async (root, options = {}) => {
|
|
|
8000
8323
|
}
|
|
8001
8324
|
const parsed = blumeConfigSchema.safeParse(raw ?? {});
|
|
8002
8325
|
if (!parsed.success) {
|
|
8003
|
-
const source = configFile &&
|
|
8326
|
+
const source = configFile && existsSync11(configFile) ? readFileSync7(configFile, "utf-8") : undefined;
|
|
8004
8327
|
const diagnostics = diagnosticsFromZod(parsed.error, {
|
|
8005
8328
|
code: "BLUME_CONFIG_INVALID",
|
|
8006
8329
|
file: configFile ?? undefined,
|
|
@@ -8091,7 +8414,6 @@ var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
8091
8414
|
group.icon = meta.icon ?? group.icon;
|
|
8092
8415
|
group.order = meta.order ?? group.order;
|
|
8093
8416
|
group.collapsed = meta.collapsed ?? group.collapsed;
|
|
8094
|
-
group.display = meta.display ?? group.display;
|
|
8095
8417
|
if (meta.pages) {
|
|
8096
8418
|
const rank = new Map(meta.pages.map((key, i) => [key, i]));
|
|
8097
8419
|
for (const child of group.children) {
|
|
@@ -8121,7 +8443,15 @@ var sortNodes = (nodes) => {
|
|
|
8121
8443
|
}
|
|
8122
8444
|
}
|
|
8123
8445
|
};
|
|
8124
|
-
var
|
|
8446
|
+
var hoistPages = (nodes) => {
|
|
8447
|
+
const pages = nodes.filter((node) => node.kind === "page");
|
|
8448
|
+
const groups = nodes.filter((node) => node.kind === "group");
|
|
8449
|
+
nodes.splice(0, nodes.length, ...pages, ...groups);
|
|
8450
|
+
for (const group of groups) {
|
|
8451
|
+
hoistPages(group.children);
|
|
8452
|
+
}
|
|
8453
|
+
};
|
|
8454
|
+
var toNavNode = (node, display) => {
|
|
8125
8455
|
if (node.kind === "page") {
|
|
8126
8456
|
return {
|
|
8127
8457
|
badge: node.badge,
|
|
@@ -8135,16 +8465,16 @@ var toNavNode = (node) => {
|
|
|
8135
8465
|
};
|
|
8136
8466
|
}
|
|
8137
8467
|
return {
|
|
8138
|
-
children: node.children.map(toNavNode),
|
|
8468
|
+
children: node.children.map((child) => toNavNode(child, display)),
|
|
8139
8469
|
collapsed: node.collapsed,
|
|
8140
|
-
display
|
|
8470
|
+
display,
|
|
8141
8471
|
icon: node.icon,
|
|
8142
8472
|
kind: "group",
|
|
8143
8473
|
label: node.label,
|
|
8144
8474
|
path: node.routePath
|
|
8145
8475
|
};
|
|
8146
8476
|
};
|
|
8147
|
-
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
8477
|
+
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display) => {
|
|
8148
8478
|
const root = createGroup("", "", "", 0);
|
|
8149
8479
|
for (const page of pages) {
|
|
8150
8480
|
if (page.meta.sidebar.hidden) {
|
|
@@ -8175,7 +8505,10 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
8175
8505
|
}
|
|
8176
8506
|
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix);
|
|
8177
8507
|
sortNodes(root.children);
|
|
8178
|
-
|
|
8508
|
+
if (display === "flat") {
|
|
8509
|
+
hoistPages(root.children);
|
|
8510
|
+
}
|
|
8511
|
+
return root.children.map((child) => toNavNode(child, display));
|
|
8179
8512
|
};
|
|
8180
8513
|
var normalizeRef = (ref) => {
|
|
8181
8514
|
if (ref === "index") {
|
|
@@ -8192,7 +8525,7 @@ var routeForRef = (ref, byRoute) => {
|
|
|
8192
8525
|
const normalized = normalizeRef(ref);
|
|
8193
8526
|
return byRoute.get(normalized)?.route ?? normalized;
|
|
8194
8527
|
};
|
|
8195
|
-
var buildConfigSidebar = (items, byRoute) => {
|
|
8528
|
+
var buildConfigSidebar = (items, byRoute, display) => {
|
|
8196
8529
|
const nodes = [];
|
|
8197
8530
|
for (const item of items) {
|
|
8198
8531
|
if (typeof item === "string") {
|
|
@@ -8214,10 +8547,10 @@ var buildConfigSidebar = (items, byRoute) => {
|
|
|
8214
8547
|
if (item.items) {
|
|
8215
8548
|
nodes.push({
|
|
8216
8549
|
badge: item.badge,
|
|
8217
|
-
children: buildConfigSidebar(item.items, byRoute),
|
|
8550
|
+
children: buildConfigSidebar(item.items, byRoute, display),
|
|
8218
8551
|
collapsed: item.collapsed,
|
|
8219
8552
|
directory: item.directory,
|
|
8220
|
-
display: item.display,
|
|
8553
|
+
display: item.display ?? display,
|
|
8221
8554
|
icon: item.icon,
|
|
8222
8555
|
kind: "group",
|
|
8223
8556
|
label: item.label,
|
|
@@ -8252,8 +8585,10 @@ var buildConfigSidebar = (items, byRoute) => {
|
|
|
8252
8585
|
return nodes;
|
|
8253
8586
|
};
|
|
8254
8587
|
var buildNavigation = (pages, options) => {
|
|
8588
|
+
const featured = options.featured ?? [];
|
|
8255
8589
|
const selectors = options.selectors ?? [];
|
|
8256
8590
|
const tabs = options.tabs ?? [];
|
|
8591
|
+
const display = options.display ?? "flat";
|
|
8257
8592
|
const metaPrefix = options.metaPrefix ?? "";
|
|
8258
8593
|
const sharedFolderMeta = options.sharedFolderMeta ?? new Map;
|
|
8259
8594
|
const byRoute = new Map(pages.map((page) => [
|
|
@@ -8262,14 +8597,16 @@ var buildNavigation = (pages, options) => {
|
|
|
8262
8597
|
]));
|
|
8263
8598
|
if (options.sidebar) {
|
|
8264
8599
|
return {
|
|
8600
|
+
featured,
|
|
8265
8601
|
selectors,
|
|
8266
|
-
sidebar: buildConfigSidebar(options.sidebar, byRoute),
|
|
8602
|
+
sidebar: buildConfigSidebar(options.sidebar, byRoute, display),
|
|
8267
8603
|
tabs
|
|
8268
8604
|
};
|
|
8269
8605
|
}
|
|
8270
8606
|
return {
|
|
8607
|
+
featured,
|
|
8271
8608
|
selectors,
|
|
8272
|
-
sidebar: buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix),
|
|
8609
|
+
sidebar: buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display),
|
|
8273
8610
|
tabs
|
|
8274
8611
|
};
|
|
8275
8612
|
};
|
|
@@ -8327,26 +8664,31 @@ var buildContentGraph = (pages, options) => {
|
|
|
8327
8664
|
localePages = [...real, ...filled];
|
|
8328
8665
|
}
|
|
8329
8666
|
navigationByLocale[code] = buildNavigation(localePages, {
|
|
8667
|
+
display: options.navigation.sidebar.display,
|
|
8668
|
+
featured: options.navigation.featured,
|
|
8330
8669
|
folderMeta: options.folderMeta,
|
|
8331
8670
|
metaPrefix: i18n.parser === "dir" && code !== i18n.defaultLocale ? code : "",
|
|
8332
8671
|
refByLogical: true,
|
|
8333
8672
|
selectors: options.navigation.selectors,
|
|
8334
8673
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
8335
|
-
sidebar: options.navigation.sidebar,
|
|
8674
|
+
sidebar: options.navigation.sidebar.items,
|
|
8336
8675
|
tabs
|
|
8337
8676
|
});
|
|
8338
8677
|
}
|
|
8339
8678
|
navigation = navigationByLocale[i18n.defaultLocale] ?? {
|
|
8679
|
+
featured: [],
|
|
8340
8680
|
selectors: [],
|
|
8341
8681
|
sidebar: [],
|
|
8342
8682
|
tabs: []
|
|
8343
8683
|
};
|
|
8344
8684
|
} else {
|
|
8345
8685
|
navigation = buildNavigation(pages, {
|
|
8686
|
+
display: options.navigation.sidebar.display,
|
|
8687
|
+
featured: options.navigation.featured,
|
|
8346
8688
|
folderMeta: options.folderMeta,
|
|
8347
8689
|
selectors: options.navigation.selectors,
|
|
8348
8690
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
8349
|
-
sidebar: options.navigation.sidebar,
|
|
8691
|
+
sidebar: options.navigation.sidebar.items,
|
|
8350
8692
|
tabs: options.navigation.tabs
|
|
8351
8693
|
});
|
|
8352
8694
|
}
|
|
@@ -8415,7 +8757,7 @@ var gitLastModifiedTimes = (root, contentRoot, sourcePaths) => {
|
|
|
8415
8757
|
};
|
|
8416
8758
|
|
|
8417
8759
|
// src/core/meta.ts
|
|
8418
|
-
import { basename as basename3, dirname as
|
|
8760
|
+
import { basename as basename3, dirname as dirname9, relative as relative9 } from "pathe";
|
|
8419
8761
|
import { glob as glob5 } from "tinyglobby";
|
|
8420
8762
|
var META_FILES = [
|
|
8421
8763
|
"**/meta.ts",
|
|
@@ -8445,7 +8787,7 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
8445
8787
|
const shared = new Map;
|
|
8446
8788
|
const diagnostics = [];
|
|
8447
8789
|
for (const entry of loaded) {
|
|
8448
|
-
const dir = relative9(contentRoot,
|
|
8790
|
+
const dir = relative9(contentRoot, dirname9(entry.file));
|
|
8449
8791
|
if (!entry.ok) {
|
|
8450
8792
|
diagnostics.push({
|
|
8451
8793
|
code: "BLUME_META_LOAD_FAILED",
|
|
@@ -8470,7 +8812,7 @@ var discoverFolderMeta = async (contentRoot) => {
|
|
|
8470
8812
|
};
|
|
8471
8813
|
|
|
8472
8814
|
// src/core/sources/normalize.ts
|
|
8473
|
-
import { existsSync as
|
|
8815
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
|
|
8474
8816
|
import GithubSlugger from "github-slugger";
|
|
8475
8817
|
import { extname as extname4 } from "pathe";
|
|
8476
8818
|
var NUMERIC_PREFIX2 = /^\d+[-_.]/u;
|
|
@@ -8604,7 +8946,7 @@ var normalizeEntry2 = (entry, ctx) => {
|
|
|
8604
8946
|
const ext = format === "mdx" ? ".mdx" : ".md";
|
|
8605
8947
|
const result = pageMetaSchema.safeParse(entry.data);
|
|
8606
8948
|
if (!result.success) {
|
|
8607
|
-
const source = entry.raw ?? (entry.sourcePath &&
|
|
8949
|
+
const source = entry.raw ?? (entry.sourcePath && existsSync12(entry.sourcePath) ? readFileSync8(entry.sourcePath, "utf-8") : undefined);
|
|
8608
8950
|
return {
|
|
8609
8951
|
diagnostics: diagnosticsFromZod(result.error, {
|
|
8610
8952
|
code: "BLUME_FRONTMATTER_INVALID",
|
|
@@ -8655,35 +8997,20 @@ var normalizeEntry2 = (entry, ctx) => {
|
|
|
8655
8997
|
};
|
|
8656
8998
|
|
|
8657
8999
|
// src/core/sources/resolve.ts
|
|
8658
|
-
import { join as
|
|
9000
|
+
import { join as join22 } from "pathe";
|
|
8659
9001
|
|
|
8660
9002
|
// src/core/sources/filesystem.ts
|
|
8661
|
-
import { existsSync as
|
|
9003
|
+
import { existsSync as existsSync13, watch as fsWatch } from "node:fs";
|
|
8662
9004
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
8663
|
-
import { extname as extname5, isAbsolute as isAbsolute7, join as
|
|
9005
|
+
import { extname as extname5, isAbsolute as isAbsolute7, join as join18, relative as relative10, resolve as resolve5 } from "pathe";
|
|
8664
9006
|
import { glob as glob6 } from "tinyglobby";
|
|
8665
|
-
|
|
8666
|
-
// src/core/sources/watch.ts
|
|
8667
|
-
var BLUME_WATCH_IGNORE_DIRS = [".blume", ".git", "node_modules"];
|
|
8668
|
-
var excludeDirSegments = (patterns) => patterns.map((pattern) => /^(?<dir>[^*/]+)\/\*\*$/u.exec(pattern)?.groups?.dir).filter((dir) => dir !== undefined);
|
|
8669
|
-
var ignoringWatchListener = (onChange, ignoreDirs = BLUME_WATCH_IGNORE_DIRS) => {
|
|
8670
|
-
const ignore = new Set(ignoreDirs);
|
|
8671
|
-
return (_event, filename) => {
|
|
8672
|
-
if (typeof filename === "string" && filename.split(/[/\\]/u).some((segment) => ignore.has(segment))) {
|
|
8673
|
-
return;
|
|
8674
|
-
}
|
|
8675
|
-
onChange();
|
|
8676
|
-
};
|
|
8677
|
-
};
|
|
8678
|
-
|
|
8679
|
-
// src/core/sources/filesystem.ts
|
|
8680
9007
|
var filesystemSource = (options) => {
|
|
8681
|
-
const contentRoot = isAbsolute7(options.root) ? options.root :
|
|
9008
|
+
const contentRoot = isAbsolute7(options.root) ? options.root : join18(resolve5(options.projectRoot), options.root);
|
|
8682
9009
|
const load2 = async () => {
|
|
8683
9010
|
const files = await glob6(options.include, {
|
|
8684
9011
|
absolute: true,
|
|
8685
9012
|
cwd: contentRoot,
|
|
8686
|
-
ignore: options.exclude,
|
|
9013
|
+
ignore: [...options.exclude, ...baselineScanIgnore()],
|
|
8687
9014
|
onlyFiles: true
|
|
8688
9015
|
});
|
|
8689
9016
|
files.sort();
|
|
@@ -8702,7 +9029,7 @@ var filesystemSource = (options) => {
|
|
|
8702
9029
|
return { diagnostics: [], entries };
|
|
8703
9030
|
};
|
|
8704
9031
|
const validate = () => {
|
|
8705
|
-
if (!
|
|
9032
|
+
if (!existsSync13(contentRoot)) {
|
|
8706
9033
|
throw new BlumeError({
|
|
8707
9034
|
code: options.missingCode ?? "BLUME_CONTENT_ROOT_MISSING",
|
|
8708
9035
|
file: contentRoot,
|
|
@@ -8717,7 +9044,7 @@ var filesystemSource = (options) => {
|
|
|
8717
9044
|
...excludeDirSegments(options.exclude)
|
|
8718
9045
|
]);
|
|
8719
9046
|
const watch = (onChange) => {
|
|
8720
|
-
if (!
|
|
9047
|
+
if (!existsSync13(contentRoot)) {
|
|
8721
9048
|
return () => {};
|
|
8722
9049
|
}
|
|
8723
9050
|
const watcher = fsWatch(contentRoot, { recursive: true }, ignoringWatchListener(onChange, watchIgnoreDirs));
|
|
@@ -8728,7 +9055,7 @@ var filesystemSource = (options) => {
|
|
|
8728
9055
|
load: load2,
|
|
8729
9056
|
name: options.name,
|
|
8730
9057
|
prefix: options.prefix,
|
|
8731
|
-
read: (ref) => readFile11(
|
|
9058
|
+
read: (ref) => readFile11(join18(contentRoot, ref), "utf-8"),
|
|
8732
9059
|
staged: false,
|
|
8733
9060
|
validate,
|
|
8734
9061
|
watch
|
|
@@ -9018,11 +9345,11 @@ var mdxRemoteSource = (options, ctx) => {
|
|
|
9018
9345
|
|
|
9019
9346
|
// src/core/sources/notion.ts
|
|
9020
9347
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
9021
|
-
import { join as
|
|
9348
|
+
import { join as join20 } from "pathe";
|
|
9022
9349
|
|
|
9023
9350
|
// src/core/sources/assets.ts
|
|
9024
|
-
import { mkdir as
|
|
9025
|
-
import { extname as extname6, join as
|
|
9351
|
+
import { mkdir as mkdir6, writeFile as writeFile6 } from "node:fs/promises";
|
|
9352
|
+
import { extname as extname6, join as join19 } from "pathe";
|
|
9026
9353
|
var MD_IMAGE = /!\[(?<alt>[^\]]*)\]\((?<url>[^)\s]+)\)/gu;
|
|
9027
9354
|
var REMOTE = /^https?:\/\//u;
|
|
9028
9355
|
var SAFE_EXT = /^\.[a-z0-9]+$/iu;
|
|
@@ -9050,8 +9377,8 @@ var materializeAssets = async (markdown, ctx) => {
|
|
|
9050
9377
|
}
|
|
9051
9378
|
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
9052
9379
|
const file = `${hashText(url)}${extFor(url)}`;
|
|
9053
|
-
await
|
|
9054
|
-
await writeFile6(
|
|
9380
|
+
await mkdir6(ctx.assetsDir, { recursive: true });
|
|
9381
|
+
await writeFile6(join19(ctx.assetsDir, file), bytes);
|
|
9055
9382
|
rewrites.set(url, `${ctx.assetsBaseUrl}/${file}`);
|
|
9056
9383
|
} catch (error) {
|
|
9057
9384
|
diagnostics.push({
|
|
@@ -9167,8 +9494,8 @@ ${text}
|
|
|
9167
9494
|
};
|
|
9168
9495
|
var notionSource = (options, ctx) => {
|
|
9169
9496
|
const props = options.properties ?? {};
|
|
9170
|
-
const cache = snapshotCache(ctx?.cacheDir ??
|
|
9171
|
-
const assetsDir = ctx?.assetsDir ??
|
|
9497
|
+
const cache = snapshotCache(ctx?.cacheDir ?? join20(".blume", "cache", options.name));
|
|
9498
|
+
const assetsDir = ctx?.assetsDir ?? join20(".blume", "public", "blume-assets", options.name);
|
|
9172
9499
|
const assetsBaseUrl = ctx?.assetsBaseUrl ?? `/blume-assets/${options.name}`;
|
|
9173
9500
|
let snapshot = new Map;
|
|
9174
9501
|
const resolveClient = async () => {
|
|
@@ -9336,7 +9663,7 @@ ${rendered.join(`
|
|
|
9336
9663
|
};
|
|
9337
9664
|
|
|
9338
9665
|
// src/core/sources/sanity.ts
|
|
9339
|
-
import { join as
|
|
9666
|
+
import { join as join21 } from "pathe";
|
|
9340
9667
|
|
|
9341
9668
|
// src/core/sources/portable-text.ts
|
|
9342
9669
|
var HEADING_STYLES = {
|
|
@@ -9475,7 +9802,7 @@ var resolveClient = async (options, preview) => {
|
|
|
9475
9802
|
};
|
|
9476
9803
|
var sanitySource = (options, ctx) => {
|
|
9477
9804
|
const fields = options.fields ?? {};
|
|
9478
|
-
const cache = snapshotCache(ctx?.cacheDir ??
|
|
9805
|
+
const cache = snapshotCache(ctx?.cacheDir ?? join21(".blume", "cache", options.name));
|
|
9479
9806
|
let snapshot = new Map;
|
|
9480
9807
|
const toEntry2 = (doc) => {
|
|
9481
9808
|
const slugValue = asString(getPath(doc, fields.slug ?? "slug.current")) ?? asString(doc._id) ?? "untitled";
|
|
@@ -9550,8 +9877,8 @@ var uniqueNamer = () => {
|
|
|
9550
9877
|
};
|
|
9551
9878
|
var sourceContext = (context, name, runtime) => ({
|
|
9552
9879
|
assetsBaseUrl: `/blume-assets/${name}`,
|
|
9553
|
-
assetsDir:
|
|
9554
|
-
cacheDir:
|
|
9880
|
+
assetsDir: join22(context.outDir, "public", "blume-assets", name),
|
|
9881
|
+
cacheDir: join22(context.outDir, "cache", name),
|
|
9555
9882
|
mode: runtime.mode,
|
|
9556
9883
|
preview: runtime.preview,
|
|
9557
9884
|
projectRoot: context.root,
|
|
@@ -9741,8 +10068,8 @@ var scanProject = async (root, options = {}) => {
|
|
|
9741
10068
|
};
|
|
9742
10069
|
|
|
9743
10070
|
// src/cli/env.ts
|
|
9744
|
-
import { existsSync as
|
|
9745
|
-
import { dirname as
|
|
10071
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
10072
|
+
import { dirname as dirname10, join as join23, resolve as resolve6 } from "pathe";
|
|
9746
10073
|
var ENV_LINE = /^\s*(?:export\s+)?(?<key>[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?<value>.*?)\s*$/u;
|
|
9747
10074
|
var DOUBLE_QUOTED2 = /^"(?<body>[\s\S]*)"$/u;
|
|
9748
10075
|
var SINGLE_QUOTED = /^'(?<body>[\s\S]*)'$/u;
|
|
@@ -9780,7 +10107,7 @@ var applyEnv = (parsed) => {
|
|
|
9780
10107
|
};
|
|
9781
10108
|
var loadFile = (path) => {
|
|
9782
10109
|
try {
|
|
9783
|
-
if (
|
|
10110
|
+
if (existsSync14(path)) {
|
|
9784
10111
|
applyEnv(parseEnv(readFileSync9(path, "utf-8")));
|
|
9785
10112
|
}
|
|
9786
10113
|
} catch {}
|
|
@@ -9789,10 +10116,10 @@ var loadEnvFiles = (startDir) => {
|
|
|
9789
10116
|
let dir = resolve6(startDir);
|
|
9790
10117
|
let done = false;
|
|
9791
10118
|
while (!done) {
|
|
9792
|
-
loadFile(
|
|
9793
|
-
loadFile(
|
|
9794
|
-
const parent =
|
|
9795
|
-
done =
|
|
10119
|
+
loadFile(join23(dir, ".env.local"));
|
|
10120
|
+
loadFile(join23(dir, ".env"));
|
|
10121
|
+
const parent = dirname10(dir);
|
|
10122
|
+
done = existsSync14(join23(dir, ".git")) || parent === dir;
|
|
9796
10123
|
dir = parent;
|
|
9797
10124
|
}
|
|
9798
10125
|
};
|
|
@@ -9922,24 +10249,24 @@ var emitRedirectFiles = async (config, distDir) => {
|
|
|
9922
10249
|
if (redirects.length === 0 || config.deployment.output !== "static") {
|
|
9923
10250
|
return;
|
|
9924
10251
|
}
|
|
9925
|
-
await writeFile7(
|
|
10252
|
+
await writeFile7(join24(distDir, "blume-redirects.json"), buildRedirectManifest(redirects), "utf-8");
|
|
9926
10253
|
const platformFiles = [
|
|
9927
10254
|
{ content: buildNetlifyRedirects(redirects), name: "_redirects" },
|
|
9928
10255
|
{ content: buildVercelConfig(redirects), name: "vercel.json" }
|
|
9929
10256
|
];
|
|
9930
|
-
await Promise.all(platformFiles.map((file) =>
|
|
10257
|
+
await Promise.all(platformFiles.map((file) => existsSync15(join24(distDir, file.name)) ? Promise.resolve() : writeFile7(join24(distDir, file.name), file.content, "utf-8")));
|
|
9931
10258
|
logger.success(`Emitted redirect files for ${redirects.length} redirect(s)`);
|
|
9932
10259
|
};
|
|
9933
10260
|
var formatBytes = (bytes) => bytes < 1024 ? `${bytes} B` : `${(bytes / 1024).toFixed(bytes < 1024 * 100 ? 1 : 0)} kB`;
|
|
9934
10261
|
var astroAssets = async (distDir, ext) => {
|
|
9935
|
-
const astroDir =
|
|
9936
|
-
if (!
|
|
10262
|
+
const astroDir = join24(distDir, "_astro");
|
|
10263
|
+
if (!existsSync15(astroDir)) {
|
|
9937
10264
|
return [];
|
|
9938
10265
|
}
|
|
9939
10266
|
const entries = await readdir(astroDir);
|
|
9940
10267
|
const files = entries.filter((name) => name.endsWith(`.${ext}`));
|
|
9941
10268
|
const sized = await Promise.all(files.map(async (name) => {
|
|
9942
|
-
const info = await stat(
|
|
10269
|
+
const info = await stat(join24(astroDir, name));
|
|
9943
10270
|
return { name, size: info.size };
|
|
9944
10271
|
}));
|
|
9945
10272
|
return sized.toSorted((a, b) => b.size - a.size);
|
|
@@ -9995,21 +10322,27 @@ var publishBuildArtifacts = async (project, distDir, args) => {
|
|
|
9995
10322
|
if (project.config.ai.llmsTxt) {
|
|
9996
10323
|
const { index, full } = await buildLlmsFiles(project);
|
|
9997
10324
|
await Promise.all([
|
|
9998
|
-
writeFile7(
|
|
9999
|
-
writeFile7(
|
|
10325
|
+
writeFile7(join24(distDir, "llms.txt"), index, "utf-8"),
|
|
10326
|
+
writeFile7(join24(distDir, "llms-full.txt"), full, "utf-8")
|
|
10000
10327
|
]);
|
|
10001
10328
|
logger.success("Generated llms.txt and llms-full.txt");
|
|
10002
10329
|
}
|
|
10003
10330
|
const sitemap = buildSitemap(project);
|
|
10004
|
-
if (sitemap && !
|
|
10005
|
-
await writeFile7(
|
|
10331
|
+
if (sitemap && !existsSync15(join24(distDir, "sitemap.xml"))) {
|
|
10332
|
+
await writeFile7(join24(distDir, "sitemap.xml"), sitemap, "utf-8");
|
|
10006
10333
|
logger.success("Generated sitemap.xml");
|
|
10007
10334
|
}
|
|
10008
10335
|
const robots = buildRobots(project);
|
|
10009
|
-
if (robots && !
|
|
10010
|
-
await writeFile7(
|
|
10336
|
+
if (robots && !existsSync15(join24(distDir, "robots.txt"))) {
|
|
10337
|
+
await writeFile7(join24(distDir, "robots.txt"), robots, "utf-8");
|
|
10011
10338
|
logger.success("Generated robots.txt");
|
|
10012
10339
|
}
|
|
10340
|
+
const agentReadability = buildAgentReadability(project);
|
|
10341
|
+
if (agentReadability && !existsSync15(join24(distDir, "agent-readability.json"))) {
|
|
10342
|
+
await writeFile7(join24(distDir, "agent-readability.json"), `${JSON.stringify(agentReadability, null, 2)}
|
|
10343
|
+
`, "utf-8");
|
|
10344
|
+
logger.success("Generated agent-readability.json");
|
|
10345
|
+
}
|
|
10013
10346
|
await emitRedirectFiles(project.config, distDir);
|
|
10014
10347
|
const { config } = project;
|
|
10015
10348
|
const features = serverFeatures(config);
|
|
@@ -10021,6 +10354,7 @@ var publishBuildArtifacts = async (project, distDir, args) => {
|
|
|
10021
10354
|
`Redirects ${config.redirects.length}`,
|
|
10022
10355
|
`Sitemap ${sitemap ? "yes" : "no (set deployment.site)"}`,
|
|
10023
10356
|
`Robots ${robots ? "yes" : "no"}`,
|
|
10357
|
+
`Agent JSON ${agentReadability ? "yes" : "no"}`,
|
|
10024
10358
|
`LLM files ${config.ai.llmsTxt ? "yes" : "no"}`,
|
|
10025
10359
|
`Server features ${features.length > 0 ? features.join(", ") : "none"}`
|
|
10026
10360
|
].join(`
|
|
@@ -10106,21 +10440,26 @@ var buildCommand = defineCommand2({
|
|
|
10106
10440
|
logLevel: "info",
|
|
10107
10441
|
root: project.context.outDir
|
|
10108
10442
|
});
|
|
10109
|
-
const distDir = project.context.distDir ??
|
|
10443
|
+
const distDir = project.context.distDir ?? join24(root, "dist");
|
|
10110
10444
|
if (runtimeDir) {
|
|
10111
10445
|
logger.success(`Isolated build OK — output at ${distDir} (not published).`);
|
|
10112
10446
|
return;
|
|
10113
10447
|
}
|
|
10114
|
-
await
|
|
10448
|
+
const surfaced = await surfaceAdapterOutput(project.config, project.context);
|
|
10449
|
+
if (surfaced.moved) {
|
|
10450
|
+
logger.success(`Surfaced ${project.config.deployment.adapter} output to ${surfaced.to}`);
|
|
10451
|
+
await ensureGitignore(root, [surfaced.ignore]);
|
|
10452
|
+
}
|
|
10453
|
+
await publishBuildArtifacts(project, deployStaticDir(project.config, project.context), args);
|
|
10115
10454
|
}
|
|
10116
10455
|
});
|
|
10117
10456
|
|
|
10118
10457
|
// src/cli/commands/check.ts
|
|
10119
|
-
import { existsSync as
|
|
10458
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
10120
10459
|
import { check } from "@astrojs/check";
|
|
10121
10460
|
import { sync } from "astro";
|
|
10122
10461
|
import { defineCommand as defineCommand3 } from "citty";
|
|
10123
|
-
import { join as
|
|
10462
|
+
import { join as join25 } from "pathe";
|
|
10124
10463
|
var checkCommand = defineCommand3({
|
|
10125
10464
|
args: {
|
|
10126
10465
|
isolated: {
|
|
@@ -10156,13 +10495,13 @@ var checkCommand = defineCommand3({
|
|
|
10156
10495
|
});
|
|
10157
10496
|
const { outDir } = project.context;
|
|
10158
10497
|
await sync({ logLevel: "warn", root: outDir });
|
|
10159
|
-
const tsconfig =
|
|
10498
|
+
const tsconfig = join25(root, "tsconfig.json");
|
|
10160
10499
|
logger.start(`Type-checking ${project.graph.pages.length} page(s)`);
|
|
10161
10500
|
const failed = await check({
|
|
10162
10501
|
minimumFailingSeverity: "error",
|
|
10163
10502
|
minimumSeverity: "hint",
|
|
10164
10503
|
root: outDir,
|
|
10165
|
-
tsconfig:
|
|
10504
|
+
tsconfig: existsSync16(tsconfig) ? tsconfig : undefined,
|
|
10166
10505
|
watch: false
|
|
10167
10506
|
});
|
|
10168
10507
|
if (failed) {
|
|
@@ -10279,6 +10618,14 @@ var devCommand = defineCommand4({
|
|
|
10279
10618
|
const explicitPort = parsePort(args.port);
|
|
10280
10619
|
const port = explicitPort ?? 4321;
|
|
10281
10620
|
const devServerUrl = `http://localhost:${port}`;
|
|
10621
|
+
const outDir = resolveRuntimeDir(root);
|
|
10622
|
+
const running = readDevLock(outDir);
|
|
10623
|
+
if (running) {
|
|
10624
|
+
logger.error(`A \`blume dev\` server is already running${describeDevLock(running)} in this project. Reuse that server instead of starting a second one — two dev servers would corrupt the shared .blume dir. If it crashed, delete .blume/dev.lock.`);
|
|
10625
|
+
process.exit(1);
|
|
10626
|
+
}
|
|
10627
|
+
const releaseLock = acquireDevLock(outDir, port);
|
|
10628
|
+
process.on("exit", releaseLock);
|
|
10282
10629
|
const project = await prepareProject({
|
|
10283
10630
|
devServerUrl,
|
|
10284
10631
|
mode: "dev",
|
|
@@ -10287,12 +10634,6 @@ var devCommand = defineCommand4({
|
|
|
10287
10634
|
root,
|
|
10288
10635
|
strict: args.strict
|
|
10289
10636
|
});
|
|
10290
|
-
if (isDevLocked(project.context.outDir)) {
|
|
10291
|
-
logger.error("Another `blume dev` is already running in this project; two dev servers would corrupt the shared .blume dir. Stop the other one first (or delete .blume/dev.lock if it crashed).");
|
|
10292
|
-
process.exit(1);
|
|
10293
|
-
}
|
|
10294
|
-
const releaseLock = acquireDevLock(project.context.outDir);
|
|
10295
|
-
process.on("exit", releaseLock);
|
|
10296
10637
|
const server = await dev({
|
|
10297
10638
|
logLevel: args.debug ? "debug" : "info",
|
|
10298
10639
|
root: project.context.outDir,
|
|
@@ -10302,6 +10643,9 @@ var devCommand = defineCommand4({
|
|
|
10302
10643
|
port: explicitPort
|
|
10303
10644
|
}
|
|
10304
10645
|
});
|
|
10646
|
+
if (server.address.port !== port) {
|
|
10647
|
+
updateDevLockPort(outDir, server.address.port);
|
|
10648
|
+
}
|
|
10305
10649
|
showBlumeErrorOverlay(project.diagnostics);
|
|
10306
10650
|
const runRegenerate = coalescedRunner(async () => {
|
|
10307
10651
|
try {
|
|
@@ -10429,12 +10773,12 @@ var doctorCommand = defineCommand5({
|
|
|
10429
10773
|
// src/cli/commands/eject.ts
|
|
10430
10774
|
import { readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
|
|
10431
10775
|
import { defineCommand as defineCommand6 } from "citty";
|
|
10432
|
-
import { join as
|
|
10776
|
+
import { join as join27, relative as relative12 } from "pathe";
|
|
10433
10777
|
|
|
10434
10778
|
// src/registry/eject.ts
|
|
10435
|
-
import { existsSync as
|
|
10436
|
-
import { cp, mkdir as
|
|
10437
|
-
import { join as
|
|
10779
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
10780
|
+
import { cp as cp2, mkdir as mkdir7, readFile as readFile12, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
|
|
10781
|
+
import { join as join26, relative as relative11 } from "pathe";
|
|
10438
10782
|
var POSIX = (path) => path.split("\\").join("/");
|
|
10439
10783
|
var ejectOpenApiData = (project) => {
|
|
10440
10784
|
const source = project.sources.find(isOpenApiSource);
|
|
@@ -10449,14 +10793,14 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
10449
10793
|
const files = [
|
|
10450
10794
|
{
|
|
10451
10795
|
content: askEndpointTemplate(resolveAskBackend(ask), grounded),
|
|
10452
|
-
path:
|
|
10796
|
+
path: join26(srcDir, "pages", "api", "ask.ts")
|
|
10453
10797
|
}
|
|
10454
10798
|
];
|
|
10455
10799
|
if (grounded) {
|
|
10456
10800
|
files.push({
|
|
10457
10801
|
content: `${JSON.stringify(await buildAskData(project))}
|
|
10458
10802
|
`,
|
|
10459
|
-
path:
|
|
10803
|
+
path: join26(genDir, "ask-data.json")
|
|
10460
10804
|
});
|
|
10461
10805
|
}
|
|
10462
10806
|
return files;
|
|
@@ -10464,14 +10808,23 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
10464
10808
|
var eject = async (root) => {
|
|
10465
10809
|
const project = await scanProject(root, { mode: "build" });
|
|
10466
10810
|
const { context, config } = project;
|
|
10467
|
-
const srcDir =
|
|
10468
|
-
const genDir =
|
|
10811
|
+
const srcDir = join26(root, "src");
|
|
10812
|
+
const genDir = join26(srcDir, "generated");
|
|
10469
10813
|
const askEnabled = config.ai.ask?.enabled ?? false;
|
|
10470
10814
|
const exportPdf = config.export.pdf;
|
|
10471
10815
|
const exportEpub = config.export.epub;
|
|
10472
|
-
const [
|
|
10816
|
+
const [
|
|
10817
|
+
pages,
|
|
10818
|
+
needsReactRaw,
|
|
10819
|
+
usesMath,
|
|
10820
|
+
userTheme,
|
|
10821
|
+
rawMarkdown,
|
|
10822
|
+
islands,
|
|
10823
|
+
examples
|
|
10824
|
+
] = await Promise.all([
|
|
10473
10825
|
context.pagesRoot ? discoverPages(context.pagesRoot) : Promise.resolve([]),
|
|
10474
10826
|
detectNeedsReact(root),
|
|
10827
|
+
detectUsesMath(root),
|
|
10475
10828
|
context.themeFile ? readFile12(context.themeFile, "utf-8") : Promise.resolve(""),
|
|
10476
10829
|
buildRawMarkdown(project),
|
|
10477
10830
|
discoverIslands(root),
|
|
@@ -10514,14 +10867,14 @@ var eject = async (root) => {
|
|
|
10514
10867
|
searchClientPath: "./src/generated/search-client.ts",
|
|
10515
10868
|
themePath: "./src/generated/app.css"
|
|
10516
10869
|
}),
|
|
10517
|
-
path:
|
|
10870
|
+
path: join26(root, "astro.config.mjs")
|
|
10518
10871
|
},
|
|
10519
10872
|
{
|
|
10520
10873
|
content: runtimeTsconfigTemplate(),
|
|
10521
|
-
path:
|
|
10874
|
+
path: join26(root, "tsconfig.json"),
|
|
10522
10875
|
skipIfExists: true
|
|
10523
10876
|
},
|
|
10524
|
-
{ content: envTemplate(), path:
|
|
10877
|
+
{ content: envTemplate(), path: join26(srcDir, "env.d.ts") },
|
|
10525
10878
|
{
|
|
10526
10879
|
content: contentConfigTemplate({
|
|
10527
10880
|
config,
|
|
@@ -10529,29 +10882,29 @@ var eject = async (root) => {
|
|
|
10529
10882
|
staged: hasStaged,
|
|
10530
10883
|
stagedBase: stagedDir
|
|
10531
10884
|
}),
|
|
10532
|
-
path:
|
|
10885
|
+
path: join26(srcDir, "content.config.ts")
|
|
10533
10886
|
},
|
|
10534
10887
|
{
|
|
10535
10888
|
content: catchAllPageTemplate({
|
|
10536
10889
|
askEnabled,
|
|
10537
10890
|
exportEpub,
|
|
10538
10891
|
exportPdf,
|
|
10539
|
-
mathEnabled:
|
|
10892
|
+
mathEnabled: usesMath,
|
|
10540
10893
|
needsReact
|
|
10541
10894
|
}),
|
|
10542
|
-
path:
|
|
10895
|
+
path: join26(srcDir, "pages", "[...slug].astro")
|
|
10543
10896
|
},
|
|
10544
10897
|
{
|
|
10545
10898
|
content: planComponentSlots(componentsImport, null).module,
|
|
10546
|
-
path:
|
|
10899
|
+
path: join26(genDir, "components.ts")
|
|
10547
10900
|
},
|
|
10548
10901
|
{
|
|
10549
10902
|
content: islandMapTemplate(islands.islands),
|
|
10550
|
-
path:
|
|
10903
|
+
path: join26(genDir, "islands.ts")
|
|
10551
10904
|
},
|
|
10552
10905
|
{
|
|
10553
10906
|
content: exampleMapTemplate(examples.examples),
|
|
10554
|
-
path:
|
|
10907
|
+
path: join26(genDir, "examples.ts")
|
|
10555
10908
|
},
|
|
10556
10909
|
{
|
|
10557
10910
|
content: tailwindEntryTemplate({
|
|
@@ -10563,26 +10916,26 @@ var eject = async (root) => {
|
|
|
10563
10916
|
twoslashCss: twoslashCss(),
|
|
10564
10917
|
userTheme
|
|
10565
10918
|
}),
|
|
10566
|
-
path:
|
|
10919
|
+
path: join26(genDir, "app.css")
|
|
10567
10920
|
},
|
|
10568
|
-
{ content: buildRuntimeData(project), path:
|
|
10921
|
+
{ content: buildRuntimeData(project), path: join26(genDir, "data.json") },
|
|
10569
10922
|
{
|
|
10570
10923
|
content: `${JSON.stringify(ejectOpenApiData(project))}
|
|
10571
10924
|
`,
|
|
10572
|
-
path:
|
|
10925
|
+
path: join26(genDir, "openapi.json")
|
|
10573
10926
|
},
|
|
10574
10927
|
{
|
|
10575
10928
|
content: `${JSON.stringify(rawMarkdown)}
|
|
10576
10929
|
`,
|
|
10577
|
-
path:
|
|
10930
|
+
path: join26(genDir, "raw-markdown.json")
|
|
10578
10931
|
},
|
|
10579
10932
|
{
|
|
10580
10933
|
content: rawMarkdownEndpointTemplate(),
|
|
10581
|
-
path:
|
|
10934
|
+
path: join26(srcDir, "pages", "[...slug].md.ts")
|
|
10582
10935
|
},
|
|
10583
10936
|
{
|
|
10584
10937
|
content: rawMarkdownEndpointTemplate(),
|
|
10585
|
-
path:
|
|
10938
|
+
path: join26(srcDir, "pages", "[...slug].mdx.ts")
|
|
10586
10939
|
}
|
|
10587
10940
|
];
|
|
10588
10941
|
if (askEnabled) {
|
|
@@ -10591,34 +10944,34 @@ var eject = async (root) => {
|
|
|
10591
10944
|
if (config.seo.og.enabled) {
|
|
10592
10945
|
files.push({
|
|
10593
10946
|
content: ogEndpointTemplate(customOgRoutes(pages, config.title)),
|
|
10594
|
-
path:
|
|
10947
|
+
path: join26(srcDir, "pages", "og", "[...slug].png.ts")
|
|
10595
10948
|
});
|
|
10596
10949
|
}
|
|
10597
10950
|
if (!routeIsTaken(pages, project.graph.pages, "/404")) {
|
|
10598
10951
|
files.push({
|
|
10599
10952
|
content: notFoundPageTemplate(),
|
|
10600
|
-
path:
|
|
10953
|
+
path: join26(srcDir, "pages", "404.astro")
|
|
10601
10954
|
});
|
|
10602
10955
|
}
|
|
10603
10956
|
files.push({
|
|
10604
10957
|
content: searchClientTemplate(config),
|
|
10605
|
-
path:
|
|
10958
|
+
path: join26(genDir, "search-client.ts")
|
|
10606
10959
|
});
|
|
10607
10960
|
if (servesStaticIndex(config.search.provider)) {
|
|
10608
10961
|
const documents = await buildSearchDocuments(project);
|
|
10609
10962
|
files.push({
|
|
10610
10963
|
content: `${JSON.stringify(documents)}
|
|
10611
10964
|
`,
|
|
10612
|
-
path:
|
|
10965
|
+
path: join26(genDir, "search.json")
|
|
10613
10966
|
}, {
|
|
10614
10967
|
content: searchEndpointTemplate(),
|
|
10615
|
-
path:
|
|
10968
|
+
path: join26(srcDir, "pages", "blume-search.json.ts")
|
|
10616
10969
|
});
|
|
10617
10970
|
}
|
|
10618
10971
|
if (config.search.provider === "mixedbread") {
|
|
10619
10972
|
files.push({
|
|
10620
10973
|
content: mixedbreadSearchEndpointTemplate(config.search.mixedbread?.storeId ?? ""),
|
|
10621
|
-
path:
|
|
10974
|
+
path: join26(srcDir, "pages", "api", "search.ts")
|
|
10622
10975
|
});
|
|
10623
10976
|
}
|
|
10624
10977
|
const feeds = buildRssFeeds(project);
|
|
@@ -10627,10 +10980,10 @@ var eject = async (root) => {
|
|
|
10627
10980
|
files.push({
|
|
10628
10981
|
content: `${JSON.stringify(feedXml)}
|
|
10629
10982
|
`,
|
|
10630
|
-
path:
|
|
10983
|
+
path: join26(genDir, "rss.json")
|
|
10631
10984
|
}, {
|
|
10632
10985
|
content: rssEndpointTemplate(),
|
|
10633
|
-
path:
|
|
10986
|
+
path: join26(srcDir, "pages", "[section]", "rss.xml.ts")
|
|
10634
10987
|
});
|
|
10635
10988
|
}
|
|
10636
10989
|
if (hasScalarReferences(config)) {
|
|
@@ -10642,38 +10995,38 @@ var eject = async (root) => {
|
|
|
10642
10995
|
for (const file of references.files) {
|
|
10643
10996
|
files.push({
|
|
10644
10997
|
content: file.content,
|
|
10645
|
-
path:
|
|
10998
|
+
path: join26(srcDir, "pages", file.pagePath)
|
|
10646
10999
|
});
|
|
10647
11000
|
}
|
|
10648
11001
|
}
|
|
10649
11002
|
files.push(...islands.islands.map((island) => ({
|
|
10650
11003
|
content: islandWrapperTemplate(island),
|
|
10651
|
-
path:
|
|
11004
|
+
path: join26(genDir, "islands", `${island.name}.astro`)
|
|
10652
11005
|
})), ...examples.examples.map((example) => ({
|
|
10653
11006
|
content: exampleWrapperTemplate(example),
|
|
10654
|
-
path:
|
|
11007
|
+
path: join26(genDir, "examples", `${exampleSlug(example.path)}.astro`)
|
|
10655
11008
|
})));
|
|
10656
11009
|
for (const [entryId, content] of staged) {
|
|
10657
|
-
files.push({ content, path:
|
|
11010
|
+
files.push({ content, path: join26(root, stagedDir, entryId) });
|
|
10658
11011
|
}
|
|
10659
|
-
const written = files.filter((file) => !(file.skipIfExists &&
|
|
11012
|
+
const written = files.filter((file) => !(file.skipIfExists && existsSync17(file.path)));
|
|
10660
11013
|
await Promise.all(written.map(async (file) => {
|
|
10661
|
-
await
|
|
11014
|
+
await mkdir7(join26(file.path, ".."), { recursive: true });
|
|
10662
11015
|
await writeFile8(file.path, file.content, "utf-8");
|
|
10663
11016
|
}));
|
|
10664
|
-
const assetsSrc =
|
|
10665
|
-
if (
|
|
10666
|
-
await
|
|
11017
|
+
const assetsSrc = join26(context.outDir, "public", "blume-assets");
|
|
11018
|
+
if (existsSync17(assetsSrc)) {
|
|
11019
|
+
await cp2(assetsSrc, join26(root, "public", "blume-assets"), {
|
|
10667
11020
|
recursive: true
|
|
10668
11021
|
});
|
|
10669
11022
|
}
|
|
10670
|
-
await
|
|
11023
|
+
await rm3(context.outDir, { force: true, recursive: true });
|
|
10671
11024
|
return written.map((file) => file.path);
|
|
10672
11025
|
};
|
|
10673
11026
|
|
|
10674
11027
|
// src/cli/commands/eject.ts
|
|
10675
11028
|
var updatePackageScripts = async (root) => {
|
|
10676
|
-
const pkgPath =
|
|
11029
|
+
const pkgPath = join27(root, "package.json");
|
|
10677
11030
|
let pkg;
|
|
10678
11031
|
try {
|
|
10679
11032
|
pkg = JSON.parse(await readFile13(pkgPath, "utf-8"));
|
|
@@ -10723,10 +11076,10 @@ The blume package remains importable.`);
|
|
|
10723
11076
|
});
|
|
10724
11077
|
|
|
10725
11078
|
// src/cli/commands/init.ts
|
|
10726
|
-
import { existsSync as
|
|
10727
|
-
import { mkdir as
|
|
11079
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
11080
|
+
import { mkdir as mkdir8, writeFile as writeFile10 } from "node:fs/promises";
|
|
10728
11081
|
import { defineCommand as defineCommand7 } from "citty";
|
|
10729
|
-
import { basename as basename4, dirname as
|
|
11082
|
+
import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute8, join as join28, relative as relative13 } from "pathe";
|
|
10730
11083
|
|
|
10731
11084
|
// src/core/package-json.ts
|
|
10732
11085
|
var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
@@ -10778,7 +11131,7 @@ var STARTERS = {
|
|
|
10778
11131
|
files: (dir) => [
|
|
10779
11132
|
{
|
|
10780
11133
|
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`."),
|
|
10781
|
-
path:
|
|
11134
|
+
path: join28(dir, "index.mdx")
|
|
10782
11135
|
}
|
|
10783
11136
|
]
|
|
10784
11137
|
},
|
|
@@ -10793,7 +11146,7 @@ var STARTERS = {
|
|
|
10793
11146
|
files: (dir) => [
|
|
10794
11147
|
{
|
|
10795
11148
|
content: page("Introduction", "Welcome to your new Blume docs.", "# Introduction\n\nWrite your docs here, and log releases under `changelog/`."),
|
|
10796
|
-
path:
|
|
11149
|
+
path: join28(dir, "index.mdx")
|
|
10797
11150
|
},
|
|
10798
11151
|
{
|
|
10799
11152
|
content: `---
|
|
@@ -10804,7 +11157,7 @@ date: 2026-01-01
|
|
|
10804
11157
|
|
|
10805
11158
|
The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries beside it.
|
|
10806
11159
|
`,
|
|
10807
|
-
path:
|
|
11160
|
+
path: join28(dir, "changelog", "v1-0-0.mdx")
|
|
10808
11161
|
}
|
|
10809
11162
|
]
|
|
10810
11163
|
},
|
|
@@ -10817,7 +11170,7 @@ The first release. Edit \`${dir}/changelog/v1-0-0.mdx\` or add new entries besid
|
|
|
10817
11170
|
Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
|
|
10818
11171
|
|
|
10819
11172
|
Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
|
|
10820
|
-
path:
|
|
11173
|
+
path: join28(dir, "index.mdx")
|
|
10821
11174
|
}
|
|
10822
11175
|
]
|
|
10823
11176
|
},
|
|
@@ -10828,11 +11181,11 @@ Edit \`${dir}/index.mdx\` to get started, then run \`blume dev\`.`),
|
|
|
10828
11181
|
content: page("Introduction", "Get started with the SDK.", `# Introduction
|
|
10829
11182
|
|
|
10830
11183
|
Install the SDK and make your first call. See [Installation](/installation).`),
|
|
10831
|
-
path:
|
|
11184
|
+
path: join28(dir, "index.mdx")
|
|
10832
11185
|
},
|
|
10833
11186
|
{
|
|
10834
11187
|
content: page("Installation", "Install the SDK.", "# Installation\n\n```package-install\nyour-sdk\n```"),
|
|
10835
|
-
path:
|
|
11188
|
+
path: join28(dir, "installation.mdx")
|
|
10836
11189
|
}
|
|
10837
11190
|
]
|
|
10838
11191
|
}
|
|
@@ -10842,11 +11195,11 @@ var commandsFor = (pm) => ({
|
|
|
10842
11195
|
install: `${pm} install`
|
|
10843
11196
|
});
|
|
10844
11197
|
var writeFileSafe = async (path, content) => {
|
|
10845
|
-
if (
|
|
11198
|
+
if (existsSync18(path)) {
|
|
10846
11199
|
logger.info(`Skipped existing ${path}`);
|
|
10847
11200
|
return false;
|
|
10848
11201
|
}
|
|
10849
|
-
await
|
|
11202
|
+
await mkdir8(dirname11(path), { recursive: true });
|
|
10850
11203
|
await writeFile10(path, content, "utf-8");
|
|
10851
11204
|
logger.success(`Created ${path}`);
|
|
10852
11205
|
return true;
|
|
@@ -10879,7 +11232,7 @@ var initCommand = defineCommand7({
|
|
|
10879
11232
|
async run({ args }) {
|
|
10880
11233
|
const root = process.cwd();
|
|
10881
11234
|
const contentDir = args["content-dir"] ?? "docs";
|
|
10882
|
-
if (isAbsolute8(contentDir) || relative13(root,
|
|
11235
|
+
if (isAbsolute8(contentDir) || relative13(root, join28(root, contentDir)).startsWith("..")) {
|
|
10883
11236
|
logger.error(`Invalid --content-dir "${contentDir}" (must be a path inside the project).`);
|
|
10884
11237
|
process.exit(1);
|
|
10885
11238
|
}
|
|
@@ -10894,9 +11247,9 @@ var initCommand = defineCommand7({
|
|
|
10894
11247
|
process.exit(1);
|
|
10895
11248
|
}
|
|
10896
11249
|
const starter = STARTERS[template];
|
|
10897
|
-
const createdPackage = await writeFileSafe(
|
|
10898
|
-
await writeFileSafe(
|
|
10899
|
-
await Promise.all(starter.files(contentDir).map((file) => writeFileSafe(
|
|
11250
|
+
const createdPackage = await writeFileSafe(join28(root, "package.json"), blumePackageJson(toPackageName(basename4(root))));
|
|
11251
|
+
await writeFileSafe(join28(root, "blume.config.ts"), starter.config);
|
|
11252
|
+
await Promise.all(starter.files(contentDir).map((file) => writeFileSafe(join28(root, file.path), file.content)));
|
|
10900
11253
|
const ignored = await ensureGitignore(root, [".blume/", "dist/"]);
|
|
10901
11254
|
if (ignored.length > 0) {
|
|
10902
11255
|
logger.success(`Added ${ignored.join(", ")} to .gitignore`);
|
|
@@ -10934,10 +11287,10 @@ var initCommand = defineCommand7({
|
|
|
10934
11287
|
});
|
|
10935
11288
|
|
|
10936
11289
|
// src/cli/commands/preview.ts
|
|
10937
|
-
import { existsSync as
|
|
11290
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
10938
11291
|
import { preview } from "astro";
|
|
10939
11292
|
import { defineCommand as defineCommand8 } from "citty";
|
|
10940
|
-
import { join as
|
|
11293
|
+
import { join as join29 } from "pathe";
|
|
10941
11294
|
var previewCommand = defineCommand8({
|
|
10942
11295
|
args: {
|
|
10943
11296
|
host: { description: "Network host to bind.", type: "string" },
|
|
@@ -10951,7 +11304,7 @@ var previewCommand = defineCommand8({
|
|
|
10951
11304
|
const root = process.cwd();
|
|
10952
11305
|
const { config } = await loadConfig(root);
|
|
10953
11306
|
const context = resolveProjectContext(root, config);
|
|
10954
|
-
if (!
|
|
11307
|
+
if (!existsSync19(join29(context.outDir, "astro.config.mjs"))) {
|
|
10955
11308
|
logger.error("No build found. Run `blume build` first.");
|
|
10956
11309
|
process.exit(1);
|
|
10957
11310
|
}
|
|
@@ -10967,9 +11320,9 @@ var previewCommand = defineCommand8({
|
|
|
10967
11320
|
});
|
|
10968
11321
|
|
|
10969
11322
|
// src/cli/commands/sync.ts
|
|
10970
|
-
import { rm as
|
|
11323
|
+
import { rm as rm4 } from "node:fs/promises";
|
|
10971
11324
|
import { defineCommand as defineCommand9 } from "citty";
|
|
10972
|
-
import { join as
|
|
11325
|
+
import { join as join30 } from "pathe";
|
|
10973
11326
|
var syncCommand = defineCommand9({
|
|
10974
11327
|
args: {
|
|
10975
11328
|
force: {
|
|
@@ -10991,7 +11344,7 @@ var syncCommand = defineCommand9({
|
|
|
10991
11344
|
if (args.force) {
|
|
10992
11345
|
const { config } = await loadConfig(root);
|
|
10993
11346
|
const context = resolveProjectContext(root, config);
|
|
10994
|
-
await
|
|
11347
|
+
await rm4(join30(context.outDir, "cache"), { force: true, recursive: true });
|
|
10995
11348
|
logger.info("Cleared source cache.");
|
|
10996
11349
|
}
|
|
10997
11350
|
await prepareProject({
|
|
@@ -11006,13 +11359,13 @@ var syncCommand = defineCommand9({
|
|
|
11006
11359
|
});
|
|
11007
11360
|
|
|
11008
11361
|
// src/cli/commands/validate.ts
|
|
11009
|
-
import { existsSync as
|
|
11362
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
11010
11363
|
import { defineCommand as defineCommand10 } from "citty";
|
|
11011
|
-
import { join as
|
|
11364
|
+
import { join as join32 } from "pathe";
|
|
11012
11365
|
|
|
11013
11366
|
// src/core/links.ts
|
|
11014
|
-
import { existsSync as
|
|
11015
|
-
import { basename as basename5, join as
|
|
11367
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
11368
|
+
import { basename as basename5, join as join31 } from "pathe";
|
|
11016
11369
|
var HTTP = /^https?:\/\//iu;
|
|
11017
11370
|
var PROTOCOL_RELATIVE = /^\/\//u;
|
|
11018
11371
|
var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
|
|
@@ -11024,7 +11377,7 @@ var STATUS_NOT_FOUND = 404;
|
|
|
11024
11377
|
var STATUS_GONE = 410;
|
|
11025
11378
|
var STATUS_METHOD_NOT_ALLOWED = 405;
|
|
11026
11379
|
var STATUS_NOT_IMPLEMENTED = 501;
|
|
11027
|
-
var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null &&
|
|
11380
|
+
var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync20(join31(ctx.publicDir, resolved));
|
|
11028
11381
|
var isIndexPage = (page2) => {
|
|
11029
11382
|
const ref = page2.source?.ref ?? page2.sourcePath ?? "";
|
|
11030
11383
|
return /^index\.(?:md|mdx)$/iu.test(basename5(ref));
|
|
@@ -11267,10 +11620,10 @@ var validateCommand = defineCommand10({
|
|
|
11267
11620
|
try {
|
|
11268
11621
|
const project = await scanProject(root, { mode: "build" });
|
|
11269
11622
|
diagnostics.push(...project.diagnostics);
|
|
11270
|
-
const publicDir =
|
|
11623
|
+
const publicDir = join32(root, "public");
|
|
11271
11624
|
diagnostics.push(...await validateLinks(project.graph, {
|
|
11272
11625
|
checkExternal: Boolean(args.external),
|
|
11273
|
-
publicDir:
|
|
11626
|
+
publicDir: existsSync21(publicDir) ? publicDir : null,
|
|
11274
11627
|
redirects: project.config.redirects
|
|
11275
11628
|
}));
|
|
11276
11629
|
} catch (error) {
|
|
@@ -11330,5 +11683,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
11330
11683
|
});
|
|
11331
11684
|
runMain(main);
|
|
11332
11685
|
|
|
11333
|
-
//# debugId=
|
|
11686
|
+
//# debugId=0628D18D87A2023564756E2164756E21
|
|
11334
11687
|
//# sourceMappingURL=index.js.map
|