blume 1.0.1 → 1.0.3

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.
@@ -83,7 +83,17 @@ export const surfaceAdapterOutput = async (
83
83
  }
84
84
  await mkdir(dirname(to), { recursive: true });
85
85
  await rm(to, { force: true, recursive: true });
86
- await cp(from, to, { recursive: true });
86
+ // `verbatimSymlinks` keeps each symlink's target text as written. Without it,
87
+ // `cp` resolves every relative target against the *source*, rewriting it to an
88
+ // absolute path under `.blume` — which this function then deletes. Adapters
89
+ // that trace dependencies into their function bundle link one package to
90
+ // another that way (under an isolated linker — Bun's `isolated` mode, pnpm —
91
+ // that is every external dependency the function imports), so the resolved
92
+ // links leave the deployed function dying on its first external import with
93
+ // ERR_MODULE_NOT_FOUND. Verbatim, the links stay relative and internal to the
94
+ // bundle, surviving both this move and the platform's own (Vercel mounts the
95
+ // bundle at `/var/task`).
96
+ await cp(from, to, { recursive: true, verbatimSymlinks: true });
87
97
  await rm(from, { force: true, recursive: true });
88
98
  // The `.gitignore` entry is the surfaced top-level dir (`.vercel`/`.netlify`),
89
99
  // never the moved sub-path — the platform's own state (`.vercel/project.json`,
@@ -1,5 +1,6 @@
1
1
  import { withBasePath } from "../core/base-path.ts";
2
2
  import type { ResolvedConfig } from "../core/schema.ts";
3
+ import { trimChar, trimEnd } from "../core/trim.ts";
3
4
  import type { NavTab } from "../core/types.ts";
4
5
 
5
6
  /**
@@ -52,24 +53,21 @@ export interface ReferenceSource {
52
53
  }
53
54
 
54
55
  const NON_SLUG = /[^a-z0-9]+/gu;
55
- const SLUG_EDGES = /^-+|-+$/gu;
56
- const ROUTE_EDGES = /^\/+|\/+$/gu;
57
- const TRAILING_SLASH = /\/+$/u;
58
56
 
59
57
  export const slugify = (text: string): string =>
60
- text.toLowerCase().replace(NON_SLUG, "-").replace(SLUG_EDGES, "");
58
+ trimChar(text.toLowerCase().replace(NON_SLUG, "-"), "-");
61
59
 
62
60
  /** Normalize a configured route to a single leading slash, no trailing slash. */
63
61
  export const normalizeRoute = (route: string): string => {
64
62
  const trimmed = route.trim();
65
63
  const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
66
- const noTrailing = withSlash.replace(TRAILING_SLASH, "");
64
+ const noTrailing = trimEnd(withSlash, "/");
67
65
  return noTrailing === "" ? "/" : noTrailing;
68
66
  };
69
67
 
70
68
  /** A stable per-reference token from its route: `/api/events` -> `api-events`. */
71
69
  const routeSlug = (route: string): string =>
72
- slugify(route.replace(ROUTE_EDGES, "")) || "reference";
70
+ slugify(trimChar(route, "/")) || "reference";
73
71
 
74
72
  type Block = ResolvedConfig["openapi"] | ResolvedConfig["asyncapi"];
75
73
 
@@ -20,6 +20,7 @@ import { discoverIslands } from "../astro/islands.ts";
20
20
  import { customOgRoutes, discoverPages, routeIsTaken } from "../astro/pages.ts";
21
21
  import {
22
22
  askEndpointTemplate,
23
+ askComponentTemplate,
23
24
  astroConfigTemplate,
24
25
  catchAllPageTemplate,
25
26
  changelogIndexTemplate,
@@ -135,8 +136,8 @@ const hostsMcp = (
135
136
  project: BlumeProject,
136
137
  userPages: { pattern: string }[]
137
138
  ): boolean =>
138
- project.config.mcp.enabled &&
139
- !routeIsTaken(userPages, project.graph.pages, project.config.mcp.route);
139
+ project.config.ai.mcp.enabled &&
140
+ !routeIsTaken(userPages, project.graph.pages, project.config.ai.mcp.route);
140
141
 
141
142
  /**
142
143
  * The `.well-known` MCP discovery routes, injected as prerendered pages
@@ -174,7 +175,7 @@ const mcpFiles = async (
174
175
  if (!hostsMcp(project, userPages)) {
175
176
  return [];
176
177
  }
177
- const { route } = project.config.mcp;
178
+ const { route } = project.config.ai.mcp;
178
179
  const data = await buildMcpData(project);
179
180
  const discoveryInput = {
180
181
  base: data.base,
@@ -356,6 +357,7 @@ export const eject = async (
356
357
  }[] = [
357
358
  {
358
359
  content: astroConfigTemplate({
360
+ askPath: "./src/generated/Ask.astro",
359
361
  config,
360
362
  contentRoutes: project.manifest.routes.map((route) => route.path),
361
363
  context: relContext,
@@ -390,7 +392,6 @@ export const eject = async (
390
392
  },
391
393
  {
392
394
  content: catchAllPageTemplate({
393
- askEnabled,
394
395
  exportEpub,
395
396
  exportPdf,
396
397
  mathEnabled: usesMath,
@@ -441,6 +442,12 @@ export const eject = async (
441
442
  path: join(genDir, "app.css"),
442
443
  },
443
444
  { content: buildRuntimeData(project), path: join(genDir, "data.json") },
445
+ // The header's Ask trigger behind the `blume:ask` alias. Always written — it
446
+ // renders nothing when Ask is off — so the alias always resolves.
447
+ {
448
+ content: askComponentTemplate(askEnabled),
449
+ path: join(genDir, "Ask.astro"),
450
+ },
444
451
  {
445
452
  content: `${JSON.stringify(ejectOpenApiData(project))}\n`,
446
453
  path: join(genDir, "openapi.json"),
@@ -475,7 +482,6 @@ export const eject = async (
475
482
  files.push(
476
483
  ...(await mcpFiles(project, pages, srcDir, genDir)),
477
484
  ...changelogFiles(project, pages, srcDir, {
478
- askEnabled,
479
485
  exportEpub,
480
486
  exportPdf,
481
487
  needsReact,