@navios/di 0.8.0 → 0.9.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 (264) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +117 -17
  3. package/lib/browser/container/abstract-container.d.mts +112 -0
  4. package/lib/browser/container/abstract-container.d.mts.map +1 -0
  5. package/lib/browser/container/abstract-container.mjs +100 -0
  6. package/lib/browser/container/abstract-container.mjs.map +1 -0
  7. package/lib/browser/container/container.d.mts +100 -0
  8. package/lib/browser/container/container.d.mts.map +1 -0
  9. package/lib/browser/container/container.mjs +424 -0
  10. package/lib/browser/container/container.mjs.map +1 -0
  11. package/lib/browser/container/scoped-container.d.mts +93 -0
  12. package/lib/browser/container/scoped-container.d.mts.map +1 -0
  13. package/lib/browser/container/scoped-container.mjs +119 -0
  14. package/lib/browser/container/scoped-container.mjs.map +1 -0
  15. package/lib/browser/decorators/factory.decorator.d.mts +26 -0
  16. package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
  17. package/lib/browser/decorators/factory.decorator.mjs +20 -0
  18. package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
  19. package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
  20. package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
  21. package/lib/browser/decorators/injectable.decorator.mjs +21 -0
  22. package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
  23. package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
  24. package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
  25. package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
  26. package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
  27. package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
  28. package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
  29. package/lib/browser/enums/injectable-type.enum.mjs +10 -0
  30. package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
  31. package/lib/browser/errors/di-error.d.mts +43 -0
  32. package/lib/browser/errors/di-error.d.mts.map +1 -0
  33. package/lib/browser/errors/di-error.mjs +98 -0
  34. package/lib/browser/errors/di-error.mjs.map +1 -0
  35. package/lib/browser/event-emitter.d.mts +16 -0
  36. package/lib/browser/event-emitter.d.mts.map +1 -0
  37. package/lib/browser/event-emitter.mjs +320 -0
  38. package/lib/browser/event-emitter.mjs.map +1 -0
  39. package/lib/browser/index.d.mts +37 -1558
  40. package/lib/browser/index.mjs +29 -2749
  41. package/lib/browser/interfaces/container.interface.d.mts +59 -0
  42. package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
  43. package/lib/browser/interfaces/factory.interface.d.mts +14 -0
  44. package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
  45. package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
  46. package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
  47. package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
  48. package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
  49. package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
  50. package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
  51. package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
  52. package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
  53. package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
  54. package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
  55. package/lib/browser/internal/context/factory-context.d.mts +23 -0
  56. package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
  57. package/lib/browser/internal/context/resolution-context.d.mts +43 -0
  58. package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
  59. package/lib/browser/internal/context/resolution-context.mjs +56 -0
  60. package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
  61. package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
  62. package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
  63. package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
  64. package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
  65. package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
  66. package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
  67. package/lib/browser/internal/core/instance-resolver.mjs +306 -0
  68. package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
  69. package/lib/browser/internal/core/name-resolver.d.mts +52 -0
  70. package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
  71. package/lib/browser/internal/core/name-resolver.mjs +118 -0
  72. package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
  73. package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
  74. package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
  75. package/lib/browser/internal/core/scope-tracker.mjs +120 -0
  76. package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
  77. package/lib/browser/internal/core/service-initializer.d.mts +44 -0
  78. package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
  79. package/lib/browser/internal/core/service-initializer.mjs +109 -0
  80. package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
  81. package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
  82. package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
  83. package/lib/browser/internal/core/service-invalidator.mjs +142 -0
  84. package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
  85. package/lib/browser/internal/core/token-resolver.d.mts +54 -0
  86. package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
  87. package/lib/browser/internal/core/token-resolver.mjs +77 -0
  88. package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
  89. package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
  90. package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
  91. package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
  92. package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
  93. package/lib/browser/internal/holder/instance-holder.mjs +19 -0
  94. package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
  95. package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
  96. package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
  97. package/lib/browser/internal/holder/unified-storage.mjs +144 -0
  98. package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
  99. package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
  100. package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
  101. package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
  102. package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
  103. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
  104. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
  105. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
  106. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
  107. package/lib/browser/internal/stub-factory-class.d.mts +14 -0
  108. package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
  109. package/lib/browser/internal/stub-factory-class.mjs +18 -0
  110. package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
  111. package/lib/browser/symbols/injectable-token.d.mts +5 -0
  112. package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
  113. package/lib/browser/symbols/injectable-token.mjs +6 -0
  114. package/lib/browser/symbols/injectable-token.mjs.map +1 -0
  115. package/lib/browser/token/injection-token.d.mts +55 -0
  116. package/lib/browser/token/injection-token.d.mts.map +1 -0
  117. package/lib/browser/token/injection-token.mjs +100 -0
  118. package/lib/browser/token/injection-token.mjs.map +1 -0
  119. package/lib/browser/token/registry.d.mts +37 -0
  120. package/lib/browser/token/registry.d.mts.map +1 -0
  121. package/lib/browser/token/registry.mjs +86 -0
  122. package/lib/browser/token/registry.mjs.map +1 -0
  123. package/lib/browser/utils/default-injectors.d.mts +12 -0
  124. package/lib/browser/utils/default-injectors.d.mts.map +1 -0
  125. package/lib/browser/utils/default-injectors.mjs +13 -0
  126. package/lib/browser/utils/default-injectors.mjs.map +1 -0
  127. package/lib/browser/utils/get-injectable-token.d.mts +9 -0
  128. package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
  129. package/lib/browser/utils/get-injectable-token.mjs +13 -0
  130. package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
  131. package/lib/browser/utils/get-injectors.d.mts +55 -0
  132. package/lib/browser/utils/get-injectors.d.mts.map +1 -0
  133. package/lib/browser/utils/get-injectors.mjs +121 -0
  134. package/lib/browser/utils/get-injectors.mjs.map +1 -0
  135. package/lib/browser/utils/types.d.mts +23 -0
  136. package/lib/browser/utils/types.d.mts.map +1 -0
  137. package/lib/{container-DAKOvAgr.mjs → container-8-z89TyQ.mjs} +1325 -1462
  138. package/lib/container-8-z89TyQ.mjs.map +1 -0
  139. package/lib/{container-Bp1W-pWJ.d.mts → container-CNiqesCL.d.mts} +598 -617
  140. package/lib/container-CNiqesCL.d.mts.map +1 -0
  141. package/lib/{container-DENMeJ87.cjs → container-CaY2fDuk.cjs} +1369 -1512
  142. package/lib/container-CaY2fDuk.cjs.map +1 -0
  143. package/lib/{container-YPwvmlK2.d.cts → container-D-0Ho3qL.d.cts} +598 -612
  144. package/lib/container-D-0Ho3qL.d.cts.map +1 -0
  145. package/lib/index.cjs +13 -15
  146. package/lib/index.cjs.map +1 -1
  147. package/lib/index.d.cts +58 -223
  148. package/lib/index.d.cts.map +1 -1
  149. package/lib/index.d.mts +62 -222
  150. package/lib/index.d.mts.map +1 -1
  151. package/lib/index.mjs +5 -6
  152. package/lib/index.mjs.map +1 -1
  153. package/lib/testing/index.cjs +569 -311
  154. package/lib/testing/index.cjs.map +1 -1
  155. package/lib/testing/index.d.cts +370 -41
  156. package/lib/testing/index.d.cts.map +1 -1
  157. package/lib/testing/index.d.mts +370 -41
  158. package/lib/testing/index.d.mts.map +1 -1
  159. package/lib/testing/index.mjs +568 -305
  160. package/lib/testing/index.mjs.map +1 -1
  161. package/package.json +2 -1
  162. package/src/__tests__/circular-detector.spec.mts +193 -0
  163. package/src/__tests__/concurrent.spec.mts +368 -0
  164. package/src/__tests__/container.spec.mts +32 -30
  165. package/src/__tests__/di-error.spec.mts +351 -0
  166. package/src/__tests__/e2e.browser.spec.mts +0 -4
  167. package/src/__tests__/e2e.spec.mts +10 -19
  168. package/src/__tests__/event-emitter.spec.mts +232 -109
  169. package/src/__tests__/get-injectors.spec.mts +250 -39
  170. package/src/__tests__/injection-token.spec.mts +293 -349
  171. package/src/__tests__/library-findings.spec.mts +8 -8
  172. package/src/__tests__/registry.spec.mts +358 -210
  173. package/src/__tests__/resolution-context.spec.mts +255 -0
  174. package/src/__tests__/scope-tracker.spec.mts +598 -0
  175. package/src/__tests__/scope-upgrade.spec.mts +808 -0
  176. package/src/__tests__/scoped-container.spec.mts +595 -0
  177. package/src/__tests__/test-container.spec.mts +293 -0
  178. package/src/__tests__/token-resolver.spec.mts +207 -0
  179. package/src/__tests__/unified-storage.spec.mts +535 -0
  180. package/src/__tests__/unit-test-container.spec.mts +405 -0
  181. package/src/__type-tests__/container.spec-d.mts +180 -0
  182. package/src/__type-tests__/factory.spec-d.mts +15 -3
  183. package/src/__type-tests__/inject.spec-d.mts +115 -20
  184. package/src/__type-tests__/injectable.spec-d.mts +69 -52
  185. package/src/__type-tests__/injection-token.spec-d.mts +176 -0
  186. package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
  187. package/src/container/abstract-container.mts +327 -0
  188. package/src/container/container.mts +142 -170
  189. package/src/container/scoped-container.mts +126 -208
  190. package/src/decorators/factory.decorator.mts +16 -11
  191. package/src/decorators/injectable.decorator.mts +20 -16
  192. package/src/enums/index.mts +2 -2
  193. package/src/enums/injectable-scope.enum.mts +1 -0
  194. package/src/enums/injectable-type.enum.mts +1 -0
  195. package/src/errors/di-error.mts +96 -0
  196. package/src/event-emitter.mts +3 -27
  197. package/src/index.mts +6 -153
  198. package/src/interfaces/container.interface.mts +13 -0
  199. package/src/interfaces/factory.interface.mts +1 -1
  200. package/src/interfaces/index.mts +1 -1
  201. package/src/internal/context/async-local-storage.mts +3 -2
  202. package/src/internal/context/async-local-storage.types.mts +1 -0
  203. package/src/internal/context/factory-context.mts +1 -0
  204. package/src/internal/context/index.mts +3 -1
  205. package/src/internal/context/resolution-context.mts +1 -0
  206. package/src/internal/context/service-initialization-context.mts +43 -0
  207. package/src/internal/core/index.mts +5 -4
  208. package/src/internal/core/instance-resolver.mts +460 -302
  209. package/src/internal/core/name-resolver.mts +196 -0
  210. package/src/internal/core/scope-tracker.mts +242 -0
  211. package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
  212. package/src/internal/core/service-invalidator.mts +290 -0
  213. package/src/internal/core/token-resolver.mts +122 -0
  214. package/src/internal/holder/holder-storage.interface.mts +11 -5
  215. package/src/internal/holder/index.mts +2 -5
  216. package/src/internal/holder/instance-holder.mts +1 -3
  217. package/src/internal/holder/unified-storage.mts +245 -0
  218. package/src/internal/index.mts +2 -1
  219. package/src/internal/lifecycle/circular-detector.mts +1 -0
  220. package/src/internal/lifecycle/index.mts +1 -1
  221. package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
  222. package/src/internal/stub-factory-class.mts +16 -0
  223. package/src/symbols/injectable-token.mts +3 -1
  224. package/src/testing/index.mts +2 -0
  225. package/src/testing/test-container.mts +546 -85
  226. package/src/testing/types.mts +117 -0
  227. package/src/testing/unit-test-container.mts +509 -0
  228. package/src/token/injection-token.mts +41 -4
  229. package/src/token/registry.mts +75 -9
  230. package/src/utils/default-injectors.mts +16 -0
  231. package/src/utils/get-injectable-token.mts +2 -3
  232. package/src/utils/get-injectors.mts +26 -15
  233. package/src/utils/index.mts +3 -1
  234. package/src/utils/types.mts +1 -0
  235. package/tsdown.config.mts +11 -1
  236. package/lib/browser/index.d.mts.map +0 -1
  237. package/lib/browser/index.mjs.map +0 -1
  238. package/lib/container-Bp1W-pWJ.d.mts.map +0 -1
  239. package/lib/container-DAKOvAgr.mjs.map +0 -1
  240. package/lib/container-DENMeJ87.cjs.map +0 -1
  241. package/lib/container-YPwvmlK2.d.cts.map +0 -1
  242. package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
  243. package/src/__tests__/async-local-storage.spec.mts +0 -333
  244. package/src/__tests__/errors.spec.mts +0 -87
  245. package/src/__tests__/factory.spec.mts +0 -137
  246. package/src/__tests__/injectable.spec.mts +0 -246
  247. package/src/__tests__/request-scope.spec.mts +0 -416
  248. package/src/__tests__/service-instantiator.spec.mts +0 -410
  249. package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
  250. package/src/__tests__/service-locator-manager.spec.mts +0 -300
  251. package/src/__tests__/service-locator.spec.mts +0 -966
  252. package/src/__tests__/unified-api.spec.mts +0 -130
  253. package/src/browser.mts +0 -11
  254. package/src/injectors.mts +0 -18
  255. package/src/internal/context/request-context.mts +0 -225
  256. package/src/internal/core/invalidator.mts +0 -437
  257. package/src/internal/core/service-locator.mts +0 -202
  258. package/src/internal/core/token-processor.mts +0 -252
  259. package/src/internal/holder/base-holder-manager.mts +0 -334
  260. package/src/internal/holder/holder-manager.mts +0 -85
  261. package/src/internal/holder/request-storage.mts +0 -127
  262. package/src/internal/holder/singleton-storage.mts +0 -92
  263. package/src/testing/README.md +0 -80
  264. package/src/testing/__tests__/test-container.spec.mts +0 -173
@@ -25,19 +25,45 @@ let InjectableType = /* @__PURE__ */ function(InjectableType$1) {
25
25
  return InjectableType$1;
26
26
  }({});
27
27
 
28
+ //#endregion
29
+ //#region src/symbols/injectable-token.mts
30
+ const InjectableTokenMeta = /* @__PURE__ */ Symbol.for("InjectableTokenMeta");
31
+
28
32
  //#endregion
29
33
  //#region src/token/injection-token.mts
34
+ /**
35
+ * Simple hash function for deterministic ID generation
36
+ */ function simpleHash(str) {
37
+ let hash = 0;
38
+ for (let i = 0; i < str.length; i++) {
39
+ const char = str.charCodeAt(i);
40
+ hash = (hash << 5) - hash + char;
41
+ hash = hash & hash;
42
+ }
43
+ return Math.abs(hash).toString(36);
44
+ }
45
+ /**
46
+ * Generate deterministic ID from token name
47
+ */ function generateTokenId(name, customId) {
48
+ if (customId) return customId;
49
+ let base;
50
+ if (typeof name === "function") base = `${name.name}_${name.toString()}`;
51
+ else if (typeof name === "symbol") base = `symbol_${name.toString()}`;
52
+ else base = `token_${name}`;
53
+ return `${base.split("_")[0]}_${simpleHash(base)}`;
54
+ }
30
55
  var InjectionToken = class InjectionToken {
31
56
  name;
32
57
  schema;
33
- id = globalThis.crypto.randomUUID();
58
+ id;
34
59
  formattedName = null;
35
- constructor(name, schema) {
60
+ constructor(name, schema, customId) {
36
61
  this.name = name;
37
62
  this.schema = schema;
63
+ this.id = generateTokenId(name, customId);
38
64
  }
39
- static create(name, schema) {
40
- return new InjectionToken(name, schema);
65
+ static create(name, schema, customId) {
66
+ return new InjectionToken(name, schema, customId);
41
67
  }
42
68
  static bound(token, value) {
43
69
  return new BoundInjectionToken(token, value);
@@ -106,6 +132,7 @@ var FactoryInjectionToken = class {
106
132
  var Registry = class {
107
133
  parent;
108
134
  factories = /* @__PURE__ */ new Map();
135
+ highestPriority = /* @__PURE__ */ new Map();
109
136
  constructor(parent) {
110
137
  this.parent = parent;
111
138
  }
@@ -115,23 +142,50 @@ var Registry = class {
115
142
  return false;
116
143
  }
117
144
  get(token) {
118
- const factory = this.factories.get(token.id);
145
+ const factory = this.highestPriority.get(token.id);
119
146
  if (!factory) {
120
147
  if (this.parent) return this.parent.get(token);
121
148
  throw new Error(`[Registry] No factory found for ${token.toString()}`);
122
149
  }
123
150
  return factory;
124
151
  }
125
- set(token, scope, target, type) {
126
- this.factories.set(token.id, {
152
+ getAll(token) {
153
+ const records = this.factories.get(token.id);
154
+ if (!records || records.length === 0) {
155
+ if (this.parent) return this.parent.getAll(token);
156
+ return [];
157
+ }
158
+ return [...records].sort((a, b) => b.priority - a.priority);
159
+ }
160
+ set(token, scope, target, type, priority = 0) {
161
+ const record = {
127
162
  scope,
128
163
  originalToken: token,
129
164
  target,
130
- type
131
- });
165
+ type,
166
+ priority
167
+ };
168
+ const existing = this.factories.get(token.id) || [];
169
+ existing.push(record);
170
+ this.factories.set(token.id, existing);
171
+ const currentHighest = this.highestPriority.get(token.id);
172
+ if (!currentHighest || priority > currentHighest.priority) this.highestPriority.set(token.id, record);
132
173
  }
133
174
  delete(token) {
134
- this.factories.delete(token.id);
175
+ const records = this.factories.get(token.id);
176
+ if (records) {
177
+ const deletedHighest = this.highestPriority.get(token.id);
178
+ this.factories.delete(token.id);
179
+ this.highestPriority.delete(token.id);
180
+ if (deletedHighest && records.length > 1) {
181
+ const remaining = records.filter((r) => r.originalToken.id !== deletedHighest.originalToken.id || r.priority !== deletedHighest.priority);
182
+ if (remaining.length > 0) {
183
+ const newHighest = remaining.reduce((max, current) => current.priority > max.priority ? current : max);
184
+ this.highestPriority.set(token.id, newHighest);
185
+ this.factories.set(token.id, remaining);
186
+ }
187
+ }
188
+ }
135
189
  }
136
190
  /**
137
191
  * Updates the scope of an already registered factory.
@@ -142,29 +196,29 @@ var Registry = class {
142
196
  * @param scope The new scope to set
143
197
  * @returns true if the scope was updated, false if the token was not found
144
198
  */ updateScope(token, scope) {
145
- const factory = this.factories.get(token.id);
146
- if (factory) {
147
- factory.scope = scope;
199
+ const records = this.factories.get(token.id);
200
+ if (records && records.length > 0) {
201
+ records.forEach((record) => {
202
+ record.scope = scope;
203
+ });
204
+ const highest = this.highestPriority.get(token.id);
205
+ if (highest) highest.scope = scope;
148
206
  return true;
149
207
  }
150
208
  if (this.parent) return this.parent.updateScope(token, scope);
151
209
  return false;
152
210
  }
153
211
  };
154
- const globalRegistry = new Registry();
155
-
156
- //#endregion
157
- //#region src/symbols/injectable-token.mts
158
- const InjectableTokenMeta = Symbol.for("InjectableTokenMeta");
212
+ const globalRegistry = /* @__PURE__ */ new Registry();
159
213
 
160
214
  //#endregion
161
215
  //#region src/decorators/injectable.decorator.mts
162
- function Injectable({ scope = InjectableScope.Singleton, token, schema, registry = globalRegistry } = {}) {
216
+ function Injectable({ scope = InjectableScope.Singleton, token, schema, registry = globalRegistry, priority = 0 } = {}) {
163
217
  return (target, context) => {
164
- if (context && context.kind !== "class" || target instanceof Function && !context) throw new Error("[ServiceLocator] @Injectable decorator can only be used on classes.");
165
- if (schema && token) throw new Error("[ServiceLocator] @Injectable decorator cannot have both a token and a schema");
218
+ if (context && context.kind !== "class" || target instanceof Function && !context) throw new Error("[DI] @Injectable decorator can only be used on classes.");
219
+ if (schema && token) throw new Error("[DI] @Injectable decorator cannot have both a token and a schema");
166
220
  let injectableToken = token ?? InjectionToken.create(target, schema);
167
- registry.set(injectableToken, scope, target, InjectableType.Class);
221
+ registry.set(injectableToken, scope, target, InjectableType.Class, priority);
168
222
  target[InjectableTokenMeta] = injectableToken;
169
223
  return target;
170
224
  };
@@ -172,45 +226,97 @@ function Injectable({ scope = InjectableScope.Singleton, token, schema, registry
172
226
 
173
227
  //#endregion
174
228
  //#region src/errors/di-error.mts
175
- let DIErrorCode = /* @__PURE__ */ function(DIErrorCode$1) {
229
+ var DIErrorCode = /* @__PURE__ */ function(DIErrorCode$1) {
176
230
  DIErrorCode$1["FactoryNotFound"] = "FactoryNotFound";
177
231
  DIErrorCode$1["FactoryTokenNotResolved"] = "FactoryTokenNotResolved";
178
232
  DIErrorCode$1["InstanceNotFound"] = "InstanceNotFound";
179
233
  DIErrorCode$1["InstanceDestroying"] = "InstanceDestroying";
180
234
  DIErrorCode$1["CircularDependency"] = "CircularDependency";
235
+ DIErrorCode$1["TokenValidationError"] = "TokenValidationError";
236
+ DIErrorCode$1["TokenSchemaRequiredError"] = "TokenSchemaRequiredError";
237
+ DIErrorCode$1["ClassNotInjectable"] = "ClassNotInjectable";
238
+ DIErrorCode$1["ScopeMismatchError"] = "ScopeMismatchError";
239
+ DIErrorCode$1["PriorityConflictError"] = "PriorityConflictError";
240
+ DIErrorCode$1["StorageError"] = "StorageError";
241
+ DIErrorCode$1["InitializationError"] = "InitializationError";
242
+ DIErrorCode$1["DependencyResolutionError"] = "DependencyResolutionError";
181
243
  DIErrorCode$1["UnknownError"] = "UnknownError";
182
244
  return DIErrorCode$1;
183
245
  }({});
184
246
  var DIError = class DIError extends Error {
247
+ code;
248
+ message;
185
249
  context;
186
250
  constructor(code, message, context) {
187
- super(message);
188
- this.code = code;
189
- this.message = message;
251
+ super(message), this.code = code, this.message = message;
190
252
  this.context = context;
253
+ this.name = "DIError";
191
254
  }
192
255
  static factoryNotFound(name) {
193
- return new DIError(DIErrorCode.FactoryNotFound, `Factory ${name} not found`, { name });
256
+ return new DIError("FactoryNotFound", `Factory ${name} not found`, { name });
194
257
  }
195
258
  static factoryTokenNotResolved(token) {
196
- return new DIError(DIErrorCode.FactoryTokenNotResolved, `Factory token not resolved: ${token?.toString() ?? "unknown"}`, { token });
259
+ return new DIError("FactoryTokenNotResolved", `Factory token not resolved: ${token?.toString() ?? "unknown"}`, { token });
197
260
  }
198
261
  static instanceNotFound(name) {
199
- return new DIError(DIErrorCode.InstanceNotFound, `Instance ${name} not found`, { name });
262
+ return new DIError("InstanceNotFound", `Instance ${name} not found`, { name });
200
263
  }
201
264
  static instanceDestroying(name) {
202
- return new DIError(DIErrorCode.InstanceDestroying, `Instance ${name} destroying`, { name });
265
+ return new DIError("InstanceDestroying", `Instance ${name} destroying`, { name });
203
266
  }
204
267
  static unknown(message, context) {
205
- if (message instanceof Error) return new DIError(DIErrorCode.UnknownError, message.message, {
268
+ if (message instanceof Error) return new DIError("UnknownError", message.message, {
206
269
  ...context,
207
270
  parent: message
208
271
  });
209
- return new DIError(DIErrorCode.UnknownError, message, context);
272
+ return new DIError("UnknownError", message, context);
210
273
  }
211
274
  static circularDependency(cycle) {
212
- const cycleStr = cycle.join(" -> ");
213
- return new DIError(DIErrorCode.CircularDependency, `Circular dependency detected: ${cycleStr}`, { cycle });
275
+ return new DIError("CircularDependency", `Circular dependency detected: ${cycle.join(" -> ")}`, { cycle });
276
+ }
277
+ static tokenValidationError(message, schema, value) {
278
+ return new DIError("TokenValidationError", message, {
279
+ schema,
280
+ value
281
+ });
282
+ }
283
+ static tokenSchemaRequiredError(token) {
284
+ return new DIError("TokenSchemaRequiredError", `Token ${token?.toString() ?? "unknown"} requires schema arguments and cannot be used with addInstance. Use BoundInjectionToken or provide arguments when resolving.`, { token });
285
+ }
286
+ static classNotInjectable(className) {
287
+ return new DIError("ClassNotInjectable", `Class ${className} is not decorated with @Injectable.`, { className });
288
+ }
289
+ static scopeMismatchError(token, expectedScope, actualScope) {
290
+ return new DIError("ScopeMismatchError", `Scope mismatch for ${token?.toString() ?? "unknown"}: expected ${expectedScope}, got ${actualScope}`, {
291
+ token,
292
+ expectedScope,
293
+ actualScope
294
+ });
295
+ }
296
+ static priorityConflictError(token, records) {
297
+ return new DIError("PriorityConflictError", `Priority conflict for ${token?.toString() ?? "unknown"}: multiple bindings with same priority`, {
298
+ token,
299
+ records
300
+ });
301
+ }
302
+ static storageError(message, operation, instanceName) {
303
+ return new DIError("StorageError", `Storage error: ${message}`, {
304
+ operation,
305
+ instanceName
306
+ });
307
+ }
308
+ static initializationError(serviceName, error) {
309
+ return new DIError("InitializationError", `Service ${serviceName} initialization failed: ${error instanceof Error ? error.message : error}`, {
310
+ serviceName,
311
+ error
312
+ });
313
+ }
314
+ static dependencyResolutionError(serviceName, dependencyName, error) {
315
+ return new DIError("DependencyResolutionError", `Failed to resolve dependency ${dependencyName} for service ${serviceName}: ${error instanceof Error ? error.message : error}`, {
316
+ serviceName,
317
+ dependencyName,
318
+ error
319
+ });
214
320
  }
215
321
  };
216
322
 
@@ -240,6 +346,9 @@ function getModule() {
240
346
  function createAsyncLocalStorage() {
241
347
  return getModule().createAsyncLocalStorage();
242
348
  }
349
+ function isUsingNativeAsyncLocalStorage() {
350
+ return getModule().isUsingNativeAsyncLocalStorage();
351
+ }
243
352
 
244
353
  //#endregion
245
354
  //#region src/internal/context/resolution-context.mts
@@ -294,135 +403,21 @@ function getResolutionContext() {
294
403
  }
295
404
 
296
405
  //#endregion
297
- //#region src/utils/get-injectors.mts
298
- function getInjectors() {
299
- let currentFactoryContext = null;
300
- function provideFactoryContext$1(context) {
301
- const original = currentFactoryContext;
302
- currentFactoryContext = context;
303
- return original;
304
- }
305
- function getFactoryContext() {
306
- if (!currentFactoryContext) throw new Error("[Injector] Trying to access injection context outside of a injectable context");
307
- return currentFactoryContext;
308
- }
309
- let promiseCollector = null;
310
- let injectState = null;
311
- function getRequest(token, args, skipCycleTracking = false) {
312
- if (!injectState) throw new Error("[Injector] Trying to make a request outside of a injectable context");
313
- if (injectState.isFrozen) {
314
- const idx = injectState.currentIndex++;
315
- const request$1 = injectState.requests[idx];
316
- if (request$1.token !== token) throw new Error(`[Injector] Wrong token order. Expected ${request$1.token.toString()} but got ${token.toString()}`);
317
- return request$1;
318
- }
319
- let result = null;
320
- let error = null;
321
- const doInject = () => getFactoryContext().inject(token, args).then((r) => {
322
- result = r;
323
- return r;
324
- }).catch((e) => {
325
- error = e;
326
- });
327
- const request = {
328
- token,
329
- promise: skipCycleTracking ? withoutResolutionContext(doInject) : doInject(),
330
- get result() {
331
- return result;
332
- },
333
- get error() {
334
- return error;
335
- }
336
- };
337
- injectState.requests.push(request);
338
- injectState.currentIndex++;
339
- return request;
340
- }
341
- function asyncInject$1(token, args) {
342
- if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
343
- const request = getRequest(token[InjectableTokenMeta] ?? token, args, true);
344
- return request.promise.then((result) => {
345
- if (request.error) throw request.error;
346
- return result;
347
- });
348
- }
349
- function wrapSyncInit$1(cb) {
350
- return (previousState) => {
351
- const promises = [];
352
- const originalPromiseCollector = promiseCollector;
353
- const originalInjectState = injectState;
354
- injectState = previousState ? {
355
- ...previousState,
356
- currentIndex: 0
357
- } : {
358
- currentIndex: 0,
359
- isFrozen: false,
360
- requests: []
361
- };
362
- promiseCollector = (promise) => {
363
- promises.push(promise);
364
- };
365
- const result = cb();
366
- promiseCollector = originalPromiseCollector;
367
- const newInjectState = {
368
- ...injectState,
369
- isFrozen: true
370
- };
371
- injectState = originalInjectState;
372
- return [
373
- result,
374
- promises,
375
- newInjectState
376
- ];
377
- };
378
- }
379
- function inject$1(token, args) {
380
- const realToken = token[InjectableTokenMeta] ?? token;
381
- if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
382
- const instance = getFactoryContext().container.tryGetSync(realToken, args);
383
- if (!instance) {
384
- const request = getRequest(realToken, args);
385
- if (request.error) throw request.error;
386
- else if (request.result) return request.result;
387
- if (promiseCollector) promiseCollector(request.promise);
388
- return new Proxy({}, { get() {
389
- throw new Error(`[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`);
390
- } });
391
- }
392
- return instance;
393
- }
394
- function optional$1(token, args) {
395
- try {
396
- return inject$1(token, args);
397
- } catch {
398
- return null;
399
- }
400
- }
401
- return {
402
- asyncInject: asyncInject$1,
403
- inject: inject$1,
404
- optional: optional$1,
405
- wrapSyncInit: wrapSyncInit$1,
406
- provideFactoryContext: provideFactoryContext$1
407
- };
408
- }
409
-
410
- //#endregion
411
- //#region src/utils/get-injectable-token.mts
412
- function getInjectableToken(target) {
413
- const token = target[InjectableTokenMeta];
414
- if (!token) throw new Error(`[ServiceLocator] Class ${target.name} is not decorated with @Injectable.`);
415
- return token;
416
- }
417
-
418
- //#endregion
419
- //#region src/injectors.mts
420
- const defaultInjectors = getInjectors();
421
- const asyncInject = defaultInjectors.asyncInject;
422
- const inject = defaultInjectors.inject;
423
- const optional = defaultInjectors.optional;
424
- const wrapSyncInit = defaultInjectors.wrapSyncInit;
425
- const provideFactoryContext = defaultInjectors.provideFactoryContext;
406
+ //#region src/internal/holder/instance-holder.mts
407
+ /**
408
+ * Represents the lifecycle status of an instance holder.
409
+ */
410
+ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
411
+ /** Instance has been successfully created and is ready for use */
412
+ InstanceStatus$1["Created"] = "created";
413
+ /** Instance is currently being created (async initialization in progress) */
414
+ InstanceStatus$1["Creating"] = "creating";
415
+ /** Instance is being destroyed (cleanup in progress) */
416
+ InstanceStatus$1["Destroying"] = "destroying";
417
+ /** Instance creation failed with an error */
418
+ InstanceStatus$1["Error"] = "error";
419
+ return InstanceStatus$1;
420
+ }({});
426
421
 
427
422
  //#endregion
428
423
  //#region src/internal/lifecycle/circular-detector.mts
@@ -483,200 +478,249 @@ const provideFactoryContext = defaultInjectors.provideFactoryContext;
483
478
  };
484
479
 
485
480
  //#endregion
486
- //#region src/internal/holder/instance-holder.mts
487
- /**
488
- * Represents the lifecycle status of an instance holder.
489
- */
490
- let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
491
- /** Instance has been successfully created and is ready for use */
492
- InstanceStatus$1["Created"] = "created";
493
- /** Instance is currently being created (async initialization in progress) */
494
- InstanceStatus$1["Creating"] = "creating";
495
- /** Instance is being destroyed (cleanup in progress) */
496
- InstanceStatus$1["Destroying"] = "destroying";
497
- /** Instance creation failed with an error */
498
- InstanceStatus$1["Error"] = "error";
499
- return InstanceStatus$1;
500
- }({});
501
-
502
- //#endregion
503
- //#region src/internal/holder/base-holder-manager.mts
481
+ //#region src/internal/core/instance-resolver.mts
504
482
  /**
505
- * Abstract base class providing common functionality for managing InstanceHolder objects.
483
+ * Resolves instances from tokens, handling caching, creation, and scope rules.
506
484
  *
507
- * Provides shared patterns for holder storage, creation, and lifecycle management
508
- * used by both singleton (HolderManager) and request-scoped (RequestContext) managers.
509
- */ var BaseHolderManager = class BaseHolderManager {
485
+ * Uses unified storage for both singleton and request-scoped services.
486
+ * Coordinates with ServiceInitializer for actual service creation.
487
+ * Integrates ScopeTracker for automatic scope upgrades.
488
+ */ var InstanceResolver = class {
489
+ registry;
490
+ storage;
491
+ serviceInitializer;
492
+ tokenResolver;
493
+ nameResolver;
494
+ scopeTracker;
495
+ serviceInvalidator;
496
+ eventBus;
510
497
  logger;
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;
516
- constructor(logger = null) {
498
+ constructor(registry, storage, serviceInitializer, tokenResolver, nameResolver, scopeTracker, serviceInvalidator, eventBus, logger = null) {
499
+ this.registry = registry;
500
+ this.storage = storage;
501
+ this.serviceInitializer = serviceInitializer;
502
+ this.tokenResolver = tokenResolver;
503
+ this.nameResolver = nameResolver;
504
+ this.scopeTracker = scopeTracker;
505
+ this.serviceInvalidator = serviceInvalidator;
506
+ this.eventBus = eventBus;
517
507
  this.logger = logger;
518
- this._holders = /* @__PURE__ */ new Map();
519
- this._dependents = /* @__PURE__ */ new Map();
520
508
  }
521
509
  /**
522
- * Protected getter for accessing the holders map from subclasses.
523
- */ get holders() {
524
- return this._holders;
510
+ * Resolves an instance for the given token and arguments.
511
+ * This method is used for singleton and transient services.
512
+ *
513
+ * @param token The injection token
514
+ * @param args Optional arguments
515
+ * @param contextContainer The container to use for creating context
516
+ * @param requestStorage Optional request storage (for scope upgrades)
517
+ * @param requestId Optional request ID (for scope upgrades)
518
+ */ async resolveInstance(token, args, contextContainer, requestStorage, requestId) {
519
+ return this.resolveWithStorage(token, args, contextContainer, this.storage, void 0, requestStorage, requestId);
525
520
  }
526
521
  /**
527
- * Deletes a holder by name and cleans up the reverse dependency index.
528
- * @param name The name of the holder to delete
529
- * @returns true if the holder was deleted, false if it didn't exist
530
- */ delete(name) {
531
- const holder = this._holders.get(name);
532
- if (holder) this.removeFromDependentsIndex(name, holder.deps);
533
- return this._holders.delete(name);
522
+ * Resolves a request-scoped instance for a ScopedContainer.
523
+ * The service will be stored in the ScopedContainer's request storage.
524
+ *
525
+ * @param token The injection token
526
+ * @param args Optional arguments
527
+ * @param scopedContainer The ScopedContainer that owns the request context
528
+ */ async resolveRequestScopedInstance(token, args, scopedContainer) {
529
+ return this.resolveWithStorage(token, args, scopedContainer.getParent(), scopedContainer.getParent().getStorage(), scopedContainer, scopedContainer.getStorage(), scopedContainer.getRequestId());
534
530
  }
535
531
  /**
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);
532
+ * Unified resolution method that works with any IHolderStorage.
533
+ * This eliminates duplication between singleton and request-scoped resolution.
534
+ *
535
+ * IMPORTANT: The check-and-store logic is carefully designed to avoid race conditions.
536
+ * The storage check and holder creation must happen synchronously (no awaits between).
537
+ *
538
+ * @param token The injection token
539
+ * @param args Optional arguments
540
+ * @param contextContainer The container for context
541
+ * @param storage The storage strategy to use
542
+ * @param scopedContainer Optional scoped container for request-scoped services
543
+ * @param requestStorage Optional request storage (for scope upgrades)
544
+ * @param requestId Optional request ID (for scope upgrades)
545
+ */ async resolveWithStorage(token, args, contextContainer, storage, scopedContainer, requestStorage, requestId) {
546
+ const [err, data] = await this.resolveTokenAndPrepareInstanceName(token, args, contextContainer, requestId, scopedContainer);
547
+ if (err) return [err];
548
+ const { instanceName, validatedArgs, realToken, scope } = data;
549
+ const getResult = storage.get(instanceName) ?? requestStorage?.get(instanceName) ?? null;
550
+ const getHolder = (name) => {
551
+ const result = storage.get(name);
552
+ if (result && result[0] === void 0 && result[1]) return result[1];
553
+ if (requestStorage) {
554
+ const reqResult = requestStorage.get(name);
555
+ if (reqResult && reqResult[0] === void 0 && reqResult[1]) return reqResult[1];
546
556
  }
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);
557
+ };
558
+ if (getResult !== null) {
559
+ const [error, holder$1] = getResult;
560
+ if (!error && holder$1) {
561
+ const waiterHolder = getCurrentResolutionContext()?.waiterHolder;
562
+ const readyResult = await this.waitForInstanceReady(holder$1, waiterHolder, getHolder);
563
+ if (readyResult[0]) return [readyResult[0]];
564
+ return [void 0, readyResult[1].instance];
565
+ }
566
+ if (error) {
567
+ const handledResult = await this.handleStorageError(instanceName, error, holder$1, storage);
568
+ if (handledResult) return handledResult;
560
569
  }
561
570
  }
571
+ const [createError, holder] = await this.createAndStoreInstance(instanceName, realToken, validatedArgs, contextContainer, storage, scopedContainer, requestStorage, requestId, scope);
572
+ if (createError) return [createError];
573
+ return [void 0, holder.instance];
562
574
  }
563
575
  /**
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
- /**
573
- * Filters holders based on a predicate function.
574
- * @param predicate Function to test each holder
575
- * @returns A new Map containing only the holders that match the predicate
576
- * @deprecated Use forEachHolder() for iteration to avoid allocations
577
- */ filter(predicate) {
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;
596
- }
597
- /**
598
- * Clears all holders from this manager and the reverse dependency index.
599
- */ clear() {
600
- this._holders.clear();
601
- this._dependents.clear();
576
+ * Internal method to resolve token args and create instance name.
577
+ * Handles factory token resolution and validation.
578
+ */ async resolveTokenAndPrepareInstanceName(token, args, contextContainer, requestId, scopedContainer) {
579
+ const [err, { actualToken, validatedArgs }] = this.tokenResolver.validateAndResolveTokenArgs(token, args);
580
+ if (err instanceof DIError && err.code === DIErrorCode.TokenValidationError) return [err];
581
+ else if (err instanceof DIError && err.code === DIErrorCode.FactoryTokenNotResolved && actualToken instanceof FactoryInjectionToken) {
582
+ this.logger?.log(`[InstanceResolver]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`);
583
+ const factoryCtx = {
584
+ inject: async (t, a) => (scopedContainer ?? contextContainer).get(t, a),
585
+ container: scopedContainer ?? contextContainer,
586
+ addDestroyListener: () => {}
587
+ };
588
+ await actualToken.resolve(factoryCtx);
589
+ return this.resolveTokenAndPrepareInstanceName(token, void 0, contextContainer, requestId, scopedContainer);
590
+ }
591
+ const realToken = this.tokenResolver.getRealToken(actualToken);
592
+ const scope = this.registry.get(realToken).scope;
593
+ return [void 0, {
594
+ instanceName: this.nameResolver.generateInstanceName(actualToken, validatedArgs, requestId, scope),
595
+ validatedArgs,
596
+ actualToken,
597
+ realToken,
598
+ scope
599
+ }];
602
600
  }
603
601
  /**
604
- * Gets the number of holders currently managed.
605
- */ size() {
606
- return this._holders.size;
602
+ * Handles storage error states (destroying, error, etc.).
603
+ * Returns a result if handled, null if should proceed with creation.
604
+ */ async handleStorageError(instanceName, error, holder, storage) {
605
+ switch (error.code) {
606
+ case DIErrorCode.InstanceDestroying:
607
+ this.logger?.log(`[InstanceResolver] Instance ${instanceName} is being destroyed, waiting...`);
608
+ if (holder?.destroyPromise) await holder.destroyPromise;
609
+ const newResult = storage.get(instanceName);
610
+ if (newResult !== null && !newResult[0]) {
611
+ const getHolder = (name) => {
612
+ const result = storage.get(name);
613
+ return result && result[0] === void 0 && result[1] ? result[1] : void 0;
614
+ };
615
+ const readyResult = await this.waitForInstanceReady(newResult[1], void 0, getHolder);
616
+ if (readyResult[0]) return [readyResult[0]];
617
+ return [void 0, readyResult[1].instance];
618
+ }
619
+ return null;
620
+ default:
621
+ if (holder) {
622
+ this.logger?.log(`[InstanceResolver] Removing failed instance ${instanceName} from storage to allow retry`);
623
+ storage.delete(instanceName);
624
+ }
625
+ return null;
626
+ }
607
627
  }
608
628
  /**
609
- * Creates a new holder with Creating status and a deferred creation promise.
610
- * This is useful for creating placeholder holders that can be fulfilled later.
611
- * @param name The name of the instance
612
- * @param type The injectable type
613
- * @param scope The injectable scope
614
- * @param deps Optional set of dependencies
615
- * @returns A tuple containing the deferred promise and the holder
616
- */ createCreatingHolder(name, type, scope, deps = /* @__PURE__ */ new Set()) {
617
- const deferred = Promise.withResolvers();
618
- return [deferred, {
619
- status: InstanceStatus.Creating,
620
- name,
621
- instance: null,
622
- creationPromise: deferred.promise,
623
- destroyPromise: null,
624
- type,
625
- scope,
626
- deps,
627
- destroyListeners: [],
628
- createdAt: Date.now(),
629
- waitingFor: /* @__PURE__ */ new Set()
630
- }];
629
+ * Creates a new instance and stores it using the provided storage strategy.
630
+ * This unified method replaces instantiateServiceFromRegistry and createRequestScopedInstance.
631
+ *
632
+ * For transient services, the instance is created but not stored (no caching).
633
+ */ async createAndStoreInstance(instanceName, realToken, args, contextContainer, storage, scopedContainer, requestStorage, requestId, scope) {
634
+ this.logger?.log(`[InstanceResolver]#createAndStoreInstance() Creating instance for ${instanceName}`);
635
+ if (!this.registry.has(realToken)) return [DIError.factoryNotFound(realToken.name.toString())];
636
+ const record = this.registry.get(realToken);
637
+ const { type, scope: recordScope } = record;
638
+ const serviceScope = scope || recordScope;
639
+ if (serviceScope === InjectableScope.Transient) return this.createTransientInstance(instanceName, record, args, contextContainer, scopedContainer, requestStorage, requestId);
640
+ if (serviceScope === InjectableScope.Request && !requestStorage) return [DIError.initializationError(`Request storage is required for request-scoped services`, instanceName)];
641
+ let storageToUse;
642
+ if (serviceScope === InjectableScope.Request) storageToUse = requestStorage;
643
+ else storageToUse = storage;
644
+ const [deferred, holder] = storageToUse.createHolder(instanceName, type, /* @__PURE__ */ new Set());
645
+ storageToUse.set(instanceName, holder);
646
+ const ctx = this.createServiceInitializationContext(scopedContainer ?? contextContainer, instanceName, serviceScope, holder.deps, realToken, requestStorage, requestId);
647
+ holder.destroyListeners = ctx.getDestroyListeners();
648
+ const getHolder = (name) => {
649
+ const result = storage.get(name);
650
+ if (result && result[0] === void 0 && result[1]) return result[1];
651
+ if (requestStorage) {
652
+ const reqResult = requestStorage.get(name);
653
+ if (reqResult && reqResult[0] === void 0 && reqResult[1]) return reqResult[1];
654
+ }
655
+ };
656
+ withResolutionContext(holder, getHolder, () => {
657
+ this.serviceInitializer.instantiateService(ctx, record, args).then(async (result) => {
658
+ const [error, instance] = result.length === 2 ? result : [result[0], void 0];
659
+ const newScope = record.scope;
660
+ const newName = this.nameResolver.generateInstanceName(realToken, args, requestId, newScope);
661
+ await this.handleInstantiationResult(newName, holder, ctx, deferred, newScope, error, instance, scopedContainer, requestStorage, requestId);
662
+ }).catch(async (error) => {
663
+ const newScope = record.scope;
664
+ const newName = this.nameResolver.generateInstanceName(realToken, args, requestId, newScope);
665
+ await this.handleInstantiationError(newName, holder, deferred, newScope, error);
666
+ }).catch(() => {});
667
+ });
668
+ const waiterHolder = getCurrentResolutionContext()?.waiterHolder;
669
+ return this.waitForInstanceReady(holder, waiterHolder, getHolder);
631
670
  }
632
671
  /**
633
- * Creates a new holder with Created status and an actual instance.
634
- * This is useful for creating holders that already have their instance ready.
635
- * @param name The name of the instance
636
- * @param instance The actual instance to store
637
- * @param type The injectable type
638
- * @param scope The injectable scope
639
- * @param deps Optional set of dependencies
640
- * @returns The created holder
641
- */ createCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set()) {
642
- return {
672
+ * Creates a transient instance without storage or locking.
673
+ * Each call creates a new instance.
674
+ */ async createTransientInstance(instanceName, record, args, contextContainer, scopedContainer, requestStorage, requestId) {
675
+ this.logger?.log(`[InstanceResolver]#createTransientInstance() Creating transient instance for ${instanceName}`);
676
+ const ctx = this.createServiceInitializationContext(scopedContainer ?? contextContainer, instanceName, InjectableScope.Transient, /* @__PURE__ */ new Set(), record.originalToken, requestStorage, requestId);
677
+ const [error, instance] = await this.serviceInitializer.instantiateService(ctx, record, args);
678
+ if (error) return [error];
679
+ return [void 0, {
643
680
  status: InstanceStatus.Created,
644
- name,
681
+ name: instanceName,
645
682
  instance,
646
683
  creationPromise: null,
647
684
  destroyPromise: null,
648
- type,
649
- scope,
650
- deps,
651
- destroyListeners: [],
685
+ type: record.type,
686
+ scope: InjectableScope.Transient,
687
+ deps: ctx.dependencies,
688
+ destroyListeners: ctx.getDestroyListeners(),
652
689
  createdAt: Date.now(),
653
690
  waitingFor: /* @__PURE__ */ new Set()
654
- };
691
+ }];
655
692
  }
656
693
  /**
657
- * Gets all holder names currently managed.
658
- */ getAllNames() {
659
- return Array.from(this._holders.keys());
694
+ * Handles successful service instantiation.
695
+ */ async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, _scopedContainer, requestStorage, _requestId) {
696
+ holder.instance = instance;
697
+ holder.status = InstanceStatus.Created;
698
+ const storageForSubscriptions = requestStorage || this.storage;
699
+ if (ctx.dependencies.size > 0) this.serviceInvalidator.setupDependencySubscriptions(instanceName, ctx.dependencies, storageForSubscriptions, holder);
700
+ this.logger?.log(`[InstanceResolver] Instance ${instanceName} created successfully`);
701
+ deferred.resolve([void 0, instance]);
660
702
  }
661
703
  /**
662
- * Gets all holders currently managed.
663
- */ getAllHolders() {
664
- return Array.from(this._holders.values());
704
+ * Handles service instantiation errors.
705
+ */ async handleInstantiationError(instanceName, holder, deferred, scope, error) {
706
+ holder.status = InstanceStatus.Error;
707
+ holder.instance = error instanceof DIError ? error : DIError.unknown(error);
708
+ this.logger?.error(`[InstanceResolver] Instance ${instanceName} creation failed:`, error);
709
+ deferred.reject(error instanceof DIError ? error : DIError.unknown(error));
665
710
  }
666
711
  /**
667
- * Checks if this manager has any holders.
668
- */ isEmpty() {
669
- return this._holders.size === 0;
712
+ * Handles instantiation result (success or error).
713
+ */ async handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer, requestStorage, requestId) {
714
+ if (error) await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
715
+ else await this.handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer, requestStorage, requestId);
670
716
  }
671
717
  /**
672
- * Waits for a holder to be ready and returns the appropriate result.
673
- * This is a shared utility used by both singleton and request-scoped resolution.
718
+ * Waits for an instance holder to be ready and returns the appropriate result.
674
719
  *
675
720
  * @param holder The holder to wait for
676
721
  * @param waiterHolder Optional holder that is doing the waiting (for circular dependency detection)
677
722
  * @param getHolder Optional function to retrieve holders by name (required if waiterHolder is provided)
678
- * @returns A promise that resolves with [undefined, holder] on success or [DIError] on failure
679
- */ static async waitForHolderReady(holder, waiterHolder, getHolder) {
723
+ */ async waitForInstanceReady(holder, waiterHolder, getHolder) {
680
724
  switch (holder.status) {
681
725
  case InstanceStatus.Creating:
682
726
  if (waiterHolder && getHolder) {
@@ -691,642 +735,303 @@ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
691
735
  if (waiterHolder) waiterHolder.waitingFor.delete(holder.name);
692
736
  }
693
737
  }
694
- return BaseHolderManager.waitForHolderReady(holder, waiterHolder, getHolder);
738
+ return this.waitForInstanceReady(holder, waiterHolder, getHolder);
695
739
  case InstanceStatus.Destroying: return [DIError.instanceDestroying(holder.name)];
696
740
  case InstanceStatus.Error: return [holder.instance];
697
741
  case InstanceStatus.Created: return [void 0, holder];
698
- default: return [DIError.instanceNotFound("unknown")];
742
+ default: return [DIError.instanceNotFound(holder?.name ?? "unknown")];
699
743
  }
700
744
  }
745
+ /**
746
+ * Creates a ServiceInitializationContext for service instantiation.
747
+ */ createServiceInitializationContext(container, serviceName, scope, deps, serviceToken, requestStorage, requestId) {
748
+ const destroyListeners = [];
749
+ return {
750
+ inject: async (token, args) => {
751
+ const actualToken = typeof token === "function" ? this.tokenResolver.normalizeToken(token) : token;
752
+ const realToken = this.tokenResolver.getRealToken(actualToken);
753
+ const depScope = this.registry.get(realToken).scope;
754
+ const dependencyRequestId = depScope === InjectableScope.Request ? requestId : void 0;
755
+ const finalDepName = this.nameResolver.generateInstanceName(actualToken, args, dependencyRequestId, depScope);
756
+ if (scope === InjectableScope.Singleton && depScope === InjectableScope.Request && requestStorage && requestId) {
757
+ const [needsUpgrade, newServiceName] = this.scopeTracker.checkAndUpgradeScope(serviceName, scope, finalDepName, depScope, serviceToken, this.storage, requestStorage, requestId);
758
+ if (needsUpgrade && newServiceName) {}
759
+ }
760
+ deps.add(finalDepName);
761
+ return container.get(token, args);
762
+ },
763
+ container,
764
+ addDestroyListener: (listener) => {
765
+ destroyListeners.push(listener);
766
+ },
767
+ getDestroyListeners: () => destroyListeners,
768
+ serviceName,
769
+ dependencies: deps,
770
+ scope,
771
+ trackDependency: (name, depScope) => {
772
+ deps.add(name);
773
+ if (scope === InjectableScope.Singleton && depScope === InjectableScope.Request && requestStorage && requestId) this.scopeTracker.checkAndUpgradeScope(serviceName, scope, name, depScope, serviceToken, this.storage, requestStorage, requestId);
774
+ }
775
+ };
776
+ }
701
777
  };
702
778
 
703
779
  //#endregion
704
- //#region src/internal/context/request-context.mts
780
+ //#region src/internal/core/name-resolver.mts
705
781
  /**
706
- * Default implementation of RequestContext.
707
- *
708
- * Extends BaseHolderManager to provide holder management functionality
709
- * with request-specific metadata and lifecycle support.
710
- */ var DefaultRequestContext = class extends BaseHolderManager {
711
- requestId;
712
- priority;
713
- metadata = /* @__PURE__ */ new Map();
714
- createdAt = Date.now();
715
- constructor(requestId, priority = 100, initialMetadata) {
716
- super(null), this.requestId = requestId, this.priority = priority;
717
- if (initialMetadata) Object.entries(initialMetadata).forEach(([key, value]) => {
718
- this.metadata.set(key, value);
719
- });
720
- }
721
- /**
722
- * Public getter for holders to maintain interface compatibility.
723
- */ get holders() {
724
- return this._holders;
725
- }
726
- /**
727
- * Gets a holder by name. For RequestContext, this is a simple lookup.
728
- */ get(name) {
729
- return this._holders.get(name);
730
- }
731
- /**
732
- * Sets a holder by name.
733
- */ set(name, holder) {
734
- this._holders.set(name, holder);
782
+ * Simple LRU cache for instance name generation.
783
+ * Uses a Map which maintains insertion order for efficient LRU eviction.
784
+ */ var InstanceNameCache = class {
785
+ cache = /* @__PURE__ */ new Map();
786
+ maxSize;
787
+ constructor(maxSize = 1e3) {
788
+ this.maxSize = maxSize;
735
789
  }
736
- /**
737
- * Checks if a holder exists by name.
738
- */ has(name) {
739
- return this._holders.has(name);
790
+ get(key) {
791
+ const value = this.cache.get(key);
792
+ if (value !== void 0) {
793
+ this.cache.delete(key);
794
+ this.cache.set(key, value);
795
+ }
796
+ return value;
740
797
  }
741
- addInstance(instanceName, instance, holder) {
742
- if (instanceName instanceof InjectionToken) {
743
- const name = instanceName.toString();
744
- const createdHolder = this.createCreatedHolder(name, instance, InjectableType.Class, InjectableScope.Singleton, /* @__PURE__ */ new Set());
745
- this._holders.set(name, createdHolder);
746
- } else {
747
- if (!holder) throw new Error("Holder is required when adding an instance by name");
748
- this._holders.set(instanceName, holder);
798
+ set(key, value) {
799
+ if (this.cache.has(key)) this.cache.delete(key);
800
+ else if (this.cache.size >= this.maxSize) {
801
+ const firstKey = this.cache.keys().next().value;
802
+ if (firstKey !== void 0) this.cache.delete(firstKey);
749
803
  }
804
+ this.cache.set(key, value);
750
805
  }
751
806
  clear() {
752
- super.clear();
753
- this.metadata.clear();
754
- }
755
- getMetadata(key) {
756
- return this.metadata.get(key);
757
- }
758
- setMetadata(key, value) {
759
- this.metadata.set(key, value);
807
+ this.cache.clear();
760
808
  }
761
809
  };
762
810
  /**
763
- * Creates a new request context with the given parameters.
764
- */ function createRequestContext(requestId, priority = 100, initialMetadata) {
765
- return new DefaultRequestContext(requestId, priority, initialMetadata);
811
+ * Simple hash function for deterministic hashing of arguments
812
+ */ function hashArgs(args) {
813
+ const str = JSON.stringify(args, Object.keys(args || {}).sort());
814
+ let hash = 0;
815
+ for (let i = 0; i < str.length; i++) {
816
+ const char = str.charCodeAt(i);
817
+ hash = (hash << 5) - hash + char;
818
+ hash = hash & hash;
819
+ }
820
+ return Math.abs(hash).toString(36);
766
821
  }
767
-
768
- //#endregion
769
- //#region src/internal/holder/request-storage.mts
770
822
  /**
771
- * Storage implementation for Request-scoped services.
823
+ * Handles instance name generation with support for requestId and scope.
772
824
  *
773
- * Wraps a RequestContext instance from a ScopedContainer and provides
774
- * the IHolderStorage interface. This allows the InstanceResolver to work
775
- * with request-scoped storage using the same interface as singleton storage.
776
- */
777
- var RequestStorage = class {
778
- scope = InjectableScope.Request;
779
- constructor(contextHolder, holderManager) {
780
- this.contextHolder = contextHolder;
781
- this.holderManager = holderManager;
825
+ * Generates unique instance identifiers based on token, arguments, and scope.
826
+ * Request-scoped services MUST include requestId in their name for proper isolation.
827
+ */ var NameResolver = class {
828
+ logger;
829
+ instanceNameCache = new InstanceNameCache();
830
+ constructor(logger = null) {
831
+ this.logger = logger;
782
832
  }
783
- get(instanceName) {
784
- const holder = this.contextHolder.get(instanceName);
785
- if (!holder) return null;
786
- switch (holder.status) {
787
- case InstanceStatus.Destroying: return [DIError.instanceDestroying(instanceName), holder];
788
- case InstanceStatus.Error: return [holder.instance, holder];
789
- case InstanceStatus.Creating:
790
- case InstanceStatus.Created: return [void 0, holder];
791
- default: return null;
833
+ /**
834
+ * Generates a unique instance name based on token, arguments, requestId, and scope.
835
+ *
836
+ * Name formats:
837
+ * - Singleton/Transient without args: `${tokenId}`
838
+ * - Singleton/Transient with args: `${tokenId}:${argsHash}`
839
+ * - Request without args: `${tokenId}:requestId=${requestId}`
840
+ * - Request with args: `${tokenId}:requestId=${requestId}:${argsHash}`
841
+ *
842
+ * @param token The injection token
843
+ * @param args Optional arguments
844
+ * @param requestId Optional request ID (required for request-scoped services)
845
+ * @param scope Optional scope (used to determine if requestId should be included)
846
+ * @returns The generated instance name
847
+ */ generateInstanceName(token, args, requestId, scope) {
848
+ const tokenStr = token.toString();
849
+ const isRequest = scope === InjectableScope.Request;
850
+ if (isRequest && !requestId) throw new Error(`[NameResolver] requestId is required for request-scoped services`);
851
+ const cacheKey = `${tokenStr}:${scope}:${requestId || ""}:${args ? JSON.stringify(args) : ""}`;
852
+ const cached = this.instanceNameCache.get(cacheKey);
853
+ if (cached !== void 0) return cached;
854
+ let result = tokenStr;
855
+ if (isRequest && requestId) result = `${result}:requestId=${requestId}`;
856
+ if (args) {
857
+ const argsHash = hashArgs(args);
858
+ result = `${result}:${argsHash}`;
792
859
  }
860
+ this.instanceNameCache.set(cacheKey, result);
861
+ return result;
793
862
  }
794
- set(instanceName, holder) {
795
- this.contextHolder.set(instanceName, holder);
796
- }
797
- delete(instanceName) {
798
- return this.contextHolder.delete(instanceName);
799
- }
800
- createHolder(instanceName, type, deps) {
801
- return this.holderManager.createCreatingHolder(instanceName, type, this.scope, deps);
802
- }
803
- handles(scope) {
804
- return scope === InjectableScope.Request;
805
- }
806
- getAllNames() {
807
- const names = [];
808
- for (const [name] of this.contextHolder.holders) names.push(name);
809
- return names;
810
- }
811
- forEach(callback) {
812
- for (const [name, holder] of this.contextHolder.holders) callback(name, holder);
813
- }
814
- findByInstance(instance) {
815
- for (const holder of this.contextHolder.holders.values()) if (holder.instance === instance) return holder;
816
- return null;
863
+ /**
864
+ * Upgrades an existing instance name to include requestId.
865
+ * Preserves any args hash that might already be in the name.
866
+ *
867
+ * Examples:
868
+ * - `TokenName` → `TokenName:requestId=req-123`
869
+ * - `TokenName:abc123` → `TokenName:requestId=req-123:abc123`
870
+ *
871
+ * @param existingName The existing instance name (without requestId)
872
+ * @param requestId The request ID to add
873
+ * @returns The upgraded instance name with requestId
874
+ */ upgradeInstanceNameToRequest(existingName, requestId) {
875
+ if (existingName.includes(`:requestId=${requestId}`)) return existingName;
876
+ if (/:requestId=/.test(existingName)) return existingName;
877
+ const colonIndex = existingName.indexOf(":");
878
+ if (colonIndex === -1) return `${existingName}:requestId=${requestId}`;
879
+ const tokenPart = existingName.substring(0, colonIndex);
880
+ const argsPart = existingName.substring(colonIndex + 1);
881
+ if (argsPart.startsWith("requestId=")) return existingName;
882
+ return `${tokenPart}:requestId=${requestId}:${argsPart}`;
817
883
  }
818
- findDependents(instanceName) {
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];
884
+ /**
885
+ * Formats a single argument value for instance name generation.
886
+ */ formatArgValue(value) {
887
+ if (typeof value === "function") return `fn_${value.name}(${value.length})`;
888
+ if (typeof value === "symbol") return value.toString();
889
+ return JSON.stringify(value).slice(0, 40);
824
890
  }
825
891
  };
826
892
 
827
893
  //#endregion
828
- //#region src/container/scoped-container.mts
894
+ //#region src/internal/core/scope-tracker.mts
829
895
  /**
830
- * Request-scoped dependency injection container.
896
+ * Component for tracking and handling scope upgrades.
831
897
  *
832
- * Wraps a parent Container and provides isolated request-scoped instances
833
- * while delegating singleton and transient resolution to the parent.
834
- * This design eliminates race conditions that can occur with async operations
835
- * when multiple requests are processed concurrently.
836
- */ var ScopedContainer = class {
837
- parent;
898
+ * Detects when a Singleton service needs to be upgraded to Request scope
899
+ * and coordinates the scope upgrade process atomically.
900
+ */ var ScopeTracker = class {
838
901
  registry;
839
- requestId;
840
- requestContextHolder;
841
- holderStorage;
842
- disposed = false;
843
- constructor(parent, registry, requestId, metadata, priority = 100) {
844
- this.parent = parent;
902
+ nameResolver;
903
+ logger;
904
+ constructor(registry, nameResolver, logger = null) {
845
905
  this.registry = registry;
846
- this.requestId = requestId;
847
- this.requestContextHolder = new DefaultRequestContext(requestId, priority, metadata);
848
- this.holderStorage = new RequestStorage(this.requestContextHolder, this.parent.getServiceLocator().getManager());
906
+ this.nameResolver = nameResolver;
907
+ this.logger = logger;
849
908
  }
850
909
  /**
851
- * Gets the request context holder for this scoped container.
852
- */ getRequestContextHolder() {
853
- return this.requestContextHolder;
910
+ * Checks if a dependency requires scope upgrade and performs it if needed.
911
+ * Called during service resolution when a dependency is resolved.
912
+ *
913
+ * @param currentServiceName - Name of the service being created
914
+ * @param currentServiceScope - Current scope of the service being created
915
+ * @param dependencyName - Name of the dependency being resolved
916
+ * @param dependencyScope - Scope of the dependency
917
+ * @param dependencyToken - Token of the dependency
918
+ * @param singletonStorage - Singleton storage instance
919
+ * @param requestStorage - Request storage instance (if in request context)
920
+ * @param requestId - Request ID (if in request context)
921
+ * @returns [needsUpgrade: boolean, newName?: string] - whether upgrade occurred and new name
922
+ */ checkAndUpgradeScope(currentServiceName, currentServiceScope, dependencyName, dependencyScope, dependencyToken, singletonStorage, requestStorage, requestId) {
923
+ if (currentServiceScope !== InjectableScope.Singleton || dependencyScope !== InjectableScope.Request) return [false];
924
+ if (!requestStorage || !requestId) {
925
+ this.logger?.warn(`[ScopeTracker] Cannot upgrade scope for ${currentServiceName}: missing requestStorage or requestId`);
926
+ return [false];
927
+ }
928
+ this.logger?.log(`[ScopeTracker] Upgrading ${currentServiceName} from Singleton to Request scope`);
929
+ try {
930
+ const [success, newName] = this.upgradeScopeToRequestSync(currentServiceName, dependencyToken, singletonStorage, requestStorage, requestId);
931
+ if (success && newName) return [true, newName];
932
+ } catch (error) {
933
+ this.logger?.error(`[ScopeTracker] Error upgrading scope for ${currentServiceName}:`, error);
934
+ }
935
+ return [false];
854
936
  }
855
937
  /**
856
- * Gets the holder storage for this scoped container.
857
- * Used by InstanceResolver for request-scoped resolution.
858
- */ getHolderStorage() {
859
- return this.holderStorage;
938
+ * Performs the actual scope upgrade from Singleton to Request.
939
+ * This is the core migration logic.
940
+ *
941
+ * @param serviceName - Current service name (without requestId)
942
+ * @param token - Service injection token
943
+ * @param singletonStorage - Source storage
944
+ * @param requestStorage - Target storage
945
+ * @param requestId - Request ID to include in new name
946
+ * @returns [success: boolean, newName?: string, error?: DIError]
947
+ */ async upgradeScopeToRequest(serviceName, token, singletonStorage, requestStorage, requestId) {
948
+ try {
949
+ const [success, newName] = this.upgradeScopeToRequestSync(serviceName, token, singletonStorage, requestStorage, requestId);
950
+ if (success && newName) return [true, newName];
951
+ return [
952
+ false,
953
+ void 0,
954
+ DIError.storageError("Scope upgrade failed", "upgradeScopeToRequest", serviceName)
955
+ ];
956
+ } catch (error) {
957
+ return [
958
+ false,
959
+ void 0,
960
+ error instanceof DIError ? error : DIError.unknown(error)
961
+ ];
962
+ }
860
963
  }
861
964
  /**
862
- * Gets the request ID for this scoped container.
863
- */ getRequestId() {
864
- return this.requestId;
965
+ * Synchronous part of scope upgrade - handles immediate updates.
966
+ * Async operations (like waiting for holder creation) should be done separately.
967
+ */ upgradeScopeToRequestSync(serviceName, token, singletonStorage, requestStorage, requestId) {
968
+ const newName = this.nameResolver.upgradeInstanceNameToRequest(serviceName, requestId);
969
+ if (!this.registry.updateScope(token, InjectableScope.Request)) {
970
+ this.logger?.warn(`[ScopeTracker] Could not update scope in registry for ${serviceName}`);
971
+ return [false];
972
+ }
973
+ const holderResult = singletonStorage.get(serviceName);
974
+ if (holderResult === null) return [true, newName];
975
+ const [error, holder] = holderResult;
976
+ if (error) {
977
+ this.logger?.warn(`[ScopeTracker] Holder for ${serviceName} is in error state: ${error.message}`);
978
+ return [false];
979
+ }
980
+ if (!holder) return [false];
981
+ if (holder.status === InstanceStatus.Creating) {
982
+ holder.name = newName;
983
+ requestStorage.set(newName, holder);
984
+ singletonStorage.delete(serviceName);
985
+ this.updateParentDependencies(serviceName, newName, singletonStorage, requestStorage);
986
+ return [true, newName];
987
+ }
988
+ holder.name = newName;
989
+ requestStorage.set(newName, holder);
990
+ singletonStorage.delete(serviceName);
991
+ this.updateParentDependencies(serviceName, newName, singletonStorage, requestStorage);
992
+ return [true, newName];
865
993
  }
866
994
  /**
867
- * Gets the parent container.
868
- */ getParent() {
869
- return this.parent;
995
+ * Updates all parent dependencies to reference the new service name.
996
+ *
997
+ * @param oldName - Original service name
998
+ * @param newName - New service name with requestId
999
+ * @param singletonStorage - Singleton storage to check
1000
+ * @param requestStorage - Request storage to check
1001
+ */ updateParentDependencies(oldName, newName, singletonStorage, requestStorage) {
1002
+ singletonStorage.updateDependencyReference(oldName, newName);
1003
+ if (requestStorage) requestStorage.updateDependencyReference(oldName, newName);
870
1004
  }
871
- /**
872
- * Gets metadata from the request context.
873
- */ getMetadata(key) {
874
- return this.requestContextHolder.getMetadata(key);
1005
+ };
1006
+
1007
+ //#endregion
1008
+ //#region src/internal/core/service-initializer.mts
1009
+ /**
1010
+ * Creates service instances from registry records.
1011
+ *
1012
+ * Handles both class-based (@Injectable) and factory-based (@Factory) services,
1013
+ * managing the instantiation lifecycle including lifecycle hook invocation.
1014
+ */ var ServiceInitializer = class {
1015
+ injectors;
1016
+ constructor(injectors) {
1017
+ this.injectors = injectors;
875
1018
  }
876
1019
  /**
877
- * Sets metadata on the request context.
878
- */ setMetadata(key, value) {
879
- this.requestContextHolder.setMetadata(key, value);
880
- }
881
- /**
882
- * Adds a pre-prepared instance to the request context.
883
- */ addInstance(token, instance) {
884
- this.requestContextHolder.addInstance(token, instance);
885
- }
886
- async get(token, args) {
887
- if (this.disposed) throw DIError.unknown(`ScopedContainer for request ${this.requestId} has been disposed`);
888
- const actualToken = this.parent.getServiceLocator().getTokenProcessor().normalizeToken(token);
889
- if (this.isRequestScoped(actualToken)) return this.resolveRequestScoped(actualToken, args);
890
- return this.parent.getWithContext(token, args, this);
891
- }
892
- /**
893
- * Invalidates a service and its dependencies.
894
- * For request-scoped services, invalidation is handled within this context.
895
- */ async invalidate(service) {
896
- const holder = this.holderStorage.findByInstance(service);
897
- if (holder) {
898
- await this.parent.getServiceLocator().getInvalidator().invalidateWithStorage(holder.name, this.holderStorage, 1, { emitEvents: false });
899
- return;
900
- }
901
- await this.parent.invalidate(service);
902
- }
903
- /**
904
- * Checks if a service is registered.
905
- */ isRegistered(token) {
906
- return this.parent.isRegistered(token);
907
- }
908
- /**
909
- * Disposes this scoped container and cleans up all request-scoped instances.
910
- * This is an alias for endRequest() for IContainer compatibility.
911
- */ async dispose() {
912
- await this.endRequest();
913
- }
914
- /**
915
- * Ends the request and cleans up all request-scoped instances.
916
- * Uses the invalidation system to properly cascade to dependent singletons.
917
- */ async endRequest() {
918
- if (this.disposed) return;
919
- this.disposed = true;
920
- await this.parent.getServiceLocator().getInvalidator().clearAllWithStorage(this.holderStorage, {
921
- waitForSettlement: true,
922
- maxRounds: 10
923
- });
924
- this.requestContextHolder.clear();
925
- this.parent.removeActiveRequest(this.requestId);
926
- }
927
- /**
928
- * Waits for all pending operations to complete.
929
- */ async ready() {
930
- await this.parent.ready();
931
- }
932
- /**
933
- * @internal
934
- * Attempts to get an instance synchronously if it already exists and is ready.
935
- * For request-scoped services, checks this container's context first.
936
- * For other services, delegates to the parent container.
937
- *
938
- * Returns null if the instance doesn't exist or is not yet ready (still creating).
939
- */ tryGetSync(token, args) {
940
- const actualToken = this.parent.getServiceLocator().getTokenProcessor().normalizeToken(token);
941
- if (this.isRequestScoped(actualToken)) {
942
- const instanceName = this.parent.getServiceLocator().getInstanceIdentifier(token, args);
943
- const holder = this.requestContextHolder.get(instanceName);
944
- if (holder && holder.status === InstanceStatus.Created) return holder.instance;
945
- return null;
946
- }
947
- return this.parent.tryGetSync(token, args);
948
- }
949
- /**
950
- * Checks if a token is for a request-scoped service.
951
- */ isRequestScoped(token) {
952
- const realToken = this.parent.getServiceLocator().getTokenProcessor().getRealToken(token);
953
- if (!this.registry.has(realToken)) return false;
954
- return this.registry.get(realToken).scope === InjectableScope.Request;
955
- }
956
- /**
957
- * Resolves a request-scoped service from this container's context.
958
- * Uses locking to prevent duplicate initialization during concurrent resolution.
959
- */ async resolveRequestScoped(token, args) {
960
- const instanceName = this.parent.getServiceLocator().getInstanceIdentifier(token, args);
961
- const existingHolder = this.requestContextHolder.get(instanceName);
962
- if (existingHolder) if (existingHolder.status === InstanceStatus.Error) this.requestContextHolder.delete(instanceName);
963
- else {
964
- const [error, readyHolder] = await BaseHolderManager.waitForHolderReady(existingHolder);
965
- if (error) throw error;
966
- return readyHolder.instance;
967
- }
968
- return this.parent.resolveForRequest(token, args, this);
969
- }
970
- /**
971
- * Stores an instance in the request context.
972
- * Called by Container during request-scoped service resolution.
973
- */ storeRequestInstance(instanceName, instance, holder) {
974
- this.requestContextHolder.addInstance(instanceName, instance, holder);
975
- }
976
- /**
977
- * Gets an existing instance from the request context.
978
- * Called by Container during resolution to check for existing instances.
979
- */ getRequestInstance(instanceName) {
980
- return this.requestContextHolder.get(instanceName);
981
- }
982
- /**
983
- * Generates a prefixed event name for request-scoped services.
984
- * Format: {requestId}:{instanceName}
985
- */ getPrefixedEventName(instanceName) {
986
- return `${this.requestId}:${instanceName}`;
987
- }
988
- };
989
-
990
- //#endregion
991
- //#region src/internal/holder/singleton-storage.mts
992
- /**
993
- * Storage implementation for Singleton-scoped services.
994
- *
995
- * Wraps a HolderManager instance and provides the IHolderStorage interface.
996
- * This allows the InstanceResolver to work with singleton storage
997
- * using the same interface as request-scoped storage.
998
- */
999
- var SingletonStorage = class {
1000
- scope = InjectableScope.Singleton;
1001
- constructor(manager) {
1002
- this.manager = manager;
1003
- }
1004
- get(instanceName) {
1005
- const [error, holder] = this.manager.get(instanceName);
1006
- if (!error) return [void 0, holder];
1007
- switch (error.code) {
1008
- case DIErrorCode.InstanceNotFound: return null;
1009
- case DIErrorCode.InstanceDestroying: return [error, holder];
1010
- default: return [error];
1011
- }
1012
- }
1013
- set(instanceName, holder) {
1014
- this.manager.set(instanceName, holder);
1015
- }
1016
- delete(instanceName) {
1017
- return this.manager.delete(instanceName);
1018
- }
1019
- createHolder(instanceName, type, deps) {
1020
- return this.manager.createCreatingHolder(instanceName, type, this.scope, deps);
1021
- }
1022
- handles(scope) {
1023
- return scope === InjectableScope.Singleton;
1024
- }
1025
- getAllNames() {
1026
- return this.manager.getAllNames();
1027
- }
1028
- forEach(callback) {
1029
- this.manager.forEachHolder((holder, name) => callback(name, holder));
1030
- }
1031
- findByInstance(instance) {
1032
- return this.manager.findHolder((h) => h.instance === instance) ?? null;
1033
- }
1034
- findDependents(instanceName) {
1035
- return this.manager.getDependents(instanceName);
1036
- }
1037
- };
1038
-
1039
- //#endregion
1040
- //#region src/internal/core/instance-resolver.mts
1041
- /**
1042
- * Resolves instances from tokens, handling caching, creation, and scope rules.
1043
- *
1044
- * Uses the Storage Strategy pattern for unified singleton/request-scoped handling.
1045
- * Coordinates with Instantiator for actual service creation.
1046
- */ var InstanceResolver = class {
1047
- registry;
1048
- manager;
1049
- instantiator;
1050
- tokenProcessor;
1051
- logger;
1052
- serviceLocator;
1053
- singletonStorage;
1054
- constructor(registry, manager, instantiator, tokenProcessor, logger = null, serviceLocator) {
1055
- this.registry = registry;
1056
- this.manager = manager;
1057
- this.instantiator = instantiator;
1058
- this.tokenProcessor = tokenProcessor;
1059
- this.logger = logger;
1060
- this.serviceLocator = serviceLocator;
1061
- this.singletonStorage = new SingletonStorage(manager);
1062
- }
1063
- /**
1064
- * Resolves an instance for the given token and arguments.
1065
- * This method is used for singleton and transient services.
1066
- *
1067
- * @param token The injection token
1068
- * @param args Optional arguments
1069
- * @param contextContainer The container to use for creating FactoryContext
1070
- */ async resolveInstance(token, args, contextContainer) {
1071
- return this.resolveWithStorage(token, args, contextContainer, this.singletonStorage);
1072
- }
1073
- /**
1074
- * Resolves a request-scoped instance for a ScopedContainer.
1075
- * The service will be stored in the ScopedContainer's request context.
1076
- *
1077
- * @param token The injection token
1078
- * @param args Optional arguments
1079
- * @param scopedContainer The ScopedContainer that owns the request context
1080
- */ async resolveRequestScopedInstance(token, args, scopedContainer) {
1081
- return this.resolveWithStorage(token, args, scopedContainer, scopedContainer.getHolderStorage(), scopedContainer);
1082
- }
1083
- /**
1084
- * Unified resolution method that works with any IHolderStorage.
1085
- * This eliminates duplication between singleton and request-scoped resolution.
1086
- *
1087
- * IMPORTANT: The check-and-store logic is carefully designed to avoid race conditions.
1088
- * The storage check and holder creation must happen synchronously (no awaits between).
1089
- *
1090
- * @param token The injection token
1091
- * @param args Optional arguments
1092
- * @param contextContainer The container for FactoryContext
1093
- * @param storage The storage strategy to use
1094
- * @param scopedContainer Optional scoped container for request-scoped services
1095
- */ async resolveWithStorage(token, args, contextContainer, storage, scopedContainer) {
1096
- const [err, data] = await this.resolveTokenAndPrepareInstanceName(token, args, contextContainer);
1097
- if (err) return [err];
1098
- const { instanceName, validatedArgs, realToken } = data;
1099
- const getResult = storage.get(instanceName);
1100
- if (getResult !== null) {
1101
- const [error, holder$1] = getResult;
1102
- if (!error && holder$1) {
1103
- const readyResult = await this.waitForInstanceReady(holder$1);
1104
- if (readyResult[0]) return [readyResult[0]];
1105
- return [void 0, readyResult[1].instance];
1106
- }
1107
- if (error) {
1108
- const handledResult = await this.handleStorageError(instanceName, error, holder$1, storage);
1109
- if (handledResult) return handledResult;
1110
- }
1111
- }
1112
- const [createError, holder] = await this.createAndStoreInstance(instanceName, realToken, validatedArgs, contextContainer, storage, scopedContainer);
1113
- if (createError) return [createError];
1114
- return [void 0, holder.instance];
1115
- }
1116
- /**
1117
- * Handles storage error states (destroying, error, etc.).
1118
- * Returns a result if handled, null if should proceed with creation.
1119
- */ async handleStorageError(instanceName, error, holder, storage) {
1120
- switch (error.code) {
1121
- case DIErrorCode.InstanceDestroying:
1122
- this.logger?.log(`[InstanceResolver] Instance ${instanceName} is being destroyed, waiting...`);
1123
- if (holder?.destroyPromise) await holder.destroyPromise;
1124
- const newResult = storage.get(instanceName);
1125
- if (newResult !== null && !newResult[0]) {
1126
- const readyResult = await this.waitForInstanceReady(newResult[1]);
1127
- if (readyResult[0]) return [readyResult[0]];
1128
- return [void 0, readyResult[1].instance];
1129
- }
1130
- return null;
1131
- default:
1132
- if (holder) {
1133
- this.logger?.log(`[InstanceResolver] Removing failed instance ${instanceName} from storage to allow retry`);
1134
- storage.delete(instanceName);
1135
- }
1136
- return null;
1137
- }
1138
- }
1139
- /**
1140
- * Creates a new instance and stores it using the provided storage strategy.
1141
- * This unified method replaces instantiateServiceFromRegistry and createRequestScopedInstance.
1142
- *
1143
- * For transient services, the instance is created but not stored (no caching).
1144
- */ async createAndStoreInstance(instanceName, realToken, args, contextContainer, storage, scopedContainer) {
1145
- this.logger?.log(`[InstanceResolver]#createAndStoreInstance() Creating instance for ${instanceName}`);
1146
- if (!this.registry.has(realToken)) return [DIError.factoryNotFound(realToken.name.toString())];
1147
- const ctx = this.createFactoryContext(contextContainer);
1148
- const record = this.registry.get(realToken);
1149
- const { scope, type } = record;
1150
- if (scope === InjectableScope.Transient) return this.createTransientInstance(instanceName, record, args, ctx);
1151
- const [deferred, holder] = this.manager.createCreatingHolder(instanceName, type, scope, ctx.deps);
1152
- storage.set(instanceName, holder);
1153
- const getHolder = (name) => {
1154
- const storageResult = storage.get(name);
1155
- if (storageResult !== null) {
1156
- const [, storageHolder] = storageResult;
1157
- if (storageHolder) return storageHolder;
1158
- }
1159
- const [, managerHolder] = this.manager.get(name);
1160
- return managerHolder;
1161
- };
1162
- withResolutionContext(holder, getHolder, () => {
1163
- this.instantiator.instantiateService(ctx, record, args).then(async (result) => {
1164
- const [error, instance] = result.length === 2 ? result : [result[0], void 0];
1165
- await this.handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer);
1166
- }).catch(async (error) => {
1167
- await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
1168
- }).catch(() => {});
1169
- });
1170
- return this.waitForInstanceReady(holder);
1171
- }
1172
- /**
1173
- * Creates a transient instance without storage or locking.
1174
- * Each call creates a new instance.
1175
- */ async createTransientInstance(instanceName, record, args, ctx) {
1176
- this.logger?.log(`[InstanceResolver]#createTransientInstance() Creating transient instance for ${instanceName}`);
1177
- const tempHolder = {
1178
- status: InstanceStatus.Creating,
1179
- name: instanceName,
1180
- instance: null,
1181
- creationPromise: null,
1182
- destroyPromise: null,
1183
- type: record.type,
1184
- scope: InjectableScope.Transient,
1185
- deps: ctx.deps,
1186
- destroyListeners: [],
1187
- createdAt: Date.now(),
1188
- waitingFor: /* @__PURE__ */ new Set()
1189
- };
1190
- const getHolder = (name) => {
1191
- const [, managerHolder] = this.manager.get(name);
1192
- return managerHolder;
1193
- };
1194
- const [error, instance] = await withResolutionContext(tempHolder, getHolder, () => this.instantiator.instantiateService(ctx, record, args));
1195
- if (error) return [error];
1196
- return [void 0, {
1197
- status: InstanceStatus.Created,
1198
- name: instanceName,
1199
- instance,
1200
- creationPromise: null,
1201
- destroyPromise: null,
1202
- type: record.type,
1203
- scope: InjectableScope.Transient,
1204
- deps: ctx.deps,
1205
- destroyListeners: ctx.getDestroyListeners(),
1206
- createdAt: Date.now(),
1207
- waitingFor: /* @__PURE__ */ new Set()
1208
- }];
1209
- }
1210
- /**
1211
- * Gets a synchronous instance (for sync operations).
1212
- */ getSyncInstance(token, args, contextContainer) {
1213
- const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
1214
- if (err) return null;
1215
- const instanceName = this.tokenProcessor.generateInstanceName(actualToken, validatedArgs);
1216
- if ("getRequestInstance" in contextContainer) {
1217
- const requestHolder = contextContainer.getRequestInstance(instanceName);
1218
- if (requestHolder) return requestHolder.instance;
1219
- }
1220
- const [error, holder] = this.manager.get(instanceName);
1221
- if (error) return null;
1222
- return holder.instance;
1223
- }
1224
- /**
1225
- * Internal method to resolve token args and create instance name.
1226
- * Handles factory token resolution and validation.
1227
- */ async resolveTokenAndPrepareInstanceName(token, args, contextContainer) {
1228
- const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
1229
- if (err instanceof DIError && err.code === DIErrorCode.UnknownError) return [err];
1230
- else if (err instanceof DIError && err.code === DIErrorCode.FactoryTokenNotResolved && actualToken instanceof FactoryInjectionToken) {
1231
- this.logger?.log(`[InstanceResolver]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`);
1232
- await actualToken.resolve(this.createFactoryContext(contextContainer));
1233
- return this.resolveTokenAndPrepareInstanceName(token, void 0, contextContainer);
1234
- }
1235
- return [void 0, {
1236
- instanceName: this.tokenProcessor.generateInstanceName(actualToken, validatedArgs),
1237
- validatedArgs,
1238
- actualToken,
1239
- realToken: actualToken instanceof BoundInjectionToken || actualToken instanceof FactoryInjectionToken ? actualToken.token : actualToken
1240
- }];
1241
- }
1242
- /**
1243
- * Waits for an instance holder to be ready and returns the appropriate result.
1244
- * Uses the shared utility from BaseHolderManager.
1245
- * Passes the current resolution context for circular dependency detection.
1246
- */ waitForInstanceReady(holder) {
1247
- const ctx = getCurrentResolutionContext();
1248
- return BaseHolderManager.waitForHolderReady(holder, ctx?.waiterHolder, ctx?.getHolder);
1249
- }
1250
- /**
1251
- * Handles the result of service instantiation.
1252
- */ async handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer) {
1253
- holder.destroyListeners = ctx.getDestroyListeners();
1254
- holder.creationPromise = null;
1255
- if (error) await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
1256
- else await this.handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer);
1257
- }
1258
- /**
1259
- * Handles successful service instantiation.
1260
- */ async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer) {
1261
- holder.instance = instance;
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);
1265
- if (ctx.deps.size > 0) ctx.deps.forEach((dependency) => {
1266
- holder.destroyListeners.push(this.serviceLocator.getEventBus().on(dependency, "destroy", () => {
1267
- this.logger?.log(`[InstanceResolver] Dependency ${dependency} destroyed, invalidating ${instanceName}`);
1268
- this.serviceLocator.getInvalidator().invalidate(instanceName);
1269
- }));
1270
- if (scopedContainer) {
1271
- const prefixedDependency = scopedContainer.getPrefixedEventName(dependency);
1272
- holder.destroyListeners.push(this.serviceLocator.getEventBus().on(prefixedDependency, "destroy", () => {
1273
- this.logger?.log(`[InstanceResolver] Request-scoped dependency ${dependency} destroyed, invalidating ${instanceName}`);
1274
- scopedContainer.invalidate(instance);
1275
- }));
1276
- }
1277
- });
1278
- this.logger?.log(`[InstanceResolver] Instance ${instanceName} created successfully`);
1279
- deferred.resolve([void 0, instance]);
1280
- }
1281
- /**
1282
- * Handles service instantiation errors.
1283
- */ async handleInstantiationError(instanceName, holder, deferred, scope, error) {
1284
- this.logger?.error(`[InstanceResolver] Error creating instance for ${instanceName}`, error);
1285
- holder.status = InstanceStatus.Error;
1286
- holder.instance = error;
1287
- holder.creationPromise = null;
1288
- if (scope === InjectableScope.Singleton) {
1289
- this.logger?.log(`[InstanceResolver] Singleton ${instanceName} failed, will be invalidated`);
1290
- this.serviceLocator.getInvalidator().invalidate(instanceName).catch(() => {});
1291
- }
1292
- deferred.reject(error);
1293
- }
1294
- /**
1295
- * Creates a factory context for dependency injection during service instantiation.
1296
- */ createFactoryContext(contextContainer) {
1297
- return this.tokenProcessor.createFactoryContext(contextContainer);
1298
- }
1299
- };
1300
-
1301
- //#endregion
1302
- //#region src/internal/core/instantiator.mts
1303
- /**
1304
- * Creates service instances from registry records.
1305
- *
1306
- * Handles both class-based (@Injectable) and factory-based (@Factory) services,
1307
- * managing the instantiation lifecycle including sync initialization retries
1308
- * and lifecycle hook invocation (onServiceInit, onServiceDestroy).
1309
- */ var Instantiator = class {
1310
- injectors;
1311
- constructor(injectors) {
1312
- this.injectors = injectors;
1313
- }
1314
- /**
1315
- * Instantiates a service based on its registry record.
1316
- * @param ctx The factory context for dependency injection
1317
- * @param record The factory record from the registry
1318
- * @param args Optional arguments for the service
1319
- * @returns Promise resolving to [undefined, instance] or [error]
1320
- */ async instantiateService(ctx, record, args = void 0) {
1321
- try {
1322
- switch (record.type) {
1323
- case InjectableType.Class: return this.instantiateClass(ctx, record, args);
1324
- case InjectableType.Factory: return this.instantiateFactory(ctx, record, args);
1325
- default: throw DIError.unknown(`[Instantiator] Unknown service type: ${record.type}`);
1326
- }
1327
- } catch (error) {
1328
- return [error instanceof DIError ? error : DIError.unknown(String(error))];
1329
- }
1020
+ * Instantiates a service based on its registry record.
1021
+ * @param ctx The factory context for dependency injection
1022
+ * @param record The factory record from the registry
1023
+ * @param args Optional arguments for the service
1024
+ * @returns Promise resolving to [undefined, instance] or [error]
1025
+ */ async instantiateService(ctx, record, args = void 0) {
1026
+ try {
1027
+ switch (record.type) {
1028
+ case InjectableType.Class: return this.instantiateClass(ctx, record, args);
1029
+ case InjectableType.Factory: return this.instantiateFactory(ctx, record, args);
1030
+ default: throw DIError.unknown(`[ServiceInitializer] Unknown service type: ${record.type}`);
1031
+ }
1032
+ } catch (error) {
1033
+ return [error instanceof DIError ? error : DIError.initializationError(record.target.name, error)];
1034
+ }
1330
1035
  }
1331
1036
  /**
1332
1037
  * Instantiates a class-based service (Injectable decorator).
@@ -1344,18 +1049,18 @@ var SingletonStorage = class {
1344
1049
  });
1345
1050
  let [instance, promises, injectState] = tryLoad();
1346
1051
  if (promises.length > 0) {
1347
- if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
1052
+ if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.initializationError(record.target.name, /* @__PURE__ */ new Error("Service cannot be instantiated"));
1348
1053
  const newRes = tryLoad(injectState);
1349
1054
  instance = newRes[0];
1350
1055
  promises = newRes[1];
1351
1056
  }
1352
1057
  if (promises.length > 0) {
1353
- console.error(`[Instantiator] ${record.target.name} has problem with it's definition.
1058
+ console.error(`[ServiceInitializer] ${record.target.name} has problem with it's definition.
1354
1059
 
1355
- One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
1060
+ One or more of the dependencies are registered as a InjectableScope.Transient and are used with inject.
1356
1061
 
1357
- Please use inject asyncInject of inject to load those dependencies.`);
1358
- throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
1062
+ Please use asyncInject instead of inject to load those dependencies.`);
1063
+ throw DIError.initializationError(record.target.name, /* @__PURE__ */ new Error("Service cannot be instantiated"));
1359
1064
  }
1360
1065
  if ("onServiceInit" in instance) await instance.onServiceInit();
1361
1066
  if ("onServiceDestroy" in instance) ctx.addDestroyListener(async () => {
@@ -1363,7 +1068,7 @@ var SingletonStorage = class {
1363
1068
  });
1364
1069
  return [void 0, instance];
1365
1070
  } catch (error) {
1366
- return [error instanceof DIError ? error : DIError.unknown(String(error))];
1071
+ return [error instanceof DIError ? error : DIError.initializationError(record.target.name, error)];
1367
1072
  }
1368
1073
  }
1369
1074
  /**
@@ -1382,242 +1087,503 @@ var SingletonStorage = class {
1382
1087
  });
1383
1088
  let [builder, promises, injectState] = tryLoad();
1384
1089
  if (promises.length > 0) {
1385
- if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
1090
+ if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.initializationError(record.target.name, /* @__PURE__ */ new Error("Service cannot be instantiated"));
1386
1091
  const newRes = tryLoad(injectState);
1387
1092
  builder = newRes[0];
1388
1093
  promises = newRes[1];
1389
1094
  }
1390
1095
  if (promises.length > 0) {
1391
- console.error(`[Instantiator] ${record.target.name} has problem with it's definition.
1096
+ console.error(`[ServiceInitializer] ${record.target.name} has problem with it's definition.
1392
1097
 
1393
- One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
1098
+ One or more of the dependencies are registered as a InjectableScope.Transient and are used with inject.
1394
1099
 
1395
1100
  Please use asyncInject instead of inject to load those dependencies.`);
1396
- throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
1101
+ throw DIError.initializationError(record.target.name, /* @__PURE__ */ new Error("Service cannot be instantiated"));
1397
1102
  }
1398
- if (typeof builder.create !== "function") throw DIError.unknown(`[Instantiator] Factory ${record.target.name} does not implement the create method.`);
1103
+ if (typeof builder.create !== "function") throw DIError.initializationError(record.target.name, /* @__PURE__ */ new Error("Factory does not implement the create method"));
1399
1104
  return [void 0, await builder.create(ctx, args)];
1400
1105
  } catch (error) {
1401
- return [error instanceof DIError ? error : DIError.unknown(String(error))];
1106
+ return [error instanceof DIError ? error : DIError.initializationError(record.target.name, error)];
1107
+ }
1108
+ }
1109
+ };
1110
+
1111
+ //#endregion
1112
+ //#region src/internal/core/service-invalidator.mts
1113
+ /**
1114
+ * Manages graceful service cleanup with event-based invalidation.
1115
+ *
1116
+ * Uses event subscriptions instead of manual dependent finding.
1117
+ * When a service is created, it subscribes to destroy events of its dependencies.
1118
+ * When a dependency is destroyed, the event automatically invalidates dependents.
1119
+ */ var ServiceInvalidator = class {
1120
+ eventBus;
1121
+ logger;
1122
+ constructor(eventBus, logger = null) {
1123
+ this.eventBus = eventBus;
1124
+ this.logger = logger;
1125
+ }
1126
+ /**
1127
+ * Invalidates a service using a specific storage.
1128
+ * Event-based invalidation means dependents are automatically invalidated
1129
+ * via destroy event subscriptions - no need to manually find dependents.
1130
+ *
1131
+ * @param service The instance name to invalidate
1132
+ * @param storage The storage to use for this invalidation
1133
+ * @param options Additional options for invalidation behavior
1134
+ */ async invalidateWithStorage(service, storage, options = {}) {
1135
+ const { emitEvents = true, onInvalidated } = options;
1136
+ this.logger?.log(`[ServiceInvalidator] Starting invalidation process for ${service}`);
1137
+ const result = storage.get(service);
1138
+ if (result === null) return;
1139
+ const [, holder] = result;
1140
+ if (holder) await this.invalidateHolderWithStorage(service, holder, storage, emitEvents, onInvalidated);
1141
+ }
1142
+ /**
1143
+ * Sets up destroy event subscriptions for a service's dependencies.
1144
+ * Called when a service is successfully instantiated.
1145
+ *
1146
+ * @param serviceName The name of the service
1147
+ * @param dependencies The set of dependency names
1148
+ * @param storage The storage to use for invalidation
1149
+ * @param holder The holder for the service (to add unsubscribe to destroy listeners)
1150
+ */ setupDependencySubscriptions(serviceName, dependencies, storage, holder) {
1151
+ if (!this.eventBus) return;
1152
+ for (const dependencyName of dependencies) {
1153
+ const unsubscribe = this.eventBus.on(dependencyName, "destroy", () => {
1154
+ this.logger?.log(`[ServiceInvalidator] Dependency ${dependencyName} destroyed, invalidating ${serviceName}`);
1155
+ this.invalidateWithStorage(serviceName, storage).catch((error) => {
1156
+ this.logger?.error(`[ServiceInvalidator] Error invalidating ${serviceName} after dependency ${dependencyName} destroyed:`, error);
1157
+ });
1158
+ });
1159
+ holder.destroyListeners.push(unsubscribe);
1160
+ }
1161
+ }
1162
+ /**
1163
+ * Gracefully clears all services in a specific storage.
1164
+ * This allows clearing request-scoped services using a RequestStorage.
1165
+ */ async clearAllWithStorage(storage, options = {}) {
1166
+ const { waitForSettlement = true } = options;
1167
+ this.logger?.log("[ServiceInvalidator] Starting graceful clearing of all services");
1168
+ if (waitForSettlement) {
1169
+ this.logger?.log("[ServiceInvalidator] Waiting for all services to settle...");
1170
+ await this.readyWithStorage(storage);
1171
+ }
1172
+ const allServiceNames = storage.getAllNames();
1173
+ if (allServiceNames.length === 0) this.logger?.log("[ServiceInvalidator] No services to clear");
1174
+ else {
1175
+ this.logger?.log(`[ServiceInvalidator] Found ${allServiceNames.length} services to clear: ${allServiceNames.join(", ")}`);
1176
+ const clearPromises = allServiceNames.map((serviceName) => this.invalidateWithStorage(serviceName, storage));
1177
+ await Promise.all(clearPromises);
1178
+ }
1179
+ this.logger?.log("[ServiceInvalidator] Graceful clearing completed");
1180
+ }
1181
+ /**
1182
+ * Waits for all services in a specific storage to settle.
1183
+ */ async readyWithStorage(storage) {
1184
+ const holders = [];
1185
+ storage.forEach((_, holder) => holders.push(holder));
1186
+ await Promise.all(holders.map((holder) => this.waitForHolderToSettle(holder)));
1187
+ }
1188
+ /**
1189
+ * Invalidates a single holder using a specific storage.
1190
+ */ async invalidateHolderWithStorage(key, holder, storage, emitEvents, onInvalidated) {
1191
+ await this.invalidateHolderByStatus(holder, {
1192
+ context: key,
1193
+ onDestroy: () => this.destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated)
1194
+ });
1195
+ }
1196
+ /**
1197
+ * Common invalidation logic for holders based on their status.
1198
+ */ async invalidateHolderByStatus(holder, options) {
1199
+ switch (holder.status) {
1200
+ case InstanceStatus.Destroying:
1201
+ await holder.destroyPromise;
1202
+ break;
1203
+ case InstanceStatus.Creating:
1204
+ await holder.creationPromise;
1205
+ await options.onDestroy();
1206
+ break;
1207
+ default:
1208
+ await options.onDestroy();
1209
+ break;
1210
+ }
1211
+ }
1212
+ /**
1213
+ * Destroys a holder using a specific storage.
1214
+ */ async destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated) {
1215
+ holder.status = InstanceStatus.Destroying;
1216
+ this.logger?.log(`[ServiceInvalidator] Invalidating ${key} and notifying listeners`);
1217
+ holder.destroyPromise = Promise.all(holder.destroyListeners.map((listener) => listener())).then(async () => {
1218
+ holder.destroyListeners = [];
1219
+ holder.deps.clear();
1220
+ storage.delete(key);
1221
+ if (emitEvents && this.eventBus) await this.emitInstanceEvent(key, "destroy");
1222
+ if (onInvalidated) await onInvalidated(key);
1223
+ });
1224
+ await holder.destroyPromise;
1225
+ }
1226
+ /**
1227
+ * Waits for a holder to settle (either created, destroyed, or error state).
1228
+ */ async waitForHolderToSettle(holder) {
1229
+ switch (holder.status) {
1230
+ case InstanceStatus.Creating:
1231
+ await holder.creationPromise;
1232
+ break;
1233
+ case InstanceStatus.Destroying:
1234
+ await holder.destroyPromise;
1235
+ break;
1236
+ case InstanceStatus.Created:
1237
+ case InstanceStatus.Error: break;
1402
1238
  }
1403
1239
  }
1240
+ /**
1241
+ * Emits events to listeners for instance lifecycle events.
1242
+ */ emitInstanceEvent(name, event = "create") {
1243
+ if (!this.eventBus) return Promise.resolve();
1244
+ this.logger?.log(`[ServiceInvalidator]#emitInstanceEvent() Notifying listeners for ${name} with event ${event}`);
1245
+ return this.eventBus.emit(name, event);
1246
+ }
1404
1247
  };
1405
1248
 
1406
1249
  //#endregion
1407
- //#region src/internal/core/invalidator.mts
1250
+ //#region src/utils/get-injectors.mts
1251
+ function getInjectors() {
1252
+ let currentFactoryContext = null;
1253
+ function provideFactoryContext$1(context) {
1254
+ const original = currentFactoryContext;
1255
+ currentFactoryContext = context;
1256
+ return original;
1257
+ }
1258
+ function getFactoryContext() {
1259
+ if (!currentFactoryContext) throw new Error("[Injector] Trying to access injection context outside of a injectable context");
1260
+ return currentFactoryContext;
1261
+ }
1262
+ let promiseCollector = null;
1263
+ let injectState = null;
1264
+ function getRequest(token, args, skipCycleTracking = false) {
1265
+ if (!injectState) throw new Error("[Injector] Trying to make a request outside of a injectable context");
1266
+ if (injectState.isFrozen) {
1267
+ const idx = injectState.currentIndex++;
1268
+ const request$1 = injectState.requests[idx];
1269
+ if (request$1.token !== token) throw new Error(`[Injector] Wrong token order. Expected ${request$1.token.toString()} but got ${token.toString()}`);
1270
+ return request$1;
1271
+ }
1272
+ let result = null;
1273
+ let error = null;
1274
+ const doInject = () => getFactoryContext().inject(token, args).then((r) => {
1275
+ result = r;
1276
+ return r;
1277
+ }).catch((e) => {
1278
+ error = e;
1279
+ });
1280
+ const request = {
1281
+ token,
1282
+ promise: skipCycleTracking ? withoutResolutionContext(doInject) : doInject(),
1283
+ get result() {
1284
+ return result;
1285
+ },
1286
+ get error() {
1287
+ return error;
1288
+ }
1289
+ };
1290
+ injectState.requests.push(request);
1291
+ injectState.currentIndex++;
1292
+ return request;
1293
+ }
1294
+ function asyncInject$1(token, args) {
1295
+ if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
1296
+ const request = getRequest(token[InjectableTokenMeta] ?? token, args, true);
1297
+ return request.promise.then((result) => {
1298
+ if (request.error) throw request.error;
1299
+ return result;
1300
+ });
1301
+ }
1302
+ function wrapSyncInit$1(cb) {
1303
+ return (previousState) => {
1304
+ const promises = [];
1305
+ const originalPromiseCollector = promiseCollector;
1306
+ const originalInjectState = injectState;
1307
+ injectState = previousState ? {
1308
+ ...previousState,
1309
+ currentIndex: 0
1310
+ } : {
1311
+ currentIndex: 0,
1312
+ isFrozen: false,
1313
+ requests: []
1314
+ };
1315
+ promiseCollector = (promise) => {
1316
+ promises.push(promise);
1317
+ };
1318
+ const result = cb();
1319
+ promiseCollector = originalPromiseCollector;
1320
+ const newInjectState = {
1321
+ ...injectState,
1322
+ isFrozen: true
1323
+ };
1324
+ injectState = originalInjectState;
1325
+ return [
1326
+ result,
1327
+ promises,
1328
+ newInjectState
1329
+ ];
1330
+ };
1331
+ }
1332
+ function inject$1(token, args) {
1333
+ const realToken = token[InjectableTokenMeta] ?? token;
1334
+ if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
1335
+ const ctx = getFactoryContext();
1336
+ const instance = ctx.container.tryGetSync(realToken, args);
1337
+ if (!instance) {
1338
+ const request = getRequest(realToken, args);
1339
+ if (request.error) throw request.error;
1340
+ else if (request.result) return request.result;
1341
+ if (promiseCollector) promiseCollector(request.promise);
1342
+ return new Proxy({}, { get() {
1343
+ throw new Error(`[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`);
1344
+ } });
1345
+ }
1346
+ ctx.inject(realToken, args).catch(() => {});
1347
+ return instance;
1348
+ }
1349
+ function optional$1(token, args) {
1350
+ try {
1351
+ return inject$1(token, args);
1352
+ } catch {
1353
+ return null;
1354
+ }
1355
+ }
1356
+ return {
1357
+ asyncInject: asyncInject$1,
1358
+ inject: inject$1,
1359
+ optional: optional$1,
1360
+ wrapSyncInit: wrapSyncInit$1,
1361
+ provideFactoryContext: provideFactoryContext$1
1362
+ };
1363
+ }
1364
+
1365
+ //#endregion
1366
+ //#region src/utils/default-injectors.mts
1367
+ const defaultInjectors = /* @__PURE__ */ getInjectors();
1368
+ const inject = defaultInjectors.inject;
1369
+ const optional = defaultInjectors.optional;
1370
+ const asyncInject = defaultInjectors.asyncInject;
1371
+ const wrapSyncInit = defaultInjectors.wrapSyncInit;
1372
+ const provideFactoryContext = defaultInjectors.provideFactoryContext;
1373
+
1374
+ //#endregion
1375
+ //#region src/utils/get-injectable-token.mts
1376
+ function getInjectableToken(target) {
1377
+ const token = target[InjectableTokenMeta];
1378
+ if (!token) throw DIError.classNotInjectable(target.name);
1379
+ return token;
1380
+ }
1381
+
1382
+ //#endregion
1383
+ //#region src/internal/core/token-resolver.mts
1408
1384
  /**
1409
- * Manages graceful service cleanup with dependency-aware invalidation.
1385
+ * Handles token validation and resolution.
1410
1386
  *
1411
- * Ensures services are destroyed in the correct order based on their dependencies.
1412
- * Works with any IHolderStorage implementation, enabling unified invalidation
1413
- * for both singleton and request-scoped services.
1414
- */ var Invalidator = class {
1415
- eventBus;
1387
+ * Focuses on token validation, normalization, and argument validation.
1388
+ * Name generation is handled by NameResolver.
1389
+ */ var TokenResolver = class {
1416
1390
  logger;
1417
- storage;
1418
- constructor(manager, eventBus, logger = null) {
1419
- this.eventBus = eventBus;
1391
+ constructor(logger = null) {
1420
1392
  this.logger = logger;
1421
- this.storage = new SingletonStorage(manager);
1422
1393
  }
1423
1394
  /**
1424
- * Invalidates a service and all its dependencies.
1425
- * Works with the configured storage (singleton by default).
1426
- */ invalidate(service, round = 1) {
1427
- return this.invalidateWithStorage(service, this.storage, round);
1395
+ * Normalizes a token to an InjectionToken.
1396
+ * Handles class constructors by getting their injectable token.
1397
+ *
1398
+ * @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
1399
+ * @returns The normalized InjectionTokenType
1400
+ */ normalizeToken(token) {
1401
+ if (typeof token === "function") return getInjectableToken(token);
1402
+ return token;
1428
1403
  }
1429
1404
  /**
1430
- * Invalidates a service using a specific storage.
1431
- * This allows request-scoped invalidation using a RequestStorage.
1405
+ * Gets the underlying "real" token from wrapped tokens.
1406
+ * For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.
1407
+ * For other tokens, returns the token itself.
1432
1408
  *
1433
- * @param service The instance name to invalidate
1434
- * @param storage The storage to use for this invalidation
1435
- * @param round Current invalidation round (for recursion limiting)
1436
- * @param options Additional options for invalidation behavior
1437
- */ async invalidateWithStorage(service, storage, round = 1, options = {}) {
1438
- const { cascade = true, _invalidating = /* @__PURE__ */ new Set() } = options;
1439
- if (_invalidating.has(service)) {
1440
- this.logger?.log(`[Invalidator] Skipping ${service} - already being invalidated in this chain`);
1441
- return;
1442
- }
1443
- this.logger?.log(`[Invalidator] Starting invalidation process for ${service}`);
1444
- const result = storage.get(service);
1445
- if (result === null) return;
1446
- _invalidating.add(service);
1447
- const optionsWithTracking = {
1448
- ...options,
1449
- _invalidating
1450
- };
1451
- if (cascade) {
1452
- const dependents = storage.findDependents(service);
1453
- for (const dependentName of dependents) await this.invalidateWithStorage(dependentName, storage, round, optionsWithTracking);
1454
- }
1455
- const [, holder] = result;
1456
- if (holder) await this.invalidateHolderWithStorage(service, holder, storage, round, optionsWithTracking);
1409
+ * @param token The token to unwrap
1410
+ * @returns The underlying InjectionToken
1411
+ */ getRealToken(token) {
1412
+ if (token instanceof BoundInjectionToken || token instanceof FactoryInjectionToken) return token.token;
1413
+ return token;
1457
1414
  }
1458
1415
  /**
1459
- * Gracefully clears all services using invalidation logic.
1460
- * This method respects service dependencies and ensures proper cleanup order.
1461
- * Services that depend on others will be invalidated first, then their dependencies.
1462
- */ async clearAll(options = {}) {
1463
- return this.clearAllWithStorage(this.storage, options);
1416
+ * Convenience method that normalizes a token and then gets the real token.
1417
+ * Useful for checking registry entries where you need the actual registered token.
1418
+ *
1419
+ * @param token Any injectable type
1420
+ * @returns The underlying InjectionToken
1421
+ */ getRegistryToken(token) {
1422
+ return this.getRealToken(this.normalizeToken(token));
1464
1423
  }
1465
1424
  /**
1466
- * Gracefully clears all services in a specific storage.
1467
- * This allows clearing request-scoped services using a RequestStorage.
1468
- */ async clearAllWithStorage(storage, options = {}) {
1469
- const { maxRounds = 10, waitForSettlement = true } = options;
1470
- this.logger?.log("[Invalidator] Starting graceful clearing of all services");
1471
- if (waitForSettlement) {
1472
- this.logger?.log("[Invalidator] Waiting for all services to settle...");
1473
- await this.readyWithStorage(storage);
1474
- }
1475
- const allServiceNames = storage.getAllNames();
1476
- if (allServiceNames.length === 0) this.logger?.log("[Invalidator] No services to clear");
1477
- else {
1478
- this.logger?.log(`[Invalidator] Found ${allServiceNames.length} services to clear: ${allServiceNames.join(", ")}`);
1479
- await this.clearServicesWithDependencyAwarenessForStorage(allServiceNames, maxRounds, storage);
1425
+ * Validates and resolves token arguments, handling factory token resolution and validation.
1426
+ *
1427
+ * @param token The token to validate
1428
+ * @param args Optional arguments
1429
+ * @returns [error, { actualToken, validatedArgs }]
1430
+ */ validateAndResolveTokenArgs(token, args) {
1431
+ let actualToken = token;
1432
+ if (typeof token === "function") actualToken = getInjectableToken(token);
1433
+ let realArgs = args;
1434
+ if (actualToken instanceof BoundInjectionToken) realArgs = actualToken.value;
1435
+ else if (actualToken instanceof FactoryInjectionToken) if (actualToken.resolved) realArgs = actualToken.value;
1436
+ else return [DIError.factoryTokenNotResolved(token.name), { actualToken }];
1437
+ if (!actualToken.schema) return [void 0, {
1438
+ actualToken,
1439
+ validatedArgs: realArgs
1440
+ }];
1441
+ const validatedArgs = actualToken.schema?.safeParse(realArgs);
1442
+ if (validatedArgs && !validatedArgs.success) {
1443
+ this.logger?.error(`[TokenResolver]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`, validatedArgs.error);
1444
+ return [DIError.tokenValidationError(`Validation failed for ${actualToken.name.toString()}`, actualToken.schema, realArgs), { actualToken }];
1480
1445
  }
1481
- this.logger?.log("[Invalidator] Graceful clearing completed");
1482
- }
1483
- /**
1484
- * Waits for all services to settle (either created, destroyed, or error state).
1485
- */ async ready() {
1486
- return this.readyWithStorage(this.storage);
1487
- }
1488
- /**
1489
- * Waits for all services in a specific storage to settle.
1490
- */ async readyWithStorage(storage) {
1491
- const holders = [];
1492
- storage.forEach((_, holder) => holders.push(holder));
1493
- await Promise.all(holders.map((holder) => this.waitForHolderToSettle(holder)));
1446
+ return [void 0, {
1447
+ actualToken,
1448
+ validatedArgs: validatedArgs?.data
1449
+ }];
1494
1450
  }
1451
+ };
1452
+
1453
+ //#endregion
1454
+ //#region src/internal/holder/unified-storage.mts
1455
+ /**
1456
+ * Unified storage implementation that works the same way regardless of scope.
1457
+ * Replaces RequestContext, HolderManager, SingletonStorage, RequestStorage.
1458
+ *
1459
+ * Scope is just metadata - storage operations are identical for all scopes.
1460
+ * Different storage instances are just isolated storage spaces.
1461
+ */ var UnifiedStorage = class {
1462
+ scope;
1463
+ holders = /* @__PURE__ */ new Map();
1495
1464
  /**
1496
- * Invalidates a single holder using a specific storage.
1497
- */ async invalidateHolderWithStorage(key, holder, storage, round, options = {}) {
1498
- const { emitEvents = true, onInvalidated } = options;
1499
- await this.invalidateHolderByStatus(holder, round, {
1500
- context: key,
1501
- onCreationError: () => this.logger?.error(`[Invalidator] ${key} creation triggered too many invalidation rounds`),
1502
- onRecursiveInvalidate: () => this.invalidateWithStorage(key, storage, round + 1, options),
1503
- onDestroy: () => this.destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated)
1504
- });
1465
+ * Reverse dependency index: maps a dependency name to the set of holder names that depend on it.
1466
+ * This allows O(1) lookup of dependents instead of O(n) iteration.
1467
+ */ dependents = /* @__PURE__ */ new Map();
1468
+ constructor(scope = InjectableScope.Singleton) {
1469
+ this.scope = scope;
1505
1470
  }
1506
- /**
1507
- * Common invalidation logic for holders based on their status.
1508
- */ async invalidateHolderByStatus(holder, round, options) {
1471
+ get(instanceName) {
1472
+ const holder = this.holders.get(instanceName);
1473
+ if (!holder) return null;
1509
1474
  switch (holder.status) {
1510
- case InstanceStatus.Destroying:
1511
- await holder.destroyPromise;
1512
- break;
1475
+ case InstanceStatus.Destroying: return [DIError.instanceDestroying(instanceName), holder];
1476
+ case InstanceStatus.Error: return [holder.instance, holder];
1513
1477
  case InstanceStatus.Creating:
1514
- await holder.creationPromise;
1515
- if (round > 3) {
1516
- options.onCreationError();
1517
- return;
1518
- }
1519
- await options.onRecursiveInvalidate();
1520
- break;
1521
- default:
1522
- await options.onDestroy();
1523
- break;
1478
+ case InstanceStatus.Created: return [void 0, holder];
1479
+ default: return null;
1524
1480
  }
1525
1481
  }
1526
- /**
1527
- * Destroys a holder using a specific storage.
1528
- */ async destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated) {
1529
- holder.status = InstanceStatus.Destroying;
1530
- this.logger?.log(`[Invalidator] Invalidating ${key} and notifying listeners`);
1531
- holder.destroyPromise = Promise.all(holder.destroyListeners.map((listener) => listener())).then(async () => {
1532
- holder.destroyListeners = [];
1533
- holder.deps.clear();
1534
- storage.delete(key);
1535
- if (emitEvents && this.eventBus) await this.emitInstanceEvent(key, "destroy");
1536
- if (onInvalidated) await onInvalidated(key);
1482
+ set(instanceName, holder) {
1483
+ this.holders.set(instanceName, holder);
1484
+ if (holder.deps.size > 0) this.registerDependencies(instanceName, holder.deps);
1485
+ }
1486
+ delete(instanceName) {
1487
+ const holder = this.holders.get(instanceName);
1488
+ if (holder) this.removeFromDependentsIndex(instanceName, holder.deps);
1489
+ return this.holders.delete(instanceName);
1490
+ }
1491
+ createHolder(instanceName, type, deps) {
1492
+ const deferred = Promise.withResolvers();
1493
+ return [deferred, {
1494
+ status: InstanceStatus.Creating,
1495
+ name: instanceName,
1496
+ instance: null,
1497
+ creationPromise: deferred.promise,
1498
+ destroyPromise: null,
1499
+ type,
1500
+ scope: this.scope,
1501
+ deps,
1502
+ destroyListeners: [],
1503
+ createdAt: Date.now(),
1504
+ waitingFor: /* @__PURE__ */ new Set()
1505
+ }];
1506
+ }
1507
+ storeInstance(instanceName, instance) {
1508
+ if (this.holders.get(instanceName)) throw DIError.storageError("Instance already stored", "storeInstance", instanceName);
1509
+ this.set(instanceName, {
1510
+ status: InstanceStatus.Created,
1511
+ name: instanceName,
1512
+ instance,
1513
+ creationPromise: null,
1514
+ destroyPromise: null,
1515
+ type: InjectableType.Class,
1516
+ scope: this.scope,
1517
+ deps: /* @__PURE__ */ new Set(),
1518
+ destroyListeners: typeof instance === "object" && instance !== null && "onServiceDestroy" in instance ? [instance.onServiceDestroy] : [],
1519
+ createdAt: Date.now(),
1520
+ waitingFor: /* @__PURE__ */ new Set()
1537
1521
  });
1538
- await holder.destroyPromise;
1522
+ }
1523
+ handles(scope) {
1524
+ return scope === this.scope;
1525
+ }
1526
+ getAllNames() {
1527
+ return Array.from(this.holders.keys());
1528
+ }
1529
+ forEach(callback) {
1530
+ for (const [name, holder] of this.holders) callback(name, holder);
1531
+ }
1532
+ findByInstance(instance) {
1533
+ for (const holder of this.holders.values()) if (holder.instance === instance) return holder;
1534
+ return null;
1535
+ }
1536
+ findDependents(instanceName) {
1537
+ const dependents = this.dependents.get(instanceName);
1538
+ return dependents ? Array.from(dependents) : [];
1539
1539
  }
1540
1540
  /**
1541
- * Waits for a holder to settle (either created, destroyed, or error state).
1542
- */ async waitForHolderToSettle(holder) {
1543
- switch (holder.status) {
1544
- case InstanceStatus.Creating:
1545
- await holder.creationPromise;
1546
- break;
1547
- case InstanceStatus.Destroying:
1548
- await holder.destroyPromise;
1549
- break;
1550
- case InstanceStatus.Created:
1551
- case InstanceStatus.Error: break;
1541
+ * Updates dependency references when instance names change.
1542
+ * Used during scope upgrades when instance names are regenerated with requestId.
1543
+ *
1544
+ * @param oldName The old instance name
1545
+ * @param newName The new instance name
1546
+ */ updateDependencyReference(oldName, newName) {
1547
+ for (const holder of this.holders.values()) if (holder.deps.has(oldName)) {
1548
+ holder.deps.delete(oldName);
1549
+ holder.deps.add(newName);
1550
+ }
1551
+ const oldDependents = this.dependents.get(oldName);
1552
+ if (oldDependents) {
1553
+ const newDependents = this.dependents.get(newName) || /* @__PURE__ */ new Set();
1554
+ for (const dependent of oldDependents) newDependents.add(dependent);
1555
+ this.dependents.set(newName, newDependents);
1556
+ this.dependents.delete(oldName);
1557
+ }
1558
+ for (const [depName, dependents] of this.dependents.entries()) if (depName === oldName) {
1559
+ const newDependents = this.dependents.get(newName) || /* @__PURE__ */ new Set();
1560
+ for (const dependent of dependents) newDependents.add(dependent);
1561
+ this.dependents.set(newName, newDependents);
1562
+ this.dependents.delete(oldName);
1552
1563
  }
1553
1564
  }
1554
1565
  /**
1555
- * Clears services with dependency awareness for a specific storage.
1556
- */ async clearServicesWithDependencyAwarenessForStorage(serviceNames, maxRounds, storage) {
1557
- const clearedServices = /* @__PURE__ */ new Set();
1558
- let round = 1;
1559
- while (clearedServices.size < serviceNames.length && round <= maxRounds) {
1560
- this.logger?.log(`[Invalidator] Clearing round ${round}/${maxRounds}, ${clearedServices.size}/${serviceNames.length} services cleared`);
1561
- const servicesToClearThisRound = this.findServicesReadyForClearingInStorage(serviceNames, clearedServices, storage);
1562
- if (servicesToClearThisRound.length === 0) {
1563
- const remainingServices = serviceNames.filter((name) => !clearedServices.has(name));
1564
- if (remainingServices.length > 0) {
1565
- this.logger?.warn(`[Invalidator] No services ready for clearing, forcing cleanup of remaining: ${remainingServices.join(", ")}`);
1566
- await this.forceClearServicesInStorage(remainingServices, storage);
1567
- remainingServices.forEach((name) => clearedServices.add(name));
1568
- }
1569
- break;
1566
+ * Registers a holder's dependencies in the reverse index.
1567
+ */ registerDependencies(holderName, deps) {
1568
+ for (const dep of deps) {
1569
+ let dependents = this.dependents.get(dep);
1570
+ if (!dependents) {
1571
+ dependents = /* @__PURE__ */ new Set();
1572
+ this.dependents.set(dep, dependents);
1570
1573
  }
1571
- const clearPromises = servicesToClearThisRound.map(async (serviceName) => {
1572
- try {
1573
- await this.invalidateWithStorage(serviceName, storage, round);
1574
- clearedServices.add(serviceName);
1575
- this.logger?.log(`[Invalidator] Successfully cleared service: ${serviceName}`);
1576
- } catch (error) {
1577
- this.logger?.error(`[Invalidator] Error clearing service ${serviceName}:`, error);
1578
- clearedServices.add(serviceName);
1579
- }
1580
- });
1581
- await Promise.all(clearPromises);
1582
- round++;
1574
+ dependents.add(holderName);
1583
1575
  }
1584
- if (clearedServices.size < serviceNames.length) this.logger?.warn(`[Invalidator] Clearing completed after ${maxRounds} rounds, but ${serviceNames.length - clearedServices.size} services may not have been properly cleared`);
1585
- }
1586
- /**
1587
- * Finds services that are ready to be cleared in the current round.
1588
- * A service is ready if all its dependencies have already been cleared.
1589
- */ findServicesReadyForClearingInStorage(allServiceNames, clearedServices, storage) {
1590
- return allServiceNames.filter((serviceName) => {
1591
- if (clearedServices.has(serviceName)) return false;
1592
- const result = storage.get(serviceName);
1593
- if (result === null || result[0]) return true;
1594
- const [, holder] = result;
1595
- return !Array.from(holder.deps).some((dep) => !clearedServices.has(dep));
1596
- });
1597
1576
  }
1598
1577
  /**
1599
- * Force clears services that couldn't be cleared through normal dependency resolution.
1600
- * This handles edge cases like circular dependencies.
1601
- */ async forceClearServicesInStorage(serviceNames, storage) {
1602
- const promises = serviceNames.map(async (serviceName) => {
1603
- try {
1604
- const result = storage.get(serviceName);
1605
- if (result !== null && !result[0]) {
1606
- const [, holder] = result;
1607
- await this.destroyHolderWithStorage(serviceName, holder, storage, true);
1608
- }
1609
- } catch (error) {
1610
- this.logger?.error(`[Invalidator] Error force clearing service ${serviceName}:`, error);
1578
+ * Removes a holder from the reverse dependency index.
1579
+ */ removeFromDependentsIndex(holderName, deps) {
1580
+ for (const dep of deps) {
1581
+ const dependents = this.dependents.get(dep);
1582
+ if (dependents) {
1583
+ dependents.delete(holderName);
1584
+ if (dependents.size === 0) this.dependents.delete(dep);
1611
1585
  }
1612
- });
1613
- await Promise.all(promises);
1614
- }
1615
- /**
1616
- * Emits events to listeners for instance lifecycle events.
1617
- */ emitInstanceEvent(name, event = "create") {
1618
- if (!this.eventBus) return Promise.resolve();
1619
- this.logger?.log(`[Invalidator]#emitInstanceEvent() Notifying listeners for ${name} with event ${event}`);
1620
- return this.eventBus.emit(name, event);
1586
+ }
1621
1587
  }
1622
1588
  };
1623
1589
 
@@ -1641,328 +1607,242 @@ var SingletonStorage = class {
1641
1607
  const nsEvents = this.listeners.get(ns);
1642
1608
  if (!nsEvents.has(event)) nsEvents.set(event, /* @__PURE__ */ new Set());
1643
1609
  nsEvents.get(event).add(listener);
1644
- return () => {
1645
- nsEvents.get(event)?.delete(listener);
1646
- if (nsEvents.get(event)?.size === 0) nsEvents.delete(event);
1647
- if (nsEvents.size === 0) this.listeners.delete(ns);
1648
- };
1649
- }
1650
- async emit(key, event) {
1651
- if (!this.listeners.has(key)) return;
1652
- const events = this.listeners.get(key);
1653
- this.logger?.debug(`[LifecycleEventBus]#emit(): ${key}:${event}`);
1654
- return await Promise.allSettled([...events.get(event) ?? []].map((listener) => listener(event))).then((results) => {
1655
- const res = results.filter((result) => result.status === "rejected").map((result) => {
1656
- this.logger?.warn(`[LifecycleEventBus]#emit(): ${key}:${event} rejected with`, result.reason);
1657
- return result;
1658
- });
1659
- if (res.length > 0) return Promise.reject(res);
1660
- return results;
1661
- });
1662
- }
1663
- };
1664
-
1665
- //#endregion
1666
- //#region src/internal/holder/holder-manager.mts
1667
- /**
1668
- * Manages the storage and retrieval of singleton instance holders.
1669
- *
1670
- * Provides CRUD operations and filtering for the holder map.
1671
- * Handles holder state validation (destroying, error states) on retrieval.
1672
- */ var HolderManager = class extends BaseHolderManager {
1673
- constructor(logger = null) {
1674
- super(logger);
1675
- }
1676
- get(name) {
1677
- const holder = this._holders.get(name);
1678
- if (holder) {
1679
- if (holder.status === InstanceStatus.Destroying) {
1680
- this.logger?.log(`[HolderManager]#get() Instance ${holder.name} is destroying`);
1681
- return [DIError.instanceDestroying(holder.name), holder];
1682
- } else if (holder.status === InstanceStatus.Error) {
1683
- this.logger?.log(`[HolderManager]#get() Instance ${holder.name} is in error state`);
1684
- return [holder.instance, holder];
1685
- }
1686
- return [void 0, holder];
1687
- } else {
1688
- this.logger?.log(`[HolderManager]#get() Instance ${name} not found`);
1689
- return [DIError.instanceNotFound(name)];
1690
- }
1691
- }
1692
- set(name, holder) {
1693
- this._holders.set(name, holder);
1694
- }
1695
- has(name) {
1696
- const [error, holder] = this.get(name);
1697
- if (!error) return [void 0, true];
1698
- if (error.code === DIErrorCode.InstanceDestroying) return [error];
1699
- return [void 0, !!holder];
1700
- }
1701
- /**
1702
- * Creates a new holder with Created status and stores it.
1703
- * This is useful for creating holders that already have their instance ready.
1704
- * @param name The name of the instance
1705
- * @param instance The actual instance to store
1706
- * @param type The injectable type
1707
- * @param scope The injectable scope
1708
- * @param deps Optional set of dependencies
1709
- * @returns The created holder
1710
- */ storeCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set()) {
1711
- const holder = this.createCreatedHolder(name, instance, type, scope, deps);
1712
- this._holders.set(name, holder);
1713
- return holder;
1714
- }
1715
- };
1716
-
1717
- //#endregion
1718
- //#region src/internal/core/token-processor.mts
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);
1610
+ return () => {
1611
+ nsEvents.get(event)?.delete(listener);
1612
+ if (nsEvents.get(event)?.size === 0) nsEvents.delete(event);
1613
+ if (nsEvents.size === 0) this.listeners.delete(ns);
1614
+ };
1743
1615
  }
1744
- clear() {
1745
- this.cache.clear();
1616
+ async emit(key, event) {
1617
+ if (!this.listeners.has(key)) return;
1618
+ const events = this.listeners.get(key);
1619
+ this.logger?.debug(`[LifecycleEventBus]#emit(): ${key}:${event}`);
1620
+ return await Promise.allSettled([...events.get(event) ?? []].map((listener) => listener(event))).then((results) => {
1621
+ const res = results.filter((result) => result.status === "rejected").map((result) => {
1622
+ this.logger?.warn(`[LifecycleEventBus]#emit(): ${key}:${event} rejected with`, result.reason);
1623
+ return result;
1624
+ });
1625
+ if (res.length > 0) return Promise.reject(res);
1626
+ return results;
1627
+ });
1746
1628
  }
1747
1629
  };
1630
+
1631
+ //#endregion
1632
+ //#region src/internal/stub-factory-class.mts
1748
1633
  /**
1749
- * Handles token validation, normalization, and instance name generation.
1634
+ * Stub factory class used when registering InjectionTokens without a real class implementation.
1635
+ * This is used in ScopedContainer.addInstance() to allow registering tokens that don't have
1636
+ * a corresponding class, while preventing accidental instantiation.
1750
1637
  *
1751
- * Provides utilities for resolving tokens to their underlying InjectionToken,
1752
- * validating arguments against schemas, and generating unique instance identifiers.
1753
- */ var TokenProcessor = class {
1754
- logger;
1755
- instanceNameCache = new InstanceNameCache();
1756
- constructor(logger = null) {
1757
- this.logger = logger;
1638
+ * @internal
1639
+ */ var StubFactoryClass = class {
1640
+ constructor() {
1641
+ throw DIError.factoryNotFound("Trying to get instance of factory without real implementation");
1758
1642
  }
1643
+ };
1644
+
1645
+ //#endregion
1646
+ //#region src/container/abstract-container.mts
1647
+ /**
1648
+ * Abstract base class for dependency injection containers.
1649
+ *
1650
+ * Provides shared implementation for common container operations.
1651
+ * Both Container and ScopedContainer extend this class.
1652
+ */ var AbstractContainer = class {
1759
1653
  /**
1760
- * Normalizes a token to an InjectionToken.
1761
- * Handles class constructors by getting their injectable token.
1654
+ * Calculates the instance name for a given token and optional arguments.
1762
1655
  *
1763
- * @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
1764
- * @returns The normalized InjectionTokenType
1765
- */ normalizeToken(token) {
1766
- if (typeof token === "function") return getInjectableToken(token);
1767
- return token;
1656
+ * @internal
1657
+ * @param token The class type, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
1658
+ * @param args Optional arguments (ignored for BoundInjectionToken which uses its bound value)
1659
+ * @returns The calculated instance name string, or null if the token is a FactoryInjectionToken that is not yet resolved
1660
+ */ calculateInstanceName(token, args) {
1661
+ const [err, { actualToken, validatedArgs }] = this.getTokenResolver().validateAndResolveTokenArgs(token, args);
1662
+ if (err) {
1663
+ if (err instanceof DIError && err.code === DIErrorCode.FactoryTokenNotResolved) return null;
1664
+ if (err instanceof DIError && err.code === DIErrorCode.TokenValidationError) return null;
1665
+ }
1666
+ const realToken = this.getTokenResolver().getRealToken(actualToken);
1667
+ const registry = this.getRegistry();
1668
+ const scope = registry.has(realToken) ? registry.get(realToken).scope : this.defaultScope;
1669
+ return this.getNameResolver().generateInstanceName(actualToken, validatedArgs, scope === InjectableScope.Request ? this.requestId : void 0, scope);
1768
1670
  }
1769
1671
  /**
1770
- * Gets the underlying "real" token from wrapped tokens.
1771
- * For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.
1772
- * For other tokens, returns the token itself.
1773
- *
1774
- * @param token The token to unwrap
1775
- * @returns The underlying InjectionToken
1776
- */ getRealToken(token) {
1777
- if (token instanceof BoundInjectionToken || token instanceof FactoryInjectionToken) return token.token;
1778
- return token;
1672
+ * Checks if a service is registered in the container.
1673
+ */ isRegistered(token) {
1674
+ const realToken = this.getTokenResolver().getRegistryToken(token);
1675
+ return this.getRegistry().has(realToken);
1779
1676
  }
1780
1677
  /**
1781
- * Convenience method that normalizes a token and then gets the real token.
1782
- * Useful for checking registry entries where you need the actual registered token.
1783
- *
1784
- * @param token Any injectable type
1785
- * @returns The underlying InjectionToken
1786
- */ getRegistryToken(token) {
1787
- return this.getRealToken(this.normalizeToken(token));
1678
+ * Waits for all pending operations to complete.
1679
+ */ async ready() {
1680
+ await this.getServiceInvalidator().readyWithStorage(this.getStorage());
1788
1681
  }
1789
1682
  /**
1790
- * Validates and resolves token arguments, handling factory token resolution and validation.
1791
- */ validateAndResolveTokenArgs(token, args) {
1792
- let actualToken = token;
1793
- if (typeof token === "function") actualToken = getInjectableToken(token);
1794
- let realArgs = args;
1795
- if (actualToken instanceof BoundInjectionToken) realArgs = actualToken.value;
1796
- else if (actualToken instanceof FactoryInjectionToken) if (actualToken.resolved) realArgs = actualToken.value;
1797
- else return [DIError.factoryTokenNotResolved(token.name), { actualToken }];
1798
- if (!actualToken.schema) return [void 0, {
1799
- actualToken,
1800
- validatedArgs: realArgs
1801
- }];
1802
- const validatedArgs = actualToken.schema?.safeParse(realArgs);
1803
- if (validatedArgs && !validatedArgs.success) {
1804
- this.logger?.error(`[TokenProcessor]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`, validatedArgs.error);
1805
- return [DIError.unknown(validatedArgs.error), { actualToken }];
1806
- }
1807
- return [void 0, {
1808
- actualToken,
1809
- validatedArgs: validatedArgs?.data
1810
- }];
1683
+ * @internal
1684
+ * Attempts to get an instance synchronously if it already exists.
1685
+ */ tryGetSync(token, args) {
1686
+ return this.tryGetSyncFromStorage(token, args, this.getStorage(), this.requestId);
1811
1687
  }
1812
1688
  /**
1813
- * Generates a unique instance name based on token and arguments.
1814
- * Results are cached using an LRU cache for performance.
1815
- */ generateInstanceName(token, args) {
1816
- if (!args) return token.toString();
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;
1689
+ * @internal
1690
+ * Internal method for getting instances synchronously with configurable storage.
1691
+ */ tryGetSyncFromStorage(token, args, storage, requestId) {
1692
+ const tokenResolver = this.getTokenResolver();
1693
+ const realToken = tokenResolver.getRegistryToken(token);
1694
+ const registry = this.getRegistry();
1695
+ const scope = registry.has(realToken) ? registry.get(realToken).scope : InjectableScope.Singleton;
1696
+ try {
1697
+ const instanceName = this.getNameResolver().generateInstanceName(tokenResolver.normalizeToken(token), args, requestId, scope);
1698
+ const result = storage.get(instanceName);
1699
+ if (result && result[0] === void 0 && result[1]) {
1700
+ const holder = result[1];
1701
+ if (holder.status === InstanceStatus.Created) return holder.instance;
1702
+ }
1703
+ } catch {}
1704
+ return null;
1824
1705
  }
1825
1706
  /**
1826
- * Formats a single argument value for instance name generation.
1827
- */ formatArgValue(value) {
1828
- if (typeof value === "function") return `fn_${value.name}(${value.length})`;
1829
- if (typeof value === "symbol") return value.toString();
1830
- return JSON.stringify(value).slice(0, 40);
1707
+ * Adds an instance to the container.
1708
+ * Accepts class types, InjectionTokens, and BoundInjectionTokens.
1709
+ * Rejects InjectionTokens with required schemas (use BoundInjectionToken instead).
1710
+ *
1711
+ * @param token The class type, InjectionToken, or BoundInjectionToken to register the instance for
1712
+ * @param instance The instance to store
1713
+ */ addInstance(token, instance) {
1714
+ this.addInstanceToStorage(token, instance, this.getStorage(), this.defaultScope, this.requestId);
1831
1715
  }
1832
1716
  /**
1833
- * Creates a factory context for dependency injection during service instantiation.
1834
- * @param container The container instance (Container or ScopedContainer) for dependency resolution
1835
- * @param onDependencyResolved Callback when a dependency is resolved, receives the instance name
1836
- */ createFactoryContext(container, onDependencyResolved) {
1837
- const destroyListeners = /* @__PURE__ */ new Set();
1838
- const deps = /* @__PURE__ */ new Set();
1839
- function addDestroyListener(listener) {
1840
- destroyListeners.add(listener);
1841
- }
1842
- function getDestroyListeners() {
1843
- return Array.from(destroyListeners);
1717
+ * @internal
1718
+ * Internal method for adding instances with configurable scope and storage.
1719
+ */ addInstanceToStorage(token, instance, storage, scope, requestId) {
1720
+ if (token instanceof InjectionToken) {
1721
+ if (token.schema) {
1722
+ if (token.schema?.def?.type !== "optional") throw DIError.tokenSchemaRequiredError(token.name);
1723
+ }
1844
1724
  }
1845
- const self = this;
1846
- return {
1847
- async inject(token, args) {
1848
- const actualToken = typeof token === "function" ? getInjectableToken(token) : token;
1849
- const instanceName = self.generateInstanceName(actualToken, args);
1850
- deps.add(instanceName);
1851
- if (onDependencyResolved) onDependencyResolved(instanceName);
1852
- return container.get(token, args);
1853
- },
1854
- addDestroyListener,
1855
- getDestroyListeners,
1856
- container,
1857
- deps
1858
- };
1725
+ const tokenResolver = this.getTokenResolver();
1726
+ const registry = this.getRegistry();
1727
+ const normalizedToken = tokenResolver.normalizeToken(token);
1728
+ const realToken = tokenResolver.getRegistryToken(token);
1729
+ if (typeof token === "function" && !registry.has(realToken)) registry.set(realToken, scope, token, InjectableType.Class);
1730
+ else if (!registry.has(realToken)) registry.set(realToken, scope, StubFactoryClass, InjectableType.Class, -1);
1731
+ const instanceName = this.getNameResolver().generateInstanceName(normalizedToken, normalizedToken instanceof BoundInjectionToken ? normalizedToken.value : void 0, requestId, scope);
1732
+ storage.storeInstance(instanceName, instance);
1859
1733
  }
1860
1734
  };
1861
1735
 
1862
1736
  //#endregion
1863
- //#region src/internal/core/service-locator.mts
1737
+ //#region src/container/scoped-container.mts
1864
1738
  /**
1865
- * Core DI engine that coordinates service instantiation, resolution, and lifecycle.
1739
+ * Request-scoped dependency injection container.
1866
1740
  *
1867
- * Acts as the central orchestrator for dependency injection operations,
1868
- * delegating to specialized components (InstanceResolver, Instantiator, Invalidator)
1869
- * for specific tasks.
1870
- */ var ServiceLocator = class {
1741
+ * Wraps a parent Container and provides isolated request-scoped instances
1742
+ * while delegating singleton and transient resolution to the parent.
1743
+ * This design eliminates race conditions that can occur with async operations
1744
+ * when multiple requests are processed concurrently.
1745
+ */ var ScopedContainer = class extends AbstractContainer {
1746
+ parent;
1871
1747
  registry;
1872
- logger;
1873
- injectors;
1874
- eventBus;
1875
- manager;
1876
- instantiator;
1877
- tokenProcessor;
1878
- invalidator;
1879
- instanceResolver;
1880
- constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
1881
- this.registry = registry;
1882
- this.logger = logger;
1883
- this.injectors = injectors;
1884
- this.eventBus = new LifecycleEventBus(logger);
1885
- this.manager = new HolderManager(logger);
1886
- this.instantiator = new Instantiator(injectors);
1887
- this.tokenProcessor = new TokenProcessor(logger);
1888
- this.invalidator = new Invalidator(this.manager, this.eventBus, logger);
1889
- this.instanceResolver = new InstanceResolver(this.registry, this.manager, this.instantiator, this.tokenProcessor, logger, this);
1748
+ requestId;
1749
+ defaultScope = InjectableScope.Request;
1750
+ storage;
1751
+ disposed = false;
1752
+ metadata;
1753
+ constructor(parent, registry, requestId, metadata) {
1754
+ super(), this.parent = parent, this.registry = registry, this.requestId = requestId;
1755
+ this.storage = new UnifiedStorage(InjectableScope.Request);
1756
+ this.metadata = metadata || {};
1890
1757
  }
1891
- getEventBus() {
1892
- return this.eventBus;
1758
+ getStorage() {
1759
+ return this.storage;
1893
1760
  }
1894
- getManager() {
1895
- return this.manager;
1761
+ getRegistry() {
1762
+ return this.registry;
1896
1763
  }
1897
- getInvalidator() {
1898
- return this.invalidator;
1764
+ getTokenResolver() {
1765
+ return this.parent.getTokenResolver();
1899
1766
  }
1900
- getTokenProcessor() {
1901
- return this.tokenProcessor;
1767
+ getNameResolver() {
1768
+ return this.parent.getNameResolver();
1902
1769
  }
1903
- getInstanceIdentifier(token, args) {
1904
- const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
1905
- if (err) throw err;
1906
- return this.tokenProcessor.generateInstanceName(actualToken, validatedArgs);
1770
+ getServiceInvalidator() {
1771
+ return this.parent.getServiceInvalidator();
1907
1772
  }
1908
1773
  /**
1909
- * Gets or creates an instance for the given token.
1910
- * @param token The injection token
1911
- * @param args Optional arguments
1912
- * @param contextContainer The container to use for creating FactoryContext
1913
- */ async getInstance(token, args, contextContainer) {
1914
- const [err, data] = await this.instanceResolver.resolveInstance(token, args, contextContainer);
1915
- if (err) return [err];
1916
- return [void 0, data];
1774
+ * Gets the request ID for this scoped container.
1775
+ */ getRequestId() {
1776
+ return this.requestId;
1917
1777
  }
1918
1778
  /**
1919
- * Gets or throws an instance for the given token.
1920
- * @param token The injection token
1921
- * @param args Optional arguments
1922
- * @param contextContainer The container to use for creating FactoryContext
1923
- */ async getOrThrowInstance(token, args, contextContainer) {
1924
- const [error, instance] = await this.getInstance(token, args, contextContainer);
1779
+ * Gets the parent container.
1780
+ */ getParent() {
1781
+ return this.parent;
1782
+ }
1783
+ /**
1784
+ * Gets metadata from the request context.
1785
+ */ getMetadata(key) {
1786
+ return this.metadata[key];
1787
+ }
1788
+ /**
1789
+ * Sets metadata on the request context.
1790
+ */ setMetadata(key, value) {
1791
+ this.metadata[key] = value;
1792
+ }
1793
+ async get(token, args) {
1794
+ if (this.disposed) throw new Error("ScopedContainer has been disposed");
1795
+ const realToken = this.getTokenResolver().getRegistryToken(token);
1796
+ if (this.registry.has(realToken)) {
1797
+ if (this.registry.get(realToken).scope === InjectableScope.Request) {
1798
+ const [error$1, instance$1] = await this.parent.getInstanceResolver().resolveRequestScopedInstance(token, args, this);
1799
+ if (error$1) throw error$1;
1800
+ return instance$1;
1801
+ }
1802
+ }
1803
+ const [error, instance] = await this.parent.getInstanceResolver().resolveInstance(token, args, this, this.storage, this.requestId);
1925
1804
  if (error) throw error;
1926
1805
  return instance;
1927
1806
  }
1928
1807
  /**
1929
- * Resolves a request-scoped service for a ScopedContainer.
1930
- * The service will be stored in the ScopedContainer's request context.
1931
- *
1932
- * @param token The injection token
1933
- * @param args Optional arguments
1934
- * @param scopedContainer The ScopedContainer that owns the request context
1935
- */ async resolveRequestScoped(token, args, scopedContainer) {
1936
- const [err, data] = await this.instanceResolver.resolveRequestScopedInstance(token, args, scopedContainer);
1937
- if (err) throw err;
1938
- return data;
1939
- }
1940
- getSyncInstance(token, args, contextContainer) {
1941
- return this.instanceResolver.getSyncInstance(token, args, contextContainer);
1808
+ * Invalidates a service and its dependencies.
1809
+ */ async invalidate(service) {
1810
+ const holder = this.storage.findByInstance(service);
1811
+ if (!holder) return this.parent.invalidate(service);
1812
+ await this.getServiceInvalidator().invalidateWithStorage(holder.name, this.storage);
1942
1813
  }
1943
- invalidate(service, round = 1) {
1944
- return this.invalidator.invalidate(service, round);
1814
+ /**
1815
+ * Disposes the container and cleans up all resources.
1816
+ * Alias for endRequest().
1817
+ */ async dispose() {
1818
+ return this.endRequest();
1945
1819
  }
1946
1820
  /**
1947
- * Gracefully clears all services in the ServiceLocator using invalidation logic.
1948
- * This method respects service dependencies and ensures proper cleanup order.
1949
- * Services that depend on others will be invalidated first, then their dependencies.
1950
- *
1951
- * @param options Optional configuration for the clearing process
1952
- * @returns Promise that resolves when all services have been cleared
1953
- */ async clearAll(options = {}) {
1954
- return this.invalidator.clearAll(options);
1821
+ * @internal
1822
+ * Attempts to get an instance synchronously if it already exists.
1823
+ * Checks request storage first, then delegates to parent.
1824
+ */ tryGetSync(token, args) {
1825
+ const realToken = this.getTokenResolver().getRegistryToken(token);
1826
+ if ((this.registry.has(realToken) ? this.registry.get(realToken).scope : InjectableScope.Singleton) === InjectableScope.Request) {
1827
+ const result = this.tryGetSyncFromStorage(token, args, this.storage, this.requestId);
1828
+ if (result !== null) return result;
1829
+ }
1830
+ return this.parent.tryGetSync(token, args, this.requestId);
1955
1831
  }
1956
1832
  /**
1957
- * Waits for all services to settle (either created, destroyed, or error state).
1958
- */ async ready() {
1959
- return this.invalidator.ready();
1833
+ * Adds an instance to the container.
1834
+ * Overrides base class to check disposed state.
1835
+ */ addInstance(token, instance) {
1836
+ if (this.disposed) throw new Error("ScopedContainer has been disposed");
1837
+ super.addInstance(token, instance);
1960
1838
  }
1961
1839
  /**
1962
- * Helper method for InstanceResolver to generate instance names.
1963
- * This is needed for the factory context creation.
1964
- */ generateInstanceName(token, args) {
1965
- return this.tokenProcessor.generateInstanceName(token, args);
1840
+ * Ends the request and cleans up all request-scoped services.
1841
+ */ async endRequest() {
1842
+ if (this.disposed) return;
1843
+ this.disposed = true;
1844
+ await this.getServiceInvalidator().clearAllWithStorage(this.storage);
1845
+ this.parent.removeRequestId(this.requestId);
1966
1846
  }
1967
1847
  };
1968
1848
 
@@ -2245,142 +2125,125 @@ function applyDecs2203RFactory() {
2245
2125
  function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
2246
2126
  return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
2247
2127
  }
2248
- var _dec, _initClass;
2128
+ var _dec, _initClass, _AbstractContainer;
2249
2129
  let _Container;
2250
2130
  _dec = Injectable();
2251
- var Container = class {
2131
+ var Container = class extends (_AbstractContainer = AbstractContainer) {
2252
2132
  registry;
2253
2133
  logger;
2254
2134
  injectors;
2255
2135
  static {
2256
- ({c: [_Container, _initClass]} = _apply_decs_2203_r(this, [], [_dec]));
2136
+ ({c: [_Container, _initClass]} = _apply_decs_2203_r(this, [], [_dec], _AbstractContainer));
2257
2137
  }
2258
2138
  constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
2259
- this.registry = registry;
2260
- this.logger = logger;
2261
- this.injectors = injectors;
2262
- this.serviceLocator = new ServiceLocator(registry, logger, injectors);
2139
+ super(), this.registry = registry, this.logger = logger, this.injectors = injectors;
2140
+ this.storage = new UnifiedStorage(InjectableScope.Singleton);
2141
+ this.eventBus = new LifecycleEventBus(logger);
2142
+ this.nameResolver = new NameResolver(logger);
2143
+ this.tokenResolver = new TokenResolver(logger);
2144
+ this.scopeTracker = new ScopeTracker(registry, this.nameResolver, logger);
2145
+ this.serviceInitializer = new ServiceInitializer(injectors);
2146
+ this.serviceInvalidator = new ServiceInvalidator(this.eventBus, logger);
2147
+ this.instanceResolver = new InstanceResolver(registry, this.storage, this.serviceInitializer, this.tokenResolver, this.nameResolver, this.scopeTracker, this.serviceInvalidator, this.eventBus, logger);
2263
2148
  this.registerSelf();
2264
2149
  }
2265
- serviceLocator;
2150
+ defaultScope = InjectableScope.Singleton;
2151
+ requestId = void 0;
2152
+ storage;
2153
+ serviceInitializer;
2154
+ serviceInvalidator;
2155
+ tokenResolver;
2156
+ nameResolver;
2157
+ scopeTracker;
2158
+ eventBus;
2159
+ instanceResolver;
2266
2160
  activeRequestIds = /* @__PURE__ */ new Set();
2267
2161
  registerSelf() {
2268
2162
  const token = getInjectableToken(_Container);
2269
- const instanceName = this.serviceLocator.getInstanceIdentifier(token);
2270
- this.serviceLocator.getManager().storeCreatedHolder(instanceName, this, InjectableType.Class, InjectableScope.Singleton);
2163
+ this.registry.set(token, InjectableScope.Singleton, _Container, InjectableType.Class);
2164
+ const instanceName = this.nameResolver.generateInstanceName(token, void 0, void 0, InjectableScope.Singleton);
2165
+ this.storage.storeInstance(instanceName, this);
2271
2166
  }
2272
2167
  async get(token, args) {
2273
- const realToken = this.serviceLocator.getTokenProcessor().getRegistryToken(token);
2168
+ const realToken = this.tokenResolver.getRegistryToken(token);
2274
2169
  if (this.registry.has(realToken)) {
2275
- if (this.registry.get(realToken).scope === InjectableScope.Request) throw DIError.unknown(`Cannot resolve request-scoped service "${String(realToken.name)}" from Container. Use beginRequest() to create a ScopedContainer for request-scoped services.`);
2170
+ if (this.registry.get(realToken).scope === InjectableScope.Request) throw DIError.scopeMismatchError(realToken.name, "ScopedContainer", "Container");
2276
2171
  }
2277
- return this.serviceLocator.getOrThrowInstance(token, args, this);
2278
- }
2279
- /**
2280
- * Gets an instance with a specific container context.
2281
- * Used by ScopedContainer to delegate singleton/transient resolution
2282
- * while maintaining the correct container context for nested inject() calls.
2283
- *
2284
- * @internal
2285
- */ async getWithContext(token, args, contextContainer) {
2286
- return this.serviceLocator.getOrThrowInstance(token, args, contextContainer);
2287
- }
2288
- /**
2289
- * Resolves a request-scoped service for a ScopedContainer.
2290
- * The service will be stored in the ScopedContainer's request context.
2291
- *
2292
- * @internal
2293
- */ async resolveForRequest(token, args, scopedContainer) {
2294
- return this.serviceLocator.resolveRequestScoped(token, args, scopedContainer);
2295
- }
2296
- /**
2297
- * Gets the underlying ServiceLocator instance for advanced usage
2298
- */ getServiceLocator() {
2299
- return this.serviceLocator;
2300
- }
2301
- /**
2302
- * Gets the registry
2303
- */ getRegistry() {
2304
- return this.registry;
2172
+ const [error, instance] = await this.instanceResolver.resolveInstance(token, args, this);
2173
+ if (error) throw error;
2174
+ return instance;
2305
2175
  }
2306
2176
  /**
2307
- * Invalidates a service and its dependencies
2177
+ * Invalidates a service and its dependencies.
2308
2178
  */ async invalidate(service) {
2309
- const holder = this.getHolderByInstance(service);
2310
- if (holder) await this.serviceLocator.invalidate(holder.name);
2311
- }
2312
- /**
2313
- * Gets a service holder by instance (reverse lookup)
2314
- */ getHolderByInstance(instance) {
2315
- const holderMap = Array.from(this.serviceLocator.getManager().filter((holder) => holder.instance === instance).values());
2316
- return holderMap.length > 0 ? holderMap[0] : null;
2317
- }
2318
- /**
2319
- * Checks if a service is registered in the container
2320
- */ isRegistered(token) {
2321
- try {
2322
- return this.serviceLocator.getInstanceIdentifier(token) !== null;
2323
- } catch {
2324
- return false;
2179
+ const holder = this.storage.findByInstance(service);
2180
+ if (!holder) {
2181
+ this.logger?.warn(`[Container] Service instance not found for invalidation`);
2182
+ return;
2325
2183
  }
2184
+ await this.serviceInvalidator.invalidateWithStorage(holder.name, this.storage);
2326
2185
  }
2327
2186
  /**
2328
- * Disposes the container and cleans up all resources
2187
+ * Disposes the container and cleans up all resources.
2329
2188
  */ async dispose() {
2330
- await this.serviceLocator.clearAll();
2331
- }
2332
- /**
2333
- * Waits for all pending operations to complete
2334
- */ async ready() {
2335
- await this.serviceLocator.ready();
2189
+ await this.serviceInvalidator.clearAllWithStorage(this.storage);
2336
2190
  }
2337
2191
  /**
2338
2192
  * @internal
2339
2193
  * Attempts to get an instance synchronously if it already exists.
2340
- * Returns null if the instance doesn't exist or is not ready.
2341
- */ tryGetSync(token, args) {
2342
- return this.serviceLocator.getSyncInstance(token, args, this);
2194
+ * Overrides base class to support requestId parameter for ScopedContainer compatibility.
2195
+ */ tryGetSync(token, args, requestId) {
2196
+ return this.tryGetSyncFromStorage(token, args, this.storage, requestId ?? this.requestId);
2343
2197
  }
2344
2198
  /**
2345
2199
  * Begins a new request context and returns a ScopedContainer.
2346
- *
2347
- * The ScopedContainer provides isolated request-scoped service resolution
2348
- * while delegating singleton and transient services to this Container.
2349
- *
2350
- * @param requestId Unique identifier for this request
2351
- * @param metadata Optional metadata for the request
2352
- * @param priority Priority for resolution (higher = more priority)
2353
- * @returns A ScopedContainer for this request
2354
- */ beginRequest(requestId, metadata, priority = 100) {
2355
- if (this.activeRequestIds.has(requestId)) throw DIError.unknown(`Request context "${requestId}" already exists. Use a unique request ID.`);
2200
+ */ beginRequest(requestId, metadata) {
2201
+ if (this.activeRequestIds.has(requestId)) throw new Error(`Request with ID ${requestId} already exists`);
2356
2202
  this.activeRequestIds.add(requestId);
2357
- this.logger?.log(`[Container] Started request context: ${requestId}`);
2358
- return new ScopedContainer(this, this.registry, requestId, metadata, priority);
2359
- }
2360
- /**
2361
- * Removes a request ID from the active set.
2362
- * Called by ScopedContainer when the request ends.
2363
- *
2364
- * @internal
2365
- */ removeActiveRequest(requestId) {
2366
- this.activeRequestIds.delete(requestId);
2367
- this.logger?.log(`[Container] Ended request context: ${requestId}`);
2203
+ return new ScopedContainer(this, this.registry, requestId, metadata);
2368
2204
  }
2369
2205
  /**
2370
- * Gets the set of active request IDs.
2206
+ * Gets all active request IDs.
2371
2207
  */ getActiveRequestIds() {
2372
2208
  return this.activeRequestIds;
2373
2209
  }
2374
2210
  /**
2375
- * Checks if a request ID is currently active.
2211
+ * Checks if a request is active.
2376
2212
  */ hasActiveRequest(requestId) {
2377
2213
  return this.activeRequestIds.has(requestId);
2378
2214
  }
2379
2215
  /**
2380
- * Clears all instances and bindings from the container.
2381
- * This is useful for testing or resetting the container state.
2382
- */ clear() {
2383
- return this.serviceLocator.clearAll();
2216
+ * Removes a request ID from active requests.
2217
+ * Called by ScopedContainer when request ends.
2218
+ */ removeRequestId(requestId) {
2219
+ this.activeRequestIds.delete(requestId);
2220
+ }
2221
+ getStorage() {
2222
+ return this.storage;
2223
+ }
2224
+ getServiceInitializer() {
2225
+ return this.serviceInitializer;
2226
+ }
2227
+ getServiceInvalidator() {
2228
+ return this.serviceInvalidator;
2229
+ }
2230
+ getTokenResolver() {
2231
+ return this.tokenResolver;
2232
+ }
2233
+ getNameResolver() {
2234
+ return this.nameResolver;
2235
+ }
2236
+ getScopeTracker() {
2237
+ return this.scopeTracker;
2238
+ }
2239
+ getEventBus() {
2240
+ return this.eventBus;
2241
+ }
2242
+ getRegistry() {
2243
+ return this.registry;
2244
+ }
2245
+ getInstanceResolver() {
2246
+ return this.instanceResolver;
2384
2247
  }
2385
2248
  static {
2386
2249
  _initClass();
@@ -2388,12 +2251,6 @@ var Container = class {
2388
2251
  };
2389
2252
 
2390
2253
  //#endregion
2391
- Object.defineProperty(exports, 'BaseHolderManager', {
2392
- enumerable: true,
2393
- get: function () {
2394
- return BaseHolderManager;
2395
- }
2396
- });
2397
2254
  Object.defineProperty(exports, 'BoundInjectionToken', {
2398
2255
  enumerable: true,
2399
2256
  get: function () {
@@ -2418,24 +2275,12 @@ Object.defineProperty(exports, 'DIErrorCode', {
2418
2275
  return DIErrorCode;
2419
2276
  }
2420
2277
  });
2421
- Object.defineProperty(exports, 'DefaultRequestContext', {
2422
- enumerable: true,
2423
- get: function () {
2424
- return DefaultRequestContext;
2425
- }
2426
- });
2427
2278
  Object.defineProperty(exports, 'FactoryInjectionToken', {
2428
2279
  enumerable: true,
2429
2280
  get: function () {
2430
2281
  return FactoryInjectionToken;
2431
2282
  }
2432
2283
  });
2433
- Object.defineProperty(exports, 'HolderManager', {
2434
- enumerable: true,
2435
- get: function () {
2436
- return HolderManager;
2437
- }
2438
- });
2439
2284
  Object.defineProperty(exports, 'Injectable', {
2440
2285
  enumerable: true,
2441
2286
  get: function () {
@@ -2478,22 +2323,16 @@ Object.defineProperty(exports, 'InstanceStatus', {
2478
2323
  return InstanceStatus;
2479
2324
  }
2480
2325
  });
2481
- Object.defineProperty(exports, 'Instantiator', {
2482
- enumerable: true,
2483
- get: function () {
2484
- return Instantiator;
2485
- }
2486
- });
2487
- Object.defineProperty(exports, 'Invalidator', {
2326
+ Object.defineProperty(exports, 'LifecycleEventBus', {
2488
2327
  enumerable: true,
2489
2328
  get: function () {
2490
- return Invalidator;
2329
+ return LifecycleEventBus;
2491
2330
  }
2492
2331
  });
2493
- Object.defineProperty(exports, 'LifecycleEventBus', {
2332
+ Object.defineProperty(exports, 'NameResolver', {
2494
2333
  enumerable: true,
2495
2334
  get: function () {
2496
- return LifecycleEventBus;
2335
+ return NameResolver;
2497
2336
  }
2498
2337
  });
2499
2338
  Object.defineProperty(exports, 'Registry', {
@@ -2502,10 +2341,10 @@ Object.defineProperty(exports, 'Registry', {
2502
2341
  return Registry;
2503
2342
  }
2504
2343
  });
2505
- Object.defineProperty(exports, 'RequestStorage', {
2344
+ Object.defineProperty(exports, 'ScopeTracker', {
2506
2345
  enumerable: true,
2507
2346
  get: function () {
2508
- return RequestStorage;
2347
+ return ScopeTracker;
2509
2348
  }
2510
2349
  });
2511
2350
  Object.defineProperty(exports, 'ScopedContainer', {
@@ -2514,22 +2353,34 @@ Object.defineProperty(exports, 'ScopedContainer', {
2514
2353
  return ScopedContainer;
2515
2354
  }
2516
2355
  });
2517
- Object.defineProperty(exports, 'ServiceLocator', {
2356
+ Object.defineProperty(exports, 'ServiceInitializer', {
2357
+ enumerable: true,
2358
+ get: function () {
2359
+ return ServiceInitializer;
2360
+ }
2361
+ });
2362
+ Object.defineProperty(exports, 'ServiceInvalidator', {
2518
2363
  enumerable: true,
2519
2364
  get: function () {
2520
- return ServiceLocator;
2365
+ return ServiceInvalidator;
2521
2366
  }
2522
2367
  });
2523
- Object.defineProperty(exports, 'SingletonStorage', {
2368
+ Object.defineProperty(exports, 'StubFactoryClass', {
2524
2369
  enumerable: true,
2525
2370
  get: function () {
2526
- return SingletonStorage;
2371
+ return StubFactoryClass;
2527
2372
  }
2528
2373
  });
2529
- Object.defineProperty(exports, 'TokenProcessor', {
2374
+ Object.defineProperty(exports, 'TokenResolver', {
2530
2375
  enumerable: true,
2531
2376
  get: function () {
2532
- return TokenProcessor;
2377
+ return TokenResolver;
2378
+ }
2379
+ });
2380
+ Object.defineProperty(exports, 'UnifiedStorage', {
2381
+ enumerable: true,
2382
+ get: function () {
2383
+ return UnifiedStorage;
2533
2384
  }
2534
2385
  });
2535
2386
  Object.defineProperty(exports, '_Container', {
@@ -2544,10 +2395,10 @@ Object.defineProperty(exports, 'asyncInject', {
2544
2395
  return asyncInject;
2545
2396
  }
2546
2397
  });
2547
- Object.defineProperty(exports, 'createRequestContext', {
2398
+ Object.defineProperty(exports, 'createAsyncLocalStorage', {
2548
2399
  enumerable: true,
2549
2400
  get: function () {
2550
- return createRequestContext;
2401
+ return createAsyncLocalStorage;
2551
2402
  }
2552
2403
  });
2553
2404
  Object.defineProperty(exports, 'defaultInjectors', {
@@ -2586,6 +2437,12 @@ Object.defineProperty(exports, 'inject', {
2586
2437
  return inject;
2587
2438
  }
2588
2439
  });
2440
+ Object.defineProperty(exports, 'isUsingNativeAsyncLocalStorage', {
2441
+ enumerable: true,
2442
+ get: function () {
2443
+ return isUsingNativeAsyncLocalStorage;
2444
+ }
2445
+ });
2589
2446
  Object.defineProperty(exports, 'optional', {
2590
2447
  enumerable: true,
2591
2448
  get: function () {
@@ -2616,4 +2473,4 @@ Object.defineProperty(exports, 'wrapSyncInit', {
2616
2473
  return wrapSyncInit;
2617
2474
  }
2618
2475
  });
2619
- //# sourceMappingURL=container-DENMeJ87.cjs.map
2476
+ //# sourceMappingURL=container-CaY2fDuk.cjs.map