blume 0.5.4 → 0.6.0
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 +380 -157
- package/dist/cli/index.js.map +23 -22
- 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 +328 -39
- package/dist/types/core/types.d.ts +8 -0
- package/docs/configuration/ai.mdx +56 -0
- 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/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 +4 -0
- package/src/astro/templates.ts +24 -5
- package/src/cli/commands/build.ts +15 -0
- 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/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 +48 -2
- 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 +124 -9
- 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/robots.ts +37 -4
- package/src/openapi/scalar.ts +1 -1
- package/src/search/documents.ts +9 -2
- package/src/theme/palette.ts +21 -14
package/dist/cli/index.js
CHANGED
|
@@ -519,6 +519,150 @@ import { build } from "astro";
|
|
|
519
519
|
import { defineCommand as defineCommand2 } from "citty";
|
|
520
520
|
import { join as join23 } from "pathe";
|
|
521
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
|
+
};
|
|
665
|
+
|
|
522
666
|
// src/core/frontmatter.ts
|
|
523
667
|
import baseMatter from "gray-matter";
|
|
524
668
|
import { dump, load } from "js-yaml";
|
|
@@ -720,12 +864,29 @@ var buildRedirectManifest = (redirects) => `${JSON.stringify(redirects.map((redi
|
|
|
720
864
|
`;
|
|
721
865
|
|
|
722
866
|
// src/deploy/robots.ts
|
|
867
|
+
var SIGNAL_TOKENS = [
|
|
868
|
+
["search", "search"],
|
|
869
|
+
["aiInput", "ai-input"],
|
|
870
|
+
["aiTrain", "ai-train"]
|
|
871
|
+
];
|
|
872
|
+
var contentSignalLine = (signals) => {
|
|
873
|
+
if (!signals) {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
876
|
+
const tokens = SIGNAL_TOKENS.map(([key, token]) => `${token}=${signals[key] ? "yes" : "no"}`);
|
|
877
|
+
return `Content-Signal: ${tokens.join(", ")}`;
|
|
878
|
+
};
|
|
723
879
|
var buildRobots = (project) => {
|
|
724
880
|
const { config } = project;
|
|
725
881
|
if (!config.seo.robots) {
|
|
726
882
|
return null;
|
|
727
883
|
}
|
|
728
|
-
const lines = ["User-agent: *"
|
|
884
|
+
const lines = ["User-agent: *"];
|
|
885
|
+
const signal = contentSignalLine(config.seo.contentSignals);
|
|
886
|
+
if (signal) {
|
|
887
|
+
lines.push(signal);
|
|
888
|
+
}
|
|
889
|
+
lines.push("Allow: /");
|
|
729
890
|
const { site } = config.deployment;
|
|
730
891
|
if (site && config.seo.sitemap) {
|
|
731
892
|
lines.push("", `Sitemap: ${site.replace(/\/$/u, "")}/sitemap.xml`);
|
|
@@ -735,9 +896,6 @@ var buildRobots = (project) => {
|
|
|
735
896
|
`;
|
|
736
897
|
};
|
|
737
898
|
|
|
738
|
-
// src/deploy/xml.ts
|
|
739
|
-
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
740
|
-
|
|
741
899
|
// src/deploy/sitemap.ts
|
|
742
900
|
var lastmodTag = (value) => {
|
|
743
901
|
if (!value) {
|
|
@@ -2676,7 +2834,8 @@ var buildSearchDocuments = async (project, options) => {
|
|
|
2676
2834
|
return await Promise.all(indexable.map(async (route) => {
|
|
2677
2835
|
const page = pageById.get(route.id);
|
|
2678
2836
|
const raw = page ? await readEntryText(project, page) : "";
|
|
2679
|
-
const
|
|
2837
|
+
const source = raw ? frontmatter_default(raw).content : "";
|
|
2838
|
+
const body = options?.content === "markdown" ? source.trim() : toPlainText(source);
|
|
2680
2839
|
const tags = page?.meta?.search?.tags;
|
|
2681
2840
|
const crumb = crumbs.get(route.path);
|
|
2682
2841
|
return {
|
|
@@ -2867,15 +3026,26 @@ var resolveProjectContext = (root, config, options) => {
|
|
|
2867
3026
|
|
|
2868
3027
|
// src/cli/dev-lock.ts
|
|
2869
3028
|
var lockPath = (outDir) => join8(outDir, "dev.lock");
|
|
2870
|
-
var
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3029
|
+
var isValidPid = (pid) => typeof pid === "number" && Number.isInteger(pid) && pid > 0;
|
|
3030
|
+
var parseLock = (raw) => {
|
|
3031
|
+
let data;
|
|
3032
|
+
try {
|
|
3033
|
+
data = JSON.parse(raw.trim());
|
|
3034
|
+
} catch {
|
|
3035
|
+
return null;
|
|
2874
3036
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3037
|
+
if (isValidPid(data)) {
|
|
3038
|
+
return { pid: data };
|
|
3039
|
+
}
|
|
3040
|
+
if (typeof data === "object" && data !== null) {
|
|
3041
|
+
const { pid, port } = data;
|
|
3042
|
+
if (isValidPid(pid)) {
|
|
3043
|
+
return typeof port === "number" ? { pid, port } : { pid };
|
|
3044
|
+
}
|
|
2878
3045
|
}
|
|
3046
|
+
return null;
|
|
3047
|
+
};
|
|
3048
|
+
var isProcessAlive = (pid) => {
|
|
2879
3049
|
try {
|
|
2880
3050
|
process.kill(pid, 0);
|
|
2881
3051
|
return true;
|
|
@@ -2883,10 +3053,34 @@ var isDevLocked = (outDir) => {
|
|
|
2883
3053
|
return error.code === "EPERM";
|
|
2884
3054
|
}
|
|
2885
3055
|
};
|
|
2886
|
-
var
|
|
3056
|
+
var readDevLock = (outDir) => {
|
|
2887
3057
|
const path = lockPath(outDir);
|
|
3058
|
+
if (!existsSync5(path)) {
|
|
3059
|
+
return null;
|
|
3060
|
+
}
|
|
3061
|
+
const lock = parseLock(readFileSync2(path, "utf-8"));
|
|
3062
|
+
return lock && isProcessAlive(lock.pid) ? lock : null;
|
|
3063
|
+
};
|
|
3064
|
+
var writeLock = (outDir, port) => {
|
|
3065
|
+
writeFileSync(lockPath(outDir), JSON.stringify({
|
|
3066
|
+
pid: process.pid,
|
|
3067
|
+
...port === undefined ? {} : { port }
|
|
3068
|
+
}));
|
|
3069
|
+
};
|
|
3070
|
+
var ownsLock = (outDir) => {
|
|
3071
|
+
const path = lockPath(outDir);
|
|
3072
|
+
if (!existsSync5(path)) {
|
|
3073
|
+
return false;
|
|
3074
|
+
}
|
|
3075
|
+
try {
|
|
3076
|
+
return parseLock(readFileSync2(path, "utf-8"))?.pid === process.pid;
|
|
3077
|
+
} catch {
|
|
3078
|
+
return false;
|
|
3079
|
+
}
|
|
3080
|
+
};
|
|
3081
|
+
var acquireDevLock = (outDir, port) => {
|
|
2888
3082
|
mkdirSync(outDir, { recursive: true });
|
|
2889
|
-
|
|
3083
|
+
writeLock(outDir, port);
|
|
2890
3084
|
let released = false;
|
|
2891
3085
|
return () => {
|
|
2892
3086
|
if (released) {
|
|
@@ -2894,15 +3088,22 @@ var acquireDevLock = (outDir) => {
|
|
|
2894
3088
|
}
|
|
2895
3089
|
released = true;
|
|
2896
3090
|
try {
|
|
2897
|
-
if (
|
|
2898
|
-
rmSync(
|
|
3091
|
+
if (ownsLock(outDir)) {
|
|
3092
|
+
rmSync(lockPath(outDir), { force: true });
|
|
2899
3093
|
}
|
|
2900
3094
|
} catch {}
|
|
2901
3095
|
};
|
|
2902
3096
|
};
|
|
3097
|
+
var updateDevLockPort = (outDir, port) => {
|
|
3098
|
+
if (ownsLock(outDir)) {
|
|
3099
|
+
writeLock(outDir, port);
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
var describeDevLock = (lock) => lock.port === undefined ? "" : ` at http://localhost:${lock.port}`;
|
|
2903
3103
|
var refuseIfDevRunning = (root, action, runtimeDir) => {
|
|
2904
|
-
|
|
2905
|
-
|
|
3104
|
+
const lock = readDevLock(resolveRuntimeDir(root, runtimeDir));
|
|
3105
|
+
if (lock) {
|
|
3106
|
+
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
3107
|
process.exit(1);
|
|
2907
3108
|
}
|
|
2908
3109
|
};
|
|
@@ -2926,6 +3127,7 @@ import { glob as glob4 } from "tinyglobby";
|
|
|
2926
3127
|
// src/ai/ask-data.ts
|
|
2927
3128
|
var buildAskData = async (project) => {
|
|
2928
3129
|
const documents = await buildSearchDocuments(project, {
|
|
3130
|
+
content: "markdown",
|
|
2929
3131
|
includeWhenDisabled: true
|
|
2930
3132
|
});
|
|
2931
3133
|
return {
|
|
@@ -3424,6 +3626,7 @@ var uiStringsObject = z.object({
|
|
|
3424
3626
|
connectMcp: z.string().default("Connect to MCP"),
|
|
3425
3627
|
copied: z.string().default("Copied!"),
|
|
3426
3628
|
copyClaudeCode: z.string().default("Copy Claude Code command"),
|
|
3629
|
+
copyCodex: z.string().default("Copy Codex command"),
|
|
3427
3630
|
copyMarkdown: z.string().default("Copy as Markdown"),
|
|
3428
3631
|
copyServerUrl: z.string().default("Copy server URL"),
|
|
3429
3632
|
edit: z.string().default("Edit on GitHub"),
|
|
@@ -3431,11 +3634,15 @@ var uiStringsObject = z.object({
|
|
|
3431
3634
|
scrollToTop: z.string().default("Scroll to top")
|
|
3432
3635
|
}).default({}),
|
|
3433
3636
|
ask: z.object({
|
|
3637
|
+
clear: z.string().default("Clear conversation"),
|
|
3638
|
+
close: z.string().default("Close"),
|
|
3639
|
+
copy: z.string().default("Copy conversation"),
|
|
3434
3640
|
empty: z.string().default("Ask a question about the docs."),
|
|
3435
3641
|
error: z.string().default("Sorry, something went wrong."),
|
|
3436
3642
|
label: z.string().default("Ask a question"),
|
|
3437
3643
|
placeholder: z.string().default("Ask a question…"),
|
|
3438
3644
|
send: z.string().default("Send"),
|
|
3645
|
+
tip: z.string().default("Tip: You can open and close chat with"),
|
|
3439
3646
|
title: z.string().default("Ask AI")
|
|
3440
3647
|
}).default({}),
|
|
3441
3648
|
feedback: z.object({
|
|
@@ -3568,6 +3775,9 @@ var collectIcons = (navigation) => {
|
|
|
3568
3775
|
push(item.icon, `selector "${item.label}"`);
|
|
3569
3776
|
}
|
|
3570
3777
|
}
|
|
3778
|
+
for (const link of navigation.featured) {
|
|
3779
|
+
push(link.icon, `featured link "${link.label}"`);
|
|
3780
|
+
}
|
|
3571
3781
|
const sidebars = [navigation.sidebar];
|
|
3572
3782
|
for (const sidebar of sidebars) {
|
|
3573
3783
|
for (const node of flattenNodes(sidebar)) {
|
|
@@ -3597,7 +3807,11 @@ var resolvesToPages = (routes, path) => routes.has(path) || [...routes].some((ro
|
|
|
3597
3807
|
var validateNavTargets = (navigation, routes) => {
|
|
3598
3808
|
const targets = [
|
|
3599
3809
|
...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 })))
|
|
3810
|
+
...navigation.selectors.flatMap((selector) => selector.items.map((item) => ({ label: item.label, path: item.path }))),
|
|
3811
|
+
...navigation.featured.map((link) => ({
|
|
3812
|
+
label: link.label,
|
|
3813
|
+
path: link.href
|
|
3814
|
+
}))
|
|
3601
3815
|
];
|
|
3602
3816
|
const diagnostics = [];
|
|
3603
3817
|
const seen = new Set;
|
|
@@ -3813,84 +4027,6 @@ var resolveTsconfigAliases = (root) => {
|
|
|
3813
4027
|
return aliases;
|
|
3814
4028
|
};
|
|
3815
4029
|
|
|
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
4030
|
// src/openapi/references.ts
|
|
3895
4031
|
var NON_SLUG = /[^a-z0-9]+/gu;
|
|
3896
4032
|
var SLUG_EDGES = /^-+|-+$/gu;
|
|
@@ -3977,6 +4113,30 @@ import { isAbsolute as isAbsolute5, join as join11 } from "pathe";
|
|
|
3977
4113
|
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
|
|
3978
4114
|
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join10, relative as relative4 } from "pathe";
|
|
3979
4115
|
|
|
4116
|
+
// src/core/sources/watch.ts
|
|
4117
|
+
var BLUME_IGNORE_DIRS = [
|
|
4118
|
+
".blume",
|
|
4119
|
+
".cache",
|
|
4120
|
+
".git",
|
|
4121
|
+
".next",
|
|
4122
|
+
".turbo",
|
|
4123
|
+
".vercel",
|
|
4124
|
+
"dist",
|
|
4125
|
+
"node_modules"
|
|
4126
|
+
];
|
|
4127
|
+
var baselineScanIgnore = () => BLUME_IGNORE_DIRS.map((dir) => `**/${dir}/**`);
|
|
4128
|
+
var BLUME_WATCH_IGNORE_DIRS = BLUME_IGNORE_DIRS;
|
|
4129
|
+
var excludeDirSegments = (patterns) => patterns.map((pattern) => /^(?<dir>[^*/]+)\/\*\*$/u.exec(pattern)?.groups?.dir).filter((dir) => dir !== undefined);
|
|
4130
|
+
var ignoringWatchListener = (onChange, ignoreDirs = BLUME_WATCH_IGNORE_DIRS) => {
|
|
4131
|
+
const ignore = new Set(ignoreDirs);
|
|
4132
|
+
return (_event, filename) => {
|
|
4133
|
+
if (typeof filename === "string" && filename.split(/[/\\]/u).some((segment) => ignore.has(segment))) {
|
|
4134
|
+
return;
|
|
4135
|
+
}
|
|
4136
|
+
onChange();
|
|
4137
|
+
};
|
|
4138
|
+
};
|
|
4139
|
+
|
|
3980
4140
|
// src/theme/fonts.ts
|
|
3981
4141
|
var FALLBACKS = {
|
|
3982
4142
|
mono: ["ui-monospace", "SF Mono", "Menlo", "monospace"],
|
|
@@ -4314,9 +4474,17 @@ export default defineConfig({
|
|
|
4314
4474
|
// native bindings resolve at runtime and isolated linkers don't bundle
|
|
4315
4475
|
// symlinked store copies (which would surface their children as unresolvable
|
|
4316
4476
|
// imports). See RENDER_EXTERNAL_DEPS / prerenderDepsPlugin.
|
|
4477
|
+
//
|
|
4478
|
+
// The SSR externals go through the legacy \`ssr.external\` key rather than
|
|
4479
|
+
// \`environments.ssr\`: defining a user-owned \`environments.ssr\` block
|
|
4480
|
+
// collides with the internal environment Astro 7 builds the server under and
|
|
4481
|
+
// detaches the adapter's server entrypoint from the rolldown input, so the
|
|
4482
|
+
// SSR entry is emitted as \`index.mjs\` instead of the \`entry.mjs\` the
|
|
4483
|
+
// Vercel adapter's \`astro:build:done\` hook then fails to find. \`prerender\`
|
|
4484
|
+
// is Astro-only and has no legacy equivalent, so it stays under \`environments\`.
|
|
4485
|
+
ssr: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} },
|
|
4317
4486
|
environments: {
|
|
4318
4487
|
prerender: { resolve: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} } },
|
|
4319
|
-
ssr: { resolve: { external: ${JSON.stringify(RENDER_EXTERNAL_DEPS)} } },
|
|
4320
4488
|
},
|
|
4321
4489
|
resolve: {
|
|
4322
4490
|
alias: {
|
|
@@ -4355,7 +4523,7 @@ var contentConfigTemplate = (options) => {
|
|
|
4355
4523
|
const docsPattern = filesystem ? [
|
|
4356
4524
|
...config.content.include,
|
|
4357
4525
|
...(config.content.exclude ?? []).map((pattern) => `!${pattern}`),
|
|
4358
|
-
"
|
|
4526
|
+
...BLUME_IGNORE_DIRS.filter((dir) => dir !== ".blume").map((dir) => `!**/${dir}/**`),
|
|
4359
4527
|
...outDirIgnore
|
|
4360
4528
|
] : [];
|
|
4361
4529
|
const stagedBlock = options.staged ? `
|
|
@@ -4691,7 +4859,7 @@ const siteHost = (() => {
|
|
|
4691
4859
|
|
|
4692
4860
|
export async function GET({ props }) {
|
|
4693
4861
|
const png = await renderOgImage({
|
|
4694
|
-
accent: data.config.theme.accent,
|
|
4862
|
+
accent: data.config.theme.accent.light,
|
|
4695
4863
|
brand: data.config.title,
|
|
4696
4864
|
description: data.config.description,
|
|
4697
4865
|
logo: data.config.logo?.svg,
|
|
@@ -4739,7 +4907,7 @@ var catchAllPageTemplate = (options) => {
|
|
|
4739
4907
|
const askImport = options.askEnabled ? `import AskAI from "blume/components/islands/AskAI.astro";
|
|
4740
4908
|
` : "";
|
|
4741
4909
|
const askSlot = options.askEnabled ? `
|
|
4742
|
-
<AskAI slot="ask" strings={ui.ask} />` : "";
|
|
4910
|
+
<AskAI slot="ask" strings={ui.ask} suggestions={data.config.ask?.suggestions ?? []} />` : "";
|
|
4743
4911
|
const mathImport = options.mathEnabled ? `import Math from "blume/components/content/Math.astro";
|
|
4744
4912
|
` : "";
|
|
4745
4913
|
const mathEntry = options.mathEnabled ? `Math,
|
|
@@ -4991,7 +5159,7 @@ var changelogIndexTemplate = (options) => {
|
|
|
4991
5159
|
const askImport = options.askEnabled ? `import AskAI from "blume/components/islands/AskAI.astro";
|
|
4992
5160
|
` : "";
|
|
4993
5161
|
const askSlot = options.askEnabled ? `
|
|
4994
|
-
<AskAI slot="ask" />` : "";
|
|
5162
|
+
<AskAI slot="ask" strings={data.ui.ask} suggestions={data.config.ask?.suggestions ?? []} />` : "";
|
|
4995
5163
|
const clientData = options.needsReact ? `
|
|
4996
5164
|
clientData={{ config: data.config, navigation: data.navigation, page: { route: "/changelog", title: data.config.title + " changelog" } }}` : "";
|
|
4997
5165
|
const stagedSpread = options.staged ? `
|
|
@@ -5281,8 +5449,8 @@ var themeRootCss = (theme, options) => [
|
|
|
5281
5449
|
` --blume-accent: ${options.accent};`,
|
|
5282
5450
|
...cssToken("--blume-action", options.action),
|
|
5283
5451
|
...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),
|
|
5452
|
+
...cssToken("--blume-background", safeColorOrNull(theme.background?.light)),
|
|
5453
|
+
...cssToken("--blume-background-image", theme.backgroundImage?.light ? backgroundImageCss(theme.backgroundImage.light) : null),
|
|
5286
5454
|
` --blume-radius: ${options.radius};`
|
|
5287
5455
|
].filter(Boolean).join(`
|
|
5288
5456
|
`);
|
|
@@ -5292,8 +5460,8 @@ var themeDarkCss = (theme, options) => {
|
|
|
5292
5460
|
" --blume-accent-foreground: oklch(1 0 0);",
|
|
5293
5461
|
...cssToken("--blume-action", options.action),
|
|
5294
5462
|
...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
|
|
5295
|
-
...cssToken("--blume-background", safeColorOrNull(theme.
|
|
5296
|
-
...cssToken("--blume-background-image", theme.
|
|
5463
|
+
...cssToken("--blume-background", safeColorOrNull(theme.background?.dark)),
|
|
5464
|
+
...cssToken("--blume-background-image", theme.backgroundImage?.dark ? backgroundImageCss(theme.backgroundImage.dark) : null)
|
|
5297
5465
|
].filter(Boolean);
|
|
5298
5466
|
return `:root[data-theme="dark"] {
|
|
5299
5467
|
${tokens.join(`
|
|
@@ -5301,20 +5469,22 @@ ${tokens.join(`
|
|
|
5301
5469
|
}
|
|
5302
5470
|
`;
|
|
5303
5471
|
};
|
|
5304
|
-
var resolveAccent = (theme) =>
|
|
5472
|
+
var resolveAccent = (theme) => ({
|
|
5473
|
+
dark: presetOrColor(theme.accent.dark),
|
|
5474
|
+
light: presetOrColor(theme.accent.light)
|
|
5475
|
+
});
|
|
5305
5476
|
var resolveRadius = (theme) => RADII[theme.radius];
|
|
5306
5477
|
var buildThemeCss = (theme) => {
|
|
5307
|
-
const accent =
|
|
5308
|
-
const accentDark = theme.accentDark ? presetOrColor(theme.accentDark) : null;
|
|
5478
|
+
const accent = resolveAccent(theme);
|
|
5309
5479
|
const action = theme.action ? presetOrColor(theme.action) : null;
|
|
5310
5480
|
const radius = RADII[theme.radius];
|
|
5311
5481
|
const root = themeRootCss(theme, {
|
|
5312
|
-
accent,
|
|
5482
|
+
accent: accent.light,
|
|
5313
5483
|
action,
|
|
5314
5484
|
radius
|
|
5315
5485
|
});
|
|
5316
5486
|
const dark = themeDarkCss(theme, {
|
|
5317
|
-
accent:
|
|
5487
|
+
accent: accent.dark,
|
|
5318
5488
|
action
|
|
5319
5489
|
});
|
|
5320
5490
|
return `/* Generated by Blume from theme config. */
|
|
@@ -5347,7 +5517,7 @@ var themeConfiguration = (config, override) => {
|
|
|
5347
5517
|
const accent = resolveAccent(config.theme);
|
|
5348
5518
|
const radius = resolveRadius(config.theme);
|
|
5349
5519
|
return {
|
|
5350
|
-
customCss: `:root,.light-mode,.dark-mode{--scalar-color-accent:${accent};--scalar-radius:${radius};}`,
|
|
5520
|
+
customCss: `:root,.light-mode,.dark-mode{--scalar-color-accent:${accent.light};--scalar-radius:${radius};}.dark-mode{--scalar-color-accent:${accent.dark};}`,
|
|
5351
5521
|
...darkModeConfig(config.theme.mode)
|
|
5352
5522
|
};
|
|
5353
5523
|
};
|
|
@@ -7097,6 +7267,7 @@ var buildRuntimeData = (project) => {
|
|
|
7097
7267
|
const navigationByLocale = i18n ? Object.fromEntries(i18n.locales.map(({ code }) => [
|
|
7098
7268
|
code,
|
|
7099
7269
|
withReferenceTabs(graph.navigationByLocale[code] ?? {
|
|
7270
|
+
featured: [],
|
|
7100
7271
|
selectors: [],
|
|
7101
7272
|
sidebar: [],
|
|
7102
7273
|
tabs: []
|
|
@@ -7106,6 +7277,7 @@ var buildRuntimeData = (project) => {
|
|
|
7106
7277
|
config: {
|
|
7107
7278
|
analytics: config.analytics ?? null,
|
|
7108
7279
|
appleIcon: resolveAppleIcon(project),
|
|
7280
|
+
ask: config.ai.ask?.enabled ? { suggestions: config.ai.ask.suggestions } : null,
|
|
7109
7281
|
banner: resolveBanner(config),
|
|
7110
7282
|
codeWrap: config.markdown.code.wrap,
|
|
7111
7283
|
description: config.description,
|
|
@@ -7545,7 +7717,6 @@ var pageMetaSchema = pageMetaBaseSchema;
|
|
|
7545
7717
|
var sidebarDisplaySchema = z2.enum(["flat", "group", "page"]);
|
|
7546
7718
|
var folderMetaSchema = z2.object({
|
|
7547
7719
|
collapsed: z2.boolean().optional(),
|
|
7548
|
-
display: sidebarDisplaySchema.optional(),
|
|
7549
7720
|
icon: iconName.optional(),
|
|
7550
7721
|
order: z2.number().optional(),
|
|
7551
7722
|
pages: z2.array(z2.string()).optional(),
|
|
@@ -7699,14 +7870,18 @@ var sidebarItemSchema = z2.lazy(() => z2.union([
|
|
|
7699
7870
|
var fontSlug = z2.string().refine(isFontSlug, (value) => ({
|
|
7700
7871
|
message: `Unknown font "${value}". Supported fonts: ${FONT_SLUGS.join(", ")}.`
|
|
7701
7872
|
}));
|
|
7873
|
+
var perModeValueSchema = z2.union([
|
|
7874
|
+
z2.string(),
|
|
7875
|
+
z2.object({ dark: z2.string().optional(), light: z2.string().optional() }).strict()
|
|
7876
|
+
]).optional().transform((value) => typeof value === "string" ? { dark: value, light: value } : value);
|
|
7702
7877
|
var themeConfigSchema = z2.object({
|
|
7703
|
-
accent: z2.
|
|
7704
|
-
|
|
7878
|
+
accent: z2.union([
|
|
7879
|
+
z2.string(),
|
|
7880
|
+
z2.object({ dark: z2.string(), light: z2.string() }).strict()
|
|
7881
|
+
]).default("blue").transform((value) => typeof value === "string" ? { dark: value, light: value } : value),
|
|
7705
7882
|
action: z2.string().optional(),
|
|
7706
|
-
background:
|
|
7707
|
-
|
|
7708
|
-
backgroundImage: z2.string().optional(),
|
|
7709
|
-
backgroundImageDark: z2.string().optional(),
|
|
7883
|
+
background: perModeValueSchema,
|
|
7884
|
+
backgroundImage: perModeValueSchema,
|
|
7710
7885
|
fonts: z2.object({
|
|
7711
7886
|
body: fontSlug.default("inter"),
|
|
7712
7887
|
display: fontSlug.default("inter-tight"),
|
|
@@ -7785,7 +7960,11 @@ var aiConfigSchema = z2.object({
|
|
|
7785
7960
|
baseUrl: z2.string().url().optional(),
|
|
7786
7961
|
enabled: z2.boolean().default(false),
|
|
7787
7962
|
model: z2.string().default("openai/gpt-5.5"),
|
|
7788
|
-
provider: z2.enum(askAiProviders).default("gateway")
|
|
7963
|
+
provider: z2.enum(askAiProviders).default("gateway"),
|
|
7964
|
+
suggestions: z2.array(z2.object({
|
|
7965
|
+
icon: iconName.optional(),
|
|
7966
|
+
label: z2.string().min(1)
|
|
7967
|
+
}).strict()).default([])
|
|
7789
7968
|
}).strict().superRefine((value, ctx) => {
|
|
7790
7969
|
if (value.provider === "openai-compatible" && !value.baseUrl) {
|
|
7791
7970
|
ctx.addIssue({
|
|
@@ -7797,10 +7976,22 @@ var aiConfigSchema = z2.object({
|
|
|
7797
7976
|
}).optional(),
|
|
7798
7977
|
llmsTxt: z2.boolean().default(false)
|
|
7799
7978
|
}).strict();
|
|
7979
|
+
var featuredLinkSchema = z2.object({
|
|
7980
|
+
href: z2.string(),
|
|
7981
|
+
icon: iconName.optional(),
|
|
7982
|
+
label: z2.string()
|
|
7983
|
+
}).strict();
|
|
7800
7984
|
var navigationConfigSchema = z2.object({
|
|
7985
|
+
featured: z2.array(featuredLinkSchema).default([]),
|
|
7801
7986
|
repo: z2.boolean().default(true),
|
|
7802
7987
|
selectors: z2.array(navSelectorSchema).default([]),
|
|
7803
|
-
sidebar: z2.
|
|
7988
|
+
sidebar: z2.union([
|
|
7989
|
+
z2.array(sidebarItemSchema),
|
|
7990
|
+
z2.object({
|
|
7991
|
+
display: sidebarDisplaySchema.default("flat"),
|
|
7992
|
+
items: z2.array(sidebarItemSchema).optional()
|
|
7993
|
+
}).strict()
|
|
7994
|
+
]).default({}).transform((value) => Array.isArray(value) ? { display: "flat", items: value } : value),
|
|
7804
7995
|
tabs: z2.array(navTabSchema).optional()
|
|
7805
7996
|
}).strict();
|
|
7806
7997
|
var exportConfigSchema = z2.union([
|
|
@@ -7880,7 +8071,23 @@ var rssConfigSchema = z2.object({
|
|
|
7880
8071
|
limit: z2.number().int().positive().default(50),
|
|
7881
8072
|
types: z2.array(z2.string()).default(["blog", "changelog"])
|
|
7882
8073
|
}).strict();
|
|
8074
|
+
var contentSignalsObjectSchema = z2.object({
|
|
8075
|
+
aiInput: z2.boolean().default(true),
|
|
8076
|
+
aiTrain: z2.boolean().default(true),
|
|
8077
|
+
search: z2.boolean().default(true)
|
|
8078
|
+
}).strict();
|
|
8079
|
+
var contentSignalsSchema = z2.union([z2.boolean(), contentSignalsObjectSchema]).transform((value) => {
|
|
8080
|
+
if (value === true) {
|
|
8081
|
+
return contentSignalsObjectSchema.parse({});
|
|
8082
|
+
}
|
|
8083
|
+
if (value === false) {
|
|
8084
|
+
return null;
|
|
8085
|
+
}
|
|
8086
|
+
return value;
|
|
8087
|
+
});
|
|
7883
8088
|
var seoConfigSchema = z2.object({
|
|
8089
|
+
agentReadability: z2.boolean().default(true),
|
|
8090
|
+
contentSignals: contentSignalsSchema.default(true),
|
|
7884
8091
|
og: ogConfigSchema.default({}),
|
|
7885
8092
|
robots: z2.boolean().default(true),
|
|
7886
8093
|
rss: rssConfigSchema.default({}),
|
|
@@ -8091,7 +8298,6 @@ var applyFolderMeta = (group, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
8091
8298
|
group.icon = meta.icon ?? group.icon;
|
|
8092
8299
|
group.order = meta.order ?? group.order;
|
|
8093
8300
|
group.collapsed = meta.collapsed ?? group.collapsed;
|
|
8094
|
-
group.display = meta.display ?? group.display;
|
|
8095
8301
|
if (meta.pages) {
|
|
8096
8302
|
const rank = new Map(meta.pages.map((key, i) => [key, i]));
|
|
8097
8303
|
for (const child of group.children) {
|
|
@@ -8121,7 +8327,15 @@ var sortNodes = (nodes) => {
|
|
|
8121
8327
|
}
|
|
8122
8328
|
}
|
|
8123
8329
|
};
|
|
8124
|
-
var
|
|
8330
|
+
var hoistPages = (nodes) => {
|
|
8331
|
+
const pages = nodes.filter((node) => node.kind === "page");
|
|
8332
|
+
const groups = nodes.filter((node) => node.kind === "group");
|
|
8333
|
+
nodes.splice(0, nodes.length, ...pages, ...groups);
|
|
8334
|
+
for (const group of groups) {
|
|
8335
|
+
hoistPages(group.children);
|
|
8336
|
+
}
|
|
8337
|
+
};
|
|
8338
|
+
var toNavNode = (node, display) => {
|
|
8125
8339
|
if (node.kind === "page") {
|
|
8126
8340
|
return {
|
|
8127
8341
|
badge: node.badge,
|
|
@@ -8135,16 +8349,16 @@ var toNavNode = (node) => {
|
|
|
8135
8349
|
};
|
|
8136
8350
|
}
|
|
8137
8351
|
return {
|
|
8138
|
-
children: node.children.map(toNavNode),
|
|
8352
|
+
children: node.children.map((child) => toNavNode(child, display)),
|
|
8139
8353
|
collapsed: node.collapsed,
|
|
8140
|
-
display
|
|
8354
|
+
display,
|
|
8141
8355
|
icon: node.icon,
|
|
8142
8356
|
kind: "group",
|
|
8143
8357
|
label: node.label,
|
|
8144
8358
|
path: node.routePath
|
|
8145
8359
|
};
|
|
8146
8360
|
};
|
|
8147
|
-
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
8361
|
+
var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix, display) => {
|
|
8148
8362
|
const root = createGroup("", "", "", 0);
|
|
8149
8363
|
for (const page of pages) {
|
|
8150
8364
|
if (page.meta.sidebar.hidden) {
|
|
@@ -8175,7 +8389,10 @@ var buildFileSystemSidebar = (pages, folderMeta, sharedMeta, metaPrefix) => {
|
|
|
8175
8389
|
}
|
|
8176
8390
|
applyFolderMeta(root, folderMeta, sharedMeta, metaPrefix);
|
|
8177
8391
|
sortNodes(root.children);
|
|
8178
|
-
|
|
8392
|
+
if (display === "flat") {
|
|
8393
|
+
hoistPages(root.children);
|
|
8394
|
+
}
|
|
8395
|
+
return root.children.map((child) => toNavNode(child, display));
|
|
8179
8396
|
};
|
|
8180
8397
|
var normalizeRef = (ref) => {
|
|
8181
8398
|
if (ref === "index") {
|
|
@@ -8192,7 +8409,7 @@ var routeForRef = (ref, byRoute) => {
|
|
|
8192
8409
|
const normalized = normalizeRef(ref);
|
|
8193
8410
|
return byRoute.get(normalized)?.route ?? normalized;
|
|
8194
8411
|
};
|
|
8195
|
-
var buildConfigSidebar = (items, byRoute) => {
|
|
8412
|
+
var buildConfigSidebar = (items, byRoute, display) => {
|
|
8196
8413
|
const nodes = [];
|
|
8197
8414
|
for (const item of items) {
|
|
8198
8415
|
if (typeof item === "string") {
|
|
@@ -8214,10 +8431,10 @@ var buildConfigSidebar = (items, byRoute) => {
|
|
|
8214
8431
|
if (item.items) {
|
|
8215
8432
|
nodes.push({
|
|
8216
8433
|
badge: item.badge,
|
|
8217
|
-
children: buildConfigSidebar(item.items, byRoute),
|
|
8434
|
+
children: buildConfigSidebar(item.items, byRoute, display),
|
|
8218
8435
|
collapsed: item.collapsed,
|
|
8219
8436
|
directory: item.directory,
|
|
8220
|
-
display: item.display,
|
|
8437
|
+
display: item.display ?? display,
|
|
8221
8438
|
icon: item.icon,
|
|
8222
8439
|
kind: "group",
|
|
8223
8440
|
label: item.label,
|
|
@@ -8252,8 +8469,10 @@ var buildConfigSidebar = (items, byRoute) => {
|
|
|
8252
8469
|
return nodes;
|
|
8253
8470
|
};
|
|
8254
8471
|
var buildNavigation = (pages, options) => {
|
|
8472
|
+
const featured = options.featured ?? [];
|
|
8255
8473
|
const selectors = options.selectors ?? [];
|
|
8256
8474
|
const tabs = options.tabs ?? [];
|
|
8475
|
+
const display = options.display ?? "flat";
|
|
8257
8476
|
const metaPrefix = options.metaPrefix ?? "";
|
|
8258
8477
|
const sharedFolderMeta = options.sharedFolderMeta ?? new Map;
|
|
8259
8478
|
const byRoute = new Map(pages.map((page) => [
|
|
@@ -8262,14 +8481,16 @@ var buildNavigation = (pages, options) => {
|
|
|
8262
8481
|
]));
|
|
8263
8482
|
if (options.sidebar) {
|
|
8264
8483
|
return {
|
|
8484
|
+
featured,
|
|
8265
8485
|
selectors,
|
|
8266
|
-
sidebar: buildConfigSidebar(options.sidebar, byRoute),
|
|
8486
|
+
sidebar: buildConfigSidebar(options.sidebar, byRoute, display),
|
|
8267
8487
|
tabs
|
|
8268
8488
|
};
|
|
8269
8489
|
}
|
|
8270
8490
|
return {
|
|
8491
|
+
featured,
|
|
8271
8492
|
selectors,
|
|
8272
|
-
sidebar: buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix),
|
|
8493
|
+
sidebar: buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, display),
|
|
8273
8494
|
tabs
|
|
8274
8495
|
};
|
|
8275
8496
|
};
|
|
@@ -8327,26 +8548,31 @@ var buildContentGraph = (pages, options) => {
|
|
|
8327
8548
|
localePages = [...real, ...filled];
|
|
8328
8549
|
}
|
|
8329
8550
|
navigationByLocale[code] = buildNavigation(localePages, {
|
|
8551
|
+
display: options.navigation.sidebar.display,
|
|
8552
|
+
featured: options.navigation.featured,
|
|
8330
8553
|
folderMeta: options.folderMeta,
|
|
8331
8554
|
metaPrefix: i18n.parser === "dir" && code !== i18n.defaultLocale ? code : "",
|
|
8332
8555
|
refByLogical: true,
|
|
8333
8556
|
selectors: options.navigation.selectors,
|
|
8334
8557
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
8335
|
-
sidebar: options.navigation.sidebar,
|
|
8558
|
+
sidebar: options.navigation.sidebar.items,
|
|
8336
8559
|
tabs
|
|
8337
8560
|
});
|
|
8338
8561
|
}
|
|
8339
8562
|
navigation = navigationByLocale[i18n.defaultLocale] ?? {
|
|
8563
|
+
featured: [],
|
|
8340
8564
|
selectors: [],
|
|
8341
8565
|
sidebar: [],
|
|
8342
8566
|
tabs: []
|
|
8343
8567
|
};
|
|
8344
8568
|
} else {
|
|
8345
8569
|
navigation = buildNavigation(pages, {
|
|
8570
|
+
display: options.navigation.sidebar.display,
|
|
8571
|
+
featured: options.navigation.featured,
|
|
8346
8572
|
folderMeta: options.folderMeta,
|
|
8347
8573
|
selectors: options.navigation.selectors,
|
|
8348
8574
|
sharedFolderMeta: options.sharedFolderMeta,
|
|
8349
|
-
sidebar: options.navigation.sidebar,
|
|
8575
|
+
sidebar: options.navigation.sidebar.items,
|
|
8350
8576
|
tabs: options.navigation.tabs
|
|
8351
8577
|
});
|
|
8352
8578
|
}
|
|
@@ -8662,28 +8888,13 @@ import { existsSync as existsSync12, watch as fsWatch } from "node:fs";
|
|
|
8662
8888
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
8663
8889
|
import { extname as extname5, isAbsolute as isAbsolute7, join as join17, relative as relative10, resolve as resolve5 } from "pathe";
|
|
8664
8890
|
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
8891
|
var filesystemSource = (options) => {
|
|
8681
8892
|
const contentRoot = isAbsolute7(options.root) ? options.root : join17(resolve5(options.projectRoot), options.root);
|
|
8682
8893
|
const load2 = async () => {
|
|
8683
8894
|
const files = await glob6(options.include, {
|
|
8684
8895
|
absolute: true,
|
|
8685
8896
|
cwd: contentRoot,
|
|
8686
|
-
ignore: options.exclude,
|
|
8897
|
+
ignore: [...options.exclude, ...baselineScanIgnore()],
|
|
8687
8898
|
onlyFiles: true
|
|
8688
8899
|
});
|
|
8689
8900
|
files.sort();
|
|
@@ -10010,6 +10221,12 @@ var publishBuildArtifacts = async (project, distDir, args) => {
|
|
|
10010
10221
|
await writeFile7(join23(distDir, "robots.txt"), robots, "utf-8");
|
|
10011
10222
|
logger.success("Generated robots.txt");
|
|
10012
10223
|
}
|
|
10224
|
+
const agentReadability = buildAgentReadability(project);
|
|
10225
|
+
if (agentReadability && !existsSync14(join23(distDir, "agent-readability.json"))) {
|
|
10226
|
+
await writeFile7(join23(distDir, "agent-readability.json"), `${JSON.stringify(agentReadability, null, 2)}
|
|
10227
|
+
`, "utf-8");
|
|
10228
|
+
logger.success("Generated agent-readability.json");
|
|
10229
|
+
}
|
|
10013
10230
|
await emitRedirectFiles(project.config, distDir);
|
|
10014
10231
|
const { config } = project;
|
|
10015
10232
|
const features = serverFeatures(config);
|
|
@@ -10021,6 +10238,7 @@ var publishBuildArtifacts = async (project, distDir, args) => {
|
|
|
10021
10238
|
`Redirects ${config.redirects.length}`,
|
|
10022
10239
|
`Sitemap ${sitemap ? "yes" : "no (set deployment.site)"}`,
|
|
10023
10240
|
`Robots ${robots ? "yes" : "no"}`,
|
|
10241
|
+
`Agent JSON ${agentReadability ? "yes" : "no"}`,
|
|
10024
10242
|
`LLM files ${config.ai.llmsTxt ? "yes" : "no"}`,
|
|
10025
10243
|
`Server features ${features.length > 0 ? features.join(", ") : "none"}`
|
|
10026
10244
|
].join(`
|
|
@@ -10279,6 +10497,14 @@ var devCommand = defineCommand4({
|
|
|
10279
10497
|
const explicitPort = parsePort(args.port);
|
|
10280
10498
|
const port = explicitPort ?? 4321;
|
|
10281
10499
|
const devServerUrl = `http://localhost:${port}`;
|
|
10500
|
+
const outDir = resolveRuntimeDir(root);
|
|
10501
|
+
const running = readDevLock(outDir);
|
|
10502
|
+
if (running) {
|
|
10503
|
+
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.`);
|
|
10504
|
+
process.exit(1);
|
|
10505
|
+
}
|
|
10506
|
+
const releaseLock = acquireDevLock(outDir, port);
|
|
10507
|
+
process.on("exit", releaseLock);
|
|
10282
10508
|
const project = await prepareProject({
|
|
10283
10509
|
devServerUrl,
|
|
10284
10510
|
mode: "dev",
|
|
@@ -10287,12 +10513,6 @@ var devCommand = defineCommand4({
|
|
|
10287
10513
|
root,
|
|
10288
10514
|
strict: args.strict
|
|
10289
10515
|
});
|
|
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
10516
|
const server = await dev({
|
|
10297
10517
|
logLevel: args.debug ? "debug" : "info",
|
|
10298
10518
|
root: project.context.outDir,
|
|
@@ -10302,6 +10522,9 @@ var devCommand = defineCommand4({
|
|
|
10302
10522
|
port: explicitPort
|
|
10303
10523
|
}
|
|
10304
10524
|
});
|
|
10525
|
+
if (server.address.port !== port) {
|
|
10526
|
+
updateDevLockPort(outDir, server.address.port);
|
|
10527
|
+
}
|
|
10305
10528
|
showBlumeErrorOverlay(project.diagnostics);
|
|
10306
10529
|
const runRegenerate = coalescedRunner(async () => {
|
|
10307
10530
|
try {
|
|
@@ -11330,5 +11553,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
11330
11553
|
});
|
|
11331
11554
|
runMain(main);
|
|
11332
11555
|
|
|
11333
|
-
//# debugId=
|
|
11556
|
+
//# debugId=0E9EF5D2749C00F464756E2164756E21
|
|
11334
11557
|
//# sourceMappingURL=index.js.map
|