@antelopejs/core 1.4.6 → 1.4.8

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 (77) hide show
  1. package/dist/core/cli/commands/module/init.js +1 -1
  2. package/dist/core/cli/commands/module/init.js.map +1 -1
  3. package/dist/core/cli/commands/project/start.js +5 -1
  4. package/dist/core/cli/commands/project/start.js.map +1 -1
  5. package/dist/core/cli/full-cli.d.ts +3 -0
  6. package/dist/core/cli/full-cli.js +68 -0
  7. package/dist/core/cli/full-cli.js.map +1 -0
  8. package/dist/core/cli/index.d.ts +2 -3
  9. package/dist/core/cli/index.js +56 -69
  10. package/dist/core/cli/index.js.map +1 -1
  11. package/dist/core/cli/package-manager.d.ts +3 -1
  12. package/dist/core/cli/package-manager.js +50 -14
  13. package/dist/core/cli/package-manager.js.map +1 -1
  14. package/dist/core/cli/production-start.d.ts +10 -0
  15. package/dist/core/cli/production-start.js +87 -0
  16. package/dist/core/cli/production-start.js.map +1 -0
  17. package/dist/core/interface-registry.d.ts +6 -1
  18. package/dist/core/interface-registry.js +45 -2
  19. package/dist/core/interface-registry.js.map +1 -1
  20. package/dist/core/module-context.d.ts +7 -0
  21. package/dist/core/module-context.js +60 -0
  22. package/dist/core/module-context.js.map +1 -0
  23. package/dist/core/module-lifecycle.d.ts +7 -1
  24. package/dist/core/module-lifecycle.js +47 -10
  25. package/dist/core/module-lifecycle.js.map +1 -1
  26. package/dist/core/module-manager.d.ts +21 -4
  27. package/dist/core/module-manager.js +333 -129
  28. package/dist/core/module-manager.js.map +1 -1
  29. package/dist/core/module-registry.d.ts +1 -0
  30. package/dist/core/module-registry.js +3 -0
  31. package/dist/core/module-registry.js.map +1 -1
  32. package/dist/core/module-tracker.d.ts +1 -0
  33. package/dist/core/module-tracker.js +5 -1
  34. package/dist/core/module-tracker.js.map +1 -1
  35. package/dist/core/module.d.ts +3 -1
  36. package/dist/core/module.js +51 -28
  37. package/dist/core/module.js.map +1 -1
  38. package/dist/core/resolution/interface-resolution.js +7 -13
  39. package/dist/core/resolution/interface-resolution.js.map +1 -1
  40. package/dist/core/resolution/package-resolution.d.ts +14 -0
  41. package/dist/core/resolution/package-resolution.js +95 -0
  42. package/dist/core/resolution/package-resolution.js.map +1 -0
  43. package/dist/core/resolution/path-mapper.js +1 -1
  44. package/dist/core/resolution/path-mapper.js.map +1 -1
  45. package/dist/core/resolution/resolver-detour.d.ts +2 -2
  46. package/dist/core/resolution/resolver-detour.js +114 -22
  47. package/dist/core/resolution/resolver-detour.js.map +1 -1
  48. package/dist/core/resolution/resolver.d.ts +34 -0
  49. package/dist/core/resolution/resolver.js +233 -8
  50. package/dist/core/resolution/resolver.js.map +1 -1
  51. package/dist/core/resolution/stub-interface-runtime.js +11 -1
  52. package/dist/core/resolution/stub-interface-runtime.js.map +1 -1
  53. package/dist/core/runtime/dev-server-registry.js +4 -2
  54. package/dist/core/runtime/dev-server-registry.js.map +1 -1
  55. package/dist/core/runtime/launch-sequence.js +78 -11
  56. package/dist/core/runtime/launch-sequence.js.map +1 -1
  57. package/dist/core/runtime/module-loading.d.ts +1 -0
  58. package/dist/core/runtime/module-loading.js +92 -25
  59. package/dist/core/runtime/module-loading.js.map +1 -1
  60. package/dist/core/runtime/project-launch.d.ts +5 -0
  61. package/dist/core/runtime/project-launch.js +184 -0
  62. package/dist/core/runtime/project-launch.js.map +1 -0
  63. package/dist/core/runtime/runtime-bootstrap.d.ts +1 -0
  64. package/dist/core/runtime/runtime-bootstrap.js +11 -2
  65. package/dist/core/runtime/runtime-bootstrap.js.map +1 -1
  66. package/dist/core/shutdown/shutdown-manager.js +8 -2
  67. package/dist/core/shutdown/shutdown-manager.js.map +1 -1
  68. package/dist/core/test/test-context.d.ts +1 -1
  69. package/dist/core/test/test-context.js +1 -1
  70. package/dist/core/test/test-context.js.map +1 -1
  71. package/dist/core/test/test-module.js +18 -13
  72. package/dist/core/test/test-module.js.map +1 -1
  73. package/dist/index.d.ts +1 -1
  74. package/dist/index.js +13 -113
  75. package/dist/index.js.map +1 -1
  76. package/dist/types/module.types.d.ts +1 -1
  77. package/package.json +4 -3
@@ -36,10 +36,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ModuleManager = void 0;
37
37
  const path = __importStar(require("node:path"));
38
38
  const logging_1 = require("@antelopejs/interface-core/logging");
39
+ const semver_1 = require("semver");
40
+ const types_1 = require("../types");
39
41
  const interface_registry_1 = require("./interface-registry");
40
42
  const module_1 = require("./module");
43
+ const module_context_1 = require("./module-context");
41
44
  const module_registry_1 = require("./module-registry");
42
45
  const module_tracker_1 = require("./module-tracker");
46
+ const package_resolution_1 = require("./resolution/package-resolution");
43
47
  const path_mapper_1 = require("./resolution/path-mapper");
44
48
  const resolver_1 = require("./resolution/resolver");
45
49
  const resolver_detour_1 = require("./resolution/resolver-detour");
@@ -52,9 +56,13 @@ class ModuleManager {
52
56
  moduleTracker;
53
57
  resolverDetour;
54
58
  resolvedAssociations = new Map();
59
+ resolvedConnections = new Map();
60
+ selectedProviders = new Map();
55
61
  staticModules = [];
56
62
  loaded = new Map();
57
- stubbedInterfacePaths = new Map();
63
+ stubbedInterfacePackages = new Map();
64
+ interfacePackagePlans = new Map();
65
+ pendingCleanup = [];
58
66
  startupOrder = [];
59
67
  constructor(deps = {}) {
60
68
  this.registry = deps.registry ?? new module_registry_1.ModuleRegistry();
@@ -160,41 +168,37 @@ class ModuleManager {
160
168
  return this.resolvedAssociations.get(moduleId)?.has(interfaceName) ?? false;
161
169
  }
162
170
  registerStubbedInterfaces(stubbed) {
163
- for (const { moduleId, interfacePackage, standalone } of stubbed) {
164
- if (this.stubbedInterfacePaths.has(interfacePackage)) {
165
- continue;
166
- }
167
- const consumerFolder = this.loaded.get(moduleId)?.module.manifest.folder;
168
- if (!consumerFolder) {
169
- continue;
170
- }
171
- const pkgRoot = this.resolveInterfacePackageRoot(interfacePackage, consumerFolder);
172
- if (!pkgRoot) {
173
- continue;
174
- }
175
- this.stubbedInterfacePaths.set(interfacePackage, pkgRoot);
176
- this.resolver.interfacePackages.set(interfacePackage, pkgRoot);
177
- (0, stub_interface_runtime_1.logStubInterfaceWarningOnce)(interfacePackage, standalone);
171
+ const packageNames = new Set(stubbed.map((entry) => entry.interfacePackage));
172
+ for (const packageName of packageNames) {
173
+ const entries = stubbed.filter((entry) => entry.interfacePackage === packageName);
174
+ this.registerStubbedInterfacePackage(packageName, entries);
178
175
  }
179
176
  }
180
- resolveInterfacePackageRoot(ifacePkg, fromFolder) {
181
- try {
182
- const mainPath = require.resolve(ifacePkg, { paths: [fromFolder] });
183
- return extractPackageRoot(mainPath, ifacePkg);
184
- }
185
- catch {
186
- return undefined;
177
+ registerStubbedInterfacePackage(packageName, entries) {
178
+ const consumers = this.collectInterfacePackageConsumers(packageName);
179
+ const canonicalPackage = consumers.find((consumer) => consumer.resolvedPackage)?.resolvedPackage;
180
+ if (!canonicalPackage) {
181
+ return;
187
182
  }
183
+ this.stubbedInterfacePackages.set(packageName, canonicalPackage);
184
+ this.interfacePackagePlans.set(packageName, {
185
+ canonicalPackage,
186
+ consumers,
187
+ });
188
+ this.registerInterfacePackage(packageName, canonicalPackage);
189
+ (0, stub_interface_runtime_1.logStubInterfaceWarningOnce)(packageName, entries.some((entry) => entry.standalone));
188
190
  }
189
191
  applyInterfaceStubs() {
190
192
  const implemented = this.collectImplementedInterfaces();
191
- for (const [interfaceName, pkgRoot] of [...this.stubbedInterfacePaths]) {
193
+ for (const [interfaceName, resolvedPackage] of [
194
+ ...this.stubbedInterfacePackages,
195
+ ]) {
192
196
  if (implemented.has(interfaceName)) {
193
- this.stubbedInterfacePaths.delete(interfaceName);
197
+ this.stubbedInterfacePackages.delete(interfaceName);
194
198
  continue;
195
199
  }
196
200
  if (!this.resolver.interfacePackages.has(interfaceName)) {
197
- this.resolver.interfacePackages.set(interfaceName, pkgRoot);
201
+ this.registerInterfacePackage(interfaceName, resolvedPackage);
198
202
  }
199
203
  try {
200
204
  require(interfaceName);
@@ -203,7 +207,7 @@ class ModuleManager {
203
207
  Logger.Error(`Failed to load interface '${interfaceName}':`, err);
204
208
  continue;
205
209
  }
206
- (0, stub_interface_runtime_1.neutralizeInterfacePackage)(pkgRoot, interfaceName);
210
+ (0, stub_interface_runtime_1.neutralizeInterfacePackage)(resolvedPackage.root, interfaceName);
207
211
  }
208
212
  }
209
213
  collectImplementedInterfaces() {
@@ -218,84 +222,143 @@ class ModuleManager {
218
222
  return implemented;
219
223
  }
220
224
  async constructAll() {
221
- this.resolverDetour.attach();
222
- this.applyInterfaceStubs();
225
+ const leaseAcquired = this.resolverDetour.attach();
226
+ const modules = [...this.loaded.values()];
223
227
  try {
224
- await Promise.all([...this.loaded.values()].map(({ module, config }) => module.construct(config.config).catch((err) => {
225
- Logger.Error(`Failed to construct module:`);
226
- Logger.Error(` - ID: ${module.id}`);
227
- Logger.Error(` - Version: ${module.version}`);
228
- Logger.Error(" - Error:", err);
229
- throw err;
230
- })));
231
- }
232
- catch (err) {
233
- this.resolverDetour.detach();
234
- throw err;
228
+ this.validateInterfacePackages();
229
+ this.applyInterfaceStubs();
230
+ }
231
+ catch (error) {
232
+ if (leaseAcquired) {
233
+ throw aggregateErrors([error, ...this.releaseRuntimeState()], "Failed to construct modules");
234
+ }
235
+ throw error;
235
236
  }
237
+ const results = await Promise.allSettled(modules.map(({ module, config }) => this.constructModule(module, config.config)));
238
+ const errors = collectRejectedErrors(results);
239
+ if (errors.length === 0) {
240
+ return;
241
+ }
242
+ const cleanupCandidates = modules.filter(({ module }) => module.state !== types_1.ModuleState.Loaded);
243
+ const cleanupErrors = await runModuleOperations(cleanupCandidates.reverse(), (module) => module.destroy());
244
+ if (leaseAcquired) {
245
+ cleanupErrors.push(...this.releaseRuntimeState());
246
+ }
247
+ throw new AggregateError([...errors, ...cleanupErrors], "Failed to construct modules");
236
248
  }
237
249
  async constructModules(modules) {
238
- this.resolverDetour.attach();
239
- this.applyInterfaceStubs();
240
- await Promise.all(modules.map(({ module, config }) => module.construct(config.config).catch((err) => {
241
- Logger.Error(`Failed to construct module:`);
242
- Logger.Error(` - ID: ${module.id}`);
243
- Logger.Error(` - Version: ${module.version}`);
244
- Logger.Error(" - Error:", err);
245
- throw err;
246
- })));
247
- }
248
- startAll() {
249
- for (const { module } of this.loaded.values()) {
250
- module.start();
251
- this.trackModuleStart(module.id);
250
+ const leaseAcquired = this.resolverDetour.attach();
251
+ try {
252
+ this.validateInterfacePackages();
253
+ this.applyInterfaceStubs();
254
+ await Promise.all(modules.map(({ module, config }) => this.constructModule(module, config.config)));
252
255
  }
253
- }
254
- startModules(modules) {
255
- for (const { module } of modules) {
256
- module.start();
257
- this.trackModuleStart(module.id);
256
+ catch (error) {
257
+ if (leaseAcquired) {
258
+ throw aggregateErrors([error, ...this.releaseRuntimeState()], "Failed to construct modules");
259
+ }
260
+ throw error;
258
261
  }
259
262
  }
260
- async stopAll() {
261
- const reverseOrder = [...this.startupOrder].reverse();
262
- const idsToStop = reverseOrder.length > 0
263
- ? reverseOrder
264
- : [...this.loaded.keys()].reverse();
265
- for (const id of idsToStop) {
266
- const entry = this.loaded.get(id);
267
- if (!entry) {
268
- continue;
269
- }
263
+ async startAll() {
264
+ try {
265
+ await this.startModules([...this.loaded.values()]);
266
+ }
267
+ catch (error) {
268
+ let cleanupErrors = [];
270
269
  try {
271
- await entry.module.stop();
270
+ await this.destroyAll();
272
271
  }
273
- catch (error) {
274
- Logger.Error(`Failed to stop module ${id}:`, error);
272
+ catch (cleanupError) {
273
+ cleanupErrors = unpackErrors(cleanupError);
275
274
  }
275
+ throw new AggregateError([...unpackErrors(error), ...cleanupErrors], "Failed to start modules");
276
276
  }
277
+ }
278
+ async startModules(modules) {
279
+ modules.forEach(({ module }) => {
280
+ this.trackModuleStart(module.id);
281
+ });
282
+ const results = await Promise.allSettled(modules.map(({ module }) => module.start()));
283
+ const errors = collectRejectedErrors(results);
284
+ if (errors.length > 0) {
285
+ throw new AggregateError(errors, "Failed to start modules");
286
+ }
287
+ }
288
+ async stopAll() {
289
+ const modules = this.getReverseLifecycleModules();
290
+ const errors = await runModuleOperations(modules, (module) => module.stop());
277
291
  this.startupOrder = [];
292
+ if (errors.length > 0) {
293
+ throw new AggregateError(errors, "Failed to stop modules");
294
+ }
278
295
  }
279
296
  async destroyAll() {
280
- const reverseOrder = [...this.startupOrder].reverse();
281
- const idsToDestroy = reverseOrder.length > 0
282
- ? reverseOrder
283
- : [...this.loaded.keys()].reverse();
297
+ const modules = this.getReverseLifecycleModules();
298
+ const results = await runTrackedModuleOperations(modules, (module) => module.destroy());
299
+ this.pendingCleanup = results.failed.filter(({ module }) => module.state !== types_1.ModuleState.Loaded);
300
+ const errors = [...results.errors, ...this.clearManagedState()];
301
+ if (errors.length > 0) {
302
+ throw new AggregateError(errors, "Failed to destroy modules");
303
+ }
304
+ }
305
+ async constructModule(module, config) {
284
306
  try {
285
- for (const id of idsToDestroy) {
286
- const entry = this.loaded.get(id);
287
- if (!entry) {
288
- continue;
289
- }
290
- await entry.module.destroy();
307
+ await module.construct(config);
308
+ }
309
+ catch (error) {
310
+ Logger.Error(`Failed to construct module:`);
311
+ Logger.Error(` - ID: ${module.id}`);
312
+ Logger.Error(` - Version: ${module.version}`);
313
+ Logger.Error(" - Error:", error);
314
+ throw error;
315
+ }
316
+ }
317
+ getReverseLifecycleModules() {
318
+ const orderedIds = [...this.startupOrder].reverse();
319
+ const seen = new Set(orderedIds);
320
+ for (const id of [...this.loaded.keys()].reverse()) {
321
+ if (!seen.has(id)) {
322
+ orderedIds.push(id);
291
323
  }
292
324
  }
293
- finally {
294
- this.startupOrder = [];
295
- this.stubbedInterfacePaths.clear();
296
- (0, stub_interface_runtime_1.clearStubInterfaceWarnings)();
325
+ const loadedModules = orderedIds.flatMap((id) => {
326
+ const entry = this.loaded.get(id);
327
+ return entry ? [entry] : [];
328
+ });
329
+ const loadedInstances = new Set(loadedModules.map(({ module }) => module));
330
+ return [
331
+ ...loadedModules,
332
+ ...this.pendingCleanup.filter(({ module }) => !loadedInstances.has(module)),
333
+ ];
334
+ }
335
+ clearManagedState() {
336
+ this.loaded.clear();
337
+ this.staticModules.length = 0;
338
+ this.registry.clear();
339
+ this.resolvedAssociations.clear();
340
+ this.resolver.moduleByFolder.clear();
341
+ this.resolver.modulesById.clear();
342
+ this.resolver.interfacePackages.clear();
343
+ this.resolver.interfacePackageEntries.clear();
344
+ this.resolver.interfacePackageResolveFrom.clear();
345
+ this.interfacePackagePlans.clear();
346
+ this.startupOrder = [];
347
+ return this.releaseRuntimeState();
348
+ }
349
+ releaseRuntimeState() {
350
+ const errors = [];
351
+ this.stubbedInterfacePackages.clear();
352
+ (0, stub_interface_runtime_1.clearStubInterfaceWarnings)();
353
+ this.moduleTracker.clear();
354
+ this.interfaceRegistry.clear();
355
+ try {
297
356
  this.resolverDetour.detach();
298
357
  }
358
+ catch (error) {
359
+ errors.push(error);
360
+ }
361
+ return errors;
299
362
  }
300
363
  trackModuleStart(moduleId) {
301
364
  this.startupOrder = this.startupOrder.filter((id) => id !== moduleId);
@@ -304,13 +367,20 @@ class ModuleManager {
304
367
  rebuildAssociations() {
305
368
  const interfaceSources = this.collectInterfaceSources();
306
369
  this.buildModuleAssociations(interfaceSources);
370
+ this.configureModuleContexts();
307
371
  }
308
372
  collectInterfaceSources() {
309
373
  this.resolver.moduleByFolder.clear();
310
374
  this.resolver.modulesById.clear();
311
375
  this.resolver.interfacePackages.clear();
376
+ this.resolver.interfacePackageEntries.clear();
377
+ this.resolver.interfacePackageResolveFrom.clear();
378
+ this.interfacePackagePlans.clear();
312
379
  this.resolvedAssociations.clear();
380
+ this.resolvedConnections.clear();
381
+ this.selectedProviders.clear();
313
382
  this.moduleTracker.clear();
383
+ this.interfaceRegistry.clear();
314
384
  const interfaceSources = new Map();
315
385
  for (const { module, config } of this.loaded.values()) {
316
386
  this.resolver.moduleByFolder.set(module.manifest.folder, module);
@@ -322,7 +392,7 @@ class ModuleManager {
322
392
  });
323
393
  for (const interfacePackage of module.manifest.implements ?? []) {
324
394
  if (!config.disabledExports?.has(interfacePackage)) {
325
- interfaceSources.set(interfacePackage, module);
395
+ this.addInterfaceSource(interfaceSources, interfacePackage, module);
326
396
  }
327
397
  }
328
398
  }
@@ -330,7 +400,7 @@ class ModuleManager {
330
400
  this.resolver.modulesById.set(module.id, module);
331
401
  for (const interfacePackage of module.manifest.implements ?? []) {
332
402
  if (!config.disabledExports?.has(interfacePackage)) {
333
- interfaceSources.set(interfacePackage, module);
403
+ this.addInterfaceSource(interfaceSources, interfacePackage, module);
334
404
  }
335
405
  }
336
406
  }
@@ -338,75 +408,209 @@ class ModuleManager {
338
408
  return interfaceSources;
339
409
  }
340
410
  resolveInterfacePackagePaths(interfaceSources) {
341
- for (const [ifacePkg, module] of interfaceSources) {
342
- if (module.manifest.manifest.name === ifacePkg) {
343
- this.resolver.interfacePackages.set(ifacePkg, module.manifest.folder);
411
+ for (const [ifacePkg, modules] of interfaceSources) {
412
+ const module = [...modules].sort((left, right) => left.id.localeCompare(right.id))[0];
413
+ if (!module) {
344
414
  continue;
345
415
  }
346
- try {
347
- const mainPath = require.resolve(ifacePkg, {
348
- paths: [module.manifest.folder],
349
- });
350
- const pkgRoot = extractPackageRoot(mainPath, ifacePkg);
351
- if (pkgRoot) {
352
- this.resolver.interfacePackages.set(ifacePkg, pkgRoot);
353
- }
416
+ const canonicalPackage = this.resolveImplementedPackage(ifacePkg, module);
417
+ if (!canonicalPackage) {
418
+ continue;
354
419
  }
355
- catch {
420
+ this.interfacePackagePlans.set(ifacePkg, {
421
+ canonicalPackage,
422
+ consumers: this.collectInterfacePackageConsumers(ifacePkg),
423
+ });
424
+ this.registerInterfacePackage(ifacePkg, canonicalPackage);
425
+ }
426
+ for (const [packageName, canonicalPackage] of this
427
+ .stubbedInterfacePackages) {
428
+ if (interfaceSources.has(packageName)) {
429
+ continue;
356
430
  }
431
+ this.interfacePackagePlans.set(packageName, {
432
+ canonicalPackage,
433
+ consumers: this.collectInterfacePackageConsumers(packageName),
434
+ });
435
+ this.registerInterfacePackage(packageName, canonicalPackage);
436
+ }
437
+ }
438
+ resolveImplementedPackage(packageName, module) {
439
+ const resolvedPackage = (0, package_resolution_1.resolvePackage)(packageName, module.manifest.folder);
440
+ if (resolvedPackage) {
441
+ return resolvedPackage;
442
+ }
443
+ if (module.manifest.manifest.name !== packageName) {
444
+ return undefined;
357
445
  }
446
+ return (0, package_resolution_1.resolvePackageAtRoot)(packageName, module.manifest.folder, module.manifest.version);
447
+ }
448
+ collectInterfacePackageConsumers(packageName) {
449
+ const consumers = [];
450
+ for (const { module } of this.loaded.values()) {
451
+ const manifest = module.manifest.manifest;
452
+ const range = manifest.dependencies?.[packageName] ??
453
+ manifest.optionalDependencies?.[packageName];
454
+ if (!range) {
455
+ continue;
456
+ }
457
+ consumers.push({
458
+ moduleId: module.id,
459
+ range,
460
+ resolvedPackage: (0, package_resolution_1.resolvePackage)(packageName, module.manifest.folder),
461
+ });
462
+ }
463
+ return consumers;
464
+ }
465
+ registerInterfacePackage(packageName, resolvedPackage) {
466
+ this.resolver.interfacePackages.set(packageName, resolvedPackage.root);
467
+ this.resolver.interfacePackageEntries.set(packageName, resolvedPackage.entry);
468
+ this.resolver.interfacePackageResolveFrom.set(packageName, resolvedPackage.resolveFrom);
469
+ }
470
+ validateInterfacePackages() {
471
+ const errors = [...this.interfacePackagePlans].flatMap(([name, plan]) => [
472
+ ...this.findVersionErrors(name, plan),
473
+ ...this.findPreloadedCopyErrors(name, plan),
474
+ ]);
475
+ if (errors.length === 0) {
476
+ return;
477
+ }
478
+ throw new Error(`Incompatible interface package resolution:\n${errors.join("\n")}`);
479
+ }
480
+ findVersionErrors(packageName, plan) {
481
+ return plan.consumers.flatMap((consumer) => {
482
+ const range = (0, semver_1.validRange)(consumer.range);
483
+ if (!range || (0, semver_1.satisfies)(plan.canonicalPackage.version, range)) {
484
+ return [];
485
+ }
486
+ const installed = consumer.resolvedPackage
487
+ ? `${consumer.resolvedPackage.version} at ${consumer.resolvedPackage.root}`
488
+ : "not installed from the consumer";
489
+ return [
490
+ ` - ${consumer.moduleId} requires ${packageName}@${consumer.range}, but the canonical package is ${plan.canonicalPackage.version} at ${plan.canonicalPackage.root} (consumer copy: ${installed})`,
491
+ ];
492
+ });
493
+ }
494
+ findPreloadedCopyErrors(packageName, plan) {
495
+ const canonicalRoot = plan.canonicalPackage.realRoot;
496
+ const copies = plan.consumers
497
+ .map((consumer) => consumer.resolvedPackage)
498
+ .filter((resolvedPackage) => Boolean(resolvedPackage && resolvedPackage.realRoot !== canonicalRoot));
499
+ return copies.flatMap((copy) => {
500
+ const loadedFile = Object.keys(require.cache).find((filePath) => (0, package_resolution_1.isPathWithin)(filePath, copy.root));
501
+ return loadedFile
502
+ ? [
503
+ ` - ${packageName}@${copy.version} was loaded from ${copy.root} before the canonical copy at ${plan.canonicalPackage.root}; preloaded interface copies cannot be redirected (${loadedFile})`,
504
+ ]
505
+ : [];
506
+ });
358
507
  }
359
508
  buildModuleAssociations(interfaceSources) {
360
509
  for (const { module, config } of this.loaded.values()) {
361
- const associations = new Map();
362
510
  const connections = new Map();
363
- this.addDefaultAssociations(module, associations, connections, interfaceSources);
364
- this.applyImportOverrides(config.importOverrides, associations, connections);
365
- this.resolvedAssociations.set(module.id, new Set(associations.keys()));
366
- this.interfaceRegistry.setConnections(module.id, connections);
511
+ const selected = new Map();
512
+ this.addDefaultAssociations(module, connections, selected, interfaceSources);
513
+ this.applyImportOverrides(module.id, config.importOverrides, connections, selected);
514
+ this.resolvedAssociations.set(module.id, new Set(connections.keys()));
515
+ this.resolvedConnections.set(module.id, connections);
516
+ this.selectedProviders.set(module.id, selected);
517
+ this.interfaceRegistry.setConnections(module.id, connections, selected);
367
518
  }
368
519
  }
369
- addDefaultAssociations(module, associations, connections, interfaceSources) {
520
+ addDefaultAssociations(module, connections, selected, interfaceSources) {
370
521
  const dependencies = module.manifest.manifest.dependencies ?? {};
371
522
  const optionalDependencies = module.manifest.manifest.optionalDependencies ?? {};
372
- for (const [iface, provider] of interfaceSources) {
523
+ for (const [iface, providers] of interfaceSources) {
373
524
  if (iface in dependencies || iface in optionalDependencies) {
374
- associations.set(iface, provider);
375
- connections.set(iface, [{ module: provider.id }]);
525
+ const providerIds = providers.map(({ id }) => id).sort();
526
+ const defaultProvider = providerIds[0];
527
+ if (!defaultProvider) {
528
+ continue;
529
+ }
530
+ connections.set(iface, providerIds.map((provider) => ({ module: provider })));
531
+ selected.set(iface, defaultProvider);
376
532
  }
377
533
  }
378
534
  }
379
- applyImportOverrides(importOverrides, associations, connections) {
535
+ applyImportOverrides(moduleId, importOverrides, connections, selected) {
380
536
  if (!importOverrides) {
381
537
  return;
382
538
  }
383
539
  for (const [iface, overrides] of importOverrides.entries()) {
384
- const usable = overrides.filter((override) => this.loaded.has(override.module));
385
- connections.set(iface, usable);
386
- if (usable.length > 0) {
387
- const target = this.loaded.get(usable[0].module)?.module;
388
- if (target) {
389
- associations.set(iface, target);
390
- }
540
+ this.validateImportOverrides(moduleId, iface, overrides);
541
+ connections.set(iface, overrides);
542
+ selected.set(iface, overrides[0].module);
543
+ }
544
+ }
545
+ addInterfaceSource(sources, interfaceName, module) {
546
+ const providers = sources.get(interfaceName) ?? [];
547
+ providers.push(module);
548
+ sources.set(interfaceName, providers);
549
+ }
550
+ validateImportOverrides(consumerId, interfaceName, overrides) {
551
+ if (overrides.length === 0) {
552
+ throw new Error(`Module '${consumerId}' has no providers in its '${interfaceName}' import override.`);
553
+ }
554
+ const connectionIds = new Set();
555
+ for (const override of overrides) {
556
+ const target = this.getModuleEntry(override.module);
557
+ const implementsInterface = target?.module.manifest.implements.includes(interfaceName) &&
558
+ !target.config.disabledExports?.has(interfaceName);
559
+ if (!implementsInterface) {
560
+ throw new Error(`Module '${consumerId}' routes '${interfaceName}' to '${override.module}', but that loaded module does not provide the interface.`);
561
+ }
562
+ if (override.id && connectionIds.has(override.id)) {
563
+ throw new Error(`Module '${consumerId}' has duplicate connection ID '${override.id}' for '${interfaceName}'.`);
564
+ }
565
+ if (override.id) {
566
+ connectionIds.add(override.id);
391
567
  }
392
568
  }
393
569
  }
394
- isPathWithin(filePath, dirPath) {
395
- const normalizedDir = path.resolve(dirPath);
396
- const normalizedFile = path.resolve(filePath);
397
- if (normalizedFile === normalizedDir) {
398
- return true;
570
+ configureModuleContexts() {
571
+ for (const { module, config } of this.getAllManagedModules()) {
572
+ const selected = this.selectedProviders.get(module.id) ?? new Map();
573
+ const connections = this.resolvedConnections.get(module.id) ??
574
+ new Map();
575
+ const routes = [...selected].map(([interfaceName, provider]) => ({
576
+ interfaceName,
577
+ packageEntry: this.resolver.interfacePackageEntries.get(interfaceName),
578
+ provider,
579
+ providerCount: new Set(connections.get(interfaceName)?.map(({ module }) => module)).size,
580
+ }));
581
+ const isProvider = (module.manifest.implements ?? []).some((interfaceName) => !config.disabledExports?.has(interfaceName));
582
+ module.setProviderRoutes((0, module_context_1.buildProviderRoutes)(module.id, routes), isProvider);
399
583
  }
400
- return normalizedFile.startsWith(normalizedDir + path.sep);
584
+ }
585
+ isPathWithin(filePath, dirPath) {
586
+ return (0, package_resolution_1.isPathWithin)(filePath, dirPath);
401
587
  }
402
588
  }
403
589
  exports.ModuleManager = ModuleManager;
404
- function extractPackageRoot(mainPath, ifacePkg) {
405
- const marker = `${path.sep}${ifacePkg.replace("/", path.sep)}${path.sep}`;
406
- const scopeIndex = mainPath.indexOf(marker);
407
- if (scopeIndex === -1) {
408
- return undefined;
590
+ function collectRejectedErrors(results) {
591
+ return results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
592
+ }
593
+ function unpackErrors(error) {
594
+ return error instanceof AggregateError ? error.errors : [error];
595
+ }
596
+ function aggregateErrors(errors, message) {
597
+ return errors.length === 1 ? errors[0] : new AggregateError(errors, message);
598
+ }
599
+ async function runModuleOperations(modules, operation) {
600
+ return (await runTrackedModuleOperations(modules, operation)).errors;
601
+ }
602
+ async function runTrackedModuleOperations(modules, operation) {
603
+ const errors = [];
604
+ const failed = [];
605
+ for (const entry of modules) {
606
+ try {
607
+ await operation(entry.module);
608
+ }
609
+ catch (error) {
610
+ errors.push(...unpackErrors(error));
611
+ failed.push(entry);
612
+ }
409
613
  }
410
- return mainPath.substring(0, scopeIndex + marker.length - 1);
614
+ return { errors, failed };
411
615
  }
412
616
  //# sourceMappingURL=module-manager.js.map