@navios/di 0.7.1 → 0.8.0

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 (32) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/lib/browser/index.d.mts +52 -2
  3. package/lib/browser/index.d.mts.map +1 -1
  4. package/lib/browser/index.mjs +114 -15
  5. package/lib/browser/index.mjs.map +1 -1
  6. package/lib/{container-BuAutHGg.d.mts → container-Bp1W-pWJ.d.mts} +53 -3
  7. package/lib/{container-BuAutHGg.d.mts.map → container-Bp1W-pWJ.d.mts.map} +1 -1
  8. package/lib/{container-Pb_Y4Z4x.mjs → container-DAKOvAgr.mjs} +119 -18
  9. package/lib/container-DAKOvAgr.mjs.map +1 -0
  10. package/lib/{container-DnzgpfBe.cjs → container-DENMeJ87.cjs} +119 -18
  11. package/lib/container-DENMeJ87.cjs.map +1 -0
  12. package/lib/{container-oGTgX2iX.d.cts → container-YPwvmlK2.d.cts} +53 -3
  13. package/lib/{container-oGTgX2iX.d.cts.map → container-YPwvmlK2.d.cts.map} +1 -1
  14. package/lib/index.cjs +1 -1
  15. package/lib/index.d.cts +1 -1
  16. package/lib/index.d.cts.map +1 -1
  17. package/lib/index.d.mts +1 -1
  18. package/lib/index.d.mts.map +1 -1
  19. package/lib/index.mjs +1 -1
  20. package/lib/testing/index.cjs +1 -1
  21. package/lib/testing/index.d.cts +1 -1
  22. package/lib/testing/index.d.mts +1 -1
  23. package/lib/testing/index.mjs +1 -1
  24. package/package.json +1 -1
  25. package/src/internal/context/request-context.mts +11 -0
  26. package/src/internal/core/instance-resolver.mts +11 -0
  27. package/src/internal/core/token-processor.mts +60 -1
  28. package/src/internal/holder/base-holder-manager.mts +106 -10
  29. package/src/internal/holder/request-storage.mts +7 -14
  30. package/src/internal/holder/singleton-storage.mts +3 -16
  31. package/lib/container-DnzgpfBe.cjs.map +0 -1
  32. package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
@@ -509,9 +509,14 @@ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
509
509
  */ var BaseHolderManager = class BaseHolderManager {
510
510
  logger;
511
511
  _holders;
512
+ /**
513
+ * Reverse dependency index: maps a dependency name to the set of holder names that depend on it.
514
+ * This allows O(1) lookup of dependents instead of O(n) iteration.
515
+ */ _dependents;
512
516
  constructor(logger = null) {
513
517
  this.logger = logger;
514
518
  this._holders = /* @__PURE__ */ new Map();
519
+ this._dependents = /* @__PURE__ */ new Map();
515
520
  }
516
521
  /**
517
522
  * Protected getter for accessing the holders map from subclasses.
@@ -519,23 +524,81 @@ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
519
524
  return this._holders;
520
525
  }
521
526
  /**
522
- * Deletes a holder by name.
527
+ * Deletes a holder by name and cleans up the reverse dependency index.
523
528
  * @param name The name of the holder to delete
524
529
  * @returns true if the holder was deleted, false if it didn't exist
525
530
  */ delete(name) {
531
+ const holder = this._holders.get(name);
532
+ if (holder) this.removeFromDependentsIndex(name, holder.deps);
526
533
  return this._holders.delete(name);
527
534
  }
528
535
  /**
536
+ * Registers a holder's dependencies in the reverse index.
537
+ * Call this after creating a holder with dependencies.
538
+ * @param holderName The name of the holder that has dependencies
539
+ * @param deps The set of dependency names
540
+ */ registerDependencies(holderName, deps) {
541
+ for (const dep of deps) {
542
+ let dependents = this._dependents.get(dep);
543
+ if (!dependents) {
544
+ dependents = /* @__PURE__ */ new Set();
545
+ this._dependents.set(dep, dependents);
546
+ }
547
+ dependents.add(holderName);
548
+ }
549
+ }
550
+ /**
551
+ * Removes a holder from the reverse dependency index.
552
+ * @param holderName The name of the holder to remove
553
+ * @param deps The set of dependency names to clean up
554
+ */ removeFromDependentsIndex(holderName, deps) {
555
+ for (const dep of deps) {
556
+ const dependents = this._dependents.get(dep);
557
+ if (dependents) {
558
+ dependents.delete(holderName);
559
+ if (dependents.size === 0) this._dependents.delete(dep);
560
+ }
561
+ }
562
+ }
563
+ /**
564
+ * Gets all holder names that depend on the given instance name.
565
+ * O(1) lookup using the reverse dependency index.
566
+ * @param instanceName The instance name to find dependents for
567
+ * @returns Array of holder names that depend on this instance
568
+ */ getDependents(instanceName) {
569
+ const dependents = this._dependents.get(instanceName);
570
+ return dependents ? Array.from(dependents) : [];
571
+ }
572
+ /**
529
573
  * Filters holders based on a predicate function.
530
574
  * @param predicate Function to test each holder
531
575
  * @returns A new Map containing only the holders that match the predicate
576
+ * @deprecated Use forEachHolder() for iteration to avoid allocations
532
577
  */ filter(predicate) {
533
- return new Map([...this._holders].filter(([key, value]) => predicate(value, key)));
578
+ const result = /* @__PURE__ */ new Map();
579
+ for (const [key, value] of this._holders) if (predicate(value, key)) result.set(key, value);
580
+ return result;
581
+ }
582
+ /**
583
+ * Iterates over holders with a callback. More efficient than filter() as it
584
+ * avoids creating intermediate arrays and Maps.
585
+ * @param callback Function called for each holder with (holder, name)
586
+ */ forEachHolder(callback) {
587
+ for (const [name, holder] of this._holders) callback(holder, name);
588
+ }
589
+ /**
590
+ * Finds the first holder matching a predicate. More efficient than filter()
591
+ * when only one result is needed.
592
+ * @param predicate Function to test each holder
593
+ * @returns The first matching holder or undefined
594
+ */ findHolder(predicate) {
595
+ for (const [name, holder] of this._holders) if (predicate(holder, name)) return holder;
534
596
  }
535
597
  /**
536
- * Clears all holders from this manager.
598
+ * Clears all holders from this manager and the reverse dependency index.
537
599
  */ clear() {
538
600
  this._holders.clear();
601
+ this._dependents.clear();
539
602
  }
540
603
  /**
541
604
  * Gets the number of holders currently managed.
@@ -619,12 +682,14 @@ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
619
682
  if (waiterHolder && getHolder) {
620
683
  const cycle = CircularDetector.detectCycle(waiterHolder.name, holder.name, getHolder);
621
684
  if (cycle) return [DIError.circularDependency(cycle)];
622
- waiterHolder.waitingFor.add(holder.name);
685
+ if (process.env.NODE_ENV !== "production") waiterHolder.waitingFor.add(holder.name);
623
686
  }
624
687
  try {
625
688
  await holder.creationPromise;
626
689
  } finally {
627
- if (waiterHolder) waiterHolder.waitingFor.delete(holder.name);
690
+ if (process.env.NODE_ENV !== "production") {
691
+ if (waiterHolder) waiterHolder.waitingFor.delete(holder.name);
692
+ }
628
693
  }
629
694
  return BaseHolderManager.waitForHolderReady(holder, waiterHolder, getHolder);
630
695
  case InstanceStatus.Destroying: return [DIError.instanceDestroying(holder.name)];
@@ -751,10 +816,11 @@ var RequestStorage = class {
751
816
  return null;
752
817
  }
753
818
  findDependents(instanceName) {
754
- const dependents = [];
755
- for (const [name, holder] of this.contextHolder.holders) if (holder.deps.has(instanceName)) dependents.push(name);
756
- for (const [name, holder] of this.holderManager.filter(() => true)) if (holder.deps.has(instanceName)) dependents.push(name);
757
- return dependents;
819
+ const requestDependents = this.contextHolder.getDependents(instanceName);
820
+ const singletonDependents = this.holderManager.getDependents(instanceName);
821
+ if (requestDependents.length === 0) return singletonDependents;
822
+ if (singletonDependents.length === 0) return requestDependents;
823
+ return [...requestDependents, ...singletonDependents];
758
824
  }
759
825
  };
760
826
 
@@ -960,16 +1026,13 @@ var SingletonStorage = class {
960
1026
  return this.manager.getAllNames();
961
1027
  }
962
1028
  forEach(callback) {
963
- for (const [name, holder] of this.manager.filter(() => true)) callback(name, holder);
1029
+ this.manager.forEachHolder((holder, name) => callback(name, holder));
964
1030
  }
965
1031
  findByInstance(instance) {
966
- for (const [, holder] of this.manager.filter((h) => h.instance === instance)) return holder;
967
- return null;
1032
+ return this.manager.findHolder((h) => h.instance === instance) ?? null;
968
1033
  }
969
1034
  findDependents(instanceName) {
970
- const dependents = [];
971
- for (const [name, holder] of this.manager.filter(() => true)) if (holder.deps.has(instanceName)) dependents.push(name);
972
- return dependents;
1035
+ return this.manager.getDependents(instanceName);
973
1036
  }
974
1037
  };
975
1038
 
@@ -1197,6 +1260,8 @@ var SingletonStorage = class {
1197
1260
  */ async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer) {
1198
1261
  holder.instance = instance;
1199
1262
  holder.status = InstanceStatus.Created;
1263
+ if (ctx.deps.size > 0) if (scopedContainer) scopedContainer.getRequestContextHolder().registerDependencies(instanceName, ctx.deps);
1264
+ else this.manager.registerDependencies(instanceName, ctx.deps);
1200
1265
  if (ctx.deps.size > 0) ctx.deps.forEach((dependency) => {
1201
1266
  holder.destroyListeners.push(this.serviceLocator.getEventBus().on(dependency, "destroy", () => {
1202
1267
  this.logger?.log(`[InstanceResolver] Dependency ${dependency} destroyed, invalidating ${instanceName}`);
@@ -1652,12 +1717,42 @@ var SingletonStorage = class {
1652
1717
  //#endregion
1653
1718
  //#region src/internal/core/token-processor.mts
1654
1719
  /**
1720
+ * Simple LRU cache for instance name generation.
1721
+ * Uses a Map which maintains insertion order for efficient LRU eviction.
1722
+ */ var InstanceNameCache = class {
1723
+ cache = /* @__PURE__ */ new Map();
1724
+ maxSize;
1725
+ constructor(maxSize = 1e3) {
1726
+ this.maxSize = maxSize;
1727
+ }
1728
+ get(key) {
1729
+ const value = this.cache.get(key);
1730
+ if (value !== void 0) {
1731
+ this.cache.delete(key);
1732
+ this.cache.set(key, value);
1733
+ }
1734
+ return value;
1735
+ }
1736
+ set(key, value) {
1737
+ if (this.cache.has(key)) this.cache.delete(key);
1738
+ else if (this.cache.size >= this.maxSize) {
1739
+ const firstKey = this.cache.keys().next().value;
1740
+ if (firstKey !== void 0) this.cache.delete(firstKey);
1741
+ }
1742
+ this.cache.set(key, value);
1743
+ }
1744
+ clear() {
1745
+ this.cache.clear();
1746
+ }
1747
+ };
1748
+ /**
1655
1749
  * Handles token validation, normalization, and instance name generation.
1656
1750
  *
1657
1751
  * Provides utilities for resolving tokens to their underlying InjectionToken,
1658
1752
  * validating arguments against schemas, and generating unique instance identifiers.
1659
1753
  */ var TokenProcessor = class {
1660
1754
  logger;
1755
+ instanceNameCache = new InstanceNameCache();
1661
1756
  constructor(logger = null) {
1662
1757
  this.logger = logger;
1663
1758
  }
@@ -1716,10 +1811,16 @@ var SingletonStorage = class {
1716
1811
  }
1717
1812
  /**
1718
1813
  * Generates a unique instance name based on token and arguments.
1814
+ * Results are cached using an LRU cache for performance.
1719
1815
  */ generateInstanceName(token, args) {
1720
1816
  if (!args) return token.toString();
1721
- const formattedArgs = Object.entries(args).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}=${this.formatArgValue(value)}`).join(",");
1722
- return `${token.toString()}:${formattedArgs.replaceAll(/"/g, "").replaceAll(/:/g, "=")}`;
1817
+ const tokenStr = token.toString();
1818
+ const cacheKey = `${tokenStr}:${JSON.stringify(args)}`;
1819
+ const cached = this.instanceNameCache.get(cacheKey);
1820
+ if (cached !== void 0) return cached;
1821
+ const result = `${tokenStr}:${Object.entries(args).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}=${this.formatArgValue(value)}`).join(",").replaceAll(/"/g, "").replaceAll(/:/g, "=")}`;
1822
+ this.instanceNameCache.set(cacheKey, result);
1823
+ return result;
1723
1824
  }
1724
1825
  /**
1725
1826
  * Formats a single argument value for instance name generation.
@@ -2515,4 +2616,4 @@ Object.defineProperty(exports, 'wrapSyncInit', {
2515
2616
  return wrapSyncInit;
2516
2617
  }
2517
2618
  });
2518
- //# sourceMappingURL=container-DnzgpfBe.cjs.map
2619
+ //# sourceMappingURL=container-DENMeJ87.cjs.map