@zhin.js/runtime 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,17 +24,25 @@ export class SlotGenerationPreparer {
24
24
  for (const slot of replacements)
25
25
  capabilities.set(slot.id, slot);
26
26
  }
27
- const projected = await new FeatureProjector(this.model.providers.values()).project(current.generation + 1, {
27
+ // Capability-file HMR projects only the owning Features. The complete
28
+ // snapshot below is assembled by retaining every other projection.
29
+ const providers = [...selectedByFeature.keys()].map((feature) => {
30
+ const provider = this.model.providers.get(feature);
31
+ if (!provider)
32
+ throw new Error(`Missing Feature provider for ${feature}`);
33
+ return provider;
34
+ });
35
+ const projected = await new FeatureProjector(providers).project(current.generation + 1, {
28
36
  root: current.root,
29
37
  tree: current.tree,
30
38
  config: current.config,
31
39
  resources: current.resources,
32
40
  capabilities,
33
- });
41
+ }, current.projections);
34
42
  try {
35
43
  const snapshot = createSnapshotView(current.generation + 1, projected.state);
36
44
  const ownership = SourceOwnershipIndex.fromGeneration(this.model.graph, snapshot, this.model.featureIdsByPackageRoot);
37
- const assets = this.model.assets.fork(projected.disposers);
45
+ const assets = this.model.assets.replaceProjections(selectedByFeature.keys(), projected.disposers);
38
46
  return {
39
47
  generation: {
40
48
  snapshot: projected.state,
@@ -46,7 +54,7 @@ export class SlotGenerationPreparer {
46
54
  };
47
55
  }
48
56
  catch (error) {
49
- await disposeProjections(projected.disposers, error);
57
+ await disposeProjections(projected.disposers.values(), error);
50
58
  throw error;
51
59
  }
52
60
  }
@@ -42,6 +42,8 @@ export class SourceOwnershipIndex {
42
42
  }
43
43
  });
44
44
  for (const slot of snapshot.capabilities.values()) {
45
+ if (slot.origin === 'setup')
46
+ continue;
45
47
  index.add({
46
48
  source: slot.source,
47
49
  role: 'capability',
@@ -1,6 +1,7 @@
1
1
  import { type PluginId, type RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
2
  import type { RuntimeEnvironment } from './environment.js';
3
3
  import type { EnvironmentLayers } from './environment-store.js';
4
+ import type { RuntimeConfigDocument } from './config-composer.js';
4
5
  import type { IsolatedPluginRuntimePort } from './isolation.js';
5
6
  import type { ModuleRuntime } from './module-runtime.js';
6
7
  import { type PluginConfigResolver, type RootResourceInstaller } from './plugin-scope-assembler.js';
@@ -15,10 +16,11 @@ export declare class SubtreeGenerationPreparer {
15
16
  private readonly model;
16
17
  private readonly graph;
17
18
  private readonly configResolver;
19
+ private readonly primaryConfigDocument;
18
20
  private readonly environment;
19
21
  private readonly installResources?;
20
22
  private readonly environmentLayers;
21
23
  private readonly isolation?;
22
- constructor(modules: ModuleRuntime, model: RuntimeGenerationModel, graph: ProjectGraph, configResolver: PluginConfigResolver, environment: RuntimeEnvironment, installResources?: RootResourceInstaller | undefined, environmentLayers?: EnvironmentLayers, isolation?: IsolatedPluginRuntimePort | undefined);
24
+ constructor(modules: ModuleRuntime, model: RuntimeGenerationModel, graph: ProjectGraph, configResolver: PluginConfigResolver, primaryConfigDocument: RuntimeConfigDocument, environment: RuntimeEnvironment, installResources?: RootResourceInstaller | undefined, environmentLayers?: EnvironmentLayers, isolation?: IsolatedPluginRuntimePort | undefined);
23
25
  prepare(current: RuntimeSnapshot, roots: readonly PluginId[]): Promise<PreparedRuntimeGeneration>;
24
26
  }
@@ -4,6 +4,7 @@ import { FeatureProjector, composeGenerationHandoffs } from './feature-projector
4
4
  import { NodeDiscoveryHost } from './node-discovery-host.js';
5
5
  import { PluginScopeAssembler, } from './plugin-scope-assembler.js';
6
6
  import { SourceOwnershipIndex } from './source-ownership.js';
7
+ import { addCapabilitySlot, featureSetupAliases, mergeSetupCapabilities, } from './setup-capabilities.js';
7
8
  export class SubtreeTopologyChangedError extends Error {
8
9
  constructor(message) {
9
10
  super(message);
@@ -16,15 +17,17 @@ export class SubtreeGenerationPreparer {
16
17
  model;
17
18
  graph;
18
19
  configResolver;
20
+ primaryConfigDocument;
19
21
  environment;
20
22
  installResources;
21
23
  environmentLayers;
22
24
  isolation;
23
- constructor(modules, model, graph, configResolver, environment, installResources, environmentLayers = {}, isolation) {
25
+ constructor(modules, model, graph, configResolver, primaryConfigDocument, environment, installResources, environmentLayers = {}, isolation) {
24
26
  this.modules = modules;
25
27
  this.model = model;
26
28
  this.graph = graph;
27
29
  this.configResolver = configResolver;
30
+ this.primaryConfigDocument = primaryConfigDocument;
28
31
  this.environment = environment;
29
32
  this.installResources = installResources;
30
33
  this.environmentLayers = environmentLayers;
@@ -33,14 +36,15 @@ export class SubtreeGenerationPreparer {
33
36
  async prepare(current, roots) {
34
37
  const nodes = indexGraph(this.graph);
35
38
  assertCompatibleTopology(indexGraph(this.model.graph), nodes, roots);
36
- const plugins = new PluginScopeAssembler(this.modules, this.configResolver, this.environment, this.installResources, this.environmentLayers, {
39
+ const plugins = new PluginScopeAssembler(this.modules, this.configResolver, this.environment, this.primaryConfigDocument, this.installResources, this.environmentLayers, {
37
40
  scopes: this.model.scopes,
38
41
  tree: current.tree,
39
42
  config: current.config,
40
43
  resources: current.resources,
41
44
  }, this.isolation);
45
+ plugins.installSetupFeatureAliases(featureSetupAliases(this.model.providers.values()));
42
46
  plugins.removeSubtrees(roots);
43
- const projectionDisposers = [];
47
+ const projectionDisposers = new Map();
44
48
  try {
45
49
  for (const root of roots) {
46
50
  const node = nodes.get(root);
@@ -53,6 +57,7 @@ export class SubtreeGenerationPreparer {
53
57
  if (roots.some((root) => isWithin(slot.owner, root)))
54
58
  capabilities.delete(id);
55
59
  }
60
+ mergeSetupCapabilities(capabilities, plugins.setupCapabilities(), this.model.providers, this.model.rootsByFeature);
56
61
  const discovery = new FeatureDiscovery(new NodeDiscoveryHost(this.modules));
57
62
  for (const provider of this.model.providers.values()) {
58
63
  const affectedRoots = (this.model.rootsByFeature.get(provider.id) ?? [])
@@ -61,7 +66,7 @@ export class SubtreeGenerationPreparer {
61
66
  continue;
62
67
  const slots = await discovery.discover(provider, affectedRoots);
63
68
  for (const slot of slots)
64
- capabilities.set(slot.id, slot);
69
+ addCapabilitySlot(capabilities, slot);
65
70
  }
66
71
  const projected = await new FeatureProjector(this.model.providers.values()).project(current.generation + 1, {
67
72
  root: current.root,
@@ -70,7 +75,9 @@ export class SubtreeGenerationPreparer {
70
75
  resources: plugins.resources,
71
76
  capabilities,
72
77
  });
73
- projectionDisposers.push(...projected.disposers);
78
+ for (const [feature, dispose] of projected.disposers) {
79
+ projectionDisposers.set(feature, dispose);
80
+ }
74
81
  const snapshot = createSnapshotView(current.generation + 1, projected.state);
75
82
  const ownership = SourceOwnershipIndex.fromGeneration(this.graph, snapshot, this.model.featureIdsByPackageRoot);
76
83
  const replacements = new Map(plugins.createdScopeDisposers());
@@ -93,7 +100,7 @@ export class SubtreeGenerationPreparer {
93
100
  };
94
101
  }
95
102
  catch (error) {
96
- await rollback(plugins.createdScopeDisposers().map(([, dispose]) => dispose), projectionDisposers, error);
103
+ await rollback(plugins.createdScopeDisposers().map(([, dispose]) => dispose), [...projectionDisposers.values()], error);
97
104
  throw error;
98
105
  }
99
106
  }
@@ -1,6 +1,7 @@
1
1
  import { type RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
2
  import type { RuntimeEnvironment } from './environment.js';
3
3
  import type { EnvironmentLayers } from './environment-store.js';
4
+ import type { RuntimeConfigDocument } from './config-composer.js';
4
5
  import type { IsolatedPluginRuntimePort } from './isolation.js';
5
6
  import type { ModuleRuntime } from './module-runtime.js';
6
7
  import { type PluginConfigResolver, type RootResourceInstaller } from './plugin-scope-assembler.js';
@@ -13,10 +14,11 @@ export declare class TopologyGenerationPreparer {
13
14
  private readonly model;
14
15
  private readonly graph;
15
16
  private readonly configResolver;
17
+ private readonly primaryConfigDocument;
16
18
  private readonly environment;
17
19
  private readonly installResources?;
18
20
  private readonly environmentLayers;
19
21
  private readonly isolation?;
20
- constructor(modules: ModuleRuntime, model: RuntimeGenerationModel, graph: ProjectGraph, configResolver: PluginConfigResolver, environment: RuntimeEnvironment, installResources?: RootResourceInstaller | undefined, environmentLayers?: EnvironmentLayers, isolation?: IsolatedPluginRuntimePort | undefined);
22
+ constructor(modules: ModuleRuntime, model: RuntimeGenerationModel, graph: ProjectGraph, configResolver: PluginConfigResolver, primaryConfigDocument: RuntimeConfigDocument, environment: RuntimeEnvironment, installResources?: RootResourceInstaller | undefined, environmentLayers?: EnvironmentLayers, isolation?: IsolatedPluginRuntimePort | undefined);
21
23
  prepare(current: RuntimeSnapshot): Promise<PreparedRuntimeGeneration | undefined>;
22
24
  }
@@ -6,6 +6,7 @@ import { FeatureProjector, composeGenerationHandoffs } from './feature-projector
6
6
  import { NodeDiscoveryHost } from './node-discovery-host.js';
7
7
  import { PluginScopeAssembler, } from './plugin-scope-assembler.js';
8
8
  import { SourceOwnershipIndex } from './source-ownership.js';
9
+ import { addCapabilitySlot, featureSetupAliases, mergeSetupCapabilities, } from './setup-capabilities.js';
9
10
  import { TopologyTransactionPlanner, collapseRoots, graphNodes, graphOrder, isWithin, } from './topology-transaction.js';
10
11
  /** Prepares manifest topology changes without rebuilding stable Plugin Scopes. */
11
12
  export class TopologyGenerationPreparer {
@@ -13,15 +14,17 @@ export class TopologyGenerationPreparer {
13
14
  model;
14
15
  graph;
15
16
  configResolver;
17
+ primaryConfigDocument;
16
18
  environment;
17
19
  installResources;
18
20
  environmentLayers;
19
21
  isolation;
20
- constructor(modules, model, graph, configResolver, environment, installResources, environmentLayers = {}, isolation) {
22
+ constructor(modules, model, graph, configResolver, primaryConfigDocument, environment, installResources, environmentLayers = {}, isolation) {
21
23
  this.modules = modules;
22
24
  this.model = model;
23
25
  this.graph = graph;
24
26
  this.configResolver = configResolver;
27
+ this.primaryConfigDocument = primaryConfigDocument;
25
28
  this.environment = environment;
26
29
  this.installResources = installResources;
27
30
  this.environmentLayers = environmentLayers;
@@ -39,12 +42,13 @@ export class TopologyGenerationPreparer {
39
42
  if (!plan.changed)
40
43
  return undefined;
41
44
  const featureTopology = await this.#loadFeatureTopology(plan);
42
- const plugins = new PluginScopeAssembler(this.modules, this.configResolver, this.environment, this.installResources, this.environmentLayers, {
45
+ const plugins = new PluginScopeAssembler(this.modules, this.configResolver, this.environment, this.primaryConfigDocument, this.installResources, this.environmentLayers, {
43
46
  scopes: this.model.scopes,
44
47
  tree: current.tree,
45
48
  config: current.config,
46
49
  resources: current.resources,
47
50
  }, this.isolation);
51
+ plugins.installSetupFeatureAliases(featureSetupAliases(featureTopology.providers.values()));
48
52
  const setupRoots = collapseRoots([
49
53
  ...plan.addedPluginRoots,
50
54
  ...plan.replacedPluginRoots,
@@ -54,7 +58,7 @@ export class TopologyGenerationPreparer {
54
58
  ...plan.replacedPluginRoots,
55
59
  ]);
56
60
  plugins.removeSubtrees(removalRoots);
57
- const projectionDisposers = [];
61
+ const projectionDisposers = new Map();
58
62
  try {
59
63
  for (const root of setupRoots) {
60
64
  const node = nextNodes.get(root);
@@ -66,6 +70,7 @@ export class TopologyGenerationPreparer {
66
70
  // remove, move, or reorder operations.
67
71
  plugins.synchronizeTree(this.graph.root);
68
72
  const capabilities = await this.#prepareCapabilities(current, plan, setupRoots, featureTopology);
73
+ mergeSetupCapabilities(capabilities, plugins.setupCapabilities(), featureTopology.providers, featureTopology.rootsByFeature);
69
74
  const projected = await new FeatureProjector(featureTopology.providers.values()).project(current.generation + 1, {
70
75
  root: current.root,
71
76
  tree: plugins.tree,
@@ -73,7 +78,9 @@ export class TopologyGenerationPreparer {
73
78
  resources: plugins.resources,
74
79
  capabilities,
75
80
  });
76
- projectionDisposers.push(...projected.disposers);
81
+ for (const [feature, dispose] of projected.disposers) {
82
+ projectionDisposers.set(feature, dispose);
83
+ }
77
84
  const snapshot = createSnapshotView(current.generation + 1, projected.state);
78
85
  const ownership = SourceOwnershipIndex.fromGeneration(this.graph, snapshot, featureTopology.featureIdsByPackageRoot);
79
86
  const replacements = new Map(plugins.createdScopeDisposers());
@@ -96,7 +103,7 @@ export class TopologyGenerationPreparer {
96
103
  };
97
104
  }
98
105
  catch (error) {
99
- await rollback(plugins.createdScopeDisposers().map(([, dispose]) => dispose), projectionDisposers, error);
106
+ await rollback(plugins.createdScopeDisposers().map(([, dispose]) => dispose), [...projectionDisposers.values()], error);
100
107
  throw error;
101
108
  }
102
109
  }
@@ -175,7 +182,7 @@ export class TopologyGenerationPreparer {
175
182
  if (!provider)
176
183
  throw new Error(`Missing Feature provider for ${feature}`);
177
184
  for (const slot of await discovery.discover(provider, selected)) {
178
- capabilities.set(slot.id, slot);
185
+ addCapabilitySlot(capabilities, slot);
179
186
  }
180
187
  }
181
188
  return capabilities;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/runtime",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Static Plugin graph, generation transaction and HMR Root runtime for Zhin.js",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -18,22 +18,22 @@
18
18
  "dependencies": {
19
19
  "ajv": "8.18.0",
20
20
  "semver": "7.8.5",
21
- "@zhin.js/feature-kit": "1.0.1",
22
- "@zhin.js/plugin-runtime": "1.0.1"
21
+ "@zhin.js/feature-kit": "1.0.3",
22
+ "@zhin.js/plugin-runtime": "1.1.1"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^26.1.0",
26
26
  "typescript": "^6.0.3",
27
- "@zhin.js/adapter": "1.0.1",
28
- "@zhin.js/agent-feature": "1.0.1",
29
- "@zhin.js/command": "1.0.1",
30
- "@zhin.js/layout": "1.0.1",
31
- "@zhin.js/mcp-feature": "1.0.1",
32
- "@zhin.js/middleware": "1.0.1",
33
- "@zhin.js/component": "1.0.1",
34
- "@zhin.js/page": "1.0.1",
35
- "@zhin.js/skill": "1.0.1",
36
- "@zhin.js/tool": "1.0.1"
27
+ "@zhin.js/adapter": "1.1.1",
28
+ "@zhin.js/agent-feature": "1.0.3",
29
+ "@zhin.js/command": "1.0.3",
30
+ "@zhin.js/component": "1.0.3",
31
+ "@zhin.js/layout": "1.0.3",
32
+ "@zhin.js/mcp-feature": "1.0.3",
33
+ "@zhin.js/middleware": "1.0.3",
34
+ "@zhin.js/page": "1.0.3",
35
+ "@zhin.js/skill": "1.0.3",
36
+ "@zhin.js/tool": "1.0.3"
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",