@illuma/core 1.3.0 → 1.4.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 1.4.0 - 2026-01-10
11
+
12
+ ## 1.3.1 - 2026-01-10
13
+
10
14
  ## 1.3.0 - 2026-01-10
11
15
 
12
16
  ## 1.2.1 - 2026-01-10
package/dist/index.cjs CHANGED
@@ -274,6 +274,7 @@ var Illuma = class _Illuma {
274
274
  }
275
275
  static _diagnostics = [];
276
276
  static _scanners = [];
277
+ static _middlewares = [];
277
278
  /** @internal */
278
279
  static get contextScanners() {
279
280
  return _Illuma._scanners;
@@ -296,6 +297,20 @@ var Illuma = class _Illuma {
296
297
  static extendContextScanner(scanner) {
297
298
  _Illuma._scanners.push(scanner);
298
299
  }
300
+ /**
301
+ * Registers a global middleware to be applied during instance creation.
302
+ * Typically used for cross-cutting concerns like logging, profiling, or custom instantiation logic.
303
+ * Function should accept instantiation parameters and a `next` function to proceed with the next middleware or actual instantiation.
304
+ *
305
+ * @param m - The middleware function to register
306
+ */
307
+ static registerGlobalMiddleware(m) {
308
+ _Illuma._middlewares.push(m);
309
+ }
310
+ middlewares = [];
311
+ registerMiddleware(m) {
312
+ this.middlewares.push(m);
313
+ }
299
314
  static onReport(report) {
300
315
  for (const diag of _Illuma._diagnostics) diag.onReport(report);
301
316
  }
@@ -500,7 +515,34 @@ function isNotTransparentProto(proto) {
500
515
  }
501
516
  __name(isNotTransparentProto, "isNotTransparentProto");
502
517
 
518
+ // src/lib/utils/injector.ts
519
+ var InjectorImpl = class {
520
+ static {
521
+ __name(this, "InjectorImpl");
522
+ }
523
+ container;
524
+ constructor(container) {
525
+ this.container = container;
526
+ }
527
+ get(token) {
528
+ return this.container.get(token);
529
+ }
530
+ produce(fn) {
531
+ return this.container.produce(fn);
532
+ }
533
+ };
534
+ var Injector = new NodeToken("Injector");
535
+
503
536
  // src/lib/provider/tree-node.ts
537
+ function runMiddlewares(middlewares, params) {
538
+ const ms = middlewares;
539
+ const next = /* @__PURE__ */ __name((i, current) => {
540
+ if (i >= ms.length) return current.factory();
541
+ return ms[i](current, (nextParams) => next(i + 1, nextParams));
542
+ }, "next");
543
+ return next(0, params);
544
+ }
545
+ __name(runMiddlewares, "runMiddlewares");
504
546
  function retrieverFactory(node, deps, transparentDeps) {
505
547
  return (token, optional) => {
506
548
  const depNode = deps.get(token);
@@ -518,10 +560,12 @@ var TreeRootNode = class {
518
560
  __name(this, "TreeRootNode");
519
561
  }
520
562
  instant;
563
+ middlewares;
521
564
  _deps = /* @__PURE__ */ new Set();
522
565
  _treePool = /* @__PURE__ */ new WeakMap();
523
- constructor(instant = true) {
566
+ constructor(instant = true, middlewares = []) {
524
567
  this.instant = instant;
568
+ this.middlewares = middlewares;
525
569
  }
526
570
  get dependencies() {
527
571
  return this._deps;
@@ -532,14 +576,14 @@ var TreeRootNode = class {
532
576
  build() {
533
577
  for (const dep of this._deps) {
534
578
  if ("token" in dep.proto) this._treePool.set(dep.proto.token, dep);
535
- if (this.instant) dep.instantiate(this._treePool);
579
+ if (this.instant) dep.instantiate(this._treePool, this.middlewares);
536
580
  else dep.collectPool(this._treePool);
537
581
  }
538
582
  }
539
583
  find(token) {
540
584
  const node = this._treePool.get(token);
541
585
  if (!node) return null;
542
- if (!this.instant) node.instantiate(this._treePool);
586
+ if (!this.instant) node.instantiate(this._treePool, this.middlewares);
543
587
  return node;
544
588
  }
545
589
  toString() {
@@ -564,6 +608,10 @@ var TreeNodeSingle = class {
564
608
  }
565
609
  constructor(proto) {
566
610
  this.proto = proto;
611
+ if (proto.token === Injector) {
612
+ this._instance = proto.factory();
613
+ this._resolved = true;
614
+ }
567
615
  }
568
616
  addDependency(node) {
569
617
  if (node instanceof TreeNodeTransparent) this._transparent.add(node);
@@ -575,14 +623,18 @@ var TreeNodeSingle = class {
575
623
  for (const dep of this._transparent) dep.collectPool(pool);
576
624
  pool.set(this.proto.token, this);
577
625
  }
578
- instantiate(pool) {
626
+ instantiate(pool, middlewares = []) {
579
627
  if (this._resolved) return;
580
- for (const node of this._deps.values()) node.instantiate(pool);
581
- for (const dep of this._transparent) dep.instantiate(pool);
628
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
629
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
582
630
  const retriever = retrieverFactory(this.proto.token, this._deps, this._transparent);
583
631
  const factory = this.proto.factory ?? this.proto.token.opts?.factory;
584
632
  if (!factory) throw InjectionError.notFound(this.proto.token);
585
- this._instance = InjectionContext.instantiate(factory, retriever);
633
+ const contextFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(factory, retriever), "contextFactory");
634
+ this._instance = runMiddlewares(middlewares, {
635
+ token: this.proto.token,
636
+ factory: contextFactory
637
+ });
586
638
  this._resolved = true;
587
639
  if (pool) pool.set(this.proto.token, this);
588
640
  }
@@ -616,12 +668,16 @@ var TreeNodeTransparent = class _TreeNodeTransparent {
616
668
  for (const node of this._deps.values()) node.collectPool(pool);
617
669
  for (const dep of this._transparent) dep.collectPool(pool);
618
670
  }
619
- instantiate(pool) {
671
+ instantiate(pool, middlewares = []) {
620
672
  if (this._resolved) return;
621
- for (const dep of this._transparent) dep.instantiate(pool);
622
- for (const node of this._deps.values()) node.instantiate(pool);
673
+ for (const dep of this._transparent) dep.instantiate(pool, middlewares);
674
+ for (const node of this._deps.values()) node.instantiate(pool, middlewares);
623
675
  const retriever = retrieverFactory(this.proto.parent.token, this._deps, this._transparent);
624
- this._instance = InjectionContext.instantiate(this.proto.factory, retriever);
676
+ const refFactory = /* @__PURE__ */ __name(() => InjectionContext.instantiate(this.proto.factory, retriever), "refFactory");
677
+ this._instance = runMiddlewares(middlewares, {
678
+ token: this.proto.parent.token,
679
+ factory: refFactory
680
+ });
625
681
  this._resolved = true;
626
682
  }
627
683
  toString() {
@@ -644,10 +700,10 @@ var TreeNodeMulti = class _TreeNodeMulti {
644
700
  for (const dep of this._deps) dep.collectPool(pool);
645
701
  pool.set(this.proto.token, this);
646
702
  }
647
- instantiate(pool) {
703
+ instantiate(pool, middlewares = []) {
648
704
  if (this._resolved) return;
649
705
  for (const dep of this._deps) {
650
- dep.instantiate(pool);
706
+ dep.instantiate(pool, middlewares);
651
707
  if (dep instanceof TreeNodeSingle) {
652
708
  this.instance.push(dep.instance);
653
709
  } else if (dep instanceof _TreeNodeMulti) {
@@ -802,24 +858,6 @@ function resolveTreeNode(rootProto, cache, singleNodes, multiNodes, upstreamGett
802
858
  }
803
859
  __name(resolveTreeNode, "resolveTreeNode");
804
860
 
805
- // src/lib/utils/injector.ts
806
- var InjectorImpl = class {
807
- static {
808
- __name(this, "InjectorImpl");
809
- }
810
- container;
811
- constructor(container) {
812
- this.container = container;
813
- }
814
- get(token) {
815
- return this.container.get(token);
816
- }
817
- produce(fn) {
818
- return this.container.produce(fn);
819
- }
820
- };
821
- var Injector = new NodeToken("Injector");
822
-
823
861
  // src/lib/utils/defer.ts
824
862
  function injectDefer(provider, options) {
825
863
  const injector = nodeInject(Injector);
@@ -1045,7 +1083,11 @@ var NodeContainer = class extends Illuma {
1045
1083
  return parentNode.findNode(token);
1046
1084
  }
1047
1085
  _buildInjectionTree() {
1048
- const root = new TreeRootNode(this._opts?.instant);
1086
+ const middlewares = [
1087
+ ...Illuma._middlewares,
1088
+ ...this.collectMiddlewares()
1089
+ ];
1090
+ const root = new TreeRootNode(this._opts?.instant, middlewares);
1049
1091
  const cache = /* @__PURE__ */ new Map();
1050
1092
  const nodes = [
1051
1093
  ...this._protoNodes.values(),
@@ -1062,6 +1104,12 @@ var NodeContainer = class extends Illuma {
1062
1104
  this._multiProtoNodes.clear();
1063
1105
  return root;
1064
1106
  }
1107
+ collectMiddlewares() {
1108
+ return [
1109
+ ...this._parent && "collectMiddlewares" in this._parent && typeof this._parent.collectMiddlewares === "function" ? this._parent.collectMiddlewares() : [],
1110
+ ...this.middlewares
1111
+ ];
1112
+ }
1065
1113
  /**
1066
1114
  * Bootstraps the container by resolving the dependency trees and instantiating all providers.
1067
1115
  * This must be called after all providers are registered and before calling {@link get}.