@antelopejs/core 1.4.7 → 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 (71) 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 +5 -2
  24. package/dist/core/module-lifecycle.js +49 -32
  25. package/dist/core/module-lifecycle.js.map +1 -1
  26. package/dist/core/module-manager.d.ts +19 -2
  27. package/dist/core/module-manager.js +332 -127
  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 +2 -0
  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/runtime/dev-server-registry.js +4 -2
  52. package/dist/core/runtime/dev-server-registry.js.map +1 -1
  53. package/dist/core/runtime/launch-sequence.js +78 -11
  54. package/dist/core/runtime/launch-sequence.js.map +1 -1
  55. package/dist/core/runtime/module-loading.d.ts +1 -0
  56. package/dist/core/runtime/module-loading.js +89 -22
  57. package/dist/core/runtime/module-loading.js.map +1 -1
  58. package/dist/core/runtime/project-launch.d.ts +5 -0
  59. package/dist/core/runtime/project-launch.js +184 -0
  60. package/dist/core/runtime/project-launch.js.map +1 -0
  61. package/dist/core/runtime/runtime-bootstrap.d.ts +1 -0
  62. package/dist/core/runtime/runtime-bootstrap.js +11 -2
  63. package/dist/core/runtime/runtime-bootstrap.js.map +1 -1
  64. package/dist/core/shutdown/shutdown-manager.js +8 -2
  65. package/dist/core/shutdown/shutdown-manager.js.map +1 -1
  66. package/dist/core/test/test-module.js +18 -13
  67. package/dist/core/test/test-module.js.map +1 -1
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +13 -113
  70. package/dist/index.js.map +1 -1
  71. 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,83 +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;
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;
235
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
- })));
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)));
255
+ }
256
+ catch (error) {
257
+ if (leaseAcquired) {
258
+ throw aggregateErrors([error, ...this.releaseRuntimeState()], "Failed to construct modules");
259
+ }
260
+ throw error;
261
+ }
247
262
  }
248
263
  async startAll() {
249
- await this.startModules([...this.loaded.values()]);
264
+ try {
265
+ await this.startModules([...this.loaded.values()]);
266
+ }
267
+ catch (error) {
268
+ let cleanupErrors = [];
269
+ try {
270
+ await this.destroyAll();
271
+ }
272
+ catch (cleanupError) {
273
+ cleanupErrors = unpackErrors(cleanupError);
274
+ }
275
+ throw new AggregateError([...unpackErrors(error), ...cleanupErrors], "Failed to start modules");
276
+ }
250
277
  }
251
278
  async startModules(modules) {
252
- const starting = [];
253
- for (const { module } of modules) {
254
- starting.push(module.start());
279
+ modules.forEach(({ module }) => {
255
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");
256
286
  }
257
- await Promise.all(starting);
258
287
  }
259
288
  async stopAll() {
260
- const reverseOrder = [...this.startupOrder].reverse();
261
- const idsToStop = reverseOrder.length > 0
262
- ? reverseOrder
263
- : [...this.loaded.keys()].reverse();
264
- for (const id of idsToStop) {
265
- const entry = this.loaded.get(id);
266
- if (!entry) {
267
- continue;
268
- }
269
- try {
270
- await entry.module.stop();
271
- }
272
- catch (error) {
273
- Logger.Error(`Failed to stop module ${id}:`, error);
274
- }
275
- }
289
+ const modules = this.getReverseLifecycleModules();
290
+ const errors = await runModuleOperations(modules, (module) => module.stop());
276
291
  this.startupOrder = [];
292
+ if (errors.length > 0) {
293
+ throw new AggregateError(errors, "Failed to stop modules");
294
+ }
277
295
  }
278
296
  async destroyAll() {
279
- const reverseOrder = [...this.startupOrder].reverse();
280
- const idsToDestroy = reverseOrder.length > 0
281
- ? reverseOrder
282
- : [...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) {
283
306
  try {
284
- for (const id of idsToDestroy) {
285
- const entry = this.loaded.get(id);
286
- if (!entry) {
287
- continue;
288
- }
289
- 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);
290
323
  }
291
324
  }
292
- finally {
293
- this.startupOrder = [];
294
- this.stubbedInterfacePaths.clear();
295
- (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 {
296
356
  this.resolverDetour.detach();
297
357
  }
358
+ catch (error) {
359
+ errors.push(error);
360
+ }
361
+ return errors;
298
362
  }
299
363
  trackModuleStart(moduleId) {
300
364
  this.startupOrder = this.startupOrder.filter((id) => id !== moduleId);
@@ -303,13 +367,20 @@ class ModuleManager {
303
367
  rebuildAssociations() {
304
368
  const interfaceSources = this.collectInterfaceSources();
305
369
  this.buildModuleAssociations(interfaceSources);
370
+ this.configureModuleContexts();
306
371
  }
307
372
  collectInterfaceSources() {
308
373
  this.resolver.moduleByFolder.clear();
309
374
  this.resolver.modulesById.clear();
310
375
  this.resolver.interfacePackages.clear();
376
+ this.resolver.interfacePackageEntries.clear();
377
+ this.resolver.interfacePackageResolveFrom.clear();
378
+ this.interfacePackagePlans.clear();
311
379
  this.resolvedAssociations.clear();
380
+ this.resolvedConnections.clear();
381
+ this.selectedProviders.clear();
312
382
  this.moduleTracker.clear();
383
+ this.interfaceRegistry.clear();
313
384
  const interfaceSources = new Map();
314
385
  for (const { module, config } of this.loaded.values()) {
315
386
  this.resolver.moduleByFolder.set(module.manifest.folder, module);
@@ -321,7 +392,7 @@ class ModuleManager {
321
392
  });
322
393
  for (const interfacePackage of module.manifest.implements ?? []) {
323
394
  if (!config.disabledExports?.has(interfacePackage)) {
324
- interfaceSources.set(interfacePackage, module);
395
+ this.addInterfaceSource(interfaceSources, interfacePackage, module);
325
396
  }
326
397
  }
327
398
  }
@@ -329,7 +400,7 @@ class ModuleManager {
329
400
  this.resolver.modulesById.set(module.id, module);
330
401
  for (const interfacePackage of module.manifest.implements ?? []) {
331
402
  if (!config.disabledExports?.has(interfacePackage)) {
332
- interfaceSources.set(interfacePackage, module);
403
+ this.addInterfaceSource(interfaceSources, interfacePackage, module);
333
404
  }
334
405
  }
335
406
  }
@@ -337,75 +408,209 @@ class ModuleManager {
337
408
  return interfaceSources;
338
409
  }
339
410
  resolveInterfacePackagePaths(interfaceSources) {
340
- for (const [ifacePkg, module] of interfaceSources) {
341
- if (module.manifest.manifest.name === ifacePkg) {
342
- 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) {
343
414
  continue;
344
415
  }
345
- try {
346
- const mainPath = require.resolve(ifacePkg, {
347
- paths: [module.manifest.folder],
348
- });
349
- const pkgRoot = extractPackageRoot(mainPath, ifacePkg);
350
- if (pkgRoot) {
351
- this.resolver.interfacePackages.set(ifacePkg, pkgRoot);
352
- }
416
+ const canonicalPackage = this.resolveImplementedPackage(ifacePkg, module);
417
+ if (!canonicalPackage) {
418
+ continue;
353
419
  }
354
- 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;
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;
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;
355
456
  }
457
+ consumers.push({
458
+ moduleId: module.id,
459
+ range,
460
+ resolvedPackage: (0, package_resolution_1.resolvePackage)(packageName, module.manifest.folder),
461
+ });
356
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
+ });
357
507
  }
358
508
  buildModuleAssociations(interfaceSources) {
359
509
  for (const { module, config } of this.loaded.values()) {
360
- const associations = new Map();
361
510
  const connections = new Map();
362
- this.addDefaultAssociations(module, associations, connections, interfaceSources);
363
- this.applyImportOverrides(config.importOverrides, associations, connections);
364
- this.resolvedAssociations.set(module.id, new Set(associations.keys()));
365
- 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);
366
518
  }
367
519
  }
368
- addDefaultAssociations(module, associations, connections, interfaceSources) {
520
+ addDefaultAssociations(module, connections, selected, interfaceSources) {
369
521
  const dependencies = module.manifest.manifest.dependencies ?? {};
370
522
  const optionalDependencies = module.manifest.manifest.optionalDependencies ?? {};
371
- for (const [iface, provider] of interfaceSources) {
523
+ for (const [iface, providers] of interfaceSources) {
372
524
  if (iface in dependencies || iface in optionalDependencies) {
373
- associations.set(iface, provider);
374
- 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);
375
532
  }
376
533
  }
377
534
  }
378
- applyImportOverrides(importOverrides, associations, connections) {
535
+ applyImportOverrides(moduleId, importOverrides, connections, selected) {
379
536
  if (!importOverrides) {
380
537
  return;
381
538
  }
382
539
  for (const [iface, overrides] of importOverrides.entries()) {
383
- const usable = overrides.filter((override) => this.loaded.has(override.module));
384
- connections.set(iface, usable);
385
- if (usable.length > 0) {
386
- const target = this.loaded.get(usable[0].module)?.module;
387
- if (target) {
388
- associations.set(iface, target);
389
- }
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);
390
567
  }
391
568
  }
392
569
  }
393
- isPathWithin(filePath, dirPath) {
394
- const normalizedDir = path.resolve(dirPath);
395
- const normalizedFile = path.resolve(filePath);
396
- if (normalizedFile === normalizedDir) {
397
- 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);
398
583
  }
399
- return normalizedFile.startsWith(normalizedDir + path.sep);
584
+ }
585
+ isPathWithin(filePath, dirPath) {
586
+ return (0, package_resolution_1.isPathWithin)(filePath, dirPath);
400
587
  }
401
588
  }
402
589
  exports.ModuleManager = ModuleManager;
403
- function extractPackageRoot(mainPath, ifacePkg) {
404
- const marker = `${path.sep}${ifacePkg.replace("/", path.sep)}${path.sep}`;
405
- const scopeIndex = mainPath.indexOf(marker);
406
- if (scopeIndex === -1) {
407
- 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
+ }
408
613
  }
409
- return mainPath.substring(0, scopeIndex + marker.length - 1);
614
+ return { errors, failed };
410
615
  }
411
616
  //# sourceMappingURL=module-manager.js.map