blume 1.5.3 → 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 (209) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/cli/index.js +3949 -1403
  3. package/dist/cli/index.js.map +111 -96
  4. package/dist/types/ai/component-markdown.d.ts +79 -0
  5. package/dist/types/components/layout/nav-utils.d.ts +60 -0
  6. package/dist/types/core/base-path.d.ts +9 -0
  7. package/dist/types/core/config-input.d.ts +206 -4
  8. package/dist/types/core/config.d.ts +6 -4
  9. package/dist/types/core/data.d.ts +33 -2
  10. package/dist/types/core/github.d.ts +35 -0
  11. package/dist/types/core/i18n-ui.d.ts +10 -0
  12. package/dist/types/core/navigation.d.ts +69 -0
  13. package/dist/types/core/schema.d.ts +122 -1
  14. package/dist/types/core/sources/types.d.ts +31 -6
  15. package/dist/types/core/types.d.ts +29 -2
  16. package/dist/types/markdown/features.d.ts +21 -0
  17. package/dist/types/openapi/references.d.ts +26 -1
  18. package/dist/types/seo/jsonld.d.ts +105 -0
  19. package/dist/types/theme/fonts.d.ts +34 -4
  20. package/docs/07-faq.mdx +9 -9
  21. package/docs/_snippets/include-demo.mdx +7 -0
  22. package/docs/advanced/api-reference.mdx +13 -4
  23. package/docs/advanced/custom-pages.mdx +4 -2
  24. package/docs/advanced/graphql.mdx +84 -0
  25. package/docs/advanced/meta.ts +8 -1
  26. package/docs/configuration/ai.mdx +25 -3
  27. package/docs/configuration/index.mdx +24 -0
  28. package/docs/configuration/search.mdx +13 -1
  29. package/docs/configuration/seo.mdx +30 -3
  30. package/docs/configuration/theming.mdx +23 -0
  31. package/docs/content/components.mdx +15 -1
  32. package/docs/content/includes.mdx +68 -0
  33. package/docs/content/meta.ts +1 -0
  34. package/docs/content/navigation.mdx +25 -0
  35. package/docs/content/sources.mdx +42 -1
  36. package/docs/content/syntax.mdx +69 -1
  37. package/docs/content/versioning.mdx +15 -9
  38. package/docs/reference/cli.mdx +2 -1
  39. package/package.json +66 -57
  40. package/skills/blume-migrate/SKILL.md +16 -7
  41. package/skills/blume-migrate/references/docusaurus.md +5 -3
  42. package/skills/blume-migrate/references/fumadocs.md +10 -2
  43. package/skills/blume-migrate/references/mintlify.md +3 -2
  44. package/skills/blume-migrate/references/nextra.md +2 -2
  45. package/skills/blume-migrate/references/starlight.md +1 -1
  46. package/src/ai/agent-readability.ts +2 -1
  47. package/src/ai/ask-data.ts +2 -1
  48. package/src/ai/component-markdown.ts +199 -36
  49. package/src/ai/llms.ts +93 -6
  50. package/src/ai/markdown.ts +2 -2
  51. package/src/ai/mcp/discovery.ts +10 -2
  52. package/src/ai/mcp/server.ts +74 -2
  53. package/src/astro/examples.ts +29 -2
  54. package/src/astro/generate.ts +282 -177
  55. package/src/astro/include-hmr.ts +81 -0
  56. package/src/astro/include-refresh.ts +0 -0
  57. package/src/astro/index.ts +10 -5
  58. package/src/astro/markdown-negotiation.ts +1 -1
  59. package/src/astro/runtime-modules.ts +196 -0
  60. package/src/astro/templates.ts +365 -113
  61. package/src/cli/commands/build.ts +91 -16
  62. package/src/cli/commands/dev.ts +6 -3
  63. package/src/cli/host-args.ts +18 -0
  64. package/src/cli/index.ts +2 -1
  65. package/src/cli/init/questions.ts +1 -0
  66. package/src/cli/init/scaffold.ts +27 -4
  67. package/src/components/colors.ts +142 -0
  68. package/src/components/content/Badge.astro +5 -12
  69. package/src/components/content/Callout.astro +19 -36
  70. package/src/components/content/Card.astro +15 -21
  71. package/src/components/content/Component.astro +10 -1
  72. package/src/components/content/GithubInfo.astro +28 -9
  73. package/src/components/content/Tabs.astro +27 -5
  74. package/src/components/content/github-info.ts +20 -5
  75. package/src/components/copy-feedback.ts +93 -9
  76. package/src/components/dropdown-dismiss.ts +122 -0
  77. package/src/components/islands/ask-ai.tsx +4 -1
  78. package/src/components/islands/hooks.ts +3 -1
  79. package/src/components/layout/Fonts.astro +15 -8
  80. package/src/components/layout/Header.astro +44 -0
  81. package/src/components/layout/LanguageSwitcher.astro +9 -1
  82. package/src/components/layout/NavSelector.astro +12 -3
  83. package/src/components/layout/NavTree.astro +6 -18
  84. package/src/components/layout/PageActions.astro +54 -22
  85. package/src/components/layout/PageLayout.astro +2 -0
  86. package/src/components/layout/ReferenceLayout.astro +6 -1
  87. package/src/components/layout/RootLayout.astro +42 -15
  88. package/src/components/layout/Search.astro +36 -4
  89. package/src/components/layout/TableOfContents.astro +8 -2
  90. package/src/components/layout/head-scripts.ts +30 -1
  91. package/src/components/openapi/ApiOverview.astro +13 -3
  92. package/src/components/openapi/AsyncApiOperation.astro +7 -14
  93. package/src/components/openapi/GraphqlChip.astro +33 -0
  94. package/src/components/openapi/GraphqlFieldsTable.astro +111 -0
  95. package/src/components/openapi/GraphqlOperation.astro +186 -0
  96. package/src/components/openapi/GraphqlType.astro +154 -0
  97. package/src/components/openapi/MethodBadge.astro +3 -14
  98. package/src/components/openapi/Operation.astro +12 -5
  99. package/src/components/openapi/OperationPanel.astro +43 -0
  100. package/src/components/openapi/RequestPanel.astro +5 -10
  101. package/src/components/openapi/Responses.astro +1 -16
  102. package/src/components/openapi/graphql-helpers.ts +466 -0
  103. package/src/components/openapi/playground-client.ts +15 -0
  104. package/src/components/openapi/sample-panels.ts +45 -0
  105. package/src/components/openapi/snippets.ts +13 -35
  106. package/src/core/base-path.ts +11 -0
  107. package/src/core/config-input.ts +209 -2
  108. package/src/core/config.ts +6 -4
  109. package/src/core/content-assets.ts +15 -4
  110. package/src/core/data.ts +28 -3
  111. package/src/core/define-components.ts +2 -0
  112. package/src/core/diagnostics.ts +8 -0
  113. package/src/core/frontmatter.ts +20 -8
  114. package/src/core/github.ts +71 -0
  115. package/src/core/graph.ts +22 -8
  116. package/src/core/heading-markers.ts +96 -0
  117. package/src/core/i18n-ui.ts +12 -0
  118. package/src/core/includes.ts +633 -0
  119. package/src/core/last-modified.ts +36 -11
  120. package/src/core/links.ts +79 -13
  121. package/src/core/manifest.ts +10 -0
  122. package/src/core/meta.ts +2 -1
  123. package/src/core/nav-diagnostics.ts +11 -2
  124. package/src/core/navigation.ts +27 -6
  125. package/src/core/project-graph.ts +61 -9
  126. package/src/core/schema.ts +235 -36
  127. package/src/core/server-features.ts +5 -9
  128. package/src/core/sources/github-releases.ts +2 -2
  129. package/src/core/sources/normalize.ts +502 -115
  130. package/src/core/sources/notion.ts +43 -8
  131. package/src/core/sources/obsidian.ts +1038 -0
  132. package/src/core/sources/read.ts +36 -1
  133. package/src/core/sources/resolve.ts +34 -1
  134. package/src/core/sources/types.ts +28 -6
  135. package/src/core/sources/watch.ts +12 -8
  136. package/src/core/tsconfig-aliases.ts +48 -35
  137. package/src/core/types.ts +31 -2
  138. package/src/core/ui-packs/ar.ts +2 -0
  139. package/src/core/ui-packs/bg.ts +3 -0
  140. package/src/core/ui-packs/bn.ts +2 -0
  141. package/src/core/ui-packs/ca.ts +3 -0
  142. package/src/core/ui-packs/cs.ts +2 -0
  143. package/src/core/ui-packs/da.ts +2 -0
  144. package/src/core/ui-packs/de.ts +3 -0
  145. package/src/core/ui-packs/el.ts +3 -0
  146. package/src/core/ui-packs/es.ts +3 -0
  147. package/src/core/ui-packs/fa.ts +2 -0
  148. package/src/core/ui-packs/fi.ts +2 -0
  149. package/src/core/ui-packs/fr.ts +3 -0
  150. package/src/core/ui-packs/he.ts +2 -0
  151. package/src/core/ui-packs/hi.ts +2 -0
  152. package/src/core/ui-packs/hr.ts +3 -0
  153. package/src/core/ui-packs/hu.ts +3 -0
  154. package/src/core/ui-packs/id.ts +3 -0
  155. package/src/core/ui-packs/it.ts +2 -0
  156. package/src/core/ui-packs/ja.ts +3 -0
  157. package/src/core/ui-packs/ko.ts +3 -0
  158. package/src/core/ui-packs/nl.ts +3 -0
  159. package/src/core/ui-packs/no.ts +3 -0
  160. package/src/core/ui-packs/pl.ts +3 -0
  161. package/src/core/ui-packs/pt-br.ts +3 -0
  162. package/src/core/ui-packs/pt.ts +3 -0
  163. package/src/core/ui-packs/ro.ts +3 -0
  164. package/src/core/ui-packs/ru.ts +3 -0
  165. package/src/core/ui-packs/sk.ts +2 -0
  166. package/src/core/ui-packs/sr.ts +2 -0
  167. package/src/core/ui-packs/sv.ts +3 -0
  168. package/src/core/ui-packs/th.ts +2 -0
  169. package/src/core/ui-packs/tr.ts +3 -0
  170. package/src/core/ui-packs/uk.ts +3 -0
  171. package/src/core/ui-packs/vi.ts +2 -0
  172. package/src/core/ui-packs/zh-tw.ts +2 -0
  173. package/src/core/ui-packs/zh.ts +2 -0
  174. package/src/core/version-cut.ts +26 -6
  175. package/src/core/yaml.ts +26 -0
  176. package/src/deploy/function-bundle.ts +251 -0
  177. package/src/deploy/vercel-negotiation.ts +49 -6
  178. package/src/eval/schema.ts +3 -1
  179. package/src/markdown/code-title.ts +22 -16
  180. package/src/markdown/features.ts +21 -0
  181. package/src/markdown/fence-meta.ts +50 -0
  182. package/src/markdown/heading-anchors.ts +198 -37
  183. package/src/markdown/include.ts +247 -0
  184. package/src/markdown/index.ts +43 -34
  185. package/src/markdown/language-icon.ts +2 -2
  186. package/src/markdown/mdast.ts +7 -3
  187. package/src/markdown/ts2js.ts +264 -0
  188. package/src/og/card.ts +1 -1
  189. package/src/openapi/asyncapi.ts +4 -1
  190. package/src/openapi/graphql-build.ts +293 -0
  191. package/src/openapi/graphql.ts +212 -0
  192. package/src/openapi/model.ts +38 -5
  193. package/src/openapi/parse.ts +34 -0
  194. package/src/openapi/proxy.ts +30 -5
  195. package/src/openapi/references.ts +97 -13
  196. package/src/openapi/render-mdx.ts +66 -12
  197. package/src/openapi/scalar.ts +5 -16
  198. package/src/openapi/source.ts +91 -23
  199. package/src/registry/eject.ts +47 -17
  200. package/src/search/documents.ts +229 -37
  201. package/src/search/orama-index.ts +9 -5
  202. package/src/seo/jsonld.ts +293 -51
  203. package/src/theme/code-block-padding.ts +16 -0
  204. package/src/theme/entry.ts +67 -13
  205. package/src/theme/fonts.ts +189 -16
  206. package/src/theme/sources.ts +49 -0
  207. package/src/translate/prompts.ts +2 -0
  208. package/src/translate/run.ts +7 -0
  209. package/src/translate/work-list.ts +0 -0
@@ -0,0 +1,81 @@
1
+ import { readFile, utimes } from "node:fs/promises";
2
+
3
+ /**
4
+ * Dev-server invalidation for `<include>` partials. A partial is not an Astro
5
+ * content-collection entry (the default underscore-prefix exclude keeps it
6
+ * out of the `docs` glob), so Vite has no edge from an including page to it —
7
+ * editing the partial would keep serving the page's stale compiled module.
8
+ * The scan records each page's transitive includes; `generateRuntime` writes
9
+ * them to `generated/includes.json` as partial → including pages, and this
10
+ * plugin turns a partial edit into an invalidation of those page modules plus
11
+ * a full reload.
12
+ *
13
+ * The graph file is re-read on every hot update: `blume dev`'s regenerate
14
+ * loop rewrites it after each content change, so the mapping tracks include
15
+ * edits without restarting the server.
16
+ */
17
+
18
+ /** The Vite module-graph slice the plugin touches (structurally typed, like
19
+ * every Blume-authored Vite plugin — see `serverAppResolvePlugin`). */
20
+ interface IncludeHmrServer {
21
+ moduleGraph: {
22
+ getModulesByFile: (file: string) => Set<unknown> | undefined;
23
+ invalidateModule: (mod: never) => void;
24
+ };
25
+ ws: { send: (payload: { type: "full-reload" }) => void };
26
+ }
27
+
28
+ export interface IncludeHmrContext {
29
+ file: string;
30
+ server: IncludeHmrServer;
31
+ }
32
+
33
+ export interface IncludeHmrPlugin {
34
+ name: string;
35
+ handleHotUpdate: (ctx: IncludeHmrContext) => Promise<never[] | undefined>;
36
+ }
37
+
38
+ export const includeHmrPlugin = (graphPath: string): IncludeHmrPlugin => ({
39
+ async handleHotUpdate(ctx) {
40
+ let graph: Record<string, string[]>;
41
+ try {
42
+ // SAFETY: `generateRuntime` is the file's only writer and serializes
43
+ // exactly this shape; a malformed hand-edit throws into the catch below.
44
+ graph = JSON.parse(await readFile(graphPath, "utf-8")) as Record<
45
+ string,
46
+ string[]
47
+ >;
48
+ } catch {
49
+ // No graph yet (first run) — nothing to invalidate.
50
+ return;
51
+ }
52
+ const includers = graph[ctx.file];
53
+ if (!includers || includers.length === 0) {
54
+ return;
55
+ }
56
+ const { moduleGraph, ws } = ctx.server;
57
+ const now = new Date();
58
+ for (const includer of includers) {
59
+ for (const mod of moduleGraph.getModulesByFile(includer) ?? []) {
60
+ // SAFETY: the module came out of this module graph; `never` only
61
+ // reflects that the structural slice doesn't model the node type.
62
+ moduleGraph.invalidateModule(mod as never);
63
+ }
64
+ // Plain `.md` pages have no Vite module: their HTML lives in the
65
+ // content-layer store, rendered at sync time. Bump the page's mtime so
66
+ // Astro's content watcher re-syncs it — the include-aware digest
67
+ // (`withIncludeRefresh`) then forces a fresh render that re-reads the
68
+ // edited partial.
69
+ try {
70
+ // oxlint-disable-next-line no-await-in-loop -- ordered per-page touch
71
+ await utimes(includer, now, now);
72
+ } catch {
73
+ // The page may have been deleted since the graph was written.
74
+ }
75
+ }
76
+ ws.send({ type: "full-reload" });
77
+ // The partial itself is not a module; suppress Vite's default handling.
78
+ return [];
79
+ },
80
+ name: "blume:include-hmr",
81
+ });
Binary file
@@ -1,9 +1,14 @@
1
1
  export { withAdapterRoot } from "./adapter-root.ts";
2
- export {
3
- generateRuntime,
4
- prerenderDepsPlugin,
5
- serverAppResolvePlugin,
6
- } from "./generate.ts";
2
+ export { generateRuntime, prerenderDepsPlugin } from "./generate.ts";
3
+ export { includeHmrPlugin } from "./include-hmr.ts";
4
+ export { withIncludeRefresh } from "./include-refresh.ts";
7
5
  export type { GenerateResult } from "./generate.ts";
8
6
  export { blumeIntegration } from "./integration.ts";
9
7
  export type { BlumeIntegrationOptions, BlumePageRoute } from "./integration.ts";
8
+ export {
9
+ publishRuntimeModules,
10
+ readRuntimeModule,
11
+ RUNTIME_MODULE_FILES,
12
+ runtimeModulesPlugin,
13
+ } from "./runtime-modules.ts";
14
+ export type { RuntimeModuleId } from "./runtime-modules.ts";
@@ -29,7 +29,7 @@ const parseAccept = (accept: string): AcceptEntry[] =>
29
29
 
30
30
  /**
31
31
  * Whether the client explicitly prefers Markdown over HTML. Browsers never send
32
- * `text/markdown`, so an ordinary page request (`text/html`, `*​/*`) is false.
32
+ * `text/markdown`, so an ordinary page request (`text/html` or the catch-all wildcard) is false.
33
33
  */
34
34
  export const prefersMarkdown = (accept: string | null | undefined): boolean => {
35
35
  if (!accept) {
@@ -0,0 +1,196 @@
1
+ /**
2
+ * In-memory runtime data modules.
3
+ *
4
+ * The generated runtime's data snapshots — the page data behind `blume:data`,
5
+ * the parsed API specs, the static search index, the raw-Markdown and
6
+ * content-asset maps, the MCP and Ask corpora, and the rendered RSS feeds —
7
+ * used to be written under `.blume/src/generated/*.json` and imported by the
8
+ * generated pages through aliases or relative paths. `generateRuntime` now
9
+ * publishes them here and `runtimeModulesPlugin` serves them to Vite as
10
+ * virtual modules, so a regeneration never round-trips the disk or waits on a
11
+ * file watcher: publishing invalidates the changed modules in every live dev
12
+ * server (Vite walks the importers, so the pages that render them re-evaluate
13
+ * on the next request) and asks the browser to reload — the same effect a JSON
14
+ * file change used to reach through the watcher, minus the write and the
15
+ * watch debounce.
16
+ *
17
+ * The registry hangs off `globalThis`, not module state. On a published
18
+ * install the CLI bundle (`dist/cli`) carries its own copy of this module,
19
+ * separate from the one Vite loads from `blume/astro` for the generated
20
+ * config, and both must see the same map. `blume dev`, `blume build`, and
21
+ * `blume check` all run Astro in-process, so the map the CLI fills is the map
22
+ * the plugin reads.
23
+ *
24
+ * `blume eject` keeps the file form: the ejected project has no CLI to
25
+ * publish, so its `astro.config.mjs` aliases each id to the JSON file eject
26
+ * writes under `src/generated/` — the names in {@link RUNTIME_MODULE_FILES}.
27
+ */
28
+
29
+ export type RuntimeModuleId =
30
+ | "blume:ask-data"
31
+ | "blume:content-assets"
32
+ | "blume:data"
33
+ | "blume:mcp-data"
34
+ | "blume:openapi"
35
+ | "blume:raw-markdown"
36
+ | "blume:rss"
37
+ | "blume:search-index";
38
+
39
+ /** Virtual module id → the `src/generated` JSON file eject writes for it. */
40
+ export const RUNTIME_MODULE_FILES: ReadonlyMap<RuntimeModuleId, string> =
41
+ new Map([
42
+ ["blume:ask-data", "ask-data.json"],
43
+ ["blume:content-assets", "content-assets.json"],
44
+ ["blume:data", "data.json"],
45
+ ["blume:mcp-data", "mcp-data.json"],
46
+ ["blume:openapi", "openapi.json"],
47
+ ["blume:raw-markdown", "raw-markdown.json"],
48
+ ["blume:rss", "rss.json"],
49
+ ["blume:search-index", "search.json"],
50
+ ]);
51
+
52
+ const RUNTIME_MODULE_IDS: ReadonlySet<string> = new Set(
53
+ RUNTIME_MODULE_FILES.keys()
54
+ );
55
+
56
+ /** Rollup's virtual-module convention: `\0` keeps other plugins off the id. */
57
+ const RESOLVED_PREFIX = "\0";
58
+
59
+ /** A node in Vite's module graph; only its identity matters here. */
60
+ interface RuntimeModuleNode {
61
+ id: string | null;
62
+ }
63
+
64
+ /**
65
+ * The Vite dev-server slice the registry touches (structurally typed, like
66
+ * every Blume-authored Vite plugin — see `includeHmrPlugin`).
67
+ */
68
+ export interface RuntimeModuleServer {
69
+ httpServer?: {
70
+ once: (event: "close", listener: () => void) => void;
71
+ } | null;
72
+ moduleGraph: {
73
+ getModuleById: (id: string) => RuntimeModuleNode | undefined;
74
+ invalidateModule: (mod: RuntimeModuleNode) => void;
75
+ };
76
+ ws: { send: (payload: { type: "full-reload" }) => void };
77
+ }
78
+
79
+ interface RuntimeModuleRegistry {
80
+ /** Published JSON text by module id. */
81
+ modules: Map<string, string>;
82
+ /** Live dev servers to invalidate on publish. */
83
+ servers: Set<RuntimeModuleServer>;
84
+ }
85
+
86
+ const REGISTRY_KEY = Symbol.for("blume.runtime-modules");
87
+
88
+ type RegistryHost = typeof globalThis & {
89
+ [REGISTRY_KEY]?: RuntimeModuleRegistry;
90
+ };
91
+
92
+ const registry = (): RuntimeModuleRegistry => {
93
+ // SAFETY: the registry is stashed on globalThis under a well-known symbol so
94
+ // every copy of this module in the process shares it; the intersection only
95
+ // names that slot.
96
+ const host = globalThis as RegistryHost;
97
+ host[REGISTRY_KEY] ??= { modules: new Map(), servers: new Set() };
98
+ return host[REGISTRY_KEY];
99
+ };
100
+
101
+ /** The published JSON text for a module, if any (tests and diagnostics). */
102
+ export const readRuntimeModule = (id: RuntimeModuleId): string | undefined =>
103
+ registry().modules.get(id);
104
+
105
+ /**
106
+ * Replace the published snapshot set with `modules` (an id absent from the map
107
+ * is unpublished — its feature was switched off). Returns the ids whose text
108
+ * changed; each is invalidated in every live dev server, followed by one
109
+ * full-reload per server. Nothing is sent when nothing changed, so a
110
+ * regeneration triggered by an unrelated edit stays quiet — the same contract
111
+ * `writeIfChanged` gave the file form.
112
+ */
113
+ export const publishRuntimeModules = (
114
+ modules: ReadonlyMap<RuntimeModuleId, string>
115
+ ): RuntimeModuleId[] => {
116
+ const { modules: current, servers } = registry();
117
+ const changed: RuntimeModuleId[] = [];
118
+ for (const id of RUNTIME_MODULE_FILES.keys()) {
119
+ const next = modules.get(id);
120
+ if (current.get(id) === next) {
121
+ continue;
122
+ }
123
+ if (next === undefined) {
124
+ current.delete(id);
125
+ } else {
126
+ current.set(id, next);
127
+ }
128
+ changed.push(id);
129
+ }
130
+ if (changed.length === 0) {
131
+ return changed;
132
+ }
133
+ for (const server of servers) {
134
+ for (const id of changed) {
135
+ const mod = server.moduleGraph.getModuleById(`${RESOLVED_PREFIX}${id}`);
136
+ if (mod) {
137
+ server.moduleGraph.invalidateModule(mod);
138
+ }
139
+ }
140
+ server.ws.send({ type: "full-reload" });
141
+ }
142
+ return changed;
143
+ };
144
+
145
+ export interface RuntimeModulesPlugin {
146
+ configureServer: (server: RuntimeModuleServer) => void;
147
+ enforce: "pre";
148
+ load: (id: string) => string | undefined;
149
+ name: string;
150
+ resolveId: (id: string) => string | undefined;
151
+ }
152
+
153
+ /**
154
+ * Serve the published runtime modules to Vite. `enforce: "pre"` claims the
155
+ * `blume:*` ids before Vite's resolver would try (and fail) to find them as
156
+ * packages. Loading an unpublished id is a hard error rather than an empty
157
+ * module: the generated pages only import a module when its data exists, so a
158
+ * miss means the config was run outside the CLI that publishes.
159
+ */
160
+ export const runtimeModulesPlugin = (): RuntimeModulesPlugin => ({
161
+ configureServer(server) {
162
+ const { servers } = registry();
163
+ servers.add(server);
164
+ // Astro restarts the dev container in place on a config change (and the
165
+ // CLI restarts it on a route-set change): the old Vite server closes and
166
+ // a new one registers, so drop the stale handle rather than invalidating
167
+ // into a dead graph.
168
+ server.httpServer?.once("close", () => {
169
+ servers.delete(server);
170
+ });
171
+ },
172
+ enforce: "pre",
173
+ load(id) {
174
+ if (!id.startsWith(RESOLVED_PREFIX)) {
175
+ return;
176
+ }
177
+ const moduleId = id.slice(RESOLVED_PREFIX.length);
178
+ if (!RUNTIME_MODULE_IDS.has(moduleId)) {
179
+ return;
180
+ }
181
+ const text = registry().modules.get(moduleId);
182
+ if (text === undefined) {
183
+ throw new Error(
184
+ `Blume runtime module "${moduleId}" was requested before it was published. Run the generated project through the Blume CLI (blume dev / blume build), which publishes the runtime data before starting Astro.`
185
+ );
186
+ }
187
+ // A JSON.parse over a string literal evaluates faster than an equivalent
188
+ // object literal for large snapshots (V8's guidance; Vite's own JSON
189
+ // plugin does the same past a size threshold).
190
+ return `export default JSON.parse(${JSON.stringify(text)});\n`;
191
+ },
192
+ name: "blume:runtime-modules",
193
+ resolveId(id) {
194
+ return RUNTIME_MODULE_IDS.has(id) ? `${RESOLVED_PREFIX}${id}` : undefined;
195
+ },
196
+ });