@navios/di 0.5.1 → 0.6.1
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 +145 -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 +3013 -0
- package/lib/browser/index.mjs.map +1 -0
- package/lib/index-7jfWsiG4.d.mts +1211 -0
- package/lib/index-7jfWsiG4.d.mts.map +1 -0
- package/lib/index-DW3K5sOX.d.cts +1206 -0
- package/lib/index-DW3K5sOX.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-BG_fa9TJ.mjs +2656 -0
- package/lib/testing-BG_fa9TJ.mjs.map +1 -0
- package/lib/testing-DIaIRiJz.cjs +2896 -0
- package/lib/testing-DIaIRiJz.cjs.map +1 -0
- package/package.json +29 -7
- 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__/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 +18 -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 +12 -5
- 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} +11 -4
- 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-2M576LCC.mjs +0 -2043
- package/lib/chunk-2M576LCC.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/scopes.md
CHANGED
|
@@ -215,11 +215,7 @@ import { Injectable, InjectableScope } from '@navios/di'
|
|
|
215
215
|
class RequestContext {
|
|
216
216
|
private readonly requestId = Math.random().toString(36)
|
|
217
217
|
private readonly startTime = Date.now()
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
constructor(userId: string) {
|
|
221
|
-
this.userId = userId
|
|
222
|
-
}
|
|
218
|
+
userId?: string
|
|
223
219
|
|
|
224
220
|
getRequestId() {
|
|
225
221
|
return this.requestId
|
|
@@ -228,32 +224,44 @@ class RequestContext {
|
|
|
228
224
|
getDuration() {
|
|
229
225
|
return Date.now() - this.startTime
|
|
230
226
|
}
|
|
231
|
-
|
|
232
|
-
getUserId() {
|
|
233
|
-
return this.userId
|
|
234
|
-
}
|
|
235
227
|
}
|
|
236
228
|
```
|
|
237
229
|
|
|
238
230
|
### Request Context Management
|
|
239
231
|
|
|
232
|
+
Request-scoped services require using `ScopedContainer`, which is created via `container.beginRequest()`:
|
|
233
|
+
|
|
240
234
|
```typescript
|
|
241
235
|
import { Container } from '@navios/di'
|
|
242
236
|
|
|
243
237
|
const container = new Container()
|
|
244
238
|
|
|
245
|
-
// Begin a request context
|
|
246
|
-
const
|
|
247
|
-
container.beginRequest(requestId, { userId: 'user123' })
|
|
239
|
+
// Begin a request context - returns a ScopedContainer
|
|
240
|
+
const scopedContainer = container.beginRequest('req-123', { userId: 'user123' })
|
|
248
241
|
|
|
249
242
|
// All injections within this request will share the same Request-scoped instances
|
|
250
|
-
const context1 = await
|
|
251
|
-
const context2 = await
|
|
243
|
+
const context1 = await scopedContainer.get(RequestContext)
|
|
244
|
+
const context2 = await scopedContainer.get(RequestContext)
|
|
252
245
|
|
|
253
246
|
console.log(context1 === context2) // true - same instance within request
|
|
254
247
|
|
|
248
|
+
// Access metadata
|
|
249
|
+
const userId = scopedContainer.getMetadata('userId')
|
|
250
|
+
|
|
255
251
|
// End the request context (cleans up all request-scoped instances)
|
|
256
|
-
await
|
|
252
|
+
await scopedContainer.endRequest()
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Important**: You cannot resolve request-scoped services directly from the main `Container`. Attempting to do so will throw an error:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// ❌ This will throw an error
|
|
259
|
+
const context = await container.get(RequestContext)
|
|
260
|
+
// Error: Cannot resolve request-scoped service from Container
|
|
261
|
+
|
|
262
|
+
// ✅ Use ScopedContainer instead
|
|
263
|
+
const scoped = container.beginRequest('req-123')
|
|
264
|
+
const context = await scoped.get(RequestContext)
|
|
257
265
|
```
|
|
258
266
|
|
|
259
267
|
### Request Scope with Dependencies
|
|
@@ -272,15 +280,10 @@ class LoggerService {
|
|
|
272
280
|
class UserSession {
|
|
273
281
|
private readonly logger = inject(LoggerService)
|
|
274
282
|
private readonly sessionId = Math.random().toString(36)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
constructor(userId: string) {
|
|
278
|
-
this.userId = userId
|
|
279
|
-
}
|
|
283
|
+
userId?: string
|
|
280
284
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
logger.log(`User ${this.userId}: ${activity}`)
|
|
285
|
+
logActivity(activity: string) {
|
|
286
|
+
this.logger.log(`User ${this.userId}: ${activity}`)
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
getSessionId() {
|
|
@@ -293,43 +296,77 @@ class OrderService {
|
|
|
293
296
|
private readonly userSession = inject(UserSession)
|
|
294
297
|
private orders: string[] = []
|
|
295
298
|
|
|
296
|
-
|
|
297
|
-
const session = await this.userSession
|
|
299
|
+
createOrder(productName: string) {
|
|
298
300
|
const orderId = `order_${Math.random().toString(36)}`
|
|
299
301
|
|
|
300
302
|
this.orders.push(orderId)
|
|
301
|
-
|
|
303
|
+
this.userSession.logActivity(`Created order ${orderId} for ${productName}`)
|
|
302
304
|
|
|
303
|
-
return { orderId,
|
|
305
|
+
return { orderId, sessionId: this.userSession.getSessionId() }
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
308
|
```
|
|
307
309
|
|
|
308
|
-
###
|
|
310
|
+
### Multiple Concurrent Requests
|
|
309
311
|
|
|
310
|
-
|
|
312
|
+
Each request gets its own isolated `ScopedContainer`:
|
|
311
313
|
|
|
312
314
|
```typescript
|
|
313
315
|
const container = new Container()
|
|
314
316
|
|
|
315
|
-
// Start multiple requests
|
|
316
|
-
container.beginRequest('req-1', { userId: 'user1' })
|
|
317
|
-
container.beginRequest('req-2', { userId: 'user2' })
|
|
317
|
+
// Start multiple concurrent requests
|
|
318
|
+
const scoped1 = container.beginRequest('req-1', { userId: 'user1' })
|
|
319
|
+
const scoped2 = container.beginRequest('req-2', { userId: 'user2' })
|
|
318
320
|
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
// Switch to request 2
|
|
324
|
-
container.setCurrentRequestContext('req-2')
|
|
325
|
-
const context2 = await container.get(RequestContext)
|
|
321
|
+
// Each scoped container has its own request-scoped instances
|
|
322
|
+
const context1 = await scoped1.get(RequestContext)
|
|
323
|
+
const context2 = await scoped2.get(RequestContext)
|
|
326
324
|
|
|
327
325
|
// Different instances for different requests
|
|
328
326
|
console.log(context1 !== context2) // true
|
|
329
327
|
|
|
330
|
-
//
|
|
331
|
-
await
|
|
332
|
-
await
|
|
328
|
+
// Singletons are shared across all requests
|
|
329
|
+
const logger1 = await scoped1.get(LoggerService)
|
|
330
|
+
const logger2 = await scoped2.get(LoggerService)
|
|
331
|
+
console.log(logger1 === logger2) // true - same singleton
|
|
332
|
+
|
|
333
|
+
// Clean up each request independently
|
|
334
|
+
await scoped1.endRequest()
|
|
335
|
+
await scoped2.endRequest()
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Cross-Storage Dependency Invalidation
|
|
339
|
+
|
|
340
|
+
When a request-scoped service is destroyed (via `endRequest()`), any singleton services that depend on it are automatically invalidated:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
@Injectable({ scope: InjectableScope.Request })
|
|
344
|
+
class RequestData {
|
|
345
|
+
data = 'request-specific'
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
@Injectable({ scope: InjectableScope.Singleton })
|
|
349
|
+
class SingletonConsumer {
|
|
350
|
+
private requestData = inject(RequestData)
|
|
351
|
+
|
|
352
|
+
getData() {
|
|
353
|
+
return this.requestData.data
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const container = new Container()
|
|
358
|
+
const scoped = container.beginRequest('req-1')
|
|
359
|
+
|
|
360
|
+
const singleton = await scoped.get(SingletonConsumer)
|
|
361
|
+
await singleton.getData() // Works fine
|
|
362
|
+
|
|
363
|
+
await scoped.endRequest()
|
|
364
|
+
// SingletonConsumer is also invalidated because it depends on RequestData
|
|
365
|
+
|
|
366
|
+
// Next request gets fresh instances
|
|
367
|
+
const scoped2 = container.beginRequest('req-2')
|
|
368
|
+
const singleton2 = await scoped2.get(SingletonConsumer)
|
|
369
|
+
console.log(singleton !== singleton2) // true - new instance
|
|
333
370
|
```
|
|
334
371
|
|
|
335
372
|
## Scope Compatibility
|