@animus-ui/vite-plugin 0.1.8 → 0.1.11

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.
@@ -1 +1 @@
1
- {"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,GAC3D,OAAO,CAAC,IAAI,CAAC,CA2Rf"}
1
+ {"version":3,"file":"build-start.d.ts","sourceRoot":"","sources":["../src/build-start.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAC/D,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,GAC3D,OAAO,CAAC,IAAI,CAAC,CA8Pf"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,cAAc,GACrB,IAAI,CAwDN"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,cAAc,GACrB,IAAI,CAiEN"}
@@ -28,5 +28,5 @@ export declare const RESOLVED_BRIDGE_ID = "\0virtual:animus/hmr-bridge.js";
28
28
  export declare const BRIDGE_SCRIPT_SRC = "/@id/virtual:animus/hmr-bridge.js";
29
29
  export declare const VIRTUAL_SYSTEM_PROPS_ID = "virtual:animus/system-props";
30
30
  export declare const RESOLVED_SYSTEM_PROPS_ID = "\0virtual:animus/system-props";
31
- export declare const DEFAULT_EXCLUDE: string[];
31
+ export { DEFAULT_EXCLUDE } from '@animus-ui/extract/pipeline';
32
32
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,eAAO,MAAM,cAAc,8BAAgC,CAAC;AAC5D,eAAO,MAAM,eAAe,gCAAwB,CAAC;AAErD,eAAO,MAAM,qBAAqB,iCAAmC,CAAC;AACtE,eAAO,MAAM,sBAAsB,mCAA+B,CAAC;AAEnE,eAAO,MAAM,iBAAiB,iCAAmC,CAAC;AAClE,eAAO,MAAM,kBAAkB,mCAA2B,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,sCAA8B,CAAC;AAE7D,eAAO,MAAM,uBAAuB,gCAAkC,CAAC;AACvE,eAAO,MAAM,wBAAwB,kCAAiC,CAAC;AAEvE,eAAO,MAAM,eAAe,UAA+C,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,eAAO,MAAM,cAAc,8BAAgC,CAAC;AAC5D,eAAO,MAAM,eAAe,gCAAwB,CAAC;AAErD,eAAO,MAAM,qBAAqB,iCAAmC,CAAC;AACtE,eAAO,MAAM,sBAAsB,mCAA+B,CAAC;AAEnE,eAAO,MAAM,iBAAiB,iCAAmC,CAAC;AAClE,eAAO,MAAM,kBAAkB,mCAA2B,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,sCAA8B,CAAC;AAE7D,eAAO,MAAM,uBAAuB,gCAAkC,CAAC;AACvE,eAAO,MAAM,wBAAwB,kCAAiC,CAAC;AAKvE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC"}
package/dist/context.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { HotUpdateEvents } from './hot-update-events';
2
2
  import type { LightningTargets } from './css';
3
3
  import type { AnimusExtractOptions } from './index';
4
- import type { ExternalPackageOutcome, ManifestDiagnostic, SystemConfig } from '@animus-ui/extract/pipeline';
4
+ import type { ExcludeMatcher, ExternalPackageOutcome, ManifestDiagnostic, RawSourceEntry, SourceEntryOwnership, SourceIngestionDiagnostic, SourceIngestionResult, SystemConfig } from '@animus-ui/extract/pipeline';
5
5
  import type { Logger } from 'vite';
6
6
  /**
7
7
  * Structured per-layer CSS sheets from the Rust crate (dev split delivery).
@@ -18,21 +18,19 @@ export interface CssSheets {
18
18
  system: string;
19
19
  custom: string;
20
20
  }
21
- /**
22
- * Reconstruct file entries from cache, including content hashes.
23
- * For unchanged files (hash matches changedPath), sends empty source
24
- * to avoid serializing full source text across the NAPI boundary.
25
- * The engine adapter's `rehydrateFilesJson` refills empty sources from
26
- * this same cache before analyze.
27
- */
28
- export declare function buildFileEntriesFromCache(cache: Map<string, {
21
+ /** Full raw originals for one adaptation attempt. */
22
+ export declare function buildRawEntriesFromCache(cache: Map<string, {
29
23
  hash: string;
30
24
  source: string;
31
- }>, changedPath?: string): Array<{
25
+ }>): Array<{
32
26
  path: string;
33
27
  source: string;
34
28
  hash: string;
35
29
  }>;
30
+ /** Run `task` after every previously scheduled analysis transaction for
31
+ * this context. Entry points only (transform detection, hot update,
32
+ * geological reset); helpers they call internally must stay unlocked. */
33
+ export declare function runExclusiveAnalysis<T>(ctx: object, task: () => Promise<T>): Promise<T>;
36
34
  /**
37
35
  * The exact source `virtual:animus/system-props` serves for the current state.
38
36
  * One definition, so the served bytes and the change decision below can never
@@ -45,12 +43,10 @@ export declare function buildFileEntriesFromCache(cache: Map<string, {
45
43
  */
46
44
  export declare function systemPropsModuleSource(ctx: PluginContext): string;
47
45
  /**
48
- * Drop a deleted (or renamed-away) file from the dev file cache so its
49
- * last-known source stops riding along as a ghost entry on every later
50
- * re-analysis. Both key forms are tried: the plain rootDir-relative path, and
51
- * the `.tsx` suffix MDX sources carry after preprocessing. External package
52
- * entries are rootDir-relative too (with leading `..` segments) and prune the
53
- * same way. Returns whether an entry was actually removed.
46
+ * Drop a deleted (or renamed-away) raw original from the dev file cache.
47
+ * Generated MDX/Svelte children live in `analysisEntryCache` and disappear
48
+ * atomically when the next source-ingestion result publishes. External
49
+ * package entries are rootDir-relative too (with leading `..` segments).
54
50
  */
55
51
  export declare function pruneFileCache(cache: Map<string, {
56
52
  hash: string;
@@ -72,6 +68,10 @@ export declare class PluginContext {
72
68
  /** Serialized staticCss forced-emission declarations (stable key order). */
73
69
  readonly staticCssJson: string | null;
74
70
  isProd: boolean;
71
+ /** Emission-mode signal (explicit `mode` option wins over the command);
72
+ * feeds engine devMode and the minify default. Lifecycle stays on
73
+ * `isProd`. */
74
+ emissionProd: boolean;
75
75
  rootDir: string;
76
76
  logger: Logger | null;
77
77
  /** System-derived config (shared SystemConfig shape). */
@@ -79,6 +79,7 @@ export declare class PluginContext {
79
79
  lcssTargets: LightningTargets;
80
80
  pathAliasesJson: string | null;
81
81
  extensionsSet: ReadonlySet<string>;
82
+ excludeMatcher: ExcludeMatcher;
82
83
  storedManifest: any;
83
84
  storedManifestJson: string;
84
85
  globalCss: string;
@@ -117,6 +118,12 @@ export declare class PluginContext {
117
118
  hash: string;
118
119
  source: string;
119
120
  }>;
121
+ analysisEntryCache: Map<string, {
122
+ hash: string;
123
+ source: string;
124
+ }>;
125
+ sourceOwnership: Record<string, SourceEntryOwnership>;
126
+ analysisOwnerByPath: Map<string, string>;
120
127
  rawExtensionFallbacks: Set<string>;
121
128
  readonly hotUpdateEvents: HotUpdateEvents;
122
129
  private pendingReloadTimer;
@@ -171,6 +178,46 @@ export declare class PluginContext {
171
178
  source: string;
172
179
  hash?: string;
173
180
  }>): boolean;
181
+ /**
182
+ * `runtimeImport` swaps ONE module specifier under every generated
183
+ * factory import, and the engine performs no export validation — an
184
+ * override that supplies only `createClassResolver` (the documented
185
+ * class-resolver entry contract) breaks the bundle at LOAD the moment any
186
+ * non-`.asClass()` terminal exists, with the error pointing at generated
187
+ * code. Guaranteed-broken output escalates in every mode, exactly like
188
+ * error diagnostics (extraction-diagnostics §Error diagnostics fail the
189
+ * build), naming the offending components instead of the import site.
190
+ */
191
+ private assertRuntimeImportSuppliesTerminals;
192
+ /** The shared ingestion policy point — capability guard, facts memo, and
193
+ * warn-dedupe lifecycle all live in the pipeline, not per host. */
194
+ private sourceIngestor;
195
+ /** Prepare one raw-source corpus through the shared adaptation boundary. */
196
+ ingestRawSources(fileEntries: readonly RawSourceEntry[]): Promise<SourceIngestionResult>;
197
+ /** Surface adapter diagnostics under the shared strict/warn policy. */
198
+ surfaceSourceDiagnostics(diagnostics: readonly SourceIngestionDiagnostic[]): Set<string>;
199
+ /**
200
+ * The one ingest → quarantine → analyze → publish transaction, shared by
201
+ * buildStart and every incremental path. Per-file quarantine: one invalid
202
+ * original warns and drops without aborting the rest of the corpus
203
+ * (strict mode throws from the shared policy). `runAnalysis(...) !==
204
+ * false` is the documented success contract (a `void` behavioral test
205
+ * double reads as success), and the accepted corpus publishes only on
206
+ * success. `beforeAnalysis` runs between quarantine and analysis for the
207
+ * two sites with a documented ordering constraint: buildStart's dev-cache
208
+ * seed must survive a strict analysis throw, and the geological reset
209
+ * clears the engine cache only after strict ingestion diagnostics had
210
+ * their chance to throw.
211
+ */
212
+ analyzeIngested(options?: {
213
+ rawEntries?: readonly RawSourceEntry[];
214
+ beforeAnalysis?: (accepted: SourceIngestionResult) => void;
215
+ }): Promise<{
216
+ ok: boolean;
217
+ accepted: SourceIngestionResult;
218
+ }>;
219
+ /** Publish every parser child and ownership edge atomically after analysis. */
220
+ publishSourceIngestion(result: SourceIngestionResult): void;
174
221
  /** Base-prefixed dev URL for an absolute file (Vite mounts /@fs under base). */
175
222
  devFsUrl(absPath: string): string;
176
223
  /**
@@ -211,7 +258,9 @@ export declare class PluginContext {
211
258
  * sources, then invalidate the static/component/system-prop virtual
212
259
  * modules and reload the client.
213
260
  */
214
- performGeologicalReset(): void;
261
+ performGeologicalReset(): Promise<void>;
262
+ private performGeologicalResetExclusive;
263
+ private invalidateGeologicalResetModules;
215
264
  /**
216
265
  * True when the file is a member of the system's evaluated module-file
217
266
  * set. Tested BEFORE component-scan exclude filters: a system dependency
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
package/dist/hmr.d.ts CHANGED
@@ -19,5 +19,5 @@ import type { DevEnvironment, EnvironmentModuleNode, HotUpdateOptions } from 'vi
19
19
  * graph, so system dependencies registered through `watcher.add` outside the
20
20
  * root still reach the reset branch, with an empty `modules` list.
21
21
  */
22
- export declare function handleHotUpdate(ctx: PluginContext, environment: DevEnvironment, { type, file, timestamp, modules, read }: HotUpdateOptions): Promise<EnvironmentModuleNode[] | void>;
22
+ export declare function handleHotUpdate(ctx: PluginContext, environment: DevEnvironment, options: HotUpdateOptions): Promise<EnvironmentModuleNode[] | void>;
23
23
  //# sourceMappingURL=hmr.d.ts.map
package/dist/hmr.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,MAAM,CAAC;AAEd;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,WAAW,EAAE,cAAc,EAC3B,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,gBAAgB,GACzD,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAqEzC"}
1
+ {"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,MAAM,CAAC;AAEd;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAUzC"}
package/dist/index.cjs CHANGED
@@ -6,44 +6,6 @@ let _animus_ui_extract_pipeline = require("@animus-ui/extract/pipeline");
6
6
  let fs = require("fs");
7
7
  let path = require("path");
8
8
  let crypto = require("crypto");
9
- //#region src/constants.ts
10
- /**
11
- * The namespace every virtual module this plugin owns lives under. Exported so
12
- * the `transform` guard that keeps those modules out of source-file handling
13
- * matches on the same string the ids are built from — a rename of the
14
- * namespace cannot leave the guard behind.
15
- */
16
- const VIRTUAL_PREFIX = "virtual:animus/";
17
- const VIRTUAL_CSS_ID = `${VIRTUAL_PREFIX}styles.css`;
18
- const RESOLVED_CSS_ID = `\0${VIRTUAL_CSS_ID}`;
19
- const VIRTUAL_COMPONENTS_ID = `${VIRTUAL_PREFIX}components.js`;
20
- const RESOLVED_COMPONENTS_ID = `\0${VIRTUAL_COMPONENTS_ID}`;
21
- const VIRTUAL_BRIDGE_ID = `${VIRTUAL_PREFIX}hmr-bridge.js`;
22
- const RESOLVED_BRIDGE_ID = `\0${VIRTUAL_BRIDGE_ID}`;
23
- /**
24
- * Browser-addressable URL for the bridge, used as the `src` of the dev
25
- * `<script type="module">` (see index-html.ts). THE explanation of the `/@id/`
26
- * convention lives here; everything else points at it.
27
- *
28
- * Vite reserves `/@id/` for module ids that are not file paths. Its transform
29
- * middleware normalizes such a URL before serving it (`unwrapId`): strip the
30
- * prefix, then decode the `__x00__` placeholder back to a NUL byte. The
31
- * UNPREFIXED specifier is what travels here — `resolveVirtualId` is the hook
32
- * that answers it, and it answers with the `\0` form. (Vite's own `wrapId`
33
- * encodes an already-`\0`-prefixed id as `__x00__`; that form resolves too, but
34
- * it leans on the placeholder convention rather than on this plugin's own
35
- * `resolveId` contract.)
36
- */
37
- const BRIDGE_SCRIPT_SRC = `/@id/${VIRTUAL_BRIDGE_ID}`;
38
- const VIRTUAL_SYSTEM_PROPS_ID = `${VIRTUAL_PREFIX}system-props`;
39
- const RESOLVED_SYSTEM_PROPS_ID = `\0${VIRTUAL_SYSTEM_PROPS_ID}`;
40
- const DEFAULT_EXCLUDE = [
41
- "node_modules",
42
- "dist",
43
- ".test.",
44
- ".spec."
45
- ];
46
- //#endregion
47
9
  //#region src/build-start.ts
48
10
  /**
49
11
  * buildStart: load the system, discover and ingest sources (local +
@@ -70,51 +32,22 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
70
32
  ctx.log(`System loaded: ${propCount} props, ${groupCount} groups (${Math.round(performance.now() - t0)}ms)`);
71
33
  }
72
34
  t0 = performance.now();
73
- const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
35
+ ctx.excludeMatcher = (0, _animus_ui_extract_pipeline.createExcludeMatcher)(ctx.options.exclude);
36
+ const excludePatterns = ctx.excludeMatcher;
74
37
  ctx.extensionsSet = new Set(ctx.options.extensions ?? _animus_ui_extract_pipeline.DEFAULT_EXTENSIONS);
75
- const shouldHandleMdx = ctx.extensionsSet.has(".mdx");
76
- let mdxMissingDepWarned = false;
77
- const preprocessMdxEntry = async (source, relPath) => {
78
- const result = await (0, _animus_ui_extract_pipeline.preprocessMdx)(source, relPath);
79
- if (result.kind === "missing-dep") {
80
- if (!mdxMissingDepWarned) {
81
- ctx.warn("⚠ .mdx in extensions but @mdx-js/mdx not installed; MDX files skipped");
82
- mdxMissingDepWarned = true;
83
- }
84
- return null;
85
- }
86
- if (result.kind === "error") {
87
- ctx.warn(`⚠ MDX preprocessing failed for ${relPath}: ${result.error}`);
88
- return null;
89
- }
90
- return {
91
- source: result.source,
92
- relPath: relPath + ".tsx"
93
- };
94
- };
95
38
  const filePaths = (0, _animus_ui_extract_pipeline.discoverFiles)(ctx.rootDir, ctx.rootDir, excludePatterns, ctx.extensionsSet);
96
- const fileEntries = [];
39
+ const rawEntries = [];
97
40
  for (const filePath of filePaths) try {
98
- let source = (0, fs.readFileSync)(filePath, "utf-8");
99
- let relPath = (0, path.relative)(ctx.rootDir, filePath);
100
- if (shouldHandleMdx && (0, path.extname)(filePath) === ".mdx") {
101
- const processed = await preprocessMdxEntry(source, relPath);
102
- if (!processed) continue;
103
- source = processed.source;
104
- relPath = processed.relPath;
105
- }
41
+ const source = (0, fs.readFileSync)(filePath, "utf-8");
42
+ const relPath = (0, path.relative)(ctx.rootDir, filePath);
106
43
  const hash = !ctx.isProd ? (0, _animus_ui_extract_pipeline.contentHash)(source) : void 0;
107
- fileEntries.push({
44
+ rawEntries.push({
108
45
  path: relPath,
109
46
  source,
110
47
  hash
111
48
  });
112
- if (!ctx.isProd && hash) ctx.fileCache.set(relPath, {
113
- hash,
114
- source
115
- });
116
49
  } catch {}
117
- const localFileCount = fileEntries.length;
50
+ const localFileCount = rawEntries.length;
118
51
  const packageSpecifiers = (0, _animus_ui_extract_pipeline.extractSystemFilePackages)(ctx.resolvedSystemPath);
119
52
  ctx.externalSourceEntries.clear();
120
53
  ctx.externalKeyframesScanEntries.clear();
@@ -123,14 +56,7 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
123
56
  resolveSpecifier,
124
57
  rootDir: ctx.rootDir,
125
58
  extensionsSet: ctx.extensionsSet,
126
- hasEntry: (relPath) => fileEntries.some((e) => e.path === relPath),
127
- preprocessFile: async (source, relPath, absPath) => {
128
- if (shouldHandleMdx && (0, path.extname)(absPath) === ".mdx") return preprocessMdxEntry(source, relPath);
129
- return {
130
- source,
131
- relPath
132
- };
133
- },
59
+ hasEntry: (relPath) => rawEntries.some((entry) => entry.path === relPath),
134
60
  onUnreadable: (relPath, err) => ctx.warn(`skipped unreadable package file ${relPath}: ${String(err)}`)
135
61
  });
136
62
  ctx.packageMap = collected.packageMap;
@@ -142,23 +68,27 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
142
68
  for (const [specifier, scanEntry] of collected.keyframesScanEntries) ctx.externalKeyframesScanEntries.set(specifier, scanEntry);
143
69
  for (const entry of collected.entries) {
144
70
  const hash = !ctx.isProd ? (0, _animus_ui_extract_pipeline.contentHash)(entry.source) : void 0;
145
- fileEntries.push({
71
+ rawEntries.push({
146
72
  path: entry.path,
147
73
  source: entry.source,
148
74
  hash
149
75
  });
150
- if (!ctx.isProd && hash) ctx.fileCache.set(entry.path, {
151
- hash,
152
- source: entry.source
153
- });
154
76
  }
155
77
  ctx.externalPackageDirs = collected.packageDirs;
156
78
  ctx.registerSystemWatchPaths();
157
79
  ctx.applyExternalKeyframes();
158
- const packageFileCount = fileEntries.length - localFileCount;
159
- ctx.log(`Discovered ${fileEntries.length} files (${packageFileCount} from packages) (${Math.round(performance.now() - t0)}ms)`);
80
+ const packageFileCount = rawEntries.length - localFileCount;
81
+ ctx.log(`Discovered ${rawEntries.length} files (${packageFileCount} from packages) (${Math.round(performance.now() - t0)}ms)`);
160
82
  t0 = performance.now();
161
- ctx.runAnalysis(fileEntries);
83
+ await ctx.analyzeIngested({
84
+ rawEntries,
85
+ beforeAnalysis: (accepted) => {
86
+ if (!ctx.isProd) ctx.fileCache = new Map(accepted.originalEntries.map((entry) => [entry.path, {
87
+ hash: entry.hash,
88
+ source: entry.source
89
+ }]));
90
+ }
91
+ });
162
92
  const assetSpecifiers = (0, _animus_ui_extract_pipeline.findAssetSpecifiers)(ctx.globalCss);
163
93
  for (const specifier of assetSpecifiers) {
164
94
  const resolvedPath = await resolveSpecifier(specifier);
@@ -217,6 +147,7 @@ async function runBuildStart(ctx, resolveSpecifier, emitAsset) {
217
147
  */
218
148
  function applyResolvedConfig(ctx, config) {
219
149
  ctx.isProd = config.command === "build";
150
+ ctx.emissionProd = (0, _animus_ui_extract_pipeline.resolveMode)(ctx.options.mode, () => config.command === "build" ? "production" : "development").mode === "production";
220
151
  ctx.rootDir = config.root;
221
152
  ctx.logger = config.logger;
222
153
  ctx.base = config.base ?? "/";
@@ -245,6 +176,38 @@ function applyResolvedConfig(ctx, config) {
245
176
  }
246
177
  }
247
178
  //#endregion
179
+ //#region src/constants.ts
180
+ /**
181
+ * The namespace every virtual module this plugin owns lives under. Exported so
182
+ * the `transform` guard that keeps those modules out of source-file handling
183
+ * matches on the same string the ids are built from — a rename of the
184
+ * namespace cannot leave the guard behind.
185
+ */
186
+ const VIRTUAL_PREFIX = "virtual:animus/";
187
+ const VIRTUAL_CSS_ID = `${VIRTUAL_PREFIX}styles.css`;
188
+ const RESOLVED_CSS_ID = `\0${VIRTUAL_CSS_ID}`;
189
+ const VIRTUAL_COMPONENTS_ID = `${VIRTUAL_PREFIX}components.js`;
190
+ const RESOLVED_COMPONENTS_ID = `\0${VIRTUAL_COMPONENTS_ID}`;
191
+ const VIRTUAL_BRIDGE_ID = `${VIRTUAL_PREFIX}hmr-bridge.js`;
192
+ const RESOLVED_BRIDGE_ID = `\0${VIRTUAL_BRIDGE_ID}`;
193
+ /**
194
+ * Browser-addressable URL for the bridge, used as the `src` of the dev
195
+ * `<script type="module">` (see index-html.ts). THE explanation of the `/@id/`
196
+ * convention lives here; everything else points at it.
197
+ *
198
+ * Vite reserves `/@id/` for module ids that are not file paths. Its transform
199
+ * middleware normalizes such a URL before serving it (`unwrapId`): strip the
200
+ * prefix, then decode the `__x00__` placeholder back to a NUL byte. The
201
+ * UNPREFIXED specifier is what travels here — `resolveVirtualId` is the hook
202
+ * that answers it, and it answers with the `\0` form. (Vite's own `wrapId`
203
+ * encodes an already-`\0`-prefixed id as `__x00__`; that form resolves too, but
204
+ * it leans on the placeholder convention rather than on this plugin's own
205
+ * `resolveId` contract.)
206
+ */
207
+ const BRIDGE_SCRIPT_SRC = `/@id/${VIRTUAL_BRIDGE_ID}`;
208
+ const VIRTUAL_SYSTEM_PROPS_ID = `${VIRTUAL_PREFIX}system-props`;
209
+ const RESOLVED_SYSTEM_PROPS_ID = `\0${VIRTUAL_SYSTEM_PROPS_ID}`;
210
+ //#endregion
248
211
  //#region src/hot-update-events.ts
249
212
  /**
250
213
  * Once-per-file-event coordination across the `hotUpdate` dispatches.
@@ -298,6 +261,44 @@ function eventKey(file, timestamp) {
298
261
  return `${file}\u0000${timestamp}`;
299
262
  }
300
263
  //#endregion
264
+ //#region src/module-invalidation.ts
265
+ /**
266
+ * Evict every module node the dev server holds for each file — every
267
+ * environment graph (client, ssr, and any custom environment), by-file node
268
+ * sets (covers query-suffixed variants), plus the absolute-path id lookup.
269
+ * Falls back to the mixed compat graph for hosts without environment
270
+ * graphs. Returns the number of nodes invalidated.
271
+ *
272
+ * Completeness here is load-bearing: the file-plan diff is the ONLY
273
+ * invalidation candidate source, so a node shape this enumeration misses
274
+ * stays stale for the life of the server (openspec: dev-transform-coherence,
275
+ * "Client and SSR nodes are both evicted").
276
+ */
277
+ function invalidateFileModules(ctx, relPaths) {
278
+ const server = ctx.devServer;
279
+ if (!server || relPaths.length === 0) return 0;
280
+ const graphs = server.environments ? Object.values(server.environments).map((env) => env?.moduleGraph).filter(Boolean) : [server.moduleGraph].filter(Boolean);
281
+ let total = 0;
282
+ for (const relPath of relPaths) {
283
+ const absPath = (0, path.resolve)(ctx.rootDir, relPath);
284
+ let fileCount = 0;
285
+ for (const graph of graphs) {
286
+ const nodes = /* @__PURE__ */ new Set();
287
+ const byFile = graph.getModulesByFile?.(absPath);
288
+ if (byFile) for (const mod of byFile) nodes.add(mod);
289
+ const byId = graph.getModuleById?.(absPath);
290
+ if (byId) nodes.add(byId);
291
+ for (const mod of nodes) {
292
+ graph.invalidateModule(mod);
293
+ fileCount++;
294
+ }
295
+ }
296
+ if (fileCount > 0) ctx.log(`HMR invalidate: ${relPath} (plan changed, ${fileCount} nodes)`);
297
+ total += fileCount;
298
+ }
299
+ return total;
300
+ }
301
+ //#endregion
301
302
  //#region src/reset-coalescer.ts
302
303
  /**
303
304
  * Coalesces bursts of system-dependency events into single geological
@@ -326,11 +327,12 @@ var ResetCoalescer = class {
326
327
  return;
327
328
  }
328
329
  if (this.timer !== null) this.cancel(this.timer);
329
- this.timer = this.schedule(() => {
330
+ this.timer = this.schedule(async () => {
330
331
  this.timer = null;
331
332
  this.running = true;
332
333
  try {
333
- this.run();
334
+ const result = this.run();
335
+ if (result instanceof Promise) await result;
334
336
  } catch (err) {
335
337
  this.onError(err);
336
338
  } finally {
@@ -359,21 +361,22 @@ function emptySystemConfig() {
359
361
  keyframesJson: null
360
362
  };
361
363
  }
362
- /**
363
- * Reconstruct file entries from cache, including content hashes.
364
- * For unchanged files (hash matches changedPath), sends empty source
365
- * to avoid serializing full source text across the NAPI boundary.
366
- * The engine adapter's `rehydrateFilesJson` refills empty sources from
367
- * this same cache before analyze.
368
- */
369
- function buildFileEntriesFromCache(cache, changedPath) {
370
- const entries = [];
371
- for (const [path$1, { hash, source }] of cache) entries.push({
364
+ /** Full raw originals for one adaptation attempt. */
365
+ function buildRawEntriesFromCache(cache) {
366
+ return [...cache].map(([path$1, { hash, source }]) => ({
372
367
  path: path$1,
373
- source: path$1 === changedPath ? source : "",
368
+ source,
374
369
  hash
375
- });
376
- return entries;
370
+ }));
371
+ }
372
+ const analysisChains = /* @__PURE__ */ new WeakMap();
373
+ /** Run `task` after every previously scheduled analysis transaction for
374
+ * this context. Entry points only (transform detection, hot update,
375
+ * geological reset); helpers they call internally must stay unlocked. */
376
+ function runExclusiveAnalysis(ctx, task) {
377
+ const result = (analysisChains.get(ctx) ?? Promise.resolve()).then(task);
378
+ analysisChains.set(ctx, result.then(() => void 0, () => void 0));
379
+ return result;
377
380
  }
378
381
  /** Generate the module from the four inputs the context currently holds. */
379
382
  function generateSystemPropsModule(ctx) {
@@ -398,16 +401,14 @@ function systemPropsModuleSource(ctx) {
398
401
  return ctx.systemPropsModuleMemo ??= generateSystemPropsModule(ctx);
399
402
  }
400
403
  /**
401
- * Drop a deleted (or renamed-away) file from the dev file cache so its
402
- * last-known source stops riding along as a ghost entry on every later
403
- * re-analysis. Both key forms are tried: the plain rootDir-relative path, and
404
- * the `.tsx` suffix MDX sources carry after preprocessing. External package
405
- * entries are rootDir-relative too (with leading `..` segments) and prune the
406
- * same way. Returns whether an entry was actually removed.
404
+ * Drop a deleted (or renamed-away) raw original from the dev file cache.
405
+ * Generated MDX/Svelte children live in `analysisEntryCache` and disappear
406
+ * atomically when the next source-ingestion result publishes. External
407
+ * package entries are rootDir-relative too (with leading `..` segments).
407
408
  */
408
409
  function pruneFileCache(cache, rootDir, absPath) {
409
410
  const rel = (0, path.relative)(rootDir, (0, path.resolve)(absPath));
410
- return cache.delete(rel) || cache.delete(rel + ".tsx");
411
+ return cache.delete(rel);
411
412
  }
412
413
  /**
413
414
  * Per-plugin-instance state and the pipeline operations over it. Hook
@@ -425,6 +426,10 @@ var PluginContext = class {
425
426
  /** Serialized staticCss forced-emission declarations (stable key order). */
426
427
  staticCssJson;
427
428
  isProd = false;
429
+ /** Emission-mode signal (explicit `mode` option wins over the command);
430
+ * feeds engine devMode and the minify default. Lifecycle stays on
431
+ * `isProd`. */
432
+ emissionProd = false;
428
433
  rootDir = "";
429
434
  logger = null;
430
435
  /** System-derived config (shared SystemConfig shape). */
@@ -432,6 +437,7 @@ var PluginContext = class {
432
437
  lcssTargets = {};
433
438
  pathAliasesJson = null;
434
439
  extensionsSet;
440
+ excludeMatcher;
435
441
  storedManifest = null;
436
442
  storedManifestJson = "";
437
443
  globalCss = "";
@@ -478,6 +484,9 @@ var PluginContext = class {
478
484
  storedTransformsSource = "{}";
479
485
  systemPropsModuleMemo = null;
480
486
  fileCache = /* @__PURE__ */ new Map();
487
+ analysisEntryCache = /* @__PURE__ */ new Map();
488
+ sourceOwnership = {};
489
+ analysisOwnerByPath = /* @__PURE__ */ new Map();
481
490
  rawExtensionFallbacks = /* @__PURE__ */ new Set();
482
491
  hotUpdateEvents = new HotUpdateEvents();
483
492
  pendingReloadTimer = null;
@@ -506,6 +515,7 @@ var PluginContext = class {
506
515
  this.staticCssJson = (0, _animus_ui_extract_pipeline.serializeStaticCss)(options.staticCss);
507
516
  this.verbose = options.verbose || process.env.ANIMUS_DEBUG === "1" || process.env.ANIMUS_DEBUG === "true";
508
517
  this.extensionsSet = new Set(options.extensions ?? _animus_ui_extract_pipeline.DEFAULT_EXTENSIONS);
518
+ this.excludeMatcher = (0, _animus_ui_extract_pipeline.createExcludeMatcher)(options.exclude);
509
519
  if (engineApiOverride) {
510
520
  this.engineApi = engineApiOverride;
511
521
  return;
@@ -518,7 +528,7 @@ var PluginContext = class {
518
528
  rehydrateFilesJson: (filesJsonRaw) => {
519
529
  if (!filesJsonRaw.includes("\"source\":\"\"")) return filesJsonRaw;
520
530
  const entries = JSON.parse(filesJsonRaw);
521
- for (const entry of entries) if (entry.source === "") entry.source = this.fileCache.get(entry.path)?.source ?? "";
531
+ for (const entry of entries) if (entry.source === "") entry.source = this.analysisEntryCache.get(entry.path)?.source ?? "";
522
532
  return JSON.stringify(entries);
523
533
  },
524
534
  store: {
@@ -598,41 +608,123 @@ var PluginContext = class {
598
608
  * equal-content retries"). Strict mode still throws.
599
609
  */
600
610
  runAnalysis(fileEntries) {
611
+ let result;
601
612
  try {
602
- const result = (0, _animus_ui_extract_pipeline.runProjectAnalysis)(this.engineApi, {
613
+ result = (0, _animus_ui_extract_pipeline.runProjectAnalysis)(this.engineApi, {
603
614
  fileEntries,
604
615
  packageMap: this.packageMap,
605
616
  system: this.system,
606
617
  emitter: {
607
- runtimeImport: "@animus-ui/system",
618
+ runtimeImport: this.options.runtimeImport ?? "@animus-ui/system",
608
619
  cssModuleId: VIRTUAL_CSS_ID
609
620
  },
610
621
  pathAliasesJson: this.pathAliasesJson,
611
622
  staticCssJson: this.staticCssJson,
612
623
  externalDirs: this.externalPackageDirs.map((dir) => (0, path.relative)(this.rootDir, dir)),
613
- devMode: !this.isProd,
624
+ devMode: !this.emissionProd,
614
625
  warn: (m) => this.warn(m),
615
626
  strict: this.options.strict,
616
627
  extraDiagnostics: this.externalKeyframesDiagnostics
617
628
  });
618
- this.storedManifest = result.manifest;
619
- this.storedManifestJson = result.manifestJson;
620
- this.storedSystemPropMapJson = JSON.stringify(result.manifest?.system_prop_map ?? {});
621
- this.storedDynamicPropsJson = JSON.stringify(result.manifest?.dynamic_props ?? {});
622
- this.reverseProvenance = result.manifest?.reverse_provenance ?? {};
623
- this.storedSheets = result.manifest?.sheets ?? null;
624
- this.globalCss = result.globalCss;
625
- this.resolvedComponentCss = result.componentCss;
626
629
  } catch (e) {
627
630
  if (this.options.strict) throw new Error(`[animus-extract] analyzeProject failed: ${e}`, { cause: e });
628
631
  console.warn("[animus-extract] analyzeProject failed:", e);
629
632
  return false;
630
633
  }
634
+ (0, _animus_ui_extract_pipeline.assertNoErrorDiagnostics)(result.manifest?.diagnostics);
635
+ this.assertRuntimeImportSuppliesTerminals(result.manifest);
636
+ this.storedManifest = result.manifest;
637
+ this.storedManifestJson = result.manifestJson;
638
+ this.storedSystemPropMapJson = JSON.stringify(result.manifest?.system_prop_map ?? {});
639
+ this.storedDynamicPropsJson = JSON.stringify(result.manifest?.dynamic_props ?? {});
640
+ this.reverseProvenance = result.manifest?.reverse_provenance ?? {};
641
+ this.storedSheets = result.manifest?.sheets ?? null;
642
+ this.globalCss = result.globalCss;
643
+ this.resolvedComponentCss = result.componentCss;
631
644
  this.systemPropsModuleMemo = generateSystemPropsModule(this);
632
645
  this.applyAssetSubstitutions();
633
- this.enforceExternalTokenContracts();
634
646
  return true;
635
647
  }
648
+ /**
649
+ * `runtimeImport` swaps ONE module specifier under every generated
650
+ * factory import, and the engine performs no export validation — an
651
+ * override that supplies only `createClassResolver` (the documented
652
+ * class-resolver entry contract) breaks the bundle at LOAD the moment any
653
+ * non-`.asClass()` terminal exists, with the error pointing at generated
654
+ * code. Guaranteed-broken output escalates in every mode, exactly like
655
+ * error diagnostics (extraction-diagnostics §Error diagnostics fail the
656
+ * build), naming the offending components instead of the import site.
657
+ */
658
+ assertRuntimeImportSuppliesTerminals(manifest) {
659
+ const override = this.options.runtimeImport;
660
+ if (!override || override === "@animus-ui/system") return;
661
+ const offenders = [];
662
+ for (const [id, descriptor] of Object.entries(manifest?.components ?? {})) {
663
+ const replacement = String(descriptor?.replacement ?? "");
664
+ if (/\bcreateComponent\(|\bcreateComposedFamily\(/.test(replacement)) offenders.push(id);
665
+ }
666
+ if (offenders.length === 0) return;
667
+ const shown = offenders.slice(0, 5).join(", ");
668
+ throw new Error(`[animus-extract] runtimeImport '${override}' is valid only when every extracted terminal is .asClass(), but ${offenders.length} component(s) need createComponent/createComposedFamily from the default '@animus-ui/system' runtime: ${shown}` + (offenders.length > 5 ? ", …" : "") + `. Remove the override or convert these terminals to .asClass().`);
669
+ }
670
+ /** The shared ingestion policy point — capability guard, facts memo, and
671
+ * warn-dedupe lifecycle all live in the pipeline, not per host. */
672
+ sourceIngestor = (0, _animus_ui_extract_pipeline.createSourceIngestor)({
673
+ engineApi: () => this.engineApi(),
674
+ prefix: "[animus-extract]",
675
+ strict: () => !!this.options.strict,
676
+ warn: (message) => this.warn(message)
677
+ });
678
+ /** Prepare one raw-source corpus through the shared adaptation boundary. */
679
+ async ingestRawSources(fileEntries) {
680
+ return this.sourceIngestor.ingest(fileEntries);
681
+ }
682
+ /** Surface adapter diagnostics under the shared strict/warn policy. */
683
+ surfaceSourceDiagnostics(diagnostics) {
684
+ return this.sourceIngestor.surfaceDiagnostics(diagnostics);
685
+ }
686
+ /**
687
+ * The one ingest → quarantine → analyze → publish transaction, shared by
688
+ * buildStart and every incremental path. Per-file quarantine: one invalid
689
+ * original warns and drops without aborting the rest of the corpus
690
+ * (strict mode throws from the shared policy). `runAnalysis(...) !==
691
+ * false` is the documented success contract (a `void` behavioral test
692
+ * double reads as success), and the accepted corpus publishes only on
693
+ * success. `beforeAnalysis` runs between quarantine and analysis for the
694
+ * two sites with a documented ordering constraint: buildStart's dev-cache
695
+ * seed must survive a strict analysis throw, and the geological reset
696
+ * clears the engine cache only after strict ingestion diagnostics had
697
+ * their chance to throw.
698
+ */
699
+ async analyzeIngested(options) {
700
+ const ingested = await this.ingestRawSources(options?.rawEntries ?? buildRawEntriesFromCache(this.fileCache));
701
+ const accepted = (0, _animus_ui_extract_pipeline.withoutInvalidOriginals)(ingested, this.surfaceSourceDiagnostics(ingested.diagnostics));
702
+ options?.beforeAnalysis?.(accepted);
703
+ const ok = this.runAnalysis(accepted.analysisEntries) !== false;
704
+ if (ok) this.publishSourceIngestion(accepted);
705
+ return {
706
+ ok,
707
+ accepted
708
+ };
709
+ }
710
+ /** Publish every parser child and ownership edge atomically after analysis. */
711
+ publishSourceIngestion(result) {
712
+ this.sourceIngestor.markPublished(result);
713
+ const priorAnalysisPaths = new Set(this.analysisOwnerByPath.keys());
714
+ this.analysisEntryCache = new Map(result.analysisEntries.map((entry) => [entry.path, {
715
+ hash: entry.hash,
716
+ source: entry.source
717
+ }]));
718
+ this.sourceOwnership = result.ownership;
719
+ this.analysisOwnerByPath = /* @__PURE__ */ new Map();
720
+ for (const owner of Object.values(result.ownership)) for (const analysisPath of owner.analysisPaths) {
721
+ this.analysisOwnerByPath.set(analysisPath, owner.originalPath);
722
+ const externalOwner = this.externalFileOwners[owner.originalPath];
723
+ if (externalOwner) this.externalFileOwners[analysisPath] = externalOwner;
724
+ }
725
+ for (const stalePath of priorAnalysisPaths) if (!this.analysisOwnerByPath.has(stalePath)) delete this.externalFileOwners[stalePath];
726
+ this.enforceExternalTokenContracts();
727
+ }
636
728
  /** Base-prefixed dev URL for an absolute file (Vite mounts /@fs under base). */
637
729
  devFsUrl(absPath) {
638
730
  return `${this.base.endsWith("/") ? this.base.slice(0, -1) : this.base}/@fs${absPath}`;
@@ -675,7 +767,7 @@ var PluginContext = class {
675
767
  */
676
768
  requestGeologicalReset(trigger) {
677
769
  this.log(`HMR geological reset scheduled: ${trigger}`);
678
- this.resetCoalescer ??= new ResetCoalescer(() => this.performGeologicalReset(), (err) => this.geologicalResetFailed(err));
770
+ this.resetCoalescer ??= new ResetCoalescer(async () => this.performGeologicalReset(), (err) => this.geologicalResetFailed(err));
679
771
  this.resetCoalescer.request();
680
772
  }
681
773
  /**
@@ -705,18 +797,23 @@ var PluginContext = class {
705
797
  * sources, then invalidate the static/component/system-prop virtual
706
798
  * modules and reload the client.
707
799
  */
708
- performGeologicalReset() {
800
+ async performGeologicalReset() {
801
+ return runExclusiveAnalysis(this, () => this.performGeologicalResetExclusive());
802
+ }
803
+ async performGeologicalResetExclusive() {
709
804
  const resetStart = performance.now();
710
- this.loadSystem();
711
- (0, _animus_ui_extract_pipeline.clearEngineCache)(this.engineApi);
712
- const fileEntries = [];
713
- for (const [path$2, { hash, source }] of this.fileCache) fileEntries.push({
714
- path: path$2,
715
- source,
716
- hash
717
- });
718
- this.runAnalysis(fileEntries);
719
- this.log(`HMR geological reset complete: ${Math.round(performance.now() - resetStart)}ms`);
805
+ const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(this.storedManifest);
806
+ try {
807
+ this.loadSystem();
808
+ const { ok } = await this.analyzeIngested({ beforeAnalysis: () => (0, _animus_ui_extract_pipeline.clearEngineCache)(this.engineApi) });
809
+ if (!ok) return;
810
+ invalidateFileModules(this, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(this.storedManifest)));
811
+ this.log(`HMR geological reset complete: ${Math.round(performance.now() - resetStart)}ms`);
812
+ } finally {
813
+ this.invalidateGeologicalResetModules();
814
+ }
815
+ }
816
+ invalidateGeologicalResetModules() {
720
817
  const server = this.devServer;
721
818
  if (!server) return;
722
819
  for (const moduleId of [
@@ -822,23 +919,14 @@ var PluginContext = class {
822
919
  });
823
920
  }
824
921
  runSelfVerify() {
825
- const failures = [];
826
- if (Object.keys(this.storedManifest?.components ?? {}).length === 0) failures.push("No component CSS produced — check the system file and its includes list");
827
- for (const { specifier, outcome } of this.externalPackageOutcomes) if (outcome === "empty") failures.push(`include '${specifier}' resolved but discovered no component sources`);
828
- else if (outcome === "unresolvable") failures.push(`include '${specifier}' could not be resolved`);
829
- if (!this.system.variableCss.includes(":root")) failures.push("No :root variable block found in variable CSS");
830
- if (`${this.system.variableCss}\n${this.globalCss}\n${this.resolvedComponentCss}`.includes("__TRANSFORM__")) failures.push("Unresolved __TRANSFORM__ placeholders found in CSS output");
831
- if (this.storedManifest && this.resolvedComponentCss.length > 0) {
832
- const assembled = (0, _animus_ui_extract_pipeline.assembleStylesheet)({
833
- layers: this.options.layers,
834
- variableCss: this.system.variableCss,
835
- globalCss: this.globalCss,
836
- componentCss: this.resolvedComponentCss
837
- });
838
- const baseIdx = assembled.search(/@layer\s+anm-base\s*\{/);
839
- const variantsIdx = assembled.search(/@layer\s+anm-variants\s*\{/);
840
- if (baseIdx !== -1 && variantsIdx !== -1 && baseIdx >= variantsIdx) failures.push(`CSS layer ordering violated — @layer anm-base (offset ${baseIdx}) must precede @layer anm-variants (offset ${variantsIdx})`);
841
- }
922
+ const failures = (0, _animus_ui_extract_pipeline.runStructuralSelfCheck)({
923
+ componentCount: Object.keys(this.storedManifest?.components ?? {}).length,
924
+ variableCss: this.system.variableCss,
925
+ globalCss: this.globalCss,
926
+ componentCss: this.resolvedComponentCss,
927
+ layers: this.options.layers,
928
+ externalOutcomes: this.externalPackageOutcomes
929
+ });
842
930
  for (const message of failures) {
843
931
  const line = `[animus:verify] ${message}`;
844
932
  if (this.options.strict) throw new Error(line);
@@ -849,44 +937,6 @@ var PluginContext = class {
849
937
  }
850
938
  };
851
939
  //#endregion
852
- //#region src/module-invalidation.ts
853
- /**
854
- * Evict every module node the dev server holds for each file — every
855
- * environment graph (client, ssr, and any custom environment), by-file node
856
- * sets (covers query-suffixed variants), plus the absolute-path id lookup.
857
- * Falls back to the mixed compat graph for hosts without environment
858
- * graphs. Returns the number of nodes invalidated.
859
- *
860
- * Completeness here is load-bearing: the file-plan diff is the ONLY
861
- * invalidation candidate source, so a node shape this enumeration misses
862
- * stays stale for the life of the server (openspec: dev-transform-coherence,
863
- * "Client and SSR nodes are both evicted").
864
- */
865
- function invalidateFileModules(ctx, relPaths) {
866
- const server = ctx.devServer;
867
- if (!server || relPaths.length === 0) return 0;
868
- const graphs = server.environments ? Object.values(server.environments).map((env) => env?.moduleGraph).filter(Boolean) : [server.moduleGraph].filter(Boolean);
869
- let total = 0;
870
- for (const relPath of relPaths) {
871
- const absPath = (0, path.resolve)(ctx.rootDir, relPath);
872
- let fileCount = 0;
873
- for (const graph of graphs) {
874
- const nodes = /* @__PURE__ */ new Set();
875
- const byFile = graph.getModulesByFile?.(absPath);
876
- if (byFile) for (const mod of byFile) nodes.add(mod);
877
- const byId = graph.getModuleById?.(absPath);
878
- if (byId) nodes.add(byId);
879
- for (const mod of nodes) {
880
- graph.invalidateModule(mod);
881
- fileCount++;
882
- }
883
- }
884
- if (fileCount > 0) ctx.log(`HMR invalidate: ${relPath} (plan changed, ${fileCount} nodes)`);
885
- total += fileCount;
886
- }
887
- return total;
888
- }
889
- //#endregion
890
940
  //#region src/rediscovery.ts
891
941
  /** The current manifest's unresolved-parent drops, parsed from diagnostics
892
942
  * (shared Rust-mirror matcher — the regex lives in manifest-diagnostics). */
@@ -932,15 +982,11 @@ function unresolvedDropFiles(ctx) {
932
982
  * walk actually folded something (a changed discovery domain). The
933
983
  * iteration cap is containment, not semantics.
934
984
  *
935
- * Synchronous by design — it runs inside the sync `transform` hook. `.mdx`
936
- * sources need async preprocessing and are not folded here (they ingest on
937
- * their first watcher edit).
938
- *
939
985
  * Returns whether any re-analysis ran (callers diff plans across the WHOLE
940
986
  * transaction, so a fold-and-reanalyze is invisible to them beyond the
941
987
  * final manifest).
942
988
  */
943
- function stabilizeSourceUniverse(ctx) {
989
+ async function stabilizeSourceUniverse(ctx) {
944
990
  if (ctx.isProd) return false;
945
991
  let reanalyzed = false;
946
992
  for (let iteration = 0; iteration < 3; iteration++) {
@@ -953,7 +999,7 @@ function stabilizeSourceUniverse(ctx) {
953
999
  const memo = barrenWalkMemos.get(ctx);
954
1000
  if (memo && memo.dropKey === dropKey && memo.cacheSize === ctx.fileCache.size) return reanalyzed;
955
1001
  const folded = foldUndiscoveredFiles(ctx);
956
- if (folded === 0) {
1002
+ if (folded.length === 0) {
957
1003
  barrenWalkMemos.set(ctx, {
958
1004
  dropKey,
959
1005
  cacheSize: ctx.fileCache.size
@@ -962,9 +1008,15 @@ function stabilizeSourceUniverse(ctx) {
962
1008
  return reanalyzed;
963
1009
  }
964
1010
  barrenWalkMemos.delete(ctx);
965
- ctx.log(`rediscovery: folded ${folded} on-disk file(s) after unresolved-parent drop`);
1011
+ ctx.log(`rediscovery: folded ${folded.length} on-disk file(s) after unresolved-parent drop`);
966
1012
  reanalyzed = true;
967
- if (ctx.runAnalysis(buildFileEntriesFromCache(ctx.fileCache)) === false) return reanalyzed;
1013
+ let published = false;
1014
+ try {
1015
+ published = (await ctx.analyzeIngested()).ok;
1016
+ } finally {
1017
+ if (!published) for (const key of folded) ctx.fileCache.delete(key);
1018
+ }
1019
+ if (!published) return reanalyzed;
968
1020
  }
969
1021
  if (unresolvedDropFiles(ctx).size > 0) ctx.warn("source-universe rediscovery did not stabilize after bounded retries");
970
1022
  return reanalyzed;
@@ -974,10 +1026,14 @@ function stabilizeSourceUniverse(ctx) {
974
1026
  * folds every eligible file `fileCache` does not hold. Returns the fold
975
1027
  * count.
976
1028
  */
1029
+ /** Returns the cache keys this fold ADDED, so a failed analysis can roll
1030
+ * them back — `runAnalysis` requires callers that advanced the file cache to
1031
+ * restore it, or the content-hash gate suppresses the equal-content retry
1032
+ * forever. */
977
1033
  function foldUndiscoveredFiles(ctx) {
978
- const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
979
- const filePaths = (0, _animus_ui_extract_pipeline.discoverFiles)(ctx.rootDir, ctx.rootDir, excludePatterns, ctx.extensionsSet);
980
- let folded = 0;
1034
+ const excludeMatcher = ctx.excludeMatcher;
1035
+ const filePaths = (0, _animus_ui_extract_pipeline.discoverFiles)(ctx.rootDir, ctx.rootDir, excludeMatcher, ctx.extensionsSet);
1036
+ const folded = [];
981
1037
  for (const filePath of filePaths) {
982
1038
  if ((0, path.extname)(filePath) === ".mdx") continue;
983
1039
  const relPath = (0, path.relative)(ctx.rootDir, filePath);
@@ -992,7 +1048,7 @@ function foldUndiscoveredFiles(ctx) {
992
1048
  hash: (0, _animus_ui_extract_pipeline.contentHash)(source),
993
1049
  source
994
1050
  });
995
- folded++;
1051
+ folded.push(relPath);
996
1052
  }
997
1053
  return folded;
998
1054
  }
@@ -1019,7 +1075,7 @@ const PARENT_PROBE_EXTENSIONS = new Set([
1019
1075
  * engine's own diagnostic.
1020
1076
  */
1021
1077
  function warnInadmissibleParents(ctx, drops) {
1022
- const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
1078
+ const excludeMatcher = ctx.excludeMatcher;
1023
1079
  let warned = warnedVerdicts.get(ctx);
1024
1080
  if (!warned) {
1025
1081
  warned = /* @__PURE__ */ new Set();
@@ -1035,7 +1091,7 @@ function warnInadmissibleParents(ctx, drops) {
1035
1091
  const resolved = (0, _animus_ui_extract_pipeline.resolveAbsolutePathSpecifier)((0, path.resolve)(ctx.rootDir, (0, path.dirname)(drop.file), specifier), PARENT_PROBE_EXTENSIONS);
1036
1092
  if (!resolved) continue;
1037
1093
  const relPath = (0, path.relative)(ctx.rootDir, resolved);
1038
- const excludedBy = excludePatterns.find((pattern) => resolved.includes(pattern) || relPath.includes(pattern));
1094
+ const excludedBy = excludeMatcher.explain(resolved, relPath);
1039
1095
  const reason = excludedBy ? `which is excluded by pattern '${excludedBy}'. Include that file in the extraction universe or remove this extension.` : !(0, _animus_ui_extract_pipeline.isPathWithinRoot)(ctx.rootDir, resolved) ? "outside the extraction root. Declare its package in the system includes or move it under the project root." : !ctx.extensionsSet.has((0, path.extname)(resolved)) ? `whose extension is not in the configured source extensions.` : null;
1040
1096
  if (reason === null) continue;
1041
1097
  const verdictKey = `${drop.file}\0${drop.parent}\0${reason}`;
@@ -1099,7 +1155,7 @@ function rawFallbackDescendants(ctx, relPath) {
1099
1155
  * dev-stylesheet-management, "HMR bridge auto-injected in dev mode"; "Transform
1100
1156
  * emitter unchanged" forbids the emitter importing it).
1101
1157
  */
1102
- function transformSource(ctx, code, id) {
1158
+ async function transformSource(ctx, code, id) {
1103
1159
  if (!ctx.storedManifest) return null;
1104
1160
  if (id.startsWith("\0") || id.startsWith("virtual:animus/")) return null;
1105
1161
  const isExternalPkg = ctx.externalPackageDirs.some((dir) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, id));
@@ -1110,7 +1166,8 @@ function transformSource(ctx, code, id) {
1110
1166
  if (!(0, _animus_ui_extract_pipeline.isPathWithinRoot)(ctx.rootDir, id)) return null;
1111
1167
  }
1112
1168
  if (!ctx.storedManifest.files?.[relativePath]?.length) {
1113
- if (!ctx.isProd && !ctx.fileCache.has(relativePath)) {
1169
+ if (!ctx.isProd && !ctx.fileCache.has(relativePath)) await runExclusiveAnalysis(ctx, async () => {
1170
+ if (ctx.fileCache.has(relativePath)) return;
1114
1171
  if (isExternalPkg) {
1115
1172
  const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, id));
1116
1173
  if (owner) ctx.externalFileOwners[relativePath] = owner[1];
@@ -1121,21 +1178,20 @@ function transformSource(ctx, code, id) {
1121
1178
  source: code
1122
1179
  });
1123
1180
  const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
1124
- const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relativePath);
1125
1181
  let analysisOk = false;
1126
1182
  try {
1127
- analysisOk = ctx.runAnalysis(fileEntries) !== false;
1183
+ analysisOk = (await ctx.analyzeIngested()).ok;
1128
1184
  } finally {
1129
1185
  if (!analysisOk) ctx.fileCache.delete(relativePath);
1130
1186
  }
1131
1187
  if (analysisOk) {
1132
- stabilizeSourceUniverse(ctx);
1188
+ await stabilizeSourceUniverse(ctx);
1133
1189
  invalidateFileModules(ctx, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest), { exclude: relativePath }));
1134
1190
  const compCount = ctx.storedManifest.files?.[relativePath]?.length ?? 0;
1135
1191
  ctx.info(`New file detected: ${relativePath} — ${compCount ? `${compCount} components extracted` : "no components"}`);
1136
1192
  ctx.invalidateExtractedModules();
1137
1193
  }
1138
- }
1194
+ });
1139
1195
  if (!ctx.storedManifest.files?.[relativePath]?.length) {
1140
1196
  if (!ctx.isProd) if (unresolvedDropFiles(ctx).has(relativePath)) ctx.rawExtensionFallbacks.add(relativePath);
1141
1197
  else ctx.rawExtensionFallbacks.delete(relativePath);
@@ -1196,8 +1252,11 @@ function transformSource(ctx, code, id) {
1196
1252
  * graph, so system dependencies registered through `watcher.add` outside the
1197
1253
  * root still reach the reset branch, with an empty `modules` list.
1198
1254
  */
1199
- async function handleHotUpdate(ctx, environment, { type, file, timestamp, modules, read }) {
1255
+ async function handleHotUpdate(ctx, environment, options) {
1200
1256
  if (ctx.isProd) return;
1257
+ return runExclusiveAnalysis(ctx, () => handleHotUpdateExclusive(ctx, environment, options));
1258
+ }
1259
+ async function handleHotUpdateExclusive(ctx, environment, { type, file, timestamp, modules, read }) {
1201
1260
  const ownsEvent = ctx.hotUpdateEvents.claim(environment.name, file, timestamp);
1202
1261
  const absFile = (0, path.resolve)(file);
1203
1262
  ctx.log(`hotUpdate ${type} ${(0, path.relative)(ctx.rootDir, absFile)} env=${environment.name} owns=${ownsEvent}`);
@@ -1209,13 +1268,16 @@ async function handleHotUpdate(ctx, environment, { type, file, timestamp, module
1209
1268
  return [];
1210
1269
  }
1211
1270
  if (type === "delete") {
1212
- if (ownsEvent) pruneDeletedFile(ctx, absFile);
1271
+ if (ownsEvent) await pruneDeletedFile(ctx, absFile);
1213
1272
  return;
1214
1273
  }
1215
1274
  if (ownsEvent) ctx.hotUpdateEvents.record(file, timestamp, await analyzeChangedFile(ctx, file, absFile, read));
1216
1275
  const result = ctx.hotUpdateEvents.resultOf(file, timestamp);
1217
1276
  if (result.kind === "ignored") return;
1218
- if (result.kind === "unchanged") return [];
1277
+ if (result.kind === "unchanged") {
1278
+ if (type === "create") return;
1279
+ return [];
1280
+ }
1219
1281
  return invalidateStaleModules(ctx, environment, modules, result);
1220
1282
  }
1221
1283
  /**
@@ -1277,9 +1339,9 @@ async function reconcileSourceEntry(ctx, absFile, type, read) {
1277
1339
  async function analyzeChangedFile(ctx, file, absFile, read) {
1278
1340
  const ext = (0, path.extname)(file);
1279
1341
  if (!ctx.extensionsSet.has(ext)) return { kind: "ignored" };
1280
- const excludePatterns = ctx.options.exclude ?? DEFAULT_EXCLUDE;
1342
+ const excludeMatcher = ctx.excludeMatcher;
1281
1343
  const isExternalPkg = ctx.externalPackageDirs.some((dir) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, file));
1282
- if (!isExternalPkg && excludePatterns.some((pattern) => file.includes(pattern) || (0, path.relative)(ctx.rootDir, file).includes(pattern))) return { kind: "ignored" };
1344
+ if (!isExternalPkg && excludeMatcher.matches(file, (0, path.relative)(ctx.rootDir, file))) return { kind: "ignored" };
1283
1345
  const relPath = (0, path.relative)(ctx.rootDir, absFile);
1284
1346
  let source;
1285
1347
  try {
@@ -1287,41 +1349,30 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
1287
1349
  } catch {
1288
1350
  return { kind: "ignored" };
1289
1351
  }
1290
- let scannerRelPath = relPath;
1291
- if (ext === ".mdx") {
1292
- const result = await (0, _animus_ui_extract_pipeline.preprocessMdx)(source, relPath);
1293
- if (result.kind === "missing-dep") {
1294
- ctx.warn("⚠ .mdx HMR skipped: @mdx-js/mdx not installed; restart dev server after installing");
1295
- return { kind: "ignored" };
1296
- }
1297
- if (result.kind === "error") {
1298
- ctx.warn(`⚠ MDX preprocessing failed for ${relPath}: ${result.error}`);
1299
- return { kind: "ignored" };
1300
- }
1301
- source = result.source;
1302
- scannerRelPath = relPath + ".tsx";
1303
- }
1304
1352
  const hash = (0, _animus_ui_extract_pipeline.contentHash)(source);
1305
- const cached = ctx.fileCache.get(scannerRelPath);
1353
+ const cached = ctx.fileCache.get(relPath);
1306
1354
  if (cached && cached.hash === hash) {
1307
- ctx.log(`HMR skip: ${scannerRelPath} (unchanged)`);
1355
+ ctx.log(`HMR skip: ${relPath} (unchanged)`);
1308
1356
  return { kind: "unchanged" };
1309
1357
  }
1310
- if (isExternalPkg && !ctx.externalFileOwners[scannerRelPath]) {
1358
+ const priorExternalOwner = ctx.externalFileOwners[relPath];
1359
+ if (isExternalPkg && !priorExternalOwner) {
1311
1360
  const owner = Object.entries(ctx.externalDirOwners).find(([dir]) => (0, _animus_ui_extract_pipeline.isPathWithinRoot)(dir, absFile));
1312
- if (owner) ctx.externalFileOwners[scannerRelPath] = owner[1];
1361
+ if (owner) ctx.externalFileOwners[relPath] = owner[1];
1313
1362
  }
1314
- ctx.fileCache.set(scannerRelPath, {
1363
+ ctx.fileCache.set(relPath, {
1315
1364
  hash,
1316
1365
  source
1317
1366
  });
1318
1367
  const restoreEntry = () => {
1319
- if (cached) ctx.fileCache.set(scannerRelPath, cached);
1320
- else ctx.fileCache.delete(scannerRelPath);
1368
+ if (cached) ctx.fileCache.set(relPath, cached);
1369
+ else ctx.fileCache.delete(relPath);
1370
+ if (priorExternalOwner) ctx.externalFileOwners[relPath] = priorExternalOwner;
1371
+ else delete ctx.externalFileOwners[relPath];
1321
1372
  };
1322
1373
  const hmrStart = performance.now();
1323
1374
  const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
1324
- const directComponentIds = ctx.storedManifest?.files?.[scannerRelPath] ?? [];
1375
+ const directComponentIds = (ctx.sourceOwnership[relPath]?.analysisPaths ?? [relPath]).flatMap((analysisPath) => ctx.storedManifest?.files?.[analysisPath] ?? []);
1325
1376
  const invalidatedIds = new Set(directComponentIds);
1326
1377
  const queue = [...directComponentIds];
1327
1378
  while (queue.length > 0) {
@@ -1336,11 +1387,10 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
1336
1387
  }
1337
1388
  if (ctx.verbose && invalidatedIds.size > directComponentIds.length) ctx.log(`HMR: ${directComponentIds.length} direct + ${invalidatedIds.size - directComponentIds.length} transitive components invalidated`);
1338
1389
  const analysisStart = performance.now();
1339
- const fileEntries = buildFileEntriesFromCache(ctx.fileCache, relPath);
1340
1390
  const systemPropsBefore = systemPropsModuleSource(ctx);
1341
1391
  let analysisOk;
1342
1392
  try {
1343
- analysisOk = ctx.runAnalysis(fileEntries) !== false;
1393
+ analysisOk = (await ctx.analyzeIngested()).ok;
1344
1394
  } catch (e) {
1345
1395
  restoreEntry();
1346
1396
  throw e;
@@ -1349,11 +1399,17 @@ async function analyzeChangedFile(ctx, file, absFile, read) {
1349
1399
  restoreEntry();
1350
1400
  return { kind: "ignored" };
1351
1401
  }
1352
- stabilizeSourceUniverse(ctx);
1402
+ try {
1403
+ await stabilizeSourceUniverse(ctx);
1404
+ } catch (e) {
1405
+ restoreEntry();
1406
+ throw e;
1407
+ }
1353
1408
  const systemPropsChanged = systemPropsModuleSource(ctx) !== systemPropsBefore;
1354
1409
  const analysisMs = Math.round(performance.now() - analysisStart);
1355
1410
  const staleDefinitionFiles = (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest)).filter((defFile) => (0, path.resolve)(ctx.rootDir, defFile) !== absFile);
1356
- const presentationOnly = isPresentationOnlyEdit(ctx, scannerRelPath, source);
1411
+ const nativeEntry = ctx.analysisEntryCache.get(relPath);
1412
+ const presentationOnly = nativeEntry ? isPresentationOnlyEdit(ctx, relPath, nativeEntry.source) : false;
1357
1413
  const hmrMs = Math.round(performance.now() - hmrStart);
1358
1414
  ctx.log(`HMR update: ${relPath} — analysis ${analysisMs}ms, total ${hmrMs}ms${presentationOnly ? " (presentation-only)" : ""}`);
1359
1415
  ctx.logTimingWaterfall(ctx.storedManifest?.timing ?? {});
@@ -1394,16 +1450,18 @@ function isPresentationOnlyEdit(ctx, scannerRelPath, source) {
1394
1450
  * Reconcile a deleted file in dev.
1395
1451
  *
1396
1452
  * Without this the removed file's last-known source stays in `ctx.fileCache`,
1397
- * and `buildFileEntriesFromCache` re-feeds that ghost entry to the engine on
1453
+ * and shared source ingestion re-feeds that ghost original to the engine on
1398
1454
  * every later re-analysis — the deleted component's CSS survives for the life
1399
1455
  * of the process.
1400
1456
  */
1401
- function pruneDeletedFile(ctx, absFile) {
1402
- if (!pruneFileCache(ctx.fileCache, ctx.rootDir, absFile)) return;
1457
+ async function pruneDeletedFile(ctx, absFile) {
1458
+ const relPath = (0, path.relative)(ctx.rootDir, absFile);
1459
+ if (!ctx.fileCache.get(relPath) || !pruneFileCache(ctx.fileCache, ctx.rootDir, absFile)) return;
1403
1460
  const prevPlans = (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest);
1404
- const ok = ctx.runAnalysis(buildFileEntriesFromCache(ctx.fileCache)) !== false;
1461
+ const { ok } = await ctx.analyzeIngested();
1462
+ if (!ok) return;
1405
1463
  ctx.log(`Deleted file pruned: ${(0, path.relative)(ctx.rootDir, absFile)}`);
1406
- if (ok) invalidateFileModules(ctx, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest)));
1464
+ invalidateFileModules(ctx, (0, _animus_ui_extract_pipeline.diffFilePlans)(prevPlans, (0, _animus_ui_extract_pipeline.snapshotFilePlans)(ctx.storedManifest)));
1407
1465
  ctx.invalidateExtractedModules();
1408
1466
  }
1409
1467
  /**
@@ -1513,7 +1571,7 @@ function resolveVirtualId(ctx, id) {
1513
1571
  * system-props modules from manifest-derived state. */
1514
1572
  function loadVirtualModule(ctx, id) {
1515
1573
  const lcssOpts = {
1516
- minify: ctx.options.minify ?? ctx.isProd,
1574
+ minify: ctx.options.minify ?? ctx.emissionProd,
1517
1575
  targets: ctx.lcssTargets,
1518
1576
  warnFn: (msg) => ctx.warn(msg)
1519
1577
  };
@@ -1598,12 +1656,20 @@ if (import.meta.hot) {
1598
1656
  */
1599
1657
  function animusExtract(options) {
1600
1658
  (0, _animus_ui_extract_pipeline.assertNoRetiredEngineSelection)(options.engine);
1659
+ (0, _animus_ui_extract_pipeline.assertKnownOptionKeys)(options, ["verify", "appearanceBootstrap"], [{
1660
+ key: "root",
1661
+ reason: "the Vite driver derives its root from the resolved Vite config"
1662
+ }], {
1663
+ onUnknownKey: "warn",
1664
+ warn: (message) => console.warn(`[animus-extract] ${message}`)
1665
+ });
1601
1666
  const ctx = new PluginContext(options);
1602
1667
  return {
1603
1668
  name: "animus-extract",
1604
1669
  enforce: "pre",
1605
1670
  config(_config, env) {
1606
- return { define: { __ANIMUS_DEV__: env.command !== "build" } };
1671
+ const { mode } = (0, _animus_ui_extract_pipeline.resolveMode)(options.mode, () => env.command === "build" ? "production" : "development");
1672
+ return { define: { __ANIMUS_DEV__: mode === "development" } };
1607
1673
  },
1608
1674
  configureServer(server) {
1609
1675
  ctx.devServer = server;
package/dist/index.d.ts CHANGED
@@ -9,7 +9,22 @@ export interface AnimusExtractOptions {
9
9
  * and global styles — everything the extraction pipeline needs.
10
10
  */
11
11
  system: string;
12
- /** Glob patterns to exclude. */
12
+ /**
13
+ * Module specifier injected for extracted runtime factories.
14
+ *
15
+ * The default preserves the full `@animus-ui/system` runtime. Override this
16
+ * only when the selected entry supplies every terminal present in the
17
+ * analyzed consumer (for example, the framework-neutral class-resolver
18
+ * entry for a consumer containing only `.asClass()` definitions).
19
+ *
20
+ * @default '@animus-ui/system'
21
+ */
22
+ runtimeImport?: string;
23
+ /**
24
+ * Exclusion patterns (substrings, or globs when `*`/`?` present). When
25
+ * set, REPLACES the replaceable defaults (`dist`, `.test.`, `.spec.`);
26
+ * `node_modules`, `.next`, and `.animus` are always excluded.
27
+ */
13
28
  exclude?: string[];
14
29
  /**
15
30
  * File extensions to scan for component definitions and JSX usages.
@@ -46,6 +61,12 @@ export interface AnimusExtractOptions {
46
61
  * - `undefined` (default): minify in prod only
47
62
  */
48
63
  minify?: boolean;
64
+ /**
65
+ * Explicit dev/prod emission mode. Wins over the Vite command signal.
66
+ * When absent, the documented default applies: production when
67
+ * `config.command === 'build'`, development otherwise.
68
+ */
69
+ mode?: 'development' | 'production';
49
70
  /**
50
71
  * Namespace prefix for CSS variables and class names, applied to the
51
72
  * variable map/css (and theme + contextual vars) at system load.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,qGAAqG;IACrG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,mBAAmB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CA0EnE;eAEc,aAAa"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,qGAAqG;IACrG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,mBAAmB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAoGnE;eAEc,aAAa"}
@@ -27,14 +27,10 @@ export declare function unresolvedDropFiles(ctx: PluginContext): ReadonlySet<str
27
27
  * walk actually folded something (a changed discovery domain). The
28
28
  * iteration cap is containment, not semantics.
29
29
  *
30
- * Synchronous by design — it runs inside the sync `transform` hook. `.mdx`
31
- * sources need async preprocessing and are not folded here (they ingest on
32
- * their first watcher edit).
33
- *
34
30
  * Returns whether any re-analysis ran (callers diff plans across the WHOLE
35
31
  * transaction, so a fold-and-reanalyze is invisible to them beyond the
36
32
  * final manifest).
37
33
  */
38
- export declare function stabilizeSourceUniverse(ctx: PluginContext): boolean;
34
+ export declare function stabilizeSourceUniverse(ctx: PluginContext): Promise<boolean>;
39
35
  export {};
40
36
  //# sourceMappingURL=rediscovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rediscovery.d.ts","sourceRoot":"","sources":["../src/rediscovery.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,oBAAoB;IAC5B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;8EAC8E;AAC9E,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,GACjB,oBAAoB,EAAE,CAcxB;AASD;gEACgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAc3E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CA6DnE"}
1
+ {"version":3,"file":"rediscovery.d.ts","sourceRoot":"","sources":["../src/rediscovery.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,oBAAoB;IAC5B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;8EAC8E;AAC9E,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,aAAa,GACjB,oBAAoB,EAAE,CAcxB;AASD;gEACgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAc3E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,OAAO,CAAC,CA4ElB"}
@@ -16,7 +16,7 @@ export declare class ResetCoalescer {
16
16
  private timer;
17
17
  private running;
18
18
  private dirty;
19
- constructor(run: () => void, onError: (err: unknown) => void, quietMs?: number, schedule?: (fn: () => void, ms: number) => unknown, cancel?: (timer: unknown) => void);
19
+ constructor(run: () => void | Promise<void>, onError: (err: unknown) => void, quietMs?: number, schedule?: (fn: () => void, ms: number) => unknown, cancel?: (timer: unknown) => void);
20
20
  /** Ask for a reset; bursts within the quiescence window collapse. */
21
21
  request(): void;
22
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reset-coalescer.d.ts","sourceRoot":"","sources":["../src/reset-coalescer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAKpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAIzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBzB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IAEtB,YACmB,GAAG,EAAE,MAAM,IAAI,EAKf,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,EAC/B,OAAO,SAAK,EACZ,QAAQ,GAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAGpC,EACN,MAAM,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IACS,EACpD;IAEJ,qEAAqE;IACrE,OAAO,IAAI,IAAI,CAqBd;CACF"}
1
+ {"version":3,"file":"reset-coalescer.d.ts","sourceRoot":"","sources":["../src/reset-coalescer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAKpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAIzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBzB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IAEtB,YACmB,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAK/B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,EAC/B,OAAO,SAAK,EACZ,QAAQ,GAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAGpC,EACN,MAAM,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IACS,EACpD;IAEJ,qEAAqE;IACrE,OAAO,IAAI,IAAI,CAsBd;CACF"}
@@ -18,8 +18,8 @@ export declare function applyDevBridgeImport(code: string): string;
18
18
  * dev-stylesheet-management, "HMR bridge auto-injected in dev mode"; "Transform
19
19
  * emitter unchanged" forbids the emitter importing it).
20
20
  */
21
- export declare function transformSource(ctx: PluginContext, code: string, id: string): {
21
+ export declare function transformSource(ctx: PluginContext, code: string, id: string): Promise<{
22
22
  code: string;
23
23
  map: null;
24
- } | null;
24
+ } | null>;
25
25
  //# sourceMappingURL=transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzD;AAiCD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CA4LpC"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzD;AAiCD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,CAAC,CAkM7C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animus-ui/vite-plugin",
3
- "version": "0.1.8",
3
+ "version": "0.1.11",
4
4
  "description": "Animus static CSS extraction Vite plugin",
5
5
  "keywords": [
6
6
  "animus",
@@ -39,7 +39,7 @@
39
39
  "compile": "tsc --noEmit"
40
40
  },
41
41
  "dependencies": {
42
- "@animus-ui/extract": "0.1.8",
42
+ "@animus-ui/extract": "0.1.11",
43
43
  "browserslist": "^4.24.0",
44
44
  "lightningcss": "^1.29.0"
45
45
  },
@@ -51,5 +51,8 @@
51
51
  "@mdx-js/mdx": {
52
52
  "optional": true
53
53
  }
54
+ },
55
+ "engines": {
56
+ "node": ">=22.12.0"
54
57
  }
55
58
  }