@navios/di 0.4.2 → 0.5.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 (120) hide show
  1. package/README.md +211 -1
  2. package/coverage/clover.xml +1912 -1277
  3. package/coverage/coverage-final.json +37 -28
  4. package/coverage/docs/examples/basic-usage.mts.html +1 -1
  5. package/coverage/docs/examples/factory-pattern.mts.html +1 -1
  6. package/coverage/docs/examples/index.html +1 -1
  7. package/coverage/docs/examples/injection-tokens.mts.html +1 -1
  8. package/coverage/docs/examples/request-scope-example.mts.html +1 -1
  9. package/coverage/docs/examples/service-lifecycle.mts.html +1 -1
  10. package/coverage/index.html +71 -41
  11. package/coverage/lib/_tsup-dts-rollup.d.mts.html +682 -43
  12. package/coverage/lib/index.d.mts.html +7 -4
  13. package/coverage/lib/index.html +5 -5
  14. package/coverage/lib/testing/index.d.mts.html +91 -0
  15. package/coverage/lib/testing/index.html +116 -0
  16. package/coverage/src/base-instance-holder-manager.mts.html +589 -0
  17. package/coverage/src/container.mts.html +257 -74
  18. package/coverage/src/decorators/factory.decorator.mts.html +1 -1
  19. package/coverage/src/decorators/index.html +1 -1
  20. package/coverage/src/decorators/index.mts.html +1 -1
  21. package/coverage/src/decorators/injectable.decorator.mts.html +20 -20
  22. package/coverage/src/enums/index.html +1 -1
  23. package/coverage/src/enums/index.mts.html +1 -1
  24. package/coverage/src/enums/injectable-scope.enum.mts.html +1 -1
  25. package/coverage/src/enums/injectable-type.enum.mts.html +1 -1
  26. package/coverage/src/errors/di-error.mts.html +292 -0
  27. package/coverage/src/errors/errors.enum.mts.html +30 -21
  28. package/coverage/src/errors/factory-not-found.mts.html +31 -22
  29. package/coverage/src/errors/factory-token-not-resolved.mts.html +29 -26
  30. package/coverage/src/errors/index.html +56 -41
  31. package/coverage/src/errors/index.mts.html +15 -9
  32. package/coverage/src/errors/instance-destroying.mts.html +31 -22
  33. package/coverage/src/errors/instance-expired.mts.html +31 -22
  34. package/coverage/src/errors/instance-not-found.mts.html +31 -22
  35. package/coverage/src/errors/unknown-error.mts.html +31 -43
  36. package/coverage/src/event-emitter.mts.html +14 -14
  37. package/coverage/src/factory-context.mts.html +1 -1
  38. package/coverage/src/index.html +121 -46
  39. package/coverage/src/index.mts.html +7 -4
  40. package/coverage/src/injection-token.mts.html +28 -28
  41. package/coverage/src/injector.mts.html +1 -1
  42. package/coverage/src/instance-resolver.mts.html +1762 -0
  43. package/coverage/src/interfaces/factory.interface.mts.html +1 -1
  44. package/coverage/src/interfaces/index.html +1 -1
  45. package/coverage/src/interfaces/index.mts.html +1 -1
  46. package/coverage/src/interfaces/on-service-destroy.interface.mts.html +1 -1
  47. package/coverage/src/interfaces/on-service-init.interface.mts.html +1 -1
  48. package/coverage/src/registry.mts.html +28 -28
  49. package/coverage/src/request-context-holder.mts.html +183 -102
  50. package/coverage/src/request-context-manager.mts.html +532 -0
  51. package/coverage/src/service-instantiator.mts.html +49 -49
  52. package/coverage/src/service-invalidator.mts.html +1372 -0
  53. package/coverage/src/service-locator-event-bus.mts.html +48 -48
  54. package/coverage/src/service-locator-instance-holder.mts.html +2 -14
  55. package/coverage/src/service-locator-manager.mts.html +71 -335
  56. package/coverage/src/service-locator.mts.html +240 -2328
  57. package/coverage/src/symbols/index.html +1 -1
  58. package/coverage/src/symbols/index.mts.html +1 -1
  59. package/coverage/src/symbols/injectable-token.mts.html +1 -1
  60. package/coverage/src/testing/index.html +131 -0
  61. package/coverage/src/testing/index.mts.html +88 -0
  62. package/coverage/src/testing/test-container.mts.html +445 -0
  63. package/coverage/src/token-processor.mts.html +607 -0
  64. package/coverage/src/utils/defer.mts.html +28 -214
  65. package/coverage/src/utils/get-injectable-token.mts.html +7 -7
  66. package/coverage/src/utils/get-injectors.mts.html +99 -99
  67. package/coverage/src/utils/index.html +15 -15
  68. package/coverage/src/utils/index.mts.html +4 -7
  69. package/coverage/src/utils/types.mts.html +1 -1
  70. package/docs/injectable.md +51 -11
  71. package/docs/scopes.md +63 -29
  72. package/lib/_tsup-dts-rollup.d.mts +376 -213
  73. package/lib/_tsup-dts-rollup.d.ts +376 -213
  74. package/lib/{chunk-3NLYPYBY.mjs → chunk-44F3LXW5.mjs} +1021 -605
  75. package/lib/chunk-44F3LXW5.mjs.map +1 -0
  76. package/lib/index.d.mts +6 -4
  77. package/lib/index.d.ts +6 -4
  78. package/lib/index.js +1192 -776
  79. package/lib/index.js.map +1 -1
  80. package/lib/index.mjs +2 -2
  81. package/lib/testing/index.js +1258 -840
  82. package/lib/testing/index.js.map +1 -1
  83. package/lib/testing/index.mjs +1 -1
  84. package/package.json +1 -1
  85. package/src/__tests__/container.spec.mts +47 -13
  86. package/src/__tests__/errors.spec.mts +53 -27
  87. package/src/__tests__/injectable.spec.mts +73 -0
  88. package/src/__tests__/request-scope.spec.mts +0 -2
  89. package/src/__tests__/service-locator-manager.spec.mts +12 -82
  90. package/src/__tests__/service-locator.spec.mts +1009 -1
  91. package/src/__type-tests__/inject.spec-d.mts +30 -7
  92. package/src/__type-tests__/injectable.spec-d.mts +76 -37
  93. package/src/base-instance-holder-manager.mts +2 -9
  94. package/src/container.mts +61 -9
  95. package/src/decorators/injectable.decorator.mts +29 -5
  96. package/src/errors/di-error.mts +69 -0
  97. package/src/errors/index.mts +9 -7
  98. package/src/injection-token.mts +1 -0
  99. package/src/injector.mts +2 -0
  100. package/src/instance-resolver.mts +559 -0
  101. package/src/request-context-holder.mts +0 -2
  102. package/src/request-context-manager.mts +149 -0
  103. package/src/service-invalidator.mts +429 -0
  104. package/src/service-locator-instance-holder.mts +0 -4
  105. package/src/service-locator-manager.mts +10 -40
  106. package/src/service-locator.mts +86 -782
  107. package/src/token-processor.mts +174 -0
  108. package/src/utils/get-injectors.mts +161 -24
  109. package/src/utils/index.mts +0 -1
  110. package/src/utils/types.mts +12 -8
  111. package/lib/chunk-3NLYPYBY.mjs.map +0 -1
  112. package/src/__tests__/defer.spec.mts +0 -166
  113. package/src/errors/errors.enum.mts +0 -8
  114. package/src/errors/factory-not-found.mts +0 -8
  115. package/src/errors/factory-token-not-resolved.mts +0 -10
  116. package/src/errors/instance-destroying.mts +0 -8
  117. package/src/errors/instance-expired.mts +0 -8
  118. package/src/errors/instance-not-found.mts +0 -8
  119. package/src/errors/unknown-error.mts +0 -15
  120. package/src/utils/defer.mts +0 -73
@@ -1,4 +1,4 @@
1
- import { Injectable, __decoratorStart, __decorateElement, __runInitializers, Container, globalRegistry, getInjectableToken } from '../chunk-3NLYPYBY.mjs';
1
+ import { Injectable, __decoratorStart, __decorateElement, __runInitializers, Container, globalRegistry, getInjectableToken } from '../chunk-44F3LXW5.mjs';
2
2
 
3
3
  // src/testing/test-container.mts
4
4
  var TestBindingBuilder = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navios/di",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "author": {
5
5
  "name": "Oleksandr Hanzha",
6
6
  "email": "alex@granted.name"
@@ -1,3 +1,4 @@
1
+ // oxlint-disable no-unused-vars
1
2
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
3
  import { z } from 'zod/v4'
3
4
 
@@ -16,7 +17,6 @@ import { InjectionToken } from '../injection-token.mjs'
16
17
  import { asyncInject, inject } from '../injector.mjs'
17
18
  import { Registry } from '../registry.mjs'
18
19
  import { ServiceLocator } from '../service-locator.mjs'
19
- import { createDeferred } from '../utils/defer.mjs'
20
20
 
21
21
  describe('Container', () => {
22
22
  let container: Container
@@ -321,7 +321,6 @@ describe('Container', () => {
321
321
  }
322
322
  }
323
323
 
324
- @Injectable({ registry })
325
324
  class TestService {
326
325
  constructor(
327
326
  public readonly name: string,
@@ -359,7 +358,6 @@ describe('Container', () => {
359
358
  }
360
359
  }
361
360
 
362
- @Injectable({ registry })
363
361
  class TestService {
364
362
  constructor(
365
363
  public readonly name: string,
@@ -394,7 +392,6 @@ describe('Container', () => {
394
392
  }
395
393
  }
396
394
 
397
- @Injectable({ registry })
398
395
  class TestService {
399
396
  constructor(public readonly type: string) {}
400
397
  }
@@ -450,7 +447,6 @@ describe('Container', () => {
450
447
  }
451
448
  }
452
449
 
453
- @Injectable({ registry })
454
450
  class TestService {
455
451
  constructor(public readonly factory: string) {}
456
452
  }
@@ -751,7 +747,7 @@ describe('Container', () => {
751
747
 
752
748
  describe('Ready method and async operations', () => {
753
749
  it('should wait for all pending operations', async () => {
754
- const deferred = createDeferred<string>()
750
+ const deferred = Promise.withResolvers<string>()
755
751
 
756
752
  @Factory({ registry })
757
753
  class AsyncFactory implements Factorable<TestService> {
@@ -761,7 +757,6 @@ describe('Container', () => {
761
757
  }
762
758
  }
763
759
 
764
- @Injectable({ registry })
765
760
  class TestService {
766
761
  constructor(public readonly value: string) {}
767
762
  }
@@ -779,8 +774,8 @@ describe('Container', () => {
779
774
  })
780
775
 
781
776
  it('should handle multiple concurrent operations', async () => {
782
- const deferred1 = createDeferred<string>()
783
- const deferred2 = createDeferred<string>()
777
+ const deferred1 = Promise.withResolvers<string>()
778
+ const deferred2 = Promise.withResolvers<string>()
784
779
 
785
780
  @Factory({ registry })
786
781
  class AsyncFactory1 implements Factorable<TestService> {
@@ -798,7 +793,6 @@ describe('Container', () => {
798
793
  }
799
794
  }
800
795
 
801
- @Injectable({ registry })
802
796
  class TestService {
803
797
  constructor(public readonly value: string) {}
804
798
  }
@@ -817,7 +811,7 @@ describe('Container', () => {
817
811
  })
818
812
 
819
813
  it.skip('should handle factory errors in ready state', async () => {
820
- const deferred = createDeferred<string>()
814
+ const deferred = Promise.withResolvers<string>()
821
815
 
822
816
  @Factory({ registry })
823
817
  class ErrorFactory implements Factorable<TestService> {
@@ -826,13 +820,13 @@ describe('Container', () => {
826
820
  if (result === 'error') {
827
821
  throw new Error('Factory error')
828
822
  }
829
- return new TestService(result)
823
+ return new TestService()
830
824
  }
831
825
  }
832
826
 
833
827
  @Injectable({ registry })
834
828
  class TestService {
835
- constructor(public readonly value: string) {}
829
+ constructor() {}
836
830
  }
837
831
 
838
832
  const promise = container.get(ErrorFactory)
@@ -1135,6 +1129,46 @@ describe('Container', () => {
1135
1129
  expect(level1_1.id).not.toBe(level1_2.id)
1136
1130
  })
1137
1131
 
1132
+ it('should invalidate services with nested inject dependencies in request context', async () => {
1133
+ @Injectable({ registry, scope: InjectableScope.Request })
1134
+ class Level1Service {
1135
+ public id = Math.random()
1136
+ }
1137
+
1138
+ @Injectable({ registry })
1139
+ class Level2Service {
1140
+ level1 = inject(Level1Service)
1141
+ public id = Math.random()
1142
+ }
1143
+
1144
+ @Injectable({ registry })
1145
+ class RootService {
1146
+ level2 = inject(Level2Service)
1147
+ }
1148
+
1149
+ container.beginRequest('request-1')
1150
+
1151
+ const root1 = await container.get(RootService)
1152
+ const level2_1 = root1.level2
1153
+ const level1_1 = level2_1.level1
1154
+
1155
+ // Invalidate the root service
1156
+ await container.invalidate(level1_1)
1157
+
1158
+ const root2 = await container.get(RootService)
1159
+ const level2_2 = root2.level2
1160
+ const level1_2 = level2_2.level1
1161
+
1162
+ // All should be new instances
1163
+ expect(root1).not.toBe(root2)
1164
+ expect(level2_1).not.toBe(level2_2)
1165
+ expect(level1_1).not.toBe(level1_2)
1166
+ expect(level2_1.id).not.toBe(level2_2.id)
1167
+ expect(level1_1.id).not.toBe(level1_2.id)
1168
+
1169
+ await container.endRequest('request-1')
1170
+ })
1171
+
1138
1172
  it('should handle invalidation of services with mixed inject and asyncInject', async () => {
1139
1173
  @Injectable({ registry })
1140
1174
  class AsyncService {
@@ -1,61 +1,87 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
- import { ErrorsEnum } from '../errors/errors.enum.mjs'
4
- import {
5
- FactoryNotFound,
6
- InstanceDestroying,
7
- InstanceExpired,
8
- } from '../errors/index.mjs'
9
-
10
- describe('Error Classes', () => {
11
- describe('FactoryNotFound', () => {
3
+ import { DIError, DIErrorCode } from '../errors/index.mjs'
4
+
5
+ describe('DIError', () => {
6
+ describe('factoryNotFound', () => {
12
7
  it('should create error with proper message and code', () => {
13
- const error = new FactoryNotFound('TestFactory')
8
+ const error = DIError.factoryNotFound('TestFactory')
14
9
 
15
10
  expect(error.message).toBe('Factory TestFactory not found')
16
- expect(error.code).toBe(ErrorsEnum.FactoryNotFound)
17
- expect(error.name).toBe('TestFactory')
11
+ expect(error.code).toBe(DIErrorCode.FactoryNotFound)
12
+ expect(error.context?.name).toBe('TestFactory')
13
+ expect(error).toBeInstanceOf(DIError)
18
14
  expect(error).toBeInstanceOf(Error)
19
15
  })
20
16
 
21
17
  it('should be throwable', () => {
22
18
  expect(() => {
23
- throw new FactoryNotFound('SomeFactory')
19
+ throw DIError.factoryNotFound('SomeFactory')
24
20
  }).toThrow('Factory SomeFactory not found')
25
21
  })
26
22
  })
27
23
 
28
- describe('InstanceDestroying', () => {
24
+ describe('instanceDestroying', () => {
29
25
  it('should create error with proper message and code', () => {
30
- const error = new InstanceDestroying('TestInstance')
26
+ const error = DIError.instanceDestroying('TestInstance')
31
27
 
32
28
  expect(error.message).toBe('Instance TestInstance destroying')
33
- expect(error.code).toBe(ErrorsEnum.InstanceDestroying)
34
- expect(error.name).toBe('TestInstance')
29
+ expect(error.code).toBe(DIErrorCode.InstanceDestroying)
30
+ expect(error.context?.name).toBe('TestInstance')
31
+ expect(error).toBeInstanceOf(DIError)
35
32
  expect(error).toBeInstanceOf(Error)
36
33
  })
37
34
 
38
35
  it('should be throwable', () => {
39
36
  expect(() => {
40
- throw new InstanceDestroying('SomeInstance')
37
+ throw DIError.instanceDestroying('SomeInstance')
41
38
  }).toThrow('Instance SomeInstance destroying')
42
39
  })
43
40
  })
44
41
 
45
- describe('InstanceExpired', () => {
42
+ describe('instanceNotFound', () => {
46
43
  it('should create error with proper message and code', () => {
47
- const error = new InstanceExpired('TestInstance')
44
+ const error = DIError.instanceNotFound('TestInstance')
48
45
 
49
- expect(error.message).toBe('Instance TestInstance expired')
50
- expect(error.code).toBe(ErrorsEnum.InstanceExpired)
51
- expect(error.name).toBe('TestInstance')
46
+ expect(error.message).toBe('Instance TestInstance not found')
47
+ expect(error.code).toBe(DIErrorCode.InstanceNotFound)
48
+ expect(error.context?.name).toBe('TestInstance')
49
+ expect(error).toBeInstanceOf(DIError)
52
50
  expect(error).toBeInstanceOf(Error)
53
51
  })
52
+ })
54
53
 
55
- it('should be throwable', () => {
56
- expect(() => {
57
- throw new InstanceExpired('SomeInstance')
58
- }).toThrow('Instance SomeInstance expired')
54
+ describe('factoryTokenNotResolved', () => {
55
+ it('should create error with proper message and code', () => {
56
+ const error = DIError.factoryTokenNotResolved('TestToken')
57
+
58
+ expect(error.message).toBe('Factory token not resolved: TestToken')
59
+ expect(error.code).toBe(DIErrorCode.FactoryTokenNotResolved)
60
+ expect(error.context?.token).toBe('TestToken')
61
+ expect(error).toBeInstanceOf(DIError)
62
+ expect(error).toBeInstanceOf(Error)
63
+ })
64
+ })
65
+
66
+ describe('unknown', () => {
67
+ it('should create error with string message', () => {
68
+ const error = DIError.unknown('Test error message')
69
+
70
+ expect(error.message).toBe('Test error message')
71
+ expect(error.code).toBe(DIErrorCode.UnknownError)
72
+ expect(error).toBeInstanceOf(DIError)
73
+ expect(error).toBeInstanceOf(Error)
74
+ })
75
+
76
+ it('should create error with Error object', () => {
77
+ const originalError = new Error('Original error')
78
+ const error = DIError.unknown(originalError)
79
+
80
+ expect(error.message).toBe('Original error')
81
+ expect(error.code).toBe(DIErrorCode.UnknownError)
82
+ expect(error.context?.parent).toBe(originalError)
83
+ expect(error).toBeInstanceOf(DIError)
84
+ expect(error).toBeInstanceOf(Error)
59
85
  })
60
86
  })
61
87
  })
@@ -170,4 +170,77 @@ describe('Injectable decorator', () => {
170
170
  expect(value).toBeInstanceOf(TestOuter)
171
171
  expect(value.foo).toBeInstanceOf(TestInner)
172
172
  })
173
+
174
+ it('should work with inject and Transient services', async () => {
175
+ @Injectable({ scope: InjectableScope.Transient })
176
+ class TransientService {
177
+ value = Math.random()
178
+
179
+ getValue() {
180
+ return this.value
181
+ }
182
+ }
183
+
184
+ @Injectable()
185
+ class ConsumerService {
186
+ private readonly transientService = inject(TransientService)
187
+
188
+ async getTransientValue() {
189
+ // Service should be available in async methods after initialization
190
+ return this.transientService.getValue()
191
+ }
192
+
193
+ // Synchronous access should work after initialization
194
+ getTransientValueSync() {
195
+ return this.transientService.getValue()
196
+ }
197
+ }
198
+
199
+ const consumer1 = await container.get(ConsumerService)
200
+ expect(consumer1).toBeInstanceOf(ConsumerService)
201
+
202
+ const value1 = await consumer1.getTransientValue()
203
+ expect(typeof value1).toBe('number')
204
+
205
+ const value2 = consumer1.getTransientValueSync()
206
+ expect(value2).toBe(value1) // Should be the same instance
207
+
208
+ // Each consumer gets a new transient instance
209
+ const consumer2 = await container.get(ConsumerService)
210
+ expect(consumer2).toBe(consumer1) // Consumer is singleton
211
+
212
+ const value3 = await consumer2.getTransientValue()
213
+ expect(value3).toBe(value1) // Same transient instance for same consumer
214
+ })
215
+
216
+ it('should track async dependencies with inject for Transient services', async () => {
217
+ @Injectable({ scope: InjectableScope.Transient })
218
+ class AsyncTransientService {
219
+ private initialized = false
220
+
221
+ async onServiceInit() {
222
+ await new Promise((resolve) => setTimeout(resolve, 10))
223
+ this.initialized = true
224
+ }
225
+
226
+ isInitialized() {
227
+ return this.initialized
228
+ }
229
+ }
230
+
231
+ @Injectable()
232
+ class AsyncConsumerService {
233
+ private readonly transientService = inject(AsyncTransientService)
234
+
235
+ async checkInitialization() {
236
+ return this.transientService.isInitialized()
237
+ }
238
+ }
239
+
240
+ const consumer = await container.get(AsyncConsumerService)
241
+ expect(consumer).toBeInstanceOf(AsyncConsumerService)
242
+
243
+ const isInitialized = await consumer.checkInitialization()
244
+ expect(isInitialized).toBe(true) // Should be initialized after container.get()
245
+ })
173
246
  })
@@ -233,7 +233,6 @@ describe('Request Scope', () => {
233
233
  deps: new Set<string>(),
234
234
  destroyListeners: [],
235
235
  createdAt: Date.now(),
236
- ttl: Infinity,
237
236
  }
238
237
 
239
238
  holder.addInstance('test-instance', mockInstance, mockHolder)
@@ -407,7 +406,6 @@ describe('Request Scope', () => {
407
406
  deps: new Set<string>(),
408
407
  destroyListeners: [],
409
408
  createdAt: Date.now(),
410
- ttl: Infinity,
411
409
  }
412
410
  holder.addInstance(stringName, stringInstance, mockHolder)
413
411
 
@@ -1,11 +1,7 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
 
3
3
  import { InjectableScope, InjectableType } from '../enums/index.mjs'
4
- import {
5
- InstanceDestroying,
6
- InstanceExpired,
7
- InstanceNotFound,
8
- } from '../errors/index.mjs'
4
+ import { DIError } from '../errors/index.mjs'
9
5
  import { ServiceLocatorInstanceHolderStatus } from '../service-locator-instance-holder.mjs'
10
6
  import { ServiceLocatorManager } from '../service-locator-manager.mjs'
11
7
 
@@ -32,11 +28,11 @@ describe('ServiceLocatorManager', () => {
32
28
  })
33
29
 
34
30
  describe('get', () => {
35
- it('should return InstanceNotFound for non-existent instance', () => {
31
+ it('should return DIError.instanceNotFound for non-existent instance', () => {
36
32
  const result = manager.get('non-existent')
37
33
 
38
34
  expect(result).toHaveLength(1)
39
- expect(result[0]).toBeInstanceOf(InstanceNotFound)
35
+ expect(result[0]).toBeInstanceOf(DIError)
40
36
  expect(mockLogger.log).toHaveBeenCalledWith(
41
37
  '[ServiceLocatorManager]#getInstanceHolder() Instance non-existent not found',
42
38
  )
@@ -57,30 +53,7 @@ describe('ServiceLocatorManager', () => {
57
53
  expect(result[1]).toBe(holder)
58
54
  })
59
55
 
60
- it('should return InstanceExpired for expired instance with TTL', () => {
61
- const holder = manager.storeCreatedHolder(
62
- 'expired-instance',
63
- { value: 'test' },
64
- InjectableType.Class,
65
- InjectableScope.Singleton,
66
- new Set(),
67
- 100, // 100ms TTL
68
- )
69
-
70
- // Manually set creation time to past
71
- holder.createdAt = Date.now() - 200
72
-
73
- const result = manager.get('expired-instance')
74
-
75
- expect(result).toHaveLength(2)
76
- expect(result[0]).toBeInstanceOf(InstanceExpired)
77
- expect(result[1]).toBe(holder)
78
- expect(mockLogger.log).toHaveBeenCalledWith(
79
- '[ServiceLocatorManager]#getInstanceHolder() TTL expired for expired-instance',
80
- )
81
- })
82
-
83
- it('should return InstanceDestroying for destroying instance', () => {
56
+ it('should return DIError.instanceDestroying for destroying instance', () => {
84
57
  const holder = manager.storeCreatedHolder(
85
58
  'destroying-instance',
86
59
  { value: 'test' },
@@ -94,7 +67,7 @@ describe('ServiceLocatorManager', () => {
94
67
  const result = manager.get('destroying-instance')
95
68
 
96
69
  expect(result).toHaveLength(2)
97
- expect(result[0]).toBeInstanceOf(InstanceDestroying)
70
+ expect(result[0]).toBeInstanceOf(DIError)
98
71
  expect(result[1]).toBe(holder)
99
72
  expect(mockLogger.log).toHaveBeenCalledWith(
100
73
  '[ServiceLocatorManager]#getInstanceHolder() Instance destroying-instance is destroying',
@@ -111,35 +84,18 @@ describe('ServiceLocatorManager', () => {
111
84
 
112
85
  // Manually set status to error with an error instance
113
86
  holder.status = ServiceLocatorInstanceHolderStatus.Error
114
- const errorInstance = new InstanceNotFound('error-instance')
87
+ const errorInstance = DIError.instanceNotFound('error-instance')
115
88
  holder.instance = errorInstance
116
89
 
117
90
  const result = manager.get('error-instance')
118
91
 
119
92
  expect(result).toHaveLength(2)
120
- expect(result[0]).toBeInstanceOf(InstanceNotFound)
93
+ expect(result[0]).toBeInstanceOf(DIError)
121
94
  expect(result[1]).toBe(holder)
122
95
  expect(mockLogger.log).toHaveBeenCalledWith(
123
96
  '[ServiceLocatorManager]#getInstanceHolder() Instance error-instance is in error state',
124
97
  )
125
98
  })
126
-
127
- it('should handle instance with infinite TTL correctly', () => {
128
- const holder = manager.storeCreatedHolder(
129
- 'infinite-ttl-instance',
130
- { value: 'test' },
131
- InjectableType.Class,
132
- InjectableScope.Singleton,
133
- new Set(),
134
- Infinity,
135
- )
136
-
137
- const result = manager.get('infinite-ttl-instance')
138
-
139
- expect(result).toHaveLength(2)
140
- expect(result[0]).toBeUndefined()
141
- expect(result[1]).toBe(holder)
142
- })
143
99
  })
144
100
 
145
101
  describe('set', () => {
@@ -184,24 +140,6 @@ describe('ServiceLocatorManager', () => {
184
140
  expect(result[1]).toBe(true)
185
141
  })
186
142
 
187
- it('should return error for expired instance', () => {
188
- const holder = manager.storeCreatedHolder(
189
- 'expired-instance',
190
- { value: 'test' },
191
- InjectableType.Class,
192
- InjectableScope.Singleton,
193
- new Set(),
194
- 100,
195
- )
196
-
197
- holder.createdAt = Date.now() - 200
198
-
199
- const result = manager.has('expired-instance')
200
-
201
- expect(result).toHaveLength(1)
202
- expect(result[0]).toBeInstanceOf(InstanceExpired)
203
- })
204
-
205
143
  it('should return error for destroying instance', () => {
206
144
  const holder = manager.storeCreatedHolder(
207
145
  'destroying-instance',
@@ -215,7 +153,7 @@ describe('ServiceLocatorManager', () => {
215
153
  const result = manager.has('destroying-instance')
216
154
 
217
155
  expect(result).toHaveLength(1)
218
- expect(result[0]).toBeInstanceOf(InstanceDestroying)
156
+ expect(result[0]).toBeInstanceOf(DIError)
219
157
  })
220
158
  })
221
159
 
@@ -233,7 +171,7 @@ describe('ServiceLocatorManager', () => {
233
171
 
234
172
  const getResult = manager.get('test-instance')
235
173
  expect(getResult).toHaveLength(1)
236
- expect(getResult[0]).toBeInstanceOf(InstanceNotFound)
174
+ expect(getResult[0]).toBeInstanceOf(DIError)
237
175
  })
238
176
 
239
177
  it('should return false for non-existent instance', () => {
@@ -299,23 +237,19 @@ describe('ServiceLocatorManager', () => {
299
237
  expect(holder.type).toBe(InjectableType.Class)
300
238
  expect(holder.scope).toBe(InjectableScope.Singleton)
301
239
  expect(holder.deps).toEqual(new Set())
302
- expect(holder.ttl).toBe(Infinity)
303
240
  })
304
241
 
305
- it('should create holder with custom dependencies and TTL', () => {
242
+ it('should create holder with custom dependencies', () => {
306
243
  const deps = new Set(['dep1', 'dep2'])
307
- const ttl = 5000
308
244
 
309
- const [deferred, holder] = manager.createCreatingHolder(
245
+ const [, holder] = manager.createCreatingHolder(
310
246
  'test-instance',
311
247
  InjectableType.Factory,
312
248
  InjectableScope.Request,
313
249
  deps,
314
- ttl,
315
250
  )
316
251
 
317
252
  expect(holder.deps).toBe(deps)
318
- expect(holder.ttl).toBe(ttl)
319
253
  expect(holder.type).toBe(InjectableType.Factory)
320
254
  expect(holder.scope).toBe(InjectableScope.Request)
321
255
  })
@@ -338,7 +272,6 @@ describe('ServiceLocatorManager', () => {
338
272
  expect(holder.type).toBe(InjectableType.Class)
339
273
  expect(holder.scope).toBe(InjectableScope.Singleton)
340
274
  expect(holder.deps).toEqual(new Set())
341
- expect(holder.ttl).toBe(Infinity)
342
275
 
343
276
  // Verify it's stored
344
277
  const getResult = manager.get('test-instance')
@@ -347,9 +280,8 @@ describe('ServiceLocatorManager', () => {
347
280
  expect(getResult[1]).toBe(holder)
348
281
  })
349
282
 
350
- it('should create holder with custom dependencies and TTL', () => {
283
+ it('should create holder with custom dependencies', () => {
351
284
  const deps = new Set(['dep1', 'dep2'])
352
- const ttl = 5000
353
285
  const instance = { value: 'test' }
354
286
 
355
287
  const holder = manager.storeCreatedHolder(
@@ -358,11 +290,9 @@ describe('ServiceLocatorManager', () => {
358
290
  InjectableType.Factory,
359
291
  InjectableScope.Request,
360
292
  deps,
361
- ttl,
362
293
  )
363
294
 
364
295
  expect(holder.deps).toBe(deps)
365
- expect(holder.ttl).toBe(ttl)
366
296
  expect(holder.type).toBe(InjectableType.Factory)
367
297
  expect(holder.scope).toBe(InjectableScope.Request)
368
298
  })