@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
@@ -0,0 +1,306 @@
1
+ import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
2
+ import { FactoryInjectionToken } from "../../token/injection-token.mjs";
3
+ import { DIError, DIErrorCode } from "../../errors/di-error.mjs";
4
+ import { getCurrentResolutionContext, withResolutionContext } from "../context/resolution-context.mjs";
5
+ import { InstanceStatus } from "../holder/instance-holder.mjs";
6
+ import { CircularDetector } from "../lifecycle/circular-detector.mjs";
7
+
8
+ //#region src/internal/core/instance-resolver.mts
9
+ /**
10
+ * Resolves instances from tokens, handling caching, creation, and scope rules.
11
+ *
12
+ * Uses unified storage for both singleton and request-scoped services.
13
+ * Coordinates with ServiceInitializer for actual service creation.
14
+ * Integrates ScopeTracker for automatic scope upgrades.
15
+ */ var InstanceResolver = class {
16
+ registry;
17
+ storage;
18
+ serviceInitializer;
19
+ tokenResolver;
20
+ nameResolver;
21
+ scopeTracker;
22
+ serviceInvalidator;
23
+ eventBus;
24
+ logger;
25
+ constructor(registry, storage, serviceInitializer, tokenResolver, nameResolver, scopeTracker, serviceInvalidator, eventBus, logger = null) {
26
+ this.registry = registry;
27
+ this.storage = storage;
28
+ this.serviceInitializer = serviceInitializer;
29
+ this.tokenResolver = tokenResolver;
30
+ this.nameResolver = nameResolver;
31
+ this.scopeTracker = scopeTracker;
32
+ this.serviceInvalidator = serviceInvalidator;
33
+ this.eventBus = eventBus;
34
+ this.logger = logger;
35
+ }
36
+ /**
37
+ * Resolves an instance for the given token and arguments.
38
+ * This method is used for singleton and transient services.
39
+ *
40
+ * @param token The injection token
41
+ * @param args Optional arguments
42
+ * @param contextContainer The container to use for creating context
43
+ * @param requestStorage Optional request storage (for scope upgrades)
44
+ * @param requestId Optional request ID (for scope upgrades)
45
+ */ async resolveInstance(token, args, contextContainer, requestStorage, requestId) {
46
+ return this.resolveWithStorage(token, args, contextContainer, this.storage, void 0, requestStorage, requestId);
47
+ }
48
+ /**
49
+ * Resolves a request-scoped instance for a ScopedContainer.
50
+ * The service will be stored in the ScopedContainer's request storage.
51
+ *
52
+ * @param token The injection token
53
+ * @param args Optional arguments
54
+ * @param scopedContainer The ScopedContainer that owns the request context
55
+ */ async resolveRequestScopedInstance(token, args, scopedContainer) {
56
+ return this.resolveWithStorage(token, args, scopedContainer.getParent(), scopedContainer.getParent().getStorage(), scopedContainer, scopedContainer.getStorage(), scopedContainer.getRequestId());
57
+ }
58
+ /**
59
+ * Unified resolution method that works with any IHolderStorage.
60
+ * This eliminates duplication between singleton and request-scoped resolution.
61
+ *
62
+ * IMPORTANT: The check-and-store logic is carefully designed to avoid race conditions.
63
+ * The storage check and holder creation must happen synchronously (no awaits between).
64
+ *
65
+ * @param token The injection token
66
+ * @param args Optional arguments
67
+ * @param contextContainer The container for context
68
+ * @param storage The storage strategy to use
69
+ * @param scopedContainer Optional scoped container for request-scoped services
70
+ * @param requestStorage Optional request storage (for scope upgrades)
71
+ * @param requestId Optional request ID (for scope upgrades)
72
+ */ async resolveWithStorage(token, args, contextContainer, storage, scopedContainer, requestStorage, requestId) {
73
+ const [err, data] = await this.resolveTokenAndPrepareInstanceName(token, args, contextContainer, requestId, scopedContainer);
74
+ if (err) return [err];
75
+ const { instanceName, validatedArgs, realToken, scope } = data;
76
+ const getResult = storage.get(instanceName) ?? requestStorage?.get(instanceName) ?? null;
77
+ const getHolder = (name) => {
78
+ const result = storage.get(name);
79
+ if (result && result[0] === void 0 && result[1]) return result[1];
80
+ if (requestStorage) {
81
+ const reqResult = requestStorage.get(name);
82
+ if (reqResult && reqResult[0] === void 0 && reqResult[1]) return reqResult[1];
83
+ }
84
+ };
85
+ if (getResult !== null) {
86
+ const [error, holder$1] = getResult;
87
+ if (!error && holder$1) {
88
+ const waiterHolder = getCurrentResolutionContext()?.waiterHolder;
89
+ const readyResult = await this.waitForInstanceReady(holder$1, waiterHolder, getHolder);
90
+ if (readyResult[0]) return [readyResult[0]];
91
+ return [void 0, readyResult[1].instance];
92
+ }
93
+ if (error) {
94
+ const handledResult = await this.handleStorageError(instanceName, error, holder$1, storage);
95
+ if (handledResult) return handledResult;
96
+ }
97
+ }
98
+ const [createError, holder] = await this.createAndStoreInstance(instanceName, realToken, validatedArgs, contextContainer, storage, scopedContainer, requestStorage, requestId, scope);
99
+ if (createError) return [createError];
100
+ return [void 0, holder.instance];
101
+ }
102
+ /**
103
+ * Internal method to resolve token args and create instance name.
104
+ * Handles factory token resolution and validation.
105
+ */ async resolveTokenAndPrepareInstanceName(token, args, contextContainer, requestId, scopedContainer) {
106
+ const [err, { actualToken, validatedArgs }] = this.tokenResolver.validateAndResolveTokenArgs(token, args);
107
+ if (err instanceof DIError && err.code === DIErrorCode.TokenValidationError) return [err];
108
+ else if (err instanceof DIError && err.code === DIErrorCode.FactoryTokenNotResolved && actualToken instanceof FactoryInjectionToken) {
109
+ this.logger?.log(`[InstanceResolver]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`);
110
+ const factoryCtx = {
111
+ inject: async (t, a) => (scopedContainer ?? contextContainer).get(t, a),
112
+ container: scopedContainer ?? contextContainer,
113
+ addDestroyListener: () => {}
114
+ };
115
+ await actualToken.resolve(factoryCtx);
116
+ return this.resolveTokenAndPrepareInstanceName(token, void 0, contextContainer, requestId, scopedContainer);
117
+ }
118
+ const realToken = this.tokenResolver.getRealToken(actualToken);
119
+ const scope = this.registry.get(realToken).scope;
120
+ return [void 0, {
121
+ instanceName: this.nameResolver.generateInstanceName(actualToken, validatedArgs, requestId, scope),
122
+ validatedArgs,
123
+ actualToken,
124
+ realToken,
125
+ scope
126
+ }];
127
+ }
128
+ /**
129
+ * Handles storage error states (destroying, error, etc.).
130
+ * Returns a result if handled, null if should proceed with creation.
131
+ */ async handleStorageError(instanceName, error, holder, storage) {
132
+ switch (error.code) {
133
+ case DIErrorCode.InstanceDestroying:
134
+ this.logger?.log(`[InstanceResolver] Instance ${instanceName} is being destroyed, waiting...`);
135
+ if (holder?.destroyPromise) await holder.destroyPromise;
136
+ const newResult = storage.get(instanceName);
137
+ if (newResult !== null && !newResult[0]) {
138
+ const getHolder = (name) => {
139
+ const result = storage.get(name);
140
+ return result && result[0] === void 0 && result[1] ? result[1] : void 0;
141
+ };
142
+ const readyResult = await this.waitForInstanceReady(newResult[1], void 0, getHolder);
143
+ if (readyResult[0]) return [readyResult[0]];
144
+ return [void 0, readyResult[1].instance];
145
+ }
146
+ return null;
147
+ default:
148
+ if (holder) {
149
+ this.logger?.log(`[InstanceResolver] Removing failed instance ${instanceName} from storage to allow retry`);
150
+ storage.delete(instanceName);
151
+ }
152
+ return null;
153
+ }
154
+ }
155
+ /**
156
+ * Creates a new instance and stores it using the provided storage strategy.
157
+ * This unified method replaces instantiateServiceFromRegistry and createRequestScopedInstance.
158
+ *
159
+ * For transient services, the instance is created but not stored (no caching).
160
+ */ async createAndStoreInstance(instanceName, realToken, args, contextContainer, storage, scopedContainer, requestStorage, requestId, scope) {
161
+ this.logger?.log(`[InstanceResolver]#createAndStoreInstance() Creating instance for ${instanceName}`);
162
+ if (!this.registry.has(realToken)) return [DIError.factoryNotFound(realToken.name.toString())];
163
+ const record = this.registry.get(realToken);
164
+ const { type, scope: recordScope } = record;
165
+ const serviceScope = scope || recordScope;
166
+ if (serviceScope === InjectableScope.Transient) return this.createTransientInstance(instanceName, record, args, contextContainer, scopedContainer, requestStorage, requestId);
167
+ if (serviceScope === InjectableScope.Request && !requestStorage) return [DIError.initializationError(`Request storage is required for request-scoped services`, instanceName)];
168
+ let storageToUse;
169
+ if (serviceScope === InjectableScope.Request) storageToUse = requestStorage;
170
+ else storageToUse = storage;
171
+ const [deferred, holder] = storageToUse.createHolder(instanceName, type, /* @__PURE__ */ new Set());
172
+ storageToUse.set(instanceName, holder);
173
+ const ctx = this.createServiceInitializationContext(scopedContainer ?? contextContainer, instanceName, serviceScope, holder.deps, realToken, requestStorage, requestId);
174
+ holder.destroyListeners = ctx.getDestroyListeners();
175
+ const getHolder = (name) => {
176
+ const result = storage.get(name);
177
+ if (result && result[0] === void 0 && result[1]) return result[1];
178
+ if (requestStorage) {
179
+ const reqResult = requestStorage.get(name);
180
+ if (reqResult && reqResult[0] === void 0 && reqResult[1]) return reqResult[1];
181
+ }
182
+ };
183
+ withResolutionContext(holder, getHolder, () => {
184
+ this.serviceInitializer.instantiateService(ctx, record, args).then(async (result) => {
185
+ const [error, instance] = result.length === 2 ? result : [result[0], void 0];
186
+ const newScope = record.scope;
187
+ const newName = this.nameResolver.generateInstanceName(realToken, args, requestId, newScope);
188
+ await this.handleInstantiationResult(newName, holder, ctx, deferred, newScope, error, instance, scopedContainer, requestStorage, requestId);
189
+ }).catch(async (error) => {
190
+ const newScope = record.scope;
191
+ const newName = this.nameResolver.generateInstanceName(realToken, args, requestId, newScope);
192
+ await this.handleInstantiationError(newName, holder, deferred, newScope, error);
193
+ }).catch(() => {});
194
+ });
195
+ const waiterHolder = getCurrentResolutionContext()?.waiterHolder;
196
+ return this.waitForInstanceReady(holder, waiterHolder, getHolder);
197
+ }
198
+ /**
199
+ * Creates a transient instance without storage or locking.
200
+ * Each call creates a new instance.
201
+ */ async createTransientInstance(instanceName, record, args, contextContainer, scopedContainer, requestStorage, requestId) {
202
+ this.logger?.log(`[InstanceResolver]#createTransientInstance() Creating transient instance for ${instanceName}`);
203
+ const ctx = this.createServiceInitializationContext(scopedContainer ?? contextContainer, instanceName, InjectableScope.Transient, /* @__PURE__ */ new Set(), record.originalToken, requestStorage, requestId);
204
+ const [error, instance] = await this.serviceInitializer.instantiateService(ctx, record, args);
205
+ if (error) return [error];
206
+ return [void 0, {
207
+ status: InstanceStatus.Created,
208
+ name: instanceName,
209
+ instance,
210
+ creationPromise: null,
211
+ destroyPromise: null,
212
+ type: record.type,
213
+ scope: InjectableScope.Transient,
214
+ deps: ctx.dependencies,
215
+ destroyListeners: ctx.getDestroyListeners(),
216
+ createdAt: Date.now(),
217
+ waitingFor: /* @__PURE__ */ new Set()
218
+ }];
219
+ }
220
+ /**
221
+ * Handles successful service instantiation.
222
+ */ async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, _scopedContainer, requestStorage, _requestId) {
223
+ holder.instance = instance;
224
+ holder.status = InstanceStatus.Created;
225
+ const storageForSubscriptions = requestStorage || this.storage;
226
+ if (ctx.dependencies.size > 0) this.serviceInvalidator.setupDependencySubscriptions(instanceName, ctx.dependencies, storageForSubscriptions, holder);
227
+ this.logger?.log(`[InstanceResolver] Instance ${instanceName} created successfully`);
228
+ deferred.resolve([void 0, instance]);
229
+ }
230
+ /**
231
+ * Handles service instantiation errors.
232
+ */ async handleInstantiationError(instanceName, holder, deferred, scope, error) {
233
+ holder.status = InstanceStatus.Error;
234
+ holder.instance = error instanceof DIError ? error : DIError.unknown(error);
235
+ this.logger?.error(`[InstanceResolver] Instance ${instanceName} creation failed:`, error);
236
+ deferred.reject(error instanceof DIError ? error : DIError.unknown(error));
237
+ }
238
+ /**
239
+ * Handles instantiation result (success or error).
240
+ */ async handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer, requestStorage, requestId) {
241
+ if (error) await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
242
+ else await this.handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer, requestStorage, requestId);
243
+ }
244
+ /**
245
+ * Waits for an instance holder to be ready and returns the appropriate result.
246
+ *
247
+ * @param holder The holder to wait for
248
+ * @param waiterHolder Optional holder that is doing the waiting (for circular dependency detection)
249
+ * @param getHolder Optional function to retrieve holders by name (required if waiterHolder is provided)
250
+ */ async waitForInstanceReady(holder, waiterHolder, getHolder) {
251
+ switch (holder.status) {
252
+ case InstanceStatus.Creating:
253
+ if (waiterHolder && getHolder) {
254
+ const cycle = CircularDetector.detectCycle(waiterHolder.name, holder.name, getHolder);
255
+ if (cycle) return [DIError.circularDependency(cycle)];
256
+ waiterHolder.waitingFor.add(holder.name);
257
+ }
258
+ try {
259
+ await holder.creationPromise;
260
+ } finally {
261
+ if (waiterHolder) waiterHolder.waitingFor.delete(holder.name);
262
+ }
263
+ return this.waitForInstanceReady(holder, waiterHolder, getHolder);
264
+ case InstanceStatus.Destroying: return [DIError.instanceDestroying(holder.name)];
265
+ case InstanceStatus.Error: return [holder.instance];
266
+ case InstanceStatus.Created: return [void 0, holder];
267
+ default: return [DIError.instanceNotFound(holder?.name ?? "unknown")];
268
+ }
269
+ }
270
+ /**
271
+ * Creates a ServiceInitializationContext for service instantiation.
272
+ */ createServiceInitializationContext(container, serviceName, scope, deps, serviceToken, requestStorage, requestId) {
273
+ const destroyListeners = [];
274
+ return {
275
+ inject: async (token, args) => {
276
+ const actualToken = typeof token === "function" ? this.tokenResolver.normalizeToken(token) : token;
277
+ const realToken = this.tokenResolver.getRealToken(actualToken);
278
+ const depScope = this.registry.get(realToken).scope;
279
+ const dependencyRequestId = depScope === InjectableScope.Request ? requestId : void 0;
280
+ const finalDepName = this.nameResolver.generateInstanceName(actualToken, args, dependencyRequestId, depScope);
281
+ if (scope === InjectableScope.Singleton && depScope === InjectableScope.Request && requestStorage && requestId) {
282
+ const [needsUpgrade, newServiceName] = this.scopeTracker.checkAndUpgradeScope(serviceName, scope, finalDepName, depScope, serviceToken, this.storage, requestStorage, requestId);
283
+ if (needsUpgrade && newServiceName) {}
284
+ }
285
+ deps.add(finalDepName);
286
+ return container.get(token, args);
287
+ },
288
+ container,
289
+ addDestroyListener: (listener) => {
290
+ destroyListeners.push(listener);
291
+ },
292
+ getDestroyListeners: () => destroyListeners,
293
+ serviceName,
294
+ dependencies: deps,
295
+ scope,
296
+ trackDependency: (name, depScope) => {
297
+ deps.add(name);
298
+ if (scope === InjectableScope.Singleton && depScope === InjectableScope.Request && requestStorage && requestId) this.scopeTracker.checkAndUpgradeScope(serviceName, scope, name, depScope, serviceToken, this.storage, requestStorage, requestId);
299
+ }
300
+ };
301
+ }
302
+ };
303
+
304
+ //#endregion
305
+ export { InstanceResolver };
306
+ //# sourceMappingURL=instance-resolver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-resolver.mjs","names":["InjectableScope","DIError","DIErrorCode","FactoryInjectionToken","getCurrentResolutionContext","withResolutionContext","InstanceStatus","CircularDetector","InstanceResolver","registry","storage","serviceInitializer","tokenResolver","nameResolver","scopeTracker","serviceInvalidator","eventBus","logger","resolveInstance","token","args","contextContainer","requestStorage","requestId","resolveWithStorage","undefined","resolveRequestScopedInstance","scopedContainer","getParent","getStorage","getRequestId","err","data","resolveTokenAndPrepareInstanceName","instanceName","validatedArgs","realToken","scope","getResult","get","getHolder","name","result","reqResult","error","holder","resolutionCtx","waiterHolder","readyResult","waitForInstanceReady","instance","handledResult","handleStorageError","createError","createAndStoreInstance","actualToken","validateAndResolveTokenArgs","code","TokenValidationError","FactoryTokenNotResolved","log","factoryCtx","inject","t","a","container","addDestroyListener","resolve","getRealToken","record","generateInstanceName","InstanceDestroying","destroyPromise","newResult","delete","has","factoryNotFound","toString","type","recordScope","serviceScope","Transient","createTransientInstance","Request","initializationError","storageToUse","deferred","createHolder","Set","set","ctx","createServiceInitializationContext","deps","destroyListeners","getDestroyListeners","instantiateService","then","length","newScope","newName","handleInstantiationResult","catch","handleInstantiationError","originalToken","tempHolder","status","Created","creationPromise","dependencies","createdAt","Date","now","waitingFor","handleInstantiationSuccess","_scopedContainer","_requestId","storageForSubscriptions","size","setupDependencySubscriptions","Error","unknown","reject","Creating","cycle","detectCycle","circularDependency","process","env","NODE_ENV","add","Destroying","instanceDestroying","instanceNotFound","serviceName","serviceToken","normalizeToken","depRecord","depScope","dependencyRequestId","finalDepName","Singleton","needsUpgrade","newServiceName","checkAndUpgradeScope","listener","push","trackDependency"],"sources":["../../../../src/internal/core/instance-resolver.mts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { ScopedContainer } from '../../container/scoped-container.mjs'\nimport type { IContainer } from '../../interfaces/container.interface.mjs'\nimport type {\n AnyInjectableType,\n InjectionTokenType,\n} from '../../token/injection-token.mjs'\nimport type { Registry } from '../../token/registry.mjs'\nimport type { ServiceInitializationContext } from '../context/service-initialization-context.mjs'\nimport type { IHolderStorage } from '../holder/holder-storage.interface.mjs'\nimport type { InstanceHolder } from '../holder/instance-holder.mjs'\nimport type { LifecycleEventBus } from '../lifecycle/lifecycle-event-bus.mjs'\n\nimport { InjectableScope } from '../../enums/index.mjs'\nimport { DIError, DIErrorCode } from '../../errors/index.mjs'\nimport {\n BoundInjectionToken,\n FactoryInjectionToken,\n InjectionToken,\n} from '../../token/injection-token.mjs'\nimport {\n getCurrentResolutionContext,\n withResolutionContext,\n} from '../context/resolution-context.mjs'\nimport { InstanceStatus } from '../holder/instance-holder.mjs'\nimport { CircularDetector } from '../lifecycle/circular-detector.mjs'\nimport { NameResolver } from './name-resolver.mjs'\nimport { ScopeTracker } from './scope-tracker.mjs'\nimport { ServiceInitializer } from './service-initializer.mjs'\nimport { ServiceInvalidator } from './service-invalidator.mjs'\nimport { TokenResolver } from './token-resolver.mjs'\n\n/**\n * Resolves instances from tokens, handling caching, creation, and scope rules.\n *\n * Uses unified storage for both singleton and request-scoped services.\n * Coordinates with ServiceInitializer for actual service creation.\n * Integrates ScopeTracker for automatic scope upgrades.\n */\nexport class InstanceResolver {\n constructor(\n private readonly registry: Registry,\n private readonly storage: IHolderStorage,\n private readonly serviceInitializer: ServiceInitializer,\n private readonly tokenResolver: TokenResolver,\n private readonly nameResolver: NameResolver,\n private readonly scopeTracker: ScopeTracker,\n private readonly serviceInvalidator: ServiceInvalidator,\n private readonly eventBus: LifecycleEventBus,\n private readonly logger: Console | null = null,\n ) {}\n\n // ============================================================================\n // PUBLIC RESOLUTION METHODS\n // ============================================================================\n\n /**\n * Resolves an instance for the given token and arguments.\n * This method is used for singleton and transient services.\n *\n * @param token The injection token\n * @param args Optional arguments\n * @param contextContainer The container to use for creating context\n * @param requestStorage Optional request storage (for scope upgrades)\n * @param requestId Optional request ID (for scope upgrades)\n */\n async resolveInstance(\n token: AnyInjectableType,\n args: any,\n contextContainer: IContainer,\n requestStorage?: IHolderStorage,\n requestId?: string,\n ): Promise<[undefined, any] | [DIError]> {\n return this.resolveWithStorage(\n token,\n args,\n contextContainer,\n this.storage,\n undefined,\n requestStorage,\n requestId,\n )\n }\n\n /**\n * Resolves a request-scoped instance for a ScopedContainer.\n * The service will be stored in the ScopedContainer's request storage.\n *\n * @param token The injection token\n * @param args Optional arguments\n * @param scopedContainer The ScopedContainer that owns the request context\n */\n async resolveRequestScopedInstance(\n token: AnyInjectableType,\n args: any,\n scopedContainer: ScopedContainer,\n ): Promise<[undefined, any] | [DIError]> {\n return this.resolveWithStorage(\n token,\n args,\n scopedContainer.getParent(),\n scopedContainer.getParent().getStorage(),\n scopedContainer,\n scopedContainer.getStorage(),\n scopedContainer.getRequestId(),\n )\n }\n\n // ============================================================================\n // UNIFIED RESOLUTION (Storage Strategy Pattern)\n // ============================================================================\n\n /**\n * Unified resolution method that works with any IHolderStorage.\n * This eliminates duplication between singleton and request-scoped resolution.\n *\n * IMPORTANT: The check-and-store logic is carefully designed to avoid race conditions.\n * The storage check and holder creation must happen synchronously (no awaits between).\n *\n * @param token The injection token\n * @param args Optional arguments\n * @param contextContainer The container for context\n * @param storage The storage strategy to use\n * @param scopedContainer Optional scoped container for request-scoped services\n * @param requestStorage Optional request storage (for scope upgrades)\n * @param requestId Optional request ID (for scope upgrades)\n */\n private async resolveWithStorage(\n token: AnyInjectableType,\n args: any,\n contextContainer: IContainer,\n storage: IHolderStorage,\n scopedContainer?: ScopedContainer,\n requestStorage?: IHolderStorage,\n requestId?: string,\n ): Promise<[undefined, any] | [DIError]> {\n // Step 1: Resolve token and prepare instance name\n const [err, data] = await this.resolveTokenAndPrepareInstanceName(\n token,\n args,\n contextContainer,\n requestId,\n scopedContainer,\n )\n if (err) {\n return [err]\n }\n\n const { instanceName, validatedArgs, realToken, scope } = data!\n\n // Step 2: Check for existing holder SYNCHRONOUSLY (no await between check and store)\n // This is critical for preventing race conditions with concurrent resolution\n const getResult =\n storage.get(instanceName) ?? requestStorage?.get(instanceName) ?? null\n\n // Create getHolder function for circular dependency detection\n const getHolder = (name: string): InstanceHolder | undefined => {\n // Check both storages\n const result = storage.get(name)\n if (result && result[0] === undefined && result[1]) {\n return result[1]\n }\n if (requestStorage) {\n const reqResult = requestStorage.get(name)\n if (reqResult && reqResult[0] === undefined && reqResult[1]) {\n return reqResult[1]\n }\n }\n return undefined\n }\n\n if (getResult !== null) {\n const [error, holder] = getResult\n if (!error && holder) {\n // Found existing holder - wait for it to be ready\n // Try to get waiterHolder from resolution context if available\n const resolutionCtx = getCurrentResolutionContext()\n const waiterHolder = resolutionCtx?.waiterHolder\n const readyResult = await this.waitForInstanceReady(\n holder,\n waiterHolder,\n getHolder,\n )\n if (readyResult[0]) {\n return [readyResult[0]]\n }\n return [undefined, readyResult[1]!.instance]\n }\n // Handle error states (destroying, etc.)\n if (error) {\n const handledResult = await this.handleStorageError(\n instanceName,\n error,\n holder,\n storage,\n )\n if (handledResult) {\n return handledResult\n }\n }\n }\n\n // Step 3: Create new instance and store it\n // NOTE: Holder is stored synchronously inside createAndStoreInstance before any await\n const [createError, holder] = await this.createAndStoreInstance(\n instanceName,\n realToken,\n validatedArgs,\n contextContainer,\n storage,\n scopedContainer,\n requestStorage,\n requestId,\n scope,\n )\n if (createError) {\n return [createError]\n }\n\n return [undefined, holder!.instance]\n }\n\n /**\n * Internal method to resolve token args and create instance name.\n * Handles factory token resolution and validation.\n */\n private async resolveTokenAndPrepareInstanceName(\n token: AnyInjectableType,\n args: any,\n contextContainer: IContainer,\n requestId?: string,\n scopedContainer?: ScopedContainer,\n ): Promise<\n | [\n undefined,\n {\n instanceName: string\n validatedArgs: any\n actualToken: InjectionTokenType\n realToken: InjectionToken<any, any>\n scope: InjectableScope\n },\n ]\n | [DIError]\n > {\n const [err, { actualToken, validatedArgs }] =\n this.tokenResolver.validateAndResolveTokenArgs(token, args)\n if (\n err instanceof DIError &&\n err.code === DIErrorCode.TokenValidationError\n ) {\n return [err]\n } else if (\n err instanceof DIError &&\n err.code === DIErrorCode.FactoryTokenNotResolved &&\n actualToken instanceof FactoryInjectionToken\n ) {\n this.logger?.log(\n `[InstanceResolver]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`,\n )\n // Create a simple factory context for resolving the factory token\n const factoryCtx = {\n inject: async (t: any, a?: any) =>\n (scopedContainer ?? contextContainer).get(t, a),\n container: scopedContainer ?? contextContainer,\n addDestroyListener: () => {},\n }\n await actualToken.resolve(factoryCtx as any)\n return this.resolveTokenAndPrepareInstanceName(\n token,\n undefined,\n contextContainer,\n requestId,\n scopedContainer,\n )\n }\n\n // Get the real token for registry lookup\n const realToken = this.tokenResolver.getRealToken(actualToken)\n // Get scope from registry\n const record = this.registry.get(realToken)\n const scope = record.scope\n\n // Generate instance name with requestId if needed\n const instanceName = this.nameResolver.generateInstanceName(\n actualToken,\n validatedArgs,\n requestId,\n scope,\n )\n\n return [\n undefined,\n { instanceName, validatedArgs, actualToken, realToken, scope },\n ]\n }\n\n /**\n * Handles storage error states (destroying, error, etc.).\n * Returns a result if handled, null if should proceed with creation.\n */\n private async handleStorageError(\n instanceName: string,\n error: DIError,\n holder: InstanceHolder | undefined,\n storage: IHolderStorage,\n ): Promise<[undefined, any] | [DIError] | null> {\n switch (error.code) {\n case DIErrorCode.InstanceDestroying:\n // Wait for destruction then retry\n this.logger?.log(\n `[InstanceResolver] Instance ${instanceName} is being destroyed, waiting...`,\n )\n if (holder?.destroyPromise) {\n await holder.destroyPromise\n }\n // Re-check after destruction\n const newResult = storage.get(instanceName)\n if (newResult !== null && !newResult[0]) {\n // Create getHolder for circular dependency detection\n const getHolder = (name: string): InstanceHolder | undefined => {\n const result = storage.get(name)\n return result && result[0] === undefined && result[1]\n ? result[1]\n : undefined\n }\n const readyResult = await this.waitForInstanceReady(\n newResult[1]!,\n undefined,\n getHolder,\n )\n if (readyResult[0]) {\n return [readyResult[0]]\n }\n return [undefined, readyResult[1]!.instance]\n }\n return null // Proceed with creation\n\n default:\n // For error states, remove the failed holder from storage so we can retry\n if (holder) {\n this.logger?.log(\n `[InstanceResolver] Removing failed instance ${instanceName} from storage to allow retry`,\n )\n storage.delete(instanceName)\n }\n return null // Proceed with creation\n }\n }\n\n /**\n * Creates a new instance and stores it using the provided storage strategy.\n * This unified method replaces instantiateServiceFromRegistry and createRequestScopedInstance.\n *\n * For transient services, the instance is created but not stored (no caching).\n */\n private async createAndStoreInstance<Instance>(\n instanceName: string,\n realToken: InjectionToken<Instance, any>,\n args: any,\n contextContainer: IContainer,\n storage: IHolderStorage,\n scopedContainer?: ScopedContainer,\n requestStorage?: IHolderStorage,\n requestId?: string,\n scope?: InjectableScope,\n ): Promise<[undefined, InstanceHolder<Instance>] | [DIError]> {\n this.logger?.log(\n `[InstanceResolver]#createAndStoreInstance() Creating instance for ${instanceName}`,\n )\n\n if (!this.registry.has(realToken)) {\n return [DIError.factoryNotFound(realToken.name.toString())]\n }\n\n const record = this.registry.get<Instance, any>(realToken)\n const { type, scope: recordScope } = record\n const serviceScope = scope || recordScope\n\n // For transient services, don't use storage locking - create directly\n if (serviceScope === InjectableScope.Transient) {\n return this.createTransientInstance(\n instanceName,\n record,\n args,\n contextContainer,\n scopedContainer,\n requestStorage,\n requestId,\n )\n }\n if (serviceScope === InjectableScope.Request && !requestStorage) {\n return [\n DIError.initializationError(\n `Request storage is required for request-scoped services`,\n instanceName,\n ),\n ]\n }\n\n let storageToUse: IHolderStorage\n if (serviceScope === InjectableScope.Request) {\n storageToUse = requestStorage!\n } else {\n storageToUse = storage\n }\n\n // Create holder in \"Creating\" state\n const [deferred, holder] = storageToUse.createHolder<Instance>(\n instanceName,\n type,\n new Set(),\n )\n // Store holder immediately (for lock mechanism)\n storageToUse.set(instanceName, holder)\n\n // Create context for service initialization\n const ctx = this.createServiceInitializationContext(\n scopedContainer ?? contextContainer,\n instanceName,\n serviceScope,\n holder.deps,\n realToken,\n requestStorage,\n requestId,\n )\n\n holder.destroyListeners = ctx.getDestroyListeners()\n\n // Create getHolder function for resolution context\n const getHolder = (name: string): InstanceHolder | undefined => {\n // Check both storages\n const result = storage.get(name)\n if (result && result[0] === undefined && result[1]) {\n return result[1]\n }\n if (requestStorage) {\n const reqResult = requestStorage.get(name)\n if (reqResult && reqResult[0] === undefined && reqResult[1]) {\n return reqResult[1]\n }\n }\n return undefined\n }\n\n // Start async instantiation within resolution context for circular dependency detection\n withResolutionContext(holder, getHolder, () => {\n this.serviceInitializer\n .instantiateService(ctx, record, args)\n .then(async (result: [undefined, Instance] | [DIError]) => {\n const [error, instance] =\n result.length === 2 ? result : [result[0], undefined]\n const newScope = record.scope\n const newName = this.nameResolver.generateInstanceName(\n realToken,\n args,\n requestId,\n newScope,\n )\n await this.handleInstantiationResult(\n newName,\n holder,\n ctx,\n deferred,\n newScope,\n error,\n instance,\n scopedContainer,\n requestStorage,\n requestId,\n )\n })\n .catch(async (error: Error) => {\n const newScope = record.scope\n const newName = this.nameResolver.generateInstanceName(\n realToken,\n args,\n requestId,\n newScope,\n )\n\n await this.handleInstantiationError(\n newName,\n holder,\n deferred,\n newScope,\n error,\n )\n })\n .catch(() => {\n // Suppress unhandled rejections from the async chain.\n // Errors are communicated to awaiters via deferred.reject() which\n // rejects holder.creationPromise. This catch is a safety net for\n // any errors that might occur in the error handling itself.\n })\n })\n\n // Wait for instance to be ready\n // Use resolution context to get waiterHolder if available\n const resolutionCtx = getCurrentResolutionContext()\n const waiterHolder = resolutionCtx?.waiterHolder\n return this.waitForInstanceReady(holder, waiterHolder, getHolder)\n }\n\n /**\n * Creates a transient instance without storage or locking.\n * Each call creates a new instance.\n */\n private async createTransientInstance<Instance>(\n instanceName: string,\n record: any,\n args: any,\n contextContainer: IContainer,\n scopedContainer?: ScopedContainer,\n requestStorage?: IHolderStorage,\n requestId?: string,\n ): Promise<[undefined, InstanceHolder<Instance>] | [DIError]> {\n this.logger?.log(\n `[InstanceResolver]#createTransientInstance() Creating transient instance for ${instanceName}`,\n )\n\n // Create a temporary holder for resolution context (transient instances can still have deps)\n const ctx = this.createServiceInitializationContext(\n scopedContainer ?? contextContainer,\n instanceName,\n InjectableScope.Transient,\n new Set(),\n record.originalToken,\n requestStorage,\n requestId,\n )\n\n const [error, instance] = await this.serviceInitializer.instantiateService(\n ctx,\n record,\n args,\n )\n\n if (error) {\n return [error]\n }\n\n // Create a temporary holder for the result\n const tempHolder: InstanceHolder<Instance> = {\n status: InstanceStatus.Created,\n name: instanceName,\n instance: instance as Instance,\n creationPromise: null,\n destroyPromise: null,\n type: record.type,\n scope: InjectableScope.Transient,\n deps: ctx.dependencies,\n destroyListeners: ctx.getDestroyListeners(),\n createdAt: Date.now(),\n waitingFor: new Set(),\n }\n\n return [undefined, tempHolder]\n }\n\n /**\n * Handles successful service instantiation.\n */\n private async handleInstantiationSuccess(\n instanceName: string,\n holder: InstanceHolder<any>,\n ctx: ServiceInitializationContext,\n deferred: any,\n instance: any,\n _scopedContainer?: ScopedContainer,\n requestStorage?: IHolderStorage,\n _requestId?: string,\n ): Promise<void> {\n holder.instance = instance\n holder.status = InstanceStatus.Created\n\n // Set up dependency subscriptions for event-based invalidation\n // Determine which storage to use for subscriptions\n const storageForSubscriptions = requestStorage || this.storage\n\n // Set up subscriptions via ServiceInvalidator\n if (ctx.dependencies.size > 0) {\n this.serviceInvalidator.setupDependencySubscriptions(\n instanceName,\n ctx.dependencies,\n storageForSubscriptions,\n holder,\n )\n }\n\n this.logger?.log(\n `[InstanceResolver] Instance ${instanceName} created successfully`,\n )\n deferred.resolve([undefined, instance])\n }\n\n /**\n * Handles service instantiation errors.\n */\n private async handleInstantiationError(\n instanceName: string,\n holder: InstanceHolder<any>,\n deferred: any,\n scope: InjectableScope,\n error: any,\n ): Promise<void> {\n holder.status = InstanceStatus.Error\n holder.instance = error instanceof DIError ? error : DIError.unknown(error)\n this.logger?.error(\n `[InstanceResolver] Instance ${instanceName} creation failed:`,\n error,\n )\n deferred.reject(error instanceof DIError ? error : DIError.unknown(error))\n }\n\n /**\n * Handles instantiation result (success or error).\n */\n private async handleInstantiationResult(\n instanceName: string,\n holder: InstanceHolder<any>,\n ctx: ServiceInitializationContext,\n deferred: any,\n scope: InjectableScope,\n error: any,\n instance: any,\n scopedContainer?: ScopedContainer,\n requestStorage?: IHolderStorage,\n requestId?: string,\n ): Promise<void> {\n if (error) {\n await this.handleInstantiationError(\n instanceName,\n holder,\n deferred,\n scope,\n error,\n )\n } else {\n await this.handleInstantiationSuccess(\n instanceName,\n holder,\n ctx,\n deferred,\n instance,\n scopedContainer,\n requestStorage,\n requestId,\n )\n }\n }\n\n /**\n * Waits for an instance holder to be ready and returns the appropriate result.\n *\n * @param holder The holder to wait for\n * @param waiterHolder Optional holder that is doing the waiting (for circular dependency detection)\n * @param getHolder Optional function to retrieve holders by name (required if waiterHolder is provided)\n */\n private async waitForInstanceReady<T>(\n holder: InstanceHolder<T>,\n waiterHolder?: InstanceHolder,\n getHolder?: (name: string) => InstanceHolder | undefined,\n ): Promise<[undefined, InstanceHolder<T>] | [DIError]> {\n switch (holder.status) {\n case InstanceStatus.Creating: {\n // Check for circular dependency before waiting\n if (waiterHolder && getHolder) {\n const cycle = CircularDetector.detectCycle(\n waiterHolder.name,\n holder.name,\n getHolder,\n )\n if (cycle) {\n return [DIError.circularDependency(cycle)]\n }\n\n if (process.env.NODE_ENV !== 'production') {\n // Track the waiting relationship\n waiterHolder.waitingFor.add(holder.name)\n }\n }\n\n try {\n await holder.creationPromise\n } finally {\n if (process.env.NODE_ENV !== 'production') {\n // Clean up the waiting relationship\n if (waiterHolder) {\n waiterHolder.waitingFor.delete(holder.name)\n }\n }\n }\n\n // Recursively check after creation completes\n return this.waitForInstanceReady(holder, waiterHolder, getHolder)\n }\n\n case InstanceStatus.Destroying:\n return [DIError.instanceDestroying(holder.name)]\n\n case InstanceStatus.Error:\n return [holder.instance as unknown as DIError]\n\n case InstanceStatus.Created:\n return [undefined, holder]\n\n default:\n // @ts-expect-error Maybe we will use this in the future\n return [DIError.instanceNotFound(holder?.name ?? 'unknown')]\n }\n }\n\n /**\n * Creates a ServiceInitializationContext for service instantiation.\n */\n private createServiceInitializationContext(\n container: IContainer,\n serviceName: string,\n scope: InjectableScope,\n deps: Set<string>,\n serviceToken: InjectionToken<any, any>,\n requestStorage?: IHolderStorage,\n requestId?: string,\n ): ServiceInitializationContext {\n const destroyListeners: Array<() => void> = []\n\n return {\n inject: async (token: any, args?: any) => {\n // Track dependency and check for scope upgrade\n const actualToken =\n typeof token === 'function'\n ? this.tokenResolver.normalizeToken(token)\n : token\n const realToken = this.tokenResolver.getRealToken(actualToken)\n const depRecord = this.registry.get(realToken)\n const depScope = depRecord.scope\n\n // Generate dependency name - if dependency is Request-scoped and we have requestId, use it\n const dependencyRequestId =\n depScope === InjectableScope.Request ? requestId : undefined\n const finalDepName = this.nameResolver.generateInstanceName(\n actualToken,\n args,\n dependencyRequestId,\n depScope,\n )\n\n // Check if current service needs scope upgrade\n // If current service is Singleton and dependency is Request, upgrade current service\n if (\n scope === InjectableScope.Singleton &&\n depScope === InjectableScope.Request &&\n requestStorage &&\n requestId\n ) {\n // Check and perform scope upgrade for current service\n // Use the dependency name with requestId for the check\n const [needsUpgrade, newServiceName] =\n this.scopeTracker.checkAndUpgradeScope(\n serviceName,\n scope,\n finalDepName,\n depScope,\n serviceToken,\n this.storage,\n requestStorage,\n requestId,\n )\n\n if (needsUpgrade && newServiceName) {\n // Service was upgraded - update the service name in context\n // The holder will be moved to request storage by ScopeTracker\n // For now, we continue with the current resolution\n // Future resolutions will use the new name\n }\n }\n\n // Track dependency\n deps.add(finalDepName)\n\n // Resolve dependency\n // Resolution context is automatically used by the injectors system for circular dependency detection\n return container.get(token, args)\n },\n container,\n addDestroyListener: (listener: () => void) => {\n destroyListeners.push(listener)\n },\n getDestroyListeners: () => destroyListeners,\n serviceName,\n dependencies: deps,\n scope,\n trackDependency: (name: string, depScope: InjectableScope) => {\n deps.add(name)\n // Check for scope upgrade\n if (\n scope === InjectableScope.Singleton &&\n depScope === InjectableScope.Request &&\n requestStorage &&\n requestId\n ) {\n this.scopeTracker.checkAndUpgradeScope(\n serviceName,\n scope,\n name,\n depScope,\n serviceToken,\n this.storage,\n requestStorage,\n requestId,\n )\n }\n },\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { InjectionTokenType } from "../../token/injection-token.mjs";
2
+ import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
3
+
4
+ //#region src/internal/core/name-resolver.d.mts
5
+
6
+ /**
7
+ * Handles instance name generation with support for requestId and scope.
8
+ *
9
+ * Generates unique instance identifiers based on token, arguments, and scope.
10
+ * Request-scoped services MUST include requestId in their name for proper isolation.
11
+ */
12
+ declare class NameResolver {
13
+ private readonly logger;
14
+ private readonly instanceNameCache;
15
+ constructor(logger?: Console | null);
16
+ /**
17
+ * Generates a unique instance name based on token, arguments, requestId, and scope.
18
+ *
19
+ * Name formats:
20
+ * - Singleton/Transient without args: `${tokenId}`
21
+ * - Singleton/Transient with args: `${tokenId}:${argsHash}`
22
+ * - Request without args: `${tokenId}:requestId=${requestId}`
23
+ * - Request with args: `${tokenId}:requestId=${requestId}:${argsHash}`
24
+ *
25
+ * @param token The injection token
26
+ * @param args Optional arguments
27
+ * @param requestId Optional request ID (required for request-scoped services)
28
+ * @param scope Optional scope (used to determine if requestId should be included)
29
+ * @returns The generated instance name
30
+ */
31
+ generateInstanceName(token: InjectionTokenType, args?: any, requestId?: string, scope?: InjectableScope): string;
32
+ /**
33
+ * Upgrades an existing instance name to include requestId.
34
+ * Preserves any args hash that might already be in the name.
35
+ *
36
+ * Examples:
37
+ * - `TokenName` → `TokenName:requestId=req-123`
38
+ * - `TokenName:abc123` → `TokenName:requestId=req-123:abc123`
39
+ *
40
+ * @param existingName The existing instance name (without requestId)
41
+ * @param requestId The request ID to add
42
+ * @returns The upgraded instance name with requestId
43
+ */
44
+ upgradeInstanceNameToRequest(existingName: string, requestId: string): string;
45
+ /**
46
+ * Formats a single argument value for instance name generation.
47
+ */
48
+ formatArgValue(value: any): string;
49
+ }
50
+ //#endregion
51
+ export { NameResolver };
52
+ //# sourceMappingURL=name-resolver.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-resolver.d.mts","names":[],"sources":["../../../../src/internal/core/name-resolver.mts"],"sourcesContent":[],"mappings":";;;;;;;AAgEA;;;;AAwB2B,cAxBd,YAAA,CAwBc;;;uBArBY;;;;;;;;;;;;;;;;8BAkB5B,4DAGC"}
@@ -0,0 +1,118 @@
1
+ import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
2
+
3
+ //#region src/internal/core/name-resolver.mts
4
+ /**
5
+ * Simple LRU cache for instance name generation.
6
+ * Uses a Map which maintains insertion order for efficient LRU eviction.
7
+ */ var InstanceNameCache = class {
8
+ cache = /* @__PURE__ */ new Map();
9
+ maxSize;
10
+ constructor(maxSize = 1e3) {
11
+ this.maxSize = maxSize;
12
+ }
13
+ get(key) {
14
+ const value = this.cache.get(key);
15
+ if (value !== void 0) {
16
+ this.cache.delete(key);
17
+ this.cache.set(key, value);
18
+ }
19
+ return value;
20
+ }
21
+ set(key, value) {
22
+ if (this.cache.has(key)) this.cache.delete(key);
23
+ else if (this.cache.size >= this.maxSize) {
24
+ const firstKey = this.cache.keys().next().value;
25
+ if (firstKey !== void 0) this.cache.delete(firstKey);
26
+ }
27
+ this.cache.set(key, value);
28
+ }
29
+ clear() {
30
+ this.cache.clear();
31
+ }
32
+ };
33
+ /**
34
+ * Simple hash function for deterministic hashing of arguments
35
+ */ function hashArgs(args) {
36
+ const str = JSON.stringify(args, Object.keys(args || {}).sort());
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
+ * Handles instance name generation with support for requestId and scope.
47
+ *
48
+ * Generates unique instance identifiers based on token, arguments, and scope.
49
+ * Request-scoped services MUST include requestId in their name for proper isolation.
50
+ */ var NameResolver = class {
51
+ logger;
52
+ instanceNameCache = new InstanceNameCache();
53
+ constructor(logger = null) {
54
+ this.logger = logger;
55
+ }
56
+ /**
57
+ * Generates a unique instance name based on token, arguments, requestId, and scope.
58
+ *
59
+ * Name formats:
60
+ * - Singleton/Transient without args: `${tokenId}`
61
+ * - Singleton/Transient with args: `${tokenId}:${argsHash}`
62
+ * - Request without args: `${tokenId}:requestId=${requestId}`
63
+ * - Request with args: `${tokenId}:requestId=${requestId}:${argsHash}`
64
+ *
65
+ * @param token The injection token
66
+ * @param args Optional arguments
67
+ * @param requestId Optional request ID (required for request-scoped services)
68
+ * @param scope Optional scope (used to determine if requestId should be included)
69
+ * @returns The generated instance name
70
+ */ generateInstanceName(token, args, requestId, scope) {
71
+ const tokenStr = token.toString();
72
+ const isRequest = scope === InjectableScope.Request;
73
+ if (isRequest && !requestId) throw new Error(`[NameResolver] requestId is required for request-scoped services`);
74
+ const cacheKey = `${tokenStr}:${scope}:${requestId || ""}:${args ? JSON.stringify(args) : ""}`;
75
+ const cached = this.instanceNameCache.get(cacheKey);
76
+ if (cached !== void 0) return cached;
77
+ let result = tokenStr;
78
+ if (isRequest && requestId) result = `${result}:requestId=${requestId}`;
79
+ if (args) {
80
+ const argsHash = hashArgs(args);
81
+ result = `${result}:${argsHash}`;
82
+ }
83
+ this.instanceNameCache.set(cacheKey, result);
84
+ return result;
85
+ }
86
+ /**
87
+ * Upgrades an existing instance name to include requestId.
88
+ * Preserves any args hash that might already be in the name.
89
+ *
90
+ * Examples:
91
+ * - `TokenName` → `TokenName:requestId=req-123`
92
+ * - `TokenName:abc123` → `TokenName:requestId=req-123:abc123`
93
+ *
94
+ * @param existingName The existing instance name (without requestId)
95
+ * @param requestId The request ID to add
96
+ * @returns The upgraded instance name with requestId
97
+ */ upgradeInstanceNameToRequest(existingName, requestId) {
98
+ if (existingName.includes(`:requestId=${requestId}`)) return existingName;
99
+ if (/:requestId=/.test(existingName)) return existingName;
100
+ const colonIndex = existingName.indexOf(":");
101
+ if (colonIndex === -1) return `${existingName}:requestId=${requestId}`;
102
+ const tokenPart = existingName.substring(0, colonIndex);
103
+ const argsPart = existingName.substring(colonIndex + 1);
104
+ if (argsPart.startsWith("requestId=")) return existingName;
105
+ return `${tokenPart}:requestId=${requestId}:${argsPart}`;
106
+ }
107
+ /**
108
+ * Formats a single argument value for instance name generation.
109
+ */ formatArgValue(value) {
110
+ if (typeof value === "function") return `fn_${value.name}(${value.length})`;
111
+ if (typeof value === "symbol") return value.toString();
112
+ return JSON.stringify(value).slice(0, 40);
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ export { NameResolver };
118
+ //# sourceMappingURL=name-resolver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-resolver.mjs","names":["InjectableScope","InstanceNameCache","cache","Map","maxSize","get","key","value","undefined","delete","set","has","size","firstKey","keys","next","clear","hashArgs","args","str","JSON","stringify","Object","sort","hash","i","length","char","charCodeAt","Math","abs","toString","NameResolver","instanceNameCache","logger","generateInstanceName","token","requestId","scope","tokenStr","isRequest","Request","Error","cacheKey","cached","result","argsHash","upgradeInstanceNameToRequest","existingName","includes","requestIdPattern","hasRequestId","test","colonIndex","indexOf","tokenPart","substring","argsPart","startsWith","formatArgValue","name","slice"],"sources":["../../../../src/internal/core/name-resolver.mts"],"sourcesContent":["import type { InjectionTokenType } from '../../token/injection-token.mjs'\n\nimport { InjectableScope } from '../../enums/index.mjs'\n\n/**\n * Simple LRU cache for instance name generation.\n * Uses a Map which maintains insertion order for efficient LRU eviction.\n */\nclass InstanceNameCache {\n private readonly cache = new Map<string, string>()\n private readonly maxSize: number\n\n constructor(maxSize = 1000) {\n this.maxSize = maxSize\n }\n\n get(key: string): string | undefined {\n const value = this.cache.get(key)\n if (value !== undefined) {\n // Move to end (most recently used)\n this.cache.delete(key)\n this.cache.set(key, value)\n }\n return value\n }\n\n set(key: string, value: string): void {\n if (this.cache.has(key)) {\n this.cache.delete(key)\n } else if (this.cache.size >= this.maxSize) {\n // Remove least recently used (first item)\n const firstKey = this.cache.keys().next().value\n if (firstKey !== undefined) {\n this.cache.delete(firstKey)\n }\n }\n this.cache.set(key, value)\n }\n\n clear(): void {\n this.cache.clear()\n }\n}\n\n/**\n * Simple hash function for deterministic hashing of arguments\n */\nfunction hashArgs(args: any): string {\n const str = JSON.stringify(args, Object.keys(args || {}).sort())\n let hash = 0\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash = hash & hash // Convert to 32-bit integer\n }\n return Math.abs(hash).toString(36)\n}\n\n/**\n * Handles instance name generation with support for requestId and scope.\n *\n * Generates unique instance identifiers based on token, arguments, and scope.\n * Request-scoped services MUST include requestId in their name for proper isolation.\n */\nexport class NameResolver {\n private readonly instanceNameCache = new InstanceNameCache()\n\n constructor(private readonly logger: Console | null = null) {}\n\n /**\n * Generates a unique instance name based on token, arguments, requestId, and scope.\n *\n * Name formats:\n * - Singleton/Transient without args: `${tokenId}`\n * - Singleton/Transient with args: `${tokenId}:${argsHash}`\n * - Request without args: `${tokenId}:requestId=${requestId}`\n * - Request with args: `${tokenId}:requestId=${requestId}:${argsHash}`\n *\n * @param token The injection token\n * @param args Optional arguments\n * @param requestId Optional request ID (required for request-scoped services)\n * @param scope Optional scope (used to determine if requestId should be included)\n * @returns The generated instance name\n */\n generateInstanceName(\n token: InjectionTokenType,\n args?: any,\n requestId?: string,\n scope?: InjectableScope,\n ): string {\n const tokenStr = token.toString()\n const isRequest = scope === InjectableScope.Request\n\n // For request-scoped services, requestId is required\n if (isRequest && !requestId) {\n throw new Error(\n `[NameResolver] requestId is required for request-scoped services`,\n )\n }\n\n // Build cache key\n const cacheKey = `${tokenStr}:${scope}:${requestId || ''}:${args ? JSON.stringify(args) : ''}`\n\n // Check cache first\n const cached = this.instanceNameCache.get(cacheKey)\n if (cached !== undefined) {\n return cached\n }\n\n // Generate the instance name\n let result = tokenStr\n\n // Add requestId for request-scoped services\n if (isRequest && requestId) {\n result = `${result}:requestId=${requestId}`\n }\n\n // Add args hash if args are provided\n if (args) {\n const argsHash = hashArgs(args)\n result = `${result}:${argsHash}`\n }\n\n // Cache the result\n this.instanceNameCache.set(cacheKey, result)\n\n return result\n }\n\n /**\n * Upgrades an existing instance name to include requestId.\n * Preserves any args hash that might already be in the name.\n *\n * Examples:\n * - `TokenName` → `TokenName:requestId=req-123`\n * - `TokenName:abc123` → `TokenName:requestId=req-123:abc123`\n *\n * @param existingName The existing instance name (without requestId)\n * @param requestId The request ID to add\n * @returns The upgraded instance name with requestId\n */\n upgradeInstanceNameToRequest(\n existingName: string,\n requestId: string,\n ): string {\n // Check if requestId is already in the name\n if (existingName.includes(`:requestId=${requestId}`)) {\n return existingName\n }\n\n // Find where to insert requestId\n // Format: TokenName or TokenName:argsHash\n // We want: TokenName:requestId=req-123 or TokenName:requestId=req-123:argsHash\n\n // Check if there's an args hash (starts after first colon, but not requestId=)\n const requestIdPattern = /:requestId=/\n const hasRequestId = requestIdPattern.test(existingName)\n\n if (hasRequestId) {\n // Already has a requestId, don't upgrade\n return existingName\n }\n\n // Find the token part (everything before first colon, or entire string if no colon)\n const colonIndex = existingName.indexOf(':')\n if (colonIndex === -1) {\n // No colon, just token name: TokenName → TokenName:requestId=req-123\n return `${existingName}:requestId=${requestId}`\n }\n\n // Has colon, means there's an args hash: TokenName:abc123 → TokenName:requestId=req-123:abc123\n const tokenPart = existingName.substring(0, colonIndex)\n const argsPart = existingName.substring(colonIndex + 1)\n\n // Check if argsPart looks like an args hash (not requestId=)\n if (argsPart.startsWith('requestId=')) {\n // Already has requestId, return as is\n return existingName\n }\n\n return `${tokenPart}:requestId=${requestId}:${argsPart}`\n }\n\n /**\n * Formats a single argument value for instance name generation.\n */\n formatArgValue(value: any): string {\n if (typeof value === 'function') {\n return `fn_${value.name}(${value.length})`\n }\n if (typeof value === 'symbol') {\n return value.toString()\n }\n return JSON.stringify(value).slice(0, 40)\n }\n}\n"],"mappings":"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"}