@navios/di 0.5.0 → 0.6.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.
- package/CHANGELOG.md +146 -0
- package/README.md +196 -219
- package/docs/README.md +69 -11
- package/docs/api-reference.md +281 -117
- package/docs/container.md +220 -56
- package/docs/examples/request-scope-example.mts +2 -2
- package/docs/factory.md +3 -8
- package/docs/getting-started.md +37 -8
- package/docs/migration.md +318 -37
- package/docs/request-contexts.md +263 -175
- package/docs/scopes.md +79 -42
- package/lib/browser/index.d.mts +1577 -0
- package/lib/browser/index.d.mts.map +1 -0
- package/lib/browser/index.mjs +3012 -0
- package/lib/browser/index.mjs.map +1 -0
- package/lib/index-S_qX2VLI.d.mts +1211 -0
- package/lib/index-S_qX2VLI.d.mts.map +1 -0
- package/lib/index-fKPuT65j.d.cts +1206 -0
- package/lib/index-fKPuT65j.d.cts.map +1 -0
- package/lib/index.cjs +389 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +376 -0
- package/lib/index.d.cts.map +1 -0
- package/lib/index.d.mts +371 -78
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +325 -63
- package/lib/index.mjs.map +1 -1
- package/lib/testing/index.cjs +9 -0
- package/lib/testing/index.d.cts +2 -0
- package/lib/testing/index.d.mts +2 -2
- package/lib/testing/index.mjs +2 -72
- package/lib/testing-BMGmmxH7.cjs +2895 -0
- package/lib/testing-BMGmmxH7.cjs.map +1 -0
- package/lib/testing-DCXz8AJD.mjs +2655 -0
- package/lib/testing-DCXz8AJD.mjs.map +1 -0
- package/package.json +26 -4
- package/project.json +2 -2
- package/src/__tests__/async-local-storage.browser.spec.mts +240 -0
- package/src/__tests__/async-local-storage.spec.mts +333 -0
- package/src/__tests__/container.spec.mts +30 -25
- package/src/__tests__/e2e.browser.spec.mts +790 -0
- package/src/__tests__/e2e.spec.mts +1222 -0
- package/src/__tests__/errors.spec.mts +6 -6
- package/src/__tests__/factory.spec.mts +1 -1
- package/src/__tests__/get-injectors.spec.mts +1 -1
- package/src/__tests__/injectable.spec.mts +1 -1
- package/src/__tests__/injection-token.spec.mts +1 -1
- package/src/__tests__/library-findings.spec.mts +563 -0
- package/src/__tests__/registry.spec.mts +2 -2
- package/src/__tests__/request-scope.spec.mts +266 -274
- package/src/__tests__/service-instantiator.spec.mts +19 -17
- package/src/__tests__/service-locator-event-bus.spec.mts +9 -9
- package/src/__tests__/service-locator-manager.spec.mts +15 -15
- package/src/__tests__/service-locator.spec.mts +167 -244
- package/src/__tests__/unified-api.spec.mts +27 -27
- package/src/__type-tests__/factory.spec-d.mts +2 -2
- package/src/__type-tests__/inject.spec-d.mts +2 -2
- package/src/__type-tests__/injectable.spec-d.mts +1 -1
- package/src/browser.mts +16 -0
- package/src/container/container.mts +319 -0
- package/src/container/index.mts +2 -0
- package/src/container/scoped-container.mts +350 -0
- package/src/decorators/factory.decorator.mts +4 -4
- package/src/decorators/injectable.decorator.mts +5 -5
- package/src/errors/di-error.mts +13 -7
- package/src/errors/index.mts +0 -8
- package/src/index.mts +156 -15
- package/src/interfaces/container.interface.mts +82 -0
- package/src/interfaces/factory.interface.mts +2 -2
- package/src/interfaces/index.mts +1 -0
- package/src/internal/context/async-local-storage.mts +120 -0
- package/src/internal/context/factory-context.mts +18 -0
- package/src/internal/context/index.mts +3 -0
- package/src/{request-context-holder.mts → internal/context/request-context.mts} +40 -27
- package/src/internal/context/resolution-context.mts +63 -0
- package/src/internal/context/sync-local-storage.mts +51 -0
- package/src/internal/core/index.mts +5 -0
- package/src/internal/core/instance-resolver.mts +641 -0
- package/src/{service-instantiator.mts → internal/core/instantiator.mts} +31 -27
- package/src/internal/core/invalidator.mts +437 -0
- package/src/internal/core/service-locator.mts +202 -0
- package/src/{token-processor.mts → internal/core/token-processor.mts} +79 -60
- package/src/{base-instance-holder-manager.mts → internal/holder/base-holder-manager.mts} +91 -21
- package/src/internal/holder/holder-manager.mts +85 -0
- package/src/internal/holder/holder-storage.interface.mts +116 -0
- package/src/internal/holder/index.mts +6 -0
- package/src/internal/holder/instance-holder.mts +109 -0
- package/src/internal/holder/request-storage.mts +134 -0
- package/src/internal/holder/singleton-storage.mts +105 -0
- package/src/internal/index.mts +4 -0
- package/src/internal/lifecycle/circular-detector.mts +77 -0
- package/src/internal/lifecycle/index.mts +2 -0
- package/src/{service-locator-event-bus.mts → internal/lifecycle/lifecycle-event-bus.mts} +12 -5
- package/src/testing/__tests__/test-container.spec.mts +2 -2
- package/src/testing/test-container.mts +4 -4
- package/src/token/index.mts +2 -0
- package/src/{injection-token.mts → token/injection-token.mts} +1 -1
- package/src/{registry.mts → token/registry.mts} +1 -1
- package/src/utils/get-injectable-token.mts +1 -1
- package/src/utils/get-injectors.mts +32 -15
- package/src/utils/types.mts +1 -1
- package/tsdown.config.mts +67 -0
- package/lib/_tsup-dts-rollup.d.mts +0 -1283
- package/lib/_tsup-dts-rollup.d.ts +0 -1283
- package/lib/chunk-44F3LXW5.mjs +0 -2043
- package/lib/chunk-44F3LXW5.mjs.map +0 -1
- package/lib/index.d.ts +0 -78
- package/lib/index.js +0 -2127
- package/lib/index.js.map +0 -1
- package/lib/testing/index.d.ts +0 -2
- package/lib/testing/index.js +0 -2060
- package/lib/testing/index.js.map +0 -1
- package/lib/testing/index.mjs.map +0 -1
- package/src/container.mts +0 -227
- package/src/factory-context.mts +0 -8
- package/src/instance-resolver.mts +0 -559
- package/src/request-context-manager.mts +0 -149
- package/src/service-invalidator.mts +0 -429
- package/src/service-locator-instance-holder.mts +0 -70
- package/src/service-locator-manager.mts +0 -85
- package/src/service-locator.mts +0 -246
- package/tsup.config.mts +0 -12
- /package/src/{injector.mts → injectors.mts} +0 -0
package/docs/container.md
CHANGED
|
@@ -9,6 +9,7 @@ The Container wraps a `ServiceLocator` instance and provides convenient methods
|
|
|
9
9
|
- Getting service instances
|
|
10
10
|
- Invalidating services and their dependencies
|
|
11
11
|
- Managing service lifecycle
|
|
12
|
+
- Creating request-scoped containers via `ScopedContainer`
|
|
12
13
|
- Accessing the underlying service locator for advanced usage
|
|
13
14
|
|
|
14
15
|
## Basic Usage
|
|
@@ -26,14 +27,7 @@ const customRegistry = new Registry()
|
|
|
26
27
|
const container = new Container(customRegistry)
|
|
27
28
|
|
|
28
29
|
// Create with custom registry and logger
|
|
29
|
-
const
|
|
30
|
-
log: console.log,
|
|
31
|
-
error: console.error,
|
|
32
|
-
warn: console.warn,
|
|
33
|
-
info: console.info,
|
|
34
|
-
debug: console.debug,
|
|
35
|
-
}
|
|
36
|
-
const container = new Container(customRegistry, mockLogger)
|
|
30
|
+
const container = new Container(customRegistry, console)
|
|
37
31
|
```
|
|
38
32
|
|
|
39
33
|
### Getting Service Instances
|
|
@@ -131,6 +125,25 @@ await container.ready()
|
|
|
131
125
|
const [userService, emailService, dbService] = await Promise.all(promises)
|
|
132
126
|
```
|
|
133
127
|
|
|
128
|
+
### Synchronous Instance Access
|
|
129
|
+
|
|
130
|
+
Use `tryGetSync` to get an instance synchronously if it already exists:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const container = new Container()
|
|
134
|
+
|
|
135
|
+
// First, ensure the service is created
|
|
136
|
+
await container.get(UserService)
|
|
137
|
+
|
|
138
|
+
// Now you can get it synchronously
|
|
139
|
+
const userService = container.tryGetSync(UserService)
|
|
140
|
+
if (userService) {
|
|
141
|
+
console.log('Service already exists:', userService)
|
|
142
|
+
} else {
|
|
143
|
+
console.log('Service not yet created')
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
134
147
|
### Accessing the Service Locator
|
|
135
148
|
|
|
136
149
|
For advanced usage, you can access the underlying `ServiceLocator`:
|
|
@@ -145,37 +158,86 @@ const instance = await serviceLocator.getOrThrowInstance(UserService)
|
|
|
145
158
|
|
|
146
159
|
## Request Context Management
|
|
147
160
|
|
|
148
|
-
The Container provides built-in support for request contexts
|
|
161
|
+
The Container provides built-in support for request contexts via `ScopedContainer`. This allows you to manage request-scoped services with proper isolation between concurrent requests.
|
|
162
|
+
|
|
163
|
+
### Creating a ScopedContainer
|
|
149
164
|
|
|
150
165
|
```typescript
|
|
166
|
+
import { Container, Injectable, InjectableScope } from '@navios/di'
|
|
167
|
+
|
|
168
|
+
@Injectable({ scope: InjectableScope.Request })
|
|
169
|
+
class RequestContext {
|
|
170
|
+
userId?: string
|
|
171
|
+
correlationId?: string
|
|
172
|
+
}
|
|
173
|
+
|
|
151
174
|
const container = new Container()
|
|
152
175
|
|
|
153
|
-
// Begin a request context
|
|
154
|
-
const
|
|
176
|
+
// Begin a request context - returns a ScopedContainer
|
|
177
|
+
const scoped = container.beginRequest('req-123', {
|
|
178
|
+
userId: 'user-456',
|
|
179
|
+
correlationId: 'corr-789',
|
|
180
|
+
})
|
|
155
181
|
|
|
156
|
-
//
|
|
157
|
-
const
|
|
158
|
-
context.addInstance(REQUEST_ID_TOKEN, 'req-123')
|
|
182
|
+
// Get request-scoped services from the ScopedContainer
|
|
183
|
+
const context = await scoped.get(RequestContext)
|
|
159
184
|
|
|
160
|
-
//
|
|
161
|
-
|
|
185
|
+
// Access metadata
|
|
186
|
+
const userId = scoped.getMetadata('userId')
|
|
162
187
|
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
private readonly requestId = asyncInject(REQUEST_ID_TOKEN)
|
|
188
|
+
// Clean up when done
|
|
189
|
+
await scoped.endRequest()
|
|
190
|
+
```
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
const id = await this.requestId
|
|
170
|
-
console.log(`Processing in request: ${id}`)
|
|
171
|
-
}
|
|
172
|
-
}
|
|
192
|
+
### Why ScopedContainer?
|
|
173
193
|
|
|
174
|
-
|
|
175
|
-
await service.process() // "Processing in request: req-123"
|
|
194
|
+
The `ScopedContainer` pattern eliminates race conditions that occurred with the old API:
|
|
176
195
|
|
|
177
|
-
|
|
178
|
-
|
|
196
|
+
```typescript
|
|
197
|
+
// OLD API (removed) - had race conditions:
|
|
198
|
+
// container.setCurrentRequestContext('req-A')
|
|
199
|
+
// const serviceA = await container.get(RequestService) // async...
|
|
200
|
+
// container.setCurrentRequestContext('req-B') // Request B starts while A is resolving
|
|
201
|
+
// Service A might get Request B's context! Bug!
|
|
202
|
+
|
|
203
|
+
// NEW API - no race conditions:
|
|
204
|
+
const scopedA = container.beginRequest('req-A')
|
|
205
|
+
const serviceA = await scopedA.get(RequestService) // Always gets A's context
|
|
206
|
+
|
|
207
|
+
const scopedB = container.beginRequest('req-B')
|
|
208
|
+
const serviceB = await scopedB.get(RequestService) // Always gets B's context
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Request-Scoped Service Error
|
|
212
|
+
|
|
213
|
+
Attempting to get a request-scoped service from the main Container throws an error:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
@Injectable({ scope: InjectableScope.Request })
|
|
217
|
+
class RequestService {}
|
|
218
|
+
|
|
219
|
+
// ❌ This throws an error
|
|
220
|
+
await container.get(RequestService)
|
|
221
|
+
// Error: Cannot resolve request-scoped service "RequestService" from Container.
|
|
222
|
+
// Use beginRequest() to create a ScopedContainer for request-scoped services.
|
|
223
|
+
|
|
224
|
+
// ✅ Use ScopedContainer instead
|
|
225
|
+
const scoped = container.beginRequest('req-123')
|
|
226
|
+
const service = await scoped.get(RequestService)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Tracking Active Requests
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
const scoped1 = container.beginRequest('req-1')
|
|
233
|
+
const scoped2 = container.beginRequest('req-2')
|
|
234
|
+
|
|
235
|
+
// Check active requests
|
|
236
|
+
console.log(container.hasActiveRequest('req-1')) // true
|
|
237
|
+
console.log(container.getActiveRequestIds()) // Set { 'req-1', 'req-2' }
|
|
238
|
+
|
|
239
|
+
await scoped1.endRequest()
|
|
240
|
+
console.log(container.hasActiveRequest('req-1')) // false
|
|
179
241
|
```
|
|
180
242
|
|
|
181
243
|
## Best Practices
|
|
@@ -220,13 +282,22 @@ await container.invalidate(userSessionService)
|
|
|
220
282
|
### 3. Handle Errors Gracefully
|
|
221
283
|
|
|
222
284
|
```typescript
|
|
285
|
+
import { DIError, DIErrorCode } from '@navios/di'
|
|
286
|
+
|
|
223
287
|
try {
|
|
224
288
|
const service = await container.get(NonExistentService)
|
|
225
289
|
} catch (error) {
|
|
226
|
-
if (error instanceof
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
290
|
+
if (error instanceof DIError) {
|
|
291
|
+
switch (error.code) {
|
|
292
|
+
case DIErrorCode.FactoryNotFound:
|
|
293
|
+
console.error('Service not registered:', error.message)
|
|
294
|
+
break
|
|
295
|
+
case DIErrorCode.CircularDependency:
|
|
296
|
+
console.error('Circular dependency:', error.message)
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
console.error('DI error:', error.message)
|
|
300
|
+
}
|
|
230
301
|
}
|
|
231
302
|
}
|
|
232
303
|
```
|
|
@@ -253,33 +324,50 @@ const paymentContainer = new Container(paymentRegistry)
|
|
|
253
324
|
### 5. Manage Request Contexts Properly
|
|
254
325
|
|
|
255
326
|
```typescript
|
|
256
|
-
// Always clean up request contexts
|
|
327
|
+
// Always clean up request contexts with try/finally
|
|
257
328
|
async function handleRequest(req, res) {
|
|
258
329
|
const requestId = generateRequestId()
|
|
259
|
-
const
|
|
330
|
+
const scoped = container.beginRequest(requestId, {
|
|
260
331
|
ip: req.ip,
|
|
261
332
|
userAgent: req.get('User-Agent'),
|
|
262
333
|
})
|
|
263
334
|
|
|
264
335
|
try {
|
|
265
|
-
|
|
266
|
-
await
|
|
336
|
+
const service = await scoped.get(RequestHandler)
|
|
337
|
+
await service.handle(req, res)
|
|
267
338
|
} finally {
|
|
268
|
-
await
|
|
339
|
+
await scoped.endRequest()
|
|
269
340
|
}
|
|
270
341
|
}
|
|
271
342
|
```
|
|
272
343
|
|
|
344
|
+
### 6. Clean Up on Shutdown
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
async function shutdown() {
|
|
348
|
+
// Dispose the container to clean up all services
|
|
349
|
+
await container.dispose()
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
process.on('SIGTERM', shutdown)
|
|
353
|
+
process.on('SIGINT', shutdown)
|
|
354
|
+
```
|
|
355
|
+
|
|
273
356
|
## API Reference
|
|
274
357
|
|
|
275
358
|
### Constructor
|
|
276
359
|
|
|
277
360
|
```typescript
|
|
278
|
-
constructor(
|
|
361
|
+
constructor(
|
|
362
|
+
registry?: Registry,
|
|
363
|
+
logger?: Console | null,
|
|
364
|
+
injectors?: Injectors
|
|
365
|
+
)
|
|
279
366
|
```
|
|
280
367
|
|
|
281
368
|
- `registry`: Optional registry instance (defaults to global registry)
|
|
282
369
|
- `logger`: Optional logger instance for debugging
|
|
370
|
+
- `injectors`: Optional custom injectors
|
|
283
371
|
|
|
284
372
|
### Methods
|
|
285
373
|
|
|
@@ -295,6 +383,8 @@ Gets a service instance from the container.
|
|
|
295
383
|
- `get<T>(token: BoundInjectionToken<T, any>): Promise<T>`
|
|
296
384
|
- `get<T>(token: FactoryInjectionToken<T, any>): Promise<T>`
|
|
297
385
|
|
|
386
|
+
**Note:** Throws an error for request-scoped services. Use `ScopedContainer` instead.
|
|
387
|
+
|
|
298
388
|
#### `invalidate(service: unknown): Promise<void>`
|
|
299
389
|
|
|
300
390
|
Invalidates a service and its dependencies.
|
|
@@ -303,47 +393,121 @@ Invalidates a service and its dependencies.
|
|
|
303
393
|
|
|
304
394
|
Waits for all pending operations to complete.
|
|
305
395
|
|
|
396
|
+
#### `dispose(): Promise<void>`
|
|
397
|
+
|
|
398
|
+
Disposes the container and cleans up all resources.
|
|
399
|
+
|
|
400
|
+
#### `clear(): Promise<void>`
|
|
401
|
+
|
|
402
|
+
Clears all instances and bindings.
|
|
403
|
+
|
|
404
|
+
#### `isRegistered(token: any): boolean`
|
|
405
|
+
|
|
406
|
+
Checks if a service is registered.
|
|
407
|
+
|
|
408
|
+
#### `tryGetSync<T>(token: any, args?: any): T | null`
|
|
409
|
+
|
|
410
|
+
Gets an instance synchronously if it already exists and is ready.
|
|
411
|
+
|
|
306
412
|
#### `getServiceLocator(): ServiceLocator`
|
|
307
413
|
|
|
308
414
|
Returns the underlying ServiceLocator instance.
|
|
309
415
|
|
|
310
|
-
#### `
|
|
416
|
+
#### `getRegistry(): Registry`
|
|
311
417
|
|
|
312
|
-
|
|
418
|
+
Returns the registry used by this container.
|
|
419
|
+
|
|
420
|
+
#### `beginRequest(requestId: string, metadata?: Record<string, any>, priority?: number): ScopedContainer`
|
|
421
|
+
|
|
422
|
+
Begins a new request context and returns a `ScopedContainer`.
|
|
313
423
|
|
|
314
424
|
- `requestId`: Unique identifier for this request
|
|
315
425
|
- `metadata`: Optional metadata for the request
|
|
316
426
|
- `priority`: Priority for resolution (higher = more priority, defaults to 100)
|
|
317
427
|
|
|
318
|
-
#### `
|
|
428
|
+
#### `getActiveRequestIds(): ReadonlySet<string>`
|
|
319
429
|
|
|
320
|
-
|
|
430
|
+
Gets the set of active request IDs.
|
|
321
431
|
|
|
322
|
-
#### `
|
|
432
|
+
#### `hasActiveRequest(requestId: string): boolean`
|
|
323
433
|
|
|
324
|
-
|
|
434
|
+
Checks if a request is active.
|
|
325
435
|
|
|
326
|
-
|
|
436
|
+
## ScopedContainer API
|
|
327
437
|
|
|
328
|
-
|
|
438
|
+
The `ScopedContainer` is returned by `container.beginRequest()` and provides isolated request-scoped service resolution.
|
|
329
439
|
|
|
330
|
-
|
|
440
|
+
### Methods
|
|
441
|
+
|
|
442
|
+
#### `get<T>(token: T): Promise<InstanceType<T>>`
|
|
443
|
+
|
|
444
|
+
Gets a service instance. Request-scoped services are resolved from this container's context, others are delegated to the parent.
|
|
445
|
+
|
|
446
|
+
#### `invalidate(service: unknown): Promise<void>`
|
|
447
|
+
|
|
448
|
+
Invalidates a service within the request context.
|
|
331
449
|
|
|
332
|
-
|
|
450
|
+
#### `endRequest(): Promise<void>`
|
|
451
|
+
|
|
452
|
+
Ends the request and cleans up all request-scoped instances.
|
|
453
|
+
|
|
454
|
+
#### `dispose(): Promise<void>`
|
|
455
|
+
|
|
456
|
+
Alias for `endRequest()`.
|
|
457
|
+
|
|
458
|
+
#### `ready(): Promise<void>`
|
|
459
|
+
|
|
460
|
+
Waits for pending operations.
|
|
461
|
+
|
|
462
|
+
#### `getMetadata(key: string): any | undefined`
|
|
463
|
+
|
|
464
|
+
Gets request metadata.
|
|
465
|
+
|
|
466
|
+
#### `setMetadata(key: string, value: any): void`
|
|
467
|
+
|
|
468
|
+
Sets request metadata.
|
|
469
|
+
|
|
470
|
+
#### `addInstance(token: InjectionToken<any, undefined>, instance: any): void`
|
|
471
|
+
|
|
472
|
+
Adds a pre-prepared instance to the request context.
|
|
473
|
+
|
|
474
|
+
#### `getRequestId(): string`
|
|
475
|
+
|
|
476
|
+
Gets the request ID.
|
|
477
|
+
|
|
478
|
+
#### `getParent(): Container`
|
|
479
|
+
|
|
480
|
+
Gets the parent container.
|
|
481
|
+
|
|
482
|
+
#### `tryGetSync<T>(token: any, args?: any): T | null`
|
|
483
|
+
|
|
484
|
+
Gets an instance synchronously if it exists and is ready.
|
|
485
|
+
|
|
486
|
+
## Error Handling
|
|
333
487
|
|
|
334
|
-
|
|
335
|
-
- `InstanceExpiredError`: When a service instance has expired
|
|
336
|
-
- `InstanceDestroyingError`: When trying to access a service being destroyed
|
|
337
|
-
- `UnknownError`: For unexpected errors
|
|
488
|
+
The Container throws `DIError` with specific error codes:
|
|
338
489
|
|
|
339
490
|
```typescript
|
|
340
|
-
import {
|
|
491
|
+
import { DIError, DIErrorCode } from '@navios/di'
|
|
341
492
|
|
|
342
493
|
try {
|
|
343
494
|
const service = await container.get(UnregisteredService)
|
|
344
495
|
} catch (error) {
|
|
345
|
-
if (error instanceof
|
|
346
|
-
|
|
496
|
+
if (error instanceof DIError) {
|
|
497
|
+
switch (error.code) {
|
|
498
|
+
case DIErrorCode.FactoryNotFound:
|
|
499
|
+
console.error('Service not registered')
|
|
500
|
+
break
|
|
501
|
+
case DIErrorCode.InstanceDestroying:
|
|
502
|
+
console.error('Service is being destroyed')
|
|
503
|
+
break
|
|
504
|
+
case DIErrorCode.CircularDependency:
|
|
505
|
+
console.error('Circular dependency detected:', error.message)
|
|
506
|
+
break
|
|
507
|
+
case DIErrorCode.UnknownError:
|
|
508
|
+
console.error('Unknown error:', error.message)
|
|
509
|
+
break
|
|
510
|
+
}
|
|
347
511
|
}
|
|
348
512
|
}
|
|
349
513
|
```
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* where you need services that are shared within a request but isolated between requests.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Container } from '../../src/container.mjs'
|
|
8
|
+
import { Container } from '../../src/container/container.mjs'
|
|
9
9
|
import { Injectable } from '../../src/decorators/injectable.decorator.mjs'
|
|
10
10
|
import { InjectableScope } from '../../src/enums/index.mjs'
|
|
11
|
-
import { inject } from '../../src/
|
|
11
|
+
import { inject } from '../../src/injectors.mjs'
|
|
12
12
|
|
|
13
13
|
// ============================================================================
|
|
14
14
|
// EXAMPLE SERVICES
|
package/docs/factory.md
CHANGED
|
@@ -560,14 +560,9 @@ interface FactoryOptions {
|
|
|
560
560
|
|
|
561
561
|
```typescript
|
|
562
562
|
interface FactoryContext {
|
|
563
|
-
inject
|
|
564
|
-
locator: ServiceLocator
|
|
565
|
-
|
|
566
|
-
getDependencies(): any[]
|
|
567
|
-
invalidate(): Promise<void>
|
|
568
|
-
addEffect(effect: Function): void
|
|
569
|
-
setTtl(ttl: number): void
|
|
570
|
-
getTtl(): number | null
|
|
563
|
+
inject: typeof asyncInject // Inject dependencies asynchronously
|
|
564
|
+
locator: ServiceLocator // Access to the service locator
|
|
565
|
+
addDestroyListener: (listener: () => void | Promise<void>) => void // Register cleanup callback
|
|
571
566
|
}
|
|
572
567
|
```
|
|
573
568
|
|
package/docs/getting-started.md
CHANGED
|
@@ -50,7 +50,7 @@ import { asyncInject, Container, inject, Injectable } from '@navios/di'
|
|
|
50
50
|
Let's create a simple example with a user service that depends on an email service:
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
|
-
import {
|
|
53
|
+
import { Container, inject, Injectable } from '@navios/di'
|
|
54
54
|
|
|
55
55
|
// 1. Create an email service
|
|
56
56
|
@Injectable()
|
|
@@ -66,14 +66,13 @@ class EmailService {
|
|
|
66
66
|
// 2. Create a user service that depends on the email service
|
|
67
67
|
@Injectable()
|
|
68
68
|
class UserService {
|
|
69
|
-
private readonly emailService =
|
|
69
|
+
private readonly emailService = inject(EmailService)
|
|
70
70
|
|
|
71
71
|
async createUser(name: string, email: string) {
|
|
72
72
|
console.log(`Creating user: ${name}`)
|
|
73
73
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
await emailService.sendEmail(
|
|
74
|
+
// Use the injected email service
|
|
75
|
+
await this.emailService.sendEmail(
|
|
77
76
|
email,
|
|
78
77
|
'Welcome!',
|
|
79
78
|
`Hello ${name}, welcome to our platform!`,
|
|
@@ -289,8 +288,39 @@ class DatabaseService implements OnServiceInit, OnServiceDestroy {
|
|
|
289
288
|
|
|
290
289
|
**Circular dependencies:**
|
|
291
290
|
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
The library automatically detects circular dependencies and throws a clear error:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// This will throw: "Circular dependency detected: ServiceA -> ServiceB -> ServiceA"
|
|
295
|
+
@Injectable()
|
|
296
|
+
class ServiceA {
|
|
297
|
+
private serviceB = inject(ServiceB)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@Injectable()
|
|
301
|
+
class ServiceB {
|
|
302
|
+
private serviceA = inject(ServiceA)
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
To fix circular dependencies, use `asyncInject()` on at least one side:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
@Injectable()
|
|
310
|
+
class ServiceA {
|
|
311
|
+
private serviceB = asyncInject(ServiceB) // Break cycle with asyncInject
|
|
312
|
+
|
|
313
|
+
async doSomething() {
|
|
314
|
+
const b = await this.serviceB
|
|
315
|
+
return b.process()
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
@Injectable()
|
|
320
|
+
class ServiceB {
|
|
321
|
+
private serviceA = inject(ServiceA) // This side can use inject()
|
|
322
|
+
}
|
|
323
|
+
```
|
|
294
324
|
|
|
295
325
|
**Services not found:**
|
|
296
326
|
|
|
@@ -305,5 +335,4 @@ class DatabaseService implements OnServiceInit, OnServiceDestroy {
|
|
|
305
335
|
### Getting Help
|
|
306
336
|
|
|
307
337
|
- Check the [API Reference](./api-reference.md)
|
|
308
|
-
- Look at [Advanced Patterns](./advanced-patterns.md)
|
|
309
338
|
- Review the [Examples](./examples/) folder
|