@navios/di 0.7.1 → 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 (263) hide show
  1. package/CHANGELOG.md +110 -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 -1508
  40. package/lib/browser/index.mjs +29 -2650
  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-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
  138. package/lib/container-8-z89TyQ.mjs.map +1 -0
  139. package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
  140. package/lib/container-CNiqesCL.d.mts.map +1 -0
  141. package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
  142. package/lib/container-CaY2fDuk.cjs.map +1 -0
  143. package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
  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 +461 -292
  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-processor.mts → token-resolver.mts} +17 -88
  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-BuAutHGg.d.mts.map +0 -1
  239. package/lib/container-DnzgpfBe.cjs.map +0 -1
  240. package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
  241. package/lib/container-oGTgX2iX.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 -214
  256. package/src/internal/core/invalidator.mts +0 -437
  257. package/src/internal/core/service-locator.mts +0 -202
  258. package/src/internal/holder/base-holder-manager.mts +0 -238
  259. package/src/internal/holder/holder-manager.mts +0 -85
  260. package/src/internal/holder/request-storage.mts +0 -134
  261. package/src/internal/holder/singleton-storage.mts +0 -105
  262. package/src/testing/README.md +0 -80
  263. package/src/testing/__tests__/test-container.spec.mts +0 -173
@@ -0,0 +1,351 @@
1
+ import { z } from 'zod/v4'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import { DIError, DIErrorCode } from '../errors/index.mjs'
5
+ import { InjectableScope, InjectableType } from '../enums/index.mjs'
6
+ import { InjectionToken } from '../token/injection-token.mjs'
7
+ import type { FactoryRecord } from '../token/registry.mjs'
8
+
9
+ describe('DIError', () => {
10
+ describe('constructor', () => {
11
+ it('should create error with code and message', () => {
12
+ const error = new DIError(DIErrorCode.FactoryNotFound, 'Test message')
13
+
14
+ expect(error.code).toBe(DIErrorCode.FactoryNotFound)
15
+ expect(error.message).toBe('Test message')
16
+ expect(error.name).toBe('DIError')
17
+ expect(error.context).toBeUndefined()
18
+ })
19
+
20
+ it('should create error with context', () => {
21
+ const context = { key: 'value', num: 42 }
22
+ const error = new DIError(
23
+ DIErrorCode.InstanceNotFound,
24
+ 'Test message',
25
+ context,
26
+ )
27
+
28
+ expect(error.context).toEqual(context)
29
+ })
30
+
31
+ it('should extend Error class', () => {
32
+ const error = new DIError(DIErrorCode.UnknownError, 'Test')
33
+ expect(error).toBeInstanceOf(Error)
34
+ })
35
+ })
36
+
37
+ describe('factoryNotFound', () => {
38
+ it('should create FactoryNotFound error', () => {
39
+ const error = DIError.factoryNotFound('MyService')
40
+
41
+ expect(error.code).toBe(DIErrorCode.FactoryNotFound)
42
+ expect(error.message).toBe('Factory MyService not found')
43
+ expect(error.context).toEqual({ name: 'MyService' })
44
+ })
45
+ })
46
+
47
+ describe('factoryTokenNotResolved', () => {
48
+ it('should create FactoryTokenNotResolved error with string token', () => {
49
+ const error = DIError.factoryTokenNotResolved('test-token')
50
+
51
+ expect(error.code).toBe(DIErrorCode.FactoryTokenNotResolved)
52
+ expect(error.message).toBe('Factory token not resolved: test-token')
53
+ expect(error.context).toEqual({ token: 'test-token' })
54
+ })
55
+
56
+ it('should create FactoryTokenNotResolved error with symbol token', () => {
57
+ const sym = Symbol('test')
58
+ const error = DIError.factoryTokenNotResolved(sym)
59
+
60
+ expect(error.code).toBe(DIErrorCode.FactoryTokenNotResolved)
61
+ expect(error.message).toContain('Symbol(test)')
62
+ })
63
+
64
+ it('should handle null/undefined token', () => {
65
+ const error = DIError.factoryTokenNotResolved(null)
66
+
67
+ expect(error.code).toBe(DIErrorCode.FactoryTokenNotResolved)
68
+ expect(error.message).toBe('Factory token not resolved: unknown')
69
+ })
70
+ })
71
+
72
+ describe('instanceNotFound', () => {
73
+ it('should create InstanceNotFound error', () => {
74
+ const error = DIError.instanceNotFound('MyInstance')
75
+
76
+ expect(error.code).toBe(DIErrorCode.InstanceNotFound)
77
+ expect(error.message).toBe('Instance MyInstance not found')
78
+ expect(error.context).toEqual({ name: 'MyInstance' })
79
+ })
80
+ })
81
+
82
+ describe('instanceDestroying', () => {
83
+ it('should create InstanceDestroying error', () => {
84
+ const error = DIError.instanceDestroying('MyInstance')
85
+
86
+ expect(error.code).toBe(DIErrorCode.InstanceDestroying)
87
+ expect(error.message).toBe('Instance MyInstance destroying')
88
+ expect(error.context).toEqual({ name: 'MyInstance' })
89
+ })
90
+ })
91
+
92
+ describe('unknown', () => {
93
+ it('should create UnknownError from string message', () => {
94
+ const error = DIError.unknown('Something went wrong')
95
+
96
+ expect(error.code).toBe(DIErrorCode.UnknownError)
97
+ expect(error.message).toBe('Something went wrong')
98
+ })
99
+
100
+ it('should create UnknownError from Error object', () => {
101
+ const originalError = new Error('Original error')
102
+ const error = DIError.unknown(originalError)
103
+
104
+ expect(error.code).toBe(DIErrorCode.UnknownError)
105
+ expect(error.message).toBe('Original error')
106
+ expect(error.context?.parent).toBe(originalError)
107
+ })
108
+
109
+ it('should include additional context', () => {
110
+ const error = DIError.unknown('Error', { extra: 'data' })
111
+
112
+ expect(error.context).toEqual({ extra: 'data' })
113
+ })
114
+
115
+ it('should merge context with parent Error', () => {
116
+ const originalError = new Error('Original')
117
+ const error = DIError.unknown(originalError, { extra: 'data' })
118
+
119
+ expect(error.context?.parent).toBe(originalError)
120
+ expect(error.context?.extra).toBe('data')
121
+ })
122
+ })
123
+
124
+ describe('circularDependency', () => {
125
+ it('should create CircularDependency error', () => {
126
+ const cycle = ['ServiceA', 'ServiceB', 'ServiceC', 'ServiceA']
127
+ const error = DIError.circularDependency(cycle)
128
+
129
+ expect(error.code).toBe(DIErrorCode.CircularDependency)
130
+ expect(error.message).toBe(
131
+ 'Circular dependency detected: ServiceA -> ServiceB -> ServiceC -> ServiceA',
132
+ )
133
+ expect(error.context).toEqual({ cycle })
134
+ })
135
+
136
+ it('should handle self-referential cycle', () => {
137
+ const cycle = ['ServiceA', 'ServiceA']
138
+ const error = DIError.circularDependency(cycle)
139
+
140
+ expect(error.message).toBe(
141
+ 'Circular dependency detected: ServiceA -> ServiceA',
142
+ )
143
+ })
144
+ })
145
+
146
+ describe('tokenValidationError', () => {
147
+ it('should create TokenValidationError', () => {
148
+ const schema = z.object({ name: z.string() })
149
+ const value = { name: 123 }
150
+ const error = DIError.tokenValidationError(
151
+ 'Validation failed',
152
+ schema,
153
+ value,
154
+ )
155
+
156
+ expect(error.code).toBe(DIErrorCode.TokenValidationError)
157
+ expect(error.message).toBe('Validation failed')
158
+ expect(error.context?.schema).toBe(schema)
159
+ expect(error.context?.value).toEqual(value)
160
+ })
161
+
162
+ it('should handle undefined schema', () => {
163
+ const error = DIError.tokenValidationError(
164
+ 'Validation failed',
165
+ undefined,
166
+ null,
167
+ )
168
+
169
+ expect(error.context?.schema).toBeUndefined()
170
+ })
171
+ })
172
+
173
+ describe('tokenSchemaRequiredError', () => {
174
+ it('should create TokenSchemaRequiredError with string token', () => {
175
+ const error = DIError.tokenSchemaRequiredError('TestToken')
176
+
177
+ expect(error.code).toBe(DIErrorCode.TokenSchemaRequiredError)
178
+ expect(error.message).toContain('TestToken')
179
+ expect(error.message).toContain('requires schema arguments')
180
+ })
181
+
182
+ it('should create TokenSchemaRequiredError with symbol token', () => {
183
+ const sym = Symbol('test')
184
+ const error = DIError.tokenSchemaRequiredError(sym)
185
+
186
+ expect(error.code).toBe(DIErrorCode.TokenSchemaRequiredError)
187
+ expect(error.message).toContain('Symbol(test)')
188
+ })
189
+
190
+ it('should handle null/undefined token', () => {
191
+ const error = DIError.tokenSchemaRequiredError(null)
192
+
193
+ expect(error.message).toContain('unknown')
194
+ })
195
+ })
196
+
197
+ describe('classNotInjectable', () => {
198
+ it('should create ClassNotInjectable error', () => {
199
+ const error = DIError.classNotInjectable('MyClass')
200
+
201
+ expect(error.code).toBe(DIErrorCode.ClassNotInjectable)
202
+ expect(error.message).toBe(
203
+ 'Class MyClass is not decorated with @Injectable.',
204
+ )
205
+ expect(error.context).toEqual({ className: 'MyClass' })
206
+ })
207
+ })
208
+
209
+ describe('scopeMismatchError', () => {
210
+ it('should create ScopeMismatchError', () => {
211
+ const error = DIError.scopeMismatchError(
212
+ 'TestToken',
213
+ 'Singleton',
214
+ 'Request',
215
+ )
216
+
217
+ expect(error.code).toBe(DIErrorCode.ScopeMismatchError)
218
+ expect(error.message).toBe(
219
+ 'Scope mismatch for TestToken: expected Singleton, got Request',
220
+ )
221
+ expect(error.context).toEqual({
222
+ token: 'TestToken',
223
+ expectedScope: 'Singleton',
224
+ actualScope: 'Request',
225
+ })
226
+ })
227
+ })
228
+
229
+ describe('priorityConflictError', () => {
230
+ it('should create PriorityConflictError', () => {
231
+ const token = InjectionToken.create<string>('test')
232
+ const records: FactoryRecord[] = [
233
+ {
234
+ scope: InjectableScope.Singleton,
235
+ originalToken: token,
236
+ target: class A {},
237
+ type: InjectableType.Class,
238
+ priority: 1,
239
+ },
240
+ {
241
+ scope: InjectableScope.Singleton,
242
+ originalToken: token,
243
+ target: class B {},
244
+ type: InjectableType.Class,
245
+ priority: 1,
246
+ },
247
+ ]
248
+
249
+ const error = DIError.priorityConflictError('TestToken', records)
250
+
251
+ expect(error.code).toBe(DIErrorCode.PriorityConflictError)
252
+ expect(error.message).toContain('Priority conflict')
253
+ expect(error.context?.records).toBe(records)
254
+ })
255
+ })
256
+
257
+ describe('storageError', () => {
258
+ it('should create StorageError with instance name', () => {
259
+ const error = DIError.storageError('Failed to store', 'set', 'MyInstance')
260
+
261
+ expect(error.code).toBe(DIErrorCode.StorageError)
262
+ expect(error.message).toBe('Storage error: Failed to store')
263
+ expect(error.context).toEqual({
264
+ operation: 'set',
265
+ instanceName: 'MyInstance',
266
+ })
267
+ })
268
+
269
+ it('should create StorageError without instance name', () => {
270
+ const error = DIError.storageError('Failed to clear', 'clear')
271
+
272
+ expect(error.context?.instanceName).toBeUndefined()
273
+ })
274
+ })
275
+
276
+ describe('initializationError', () => {
277
+ it('should create InitializationError from Error', () => {
278
+ const originalError = new Error('Constructor failed')
279
+ const error = DIError.initializationError('MyService', originalError)
280
+
281
+ expect(error.code).toBe(DIErrorCode.InitializationError)
282
+ expect(error.message).toBe(
283
+ 'Service MyService initialization failed: Constructor failed',
284
+ )
285
+ expect(error.context?.error).toBe(originalError)
286
+ })
287
+
288
+ it('should create InitializationError from string', () => {
289
+ const error = DIError.initializationError(
290
+ 'MyService',
291
+ 'Missing dependency',
292
+ )
293
+
294
+ expect(error.message).toBe(
295
+ 'Service MyService initialization failed: Missing dependency',
296
+ )
297
+ })
298
+ })
299
+
300
+ describe('dependencyResolutionError', () => {
301
+ it('should create DependencyResolutionError from Error', () => {
302
+ const originalError = new Error('Not found')
303
+ const error = DIError.dependencyResolutionError(
304
+ 'MyService',
305
+ 'DatabaseService',
306
+ originalError,
307
+ )
308
+
309
+ expect(error.code).toBe(DIErrorCode.DependencyResolutionError)
310
+ expect(error.message).toBe(
311
+ 'Failed to resolve dependency DatabaseService for service MyService: Not found',
312
+ )
313
+ expect(error.context).toEqual({
314
+ serviceName: 'MyService',
315
+ dependencyName: 'DatabaseService',
316
+ error: originalError,
317
+ })
318
+ })
319
+
320
+ it('should create DependencyResolutionError from string', () => {
321
+ const error = DIError.dependencyResolutionError(
322
+ 'MyService',
323
+ 'DatabaseService',
324
+ 'Connection failed',
325
+ )
326
+
327
+ expect(error.message).toContain('Connection failed')
328
+ })
329
+ })
330
+
331
+ describe('DIErrorCode enum', () => {
332
+ it('should have all expected error codes', () => {
333
+ expect(DIErrorCode.FactoryNotFound).toBe('FactoryNotFound')
334
+ expect(DIErrorCode.FactoryTokenNotResolved).toBe('FactoryTokenNotResolved')
335
+ expect(DIErrorCode.InstanceNotFound).toBe('InstanceNotFound')
336
+ expect(DIErrorCode.InstanceDestroying).toBe('InstanceDestroying')
337
+ expect(DIErrorCode.CircularDependency).toBe('CircularDependency')
338
+ expect(DIErrorCode.TokenValidationError).toBe('TokenValidationError')
339
+ expect(DIErrorCode.TokenSchemaRequiredError).toBe('TokenSchemaRequiredError')
340
+ expect(DIErrorCode.ClassNotInjectable).toBe('ClassNotInjectable')
341
+ expect(DIErrorCode.ScopeMismatchError).toBe('ScopeMismatchError')
342
+ expect(DIErrorCode.PriorityConflictError).toBe('PriorityConflictError')
343
+ expect(DIErrorCode.StorageError).toBe('StorageError')
344
+ expect(DIErrorCode.InitializationError).toBe('InitializationError')
345
+ expect(DIErrorCode.DependencyResolutionError).toBe(
346
+ 'DependencyResolutionError',
347
+ )
348
+ expect(DIErrorCode.UnknownError).toBe('UnknownError')
349
+ })
350
+ })
351
+ })
@@ -424,13 +424,11 @@ describe('E2E Browser: Concurrent Requests', () => {
424
424
  describe('E2E Browser: Service Lifecycle', () => {
425
425
  let registry: Registry
426
426
  let container: Container
427
- let injectors: ReturnType<typeof getInjectors>
428
427
 
429
428
  beforeEach(() => {
430
429
  const setup = createTestSetup()
431
430
  registry = setup.registry
432
431
  container = setup.container
433
- injectors = setup.injectors
434
432
  })
435
433
 
436
434
  afterEach(async () => {
@@ -654,13 +652,11 @@ describe('E2E Browser: Service Invalidation', () => {
654
652
  describe('E2E Browser: Error Handling', () => {
655
653
  let registry: Registry
656
654
  let container: Container
657
- let injectors: ReturnType<typeof getInjectors>
658
655
 
659
656
  beforeEach(() => {
660
657
  const setup = createTestSetup()
661
658
  registry = setup.registry
662
659
  container = setup.container
663
- injectors = setup.injectors
664
660
  })
665
661
 
666
662
  afterEach(async () => {
@@ -11,12 +11,11 @@
11
11
 
12
12
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
13
13
 
14
+ import type { OnServiceDestroy, OnServiceInit } from '../index.mjs'
15
+
14
16
  import { Container } from '../container/container.mjs'
15
17
  import { Injectable } from '../decorators/injectable.decorator.mjs'
16
18
  import { InjectableScope } from '../enums/index.mjs'
17
- import { InjectionToken } from '../token/injection-token.mjs'
18
- import type { OnServiceDestroy } from '../interfaces/on-service-destroy.interface.mjs'
19
- import type { OnServiceInit } from '../interfaces/on-service-init.interface.mjs'
20
19
  import { Registry } from '../token/registry.mjs'
21
20
  import { getInjectors } from '../utils/get-injectors.mjs'
22
21
 
@@ -96,12 +95,16 @@ describe('E2E: Basic Setup', () => {
96
95
  expect(instance1.id).not.toBe(instance2.id)
97
96
  })
98
97
 
99
- it('should resolve services with constructor arguments via schema', async () => {
98
+ it('should resolve services with constructor arguments via schema', async () => {
100
99
  // Define schema first, then class, then token to avoid hoisting issues
101
100
  const { z } = await import('zod/v4')
102
101
  const configSchema = z.object({ port: z.number() })
103
102
 
104
- @Injectable({ scope: InjectableScope.Singleton, registry, schema: configSchema })
103
+ @Injectable({
104
+ scope: InjectableScope.Singleton,
105
+ registry,
106
+ schema: configSchema,
107
+ })
105
108
  class ConfigService {
106
109
  constructor(public config: { port: number }) {}
107
110
  }
@@ -135,7 +138,7 @@ it('should resolve services with constructor arguments via schema', async () =>
135
138
  expect(db.connect()).toBe('connected')
136
139
  })
137
140
 
138
- it('should resolve deep dependency chains', async () => {
141
+ it('should resolve deep dependency chains', async () => {
139
142
  @Injectable({ scope: InjectableScope.Singleton, registry })
140
143
  class ServiceLevel1 {
141
144
  name = 'Level1'
@@ -415,7 +418,7 @@ describe('E2E: Concurrent Requests', () => {
415
418
  await Promise.all(requests)
416
419
 
417
420
  // Each request should have used the same counter instance (3 identical IDs)
418
- for (const [requestId, ids] of Object.entries(instancesByRequest)) {
421
+ for (const [, ids] of Object.entries(instancesByRequest)) {
419
422
  expect(ids.length).toBe(3)
420
423
  expect(ids[0]).toBe(ids[1])
421
424
  expect(ids[1]).toBe(ids[2])
@@ -1001,13 +1004,11 @@ describe('E2E: Service Invalidation', () => {
1001
1004
  describe('E2E: Error Handling', () => {
1002
1005
  let registry: Registry
1003
1006
  let container: Container
1004
- let injectors: ReturnType<typeof getInjectors>
1005
1007
 
1006
1008
  beforeEach(() => {
1007
1009
  const setup = createTestSetup()
1008
1010
  registry = setup.registry
1009
1011
  container = setup.container
1010
- injectors = setup.injectors
1011
1012
  })
1012
1013
 
1013
1014
  afterEach(async () => {
@@ -1110,11 +1111,6 @@ describe('E2E: Advanced Scenarios', () => {
1110
1111
 
1111
1112
  describe('Metadata handling', () => {
1112
1113
  it('should pass metadata to request context', async () => {
1113
- @Injectable({ scope: InjectableScope.Request, registry })
1114
- class MetadataAwareService {
1115
- constructor() {}
1116
- }
1117
-
1118
1114
  const metadata = { userId: '123', roles: ['admin'] }
1119
1115
  const scoped = container.beginRequest('request-1', metadata)
1120
1116
 
@@ -1125,11 +1121,6 @@ describe('E2E: Advanced Scenarios', () => {
1125
1121
  })
1126
1122
 
1127
1123
  it('should allow modifying metadata during request', async () => {
1128
- @Injectable({ scope: InjectableScope.Request, registry })
1129
- class RequestTracker {
1130
- startTime = Date.now()
1131
- }
1132
-
1133
1124
  const scoped = container.beginRequest('request-1')
1134
1125
  scoped.setMetadata('stage', 'processing')
1135
1126