@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
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">93.93% </span>
26
+ <span class="strong">94.94% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>155/165</span>
28
+ <span class='fraction'>188/198</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">95.12% </span>
33
+ <span class="strong">92% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>39/41</span>
35
+ <span class='fraction'>23/25</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">94.11% </span>
40
+ <span class="strong">88.88% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>16/17</span>
42
+ <span class='fraction'>8/9</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">93.93% </span>
47
+ <span class="strong">94.94% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>155/165</span>
49
+ <span class='fraction'>188/198</span>
50
50
  </div>
51
51
 
52
52
 
@@ -84,13 +84,13 @@
84
84
  <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
85
85
  </td>
86
86
  <td data-value="100" class="pct high">100%</td>
87
- <td data-value="39" class="abs high">39/39</td>
87
+ <td data-value="73" class="abs high">73/73</td>
88
88
  <td data-value="100" class="pct high">100%</td>
89
- <td data-value="16" class="abs high">16/16</td>
89
+ <td data-value="0" class="abs high">0/0</td>
90
90
  <td data-value="100" class="pct high">100%</td>
91
- <td data-value="8" class="abs high">8/8</td>
91
+ <td data-value="0" class="abs high">0/0</td>
92
92
  <td data-value="100" class="pct high">100%</td>
93
- <td data-value="39" class="abs high">39/39</td>
93
+ <td data-value="73" class="abs high">73/73</td>
94
94
  </tr>
95
95
 
96
96
  <tr>
@@ -129,13 +129,13 @@
129
129
  <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
130
130
  </td>
131
131
  <td data-value="100" class="pct high">100%</td>
132
- <td data-value="4" class="abs high">4/4</td>
132
+ <td data-value="3" class="abs high">3/3</td>
133
133
  <td data-value="100" class="pct high">100%</td>
134
134
  <td data-value="0" class="abs high">0/0</td>
135
135
  <td data-value="100" class="pct high">100%</td>
136
136
  <td data-value="0" class="abs high">0/0</td>
137
137
  <td data-value="100" class="pct high">100%</td>
138
- <td data-value="4" class="abs high">4/4</td>
138
+ <td data-value="3" class="abs high">3/3</td>
139
139
  </tr>
140
140
 
141
141
  <tr>
@@ -161,7 +161,7 @@
161
161
  <div class='footer quiet pad2 space-top1 center small'>
162
162
  Code coverage generated by
163
163
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
164
- at 2025-09-19T12:38:51.382Z
164
+ at 2025-09-21T17:47:07.632Z
165
165
  </div>
166
166
  <script src="../../prettify.js"></script>
167
167
  <script>
@@ -25,7 +25,7 @@
25
25
  <div class='fl pad1y space-right2'>
26
26
  <span class="strong">100% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>4/4</span>
28
+ <span class='fraction'>3/3</span>
29
29
  </div>
30
30
 
31
31
 
@@ -46,7 +46,7 @@
46
46
  <div class='fl pad1y space-right2'>
47
47
  <span class="strong">100% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>4/4</span>
49
+ <span class='fraction'>3/3</span>
50
50
  </div>
51
51
 
52
52
 
@@ -66,14 +66,11 @@
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
68
68
  <a name='L3'></a><a href='#L3'>3</a>
69
- <a name='L4'></a><a href='#L4'>4</a>
70
- <a name='L5'></a><a href='#L5'>5</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
71
- <span class="cline-any cline-yes">1x</span>
69
+ <a name='L4'></a><a href='#L4'>4</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
72
70
  <span class="cline-any cline-yes">1x</span>
73
71
  <span class="cline-any cline-yes">1x</span>
74
72
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">export * from './get-injectors.mjs'
75
73
  export * from './get-injectable-token.mjs'
76
- export * from './defer.mjs'
77
74
  export * from './types.mjs'
78
75
  &nbsp;</pre></td></tr></table></pre>
79
76
 
@@ -82,7 +79,7 @@ export * from './types.mjs'
82
79
  <div class='footer quiet pad2 space-top1 center small'>
83
80
  Code coverage generated by
84
81
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
85
- at 2025-09-19T12:38:51.382Z
82
+ at 2025-09-21T17:47:07.632Z
86
83
  </div>
87
84
  <script src="../../prettify.js"></script>
88
85
  <script>
@@ -226,7 +226,7 @@ export interface InjectState {
226
226
  <div class='footer quiet pad2 space-top1 center small'>
227
227
  Code coverage generated by
228
228
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
229
- at 2025-09-19T12:38:51.382Z
229
+ at 2025-09-21T17:47:07.632Z
230
230
  </div>
231
231
  <script src="../../prettify.js"></script>
232
232
  <script>
@@ -112,14 +112,14 @@ class NotificationService {
112
112
  }
113
113
  ```
114
114
 
115
- **Important:** `inject` only works with singleton services. For transient services, use `asyncInject` instead.
115
+ **Important:** The `inject` helper now supports all service scopes including Transient. When using `inject` with Transient services, the dependency is tracked for async initialization and will be available in your service methods after initialization completes.
116
116
 
117
- ### Asynchronous Injection with `inject`
117
+ ### Asynchronous Injection with `asyncInject`
118
118
 
119
- Use `inject` for services that might not be immediately available:
119
+ Use `asyncInject` when you need explicit async control over dependency resolution:
120
120
 
121
121
  ```typescript
122
- import { inject, Injectable } from '@navios/di'
122
+ import { asyncInject, Injectable, InjectableScope } from '@navios/di'
123
123
 
124
124
  @Injectable({ scope: InjectableScope.Transient })
125
125
  class TransientService {
@@ -143,6 +143,31 @@ class ConsumerService {
143
143
  }
144
144
  ```
145
145
 
146
+ ### Using `inject` with Transient Services
147
+
148
+ You can now use `inject` with Transient services. The dependency will be tracked for async initialization:
149
+
150
+ ```typescript
151
+ import { inject, Injectable, InjectableScope } from '@navios/di'
152
+
153
+ @Injectable({ scope: InjectableScope.Transient })
154
+ class TransientService {
155
+ getValue() {
156
+ return Math.random()
157
+ }
158
+ }
159
+
160
+ @Injectable()
161
+ class ConsumerService {
162
+ private readonly transientService = inject(TransientService)
163
+
164
+ async getRandomValue() {
165
+ // Service is available in async methods after initialization
166
+ return this.transientService.getValue()
167
+ }
168
+ }
169
+ ```
170
+
146
171
  ## Advanced Patterns
147
172
 
148
173
  ### Service with Configuration Schema
@@ -319,15 +344,19 @@ class TransientService {
319
344
 
320
345
  @Injectable()
321
346
  class ConsumerService {
322
- // Only asyncInject() works with transient services
323
- private readonly transientService = asyncInject(TransientService)
347
+ // Both inject() and asyncInject() now work with transient services
348
+ private readonly transientService = inject(TransientService)
349
+ private readonly asyncTransientService = asyncInject(TransientService)
324
350
 
325
351
  async demonstrate() {
326
- const instance1 = await this.transientService
327
- const instance2 = await this.transientService
352
+ // Using inject with transient services (available after initialization)
353
+ console.log(this.transientService.getId())
328
354
 
329
- console.log(instance1.getId()) // Different ID
330
- console.log(instance2.getId()) // Different ID
355
+ // Using asyncInject for explicit async access
356
+ const instance1 = await this.asyncTransientService
357
+ const instance2 = await this.asyncTransientService
358
+ console.log(instance1.getId()) // Same as first call
359
+ console.log(instance2.getId()) // Same as first call
331
360
  }
332
361
  }
333
362
  ```
@@ -397,7 +426,18 @@ class UserService {
397
426
  }
398
427
  }
399
428
 
400
- // ✅ Good: Use asyncInject for transient dependencies
429
+ // ✅ Good: Use inject or asyncInject for transient dependencies
430
+ @Injectable()
431
+ class RequestService {
432
+ // inject now works with transient services
433
+ private readonly transientService = inject(TransientService)
434
+
435
+ async handleRequest() {
436
+ return this.transientService.process()
437
+ }
438
+ }
439
+
440
+ // ✅ Also good: Use asyncInject for explicit async control
401
441
  @Injectable()
402
442
  class RequestService {
403
443
  private readonly transientService = asyncInject(TransientService)
package/docs/scopes.md CHANGED
@@ -184,8 +184,8 @@ class RequestHandler {
184
184
  private readonly requestId = Math.random().toString(36)
185
185
 
186
186
  async handleRequest() {
187
- const logger = await this.logger
188
- logger.log(`Handling request ${this.requestId}`)
187
+ // Logger is available in async methods
188
+ this.logger.log(`Handling request ${this.requestId}`)
189
189
  return { requestId: this.requestId, status: 'processed' }
190
190
  }
191
191
  }
@@ -336,37 +336,52 @@ await container.endRequest('req-2')
336
336
 
337
337
  ### Injection Method Compatibility
338
338
 
339
- | Scope | inject | asyncInject |
340
- | --------- | ---------------- | ------------ |
341
- | Singleton | ✅ Supported | ✅ Supported |
342
- | Transient | Not Supported | ✅ Supported |
343
- | Request | ✅ Supported | ✅ Supported |
339
+ | Scope | inject | asyncInject |
340
+ | --------- | ----------------------------------- | ------------ |
341
+ | Singleton | ✅ Supported | ✅ Supported |
342
+ | Transient | Supported (async initialization) | ✅ Supported |
343
+ | Request | ✅ Supported | ✅ Supported |
344
+
345
+ ### Using inject with Transient Services
344
346
 
345
- ### Why inject Doesn't Work with Transient
347
+ The `inject` helper now supports Transient services through automatic async initialization tracking. When you use `inject` with a Transient service, the DI system tracks the async dependencies and ensures they're resolved before the service is fully initialized.
346
348
 
347
349
  ```typescript
348
- // ❌ This will cause an error
349
350
  @Injectable({ scope: InjectableScope.Transient })
350
- class TransientService {}
351
+ class TransientService {
352
+ async onServiceInit() {
353
+ console.log('Transient service initialized')
354
+ }
355
+ }
351
356
 
352
357
  @Injectable()
353
358
  class ConsumerService {
359
+ // ✅ This now works! The inject helper tracks async initialization
354
360
  private readonly service = inject(TransientService)
355
- // Error: Cannot use inject with transient services
361
+
362
+ async doSomething() {
363
+ // The service will be available after initialization completes
364
+ this.service.someMethod()
365
+ }
356
366
  }
357
367
 
358
- // ✅ Use inject instead
368
+ // ✅ You can still use asyncInject for explicit async access
359
369
  @Injectable()
360
370
  class ConsumerService {
361
371
  private readonly service = asyncInject(TransientService)
362
372
 
363
373
  async doSomething() {
364
374
  const service = await this.service
365
- // Use the service
375
+ service.someMethod()
366
376
  }
367
377
  }
368
378
  ```
369
379
 
380
+ **Important Notes:**
381
+ - When using `inject` with Transient services, the dependency won't be immediately available during constructor execution
382
+ - Access the service only in async methods or after the service initialization completes
383
+ - For synchronous access during construction, use `asyncInject` and await it explicitly
384
+
370
385
  ## Real-World Examples
371
386
 
372
387
  ### Singleton: Database Connection Pool
@@ -414,7 +429,7 @@ class DatabasePool implements OnServiceInit, OnServiceDestroy {
414
429
  ### Transient: Request Context
415
430
 
416
431
  ```typescript
417
- import { Injectable, InjectableScope } from '@navios/di'
432
+ import { inject, Injectable, InjectableScope } from '@navios/di'
418
433
 
419
434
  @Injectable({ scope: InjectableScope.Transient })
420
435
  class RequestContext {
@@ -447,16 +462,17 @@ class RequestContext {
447
462
 
448
463
  @Injectable()
449
464
  class RequestHandler {
450
- private readonly context = asyncInject(RequestContext)
465
+ private readonly context = inject(RequestContext)
451
466
 
452
467
  async handleRequest() {
453
- const ctx = await this.context
454
- console.log(`Handling request ${ctx.getRequestId()} from ${ctx.getIp()}`)
468
+ console.log(
469
+ `Handling request ${this.context.getRequestId()} from ${this.context.getIp()}`,
470
+ )
455
471
 
456
472
  // Process request...
457
473
 
458
474
  console.log(
459
- `Request ${ctx.getRequestId()} completed in ${ctx.getDuration()}ms`,
475
+ `Request ${this.context.getRequestId()} completed in ${this.context.getDuration()}ms`,
460
476
  )
461
477
  }
462
478
  }
@@ -465,7 +481,7 @@ class RequestHandler {
465
481
  ### Mixed Scopes
466
482
 
467
483
  ```typescript
468
- import { asyncInject, inject, Injectable, InjectableScope } from '@navios/di'
484
+ import { inject, Injectable, InjectableScope } from '@navios/di'
469
485
 
470
486
  // Singleton services
471
487
  @Injectable()
@@ -506,19 +522,18 @@ class UserSession {
506
522
  class UserService {
507
523
  private readonly config = inject(ConfigService) // Singleton
508
524
  private readonly logger = inject(LoggerService) // Singleton
509
- private readonly session = asyncInject(UserSession) // Transient
525
+ private readonly session = inject(UserSession) // Transient (with async initialization)
510
526
 
511
527
  async authenticateUser(userId: string) {
512
528
  this.logger.log(`Authenticating user ${userId}`)
513
529
 
514
- const session = await this.session
515
530
  this.logger.log(
516
- `Created session ${session.getSessionId()} for user ${userId}`,
531
+ `Created session ${this.session.getSessionId()} for user ${userId}`,
517
532
  )
518
533
 
519
534
  return {
520
535
  userId,
521
- sessionId: session.getSessionId(),
536
+ sessionId: this.session.getSessionId(),
522
537
  apiUrl: this.config.getConfig().apiUrl,
523
538
  }
524
539
  }
@@ -668,27 +683,46 @@ class RequestCache {
668
683
  }
669
684
  ```
670
685
 
671
- ### 2. Incorrect Injection Method
686
+ ### 2. Accessing Transient Services Too Early
672
687
 
673
688
  ```typescript
674
- // ❌ Problem: Using inject with transient
689
+ // ❌ Problem: Accessing transient service during construction
675
690
  @Injectable({ scope: InjectableScope.Transient })
676
- class TransientService {}
691
+ class TransientService {
692
+ getData() {
693
+ return 'data'
694
+ }
695
+ }
677
696
 
678
697
  @Injectable()
679
698
  class ConsumerService {
680
699
  private readonly service = inject(TransientService)
681
- // Error: Cannot use inject with transient services
700
+
701
+ constructor() {
702
+ // Error: Service not initialized yet during construction!
703
+ console.log(this.service.getData())
704
+ }
705
+ }
706
+
707
+ // ✅ Solution 1: Access in async methods after initialization
708
+ @Injectable()
709
+ class ConsumerService {
710
+ private readonly service = inject(TransientService)
711
+
712
+ async doSomething() {
713
+ // Service is available in methods
714
+ console.log(this.service.getData())
715
+ }
682
716
  }
683
717
 
684
- // ✅ Solution: Use asyncInject with transient
718
+ // ✅ Solution 2: Use asyncInject for explicit control
685
719
  @Injectable()
686
720
  class ConsumerService {
687
721
  private readonly service = asyncInject(TransientService)
688
722
 
689
723
  async doSomething() {
690
724
  const service = await this.service
691
- // Use the service
725
+ console.log(service.getData())
692
726
  }
693
727
  }
694
728
  ```