blume 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli/index.js +434 -150
  3. package/dist/cli/index.js.map +59 -56
  4. package/dist/types/core/data.d.ts +10 -1
  5. package/dist/types/core/i18n-ui.d.ts +2 -0
  6. package/dist/types/core/schema.d.ts +5 -0
  7. package/dist/types/core/types.d.ts +6 -0
  8. package/dist/types/openapi/references.d.ts +5 -0
  9. package/docs/07-faq.mdx +9 -9
  10. package/docs/advanced/api-reference.mdx +10 -1
  11. package/docs/advanced/custom-pages.mdx +3 -1
  12. package/docs/advanced/graphql.mdx +1 -1
  13. package/docs/configuration/ai.mdx +4 -0
  14. package/docs/configuration/seo.mdx +3 -3
  15. package/docs/configuration/theming.mdx +6 -0
  16. package/docs/content/components.mdx +8 -1
  17. package/package.json +53 -53
  18. package/src/astro/examples.ts +29 -2
  19. package/src/astro/generate.ts +99 -61
  20. package/src/astro/index.ts +7 -0
  21. package/src/astro/markdown-negotiation.ts +1 -1
  22. package/src/astro/runtime-modules.ts +196 -0
  23. package/src/astro/templates.ts +241 -38
  24. package/src/cli/commands/build.ts +7 -1
  25. package/src/cli/commands/dev.ts +6 -3
  26. package/src/cli/host-args.ts +18 -0
  27. package/src/cli/index.ts +2 -1
  28. package/src/components/copy-feedback.ts +93 -9
  29. package/src/components/islands/ask-ai.tsx +4 -1
  30. package/src/components/islands/hooks.ts +3 -1
  31. package/src/components/layout/PageActions.astro +25 -14
  32. package/src/core/data.ts +10 -1
  33. package/src/core/define-components.ts +2 -0
  34. package/src/core/i18n-ui.ts +1 -0
  35. package/src/core/includes.ts +2 -1
  36. package/src/core/manifest.ts +10 -0
  37. package/src/core/schema.ts +13 -5
  38. package/src/core/types.ts +6 -0
  39. package/src/core/ui-packs/ar.ts +1 -0
  40. package/src/core/ui-packs/bg.ts +1 -0
  41. package/src/core/ui-packs/bn.ts +1 -0
  42. package/src/core/ui-packs/ca.ts +1 -0
  43. package/src/core/ui-packs/cs.ts +1 -0
  44. package/src/core/ui-packs/da.ts +1 -0
  45. package/src/core/ui-packs/de.ts +1 -0
  46. package/src/core/ui-packs/el.ts +1 -0
  47. package/src/core/ui-packs/es.ts +1 -0
  48. package/src/core/ui-packs/fa.ts +1 -0
  49. package/src/core/ui-packs/fi.ts +1 -0
  50. package/src/core/ui-packs/fr.ts +1 -0
  51. package/src/core/ui-packs/he.ts +1 -0
  52. package/src/core/ui-packs/hi.ts +1 -0
  53. package/src/core/ui-packs/hr.ts +1 -0
  54. package/src/core/ui-packs/hu.ts +1 -0
  55. package/src/core/ui-packs/id.ts +1 -0
  56. package/src/core/ui-packs/it.ts +1 -0
  57. package/src/core/ui-packs/ja.ts +1 -0
  58. package/src/core/ui-packs/ko.ts +1 -0
  59. package/src/core/ui-packs/nl.ts +1 -0
  60. package/src/core/ui-packs/no.ts +1 -0
  61. package/src/core/ui-packs/pl.ts +1 -0
  62. package/src/core/ui-packs/pt-br.ts +1 -0
  63. package/src/core/ui-packs/pt.ts +1 -0
  64. package/src/core/ui-packs/ro.ts +1 -0
  65. package/src/core/ui-packs/ru.ts +1 -0
  66. package/src/core/ui-packs/sk.ts +1 -0
  67. package/src/core/ui-packs/sr.ts +1 -0
  68. package/src/core/ui-packs/sv.ts +1 -0
  69. package/src/core/ui-packs/th.ts +1 -0
  70. package/src/core/ui-packs/tr.ts +1 -0
  71. package/src/core/ui-packs/uk.ts +1 -0
  72. package/src/core/ui-packs/vi.ts +1 -0
  73. package/src/core/ui-packs/zh-tw.ts +1 -0
  74. package/src/core/ui-packs/zh.ts +1 -0
  75. package/src/core/version-cut.ts +5 -3
  76. package/src/deploy/vercel-negotiation.ts +49 -6
  77. package/src/og/card.ts +1 -1
  78. package/src/openapi/references.ts +8 -0
  79. package/src/openapi/render-mdx.ts +18 -4
  80. package/src/openapi/scalar.ts +0 -4
  81. package/src/registry/eject.ts +36 -17
  82. package/src/theme/entry.ts +2 -2
  83. package/src/theme/sources.ts +49 -0
package/dist/cli/index.js CHANGED
@@ -3158,6 +3158,7 @@ var sourcesOf = (block) => {
3158
3158
  includeInLlms: true,
3159
3159
  includeInSearch: true,
3160
3160
  noindex: false,
3161
+ seoDescriptionSuffix: true,
3161
3162
  spec: block.spec
3162
3163
  });
3163
3164
  }
@@ -3191,6 +3192,7 @@ var referencesFor = (kind, block, defaultLabel, renderer, display, basePath) =>
3191
3192
  renderer,
3192
3193
  route,
3193
3194
  scalar: block.scalar,
3195
+ seoDescriptionSuffix: source.seoDescriptionSuffix,
3194
3196
  slug: routeSlug(route),
3195
3197
  spec: source.spec,
3196
3198
  theme: block.theme
@@ -3818,6 +3820,55 @@ var configuredFonts = (fonts, locales = []) => {
3818
3820
  });
3819
3821
  };
3820
3822
 
3823
+ // src/astro/runtime-modules.ts
3824
+ var RUNTIME_MODULE_FILES = new Map([
3825
+ ["blume:ask-data", "ask-data.json"],
3826
+ ["blume:content-assets", "content-assets.json"],
3827
+ ["blume:data", "data.json"],
3828
+ ["blume:mcp-data", "mcp-data.json"],
3829
+ ["blume:openapi", "openapi.json"],
3830
+ ["blume:raw-markdown", "raw-markdown.json"],
3831
+ ["blume:rss", "rss.json"],
3832
+ ["blume:search-index", "search.json"]
3833
+ ]);
3834
+ var RUNTIME_MODULE_IDS = new Set(RUNTIME_MODULE_FILES.keys());
3835
+ var RESOLVED_PREFIX = "\x00";
3836
+ var REGISTRY_KEY = Symbol.for("blume.runtime-modules");
3837
+ var registry2 = () => {
3838
+ const host = globalThis;
3839
+ host[REGISTRY_KEY] ??= { modules: new Map, servers: new Set };
3840
+ return host[REGISTRY_KEY];
3841
+ };
3842
+ var publishRuntimeModules = (modules) => {
3843
+ const { modules: current, servers } = registry2();
3844
+ const changed = [];
3845
+ for (const id of RUNTIME_MODULE_FILES.keys()) {
3846
+ const next = modules.get(id);
3847
+ if (current.get(id) === next) {
3848
+ continue;
3849
+ }
3850
+ if (next === undefined) {
3851
+ current.delete(id);
3852
+ } else {
3853
+ current.set(id, next);
3854
+ }
3855
+ changed.push(id);
3856
+ }
3857
+ if (changed.length === 0) {
3858
+ return changed;
3859
+ }
3860
+ for (const server of servers) {
3861
+ for (const id of changed) {
3862
+ const mod = server.moduleGraph.getModuleById(`${RESOLVED_PREFIX}${id}`);
3863
+ if (mod) {
3864
+ server.moduleGraph.invalidateModule(mod);
3865
+ }
3866
+ }
3867
+ server.ws.send({ type: "full-reload" });
3868
+ }
3869
+ return changed;
3870
+ };
3871
+
3821
3872
  // src/astro/templates.ts
3822
3873
  var WORKSPACE_MARKERS = [
3823
3874
  ".git",
@@ -3944,7 +3995,18 @@ var renderUserAliases = (aliases) => Object.entries(aliases ?? {}).toSorted(([a]
3944
3995
  ${JSON.stringify(find)}: ${JSON.stringify(replacement)},`).join("");
3945
3996
  var astroOutDir = (context) => context.distDir ?? `${context.root}/dist`;
3946
3997
  var adapterRoot = (context) => dirname5(astroOutDir(context));
3947
- var REACT_EXCLUDE = String.raw`exclude: [/\/node_modules\/\.vite\//]`;
3998
+ var REACT_EXCLUDE = String.raw`exclude: [/\/node_modules\/\.vite\//, /\/\.cache\/vite\//]`;
3999
+ var runtimeCacheOptions = (context, generatedModulesDir) => {
4000
+ if (generatedModulesDir !== undefined) {
4001
+ return { astro: "", vite: "" };
4002
+ }
4003
+ return {
4004
+ astro: `
4005
+ cacheDir: ${JSON.stringify(`${context.outDir}/.cache/astro`)},`,
4006
+ vite: `
4007
+ cacheDir: ${JSON.stringify(`${context.outDir}/.cache/vite`)},`
4008
+ };
4009
+ };
3948
4010
  var reactIntegration = (compilerPath) => compilerPath ? `react({ babel: { plugins: [[${JSON.stringify(compilerPath)}, { target: "19" }]] }, ${REACT_EXCLUDE} })` : `react({ ${REACT_EXCLUDE} })`;
3949
4011
  var renderIntegrationBridge = (bridge) => {
3950
4012
  if (!bridge) {
@@ -3985,18 +4047,36 @@ var resolveOptimizeDeps = (options) => {
3985
4047
  ];
3986
4048
  return { optimizeDepsEntries, optimizeDepsInclude };
3987
4049
  };
4050
+ var renderRuntimeModuleWiring = (generatedModulesDir) => {
4051
+ if (generatedModulesDir === undefined) {
4052
+ return {
4053
+ aliasLines: "",
4054
+ imports: ["runtimeModulesPlugin"],
4055
+ pluginEntry: "runtimeModulesPlugin(), "
4056
+ };
4057
+ }
4058
+ const aliasLines = [...RUNTIME_MODULE_FILES].map(([id, file]) => `
4059
+ ${JSON.stringify(id)}: ${JSON.stringify(`${generatedModulesDir}/${file}`)},`).join("");
4060
+ return { aliasLines, imports: [], pluginEntry: "" };
4061
+ };
3988
4062
  var astroConfigTemplate = (options) => {
3989
- const { context, config, needsReact, pages, dataPath, themePath } = options;
4063
+ const { context, config, needsReact, pages, themePath } = options;
4064
+ const { astro: cacheOptions, vite: viteCacheOption } = runtimeCacheOptions(context, options.generatedModulesDir);
3990
4065
  const {
3991
4066
  askPath,
3992
4067
  contentRoutes,
3993
4068
  examplesPath,
3994
4069
  examplesThemePath,
4070
+ generatedModulesDir,
3995
4071
  needsSvelte,
3996
4072
  needsVue,
3997
- openapiPath,
3998
4073
  searchClientPath
3999
4074
  } = options;
4075
+ const {
4076
+ aliasLines: runtimeModuleAliasLines,
4077
+ imports: runtimeModuleImports,
4078
+ pluginEntry: runtimeModulesPluginEntry
4079
+ } = renderRuntimeModuleWiring(generatedModulesDir);
4000
4080
  const { deployment } = config;
4001
4081
  const userAliasLines = renderUserAliases(options.aliases);
4002
4082
  const server = deployment.output === "server";
@@ -4072,6 +4152,7 @@ var astroConfigTemplate = (options) => {
4072
4152
  "blumeIntegration",
4073
4153
  "includeHmrPlugin",
4074
4154
  "prerenderDepsPlugin",
4155
+ ...runtimeModuleImports,
4075
4156
  ...adapterOption.includes("withAdapterRoot") ? ["withAdapterRoot"] : []
4076
4157
  ];
4077
4158
  const blumeImport = `import { ${blumeImports.join(", ")} } from "blume/astro";
@@ -4118,7 +4199,7 @@ ${userConfigSetup}export default defineConfig({
4118
4199
  root: ${JSON.stringify(context.outDir)},
4119
4200
  srcDir: ${JSON.stringify(`${context.outDir}/src`)},
4120
4201
  outDir: ${JSON.stringify(astroOutDir(context))},
4121
- publicDir: ${JSON.stringify(`${context.root}/public`)},
4202
+ publicDir: ${JSON.stringify(`${context.root}/public`)},${cacheOptions}
4122
4203
  output: ${JSON.stringify(deployment.output)},${adapterOption}${sessionOption}${siteOption}${baseOption}${imageOption}${redirectsOption}${i18nOption}${fontsOption}
4123
4204
  integrations: [${integrations.join(", ")}${userIntegrationSpread}],
4124
4205
  markdown: {
@@ -4144,8 +4225,8 @@ ${userConfigSetup}export default defineConfig({
4144
4225
  // request latency behind the user's intent, so most navigations swap
4145
4226
  // instantly.
4146
4227
  prefetch: { prefetchAll: true },
4147
- vite: {
4148
- plugins: [tailwindcss(), includeHmrPlugin(${JSON.stringify(`${context.outDir}/src/generated/includes.json`)}), prerenderDepsPlugin()],
4228
+ vite: {${viteCacheOption}
4229
+ plugins: [${runtimeModulesPluginEntry}tailwindcss(), includeHmrPlugin(${JSON.stringify(`${context.outDir}/src/generated/includes.json`)}), prerenderDepsPlugin()],
4149
4230
  // Everything hydration can reach must be part of the dev dep optimizer's
4150
4231
  // FIRST run. The Vite root is the generated runtime, so user pages,
4151
4232
  // islands, and aliased components live outside it and are only crawled
@@ -4192,12 +4273,10 @@ ${userConfigSetup}export default defineConfig({
4192
4273
  resolve: {
4193
4274
  alias: {
4194
4275
  "blume:ask": ${JSON.stringify(askPath)},
4195
- "blume:data": ${JSON.stringify(dataPath)},
4196
4276
  "blume:examples": ${JSON.stringify(examplesPath)},
4197
4277
  "blume:examples-theme": ${JSON.stringify(examplesThemePath)},
4198
- "blume:openapi": ${JSON.stringify(openapiPath)},
4199
4278
  "blume:search-client": ${JSON.stringify(searchClientPath)},
4200
- "blume:theme": ${JSON.stringify(themePath)},${userAliasLines}
4279
+ "blume:theme": ${JSON.stringify(themePath)},${runtimeModuleAliasLines}${userAliasLines}
4201
4280
  },
4202
4281
  },
4203
4282
  server: {
@@ -4288,7 +4367,7 @@ const provider = createOpenAICompatible({
4288
4367
  modelExpr = `provider(${JSON.stringify(backend.model)})`;
4289
4368
  }
4290
4369
  if (grounded) {
4291
- imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "../../generated/ask-data.json";');
4370
+ imports.push('import { createAskContext } from "blume/ai/ask-context.ts";', 'import askData from "blume:ask-data";');
4292
4371
  const groundFields = [];
4293
4372
  if (instructions) {
4294
4373
  groundFields.push(`instructions: ${JSON.stringify(instructions)}`);
@@ -4396,7 +4475,7 @@ const { strings } = Astro.props;
4396
4475
  ---
4397
4476
  `;
4398
4477
  var searchEndpointTemplate = () => `// Generated by Blume. Do not edit.
4399
- import documents from "../generated/search.json";
4478
+ import documents from "blume:search-index";
4400
4479
 
4401
4480
  export const prerender = true;
4402
4481
 
@@ -4507,7 +4586,7 @@ export const POST: APIRoute = async ({ request }) => {
4507
4586
  };
4508
4587
  `;
4509
4588
  var rawMarkdownEndpointTemplate = (kind) => `// Generated by Blume. Do not edit.
4510
- import raw from "../generated/raw-markdown.json";
4589
+ import raw from "blume:raw-markdown";
4511
4590
 
4512
4591
  export const prerender = true;
4513
4592
 
@@ -4536,7 +4615,7 @@ import { existsSync } from "node:fs";
4536
4615
  import { readdir, readFile } from "node:fs/promises";
4537
4616
  import { isAbsolute, join, relative, resolve } from "node:path";
4538
4617
  import type { APIRoute } from "astro";
4539
- import assets from "../../generated/content-assets.json";
4618
+ import assets from "blume:content-assets";
4540
4619
 
4541
4620
  export const prerender = true;
4542
4621
 
@@ -4618,22 +4697,17 @@ export const GET: APIRoute = async ({ params }) => {
4618
4697
  };
4619
4698
  `;
4620
4699
  var mcpPageFile = (route) => `${trimChar(route, "/")}.ts`;
4621
- var mcpEndpointTemplate = (route) => {
4622
- const clean = trimChar(route, "/");
4623
- const up = "../".repeat(clean.split("/").length);
4624
- return `// Generated by Blume. Do not edit.
4700
+ var mcpEndpointTemplate = () => `// Generated by Blume. Do not edit.
4625
4701
  import type { APIRoute } from "astro";
4626
4702
  import { createMcpFetchHandler } from "blume/ai/mcp/server.ts";
4627
- import type { McpData } from "blume/ai/mcp/data.ts";
4628
- import data from "${up}generated/mcp-data.json";
4703
+ import data from "blume:mcp-data";
4629
4704
 
4630
4705
  export const prerender = false;
4631
4706
 
4632
- const handler = createMcpFetchHandler(data as McpData);
4707
+ const handler = createMcpFetchHandler(data);
4633
4708
 
4634
4709
  export const ALL: APIRoute = ({ request }) => handler(request);
4635
4710
  `;
4636
- };
4637
4711
  var playgroundProxyTemplate = (origins) => `// Generated by Blume. Do not edit.
4638
4712
  import type { APIRoute } from "astro";
4639
4713
  import { createPlaygroundProxyHandler } from "blume/openapi/proxy.ts";
@@ -4656,7 +4730,7 @@ export function GET() {
4656
4730
  }
4657
4731
  `;
4658
4732
  var rssEndpointTemplate = () => `// Generated by Blume. Do not edit.
4659
- import feeds from "../../generated/rss.json";
4733
+ import feeds from "blume:rss";
4660
4734
 
4661
4735
  export const prerender = true;
4662
4736
 
@@ -4693,26 +4767,50 @@ const customRoutes: { slug: string; title: string }[] = ${JSON.stringify(customR
4693
4767
  const fonts: OgFont[] = ${JSON.stringify(og.fonts ?? [])};
4694
4768
  const families: OgFontFamilies | undefined = ${og.families ? JSON.stringify(og.families) : "undefined"};
4695
4769
 
4770
+ // A page's own description (its \`seo.description\`, else \`description\`) is
4771
+ // the card subtitle, so the image says what the page's og:description says.
4772
+ // Pages without one fall back to the site-wide subtitle at render time.
4773
+ // \`seo.og.description: false\` hides the subtitle on every card, page text
4774
+ // included, which is what switches this off.
4775
+ const pageDescriptions = ${og.pageDescriptions !== false};
4776
+
4777
+ interface CardProps {
4778
+ title: string;
4779
+ description: string | null;
4780
+ }
4781
+
4696
4782
  export function getStaticPaths() {
4697
4783
  const seen = new Set<string>();
4698
- const paths: { params: { slug: string }; props: { title: string } }[] = [];
4699
- const add = (slug: string, title: string) => {
4784
+ const paths: { params: { slug: string }; props: CardProps }[] = [];
4785
+ const add = (slug: string, title: string, description: string | null) => {
4700
4786
  if (seen.has(slug)) {
4701
4787
  return;
4702
4788
  }
4703
4789
  seen.add(slug);
4704
- paths.push({ params: { slug }, props: { title } });
4790
+ paths.push({
4791
+ params: { slug },
4792
+ props: { title, description: pageDescriptions ? description : null },
4793
+ });
4705
4794
  };
4706
4795
  // A custom page wins over a content route sharing its path, so add it first.
4796
+ // Its description is unknown at generate time, so it takes the site subtitle.
4707
4797
  for (const route of customRoutes) {
4708
- add(route.slug, route.title);
4798
+ add(route.slug, route.title, null);
4709
4799
  }
4710
4800
  for (const route of data.routes) {
4711
- add(route.path === "/" ? "index" : route.path.slice(1), route.title);
4801
+ add(
4802
+ route.path === "/" ? "index" : route.path.slice(1),
4803
+ route.title,
4804
+ route.description
4805
+ );
4712
4806
  }${includeChangelog ? `
4713
4807
  // The generated changelog index is not a content route, so it needs its own
4714
4808
  // card. Added last: a custom page or content route owning /changelog wins.
4715
- add("changelog", data.ui.changelog?.title ?? "Changelog");` : ""}
4809
+ add(
4810
+ "changelog",
4811
+ data.ui.changelog?.title ?? "Changelog",
4812
+ data.ui.changelog?.description ?? null
4813
+ );` : ""}
4716
4814
  return paths;
4717
4815
  }
4718
4816
 
@@ -4723,11 +4821,11 @@ const repoSlug = data.config.github
4723
4821
  ? \`\${data.config.github.owner}/\${data.config.github.repo}\`
4724
4822
  : undefined;
4725
4823
 
4726
- export async function GET({ props }: { props: { title: string } }) {
4824
+ export async function GET({ props }: { props: CardProps }) {
4727
4825
  const png = await renderOgImage({
4728
4826
  accent: data.config.og.palette?.accent ?? data.config.theme.accent.light,
4729
4827
  brand: data.config.title,
4730
- description: data.config.og.description,
4828
+ description: props.description ?? data.config.og.description,
4731
4829
  families,
4732
4830
  fonts,
4733
4831
  logo: data.config.og.logo,
@@ -4748,7 +4846,7 @@ var scalarReferenceTemplate = (options) => `---
4748
4846
  // Generated by Blume. Do not edit.
4749
4847
  import { ScalarComponent } from "@scalar/astro";
4750
4848
  import ReferenceLayout from "blume/components/layout/ReferenceLayout.astro";
4751
- import data from ${JSON.stringify(options.dataImport)};
4849
+ import data from "blume:data";
4752
4850
 
4753
4851
  export const prerender = true;
4754
4852
 
@@ -5532,6 +5630,61 @@ const suggestions = [
5532
5630
  </div>
5533
5631
  </PageLayout>
5534
5632
  `;
5633
+ var notFoundMarkdownTemplate = () => `// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
5634
+ import { withBase } from "blume/components/islands/base-path.ts";
5635
+ import { absoluteUrl } from "blume/core/site-url.ts";
5636
+ import data from "blume:data";
5637
+
5638
+ export const prerender = true;
5639
+
5640
+ const nf = data.ui.notFound;
5641
+
5642
+ // Absolute for internal routes when the site is known; an external tab href
5643
+ // passes through untouched.
5644
+ const href = (path: string): string => {
5645
+ const based = withBase(path);
5646
+ return data.config.site && based.startsWith("/") && !based.startsWith("//")
5647
+ ? absoluteUrl(data.config.site, based)
5648
+ : based;
5649
+ };
5650
+
5651
+ // The recovery set of 404.astro: home, every top-level section (a tab links to
5652
+ // its resolved target), then the machine-readable indexes that exist.
5653
+ const links = [
5654
+ { href: href("/"), label: nf.home },
5655
+ ...data.navigation.tabs.map((tab) => ({
5656
+ href: href(tab.href ?? tab.path),
5657
+ label: tab.label,
5658
+ })),
5659
+ ...(data.config.discovery.sitemap
5660
+ ? [{ href: href("/sitemap.xml"), label: nf.sitemap }]
5661
+ : []),
5662
+ ...(data.config.discovery.llmsTxt
5663
+ ? [{ href: href("/llms.txt"), label: nf.llms }]
5664
+ : []),
5665
+ ];
5666
+
5667
+ const body = [
5668
+ "# " + nf.title,
5669
+ "",
5670
+ nf.description,
5671
+ "",
5672
+ "## " + nf.suggestions,
5673
+ "",
5674
+ ...links.map((link) => "- [" + link.label + "](" + link.href + ")"),
5675
+ "",
5676
+ ].join("\\n");
5677
+
5678
+ export function GET() {
5679
+ return new Response(body, {
5680
+ headers: {
5681
+ "Content-Type": "text/markdown; charset=utf-8",
5682
+ // ~4 characters per token; keep in sync with markdownTokenCount.
5683
+ "x-markdown-tokens": String(Math.ceil(body.length / 4)),
5684
+ },
5685
+ });
5686
+ }
5687
+ `;
5535
5688
  var islandDirective = (spec) => spec.client === "only" ? `client:only="${spec.framework}"` : `client:${spec.client}`;
5536
5689
  var wrapperPropsType = (name) => `type Props = typeof ${name} extends (
5537
5690
  props: infer P extends object,
@@ -5702,6 +5855,36 @@ declare module "blume:data" {
5702
5855
  export default data;
5703
5856
  }
5704
5857
 
5858
+ declare module "blume:ask-data" {
5859
+ const askData: import("blume/ai/ask-context.ts").AskData;
5860
+ export default askData;
5861
+ }
5862
+
5863
+ declare module "blume:content-assets" {
5864
+ const assets: Record<string, string>;
5865
+ export default assets;
5866
+ }
5867
+
5868
+ declare module "blume:mcp-data" {
5869
+ const data: import("blume/ai/mcp/data.ts").McpData;
5870
+ export default data;
5871
+ }
5872
+
5873
+ declare module "blume:raw-markdown" {
5874
+ const raw: Record<string, import("blume/ai/markdown.ts").RawMarkdownEntry>;
5875
+ export default raw;
5876
+ }
5877
+
5878
+ declare module "blume:rss" {
5879
+ const feeds: Record<string, string>;
5880
+ export default feeds;
5881
+ }
5882
+
5883
+ declare module "blume:search-index" {
5884
+ const documents: import("blume/search/documents.ts").SearchDocument[];
5885
+ export default documents;
5886
+ }
5887
+
5705
5888
  declare module "blume:examples" {
5706
5889
  type Examples = typeof import("./generated/examples.ts").examples;
5707
5890
  export const examples: Record<string, Examples[keyof Examples]>;
@@ -6288,6 +6471,7 @@ var ar = {
6288
6471
  copyClaudeCode: "نسخ أمر Claude Code",
6289
6472
  copyCode: "نسخ الكود",
6290
6473
  copyCodex: "نسخ أمر Codex",
6474
+ copyFailed: "فشل النسخ",
6291
6475
  copyMarkdown: "نسخ بصيغة Markdown",
6292
6476
  copyServerUrl: "نسخ عنوان URL للخادم",
6293
6477
  edit: "التعديل على GitHub",
@@ -6384,6 +6568,7 @@ var bg = {
6384
6568
  copyClaudeCode: "Копирай командата на Claude Code",
6385
6569
  copyCode: "Копирай кода",
6386
6570
  copyCodex: "Копирай командата на Codex",
6571
+ copyFailed: "Копирането не бе успешно",
6387
6572
  copyMarkdown: "Копирай като Markdown",
6388
6573
  copyServerUrl: "Копирай URL на сървъра",
6389
6574
  edit: "Редактирай в GitHub",
@@ -6480,6 +6665,7 @@ var bn = {
6480
6665
  copyClaudeCode: "Claude Code কমান্ড অনুলিপি করুন",
6481
6666
  copyCode: "কোড অনুলিপি করুন",
6482
6667
  copyCodex: "Codex কমান্ড অনুলিপি করুন",
6668
+ copyFailed: "অনুলিপি ব্যর্থ হয়েছে",
6483
6669
  copyMarkdown: "Markdown হিসেবে অনুলিপি করুন",
6484
6670
  copyServerUrl: "সার্ভার URL অনুলিপি করুন",
6485
6671
  edit: "GitHub-এ সম্পাদনা করুন",
@@ -6576,6 +6762,7 @@ var ca = {
6576
6762
  copyClaudeCode: "Copia l'ordre de Claude Code",
6577
6763
  copyCode: "Copia el codi",
6578
6764
  copyCodex: "Copia l'ordre de Codex",
6765
+ copyFailed: "No s'ha pogut copiar",
6579
6766
  copyMarkdown: "Copia com a Markdown",
6580
6767
  copyServerUrl: "Copia l'URL del servidor",
6581
6768
  edit: "Edita a GitHub",
@@ -6674,6 +6861,7 @@ var cs = {
6674
6861
  copyClaudeCode: "Kopírovat příkaz Claude Code",
6675
6862
  copyCode: "Kopírovat kód",
6676
6863
  copyCodex: "Kopírovat příkaz Codex",
6864
+ copyFailed: "Kopírování se nezdařilo",
6677
6865
  copyMarkdown: "Kopírovat jako Markdown",
6678
6866
  copyServerUrl: "Kopírovat URL serveru",
6679
6867
  edit: "Upravit na GitHubu",
@@ -6770,6 +6958,7 @@ var da = {
6770
6958
  copyClaudeCode: "Kopiér Claude Code-kommando",
6771
6959
  copyCode: "Kopiér kode",
6772
6960
  copyCodex: "Kopiér Codex-kommando",
6961
+ copyFailed: "Kopiering mislykkedes",
6773
6962
  copyMarkdown: "Kopiér som Markdown",
6774
6963
  copyServerUrl: "Kopiér server-URL",
6775
6964
  edit: "Rediger på GitHub",
@@ -6866,6 +7055,7 @@ var de = {
6866
7055
  copyClaudeCode: "Claude-Code-Befehl kopieren",
6867
7056
  copyCode: "Code kopieren",
6868
7057
  copyCodex: "Codex-Befehl kopieren",
7058
+ copyFailed: "Kopieren fehlgeschlagen",
6869
7059
  copyMarkdown: "Als Markdown kopieren",
6870
7060
  copyServerUrl: "Server-URL kopieren",
6871
7061
  edit: "Auf GitHub bearbeiten",
@@ -6962,6 +7152,7 @@ var el = {
6962
7152
  copyClaudeCode: "Αντιγραφή εντολής Claude Code",
6963
7153
  copyCode: "Αντιγραφή κώδικα",
6964
7154
  copyCodex: "Αντιγραφή εντολής Codex",
7155
+ copyFailed: "Η αντιγραφή απέτυχε",
6965
7156
  copyMarkdown: "Αντιγραφή ως Markdown",
6966
7157
  copyServerUrl: "Αντιγραφή URL διακομιστή",
6967
7158
  edit: "Επεξεργασία στο GitHub",
@@ -7060,6 +7251,7 @@ var es = {
7060
7251
  copyClaudeCode: "Copiar comando de Claude Code",
7061
7252
  copyCode: "Copiar código",
7062
7253
  copyCodex: "Copiar comando de Codex",
7254
+ copyFailed: "Error al copiar",
7063
7255
  copyMarkdown: "Copiar como Markdown",
7064
7256
  copyServerUrl: "Copiar URL del servidor",
7065
7257
  edit: "Editar en GitHub",
@@ -7158,6 +7350,7 @@ var fa = {
7158
7350
  copyClaudeCode: "کپی دستور Claude Code",
7159
7351
  copyCode: "کپی کد",
7160
7352
  copyCodex: "کپی دستور Codex",
7353
+ copyFailed: "کپی ناموفق بود",
7161
7354
  copyMarkdown: "کپی به‌صورت Markdown",
7162
7355
  copyServerUrl: "کپی نشانی سرور",
7163
7356
  edit: "ویرایش در GitHub",
@@ -7254,6 +7447,7 @@ var fi = {
7254
7447
  copyClaudeCode: "Kopioi Claude Code -komento",
7255
7448
  copyCode: "Kopioi koodi",
7256
7449
  copyCodex: "Kopioi Codex-komento",
7450
+ copyFailed: "Kopiointi epäonnistui",
7257
7451
  copyMarkdown: "Kopioi Markdownina",
7258
7452
  copyServerUrl: "Kopioi palvelimen URL",
7259
7453
  edit: "Muokkaa GitHubissa",
@@ -7350,6 +7544,7 @@ var fr = {
7350
7544
  copyClaudeCode: "Copier la commande Claude Code",
7351
7545
  copyCode: "Copier le code",
7352
7546
  copyCodex: "Copier la commande Codex",
7547
+ copyFailed: "Échec de la copie",
7353
7548
  copyMarkdown: "Copier en Markdown",
7354
7549
  copyServerUrl: "Copier l'URL du serveur",
7355
7550
  edit: "Modifier sur GitHub",
@@ -7448,6 +7643,7 @@ var he = {
7448
7643
  copyClaudeCode: "העתק פקודת Claude Code",
7449
7644
  copyCode: "העתק קוד",
7450
7645
  copyCodex: "העתק פקודת Codex",
7646
+ copyFailed: "ההעתקה נכשלה",
7451
7647
  copyMarkdown: "העתק כ-Markdown",
7452
7648
  copyServerUrl: "העתק כתובת URL של השרת",
7453
7649
  edit: "ערוך ב-GitHub",
@@ -7544,6 +7740,7 @@ var hi = {
7544
7740
  copyClaudeCode: "Claude Code कमांड कॉपी करें",
7545
7741
  copyCode: "कोड कॉपी करें",
7546
7742
  copyCodex: "Codex कमांड कॉपी करें",
7743
+ copyFailed: "कॉपी विफल रहा",
7547
7744
  copyMarkdown: "Markdown के रूप में कॉपी करें",
7548
7745
  copyServerUrl: "सर्वर URL कॉपी करें",
7549
7746
  edit: "GitHub पर संपादित करें",
@@ -7640,6 +7837,7 @@ var hr = {
7640
7837
  copyClaudeCode: "Kopiraj naredbu Claude Code",
7641
7838
  copyCode: "Kopiraj kôd",
7642
7839
  copyCodex: "Kopiraj naredbu Codex",
7840
+ copyFailed: "Kopiranje nije uspjelo",
7643
7841
  copyMarkdown: "Kopiraj kao Markdown",
7644
7842
  copyServerUrl: "Kopiraj URL poslužitelja",
7645
7843
  edit: "Uredi na GitHubu",
@@ -7736,6 +7934,7 @@ var hu = {
7736
7934
  copyClaudeCode: "Claude Code parancs másolása",
7737
7935
  copyCode: "Kód másolása",
7738
7936
  copyCodex: "Codex parancs másolása",
7937
+ copyFailed: "A másolás nem sikerült",
7739
7938
  copyMarkdown: "Másolás Markdownként",
7740
7939
  copyServerUrl: "Szerver URL másolása",
7741
7940
  edit: "Szerkesztés a GitHubon",
@@ -7832,6 +8031,7 @@ var id = {
7832
8031
  copyClaudeCode: "Salin perintah Claude Code",
7833
8032
  copyCode: "Salin kode",
7834
8033
  copyCodex: "Salin perintah Codex",
8034
+ copyFailed: "Gagal menyalin",
7835
8035
  copyMarkdown: "Salin sebagai Markdown",
7836
8036
  copyServerUrl: "Salin URL server",
7837
8037
  edit: "Edit di GitHub",
@@ -7928,6 +8128,7 @@ var it = {
7928
8128
  copyClaudeCode: "Copia comando di Claude Code",
7929
8129
  copyCode: "Copia codice",
7930
8130
  copyCodex: "Copia comando di Codex",
8131
+ copyFailed: "Copia non riuscita",
7931
8132
  copyMarkdown: "Copia come Markdown",
7932
8133
  copyServerUrl: "Copia URL del server",
7933
8134
  edit: "Modifica su GitHub",
@@ -8026,6 +8227,7 @@ var ja = {
8026
8227
  copyClaudeCode: "Claude Code コマンドをコピー",
8027
8228
  copyCode: "コードをコピー",
8028
8229
  copyCodex: "Codex コマンドをコピー",
8230
+ copyFailed: "コピーに失敗しました",
8029
8231
  copyMarkdown: "Markdown としてコピー",
8030
8232
  copyServerUrl: "サーバー URL をコピー",
8031
8233
  edit: "GitHub で編集",
@@ -8124,6 +8326,7 @@ var ko = {
8124
8326
  copyClaudeCode: "Claude Code 명령 복사",
8125
8327
  copyCode: "코드 복사",
8126
8328
  copyCodex: "Codex 명령 복사",
8329
+ copyFailed: "복사 실패",
8127
8330
  copyMarkdown: "Markdown으로 복사",
8128
8331
  copyServerUrl: "서버 URL 복사",
8129
8332
  edit: "GitHub에서 편집",
@@ -8222,6 +8425,7 @@ var nl = {
8222
8425
  copyClaudeCode: "Claude Code-opdracht kopiëren",
8223
8426
  copyCode: "Code kopiëren",
8224
8427
  copyCodex: "Codex-opdracht kopiëren",
8428
+ copyFailed: "Kopiëren mislukt",
8225
8429
  copyMarkdown: "Kopiëren als Markdown",
8226
8430
  copyServerUrl: "Server-URL kopiëren",
8227
8431
  edit: "Bewerken op GitHub",
@@ -8318,6 +8522,7 @@ var no = {
8318
8522
  copyClaudeCode: "Kopier Claude Code-kommando",
8319
8523
  copyCode: "Kopier kode",
8320
8524
  copyCodex: "Kopier Codex-kommando",
8525
+ copyFailed: "Kopiering mislyktes",
8321
8526
  copyMarkdown: "Kopier som Markdown",
8322
8527
  copyServerUrl: "Kopier server-URL",
8323
8528
  edit: "Rediger på GitHub",
@@ -8414,6 +8619,7 @@ var pl = {
8414
8619
  copyClaudeCode: "Kopiuj polecenie Claude Code",
8415
8620
  copyCode: "Kopiuj kod",
8416
8621
  copyCodex: "Kopiuj polecenie Codex",
8622
+ copyFailed: "Kopiowanie nie powiodło się",
8417
8623
  copyMarkdown: "Kopiuj jako Markdown",
8418
8624
  copyServerUrl: "Kopiuj adres URL serwera",
8419
8625
  edit: "Edytuj na GitHubie",
@@ -8510,6 +8716,7 @@ var ptBR = {
8510
8716
  copyClaudeCode: "Copiar comando do Claude Code",
8511
8717
  copyCode: "Copiar código",
8512
8718
  copyCodex: "Copiar comando do Codex",
8719
+ copyFailed: "Falha ao copiar",
8513
8720
  copyMarkdown: "Copiar como Markdown",
8514
8721
  copyServerUrl: "Copiar URL do servidor",
8515
8722
  edit: "Editar no GitHub",
@@ -8608,6 +8815,7 @@ var pt = {
8608
8815
  copyClaudeCode: "Copiar comando do Claude Code",
8609
8816
  copyCode: "Copiar código",
8610
8817
  copyCodex: "Copiar comando do Codex",
8818
+ copyFailed: "Falha ao copiar",
8611
8819
  copyMarkdown: "Copiar como Markdown",
8612
8820
  copyServerUrl: "Copiar URL do servidor",
8613
8821
  edit: "Editar no GitHub",
@@ -8706,6 +8914,7 @@ var ro = {
8706
8914
  copyClaudeCode: "Copiază comanda Claude Code",
8707
8915
  copyCode: "Copiază codul",
8708
8916
  copyCodex: "Copiază comanda Codex",
8917
+ copyFailed: "Copierea a eșuat",
8709
8918
  copyMarkdown: "Copiază ca Markdown",
8710
8919
  copyServerUrl: "Copiază URL-ul serverului",
8711
8920
  edit: "Editează pe GitHub",
@@ -8802,6 +9011,7 @@ var ru = {
8802
9011
  copyClaudeCode: "Скопировать команду Claude Code",
8803
9012
  copyCode: "Скопировать код",
8804
9013
  copyCodex: "Скопировать команду Codex",
9014
+ copyFailed: "Не удалось скопировать",
8805
9015
  copyMarkdown: "Скопировать как Markdown",
8806
9016
  copyServerUrl: "Скопировать URL сервера",
8807
9017
  edit: "Редактировать на GitHub",
@@ -8898,6 +9108,7 @@ var sk = {
8898
9108
  copyClaudeCode: "Kopírovať príkaz Claude Code",
8899
9109
  copyCode: "Kopírovať kód",
8900
9110
  copyCodex: "Kopírovať príkaz Codex",
9111
+ copyFailed: "Kopírovanie zlyhalo",
8901
9112
  copyMarkdown: "Kopírovať ako Markdown",
8902
9113
  copyServerUrl: "Kopírovať URL servera",
8903
9114
  edit: "Upraviť na GitHube",
@@ -8994,6 +9205,7 @@ var sr = {
8994
9205
  copyClaudeCode: "Копирај Claude Code команду",
8995
9206
  copyCode: "Копирај код",
8996
9207
  copyCodex: "Копирај Codex команду",
9208
+ copyFailed: "Копирање није успело",
8997
9209
  copyMarkdown: "Копирај као Markdown",
8998
9210
  copyServerUrl: "Копирај URL сервера",
8999
9211
  edit: "Уреди на GitHub-у",
@@ -9090,6 +9302,7 @@ var sv = {
9090
9302
  copyClaudeCode: "Kopiera Claude Code-kommando",
9091
9303
  copyCode: "Kopiera kod",
9092
9304
  copyCodex: "Kopiera Codex-kommando",
9305
+ copyFailed: "Kopiering misslyckades",
9093
9306
  copyMarkdown: "Kopiera som Markdown",
9094
9307
  copyServerUrl: "Kopiera server-URL",
9095
9308
  edit: "Redigera på GitHub",
@@ -9186,6 +9399,7 @@ var th = {
9186
9399
  copyClaudeCode: "คัดลอกคำสั่ง Claude Code",
9187
9400
  copyCode: "คัดลอกโค้ด",
9188
9401
  copyCodex: "คัดลอกคำสั่ง Codex",
9402
+ copyFailed: "คัดลอกไม่สำเร็จ",
9189
9403
  copyMarkdown: "คัดลอกเป็น Markdown",
9190
9404
  copyServerUrl: "คัดลอก URL ของเซิร์ฟเวอร์",
9191
9405
  edit: "แก้ไขบน GitHub",
@@ -9284,6 +9498,7 @@ var tr = {
9284
9498
  copyClaudeCode: "Claude Code komutunu kopyala",
9285
9499
  copyCode: "Kodu kopyala",
9286
9500
  copyCodex: "Codex komutunu kopyala",
9501
+ copyFailed: "Kopyalama başarısız oldu",
9287
9502
  copyMarkdown: "Markdown olarak kopyala",
9288
9503
  copyServerUrl: "Sunucu URL'sini kopyala",
9289
9504
  edit: "GitHub'da düzenle",
@@ -9380,6 +9595,7 @@ var uk = {
9380
9595
  copyClaudeCode: "Скопіювати команду Claude Code",
9381
9596
  copyCode: "Скопіювати код",
9382
9597
  copyCodex: "Скопіювати команду Codex",
9598
+ copyFailed: "Не вдалося скопіювати",
9383
9599
  copyMarkdown: "Скопіювати як Markdown",
9384
9600
  copyServerUrl: "Скопіювати URL сервера",
9385
9601
  edit: "Редагувати на GitHub",
@@ -9476,6 +9692,7 @@ var vi = {
9476
9692
  copyClaudeCode: "Sao chép lệnh Claude Code",
9477
9693
  copyCode: "Sao chép mã",
9478
9694
  copyCodex: "Sao chép lệnh Codex",
9695
+ copyFailed: "Sao chép thất bại",
9479
9696
  copyMarkdown: "Sao chép dưới dạng Markdown",
9480
9697
  copyServerUrl: "Sao chép URL máy chủ",
9481
9698
  edit: "Chỉnh sửa trên GitHub",
@@ -9574,6 +9791,7 @@ var zhTW = {
9574
9791
  copyClaudeCode: "複製 Claude Code 指令",
9575
9792
  copyCode: "複製程式碼",
9576
9793
  copyCodex: "複製 Codex 指令",
9794
+ copyFailed: "複製失敗",
9577
9795
  copyMarkdown: "複製為 Markdown",
9578
9796
  copyServerUrl: "複製伺服器 URL",
9579
9797
  edit: "在 GitHub 上編輯",
@@ -9672,6 +9890,7 @@ var zh = {
9672
9890
  copyClaudeCode: "复制 Claude Code 命令",
9673
9891
  copyCode: "复制代码",
9674
9892
  copyCodex: "复制 Codex 命令",
9893
+ copyFailed: "复制失败",
9675
9894
  copyMarkdown: "复制为 Markdown",
9676
9895
  copyServerUrl: "复制服务器 URL",
9677
9896
  edit: "在 GitHub 上编辑",
@@ -9810,6 +10029,7 @@ var uiStringsObject = z.object({
9810
10029
  copyClaudeCode: z.string().default("Copy Claude Code command"),
9811
10030
  copyCode: z.string().default("Copy code"),
9812
10031
  copyCodex: z.string().default("Copy Codex command"),
10032
+ copyFailed: z.string().default("Copy failed"),
9813
10033
  copyMarkdown: z.string().default("Copy as Markdown"),
9814
10034
  copyServerUrl: z.string().default("Copy server URL"),
9815
10035
  edit: z.string().default("Edit on GitHub"),
@@ -10734,6 +10954,7 @@ var openapiSourceSchema = z2.strictObject({
10734
10954
  label: z2.string().optional(),
10735
10955
  noindex: z2.boolean().default(false),
10736
10956
  route: z2.string().optional(),
10957
+ seoDescriptionSuffix: z2.boolean().default(true),
10737
10958
  spec: z2.string()
10738
10959
  });
10739
10960
  var scalarConfigSchema = z2.record(z2.string(), z2.unknown()).optional();
@@ -12651,7 +12872,8 @@ var buildIncludeGraph = (pages) => {
12651
12872
  continue;
12652
12873
  }
12653
12874
  for (const partial of page.includes ?? []) {
12654
- const includers = graph[partial] ??= [];
12875
+ const includers = graph[partial] ?? [];
12876
+ graph[partial] = includers;
12655
12877
  if (!includers.includes(sourcePath)) {
12656
12878
  includers.push(sourcePath);
12657
12879
  }
@@ -12773,6 +12995,7 @@ var versionAlternatesFor = (byKey, versionKey, locale) => {
12773
12995
  };
12774
12996
  var MANIFEST_VERSION = 1;
12775
12997
  var contentIndexable = (page, config) => !page.meta.search.exclude && (!page.meta.sidebar.hidden || config.search.indexing.includeHiddenPages);
12998
+ var routeDescription = (page) => page.meta.seo.description ?? page.description;
12776
12999
  var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath, versionAlternatesByKey) => {
12777
13000
  const fallback = resolveFallbackLocale(i18n);
12778
13001
  if (!fallback) {
@@ -12798,6 +13021,7 @@ var buildFallbackRoutes = (graph, i18n, alternatesByKey, basePath, versionAltern
12798
13021
  alternates: alternatesByKey.get(key) ?? [],
12799
13022
  collection: source.collection ?? "docs",
12800
13023
  contentType: source.contentType,
13024
+ description: routeDescription(source),
12801
13025
  draft: source.meta.draft,
12802
13026
  editUrl: source.editUrl,
12803
13027
  entryId: source.entryId ?? source.source.ref,
@@ -12840,6 +13064,7 @@ var buildManifest = (options) => {
12840
13064
  alternates: alternatesByKey.get(page.translationKey) ?? [],
12841
13065
  collection: page.collection ?? "docs",
12842
13066
  contentType: page.contentType,
13067
+ description: routeDescription(page),
12843
13068
  draft: page.meta.draft,
12844
13069
  editUrl: page.editUrl,
12845
13070
  entryId: page.entryId ?? page.source.ref,
@@ -13830,7 +14055,10 @@ var GRAPHQL_MEMBER_PHRASES = {
13830
14055
  subscription: "subscription",
13831
14056
  union: "union type"
13832
14057
  };
13833
- var operationDescription = (spec, operation) => {
14058
+ var operationDescription = (spec, operation, options) => {
14059
+ if (!options.suffix) {
14060
+ return clip(plainProse(operation.description || operation.summary) || options.title, META_DESCRIPTION_MAX);
14061
+ }
13834
14062
  let suffix;
13835
14063
  if (spec.kind === "asyncapi") {
13836
14064
  suffix = `Reference for the ${operation.method} operation on ${operation.path} in the ${apiName(spec)} API.`;
@@ -13863,7 +14091,10 @@ var operationMdx = (spec, operation, reference) => {
13863
14091
  searchFlags.exclude = true;
13864
14092
  }
13865
14093
  const seo = {
13866
- description: operationDescription(spec, operation)
14094
+ description: operationDescription(spec, operation, {
14095
+ suffix: reference?.seoDescriptionSuffix !== false,
14096
+ title
14097
+ })
13867
14098
  };
13868
14099
  if (reference?.noindex) {
13869
14100
  seo.noindex = true;
@@ -16048,7 +16279,7 @@ import { existsSync as existsSync19 } from "node:fs";
16048
16279
  import { mkdir as mkdir8, readdir as readdir4, readFile as readFile20, stat as stat4, writeFile as writeFile7 } from "node:fs/promises";
16049
16280
  import { build } from "astro";
16050
16281
  import { defineCommand as defineCommand3 } from "citty";
16051
- import { dirname as dirname15, join as join33, resolve as resolve12 } from "pathe";
16282
+ import { dirname as dirname16, join as join33, resolve as resolve13 } from "pathe";
16052
16283
 
16053
16284
  // src/deploy/rss.ts
16054
16285
  import { escape as escapeXml } from "html-escaper";
@@ -16632,7 +16863,7 @@ var SERIALIZERS = {
16632
16863
  YouTube: youtube
16633
16864
  };
16634
16865
  var escapeRegExp2 = (value) => value.replaceAll(/[$()*+.?[\\\]^{|}]/gu, String.raw`\$&`);
16635
- var componentHint = (registry2) => new RegExp(`<(?:${Object.keys(registry2).map(escapeRegExp2).join("|")})[\\s/>]`, "u");
16866
+ var componentHint = (registry3) => new RegExp(`<(?:${Object.keys(registry3).map(escapeRegExp2).join("|")})[\\s/>]`, "u");
16636
16867
  var BUILT_IN_HINT = componentHint(SERIALIZERS);
16637
16868
  var componentRegistry = (components) => components && Object.keys(components).length > 0 ? { ...SERIALIZERS, ...components } : SERIALIZERS;
16638
16869
  var renderSlice = (walk, start, end, nodes) => {
@@ -16691,8 +16922,8 @@ var collectSplices = (walk, nodes, out) => {
16691
16922
  }
16692
16923
  };
16693
16924
  var downlevelComponents = (source, components, frontmatter) => {
16694
- const registry2 = componentRegistry(components);
16695
- const hint = registry2 === SERIALIZERS ? BUILT_IN_HINT : componentHint(registry2);
16925
+ const registry3 = componentRegistry(components);
16926
+ const hint = registry3 === SERIALIZERS ? BUILT_IN_HINT : componentHint(registry3);
16696
16927
  if (!hint.test(source)) {
16697
16928
  return source;
16698
16929
  }
@@ -16703,7 +16934,7 @@ var downlevelComponents = (source, components, frontmatter) => {
16703
16934
  return source;
16704
16935
  }
16705
16936
  const splices = [];
16706
- collectSplices({ frontmatter, registry: registry2, source }, tree.children ?? [], splices);
16937
+ collectSplices({ frontmatter, registry: registry3, source }, tree.children ?? [], splices);
16707
16938
  return splices.length > 0 ? applySplices(source, splices) : source;
16708
16939
  };
16709
16940
 
@@ -17836,6 +18067,18 @@ var ACCEPT_MARKDOWN_CONDITION = [
17836
18067
  { key: "accept", type: "header", value: ACCEPT_MARKDOWN_HEADER_VALUE }
17837
18068
  ];
17838
18069
  var VARY_ACCEPT = { vary: "Accept" };
18070
+ var NOT_FOUND_MARKDOWN_DEST = "/404.md";
18071
+ var NOT_FOUND_HTML_DEST = "/404.html";
18072
+ var NOT_FOUND_MARKDOWN_ROUTES = [
18073
+ {
18074
+ dest: NOT_FOUND_MARKDOWN_DEST,
18075
+ has: ACCEPT_MARKDOWN_CONDITION,
18076
+ headers: VARY_ACCEPT,
18077
+ src: "^/.*$",
18078
+ status: 404
18079
+ },
18080
+ { dest: NOT_FOUND_MARKDOWN_DEST, src: "^/.*\\.mdx?$", status: 404 }
18081
+ ];
17839
18082
  var MAX_ALTERNATION_LENGTH = 3900;
17840
18083
  var REGEX_SPECIALS = /[$()*+.?[\]^{|}\\]/gu;
17841
18084
  var routePattern = (route) => encodeURI(route).replace(REGEX_SPECIALS, "\\$&");
@@ -17891,8 +18134,8 @@ var TRAILING_SLASH_REDIRECT = {
17891
18134
  src: "^/(.+)/$",
17892
18135
  status: 308
17893
18136
  };
17894
- 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;
17895
- var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTypeOverrides, homeTokens) => {
18137
+ var isNegotiationRoute = (route) => route.has?.some((condition) => condition.value === ACCEPT_MARKDOWN_HEADER_VALUE) === true || route.dest === NOT_FOUND_MARKDOWN_DEST && route.status === 404 || 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;
18138
+ var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTypeOverrides, homeTokens, notFoundMarkdown = false) => {
17896
18139
  const overrideEntries = Object.entries(contentTypeOverrides ?? {});
17897
18140
  let config;
17898
18141
  try {
@@ -17920,6 +18163,12 @@ var injectNegotiationRoutes = (configText, routePaths, homeLinkHeader, contentTy
17920
18163
  });
17921
18164
  }
17922
18165
  routes.splice(filesystemIndex, 0, ...headerRoutes, ...rewriteRoutes, TRAILING_SLASH_REDIRECT);
18166
+ if (notFoundMarkdown) {
18167
+ const fallbackIndex = routes.findIndex((route) => route.status === 404 && route.dest === NOT_FOUND_HTML_DEST);
18168
+ if (fallbackIndex !== -1) {
18169
+ routes.splice(fallbackIndex, 0, ...NOT_FOUND_MARKDOWN_ROUTES);
18170
+ }
18171
+ }
17923
18172
  config.routes = routes;
17924
18173
  return `${JSON.stringify(config, null, "\t")}
17925
18174
  `;
@@ -18473,12 +18722,12 @@ import { imageSize as imageSize2 } from "image-size";
18473
18722
  import pMap6 from "p-map";
18474
18723
  import {
18475
18724
  basename as basename5,
18476
- dirname as dirname13,
18477
- isAbsolute as isAbsolute11,
18725
+ dirname as dirname14,
18726
+ isAbsolute as isAbsolute13,
18478
18727
  join as join31,
18479
18728
  normalize as normalize4,
18480
- relative as relative17,
18481
- resolve as resolve10
18729
+ relative as relative18,
18730
+ resolve as resolve11
18482
18731
  } from "pathe";
18483
18732
  import { glob as glob7 } from "tinyglobby";
18484
18733
 
@@ -19321,7 +19570,6 @@ var buildReferenceFiles = async (options) => {
19321
19570
  warnings.push(spec.warning);
19322
19571
  }
19323
19572
  const pagePath = referencePagePath(ref.route);
19324
- const depth = pagePath.split("/").length - 1;
19325
19573
  files.push({
19326
19574
  content: scalarReferenceTemplate({
19327
19575
  configuration: {
@@ -19329,7 +19577,6 @@ var buildReferenceFiles = async (options) => {
19329
19577
  ...themeConfiguration(config, ref.theme),
19330
19578
  ...ref.scalar
19331
19579
  },
19332
- dataImport: `${"../".repeat(depth + 1)}generated/data.json`,
19333
19580
  noindex: ref.noindex,
19334
19581
  route: ref.route,
19335
19582
  title: ref.label
@@ -20150,7 +20397,7 @@ ${options.userTheme}
20150
20397
  var examplesEntryTemplate = (options) => `/* Generated by Blume. Do not edit. */
20151
20398
  @import "tailwindcss";
20152
20399
 
20153
- /* Scan the example files and the project sources they import. */
20400
+ /* Scan the project (and an out-of-root examples directory) for utility classes. */
20154
20401
  ${options.sources.map((source) => `@source "${source}";`).join(`
20155
20402
  `)}
20156
20403
 
@@ -20177,6 +20424,20 @@ ${options.configTokens}
20177
20424
  ${options.userCss}
20178
20425
  `;
20179
20426
 
20427
+ // src/theme/sources.ts
20428
+ import { dirname as dirname13, isAbsolute as isAbsolute11, relative as relative16, resolve as resolve10 } from "pathe";
20429
+ var SOURCE_DIRECTIVE = /@source(?<not>\s+not)?\s+(?<quote>["'])(?<path>[^"']+)\k<quote>/gu;
20430
+ var rebaseSourceDirectives = (css, options) => {
20431
+ const base = dirname13(options.from);
20432
+ return css.replace(SOURCE_DIRECTIVE, (directive, not, quote, path) => {
20433
+ if (isAbsolute11(path)) {
20434
+ return directive;
20435
+ }
20436
+ const rebased = relative16(options.to, resolve10(base, path));
20437
+ return `@source${not ?? ""} ${quote}${rebased}${quote}`;
20438
+ });
20439
+ };
20440
+
20180
20441
  // src/theme/twoslash.ts
20181
20442
  import { readFileSync as readFileSync8 } from "node:fs";
20182
20443
  import { createRequire as createRequire3 } from "node:module";
@@ -20362,7 +20623,7 @@ export const layoutOverrides = { ...(overrides.layout ?? {})${layoutEntries.leng
20362
20623
  // src/astro/examples.ts
20363
20624
  import { readFile as readFile18 } from "node:fs/promises";
20364
20625
  import pMap5 from "p-map";
20365
- import { join as join30, relative as relative16 } from "pathe";
20626
+ import { isAbsolute as isAbsolute12, join as join30, relative as relative17 } from "pathe";
20366
20627
  import { glob as glob6 } from "tinyglobby";
20367
20628
 
20368
20629
  // src/astro/islands.ts
@@ -20454,6 +20715,12 @@ var FRAMEWORK_BY_EXT3 = {
20454
20715
  var EXAMPLE_FILE = /\.(?<ext>astro|jsx|svelte|tsx|vue)$/u;
20455
20716
  var DEFAULT_EXAMPLE_GLOB = "**/*.{astro,jsx,svelte,tsx,vue}";
20456
20717
  var READ_CONCURRENCY3 = 16;
20718
+ var EXAMPLE_SCAN_GLOB = "**/*.{astro,jsx,svelte,ts,tsx,vue}";
20719
+ var exampleScanRoots = (root, examplesDir) => {
20720
+ const path = relative17(root, examplesDir);
20721
+ const outside = path.startsWith("..") || isAbsolute12(path);
20722
+ return outside ? [root, examplesDir] : [root];
20723
+ };
20457
20724
  var GLOB_MAGIC = /[!*?[\]{}]/u;
20458
20725
  var splitGlobBase = (pattern) => {
20459
20726
  const segments = pattern.split("/");
@@ -20484,7 +20751,7 @@ var discoverExamples = async (root, pattern = "examples") => {
20484
20751
  if (!(ext && framework)) {
20485
20752
  return;
20486
20753
  }
20487
- const path = relative16(dir, file).slice(0, -(ext.length + 1));
20754
+ const path = relative17(dir, file).slice(0, -(ext.length + 1));
20488
20755
  const existing = seen.get(path);
20489
20756
  if (existing) {
20490
20757
  warnings.push(`Two examples both resolve to "${path}" ("${existing}" and "${file}"); ignoring the second. Give them distinct paths.`);
@@ -20503,7 +20770,7 @@ var discoverExamples = async (root, pattern = "examples") => {
20503
20770
  for (const [index, file] of files.entries()) {
20504
20771
  collectExample(file, sources[index] ?? "");
20505
20772
  }
20506
- return { examples, warnings };
20773
+ return { dir, examples, warnings };
20507
20774
  };
20508
20775
  var exampleMarkdownLookup = (examples) => Object.fromEntries(examples.map((example) => [
20509
20776
  example.path,
@@ -20548,7 +20815,7 @@ var resolvedAstroHit = (fromDir) => {
20548
20815
  if (pkg) {
20549
20816
  return { modulesDir, pkg };
20550
20817
  }
20551
- const parent = dirname13(dir);
20818
+ const parent = dirname14(dir);
20552
20819
  if (parent === dir) {
20553
20820
  return null;
20554
20821
  }
@@ -20564,7 +20831,7 @@ var sameRealDir = (a, b) => {
20564
20831
  };
20565
20832
  var depsCandidates = (pkgDir) => [
20566
20833
  join31(pkgDir, "node_modules"),
20567
- dirname13(pkgDir)
20834
+ dirname14(pkgDir)
20568
20835
  ];
20569
20836
  var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync17(join31(dir, ...segments))) ?? null;
20570
20837
  var linkDepsJunction = async (link, depsDir) => {
@@ -20579,13 +20846,13 @@ var linkDepsJunction = async (link, depsDir) => {
20579
20846
  return;
20580
20847
  }
20581
20848
  try {
20582
- if (resolve10(dirname13(link), await readlink(link)) === resolve10(depsDir)) {
20849
+ if (resolve11(dirname14(link), await readlink(link)) === resolve11(depsDir)) {
20583
20850
  return;
20584
20851
  }
20585
20852
  } catch {}
20586
20853
  await rm2(link, { force: true });
20587
20854
  }
20588
- await mkdir7(dirname13(link), { recursive: true });
20855
+ await mkdir7(dirname14(link), { recursive: true });
20589
20856
  await symlink(depsDir, link, "junction");
20590
20857
  };
20591
20858
  var readPkgVersion = (pkgJsonPath) => {
@@ -20716,6 +20983,10 @@ var readOptional = async (path) => {
20716
20983
  return "";
20717
20984
  }
20718
20985
  };
20986
+ var readUserCss = async (file, outputDir) => {
20987
+ const css = await readOptional(file);
20988
+ return file ? rebaseSourceDirectives(css, { from: file, to: outputDir }) : css;
20989
+ };
20719
20990
  var detectNeedsReact = async (root) => {
20720
20991
  const matches2 = await glob7(["**/*.{tsx,jsx}"], {
20721
20992
  cwd: root,
@@ -20743,7 +21014,7 @@ var loadIntegrationBridge = async (config, context) => {
20743
21014
  return;
20744
21015
  }
20745
21016
  return {
20746
- configFile: relative17(context.outDir, context.configFile),
21017
+ configFile: relative18(context.outDir, context.configFile),
20747
21018
  sourceHash: hashConfigSource(await readOptional(context.configFile))
20748
21019
  };
20749
21020
  };
@@ -20988,10 +21259,10 @@ var buildRuntimeData = (project) => {
20988
21259
  if (!(editBase && sourcePath)) {
20989
21260
  return null;
20990
21261
  }
20991
- const rel = relative17(context.root, sourcePath).split("\\").join("/");
21262
+ const rel = relative18(context.root, sourcePath).split("\\").join("/");
20992
21263
  const editDir = trimChar(github?.dir ?? "", "/");
20993
21264
  const editPath = normalize4(editDir ? join31(editDir, rel) : rel);
20994
- if (editPath.startsWith("..") || isAbsolute11(editPath)) {
21265
+ if (editPath.startsWith("..") || isAbsolute13(editPath)) {
20995
21266
  return null;
20996
21267
  }
20997
21268
  return `${editBase}/${editPath}`;
@@ -21109,6 +21380,7 @@ var buildRuntimeData = (project) => {
21109
21380
  routes: manifest.routes.map((route) => ({
21110
21381
  alternates: route.alternates,
21111
21382
  collection: route.collection,
21383
+ description: route.description ?? null,
21112
21384
  draft: route.draft,
21113
21385
  editUrl: route.editUrl ?? editUrlFor(route.sourcePath),
21114
21386
  entryId: route.entryId,
@@ -21167,11 +21439,12 @@ var planMcp = (project, srcDir, userPages) => {
21167
21439
  enabled: true
21168
21440
  };
21169
21441
  };
21170
- var writeMcpFiles = async (project, plan, write) => {
21442
+ var writeMcpFiles = async (project, plan, write, modules) => {
21171
21443
  if (!plan.enabled) {
21172
21444
  return;
21173
21445
  }
21174
21446
  const data = await buildMcpData(project);
21447
+ modules.set("blume:mcp-data", JSON.stringify(data));
21175
21448
  const discoveryInput = {
21176
21449
  base: data.base,
21177
21450
  name: data.name,
@@ -21180,9 +21453,7 @@ var writeMcpFiles = async (project, plan, write) => {
21180
21453
  version: data.version
21181
21454
  };
21182
21455
  await Promise.all([
21183
- write(join31(plan.srcDir, "generated", "mcp-data.json"), `${JSON.stringify(data)}
21184
- `),
21185
- write(join31(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate(plan.route)),
21456
+ write(join31(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate()),
21186
21457
  write(join31(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
21187
21458
  write(join31(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
21188
21459
  ]);
@@ -21223,15 +21494,14 @@ var proxyAllowlistWarnings = (config, data) => {
21223
21494
  }
21224
21495
  return warnings;
21225
21496
  };
21226
- var writeAskFiles = async (project, srcDir, write) => {
21497
+ var writeAskFiles = async (project, srcDir, write, modules) => {
21227
21498
  const { ask } = project.config.ai;
21228
21499
  if (!(ask?.enabled && !ask.endpoint)) {
21229
21500
  return;
21230
21501
  }
21231
21502
  const grounded = ask.provider !== "inkeep";
21232
21503
  if (grounded) {
21233
- await write(join31(srcDir, "generated", "ask-data.json"), `${JSON.stringify(await buildAskData(project))}
21234
- `);
21504
+ modules.set("blume:ask-data", JSON.stringify(await buildAskData(project)));
21235
21505
  }
21236
21506
  await write(join31(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(resolveAskBackend(ask), grounded, {
21237
21507
  instructions: ask.instructions,
@@ -21242,7 +21512,10 @@ var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
21242
21512
  if (routeIsTaken(pages, contentPages, "/404")) {
21243
21513
  return;
21244
21514
  }
21245
- await write(join31(srcDir, "pages", "404.astro"), notFoundPageTemplate());
21515
+ await Promise.all([
21516
+ write(join31(srcDir, "pages", "404.astro"), notFoundPageTemplate()),
21517
+ write(join31(srcDir, "pages", "404.md.ts"), notFoundMarkdownTemplate())
21518
+ ]);
21246
21519
  };
21247
21520
  var diagnosticWarning = (diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message;
21248
21521
  var buildComponentSlots = async (componentsFile) => {
@@ -21274,18 +21547,18 @@ var generateRuntime = async (project) => {
21274
21547
  assertFontFilesExist(project);
21275
21548
  const out = context.outDir;
21276
21549
  const srcDir = join31(out, "src");
21550
+ const generatedDir = join31(srcDir, "generated");
21277
21551
  const askPath = join31(srcDir, "generated", "Ask.astro");
21278
- const dataPath = join31(srcDir, "generated", "data.json");
21279
21552
  const themePath = join31(srcDir, "generated", "app.css");
21280
21553
  const searchClientPath = join31(srcDir, "generated", "search-client.ts");
21281
21554
  const examplesPath = join31(srcDir, "generated", "examples.ts");
21282
21555
  const examplesThemePath = join31(srcDir, "generated", "examples.css");
21283
- const openapiPath = join31(srcDir, "generated", "openapi.json");
21284
21556
  const written = new Set;
21285
21557
  const write = (path, content) => {
21286
21558
  written.add(normalize4(path));
21287
21559
  return writeIfChanged(path, content);
21288
21560
  };
21561
+ const modules = new Map;
21289
21562
  const depsLinkWarning = await ensureDepsLink(out);
21290
21563
  const askEnabled = config.ai.ask?.enabled ?? false;
21291
21564
  const exportPdf = config.export.pdf;
@@ -21305,8 +21578,8 @@ var generateRuntime = async (project) => {
21305
21578
  context.pagesRoot ? discoverPages(context.pagesRoot) : Promise.resolve([]),
21306
21579
  detectNeedsReact(context.root),
21307
21580
  detectUsesMath(context.root, staged.values()),
21308
- readOptional(context.themeFile),
21309
- readOptional(examplesCssFile(context.root, config)),
21581
+ readUserCss(context.themeFile, generatedDir),
21582
+ readUserCss(examplesCssFile(context.root, config), generatedDir),
21310
21583
  loadIntegrationBridge(config, context),
21311
21584
  discoverIslands(context.root),
21312
21585
  discoverExamples(context.root, config.examples.source),
@@ -21353,14 +21626,12 @@ var generateRuntime = async (project) => {
21353
21626
  contentRoot: docsCollection.base,
21354
21627
  contentRoutes: markdownRoutePaths(project),
21355
21628
  context,
21356
- dataPath,
21357
21629
  examplesPath,
21358
21630
  examplesThemePath,
21359
21631
  integrationBridge,
21360
21632
  needsReact,
21361
21633
  needsSvelte,
21362
21634
  needsVue,
21363
- openapiPath,
21364
21635
  pages,
21365
21636
  reactCompilerPath,
21366
21637
  searchClientPath,
@@ -21388,7 +21659,7 @@ var generateRuntime = async (project) => {
21388
21659
  write(join31(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
21389
21660
  write(examplesThemePath, examplesEntryTemplate({
21390
21661
  configTokens: buildThemeCss(config.theme),
21391
- sources: [`${context.root}/**/*.{astro,jsx,svelte,ts,tsx,vue}`],
21662
+ sources: exampleScanRoots(context.root, exampleDiscovery.dir).map((dir) => `${dir}/${EXAMPLE_SCAN_GLOB}`),
21392
21663
  userCss: userExamplesCss
21393
21664
  })),
21394
21665
  write(themePath, tailwindEntryTemplate({
@@ -21404,12 +21675,15 @@ var generateRuntime = async (project) => {
21404
21675
  Promise.all(islandDiscovery.islands.map((island) => write(join31(srcDir, "generated", "islands", `${island.name}.astro`), islandWrapperTemplate(island)))),
21405
21676
  Promise.all(slotPlan.wrappers.map((wrapper) => write(join31(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
21406
21677
  Promise.all(exampleDiscovery.examples.map((example) => write(join31(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
21407
- writeAskFiles(project, srcDir, write),
21408
- writeMcpFiles(project, mcp, write),
21678
+ writeAskFiles(project, srcDir, write, modules),
21679
+ writeMcpFiles(project, mcp, write, modules),
21409
21680
  playgroundProxy.enabled ? write(playgroundProxy.entrypoint, playgroundProxyTemplate(proxyOrigins)) : Promise.resolve(false)
21410
21681
  ]);
21411
21682
  if (config.seo.og.enabled) {
21412
- await write(join31(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, projectOgFonts(project), changelogIndex));
21683
+ await write(join31(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, {
21684
+ ...projectOgFonts(project),
21685
+ pageDescriptions: config.seo.og.description !== false
21686
+ }, changelogIndex));
21413
21687
  }
21414
21688
  if (changelogIndex) {
21415
21689
  await write(join31(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
@@ -21432,8 +21706,7 @@ var generateRuntime = async (project) => {
21432
21706
  ]);
21433
21707
  if (servesStaticIndex(config.search.provider)) {
21434
21708
  const documents = await buildSearchDocuments(project);
21435
- await write(join31(srcDir, "generated", "search.json"), `${JSON.stringify(documents)}
21436
- `);
21709
+ modules.set("blume:search-index", JSON.stringify(documents));
21437
21710
  await write(join31(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
21438
21711
  }
21439
21712
  if (config.search.provider === "mixedbread") {
@@ -21442,24 +21715,19 @@ var generateRuntime = async (project) => {
21442
21715
  await write(join31(srcDir, "generated", "includes.json"), `${JSON.stringify(buildIncludeGraph(project.graph.pages))}
21443
21716
  `);
21444
21717
  const rawMarkdown = await buildRawMarkdown(project);
21718
+ modules.set("blume:raw-markdown", JSON.stringify(rawMarkdown));
21445
21719
  const contentAssets = await collectContentAssets(project);
21720
+ modules.set("blume:content-assets", JSON.stringify(contentAssets));
21446
21721
  await Promise.all([
21447
- write(join31(srcDir, "generated", "raw-markdown.json"), `${JSON.stringify(rawMarkdown)}
21448
- `),
21449
21722
  write(join31(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
21450
21723
  write(join31(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx")),
21451
- write(join31(srcDir, "generated", "content-assets.json"), `${JSON.stringify(contentAssets)}
21452
- `),
21453
21724
  write(join31(srcDir, "pages", "blume-assets", "[...asset].ts"), contentAssetsEndpointTemplate(join31(project.context.outDir, "public", "blume-assets")))
21454
21725
  ]);
21455
21726
  const feeds = buildRssFeeds(project);
21456
21727
  if (feeds.length > 0) {
21457
21728
  const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
21458
- await Promise.all([
21459
- write(join31(srcDir, "generated", "rss.json"), `${JSON.stringify(feedXml)}
21460
- `),
21461
- write(join31(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate())
21462
- ]);
21729
+ modules.set("blume:rss", JSON.stringify(feedXml));
21730
+ await write(join31(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate());
21463
21731
  }
21464
21732
  const warnings = [
21465
21733
  ...depsLinkWarning ? [depsLinkWarning] : [],
@@ -21497,29 +21765,29 @@ var generateRuntime = async (project) => {
21497
21765
  warnings.push(...references.warnings);
21498
21766
  await Promise.all(references.files.map((file) => write(join31(srcDir, "pages", file.pagePath), file.content)));
21499
21767
  }
21768
+ modules.set("blume:data", buildRuntimeData(project));
21769
+ modules.set("blume:openapi", JSON.stringify(openApiData));
21500
21770
  await Promise.all([
21501
- write(join31(srcDir, "generated", "data.json"), buildRuntimeData(project)),
21502
- write(openapiPath, `${JSON.stringify(openApiData)}
21503
- `),
21504
21771
  write(join31(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
21505
21772
  `),
21506
21773
  writeStagedContent(out, staged)
21507
21774
  ]);
21508
21775
  await pruneOrphans(srcDir, written);
21776
+ publishRuntimeModules(modules);
21509
21777
  return { structuralChange: structural.some(Boolean), warnings };
21510
21778
  };
21511
21779
 
21512
21780
  // src/cli/env.ts
21513
21781
  import { existsSync as existsSync18 } from "node:fs";
21514
21782
  import { config } from "dotenv";
21515
- import { dirname as dirname14, join as join32, resolve as resolve11 } from "pathe";
21783
+ import { dirname as dirname15, join as join32, resolve as resolve12 } from "pathe";
21516
21784
  var loadEnvFiles = (startDir) => {
21517
21785
  const paths = [];
21518
- let dir = resolve11(startDir);
21786
+ let dir = resolve12(startDir);
21519
21787
  let done = false;
21520
21788
  while (!done) {
21521
21789
  paths.push(join32(dir, ".env.local"), join32(dir, ".env"));
21522
- const parent = dirname14(dir);
21790
+ const parent = dirname15(dir);
21523
21791
  done = existsSync18(join32(dir, ".git")) || parent === dir;
21524
21792
  dir = parent;
21525
21793
  }
@@ -21652,7 +21920,7 @@ var collectConfiguredSkills = async (project, distDir) => {
21652
21920
  if (!configured) {
21653
21921
  return [];
21654
21922
  }
21655
- const dir = resolve12(project.context.root, configured);
21923
+ const dir = resolve13(project.context.root, configured);
21656
21924
  if (!existsSync19(dir)) {
21657
21925
  logger.warn(`ai.skills points at "${configured}" (${dir}), which does not exist; no skills published.`);
21658
21926
  return [];
@@ -21676,7 +21944,7 @@ var emitAgentSkills = async (project, distDir, skills) => {
21676
21944
  const outDir = join33(distDir, AGENT_SKILLS_DIR.slice(1));
21677
21945
  await Promise.all(skills.map(async (skill) => {
21678
21946
  const target = join33(outDir, skill.path);
21679
- await mkdir8(dirname15(target), { recursive: true });
21947
+ await mkdir8(dirname16(target), { recursive: true });
21680
21948
  await writeFile7(target, skill.content);
21681
21949
  }));
21682
21950
  await writeFile7(join33(outDir, "index.json"), buildSkillsIndex(skills, project.config), "utf-8");
@@ -21720,7 +21988,8 @@ var emitVercelNegotiation = async (project, routePaths, root) => {
21720
21988
  }
21721
21989
  const rawMarkdown = await buildRawMarkdown(project);
21722
21990
  const home = rawMarkdown["/"];
21723
- const injected = injectNegotiationRoutes(await readFile20(configPath, "utf-8"), routePaths, buildHomeLinkHeader(config2, routePaths), overrides, home ? markdownTokenCount(agentMarkdown(home)) : undefined);
21991
+ const notFoundMarkdown = existsSync19(join33(root, ".vercel", "output", "static", "404.md"));
21992
+ const injected = injectNegotiationRoutes(await readFile20(configPath, "utf-8"), routePaths, buildHomeLinkHeader(config2, routePaths), overrides, home ? markdownTokenCount(agentMarkdown(home)) : undefined, notFoundMarkdown);
21724
21993
  if (injected === null) {
21725
21994
  logger.warn("Could not wire Accept: text/markdown negotiation into .vercel/output/config.json — raw Markdown stays available at the .md URLs.");
21726
21995
  return;
@@ -22264,7 +22533,9 @@ var devCommand = defineCommand5({
22264
22533
  }).on("all", regenerate);
22265
22534
  const disposers = [
22266
22535
  ...project.sources.map((source) => source.watch?.(regenerate)),
22267
- () => void projectWatcher.close()
22536
+ () => {
22537
+ projectWatcher.close();
22538
+ }
22268
22539
  ].filter((dispose) => dispose !== undefined);
22269
22540
  const shutdown = async () => {
22270
22541
  for (const dispose of disposers) {
@@ -22368,12 +22639,12 @@ var doctorCommand = defineCommand6({
22368
22639
 
22369
22640
  // src/cli/commands/eject.ts
22370
22641
  import { defineCommand as defineCommand7 } from "citty";
22371
- import { relative as relative20 } from "pathe";
22642
+ import { relative as relative21 } from "pathe";
22372
22643
 
22373
22644
  // src/registry/eject.ts
22374
22645
  import { existsSync as existsSync21 } from "node:fs";
22375
22646
  import { cp as cp2, mkdir as mkdir9, readFile as readFile21, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
22376
- import { join as join36, relative as relative18 } from "pathe";
22647
+ import { join as join36, relative as relative19 } from "pathe";
22377
22648
  var toPosix = (path) => path.split("\\").join("/");
22378
22649
  var LOCAL_BLUME_SOURCE = "../../node_modules/blume/src/**/*.{astro,ts,tsx}";
22379
22650
  var blumeSourceGlob = (root, genDir, resolveBlumeRoot = packageRoot) => {
@@ -22382,7 +22653,7 @@ var blumeSourceGlob = (root, genDir, resolveBlumeRoot = packageRoot) => {
22382
22653
  }
22383
22654
  try {
22384
22655
  const src = join36(resolveBlumeRoot(), "src");
22385
- return `${toPosix(relative18(genDir, src))}/**/*.{astro,ts,tsx}`;
22656
+ return `${toPosix(relative19(genDir, src))}/**/*.{astro,ts,tsx}`;
22386
22657
  } catch {
22387
22658
  console.warn('blume: could not locate the installed blume package; src/generated/app.css keeps its default `@source "../../node_modules/blume/..."` glob. If blume is hoisted elsewhere, point that glob at its install location or Blume\'s utility classes will be missing.');
22388
22659
  return LOCAL_BLUME_SOURCE;
@@ -22455,7 +22726,7 @@ var mcpFiles = async (project, userPages, srcDir, genDir) => {
22455
22726
  path: join36(genDir, "mcp-data.json")
22456
22727
  },
22457
22728
  {
22458
- content: mcpEndpointTemplate(route),
22729
+ content: mcpEndpointTemplate(),
22459
22730
  path: join36(srcDir, "pages", mcpPageFile(route))
22460
22731
  },
22461
22732
  {
@@ -22481,14 +22752,20 @@ var changelogFiles = (project, userPages, srcDir, options) => {
22481
22752
  }
22482
22753
  ];
22483
22754
  };
22484
- var readExamplesCss = (root, css) => css && existsSync21(join36(root, css)) ? readFile21(join36(root, css), "utf-8") : Promise.resolve("");
22755
+ var readUserCss2 = async (file, genDir) => {
22756
+ if (!(file && existsSync21(file))) {
22757
+ return "";
22758
+ }
22759
+ const css = await readFile21(file, "utf-8");
22760
+ return rebaseSourceDirectives(css, { from: file, to: genDir });
22761
+ };
22485
22762
  var examplesPreviewFiles = (srcDir, basePath, hasExamples) => hasExamples ? [
22486
22763
  {
22487
22764
  content: examplesPageTemplate(),
22488
22765
  path: join36(srcDir, "pages", ...basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro")
22489
22766
  }
22490
22767
  ] : [];
22491
- var ejectIntegrationBridge = (config2, root, configFile) => config2.integrations.length > 0 && configFile ? { configFile: toPosix(relative18(root, configFile)) } : undefined;
22768
+ var ejectIntegrationBridge = (config2, root, configFile) => config2.integrations.length > 0 && configFile ? { configFile: toPosix(relative19(root, configFile)) } : undefined;
22492
22769
  var eject = async (root) => {
22493
22770
  const project = await scanProject(root, { mode: "build" });
22494
22771
  const { context, config: config2 } = project;
@@ -22511,8 +22788,8 @@ var eject = async (root) => {
22511
22788
  context.pagesRoot ? discoverPages(context.pagesRoot) : Promise.resolve([]),
22512
22789
  detectNeedsReact(root),
22513
22790
  detectUsesMath(root),
22514
- context.themeFile ? readFile21(context.themeFile, "utf-8") : Promise.resolve(""),
22515
- readExamplesCss(root, config2.examples.css),
22791
+ readUserCss2(context.themeFile, genDir),
22792
+ readUserCss2(config2.examples.css ? join36(root, config2.examples.css) : null, genDir),
22516
22793
  buildRawMarkdown(project),
22517
22794
  discoverIslands(root)
22518
22795
  ]);
@@ -22525,14 +22802,14 @@ var eject = async (root) => {
22525
22802
  const needsSvelte = frameworks.has("svelte");
22526
22803
  const relContext = {
22527
22804
  ...context,
22528
- contentRoot: toPosix(relative18(root, context.contentRoot)),
22805
+ contentRoot: toPosix(relative19(root, context.contentRoot)),
22529
22806
  outDir: ".",
22530
22807
  root: "."
22531
22808
  };
22532
- const componentsImport = context.componentsFile ? `../../${toPosix(relative18(root, context.componentsFile))}` : null;
22809
+ const componentsImport = context.componentsFile ? `../../${toPosix(relative19(root, context.componentsFile))}` : null;
22533
22810
  const relPages = [
22534
22811
  ...pages.map((page) => ({
22535
- entrypoint: toPosix(relative18(root, page.entrypoint)),
22812
+ entrypoint: toPosix(relative19(root, page.entrypoint)),
22536
22813
  pattern: page.pattern
22537
22814
  })),
22538
22815
  ...mcpDiscoveryPages(project, pages)
@@ -22548,14 +22825,13 @@ var eject = async (root) => {
22548
22825
  contentRoot: relContext.contentRoot,
22549
22826
  contentRoutes: project.manifest.routes.map((route) => route.path),
22550
22827
  context: relContext,
22551
- dataPath: "./src/generated/data.json",
22552
22828
  examplesPath: "./src/generated/examples.ts",
22553
22829
  examplesThemePath: "./src/generated/examples.css",
22830
+ generatedModulesDir: "./src/generated",
22554
22831
  integrationBridge: ejectIntegrationBridge(config2, root, context.configFile),
22555
22832
  needsReact,
22556
22833
  needsSvelte,
22557
22834
  needsVue,
22558
- openapiPath: "./src/generated/openapi.json",
22559
22835
  pages: relPages,
22560
22836
  searchClientPath: "./src/generated/search-client.ts",
22561
22837
  themePath: "./src/generated/app.css"
@@ -22601,7 +22877,7 @@ var eject = async (root) => {
22601
22877
  {
22602
22878
  content: examplesEntryTemplate({
22603
22879
  configTokens: buildThemeCss(config2.theme),
22604
- sources: ["../../**/*.{astro,jsx,svelte,ts,tsx,vue}"],
22880
+ sources: exampleScanRoots(root, examples.dir).map((dir) => `${relative19(genDir, dir)}/${EXAMPLE_SCAN_GLOB}`),
22605
22881
  userCss: userExamplesCss
22606
22882
  }),
22607
22883
  path: join36(genDir, "examples.css")
@@ -22652,7 +22928,7 @@ var eject = async (root) => {
22652
22928
  }
22653
22929
  if (config2.seo.og.enabled) {
22654
22930
  files.push({
22655
- content: ogEndpointTemplate(customOgRoutes(pages, config2.title, config2.seo.og.titles)),
22931
+ content: ogEndpointTemplate(customOgRoutes(pages, config2.title, config2.seo.og.titles), { pageDescriptions: config2.seo.og.description !== false }),
22656
22932
  path: join36(srcDir, "pages", "og", "[...slug].png.ts")
22657
22933
  });
22658
22934
  }
@@ -22792,7 +23068,7 @@ var updatePackageScripts = async (root) => {
22792
23068
  import { existsSync as existsSync22 } from "node:fs";
22793
23069
  import { mkdir as mkdir10, writeFile as writeFile10 } from "node:fs/promises";
22794
23070
  import { detect } from "package-manager-detector/detect";
22795
- import { basename as basename6, dirname as dirname16, isAbsolute as isAbsolute12, join as join38, relative as relative19 } from "pathe";
23071
+ import { basename as basename6, dirname as dirname17, isAbsolute as isAbsolute14, join as join38, relative as relative20 } from "pathe";
22796
23072
 
22797
23073
  // src/core/package-json.ts
22798
23074
  var toPackageName = (raw) => raw.toLowerCase().replaceAll(/[^a-z0-9._-]+/gu, "-").replaceAll(/^[-_.]+|[-_.]+$/gu, "") || "docs";
@@ -22927,7 +23203,7 @@ var detectProjectPackageManager = async (root) => {
22927
23203
  const name = detected?.name;
22928
23204
  return name !== undefined && isPackageManager(name) ? name : detectPackageManager(process.env.npm_config_user_agent);
22929
23205
  };
22930
- var validateContentDir = (root, dir) => isAbsolute12(dir) || relative19(root, join38(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
23206
+ var validateContentDir = (root, dir) => isAbsolute14(dir) || relative20(root, join38(root, dir)).startsWith("..") ? "Must be a relative path inside the project." : undefined;
22931
23207
  var titleize = (raw) => {
22932
23208
  const words = raw.replaceAll(/[-_.]+/gu, " ").split(/\s+/u).filter(Boolean);
22933
23209
  return words.length === 0 ? "My Docs" : words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
@@ -23031,7 +23307,7 @@ var writeFileSafe = async (file, log) => {
23031
23307
  log.info(`Skipped existing ${file.path}`);
23032
23308
  return false;
23033
23309
  }
23034
- await mkdir10(dirname16(file.path), { recursive: true });
23310
+ await mkdir10(dirname17(file.path), { recursive: true });
23035
23311
  await writeFile10(file.path, file.content, "utf-8");
23036
23312
  log.success(`Created ${file.path}`);
23037
23313
  return true;
@@ -23107,7 +23383,7 @@ var ejectCommand = defineCommand7({
23107
23383
  }
23108
23384
  logger.success(`Ejected ${files.length} file(s):`);
23109
23385
  for (const file of files) {
23110
- process.stdout.write(` ${relative20(root, file)}
23386
+ process.stdout.write(` ${relative21(root, file)}
23111
23387
  `);
23112
23388
  }
23113
23389
  reportDroppedArtifacts(notices);
@@ -23195,7 +23471,7 @@ When you are done, print the file and suggest running \`blume eval\` to try it.`
23195
23471
  import { mkdtemp as mkdtemp2, writeFile as writeFile11 } from "node:fs/promises";
23196
23472
  import { tmpdir as tmpdir2 } from "node:os";
23197
23473
  import { colors as colors4 } from "consola/utils";
23198
- import { join as join39, relative as relative21 } from "pathe";
23474
+ import { join as join39, relative as relative22 } from "pathe";
23199
23475
 
23200
23476
  // src/cli/report-format.ts
23201
23477
  var seconds = (ms) => `${(ms / 1000).toFixed(1)}s`;
@@ -23271,15 +23547,15 @@ var summaryLine2 = (result) => {
23271
23547
  var headerLine = (total, agent) => `${colors4.bold("blume eval")} ${total} question(s) · ${AGENTS[agent].name}`;
23272
23548
  var startLine = (id2, index, total) => ` ${colors4.dim(`▸ ${id2} (${index + 1}/${total})`)}`;
23273
23549
  var fixLines = (result, root) => result.diagnostics.filter((diagnostic) => diagnostic.code !== "BLUME_EVAL_ROUTE_UNKNOWN").map((finding2) => {
23274
- const site = finding2.file ? `${relative21(root, finding2.file)}${finding2.line ? `:${finding2.line}` : ""}` : "";
23550
+ const site = finding2.file ? `${relative22(root, finding2.file)}${finding2.line ? `:${finding2.line}` : ""}` : "";
23275
23551
  return ` ${colors4.cyan("fix:")} ${site} ${colors4.dim(finding2.message)}`;
23276
23552
  });
23277
23553
  var warningLines = (result, root) => result.diagnostics.filter((diagnostic) => diagnostic.code === "BLUME_EVAL_ROUTE_UNKNOWN").map((finding2) => {
23278
- const site = finding2.file ? ` ${relative21(root, finding2.file)}${finding2.line ? `:${finding2.line}` : ""}` : "";
23554
+ const site = finding2.file ? ` ${relative22(root, finding2.file)}${finding2.line ? `:${finding2.line}` : ""}` : "";
23279
23555
  return ` ${colors4.yellow("⚠")}${site} ${colors4.dim(finding2.message)}`;
23280
23556
  });
23281
23557
  var evalReportJson = (result, root, threshold) => {
23282
- const diagnostics = result.diagnostics.map((diagnostic) => diagnostic.file ? { ...diagnostic, file: relative21(root, diagnostic.file) } : diagnostic);
23558
+ const diagnostics = result.diagnostics.map((diagnostic) => diagnostic.file ? { ...diagnostic, file: relative22(root, diagnostic.file) } : diagnostic);
23283
23559
  return `${JSON.stringify({
23284
23560
  diagnostics,
23285
23561
  eval: {
@@ -23331,7 +23607,7 @@ var DISALLOWED_TOOLS = [
23331
23607
  "WebSearch",
23332
23608
  "Task"
23333
23609
  ];
23334
- var runAgentHeadless = (bin, args, options) => new Promise((resolve13, reject) => {
23610
+ var runAgentHeadless = (bin, args, options) => new Promise((resolve14, reject) => {
23335
23611
  const child = spawn2(bin, args, {
23336
23612
  cwd: options.cwd,
23337
23613
  stdio: ["pipe", "pipe", "pipe"]
@@ -23358,12 +23634,12 @@ var runAgentHeadless = (bin, args, options) => new Promise((resolve13, reject) =
23358
23634
  });
23359
23635
  child.once("close", (code) => {
23360
23636
  clearTimeout(deadline);
23361
- resolve13({ code: code ?? 1, stderr, stdout, timedOut });
23637
+ resolve14({ code: code ?? 1, stderr, stdout, timedOut });
23362
23638
  });
23363
23639
  child.once("exit", (code) => {
23364
23640
  if (timedOut) {
23365
23641
  clearTimeout(deadline);
23366
- resolve13({ code: code ?? 1, stderr, stdout, timedOut });
23642
+ resolve14({ code: code ?? 1, stderr, stdout, timedOut });
23367
23643
  }
23368
23644
  });
23369
23645
  child.stdin?.end(options.prompt);
@@ -23982,10 +24258,10 @@ var evalCommand = defineCommand8({
23982
24258
  // src/cli/commands/init.ts
23983
24259
  import * as clack from "@clack/prompts";
23984
24260
  import { defineCommand as defineCommand9 } from "citty";
23985
- import { resolve as resolve14 } from "pathe";
24261
+ import { resolve as resolve15 } from "pathe";
23986
24262
 
23987
24263
  // src/cli/init/questions.ts
23988
- import { basename as basename7, resolve as resolve13 } from "pathe";
24264
+ import { basename as basename7, resolve as resolve14 } from "pathe";
23989
24265
  var cancelled = (value) => typeof value === "symbol";
23990
24266
  var collectAnswers = async (prompter, flags, defaults) => {
23991
24267
  const directory = flags.directory ?? await prompter.text({
@@ -23996,7 +24272,7 @@ var collectAnswers = async (prompter, flags, defaults) => {
23996
24272
  if (cancelled(directory)) {
23997
24273
  return null;
23998
24274
  }
23999
- const root = resolve13(defaults.cwd, directory);
24275
+ const root = resolve14(defaults.cwd, directory);
24000
24276
  const title = await prompter.text({
24001
24277
  initialValue: titleize(basename7(root)),
24002
24278
  message: "What's your docs site called?",
@@ -24166,7 +24442,7 @@ var initCommand = defineCommand9({
24166
24442
  title: "My Docs"
24167
24443
  };
24168
24444
  }
24169
- const root = resolve14(cwd, answers.directory);
24445
+ const root = resolve15(cwd, answers.directory);
24170
24446
  if (validateContentDir(root, answers.contentDir) !== undefined) {
24171
24447
  logger.error(`Invalid --content-dir "${answers.contentDir}" (must be a path inside the project).`);
24172
24448
  process.exit(1);
@@ -25004,7 +25280,7 @@ import { join as join47 } from "pathe";
25004
25280
 
25005
25281
  // src/translate/meta.ts
25006
25282
  import { readFile as readFile27 } from "node:fs/promises";
25007
- import { dirname as dirname17, join as join46, relative as relative22 } from "pathe";
25283
+ import { dirname as dirname18, join as join46, relative as relative23 } from "pathe";
25008
25284
  import { glob as glob8 } from "tinyglobby";
25009
25285
  var META_FILES2 = ["**/meta.ts", "**/meta.js", "**/meta.mjs"];
25010
25286
  var isFactoryModule = (value) => typeof value === "function";
@@ -25027,7 +25303,7 @@ var discoverTranslatableMeta = async (project) => {
25027
25303
  onlyFiles: true
25028
25304
  });
25029
25305
  for (const file of files.toSorted()) {
25030
- const dir = relative22(contentRoot2, dirname17(file));
25306
+ const dir = relative23(contentRoot2, dirname18(file));
25031
25307
  const first = dir.split("/")[0]?.toLowerCase();
25032
25308
  if (first && localeDirs.has(first)) {
25033
25309
  continue;
@@ -25056,7 +25332,7 @@ var discoverTranslatableMeta = async (project) => {
25056
25332
  dir: dir === "." ? "" : dir,
25057
25333
  file,
25058
25334
  raw,
25059
- sourceRel: relative22(project.context.root, file),
25335
+ sourceRel: relative23(project.context.root, file),
25060
25336
  title: parsed.data.title
25061
25337
  });
25062
25338
  }
@@ -25370,7 +25646,7 @@ var runTranslate = async (options) => {
25370
25646
  // src/translate/work-list.ts
25371
25647
  import { existsSync as existsSync26 } from "node:fs";
25372
25648
  import { readFile as readFile29 } from "node:fs/promises";
25373
- import { dirname as dirname18, extname as extname9, join as join48, relative as relative23 } from "pathe";
25649
+ import { dirname as dirname19, extname as extname9, join as join48, relative as relative24 } from "pathe";
25374
25650
  var PAGE_EXTENSIONS = new Set([".md", ".mdx"]);
25375
25651
  var translatablePages = (project, i18n) => {
25376
25652
  const rootsByName = new Map(project.sources.flatMap((source) => source.staged || !source.contentRoot ? [] : [[source.name, source.contentRoot]]));
@@ -25421,12 +25697,12 @@ var partialWorkItems = async (universe, project, i18n, ledger, targetLocales, fo
25421
25697
  }
25422
25698
  }
25423
25699
  for (const [partialPath, contentRoot2] of partials) {
25424
- const sourceRel = relative23(root, partialPath);
25700
+ const sourceRel = relative24(root, partialPath);
25425
25701
  work.sources.push(sourceRel);
25426
25702
  const hash = hashSource(await readFile29(partialPath, "utf-8"));
25427
25703
  const ext = extname9(partialPath);
25428
25704
  const verbatim = !PAGE_EXTENSIONS.has(ext.toLowerCase());
25429
- const contentRel = relative23(contentRoot2, partialPath);
25705
+ const contentRel = relative24(contentRoot2, partialPath);
25430
25706
  for (const locale of targetLocales) {
25431
25707
  const targetPath = join48(contentRoot2, localeTargetPath(contentRel, ext, locale, i18n));
25432
25708
  const item = (status) => {
@@ -25437,7 +25713,7 @@ var partialWorkItems = async (universe, project, i18n, ledger, targetLocales, fo
25437
25713
  sourceRel,
25438
25714
  status,
25439
25715
  targetPath,
25440
- targetRel: relative23(root, targetPath)
25716
+ targetRel: relative24(root, targetPath)
25441
25717
  };
25442
25718
  if (verbatim) {
25443
25719
  partialItem.verbatim = true;
@@ -25478,10 +25754,10 @@ var computeWorkList = async (project, ledger, options = {}) => {
25478
25754
  let upToDate = 0;
25479
25755
  const universe = translatablePages(project, i18n);
25480
25756
  for (const { page: page2, contentRoot: contentRoot2, ext, sourcePath } of universe) {
25481
- const sourceRel = relative23(root, sourcePath);
25757
+ const sourceRel = relative24(root, sourcePath);
25482
25758
  knownSources.add(sourceRel);
25483
25759
  const hash = hashSource(await readFile29(sourcePath, "utf-8"));
25484
- const contentRel = relative23(contentRoot2, sourcePath);
25760
+ const contentRel = relative24(contentRoot2, sourcePath);
25485
25761
  for (const locale of targetLocales) {
25486
25762
  const targetPath = join48(contentRoot2, localeTargetPath(contentRel, ext, locale, i18n));
25487
25763
  const item = (status) => ({
@@ -25491,7 +25767,7 @@ var computeWorkList = async (project, ledger, options = {}) => {
25491
25767
  sourceRel,
25492
25768
  status,
25493
25769
  targetPath,
25494
- targetRel: relative23(root, targetPath)
25770
+ targetRel: relative24(root, targetPath)
25495
25771
  });
25496
25772
  const exists = translated.has(`${page2.translationKey}\x00${locale}`);
25497
25773
  const stamp = ledger.files[sourceRel]?.[locale];
@@ -25518,7 +25794,7 @@ var computeWorkList = async (project, ledger, options = {}) => {
25518
25794
  const entries = [];
25519
25795
  for (const source of meta.metas) {
25520
25796
  knownSources.add(source.sourceRel);
25521
- const targetDir = dirname18(metaTargetPath(source, locale));
25797
+ const targetDir = dirname19(metaTargetPath(source, locale));
25522
25798
  const exists = ["meta.ts", "meta.js", "meta.mjs"].some((name) => existsSync26(join48(targetDir, name)));
25523
25799
  const hash = hashSource(source.raw);
25524
25800
  const stamp = ledger.files[source.sourceRel]?.[locale];
@@ -25752,7 +26028,7 @@ import { join as join50 } from "pathe";
25752
26028
 
25753
26029
  // src/core/links.ts
25754
26030
  import { existsSync as existsSync27 } from "node:fs";
25755
- import { basename as basename8, dirname as dirname19, join as join49, relative as relative24, resolve as resolve15 } from "pathe";
26031
+ import { basename as basename8, dirname as dirname20, join as join49, relative as relative25, resolve as resolve16 } from "pathe";
25756
26032
  var HTTP = /^https?:\/\//iu;
25757
26033
  var PROTOCOL_RELATIVE = /^\/\//u;
25758
26034
  var SCHEME = /^[a-z][a-z0-9+.-]*:/iu;
@@ -25767,7 +26043,7 @@ var DOC_EXT = /\.(?:md|mdx)$/iu;
25767
26043
  var FILE_EXT = /\.[a-z0-9]+$/iu;
25768
26044
  var includedBySuffix = (link, page2) => link.file ? ` (included by ${basename8(page2.sourcePath ?? page2.id)})` : "";
25769
26045
  var authoredImageTarget = (target, pagePath, partialPath) => {
25770
- const authored = relative24(dirname19(partialPath), resolve15(dirname19(pagePath), target));
26046
+ const authored = relative25(dirname20(partialPath), resolve16(dirname20(pagePath), target));
25771
26047
  return authored.startsWith(".") ? authored : `./${authored}`;
25772
26048
  };
25773
26049
  var assetIsPresent = (resolved, ctx) => ctx.publicDir !== null && existsSync27(join49(ctx.publicDir, resolved));
@@ -25842,7 +26118,7 @@ var checkPathLink = (resolved, fragment, page2, link, site, ctx, via = "") => {
25842
26118
  return null;
25843
26119
  }
25844
26120
  if (link.image && page2.sourcePath && isRelativeImageTarget(link.target)) {
25845
- if (resolveRelativeImage(dirname19(page2.sourcePath), link.target)) {
26121
+ if (resolveRelativeImage(dirname20(page2.sourcePath), link.target)) {
25846
26122
  return null;
25847
26123
  }
25848
26124
  const authored = link.file ? authoredImageTarget(link.target, page2.sourcePath, link.file) : link.target;
@@ -26055,7 +26331,7 @@ import { defineCommand as defineCommand15 } from "citty";
26055
26331
  // src/core/version-cut.ts
26056
26332
  import { existsSync as existsSync29 } from "node:fs";
26057
26333
  import { cp as cp3, readdir as readdir5, readFile as readFile30, rm as rm5 } from "node:fs/promises";
26058
- import { join as join51, relative as relative25 } from "pathe";
26334
+ import { join as join51, relative as relative26 } from "pathe";
26059
26335
  class CutError extends Error {
26060
26336
  constructor(message) {
26061
26337
  super(message);
@@ -26070,7 +26346,7 @@ var buildRouteRewrites = (project, id2) => {
26070
26346
  const rewrites = new Map;
26071
26347
  for (const page2 of project.graph.pages) {
26072
26348
  const { sourcePath } = page2;
26073
- if (page2.version !== "" || page2.collection === "staged" || !sourcePath || relative25(contentRoot2, sourcePath).startsWith("..")) {
26349
+ if (page2.version !== "" || page2.collection === "staged" || !sourcePath || relative26(contentRoot2, sourcePath).startsWith("..")) {
26074
26350
  continue;
26075
26351
  }
26076
26352
  const logical = versionizeRoute(page2.versionKey, id2);
@@ -26146,13 +26422,12 @@ var insertArchivedVersion = async (configPath, id2) => {
26146
26422
  `, match.index) + 1;
26147
26423
  const indent = text2.slice(lineStart).match(/^\s*/u)?.[0] ?? "";
26148
26424
  const rest = text2.slice(insertAt);
26425
+ const eol = /^\r?\n/u.exec(rest)?.[0];
26149
26426
  let entry;
26150
26427
  if (rest.trimStart().startsWith("]")) {
26151
26428
  entry = `{ id: "${id2}" }`;
26152
- } else if (rest.startsWith(`
26153
- `)) {
26154
- entry = `
26155
- ${indent} { id: "${id2}" },`;
26429
+ } else if (eol) {
26430
+ entry = `${eol}${indent} { id: "${id2}" },`;
26156
26431
  } else {
26157
26432
  entry = `{ id: "${id2}" }, `;
26158
26433
  }
@@ -26215,7 +26490,7 @@ var cutVersion = async (root, id2, options = {}) => {
26215
26490
  const { text: text2, count } = rewriteSnapshotLinks(source, rewrites);
26216
26491
  if (count > 0) {
26217
26492
  await writeTextAtomic(abs, text2);
26218
- rewritten.push({ count, file: relative25(dir, abs) });
26493
+ rewritten.push({ count, file: relative26(dir, abs) });
26219
26494
  }
26220
26495
  }));
26221
26496
  };
@@ -26293,6 +26568,15 @@ var versionCommand = defineCommand15({
26293
26568
  }
26294
26569
  });
26295
26570
 
26571
+ // src/cli/host-args.ts
26572
+ var normalizeHostArgs = (rawArgs) => rawArgs.map((arg, index) => {
26573
+ if (arg !== "--host") {
26574
+ return arg;
26575
+ }
26576
+ const next = rawArgs[index + 1];
26577
+ return next === undefined || next.startsWith("-") ? "--host=" : arg;
26578
+ });
26579
+
26296
26580
  // src/cli/index.ts
26297
26581
  var main = defineCommand16({
26298
26582
  meta: {
@@ -26327,7 +26611,7 @@ process.on("unhandledRejection", (error) => {
26327
26611
  reportInternalError(error);
26328
26612
  process.exit(1);
26329
26613
  });
26330
- runMain(main);
26614
+ runMain(main, { rawArgs: normalizeHostArgs(process.argv.slice(2)) });
26331
26615
 
26332
- //# debugId=6AEF08BD7421838D64756E2164756E21
26616
+ //# debugId=2A8DB3E67F0908D564756E2164756E21
26333
26617
  //# sourceMappingURL=index.js.map