blume 1.5.0 → 1.5.2
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/CHANGELOG.md +32 -0
- package/README.md +16 -12
- package/dist/cli/index.js +449 -135
- package/dist/cli/index.js.map +24 -23
- package/dist/types/ai/ask-context.d.ts +78 -0
- package/dist/types/core/config-input.d.ts +54 -2
- package/dist/types/core/data.d.ts +19 -2
- package/dist/types/core/open-in-chat.d.ts +9 -0
- package/dist/types/core/schema.d.ts +48 -1
- package/dist/types/core/types.d.ts +10 -3
- package/dist/types/openapi/references.d.ts +9 -0
- package/dist/types/search/orama-index.d.ts +70 -0
- package/dist/types/theme/fonts.d.ts +11 -2
- package/docs/advanced/api-reference.mdx +67 -5
- package/docs/advanced/custom-pages.mdx +5 -1
- package/docs/configuration/ai.mdx +35 -0
- package/docs/configuration/index.mdx +14 -2
- package/docs/configuration/search.mdx +4 -4
- package/docs/configuration/theming.mdx +4 -2
- package/docs/reference/cli.mdx +2 -2
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +1 -1
- package/src/ai/ask-context.ts +51 -11
- package/src/ai/mcp/data.ts +3 -2
- package/src/ai/mcp/server.ts +3 -2
- package/src/assets/icon-dark.png +0 -0
- package/src/astro/generate.ts +172 -18
- package/src/astro/templates.ts +89 -15
- package/src/components/content/AccordionItem.astro +4 -0
- package/src/components/content/Update.astro +3 -0
- package/src/components/islands/AskAI.astro +6 -0
- package/src/components/islands/ask-ai.tsx +39 -9
- package/src/components/layout/Analytics.astro +9 -1
- package/src/components/layout/Favicon.astro +29 -8
- package/src/components/layout/Fonts.astro +23 -3
- package/src/components/layout/Header.astro +2 -2
- package/src/components/layout/NavSelector.astro +1 -1
- package/src/components/layout/PageActions.astro +120 -78
- package/src/components/layout/PageFeedback.astro +12 -3
- package/src/components/layout/PageLayout.astro +79 -5
- package/src/components/layout/ReferenceLayout.astro +12 -9
- package/src/components/layout/RootLayout.astro +153 -121
- package/src/components/layout/Search.astro +41 -26
- package/src/components/layout/drawer-inert.ts +10 -5
- package/src/components/layout/head-scripts.ts +34 -16
- package/src/components/layout/nav-utils.ts +34 -15
- package/src/components/layout/search/orama.ts +3 -2
- package/src/components/openapi/AsyncApiOperation.astro +22 -7
- package/src/components/openapi/MessageComposer.astro +238 -0
- package/src/components/openapi/Operation.astro +26 -12
- package/src/components/openapi/PanelTabs.astro +7 -0
- package/src/components/openapi/Playground.astro +320 -0
- package/src/components/openapi/RequestPanel.astro +1 -0
- package/src/components/openapi/async-snippets.ts +20 -7
- package/src/components/openapi/async.ts +13 -2
- package/src/components/openapi/message-composer.ts +242 -0
- package/src/components/openapi/message-model.ts +108 -0
- package/src/components/openapi/message.ts +153 -0
- package/src/components/openapi/operation-model.ts +260 -0
- package/src/components/openapi/playground-client.ts +486 -0
- package/src/components/openapi/playground-schema.ts +109 -0
- package/src/components/openapi/request.ts +287 -0
- package/src/components/openapi/security.ts +0 -56
- package/src/components/openapi/snippets.ts +23 -136
- package/src/components/openapi/validate-json.ts +144 -0
- package/src/components/openapi/ws-client.ts +194 -0
- package/src/core/config-input.ts +67 -1
- package/src/core/content-assets.ts +66 -15
- package/src/core/data.ts +16 -2
- package/src/core/last-modified.ts +76 -2
- package/src/core/links.ts +30 -4
- package/src/core/navigation.ts +26 -1
- package/src/core/open-in-chat.ts +17 -0
- package/src/core/project-graph.ts +11 -0
- package/src/core/schema.ts +60 -1
- package/src/core/server-features.ts +11 -0
- package/src/core/sources/normalize.ts +10 -2
- package/src/core/types.ts +10 -3
- package/src/deploy/vercel-negotiation.ts +34 -14
- package/src/og/card.ts +3 -1
- package/src/openapi/model.ts +7 -0
- package/src/openapi/proxy.ts +217 -0
- package/src/openapi/references.ts +8 -0
- package/src/openapi/source.ts +13 -0
- package/src/registry/eject.ts +4 -5
- package/src/search/orama-index.ts +109 -36
- package/src/theme/entry.ts +15 -2
- package/src/theme/fonts.ts +75 -3
package/dist/cli/index.js
CHANGED
|
@@ -3179,11 +3179,13 @@ var referencesFor = (kind, block, defaultLabel, renderer, display, basePath) =>
|
|
|
3179
3179
|
var resolveReferences = (config) => [
|
|
3180
3180
|
...referencesFor("openapi", config.openapi, "API Reference", config.openapi.renderer, {
|
|
3181
3181
|
codeSamples: config.openapi.codeSamples,
|
|
3182
|
-
expandSchemas: config.openapi.expandSchemas
|
|
3182
|
+
expandSchemas: config.openapi.expandSchemas,
|
|
3183
|
+
playground: config.openapi.playground
|
|
3183
3184
|
}, config.basePath),
|
|
3184
3185
|
...referencesFor("asyncapi", config.asyncapi, "Events", config.asyncapi.renderer, {
|
|
3185
3186
|
codeSamples: config.asyncapi.codeSamples,
|
|
3186
|
-
expandSchemas: config.asyncapi.expandSchemas
|
|
3187
|
+
expandSchemas: config.asyncapi.expandSchemas,
|
|
3188
|
+
playground: config.asyncapi.playground
|
|
3187
3189
|
}, config.basePath)
|
|
3188
3190
|
];
|
|
3189
3191
|
var referenceRoutes = (config) => resolveReferences(config).map((ref) => ref.renderer === "blume" ? withBasePath(config.basePath, ref.route) : ref.route);
|
|
@@ -3607,7 +3609,47 @@ ${lines.join(`
|
|
|
3607
3609
|
}
|
|
3608
3610
|
` : "";
|
|
3609
3611
|
};
|
|
3610
|
-
var
|
|
3612
|
+
var PRELOAD_WEIGHTS = {
|
|
3613
|
+
body: [400, 500],
|
|
3614
|
+
display: [500, 600],
|
|
3615
|
+
mono: [400]
|
|
3616
|
+
};
|
|
3617
|
+
var entryWeights = (entry) => entry.kind === "remote" ? entry.weights : entry.variants.map((variant) => variant.weight);
|
|
3618
|
+
var preloadWeightsFor = (slot, entry) => {
|
|
3619
|
+
const preferred = PRELOAD_WEIGHTS[slot];
|
|
3620
|
+
const weights = entryWeights(entry);
|
|
3621
|
+
const numeric = weights.filter((weight) => typeof weight === "number");
|
|
3622
|
+
const hits = preferred.filter((weight) => numeric.includes(weight));
|
|
3623
|
+
if (hits.length > 0) {
|
|
3624
|
+
return hits;
|
|
3625
|
+
}
|
|
3626
|
+
return numeric.length === weights.length ? numeric : preferred;
|
|
3627
|
+
};
|
|
3628
|
+
var configuredFonts = (fonts) => {
|
|
3629
|
+
if (!fonts) {
|
|
3630
|
+
return [];
|
|
3631
|
+
}
|
|
3632
|
+
const heads = new Map;
|
|
3633
|
+
for (const slot of SLOTS) {
|
|
3634
|
+
const value = fonts[slot];
|
|
3635
|
+
if (value === undefined) {
|
|
3636
|
+
continue;
|
|
3637
|
+
}
|
|
3638
|
+
const entry = resolveFontValue(slot, value);
|
|
3639
|
+
if (!entry) {
|
|
3640
|
+
continue;
|
|
3641
|
+
}
|
|
3642
|
+
const weights = heads.get(entry.cssVariable) ?? new Set;
|
|
3643
|
+
for (const weight of preloadWeightsFor(slot, entry)) {
|
|
3644
|
+
weights.add(weight);
|
|
3645
|
+
}
|
|
3646
|
+
heads.set(entry.cssVariable, weights);
|
|
3647
|
+
}
|
|
3648
|
+
return [...heads].map(([cssVariable, weights]) => ({
|
|
3649
|
+
cssVariable,
|
|
3650
|
+
preloadWeights: [...weights].toSorted((a, b) => a - b)
|
|
3651
|
+
}));
|
|
3652
|
+
};
|
|
3611
3653
|
|
|
3612
3654
|
// src/astro/templates.ts
|
|
3613
3655
|
var WORKSPACE_MARKERS = [
|
|
@@ -3936,6 +3978,11 @@ ${userConfigSetup}export default defineConfig({
|
|
|
3936
3978
|
},
|
|
3937
3979
|
},
|
|
3938
3980
|
devToolbar: { enabled: false },
|
|
3981
|
+
// The layouts render Astro's <ClientRouter />, and its in-place swaps read
|
|
3982
|
+
// from the prefetch cache — fetching every link on hover/viewport hides the
|
|
3983
|
+
// request latency behind the user's intent, so most navigations swap
|
|
3984
|
+
// instantly.
|
|
3985
|
+
prefetch: { prefetchAll: true },
|
|
3939
3986
|
vite: {
|
|
3940
3987
|
plugins: [tailwindcss(), prerenderDepsPlugin(), serverAppResolvePlugin()],
|
|
3941
3988
|
// Everything hydration can reach must be part of the dev dep optimizer's
|
|
@@ -4047,7 +4094,8 @@ export const collections = { docs${options.staged ? ", staged" : ""} };
|
|
|
4047
4094
|
`;
|
|
4048
4095
|
};
|
|
4049
4096
|
var ASK_FALLBACK_PROMPT = "You are a helpful documentation assistant. Answer using the project's documentation.";
|
|
4050
|
-
var askEndpointTemplate = (backend, grounded,
|
|
4097
|
+
var askEndpointTemplate = (backend, grounded, options) => {
|
|
4098
|
+
const instructions = options?.instructions;
|
|
4051
4099
|
const fallbackPrompt = instructions ? `${ASK_FALLBACK_PROMPT}
|
|
4052
4100
|
|
|
4053
4101
|
${instructions}` : ASK_FALLBACK_PROMPT;
|
|
@@ -4076,7 +4124,14 @@ const provider = createOpenAICompatible({
|
|
|
4076
4124
|
}
|
|
4077
4125
|
if (grounded) {
|
|
4078
4126
|
imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "../../generated/ask-data.json";');
|
|
4079
|
-
const
|
|
4127
|
+
const groundFields = [];
|
|
4128
|
+
if (instructions) {
|
|
4129
|
+
groundFields.push(`instructions: ${JSON.stringify(instructions)}`);
|
|
4130
|
+
}
|
|
4131
|
+
if (options?.retrieval) {
|
|
4132
|
+
groundFields.push(`retrieval: ${JSON.stringify(options.retrieval)}`);
|
|
4133
|
+
}
|
|
4134
|
+
const groundOptions = groundFields.length > 0 ? `, { ${groundFields.join(", ")} }` : "";
|
|
4080
4135
|
setup += `
|
|
4081
4136
|
const ground = createAskContext(askData${groundOptions});
|
|
4082
4137
|
`;
|
|
@@ -4414,6 +4469,16 @@ const handler = createMcpFetchHandler(data as McpData);
|
|
|
4414
4469
|
export const ALL: APIRoute = ({ request }) => handler(request);
|
|
4415
4470
|
`;
|
|
4416
4471
|
};
|
|
4472
|
+
var playgroundProxyTemplate = (origins) => `// Generated by Blume. Do not edit.
|
|
4473
|
+
import type { APIRoute } from "astro";
|
|
4474
|
+
import { createPlaygroundProxyHandler } from "blume/openapi/proxy.ts";
|
|
4475
|
+
|
|
4476
|
+
export const prerender = false;
|
|
4477
|
+
|
|
4478
|
+
const handler = createPlaygroundProxyHandler(${JSON.stringify(origins)});
|
|
4479
|
+
|
|
4480
|
+
export const ALL: APIRoute = ({ request }) => handler(request);
|
|
4481
|
+
`;
|
|
4417
4482
|
var staticJsonEndpointTemplate = (payload) => `// Generated by Blume. Do not edit.
|
|
4418
4483
|
export const prerender = true;
|
|
4419
4484
|
|
|
@@ -4444,7 +4509,7 @@ export function GET({ props }: { props: { section: string } }) {
|
|
|
4444
4509
|
});
|
|
4445
4510
|
}
|
|
4446
4511
|
`;
|
|
4447
|
-
var ogEndpointTemplate = (customRoutes = [], og = {}) => `// Generated by Blume. Do not edit.
|
|
4512
|
+
var ogEndpointTemplate = (customRoutes = [], og = {}, includeChangelog = false) => `// Generated by Blume. Do not edit.
|
|
4448
4513
|
import { renderOgImage } from "blume/og";
|
|
4449
4514
|
import type { OgFont, OgFontFamilies } from "blume/og";
|
|
4450
4515
|
import data from "blume:data";
|
|
@@ -4479,7 +4544,10 @@ export function getStaticPaths() {
|
|
|
4479
4544
|
}
|
|
4480
4545
|
for (const route of data.routes) {
|
|
4481
4546
|
add(route.path === "/" ? "index" : route.path.slice(1), route.title);
|
|
4482
|
-
}
|
|
4547
|
+
}${includeChangelog ? `
|
|
4548
|
+
// The generated changelog index is not a content route, so it needs its own
|
|
4549
|
+
// card. Added last: a custom page or content route owning /changelog wins.
|
|
4550
|
+
add("changelog", data.ui.changelog?.title ?? "Changelog");` : ""}
|
|
4483
4551
|
return paths;
|
|
4484
4552
|
}
|
|
4485
4553
|
|
|
@@ -4753,10 +4821,9 @@ const contentLocale =
|
|
|
4753
4821
|
const contentDir = i18n
|
|
4754
4822
|
? (i18n.locales.find((l) => l.code === contentLocale)?.dir ?? "ltr")
|
|
4755
4823
|
: "ltr";
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
};
|
|
4824
|
+
// The root route keeps its trailing slash (\`https://site/\`) so canonical and
|
|
4825
|
+
// hreflang URLs byte-match the sitemap's <loc> for the home page.
|
|
4826
|
+
const absolute = (path: string) => base + withBase(path);
|
|
4760
4827
|
|
|
4761
4828
|
// An archived page defaults its canonical to the same page in the latest docs
|
|
4762
4829
|
// when that page still exists — search engines treat the live page as
|
|
@@ -4767,7 +4834,7 @@ const canonical =
|
|
|
4767
4834
|
(archived && archived.canonical === "latest" && latestVersionAlt && base
|
|
4768
4835
|
? absolute(latestVersionAlt.path)
|
|
4769
4836
|
: base
|
|
4770
|
-
? \`\${base}\${basedRoute === "/" ? "" : encodeURI(basedRoute)}\`
|
|
4837
|
+
? \`\${base}\${basedRoute === "/" ? "/" : encodeURI(basedRoute)}\`
|
|
4771
4838
|
: null);
|
|
4772
4839
|
const effectiveNoindex = Boolean(seo.noindex) || (archived?.noindex ?? false);
|
|
4773
4840
|
|
|
@@ -4902,6 +4969,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
4902
4969
|
feedback={data.config.feedback}
|
|
4903
4970
|
exportPdf={${options.exportPdf}}
|
|
4904
4971
|
exportEpub={${options.exportEpub}}
|
|
4972
|
+
openInChat={data.config.openInChat}
|
|
4905
4973
|
feeds={data.feeds}
|
|
4906
4974
|
discovery={data.config.discovery}
|
|
4907
4975
|
siteUrl={data.config.site}
|
|
@@ -5061,6 +5129,12 @@ const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
|
5061
5129
|
const basedRoute = withBase("/changelog");
|
|
5062
5130
|
const canonical = base ? base + basedRoute : null;
|
|
5063
5131
|
|
|
5132
|
+
// The generated OG card for this route (the /og endpoint emits it alongside
|
|
5133
|
+
// the content-route cards), absolutized like the catch-all's so crawlers get
|
|
5134
|
+
// a full URL when the site is known.
|
|
5135
|
+
const ogPath = data.config.og.enabled ? withBase("/og/changelog.png") : null;
|
|
5136
|
+
const ogImage = ogPath && base ? base + ogPath : ogPath;
|
|
5137
|
+
|
|
5064
5138
|
// The page chrome (h1, title, description) comes from the same translatable
|
|
5065
5139
|
// \`changelog\` group as the reveal button; optional chaining tolerates a
|
|
5066
5140
|
// not-yet-regenerated data snapshot from before these keys existed.
|
|
@@ -5068,7 +5142,10 @@ const changelogTitle = data.ui.changelog?.title ?? "Changelog";
|
|
|
5068
5142
|
const changelogDescription =
|
|
5069
5143
|
data.ui.changelog?.description ??
|
|
5070
5144
|
"Product updates, new features, and fixes from every release.";
|
|
5071
|
-
|
|
5145
|
+
// The layout suffixes "- {site title}" itself, so the page title is just the
|
|
5146
|
+
// changelog's own name — prefixing the site title too would double it
|
|
5147
|
+
// ("Acme Changelog - Acme").
|
|
5148
|
+
const pageTitle = changelogTitle;
|
|
5072
5149
|
|
|
5073
5150
|
const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
5074
5151
|
---
|
|
@@ -5100,11 +5177,13 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
5100
5177
|
fontCssVars={data.fontCssVars}
|
|
5101
5178
|
searchEnabled={data.config.search.enabled}
|
|
5102
5179
|
indexable={true}
|
|
5103
|
-
ogImage={
|
|
5180
|
+
ogImage={ogImage}
|
|
5181
|
+
ogGenerated={Boolean(ogImage)}
|
|
5104
5182
|
x={data.config.x}
|
|
5105
5183
|
canonical={canonical}
|
|
5106
5184
|
exportPdf={${options.exportPdf}}
|
|
5107
5185
|
exportEpub={${options.exportEpub}}
|
|
5186
|
+
openInChat={data.config.openInChat}
|
|
5108
5187
|
feeds={data.feeds}
|
|
5109
5188
|
discovery={data.config.discovery}
|
|
5110
5189
|
siteUrl={data.config.site}
|
|
@@ -9566,6 +9645,16 @@ var resolveUIStrings = (locale, options) => {
|
|
|
9566
9645
|
return dict;
|
|
9567
9646
|
};
|
|
9568
9647
|
|
|
9648
|
+
// src/core/open-in-chat.ts
|
|
9649
|
+
var openInChatProviders = [
|
|
9650
|
+
"v0",
|
|
9651
|
+
"chatgpt",
|
|
9652
|
+
"claude",
|
|
9653
|
+
"t3",
|
|
9654
|
+
"scira",
|
|
9655
|
+
"cursor"
|
|
9656
|
+
];
|
|
9657
|
+
|
|
9569
9658
|
// src/core/standard-schema.ts
|
|
9570
9659
|
var isStandardSchema = (value) => typeof value === "object" && value !== null && typeof value["~standard"]?.validate === "function";
|
|
9571
9660
|
|
|
@@ -9861,7 +9950,7 @@ var themeConfigSchema = z2.strictObject({
|
|
|
9861
9950
|
backgroundImage: perModeValueSchema,
|
|
9862
9951
|
fonts: z2.strictObject({
|
|
9863
9952
|
body: fontValueSchema.default("inter"),
|
|
9864
|
-
display: fontValueSchema.default("inter
|
|
9953
|
+
display: fontValueSchema.default("inter"),
|
|
9865
9954
|
mono: fontValueSchema.default("ibm-plex-mono")
|
|
9866
9955
|
}).prefault({}),
|
|
9867
9956
|
layout: z2.enum(["sidebar"]).default("sidebar"),
|
|
@@ -9980,6 +10069,11 @@ var aiConfigSchema = z2.strictObject({
|
|
|
9980
10069
|
instructions: z2.string().trim().min(1).optional(),
|
|
9981
10070
|
model: z2.string().default("openai/gpt-5.5"),
|
|
9982
10071
|
provider: z2.enum(askAiProviders).default("gateway"),
|
|
10072
|
+
retrieval: z2.strictObject({
|
|
10073
|
+
contextBudget: z2.number().int().positive().optional(),
|
|
10074
|
+
excerptChars: z2.number().int().positive().optional(),
|
|
10075
|
+
maxResults: z2.number().int().positive().optional()
|
|
10076
|
+
}).optional(),
|
|
9983
10077
|
suggestions: z2.array(z2.strictObject({
|
|
9984
10078
|
icon: iconName.optional(),
|
|
9985
10079
|
label: z2.string().min(1)
|
|
@@ -10004,6 +10098,17 @@ var aiConfigSchema = z2.strictObject({
|
|
|
10004
10098
|
message: "Expected a serializer function."
|
|
10005
10099
|
})).default({}),
|
|
10006
10100
|
mcp: mcpConfigSchema.prefault({}),
|
|
10101
|
+
openInChat: z2.union([
|
|
10102
|
+
z2.boolean(),
|
|
10103
|
+
z2.array(z2.enum(openInChatProviders)).refine((value) => new Set(value).size === value.length, {
|
|
10104
|
+
message: "ai.openInChat must not repeat a provider."
|
|
10105
|
+
})
|
|
10106
|
+
]).default(true).transform((value) => {
|
|
10107
|
+
if (isBoolean(value)) {
|
|
10108
|
+
return value ? [...openInChatProviders] : [];
|
|
10109
|
+
}
|
|
10110
|
+
return value;
|
|
10111
|
+
}),
|
|
10007
10112
|
skills: z2.string().min(1).optional(),
|
|
10008
10113
|
webBotAuth: z2.strictObject({
|
|
10009
10114
|
keys: z2.array(publicJwkSchema).default([])
|
|
@@ -10279,6 +10384,13 @@ var referenceConfigSchema = (defaults) => z2.strictObject({
|
|
|
10279
10384
|
codeSamples: z2.array(z2.string()).default(defaults.codeSamples),
|
|
10280
10385
|
enabled: z2.boolean().default(false),
|
|
10281
10386
|
expandSchemas: z2.boolean().default(false),
|
|
10387
|
+
playground: z2.union([
|
|
10388
|
+
z2.boolean(),
|
|
10389
|
+
z2.strictObject({
|
|
10390
|
+
enabled: z2.boolean().default(true),
|
|
10391
|
+
proxy: z2.union([z2.boolean(), z2.string()]).default(false)
|
|
10392
|
+
})
|
|
10393
|
+
]).default(true).transform((value) => isBoolean(value) ? { enabled: value, proxy: false } : value),
|
|
10282
10394
|
renderer: z2.enum(["blume", "scalar"]).default("blume"),
|
|
10283
10395
|
route: z2.string().default(defaults.route),
|
|
10284
10396
|
scalar: scalarConfigSchema,
|
|
@@ -10718,6 +10830,8 @@ import { extname } from "pathe";
|
|
|
10718
10830
|
var NUMERIC_PREFIX = /^(?<order>\d+)[-_.]/u;
|
|
10719
10831
|
var GROUP_FOLDER = /^\((?<label>.+)\)$/u;
|
|
10720
10832
|
var WORD_SPLIT = /[-_]/u;
|
|
10833
|
+
var isUnderPath = (route, base) => base === "/" || route === base || route.startsWith(`${base}/`);
|
|
10834
|
+
var isRootTab = (tab, root) => isUnderPath(root, tab.path);
|
|
10721
10835
|
var humanize = (segment) => segment.replace(NUMERIC_PREFIX, "").split(WORD_SPLIT).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
10722
10836
|
var numericOrder = (segment) => {
|
|
10723
10837
|
const value = segment.match(NUMERIC_PREFIX)?.groups?.order;
|
|
@@ -11174,7 +11288,7 @@ var buildNavigation = (pages, options) => {
|
|
|
11174
11288
|
tabs: withTabHrefs(tabs, sidebar2)
|
|
11175
11289
|
};
|
|
11176
11290
|
}
|
|
11177
|
-
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, sharedMetaPrefix, display, new Set(tabs.flatMap((tab) => tab
|
|
11291
|
+
const sidebar = buildFileSystemSidebar(pages, options.folderMeta, sharedFolderMeta, metaPrefix, sharedMetaPrefix, display, new Set(tabs.flatMap((tab) => isRootTab(tab, rootTabPath) ? [] : [tab.path])), diagnostics);
|
|
11178
11292
|
return {
|
|
11179
11293
|
featured,
|
|
11180
11294
|
root: rootTabPath,
|
|
@@ -11406,6 +11520,15 @@ var buildContentGraph = (pages, options) => {
|
|
|
11406
11520
|
// src/core/last-modified.ts
|
|
11407
11521
|
import { execFileSync } from "node:child_process";
|
|
11408
11522
|
import { relative as relative7 } from "pathe";
|
|
11523
|
+
var GIT_LOCATION_VARS = new Set([
|
|
11524
|
+
"GIT_COMMON_DIR",
|
|
11525
|
+
"GIT_DIR",
|
|
11526
|
+
"GIT_INDEX_FILE",
|
|
11527
|
+
"GIT_OBJECT_DIRECTORY",
|
|
11528
|
+
"GIT_PREFIX",
|
|
11529
|
+
"GIT_WORK_TREE"
|
|
11530
|
+
]);
|
|
11531
|
+
var gitEnv = () => Object.fromEntries(Object.entries(process.env).filter(([key]) => !GIT_LOCATION_VARS.has(key)));
|
|
11409
11532
|
var resolveLastModifiedConfig = (value) => {
|
|
11410
11533
|
if (value === false) {
|
|
11411
11534
|
return { enabled: false, source: "git" };
|
|
@@ -11433,7 +11556,7 @@ var gitLastModifiedTimes = (root, contentRoots, sourcePaths) => {
|
|
|
11433
11556
|
return new Map;
|
|
11434
11557
|
}
|
|
11435
11558
|
try {
|
|
11436
|
-
const gitRoot = execFileSync("git", ["-C", root, "rev-parse", "--show-toplevel"], { encoding: "utf-8" }).trim();
|
|
11559
|
+
const gitRoot = execFileSync("git", ["-C", root, "rev-parse", "--show-toplevel"], { encoding: "utf-8", env: gitEnv() }).trim();
|
|
11437
11560
|
const output = execFileSync("git", [
|
|
11438
11561
|
"-C",
|
|
11439
11562
|
root,
|
|
@@ -11444,7 +11567,7 @@ var gitLastModifiedTimes = (root, contentRoots, sourcePaths) => {
|
|
|
11444
11567
|
"--name-only",
|
|
11445
11568
|
"--",
|
|
11446
11569
|
...contentRoots
|
|
11447
|
-
], { encoding: "utf-8", maxBuffer: 256 * 1024 * 1024 });
|
|
11570
|
+
], { encoding: "utf-8", env: gitEnv(), maxBuffer: 256 * 1024 * 1024 });
|
|
11448
11571
|
const byRepoPath = parseGitLog(output);
|
|
11449
11572
|
const result = new Map;
|
|
11450
11573
|
for (const sourcePath of sourcePaths) {
|
|
@@ -11458,6 +11581,30 @@ var gitLastModifiedTimes = (root, contentRoots, sourcePaths) => {
|
|
|
11458
11581
|
return new Map;
|
|
11459
11582
|
}
|
|
11460
11583
|
};
|
|
11584
|
+
var isShallowGitRepository = (root) => {
|
|
11585
|
+
try {
|
|
11586
|
+
return execFileSync("git", ["-C", root, "rev-parse", "--is-shallow-repository"], {
|
|
11587
|
+
encoding: "utf-8",
|
|
11588
|
+
env: gitEnv(),
|
|
11589
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
11590
|
+
}).trim() === "true";
|
|
11591
|
+
} catch {
|
|
11592
|
+
return false;
|
|
11593
|
+
}
|
|
11594
|
+
};
|
|
11595
|
+
var lastModifiedShallowWarning = (root, undatedCount) => {
|
|
11596
|
+
if (undatedCount === 0 || !isShallowGitRepository(root)) {
|
|
11597
|
+
return [];
|
|
11598
|
+
}
|
|
11599
|
+
return [
|
|
11600
|
+
{
|
|
11601
|
+
code: "BLUME_SHALLOW_GIT_HISTORY",
|
|
11602
|
+
message: `lastModified is on, but this build runs in a shallow git clone, so ${undatedCount} page(s) have no git-derived date — their sitemap <lastmod> and "Last updated" stamps are omitted.`,
|
|
11603
|
+
severity: "warning",
|
|
11604
|
+
suggestion: "Fetch full history in CI: set the VERCEL_DEEP_CLONE=true environment variable on Vercel, or fetch-depth: 0 for actions/checkout."
|
|
11605
|
+
}
|
|
11606
|
+
];
|
|
11607
|
+
};
|
|
11461
11608
|
|
|
11462
11609
|
// src/core/manifest.ts
|
|
11463
11610
|
var versionAlternateKey = (versionKey, locale) => `${versionKey}\x00${locale}`;
|
|
@@ -11829,11 +11976,15 @@ var scanLinkLine = (line, lineNumber, fence, links) => {
|
|
|
11829
11976
|
continue;
|
|
11830
11977
|
}
|
|
11831
11978
|
const targetOffset = targetOffsetIn(match[0], target, match.groups?.title);
|
|
11832
|
-
|
|
11979
|
+
const entry = {
|
|
11833
11980
|
column: match.index + targetOffset + 1,
|
|
11834
11981
|
line: lineNumber,
|
|
11835
11982
|
target
|
|
11836
|
-
}
|
|
11983
|
+
};
|
|
11984
|
+
if (masked[match.index - 1] === "!") {
|
|
11985
|
+
entry.image = true;
|
|
11986
|
+
}
|
|
11987
|
+
links.push(entry);
|
|
11837
11988
|
const label = match[0].slice(0, targetOffset - "](".length);
|
|
11838
11989
|
for (const image of label.matchAll(MD_IMAGE)) {
|
|
11839
11990
|
const imageTarget = image.groups?.target;
|
|
@@ -11842,6 +11993,7 @@ var scanLinkLine = (line, lineNumber, fence, links) => {
|
|
|
11842
11993
|
}
|
|
11843
11994
|
links.push({
|
|
11844
11995
|
column: match.index + image.index + targetOffsetIn(image[0], imageTarget, image.groups?.title) + 1,
|
|
11996
|
+
image: true,
|
|
11845
11997
|
line: lineNumber,
|
|
11846
11998
|
target: imageTarget
|
|
11847
11999
|
});
|
|
@@ -12790,6 +12942,13 @@ var openApiSource = (references, ctx) => {
|
|
|
12790
12942
|
try {
|
|
12791
12943
|
const { document, warnings, operations, tags, extractWarnings } = await parseReference(reference, ctx);
|
|
12792
12944
|
const info = document.info ?? { title: reference.label, version: "" };
|
|
12945
|
+
const { proxy: configuredProxy } = reference.display.playground;
|
|
12946
|
+
let proxy = false;
|
|
12947
|
+
if (configuredProxy === true) {
|
|
12948
|
+
proxy = withBasePath(reference.basePath, "/_api-proxy");
|
|
12949
|
+
} else if (configuredProxy !== false && configuredProxy !== "") {
|
|
12950
|
+
proxy = configuredProxy;
|
|
12951
|
+
}
|
|
12793
12952
|
const spec = {
|
|
12794
12953
|
codeSamples: reference.display.codeSamples,
|
|
12795
12954
|
description: info.description ?? "",
|
|
@@ -12804,6 +12963,7 @@ var openApiSource = (references, ctx) => {
|
|
|
12804
12963
|
route: withBasePath(reference.basePath, operation.route)
|
|
12805
12964
|
}
|
|
12806
12965
|
])),
|
|
12966
|
+
playground: { enabled: reference.display.playground.enabled, proxy },
|
|
12807
12967
|
route: reference.route,
|
|
12808
12968
|
slug: reference.slug,
|
|
12809
12969
|
tags,
|
|
@@ -14029,6 +14189,7 @@ var scanProject = async (root, options = {}) => {
|
|
|
14029
14189
|
} = normalizeLoadedEntries(loaded, config);
|
|
14030
14190
|
const pages = mode === "build" && !preview ? allPages.filter((page) => !page.meta.draft) : allPages;
|
|
14031
14191
|
const lastModified = resolveLastModifiedConfig(config.lastModified);
|
|
14192
|
+
const lastModifiedWarnings = [];
|
|
14032
14193
|
if (lastModified.enabled && lastModified.source === "git") {
|
|
14033
14194
|
const fsPaths = pages.map((page) => page.sourcePath).filter((path) => path !== undefined);
|
|
14034
14195
|
const contentRoots = sources.flatMap((source) => source.staged || !source.contentRoot ? [] : [source.contentRoot]);
|
|
@@ -14038,6 +14199,8 @@ var scanProject = async (root, options = {}) => {
|
|
|
14038
14199
|
page.lastModified = gitTimes.get(page.sourcePath);
|
|
14039
14200
|
}
|
|
14040
14201
|
}
|
|
14202
|
+
const undated = pages.filter((page) => page.sourcePath && !page.lastModified).length;
|
|
14203
|
+
lastModifiedWarnings.push(...lastModifiedShallowWarning(context.root, undated));
|
|
14041
14204
|
}
|
|
14042
14205
|
const graph = buildContentGraph(pages, {
|
|
14043
14206
|
basePath: config.basePath,
|
|
@@ -14059,7 +14222,8 @@ var scanProject = async (root, options = {}) => {
|
|
|
14059
14222
|
...entryIdDiagnostics(pages, resolveDocsCollection(config, context).base),
|
|
14060
14223
|
...graph.diagnostics,
|
|
14061
14224
|
...i18nWarnings,
|
|
14062
|
-
...versionWarnings
|
|
14225
|
+
...versionWarnings,
|
|
14226
|
+
...lastModifiedWarnings
|
|
14063
14227
|
],
|
|
14064
14228
|
droppedPages,
|
|
14065
14229
|
graph,
|
|
@@ -14250,7 +14414,7 @@ var auditCommand = defineCommand2({
|
|
|
14250
14414
|
});
|
|
14251
14415
|
|
|
14252
14416
|
// src/cli/commands/build.ts
|
|
14253
|
-
import { existsSync as
|
|
14417
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
14254
14418
|
import { mkdir as mkdir8, readdir as readdir2, readFile as readFile17, stat as stat3, writeFile as writeFile7 } from "node:fs/promises";
|
|
14255
14419
|
import { build } from "astro";
|
|
14256
14420
|
import { defineCommand as defineCommand3 } from "citty";
|
|
@@ -14423,9 +14587,16 @@ var buildAgentReadability = (project) => {
|
|
|
14423
14587
|
};
|
|
14424
14588
|
|
|
14425
14589
|
// src/core/content-assets.ts
|
|
14426
|
-
import {
|
|
14590
|
+
import { readdirSync, statSync } from "node:fs";
|
|
14427
14591
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
14428
|
-
import {
|
|
14592
|
+
import {
|
|
14593
|
+
basename as basename2,
|
|
14594
|
+
dirname as dirname7,
|
|
14595
|
+
extname as extname5,
|
|
14596
|
+
normalize as normalize3,
|
|
14597
|
+
relative as relative11,
|
|
14598
|
+
resolve as resolve5
|
|
14599
|
+
} from "pathe";
|
|
14429
14600
|
var CONTENT_ASSETS_PREFIX = "/blume-assets/content";
|
|
14430
14601
|
var IMAGE_EXTENSIONS = new Set([
|
|
14431
14602
|
".apng",
|
|
@@ -14448,19 +14619,40 @@ var contentAssetParam = (projectRoot, absPath) => {
|
|
|
14448
14619
|
}
|
|
14449
14620
|
return rel;
|
|
14450
14621
|
};
|
|
14451
|
-
var
|
|
14452
|
-
if (!isRelativeTarget(target)) {
|
|
14453
|
-
return null;
|
|
14454
|
-
}
|
|
14455
|
-
let decoded = target;
|
|
14622
|
+
var decodeTarget = (target) => {
|
|
14456
14623
|
try {
|
|
14457
|
-
|
|
14458
|
-
} catch {
|
|
14459
|
-
|
|
14624
|
+
return decodeURI(target);
|
|
14625
|
+
} catch {
|
|
14626
|
+
return target;
|
|
14627
|
+
}
|
|
14628
|
+
};
|
|
14629
|
+
var isRelativeImageTarget = (target) => isRelativeTarget(target) && IMAGE_EXTENSIONS.has(extname5(decodeTarget(target)).toLowerCase());
|
|
14630
|
+
var existsAsWritten = (abs, segments) => {
|
|
14631
|
+
let current = abs;
|
|
14632
|
+
for (let i = 0;i < segments; i += 1) {
|
|
14633
|
+
const parent = dirname7(current);
|
|
14634
|
+
let entries;
|
|
14635
|
+
try {
|
|
14636
|
+
entries = readdirSync(parent);
|
|
14637
|
+
} catch {
|
|
14638
|
+
return false;
|
|
14639
|
+
}
|
|
14640
|
+
if (!entries.includes(basename2(current))) {
|
|
14641
|
+
return false;
|
|
14642
|
+
}
|
|
14643
|
+
current = parent;
|
|
14644
|
+
}
|
|
14645
|
+
const stat2 = statSync(abs, { throwIfNoEntry: false });
|
|
14646
|
+
return stat2 !== undefined && stat2.isFile();
|
|
14647
|
+
};
|
|
14648
|
+
var resolveRelativeImage = (sourceDir, target) => {
|
|
14649
|
+
if (!isRelativeImageTarget(target)) {
|
|
14460
14650
|
return null;
|
|
14461
14651
|
}
|
|
14652
|
+
const decoded = decodeTarget(target);
|
|
14653
|
+
const segments = normalize3(decoded).split("/").filter((part) => part !== "" && part !== "..").length;
|
|
14462
14654
|
const abs = resolve5(sourceDir, decoded);
|
|
14463
|
-
return
|
|
14655
|
+
return existsAsWritten(abs, segments) ? abs : null;
|
|
14464
14656
|
};
|
|
14465
14657
|
var encodedParam = (param) => param.split("/").map(encodeURIComponent).join("/");
|
|
14466
14658
|
var rewriteLine = (line, toUrl2) => {
|
|
@@ -15178,13 +15370,13 @@ var buildSignaturesDirectory = (config) => {
|
|
|
15178
15370
|
};
|
|
15179
15371
|
|
|
15180
15372
|
// src/core/gitignore.ts
|
|
15181
|
-
import { existsSync as
|
|
15373
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
15182
15374
|
import { readFile as readFile12, writeFile as writeFile6 } from "node:fs/promises";
|
|
15183
15375
|
import { join as join19 } from "pathe";
|
|
15184
15376
|
var gitignoreKey = (line) => line.trim().replace(/\/+$/u, "");
|
|
15185
15377
|
var ensureGitignore = async (root, entries) => {
|
|
15186
15378
|
const path = join19(root, ".gitignore");
|
|
15187
|
-
const existing =
|
|
15379
|
+
const existing = existsSync9(path) ? await readFile12(path, "utf-8") : "";
|
|
15188
15380
|
const present = new Set(existing.split(`
|
|
15189
15381
|
`).flatMap((line) => {
|
|
15190
15382
|
const key = gitignoreKey(line);
|
|
@@ -15212,6 +15404,9 @@ var serverFeatures = (config) => {
|
|
|
15212
15404
|
if (config.ai.mcp.enabled) {
|
|
15213
15405
|
features.push("MCP server");
|
|
15214
15406
|
}
|
|
15407
|
+
if (config.openapi.enabled && config.openapi.renderer === "blume" && config.openapi.playground.enabled && config.openapi.playground.proxy === true) {
|
|
15408
|
+
features.push("API playground proxy");
|
|
15409
|
+
}
|
|
15215
15410
|
if (searchProviderMeta(config.search.provider).requiresServer) {
|
|
15216
15411
|
features.push(`Search (${config.search.provider})`);
|
|
15217
15412
|
}
|
|
@@ -15818,12 +16013,14 @@ var buildNegotiationRoutes = (routePaths, homeTokens) => {
|
|
|
15818
16013
|
return { headerRoutes, rewriteRoutes };
|
|
15819
16014
|
};
|
|
15820
16015
|
var HOME_SRC = "^/$";
|
|
15821
|
-
var
|
|
16016
|
+
var TRAILING_SLASH_REDIRECT = {
|
|
16017
|
+
headers: { Location: "/$1" },
|
|
16018
|
+
src: "^/(.+)/$",
|
|
16019
|
+
status: 308
|
|
16020
|
+
};
|
|
16021
|
+
var isNegotiationRoute = (route) => route.has?.some((condition) => condition.value === ACCEPT_MARKDOWN_HEADER_VALUE) === true || route.continue === true && route.headers?.vary === "Accept" && isString6(route.src) && Object.keys(route).length === 3 || route.continue === true && isString6(route.headers?.link) && route.src === HOME_SRC && Object.keys(route).length === 3 || route.status === TRAILING_SLASH_REDIRECT.status && route.src === TRAILING_SLASH_REDIRECT.src;
|
|
15822
16022
|
var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTypeOverrides, homeTokens) => {
|
|
15823
16023
|
const overrideEntries = Object.entries(contentTypeOverrides ?? {});
|
|
15824
|
-
if (routePaths.length === 0 && !homeLinkHeader && overrideEntries.length === 0) {
|
|
15825
|
-
return null;
|
|
15826
|
-
}
|
|
15827
16024
|
let config;
|
|
15828
16025
|
try {
|
|
15829
16026
|
config = JSON.parse(configText);
|
|
@@ -15849,7 +16046,7 @@ var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTy
|
|
|
15849
16046
|
src: HOME_SRC
|
|
15850
16047
|
});
|
|
15851
16048
|
}
|
|
15852
|
-
routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes);
|
|
16049
|
+
routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes, TRAILING_SLASH_REDIRECT);
|
|
15853
16050
|
config.routes = routes;
|
|
15854
16051
|
return `${JSON.stringify(config, null, "\t")}
|
|
15855
16052
|
`;
|
|
@@ -16158,7 +16355,7 @@ var syncSearchProvider = async (project, reporter) => {
|
|
|
16158
16355
|
|
|
16159
16356
|
// src/cli/dev-lock.ts
|
|
16160
16357
|
import {
|
|
16161
|
-
existsSync as
|
|
16358
|
+
existsSync as existsSync10,
|
|
16162
16359
|
mkdirSync,
|
|
16163
16360
|
readFileSync as readFileSync5,
|
|
16164
16361
|
rmSync,
|
|
@@ -16197,7 +16394,7 @@ var isProcessAlive = (pid) => {
|
|
|
16197
16394
|
};
|
|
16198
16395
|
var readDevLock = (outDir) => {
|
|
16199
16396
|
const path = lockPath(outDir);
|
|
16200
|
-
if (!
|
|
16397
|
+
if (!existsSync10(path)) {
|
|
16201
16398
|
return null;
|
|
16202
16399
|
}
|
|
16203
16400
|
const lock = parseLock(readFileSync5(path, "utf-8"));
|
|
@@ -16224,7 +16421,7 @@ class DevLockHeldError extends Error {
|
|
|
16224
16421
|
}
|
|
16225
16422
|
var ownsLock = (outDir) => {
|
|
16226
16423
|
const path = lockPath(outDir);
|
|
16227
|
-
if (!
|
|
16424
|
+
if (!existsSync10(path)) {
|
|
16228
16425
|
return false;
|
|
16229
16426
|
}
|
|
16230
16427
|
try {
|
|
@@ -16282,7 +16479,7 @@ var refuseIfDevRunning = (root, action, options = {}) => {
|
|
|
16282
16479
|
|
|
16283
16480
|
// src/astro/generate.ts
|
|
16284
16481
|
import { createHash as createHash4 } from "node:crypto";
|
|
16285
|
-
import { existsSync as
|
|
16482
|
+
import { existsSync as existsSync15, readFileSync as readFileSync8, realpathSync } from "node:fs";
|
|
16286
16483
|
import {
|
|
16287
16484
|
lstat,
|
|
16288
16485
|
mkdir as mkdir7,
|
|
@@ -16296,7 +16493,7 @@ import { createRequire as createRequire4 } from "node:module";
|
|
|
16296
16493
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
16297
16494
|
import { imageSize as imageSize2 } from "image-size";
|
|
16298
16495
|
import pMap6 from "p-map";
|
|
16299
|
-
import { basename as
|
|
16496
|
+
import { basename as basename4, dirname as dirname11, join as join28, normalize as normalize4, relative as relative14, resolve as resolve8 } from "pathe";
|
|
16300
16497
|
import { glob as glob7 } from "tinyglobby";
|
|
16301
16498
|
|
|
16302
16499
|
// src/ai/ask-data.ts
|
|
@@ -16545,7 +16742,7 @@ var validateUsedComponents = (pages, extraTags, registryNames) => {
|
|
|
16545
16742
|
};
|
|
16546
16743
|
|
|
16547
16744
|
// src/core/component-overrides.ts
|
|
16548
|
-
import { existsSync as
|
|
16745
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
16549
16746
|
import { dirname as dirname8, extname as extname7, isAbsolute as isAbsolute6, resolve as resolve6 } from "pathe";
|
|
16550
16747
|
import ts from "typescript";
|
|
16551
16748
|
var GROUPS = ["mdx", "layout", "islands"];
|
|
@@ -16640,7 +16837,7 @@ var findDefaultExportObject = (sourceFile) => {
|
|
|
16640
16837
|
var probeExtension = (base) => {
|
|
16641
16838
|
for (const extension of COMPONENT_EXTS) {
|
|
16642
16839
|
const candidate = `${base}.${extension}`;
|
|
16643
|
-
if (
|
|
16840
|
+
if (existsSync11(candidate)) {
|
|
16644
16841
|
return candidate;
|
|
16645
16842
|
}
|
|
16646
16843
|
}
|
|
@@ -16819,7 +17016,7 @@ var writeTextAtomic = async (path, text) => {
|
|
|
16819
17016
|
};
|
|
16820
17017
|
|
|
16821
17018
|
// src/core/tsconfig-aliases.ts
|
|
16822
|
-
import { existsSync as
|
|
17019
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
16823
17020
|
import { parseTsconfig } from "get-tsconfig";
|
|
16824
17021
|
import { dirname as dirname10, join as join22, resolve as resolve7 } from "pathe";
|
|
16825
17022
|
var CONFIG_DIR_TEMPLATE = "${configDir}";
|
|
@@ -16841,7 +17038,7 @@ var toAlias = (key, value, baseDir, configDir) => {
|
|
|
16841
17038
|
};
|
|
16842
17039
|
};
|
|
16843
17040
|
var resolveTsconfigAliases = (root) => {
|
|
16844
|
-
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join22(root, name)).find((file) =>
|
|
17041
|
+
const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join22(root, name)).find((file) => existsSync12(file));
|
|
16845
17042
|
if (!entry) {
|
|
16846
17043
|
return {};
|
|
16847
17044
|
}
|
|
@@ -16868,7 +17065,7 @@ var resolveTsconfigAliases = (root) => {
|
|
|
16868
17065
|
};
|
|
16869
17066
|
|
|
16870
17067
|
// src/og/derive.ts
|
|
16871
|
-
import { existsSync as
|
|
17068
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
16872
17069
|
import { isAbsolute as isAbsolute7, join as join23 } from "pathe";
|
|
16873
17070
|
var CARD_WEIGHTS = [400, 600];
|
|
16874
17071
|
var absoluteSrc = (root, src) => isAbsolute7(src) ? src : join23(root, src);
|
|
@@ -16972,11 +17169,11 @@ var missingFontFiles = (options, root) => {
|
|
|
16972
17169
|
sources.push(absoluteSrc(root, font.src));
|
|
16973
17170
|
}
|
|
16974
17171
|
}
|
|
16975
|
-
return [...new Set(sources)].filter((path) => !
|
|
17172
|
+
return [...new Set(sources)].filter((path) => !existsSync13(path));
|
|
16976
17173
|
};
|
|
16977
17174
|
|
|
16978
17175
|
// src/og/logo.ts
|
|
16979
|
-
import { existsSync as
|
|
17176
|
+
import { existsSync as existsSync14, readFileSync as readFileSync6 } from "node:fs";
|
|
16980
17177
|
import { join as join24 } from "pathe";
|
|
16981
17178
|
var resolveOgLogo = (project, source) => {
|
|
16982
17179
|
if (!source?.toLowerCase().endsWith(".svg")) {
|
|
@@ -16986,7 +17183,7 @@ var resolveOgLogo = (project, source) => {
|
|
|
16986
17183
|
const file = [
|
|
16987
17184
|
join24(project.context.root, "public", relative13),
|
|
16988
17185
|
join24(project.context.root, relative13)
|
|
16989
|
-
].find((path) =>
|
|
17186
|
+
].find((path) => existsSync14(path));
|
|
16990
17187
|
return file ? readFileSync6(file, "utf-8") : undefined;
|
|
16991
17188
|
};
|
|
16992
17189
|
|
|
@@ -17319,7 +17516,11 @@ ${THEME_MAPPING}
|
|
|
17319
17516
|
scroll-padding-top: 4.5rem;
|
|
17320
17517
|
text-rendering: optimizeLegibility;
|
|
17321
17518
|
}
|
|
17322
|
-
/* Headings use the display font (defaults to the body font when unset).
|
|
17519
|
+
/* Headings use the display font (defaults to the body font when unset).
|
|
17520
|
+
The tightened tracking is part of the theme, not the font: display-tuned
|
|
17521
|
+
families bake it into their metrics, but a text family promoted to
|
|
17522
|
+
headings (including the Inter default) reads loose without it. -0.05em
|
|
17523
|
+
was matched visually against Inter Tight, the previous display default. */
|
|
17323
17524
|
h1,
|
|
17324
17525
|
h2,
|
|
17325
17526
|
h3,
|
|
@@ -17327,6 +17528,7 @@ ${THEME_MAPPING}
|
|
|
17327
17528
|
h5,
|
|
17328
17529
|
h6 {
|
|
17329
17530
|
font-family: var(--font-display);
|
|
17531
|
+
letter-spacing: -0.05em;
|
|
17330
17532
|
}
|
|
17331
17533
|
:focus-visible {
|
|
17332
17534
|
outline: 2px solid var(--blume-accent);
|
|
@@ -17347,6 +17549,13 @@ ${THEME_MAPPING}
|
|
|
17347
17549
|
}
|
|
17348
17550
|
}
|
|
17349
17551
|
|
|
17552
|
+
/* Same-origin navigations ride Astro's client router (the layouts render
|
|
17553
|
+
ClientRouter), which owns the page-transition styling — including its own
|
|
17554
|
+
prefers-reduced-motion guard — so the theme declares nothing about it. The
|
|
17555
|
+
cross-document view-transition opt-in that briefly lived here is
|
|
17556
|
+
deliberately gone: mixing it with the client router double-animates the
|
|
17557
|
+
full-load navigations the router hands back to the browser. */
|
|
17558
|
+
|
|
17350
17559
|
/* Code reads left-to-right regardless of page direction; only the surrounding
|
|
17351
17560
|
chrome mirrors for RTL. Inline code is isolated so LTR identifiers don't
|
|
17352
17561
|
disturb the bidi flow of right-to-left prose. */
|
|
@@ -17382,9 +17591,10 @@ ${THEME_MAPPING}
|
|
|
17382
17591
|
line-height: 1.7;
|
|
17383
17592
|
}
|
|
17384
17593
|
|
|
17594
|
+
/* No letter-spacing here: prose headings inherit the base h1-h6 rule's
|
|
17595
|
+
display tracking, same as headings outside the prose column. */
|
|
17385
17596
|
.prose :where(h1, h2, h3, h4) {
|
|
17386
17597
|
font-weight: 500;
|
|
17387
|
-
letter-spacing: 0;
|
|
17388
17598
|
}
|
|
17389
17599
|
|
|
17390
17600
|
/* A heading can carry one long unbreakable token — an OpenAPI operation's title
|
|
@@ -18125,7 +18335,7 @@ import { glob as glob6 } from "tinyglobby";
|
|
|
18125
18335
|
// src/astro/islands.ts
|
|
18126
18336
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
18127
18337
|
import pMap4 from "p-map";
|
|
18128
|
-
import { basename as
|
|
18338
|
+
import { basename as basename3, join as join26 } from "pathe";
|
|
18129
18339
|
import { glob as glob5 } from "tinyglobby";
|
|
18130
18340
|
var DEFAULT_CLIENT = "visible";
|
|
18131
18341
|
var READ_CONCURRENCY2 = 16;
|
|
@@ -18170,7 +18380,7 @@ var discoverIslands = async (root) => {
|
|
|
18170
18380
|
const warnings = [];
|
|
18171
18381
|
const seen = new Map;
|
|
18172
18382
|
const collectIsland = (file, source) => {
|
|
18173
|
-
const base =
|
|
18383
|
+
const base = basename3(file);
|
|
18174
18384
|
const ext = base.match(ISLAND_FILE)?.groups?.ext;
|
|
18175
18385
|
const framework = ext ? FRAMEWORK_BY_EXT2.get(ext) : undefined;
|
|
18176
18386
|
if (!framework) {
|
|
@@ -18298,7 +18508,7 @@ var resolveAstroPackageJson = (modulesDir) => {
|
|
|
18298
18508
|
}
|
|
18299
18509
|
};
|
|
18300
18510
|
var resolvedAstroHit = (fromDir) => {
|
|
18301
|
-
let dir =
|
|
18511
|
+
let dir = normalize4(fromDir);
|
|
18302
18512
|
while (true) {
|
|
18303
18513
|
const modulesDir = join28(dir, "node_modules");
|
|
18304
18514
|
const pkg = resolveAstroPackageJson(modulesDir);
|
|
@@ -18323,7 +18533,7 @@ var depsCandidates = (pkgDir) => [
|
|
|
18323
18533
|
join28(pkgDir, "node_modules"),
|
|
18324
18534
|
dirname11(pkgDir)
|
|
18325
18535
|
];
|
|
18326
|
-
var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) =>
|
|
18536
|
+
var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync15(join28(dir, ...segments))) ?? null;
|
|
18327
18537
|
var linkDepsJunction = async (link, depsDir) => {
|
|
18328
18538
|
let existing;
|
|
18329
18539
|
try {
|
|
@@ -18459,7 +18669,7 @@ var writeExamplesPreview = async (options) => {
|
|
|
18459
18669
|
await write(join28(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
|
|
18460
18670
|
}
|
|
18461
18671
|
const cssFile = examplesCssFile(root, config);
|
|
18462
|
-
return cssFile && !
|
|
18672
|
+
return cssFile && !existsSync15(cssFile) ? [
|
|
18463
18673
|
`examples.css points at "${config.examples.css}", which doesn't exist; previews render without it.`
|
|
18464
18674
|
] : [];
|
|
18465
18675
|
};
|
|
@@ -18525,7 +18735,7 @@ var pruneOrphans = async (srcDir, written) => {
|
|
|
18525
18735
|
});
|
|
18526
18736
|
const removals = [];
|
|
18527
18737
|
for (const path of existing) {
|
|
18528
|
-
const normalized =
|
|
18738
|
+
const normalized = normalize4(path);
|
|
18529
18739
|
if (!written.has(normalized)) {
|
|
18530
18740
|
removals.push(rm2(normalized, { force: true }));
|
|
18531
18741
|
}
|
|
@@ -18546,10 +18756,10 @@ var writeStagedContent = async (out, staged) => {
|
|
|
18546
18756
|
const written = new Set;
|
|
18547
18757
|
await Promise.all([...staged].map(async ([entryId, text]) => {
|
|
18548
18758
|
const path = join28(contentDir, entryId);
|
|
18549
|
-
written.add(
|
|
18759
|
+
written.add(normalize4(path));
|
|
18550
18760
|
await writeIfChanged(path, text);
|
|
18551
18761
|
}));
|
|
18552
|
-
if (
|
|
18762
|
+
if (existsSync15(contentDir)) {
|
|
18553
18763
|
await pruneOrphans(contentDir, written);
|
|
18554
18764
|
}
|
|
18555
18765
|
};
|
|
@@ -18572,7 +18782,7 @@ var readLogoSvg = (project, source) => {
|
|
|
18572
18782
|
const file = [
|
|
18573
18783
|
join28(project.context.root, "public", rel),
|
|
18574
18784
|
join28(project.context.root, rel)
|
|
18575
|
-
].find((path) =>
|
|
18785
|
+
].find((path) => existsSync15(path));
|
|
18576
18786
|
return file ? readFileSync8(file, "utf-8") : undefined;
|
|
18577
18787
|
};
|
|
18578
18788
|
var isStringShorthand = (value) => typeof value === "string";
|
|
@@ -18606,6 +18816,7 @@ var FAVICON_CANDIDATES = [
|
|
|
18606
18816
|
"favicon.ico",
|
|
18607
18817
|
"icon.ico"
|
|
18608
18818
|
];
|
|
18819
|
+
var darkSibling = (name) => name.replace(/\.(?=[^.]+$)/u, "-dark.");
|
|
18609
18820
|
var FAVICON_TYPES = new Map([
|
|
18610
18821
|
["ico", "image/x-icon"],
|
|
18611
18822
|
["jpeg", "image/jpeg"],
|
|
@@ -18619,6 +18830,10 @@ var faviconType = (name) => {
|
|
|
18619
18830
|
};
|
|
18620
18831
|
var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync8(file).toString("base64")}`;
|
|
18621
18832
|
var defaultFavicon = () => ({
|
|
18833
|
+
dark: {
|
|
18834
|
+
href: inlineDataUri(join28(BLUME_SRC, "assets", "icon-dark.png"), "image/png"),
|
|
18835
|
+
type: "image/png"
|
|
18836
|
+
},
|
|
18622
18837
|
href: inlineDataUri(join28(BLUME_SRC, "assets", "icon.png"), "image/png"),
|
|
18623
18838
|
type: "image/png"
|
|
18624
18839
|
});
|
|
@@ -18631,20 +18846,43 @@ var APPLE_ICON_CANDIDATES = [
|
|
|
18631
18846
|
var resolveIconFile = (project, candidates) => {
|
|
18632
18847
|
const { root } = project.context;
|
|
18633
18848
|
for (const name of candidates) {
|
|
18634
|
-
if (
|
|
18849
|
+
if (existsSync15(join28(root, "public", name))) {
|
|
18635
18850
|
return { href: `/${name}`, type: faviconType(name) };
|
|
18636
18851
|
}
|
|
18637
18852
|
}
|
|
18638
18853
|
for (const name of candidates) {
|
|
18639
18854
|
const file = join28(root, name);
|
|
18640
|
-
if (
|
|
18855
|
+
if (existsSync15(file)) {
|
|
18641
18856
|
const type = faviconType(name);
|
|
18642
18857
|
return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
|
|
18643
18858
|
}
|
|
18644
18859
|
}
|
|
18645
18860
|
return null;
|
|
18646
18861
|
};
|
|
18647
|
-
var resolveFavicon = (project) =>
|
|
18862
|
+
var resolveFavicon = (project) => {
|
|
18863
|
+
const { root } = project.context;
|
|
18864
|
+
for (const name of FAVICON_CANDIDATES) {
|
|
18865
|
+
if (existsSync15(join28(root, "public", name))) {
|
|
18866
|
+
const type = faviconType(name);
|
|
18867
|
+
const sibling = darkSibling(name);
|
|
18868
|
+
return existsSync15(join28(root, "public", sibling)) ? { dark: { href: `/${sibling}`, type }, href: `/${name}`, type } : { href: `/${name}`, type };
|
|
18869
|
+
}
|
|
18870
|
+
}
|
|
18871
|
+
for (const name of FAVICON_CANDIDATES) {
|
|
18872
|
+
const file = join28(root, name);
|
|
18873
|
+
if (existsSync15(file)) {
|
|
18874
|
+
const type = faviconType(name);
|
|
18875
|
+
const mime = type ?? "image/x-icon";
|
|
18876
|
+
const siblingFile = join28(root, darkSibling(name));
|
|
18877
|
+
return existsSync15(siblingFile) ? {
|
|
18878
|
+
dark: { href: inlineDataUri(siblingFile, mime), type },
|
|
18879
|
+
href: inlineDataUri(file, mime),
|
|
18880
|
+
type
|
|
18881
|
+
} : { href: inlineDataUri(file, mime), type };
|
|
18882
|
+
}
|
|
18883
|
+
}
|
|
18884
|
+
return resolveIconFile(project, FAVICON_CANDIDATES.map(darkSibling)) ?? defaultFavicon();
|
|
18885
|
+
};
|
|
18648
18886
|
var resolveAppleIcon = (project) => resolveIconFile(project, APPLE_ICON_CANDIDATES);
|
|
18649
18887
|
var resolveBanner = (config) => {
|
|
18650
18888
|
const { banner } = config;
|
|
@@ -18771,6 +19009,7 @@ var buildRuntimeData = (project) => {
|
|
|
18771
19009
|
palette: config.seo.og.palette,
|
|
18772
19010
|
site: resolveOgSite(config)
|
|
18773
19011
|
},
|
|
19012
|
+
openInChat: config.ai.openInChat,
|
|
18774
19013
|
repoUrl,
|
|
18775
19014
|
search: {
|
|
18776
19015
|
enabled: config.search.provider !== "none",
|
|
@@ -18793,7 +19032,7 @@ var buildRuntimeData = (project) => {
|
|
|
18793
19032
|
href: feed.path,
|
|
18794
19033
|
title: feed.title
|
|
18795
19034
|
})),
|
|
18796
|
-
fontCssVars:
|
|
19035
|
+
fontCssVars: configuredFonts(config.theme.fonts),
|
|
18797
19036
|
navigation: withRepoUrl(graph.navigation),
|
|
18798
19037
|
navigationByLocale,
|
|
18799
19038
|
navigationByVersion: Object.fromEntries(Object.entries(graph.navigationByVersion).map(([id2, byLocale]) => [
|
|
@@ -18884,6 +19123,30 @@ var writeMcpFiles = async (project, plan, write) => {
|
|
|
18884
19123
|
write(join28(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
|
|
18885
19124
|
]);
|
|
18886
19125
|
};
|
|
19126
|
+
var planPlaygroundProxy = (config, srcDir) => ({
|
|
19127
|
+
enabled: config.openapi.enabled && config.openapi.renderer === "blume" && config.openapi.playground.enabled && config.openapi.playground.proxy === true,
|
|
19128
|
+
entrypoint: join28(srcDir, "blume-openapi", "api-proxy.ts"),
|
|
19129
|
+
pattern: "/_api-proxy"
|
|
19130
|
+
});
|
|
19131
|
+
var specOrigins = (data) => {
|
|
19132
|
+
const origins = new Set;
|
|
19133
|
+
for (const spec of Object.values(data)) {
|
|
19134
|
+
const { servers } = spec.document;
|
|
19135
|
+
for (const server of Array.isArray(servers) ? servers : []) {
|
|
19136
|
+
const url = server.url ?? "";
|
|
19137
|
+
if (url.includes("{")) {
|
|
19138
|
+
continue;
|
|
19139
|
+
}
|
|
19140
|
+
try {
|
|
19141
|
+
origins.add(new URL(url).origin);
|
|
19142
|
+
} catch {}
|
|
19143
|
+
}
|
|
19144
|
+
}
|
|
19145
|
+
return [...origins].toSorted();
|
|
19146
|
+
};
|
|
19147
|
+
var proxyAllowlistWarnings = (enabled, origins) => enabled && origins.length === 0 ? [
|
|
19148
|
+
"openapi.playground.proxy is enabled, but no spec declares an absolute servers[].url (relative and templated URLs carry no origin), so the proxy's allowlist is empty and it will refuse every request. Add an absolute server URL to the spec, or point playground.proxy at an external proxy URL."
|
|
19149
|
+
] : [];
|
|
18887
19150
|
var writeAskFiles = async (project, srcDir, write) => {
|
|
18888
19151
|
const { ask } = project.config.ai;
|
|
18889
19152
|
if (!(ask?.enabled && !ask.endpoint)) {
|
|
@@ -18894,7 +19157,10 @@ var writeAskFiles = async (project, srcDir, write) => {
|
|
|
18894
19157
|
await write(join28(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
|
|
18895
19158
|
`);
|
|
18896
19159
|
}
|
|
18897
|
-
await write(join28(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded,
|
|
19160
|
+
await write(join28(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded, {
|
|
19161
|
+
instructions: ask.instructions,
|
|
19162
|
+
retrieval: ask.retrieval
|
|
19163
|
+
}));
|
|
18898
19164
|
};
|
|
18899
19165
|
var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
|
|
18900
19166
|
if (routeIsTaken(pages, contentPages, "/404")) {
|
|
@@ -18942,7 +19208,7 @@ var generateRuntime = async (project) => {
|
|
|
18942
19208
|
const openapiPath = join28(srcDir, "generated", "openapi.json");
|
|
18943
19209
|
const written = new Set;
|
|
18944
19210
|
const write = (path, content) => {
|
|
18945
|
-
written.add(
|
|
19211
|
+
written.add(normalize4(path));
|
|
18946
19212
|
return writeIfChanged(path, content);
|
|
18947
19213
|
};
|
|
18948
19214
|
const depsLinkWarning = await ensureDepsLink(out);
|
|
@@ -18987,8 +19253,19 @@ var generateRuntime = async (project) => {
|
|
|
18987
19253
|
const needsSvelte = frameworks.has("svelte");
|
|
18988
19254
|
const reactCompilerPath = resolveReactCompiler(config, needsReact);
|
|
18989
19255
|
const ogRoutes = customOgRoutes(pages, config.title, config.seo.og.titles);
|
|
19256
|
+
const changelogIndex = hasGeneratedChangelog(project, pages);
|
|
18990
19257
|
const mcp = planMcp(project, srcDir, pages);
|
|
18991
19258
|
pages.push(...mcp.discoveryPages);
|
|
19259
|
+
const openApiSource2 = project.sources.find(isOpenApiSource);
|
|
19260
|
+
const openApiData = openApiSource2 ? openApiSource2.openApiData() : {};
|
|
19261
|
+
const playgroundProxy = planPlaygroundProxy(config, srcDir);
|
|
19262
|
+
if (playgroundProxy.enabled) {
|
|
19263
|
+
pages.push({
|
|
19264
|
+
entrypoint: playgroundProxy.entrypoint,
|
|
19265
|
+
pattern: playgroundProxy.pattern
|
|
19266
|
+
});
|
|
19267
|
+
}
|
|
19268
|
+
const proxyOrigins = specOrigins(openApiData);
|
|
18992
19269
|
const hasStaged = staged.size > 0;
|
|
18993
19270
|
const hasFilesystemSource = project.sources.some((source) => !source.staged);
|
|
18994
19271
|
const docsCollection = resolveDocsCollection(config, context);
|
|
@@ -19053,12 +19330,13 @@ var generateRuntime = async (project) => {
|
|
|
19053
19330
|
Promise.all(slotPlan.wrappers.map((wrapper) => write(join28(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
|
|
19054
19331
|
Promise.all(exampleDiscovery.examples.map((example) => write(join28(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
|
|
19055
19332
|
writeAskFiles(project, srcDir, write),
|
|
19056
|
-
writeMcpFiles(project, mcp, write)
|
|
19333
|
+
writeMcpFiles(project, mcp, write),
|
|
19334
|
+
playgroundProxy.enabled ? write(playgroundProxy.entrypoint, playgroundProxyTemplate(proxyOrigins)) : Promise.resolve(false)
|
|
19057
19335
|
]);
|
|
19058
19336
|
if (config.seo.og.enabled) {
|
|
19059
|
-
await write(join28(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, projectOgFonts(project)));
|
|
19337
|
+
await write(join28(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, projectOgFonts(project), changelogIndex));
|
|
19060
19338
|
}
|
|
19061
|
-
if (
|
|
19339
|
+
if (changelogIndex) {
|
|
19062
19340
|
await write(join28(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
|
|
19063
19341
|
exportEpub,
|
|
19064
19342
|
exportPdf,
|
|
@@ -19108,6 +19386,7 @@ var generateRuntime = async (project) => {
|
|
|
19108
19386
|
}
|
|
19109
19387
|
const warnings = [
|
|
19110
19388
|
...depsLinkWarning ? [depsLinkWarning] : [],
|
|
19389
|
+
...proxyAllowlistWarnings(playgroundProxy.enabled, proxyOrigins),
|
|
19111
19390
|
...reactCompilerWarnings(config, needsReact, reactCompilerPath),
|
|
19112
19391
|
...mcp.warnings,
|
|
19113
19392
|
...islandDiscovery.warnings,
|
|
@@ -19120,7 +19399,7 @@ var generateRuntime = async (project) => {
|
|
|
19120
19399
|
...pages.map((page) => page.pattern),
|
|
19121
19400
|
...referenceRoutes(config)
|
|
19122
19401
|
]);
|
|
19123
|
-
if (
|
|
19402
|
+
if (changelogIndex) {
|
|
19124
19403
|
navTargetRoutes.add("/changelog");
|
|
19125
19404
|
}
|
|
19126
19405
|
warnings.push(...[
|
|
@@ -19141,10 +19420,9 @@ var generateRuntime = async (project) => {
|
|
|
19141
19420
|
warnings.push(...references.warnings);
|
|
19142
19421
|
await Promise.all(references.files.map((file) => write(join28(srcDir, "pages", file.pagePath), file.content)));
|
|
19143
19422
|
}
|
|
19144
|
-
const openApiSource2 = project.sources.find(isOpenApiSource);
|
|
19145
19423
|
await Promise.all([
|
|
19146
19424
|
write(join28(srcDir, "generated", "data.json"), buildRuntimeData(project)),
|
|
19147
|
-
write(openapiPath, `${JSON.stringify(
|
|
19425
|
+
write(openapiPath, `${JSON.stringify(openApiData)}
|
|
19148
19426
|
`),
|
|
19149
19427
|
write(join28(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
|
|
19150
19428
|
`),
|
|
@@ -19155,7 +19433,7 @@ var generateRuntime = async (project) => {
|
|
|
19155
19433
|
};
|
|
19156
19434
|
|
|
19157
19435
|
// src/cli/env.ts
|
|
19158
|
-
import { existsSync as
|
|
19436
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
19159
19437
|
import { config } from "dotenv";
|
|
19160
19438
|
import { dirname as dirname12, join as join29, resolve as resolve9 } from "pathe";
|
|
19161
19439
|
var loadEnvFiles = (startDir) => {
|
|
@@ -19165,7 +19443,7 @@ var loadEnvFiles = (startDir) => {
|
|
|
19165
19443
|
while (!done) {
|
|
19166
19444
|
paths.push(join29(dir, ".env.local"), join29(dir, ".env"));
|
|
19167
19445
|
const parent = dirname12(dir);
|
|
19168
|
-
done =
|
|
19446
|
+
done = existsSync16(join29(dir, ".git")) || parent === dir;
|
|
19169
19447
|
dir = parent;
|
|
19170
19448
|
}
|
|
19171
19449
|
config({ path: paths, quiet: true });
|
|
@@ -19277,17 +19555,17 @@ var emitRedirectFiles = async (config2, distDir) => {
|
|
|
19277
19555
|
{ content: buildNetlifyRedirects(redirects), name: "_redirects" },
|
|
19278
19556
|
{ content: buildVercelConfig(redirects), name: "vercel.json" }
|
|
19279
19557
|
];
|
|
19280
|
-
await Promise.all(platformFiles.map((file) =>
|
|
19558
|
+
await Promise.all(platformFiles.map((file) => existsSync17(join30(distDir, file.name)) ? Promise.resolve() : writeFile7(join30(distDir, file.name), file.content, "utf-8")));
|
|
19281
19559
|
logger.success(`Emitted redirect files for ${redirects.length} redirect(s)`);
|
|
19282
19560
|
};
|
|
19283
19561
|
var emitHeaderFiles = async (project, distDir) => {
|
|
19284
19562
|
const { config: config2 } = project;
|
|
19285
|
-
if (!readsHeaderFiles(config2.deployment) ||
|
|
19563
|
+
if (!readsHeaderFiles(config2.deployment) || existsSync17(join30(project.context.root, "public", "_headers"))) {
|
|
19286
19564
|
return;
|
|
19287
19565
|
}
|
|
19288
19566
|
const ours = buildNetlifyHeaders(config2, buildHomeLinkHeader(config2, markdownRoutePaths(project)));
|
|
19289
19567
|
const target = join30(distDir, "_headers");
|
|
19290
|
-
const existing =
|
|
19568
|
+
const existing = existsSync17(target) ? await readFile17(target, "utf-8") : "";
|
|
19291
19569
|
await writeFile7(target, existing ? `${existing.trimEnd()}
|
|
19292
19570
|
${ours}` : ours, "utf-8");
|
|
19293
19571
|
logger.success("Emitted _headers (UTF-8 Content-Type + homepage Link header)");
|
|
@@ -19298,12 +19576,12 @@ var emitAgentSkills = async (project, distDir) => {
|
|
|
19298
19576
|
return;
|
|
19299
19577
|
}
|
|
19300
19578
|
const dir = resolve10(project.context.root, configured);
|
|
19301
|
-
if (!
|
|
19579
|
+
if (!existsSync17(dir)) {
|
|
19302
19580
|
logger.warn(`ai.skills points at "${configured}" (${dir}), which does not exist; no skills published.`);
|
|
19303
19581
|
return;
|
|
19304
19582
|
}
|
|
19305
19583
|
const outDir = join30(distDir, AGENT_SKILLS_DIR.slice(1));
|
|
19306
|
-
if (
|
|
19584
|
+
if (existsSync17(join30(outDir, "index.json"))) {
|
|
19307
19585
|
return;
|
|
19308
19586
|
}
|
|
19309
19587
|
const { skills, warnings } = await collectSkills(dir);
|
|
@@ -19337,7 +19615,7 @@ var emitWellKnownFiles = async (config2, distDir) => {
|
|
|
19337
19615
|
];
|
|
19338
19616
|
for (const file of files) {
|
|
19339
19617
|
const target = join30(distDir, file.path.slice(1));
|
|
19340
|
-
if (!file.content ||
|
|
19618
|
+
if (!file.content || existsSync17(target)) {
|
|
19341
19619
|
continue;
|
|
19342
19620
|
}
|
|
19343
19621
|
await mkdir8(join30(distDir, ".well-known"), { recursive: true });
|
|
@@ -19348,7 +19626,7 @@ var emitWellKnownFiles = async (config2, distDir) => {
|
|
|
19348
19626
|
var emitVercelNegotiation = async (project, routePaths, root) => {
|
|
19349
19627
|
const { config: config2 } = project;
|
|
19350
19628
|
const configPath = join30(root, ".vercel", "output", "config.json");
|
|
19351
|
-
if (!
|
|
19629
|
+
if (!existsSync17(configPath)) {
|
|
19352
19630
|
return;
|
|
19353
19631
|
}
|
|
19354
19632
|
const overrides = {};
|
|
@@ -19373,7 +19651,7 @@ var emitCloudflareNegotiation = async (project, routePaths) => {
|
|
|
19373
19651
|
const { config: config2, context } = project;
|
|
19374
19652
|
const serverDir = join30(context.distDir ?? join30(context.root, "dist"), "server");
|
|
19375
19653
|
const wranglerPath = join30(serverDir, "wrangler.json");
|
|
19376
|
-
if (!
|
|
19654
|
+
if (!existsSync17(wranglerPath)) {
|
|
19377
19655
|
warnCloudflareNegotiationSkipped();
|
|
19378
19656
|
return;
|
|
19379
19657
|
}
|
|
@@ -19404,7 +19682,7 @@ var formatBytes2 = (bytes) => {
|
|
|
19404
19682
|
};
|
|
19405
19683
|
var astroAssets = async (distDir, ext) => {
|
|
19406
19684
|
const astroDir = join30(distDir, "_astro");
|
|
19407
|
-
if (!
|
|
19685
|
+
if (!existsSync17(astroDir)) {
|
|
19408
19686
|
return [];
|
|
19409
19687
|
}
|
|
19410
19688
|
const entries = await readdir2(astroDir);
|
|
@@ -19481,8 +19759,8 @@ var isolatedStaticDir = (config2, context) => {
|
|
|
19481
19759
|
var publishLlmsFiles = async (project, distDir) => {
|
|
19482
19760
|
const indexPath = join30(distDir, "llms.txt");
|
|
19483
19761
|
const fullPath = join30(distDir, "llms-full.txt");
|
|
19484
|
-
const writeIndex = !
|
|
19485
|
-
const writeFull = !
|
|
19762
|
+
const writeIndex = !existsSync17(indexPath);
|
|
19763
|
+
const writeFull = !existsSync17(fullPath);
|
|
19486
19764
|
if (!(writeIndex || writeFull)) {
|
|
19487
19765
|
return;
|
|
19488
19766
|
}
|
|
@@ -19515,17 +19793,17 @@ var publishBuildArtifacts = async (project, distDir, args) => {
|
|
|
19515
19793
|
await publishLlmsFiles(project, distDir);
|
|
19516
19794
|
}
|
|
19517
19795
|
const sitemapFiles = buildSitemapFiles(project);
|
|
19518
|
-
if (sitemapFiles && !
|
|
19796
|
+
if (sitemapFiles && !existsSync17(join30(distDir, "sitemap.xml"))) {
|
|
19519
19797
|
await Promise.all(sitemapFiles.map((file) => writeFile7(join30(distDir, file.name), file.xml, "utf-8")));
|
|
19520
19798
|
logger.success(sitemapFiles.length === 1 ? "Generated sitemap.xml" : `Generated sitemap.xml (index of ${sitemapFiles.length - 1} sitemap files)`);
|
|
19521
19799
|
}
|
|
19522
19800
|
const robots = buildRobots(project);
|
|
19523
|
-
if (robots && !
|
|
19801
|
+
if (robots && !existsSync17(join30(distDir, "robots.txt"))) {
|
|
19524
19802
|
await writeFile7(join30(distDir, "robots.txt"), robots, "utf-8");
|
|
19525
19803
|
logger.success("Generated robots.txt");
|
|
19526
19804
|
}
|
|
19527
19805
|
const agentReadability = buildAgentReadability(project);
|
|
19528
|
-
if (agentReadability && !
|
|
19806
|
+
if (agentReadability && !existsSync17(join30(distDir, "agent-readability.json"))) {
|
|
19529
19807
|
await writeFile7(join30(distDir, "agent-readability.json"), `${JSON.stringify(agentReadability, null, 2)}
|
|
19530
19808
|
`, "utf-8");
|
|
19531
19809
|
logger.success("Generated agent-readability.json");
|
|
@@ -19658,7 +19936,7 @@ var buildCommand = defineCommand3({
|
|
|
19658
19936
|
});
|
|
19659
19937
|
|
|
19660
19938
|
// src/cli/commands/check.ts
|
|
19661
|
-
import { existsSync as
|
|
19939
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
19662
19940
|
import { check } from "@astrojs/check";
|
|
19663
19941
|
import { sync } from "astro";
|
|
19664
19942
|
import { defineCommand as defineCommand4 } from "citty";
|
|
@@ -19704,7 +19982,7 @@ var checkCommand = defineCommand4({
|
|
|
19704
19982
|
minimumFailingSeverity: "error",
|
|
19705
19983
|
minimumSeverity: "hint",
|
|
19706
19984
|
root: outDir,
|
|
19707
|
-
tsconfig:
|
|
19985
|
+
tsconfig: existsSync18(tsconfig) ? tsconfig : undefined,
|
|
19708
19986
|
watch: false
|
|
19709
19987
|
});
|
|
19710
19988
|
if (failed) {
|
|
@@ -19986,13 +20264,13 @@ import { defineCommand as defineCommand7 } from "citty";
|
|
|
19986
20264
|
import { relative as relative17 } from "pathe";
|
|
19987
20265
|
|
|
19988
20266
|
// src/registry/eject.ts
|
|
19989
|
-
import { existsSync as
|
|
20267
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
19990
20268
|
import { cp as cp2, mkdir as mkdir9, readFile as readFile18, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
|
|
19991
20269
|
import { join as join33, relative as relative15 } from "pathe";
|
|
19992
20270
|
var toPosix = (path) => path.split("\\").join("/");
|
|
19993
20271
|
var LOCAL_BLUME_SOURCE = "../../node_modules/blume/src/**/*.{astro,ts,tsx}";
|
|
19994
20272
|
var blumeSourceGlob = (root, genDir, resolveBlumeRoot = packageRoot) => {
|
|
19995
|
-
if (
|
|
20273
|
+
if (existsSync19(join33(root, "node_modules", "blume"))) {
|
|
19996
20274
|
return LOCAL_BLUME_SOURCE;
|
|
19997
20275
|
}
|
|
19998
20276
|
try {
|
|
@@ -20011,7 +20289,7 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
20011
20289
|
const { ask } = project.config.ai;
|
|
20012
20290
|
if (!(ask?.enabled && !ask.endpoint)) {
|
|
20013
20291
|
const endpointPath = join33(srcDir, "pages", "api", "ask.ts");
|
|
20014
|
-
if (
|
|
20292
|
+
if (existsSync19(endpointPath)) {
|
|
20015
20293
|
const content = await readFile18(endpointPath, "utf-8");
|
|
20016
20294
|
if (content.startsWith("// Generated by Blume. Do not edit.")) {
|
|
20017
20295
|
await rm3(endpointPath, { force: true });
|
|
@@ -20023,7 +20301,10 @@ var askFiles = async (project, srcDir, genDir) => {
|
|
|
20023
20301
|
const grounded = ask.provider !== "inkeep";
|
|
20024
20302
|
const files = [
|
|
20025
20303
|
{
|
|
20026
|
-
content: askEndpointTemplate(resolveAskBackend(ask), grounded,
|
|
20304
|
+
content: askEndpointTemplate(resolveAskBackend(ask), grounded, {
|
|
20305
|
+
instructions: ask.instructions,
|
|
20306
|
+
retrieval: ask.retrieval
|
|
20307
|
+
}),
|
|
20027
20308
|
path: join33(srcDir, "pages", "api", "ask.ts")
|
|
20028
20309
|
}
|
|
20029
20310
|
];
|
|
@@ -20093,7 +20374,7 @@ var changelogFiles = (project, userPages, srcDir, options) => {
|
|
|
20093
20374
|
}
|
|
20094
20375
|
];
|
|
20095
20376
|
};
|
|
20096
|
-
var readExamplesCss = (root, css) => css &&
|
|
20377
|
+
var readExamplesCss = (root, css) => css && existsSync19(join33(root, css)) ? readFile18(join33(root, css), "utf-8") : Promise.resolve("");
|
|
20097
20378
|
var examplesPreviewFiles = (srcDir, basePath, hasExamples) => hasExamples ? [
|
|
20098
20379
|
{
|
|
20099
20380
|
content: examplesPageTemplate(),
|
|
@@ -20332,13 +20613,13 @@ var eject = async (root) => {
|
|
|
20332
20613
|
for (const [entryId, content] of staged) {
|
|
20333
20614
|
files.push({ content, path: join33(root, stagedDir, entryId) });
|
|
20334
20615
|
}
|
|
20335
|
-
const written = files.filter((file) => !(file.skipIfExists &&
|
|
20616
|
+
const written = files.filter((file) => !(file.skipIfExists && existsSync19(file.path)));
|
|
20336
20617
|
await Promise.all(written.map(async (file) => {
|
|
20337
20618
|
await mkdir9(join33(file.path, ".."), { recursive: true });
|
|
20338
20619
|
await writeFile8(file.path, file.content, "utf-8");
|
|
20339
20620
|
}));
|
|
20340
20621
|
const assetsSrc = join33(context.outDir, "public", "blume-assets");
|
|
20341
|
-
if (
|
|
20622
|
+
if (existsSync19(assetsSrc)) {
|
|
20342
20623
|
await cp2(assetsSrc, join33(root, "public", "blume-assets"), {
|
|
20343
20624
|
recursive: true
|
|
20344
20625
|
});
|
|
@@ -20395,10 +20676,10 @@ var updatePackageScripts = async (root) => {
|
|
|
20395
20676
|
};
|
|
20396
20677
|
|
|
20397
20678
|
// src/cli/init/scaffold.ts
|
|
20398
|
-
import { existsSync as
|
|
20679
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
20399
20680
|
import { mkdir as mkdir10, writeFile as writeFile10 } from "node:fs/promises";
|
|
20400
20681
|
import { detect } from "package-manager-detector/detect";
|
|
20401
|
-
import { basename as
|
|
20682
|
+
import { basename as basename5, dirname as dirname14, isAbsolute as isAbsolute9, join as join35, relative as relative16 } from "pathe";
|
|
20402
20683
|
|
|
20403
20684
|
// src/core/package-json.ts
|
|
20404
20685
|
var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
|
|
@@ -20607,7 +20888,7 @@ var extraDepsFor = (sources) => {
|
|
|
20607
20888
|
var buildPlan = (root, answers) => {
|
|
20608
20889
|
const files = [
|
|
20609
20890
|
{
|
|
20610
|
-
content: blumePackageJson(toPackageName(
|
|
20891
|
+
content: blumePackageJson(toPackageName(basename5(root)), extraDepsFor(answers.sources)),
|
|
20611
20892
|
path: join35(root, "package.json")
|
|
20612
20893
|
},
|
|
20613
20894
|
{ content: buildConfig(answers), path: join35(root, "blume.config.ts") }
|
|
@@ -20618,7 +20899,7 @@ var buildPlan = (root, answers) => {
|
|
|
20618
20899
|
return files;
|
|
20619
20900
|
};
|
|
20620
20901
|
var writeFileSafe = async (file, log) => {
|
|
20621
|
-
if (
|
|
20902
|
+
if (existsSync20(file.path)) {
|
|
20622
20903
|
log.info(`Skipped existing ${file.path}`);
|
|
20623
20904
|
return false;
|
|
20624
20905
|
}
|
|
@@ -20629,7 +20910,7 @@ var writeFileSafe = async (file, log) => {
|
|
|
20629
20910
|
};
|
|
20630
20911
|
var applyPlan = async (files, log) => {
|
|
20631
20912
|
const created = await Promise.all(files.map((file) => writeFileSafe(file, log)));
|
|
20632
|
-
const createdPackage = files.some((file, index) => created[index] &&
|
|
20913
|
+
const createdPackage = files.some((file, index) => created[index] && basename5(file.path) === "package.json");
|
|
20633
20914
|
return { createdPackage };
|
|
20634
20915
|
};
|
|
20635
20916
|
var envVarsFor = (sources) => [
|
|
@@ -20714,7 +20995,7 @@ The blume package remains importable.`);
|
|
|
20714
20995
|
});
|
|
20715
20996
|
|
|
20716
20997
|
// src/cli/commands/eval.ts
|
|
20717
|
-
import { existsSync as
|
|
20998
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
20718
20999
|
import { defineCommand as defineCommand8 } from "citty";
|
|
20719
21000
|
import { join as join39 } from "pathe";
|
|
20720
21001
|
|
|
@@ -21438,7 +21719,7 @@ var runFixHandoff = async (agent, result, root, threshold) => {
|
|
|
21438
21719
|
};
|
|
21439
21720
|
var runInit = async (agent, file) => {
|
|
21440
21721
|
const path = join39(process.cwd(), file);
|
|
21441
|
-
if (
|
|
21722
|
+
if (existsSync21(path)) {
|
|
21442
21723
|
logger.error(`${file} already exists — edit it directly, or pass --file to draft elsewhere.`);
|
|
21443
21724
|
process.exit(1);
|
|
21444
21725
|
}
|
|
@@ -21576,7 +21857,7 @@ import { defineCommand as defineCommand9 } from "citty";
|
|
|
21576
21857
|
import { resolve as resolve12 } from "pathe";
|
|
21577
21858
|
|
|
21578
21859
|
// src/cli/init/questions.ts
|
|
21579
|
-
import { basename as
|
|
21860
|
+
import { basename as basename6, resolve as resolve11 } from "pathe";
|
|
21580
21861
|
var cancelled = (value) => typeof value === "symbol";
|
|
21581
21862
|
var collectAnswers = async (prompter, flags, defaults) => {
|
|
21582
21863
|
const directory = flags.directory ?? await prompter.text({
|
|
@@ -21589,7 +21870,7 @@ var collectAnswers = async (prompter, flags, defaults) => {
|
|
|
21589
21870
|
}
|
|
21590
21871
|
const root = resolve11(defaults.cwd, directory);
|
|
21591
21872
|
const title = await prompter.text({
|
|
21592
|
-
initialValue: titleize(
|
|
21873
|
+
initialValue: titleize(basename6(root)),
|
|
21593
21874
|
message: "What's your docs site called?",
|
|
21594
21875
|
validate: (value) => value?.trim() ? undefined : "Give your docs site a name."
|
|
21595
21876
|
});
|
|
@@ -21816,10 +22097,30 @@ var SCHEMA = {
|
|
|
21816
22097
|
};
|
|
21817
22098
|
var toFacetTerms = (facets) => Object.entries(facets).map(([key, value]) => `${key}:${value}`);
|
|
21818
22099
|
var BOOST = { description: 2, title: 3 };
|
|
21819
|
-
var
|
|
21820
|
-
var
|
|
22100
|
+
var LATIN_SCRIPT = "Latn";
|
|
22101
|
+
var parseLocale = (tag) => {
|
|
22102
|
+
const hyphenated = tag.replaceAll("_", "-");
|
|
22103
|
+
try {
|
|
22104
|
+
return new Intl.Locale(hyphenated);
|
|
22105
|
+
} catch {}
|
|
22106
|
+
const [primary = ""] = hyphenated.split("-");
|
|
22107
|
+
try {
|
|
22108
|
+
return new Intl.Locale(primary);
|
|
22109
|
+
} catch {
|
|
22110
|
+
return;
|
|
22111
|
+
}
|
|
22112
|
+
};
|
|
22113
|
+
var resolveLocale = (tag) => parseLocale(tag)?.maximize();
|
|
22114
|
+
var BIGRAM_INDEX_SCRIPTS = new Set(["Hans", "Hant", "Jpan"]);
|
|
22115
|
+
var isBigramLanguage = (language) => {
|
|
22116
|
+
const script = resolveLocale(language)?.script;
|
|
22117
|
+
return script !== undefined && BIGRAM_INDEX_SCRIPTS.has(script);
|
|
22118
|
+
};
|
|
21821
22119
|
var BIGRAM_SCRIPTS = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}々〆〇ー゙゚]+$/u;
|
|
21822
22120
|
var TERM = /[\p{L}\p{M}\p{N}]+(?:(?:['’](?=\p{L})|(?<=\p{N})[.,](?=\p{N}))[\p{L}\p{M}\p{N}]+)*/gu;
|
|
22121
|
+
var LATIN_TERM = /^[\p{Script=Latin}\p{N}'’.,]+$/u;
|
|
22122
|
+
var MARKS = /\p{M}+/gu;
|
|
22123
|
+
var foldDiacritics = (term) => LATIN_TERM.test(term) ? term.normalize("NFD").replace(MARKS, "") : term;
|
|
21823
22124
|
var addBigrams = (run, tokens) => {
|
|
21824
22125
|
const characters = [...run];
|
|
21825
22126
|
if (characters.length === 1) {
|
|
@@ -21836,15 +22137,16 @@ var addBigrams = (run, tokens) => {
|
|
|
21836
22137
|
};
|
|
21837
22138
|
var hasSegmenter = (segmenter) => typeof segmenter === "function";
|
|
21838
22139
|
var segmentingTokenizer = (locale) => {
|
|
21839
|
-
const
|
|
21840
|
-
if (!
|
|
22140
|
+
const resolved = resolveLocale(locale ?? "");
|
|
22141
|
+
if (!resolved?.script || resolved.script === LATIN_SCRIPT) {
|
|
21841
22142
|
return;
|
|
21842
22143
|
}
|
|
21843
22144
|
if (!hasSegmenter(Intl.Segmenter)) {
|
|
21844
22145
|
return;
|
|
21845
22146
|
}
|
|
22147
|
+
const { language } = resolved;
|
|
21846
22148
|
const segmenter = new Intl.Segmenter(language, { granularity: "word" });
|
|
21847
|
-
const bigram =
|
|
22149
|
+
const bigram = isBigramLanguage(language);
|
|
21848
22150
|
return {
|
|
21849
22151
|
language,
|
|
21850
22152
|
normalizationCache: new Map,
|
|
@@ -21863,7 +22165,7 @@ var segmentingTokenizer = (locale) => {
|
|
|
21863
22165
|
return;
|
|
21864
22166
|
}
|
|
21865
22167
|
flush();
|
|
21866
|
-
tokens.add(term);
|
|
22168
|
+
tokens.add(foldDiacritics(term));
|
|
21867
22169
|
};
|
|
21868
22170
|
for (const segment of segmenter.segment(raw.normalize("NFC").toLowerCase())) {
|
|
21869
22171
|
if (!segment.isWordLike) {
|
|
@@ -21916,7 +22218,7 @@ var queryOramaIndex = async (db, term, limit, filters) => {
|
|
|
21916
22218
|
term
|
|
21917
22219
|
};
|
|
21918
22220
|
const params = Object.keys(where).length > 0 ? { ...unfiltered, where } : unfiltered;
|
|
21919
|
-
const bigrammed =
|
|
22221
|
+
const bigrammed = isBigramLanguage(db.tokenizer?.language ?? "");
|
|
21920
22222
|
const strict = bigrammed ? await search(db, { ...params, threshold: ALL_TOKENS }) : undefined;
|
|
21921
22223
|
const found = strict && strict.hits.length > 0 ? strict : await search(db, params);
|
|
21922
22224
|
return found.hits.map((hit) => hit.document);
|
|
@@ -22163,7 +22465,7 @@ var mcpStdioCommand = defineCommand10({
|
|
|
22163
22465
|
});
|
|
22164
22466
|
|
|
22165
22467
|
// src/cli/commands/preview.ts
|
|
22166
|
-
import { existsSync as
|
|
22468
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
22167
22469
|
import { preview } from "astro";
|
|
22168
22470
|
import { defineCommand as defineCommand11 } from "citty";
|
|
22169
22471
|
import { join as join40 } from "pathe";
|
|
@@ -22180,7 +22482,7 @@ var previewCommand = defineCommand11({
|
|
|
22180
22482
|
const root = process.cwd();
|
|
22181
22483
|
const { config: config2 } = await loadConfig(root);
|
|
22182
22484
|
const context = resolveProjectContext(root, config2);
|
|
22183
|
-
if (!
|
|
22485
|
+
if (!existsSync22(join40(context.outDir, "astro.config.mjs"))) {
|
|
22184
22486
|
logger.error("No build found. Run `blume build` first.");
|
|
22185
22487
|
process.exit(1);
|
|
22186
22488
|
}
|
|
@@ -22531,7 +22833,7 @@ var createProgressRenderer = (options) => {
|
|
|
22531
22833
|
};
|
|
22532
22834
|
|
|
22533
22835
|
// src/translate/run.ts
|
|
22534
|
-
import { existsSync as
|
|
22836
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
22535
22837
|
import { mkdtemp as mkdtemp4, readFile as readFile25 } from "node:fs/promises";
|
|
22536
22838
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
22537
22839
|
import pLimit2 from "p-limit";
|
|
@@ -22776,7 +23078,7 @@ var runPageItem = async (item, index, context, ledger) => {
|
|
|
22776
23078
|
});
|
|
22777
23079
|
const sourceText = await readFile25(item.sourcePath, "utf-8");
|
|
22778
23080
|
const target = context.targets.get(item.locale);
|
|
22779
|
-
const previousTranslation =
|
|
23081
|
+
const previousTranslation = existsSync23(item.targetPath) ? await readFile25(item.targetPath, "utf-8") : undefined;
|
|
22780
23082
|
const output = await invokeAgent(context, pagePrompt(sourceText, target, context.source, previousTranslation), index);
|
|
22781
23083
|
if (output.isError) {
|
|
22782
23084
|
return done("failed", output.detail ?? "agent failed", output.costUsd);
|
|
@@ -22897,7 +23199,7 @@ var runTranslate = async (options) => {
|
|
|
22897
23199
|
};
|
|
22898
23200
|
|
|
22899
23201
|
// src/translate/work-list.ts
|
|
22900
|
-
import { existsSync as
|
|
23202
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
22901
23203
|
import { readFile as readFile26 } from "node:fs/promises";
|
|
22902
23204
|
import { dirname as dirname16, extname as extname8, join as join45, relative as relative20 } from "pathe";
|
|
22903
23205
|
var PAGE_EXTENSIONS = new Set([".md", ".mdx"]);
|
|
@@ -22979,7 +23281,7 @@ var computeWorkList = async (project, ledger, options = {}) => {
|
|
|
22979
23281
|
for (const source of meta.metas) {
|
|
22980
23282
|
knownSources.add(source.sourceRel);
|
|
22981
23283
|
const targetDir = dirname16(metaTargetPath(source, locale));
|
|
22982
|
-
const exists = ["meta.ts", "meta.js", "meta.mjs"].some((name) =>
|
|
23284
|
+
const exists = ["meta.ts", "meta.js", "meta.mjs"].some((name) => existsSync24(join45(targetDir, name)));
|
|
22983
23285
|
const hash = hashSource(source.raw);
|
|
22984
23286
|
const stamp = ledger.files[source.sourceRel]?.[locale];
|
|
22985
23287
|
const entry = (status) => ({
|
|
@@ -23211,13 +23513,13 @@ var translateCommand = defineCommand13({
|
|
|
23211
23513
|
});
|
|
23212
23514
|
|
|
23213
23515
|
// src/cli/commands/validate.ts
|
|
23214
|
-
import { existsSync as
|
|
23516
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
23215
23517
|
import { defineCommand as defineCommand14 } from "citty";
|
|
23216
23518
|
import { join as join47 } from "pathe";
|
|
23217
23519
|
|
|
23218
23520
|
// src/core/links.ts
|
|
23219
|
-
import { existsSync as
|
|
23220
|
-
import { basename as
|
|
23521
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
23522
|
+
import { basename as basename7, dirname as dirname17, join as join46 } from "pathe";
|
|
23221
23523
|
var HTTP = /^https?:\/\//iu;
|
|
23222
23524
|
var PROTOCOL_RELATIVE = /^\/\//u;
|
|
23223
23525
|
var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
|
|
@@ -23230,9 +23532,9 @@ var decodePercent = (value) => {
|
|
|
23230
23532
|
};
|
|
23231
23533
|
var DOC_EXT = /\.(?:md|mdx)$/iu;
|
|
23232
23534
|
var FILE_EXT = /\.[a-z0-9]+$/iu;
|
|
23233
|
-
var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null &&
|
|
23535
|
+
var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync25(join46(ctx.publicDir, resolved));
|
|
23234
23536
|
var NUMERIC_PREFIX3 = /^\d+[-_.]/u;
|
|
23235
|
-
var isIndexPage = (page2) => /^index\.(?:md|mdx)$/iu.test(
|
|
23537
|
+
var isIndexPage = (page2) => /^index\.(?:md|mdx)$/iu.test(basename7(page2.navPath).replace(NUMERIC_PREFIX3, ""));
|
|
23236
23538
|
var applyRelativePart = (segments, part) => {
|
|
23237
23539
|
if (part === "" || part === ".") {
|
|
23238
23540
|
return;
|
|
@@ -23281,7 +23583,7 @@ var checkAnchor = (route, fragment, site, ctx) => {
|
|
|
23281
23583
|
severity: "warning"
|
|
23282
23584
|
};
|
|
23283
23585
|
};
|
|
23284
|
-
var checkPathLink = (resolved, fragment,
|
|
23586
|
+
var checkPathLink = (resolved, fragment, page2, link, site, ctx) => {
|
|
23285
23587
|
const route = toRoute(withBasePath(ctx.basePath, resolved));
|
|
23286
23588
|
if (ctx.routes.has(route)) {
|
|
23287
23589
|
return fragment ? checkAnchor(route, fragment, site, ctx) : null;
|
|
@@ -23297,6 +23599,18 @@ var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
|
23297
23599
|
if (assetIsPresent(assetPath, ctx)) {
|
|
23298
23600
|
return null;
|
|
23299
23601
|
}
|
|
23602
|
+
if (link.image && page2.sourcePath && isRelativeImageTarget(link.target)) {
|
|
23603
|
+
if (resolveRelativeImage(dirname17(page2.sourcePath), link.target)) {
|
|
23604
|
+
return null;
|
|
23605
|
+
}
|
|
23606
|
+
return {
|
|
23607
|
+
...site,
|
|
23608
|
+
code: "BLUME_BROKEN_ASSET",
|
|
23609
|
+
message: `Image ${link.target} was not found next to ${basename7(page2.sourcePath)}.`,
|
|
23610
|
+
severity: "warning",
|
|
23611
|
+
suggestion: "Add the file next to the page source or fix the reference."
|
|
23612
|
+
};
|
|
23613
|
+
}
|
|
23300
23614
|
if (ctx.publicDir === null) {
|
|
23301
23615
|
return "asset-unchecked";
|
|
23302
23616
|
}
|
|
@@ -23311,7 +23625,7 @@ var checkPathLink = (resolved, fragment, target, site, ctx) => {
|
|
|
23311
23625
|
return {
|
|
23312
23626
|
...site,
|
|
23313
23627
|
code: "BLUME_BROKEN_LINK",
|
|
23314
|
-
message: `Broken link to ${target}: no page resolves to ${route}.`,
|
|
23628
|
+
message: `Broken link to ${link.target}: no page resolves to ${route}.`,
|
|
23315
23629
|
severity: "error",
|
|
23316
23630
|
suggestion: "Check the path, or create the target page."
|
|
23317
23631
|
};
|
|
@@ -23364,7 +23678,7 @@ var classifyLink = (page2, link, ctx, onExternal) => {
|
|
|
23364
23678
|
return fragment ? checkAnchor(page2.route, fragment, site, ctx) : null;
|
|
23365
23679
|
}
|
|
23366
23680
|
const resolved = rawPath.startsWith("/") ? rawPath : resolveRelative(page2.route, rawPath, isIndexPage(page2));
|
|
23367
|
-
return checkPathLink(resolved, fragment,
|
|
23681
|
+
return checkPathLink(resolved, fragment, page2, link, site, ctx);
|
|
23368
23682
|
};
|
|
23369
23683
|
var validateLinks = async (graph, options) => {
|
|
23370
23684
|
const basePath = options.basePath ?? "";
|
|
@@ -23446,7 +23760,7 @@ var validateCommand = defineCommand14({
|
|
|
23446
23760
|
basePath: project.config.basePath,
|
|
23447
23761
|
checkExternal: Boolean(args.external),
|
|
23448
23762
|
extraRoutes,
|
|
23449
|
-
publicDir:
|
|
23763
|
+
publicDir: existsSync26(publicDir) ? publicDir : null,
|
|
23450
23764
|
redirects: project.config.redirects
|
|
23451
23765
|
}));
|
|
23452
23766
|
} catch (error) {
|
|
@@ -23480,7 +23794,7 @@ var validateCommand = defineCommand14({
|
|
|
23480
23794
|
import { defineCommand as defineCommand15 } from "citty";
|
|
23481
23795
|
|
|
23482
23796
|
// src/core/version-cut.ts
|
|
23483
|
-
import { existsSync as
|
|
23797
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
23484
23798
|
import { cp as cp3, readdir as readdir3, readFile as readFile27, rm as rm5 } from "node:fs/promises";
|
|
23485
23799
|
import { join as join48, relative as relative21 } from "pathe";
|
|
23486
23800
|
class CutError extends Error {
|
|
@@ -23600,7 +23914,7 @@ var cutVersion = async (root, id2, options = {}) => {
|
|
|
23600
23914
|
throw new CutError(`Version "${id2}" is already registered in versions.archived.`);
|
|
23601
23915
|
}
|
|
23602
23916
|
const dir = join48(contentRoot2, id2);
|
|
23603
|
-
if (
|
|
23917
|
+
if (existsSync27(dir)) {
|
|
23604
23918
|
if (!options.force) {
|
|
23605
23919
|
throw new CutError(`${dir} already exists — pass --force to overwrite the snapshot.`);
|
|
23606
23920
|
}
|
|
@@ -23753,5 +24067,5 @@ process.on("unhandledRejection", (error) => {
|
|
|
23753
24067
|
});
|
|
23754
24068
|
runMain(main);
|
|
23755
24069
|
|
|
23756
|
-
//# debugId=
|
|
24070
|
+
//# debugId=94497B7DFC770E9664756E2164756E21
|
|
23757
24071
|
//# sourceMappingURL=index.js.map
|