@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.
- package/README.md +211 -1
- package/coverage/clover.xml +1912 -1277
- package/coverage/coverage-final.json +37 -28
- package/coverage/docs/examples/basic-usage.mts.html +1 -1
- package/coverage/docs/examples/factory-pattern.mts.html +1 -1
- package/coverage/docs/examples/index.html +1 -1
- package/coverage/docs/examples/injection-tokens.mts.html +1 -1
- package/coverage/docs/examples/request-scope-example.mts.html +1 -1
- package/coverage/docs/examples/service-lifecycle.mts.html +1 -1
- package/coverage/index.html +71 -41
- package/coverage/lib/_tsup-dts-rollup.d.mts.html +682 -43
- package/coverage/lib/index.d.mts.html +7 -4
- package/coverage/lib/index.html +5 -5
- package/coverage/lib/testing/index.d.mts.html +91 -0
- package/coverage/lib/testing/index.html +116 -0
- package/coverage/src/base-instance-holder-manager.mts.html +589 -0
- package/coverage/src/container.mts.html +257 -74
- package/coverage/src/decorators/factory.decorator.mts.html +1 -1
- package/coverage/src/decorators/index.html +1 -1
- package/coverage/src/decorators/index.mts.html +1 -1
- package/coverage/src/decorators/injectable.decorator.mts.html +20 -20
- package/coverage/src/enums/index.html +1 -1
- package/coverage/src/enums/index.mts.html +1 -1
- package/coverage/src/enums/injectable-scope.enum.mts.html +1 -1
- package/coverage/src/enums/injectable-type.enum.mts.html +1 -1
- package/coverage/src/errors/di-error.mts.html +292 -0
- package/coverage/src/errors/errors.enum.mts.html +30 -21
- package/coverage/src/errors/factory-not-found.mts.html +31 -22
- package/coverage/src/errors/factory-token-not-resolved.mts.html +29 -26
- package/coverage/src/errors/index.html +56 -41
- package/coverage/src/errors/index.mts.html +15 -9
- package/coverage/src/errors/instance-destroying.mts.html +31 -22
- package/coverage/src/errors/instance-expired.mts.html +31 -22
- package/coverage/src/errors/instance-not-found.mts.html +31 -22
- package/coverage/src/errors/unknown-error.mts.html +31 -43
- package/coverage/src/event-emitter.mts.html +14 -14
- package/coverage/src/factory-context.mts.html +1 -1
- package/coverage/src/index.html +121 -46
- package/coverage/src/index.mts.html +7 -4
- package/coverage/src/injection-token.mts.html +28 -28
- package/coverage/src/injector.mts.html +1 -1
- package/coverage/src/instance-resolver.mts.html +1762 -0
- package/coverage/src/interfaces/factory.interface.mts.html +1 -1
- package/coverage/src/interfaces/index.html +1 -1
- package/coverage/src/interfaces/index.mts.html +1 -1
- package/coverage/src/interfaces/on-service-destroy.interface.mts.html +1 -1
- package/coverage/src/interfaces/on-service-init.interface.mts.html +1 -1
- package/coverage/src/registry.mts.html +28 -28
- package/coverage/src/request-context-holder.mts.html +183 -102
- package/coverage/src/request-context-manager.mts.html +532 -0
- package/coverage/src/service-instantiator.mts.html +49 -49
- package/coverage/src/service-invalidator.mts.html +1372 -0
- package/coverage/src/service-locator-event-bus.mts.html +48 -48
- package/coverage/src/service-locator-instance-holder.mts.html +2 -14
- package/coverage/src/service-locator-manager.mts.html +71 -335
- package/coverage/src/service-locator.mts.html +240 -2328
- package/coverage/src/symbols/index.html +1 -1
- package/coverage/src/symbols/index.mts.html +1 -1
- package/coverage/src/symbols/injectable-token.mts.html +1 -1
- package/coverage/src/testing/index.html +131 -0
- package/coverage/src/testing/index.mts.html +88 -0
- package/coverage/src/testing/test-container.mts.html +445 -0
- package/coverage/src/token-processor.mts.html +607 -0
- package/coverage/src/utils/defer.mts.html +28 -214
- package/coverage/src/utils/get-injectable-token.mts.html +7 -7
- package/coverage/src/utils/get-injectors.mts.html +99 -99
- package/coverage/src/utils/index.html +15 -15
- package/coverage/src/utils/index.mts.html +4 -7
- package/coverage/src/utils/types.mts.html +1 -1
- package/docs/injectable.md +51 -11
- package/docs/scopes.md +63 -29
- package/lib/_tsup-dts-rollup.d.mts +376 -213
- package/lib/_tsup-dts-rollup.d.ts +376 -213
- package/lib/{chunk-3NLYPYBY.mjs → chunk-44F3LXW5.mjs} +1021 -605
- package/lib/chunk-44F3LXW5.mjs.map +1 -0
- package/lib/index.d.mts +6 -4
- package/lib/index.d.ts +6 -4
- package/lib/index.js +1192 -776
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2 -2
- package/lib/testing/index.js +1258 -840
- package/lib/testing/index.js.map +1 -1
- package/lib/testing/index.mjs +1 -1
- package/package.json +1 -1
- package/src/__tests__/container.spec.mts +47 -13
- package/src/__tests__/errors.spec.mts +53 -27
- package/src/__tests__/injectable.spec.mts +73 -0
- package/src/__tests__/request-scope.spec.mts +0 -2
- package/src/__tests__/service-locator-manager.spec.mts +12 -82
- package/src/__tests__/service-locator.spec.mts +1009 -1
- package/src/__type-tests__/inject.spec-d.mts +30 -7
- package/src/__type-tests__/injectable.spec-d.mts +76 -37
- package/src/base-instance-holder-manager.mts +2 -9
- package/src/container.mts +61 -9
- package/src/decorators/injectable.decorator.mts +29 -5
- package/src/errors/di-error.mts +69 -0
- package/src/errors/index.mts +9 -7
- package/src/injection-token.mts +1 -0
- package/src/injector.mts +2 -0
- package/src/instance-resolver.mts +559 -0
- package/src/request-context-holder.mts +0 -2
- package/src/request-context-manager.mts +149 -0
- package/src/service-invalidator.mts +429 -0
- package/src/service-locator-instance-holder.mts +0 -4
- package/src/service-locator-manager.mts +10 -40
- package/src/service-locator.mts +86 -782
- package/src/token-processor.mts +174 -0
- package/src/utils/get-injectors.mts +161 -24
- package/src/utils/index.mts +0 -1
- package/src/utils/types.mts +12 -8
- package/lib/chunk-3NLYPYBY.mjs.map +0 -1
- package/src/__tests__/defer.spec.mts +0 -166
- package/src/errors/errors.enum.mts +0 -8
- package/src/errors/factory-not-found.mts +0 -8
- package/src/errors/factory-token-not-resolved.mts +0 -10
- package/src/errors/instance-destroying.mts +0 -8
- package/src/errors/instance-expired.mts +0 -8
- package/src/errors/instance-not-found.mts +0 -8
- package/src/errors/unknown-error.mts +0 -15
- package/src/utils/defer.mts +0 -73
package/README.md
CHANGED
|
@@ -88,6 +88,9 @@ The `@Injectable` decorator marks a class as injectable:
|
|
|
88
88
|
```typescript
|
|
89
89
|
import { Injectable, InjectableScope } from '@navios/di'
|
|
90
90
|
|
|
91
|
+
// With schema (for constructor arguments)
|
|
92
|
+
import { z } from 'zod'
|
|
93
|
+
|
|
91
94
|
// Singleton (default)
|
|
92
95
|
@Injectable()
|
|
93
96
|
class SingletonService {}
|
|
@@ -99,6 +102,16 @@ class TransientService {}
|
|
|
99
102
|
// With custom injection token
|
|
100
103
|
@Injectable({ token: MyToken })
|
|
101
104
|
class TokenizedService {}
|
|
105
|
+
|
|
106
|
+
const configSchema = z.object({
|
|
107
|
+
host: z.string(),
|
|
108
|
+
port: z.number(),
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
@Injectable({ schema: configSchema })
|
|
112
|
+
class DatabaseConfig {
|
|
113
|
+
constructor(public readonly config: z.output<typeof configSchema>) {}
|
|
114
|
+
}
|
|
102
115
|
```
|
|
103
116
|
|
|
104
117
|
### Injection Methods
|
|
@@ -302,6 +315,201 @@ const FactoryConfig = InjectionToken.factory(CONFIG_TOKEN, async () => {
|
|
|
302
315
|
const config = await container.get(FactoryConfig)
|
|
303
316
|
```
|
|
304
317
|
|
|
318
|
+
### Injectable with Schema
|
|
319
|
+
|
|
320
|
+
Instead of creating an injection token with a schema, you can directly provide a schema to the `@Injectable` decorator. This is a more concise way to define services that require constructor arguments with validation.
|
|
321
|
+
|
|
322
|
+
#### Basic Schema Usage
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { getInjectableToken, Injectable, InjectionToken } from '@navios/di'
|
|
326
|
+
|
|
327
|
+
import { z } from 'zod'
|
|
328
|
+
|
|
329
|
+
const databaseConfigSchema = z.object({
|
|
330
|
+
host: z.string(),
|
|
331
|
+
port: z.number(),
|
|
332
|
+
username: z.string(),
|
|
333
|
+
password: z.string(),
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
@Injectable({ schema: databaseConfigSchema })
|
|
337
|
+
class DatabaseConfig {
|
|
338
|
+
constructor(public readonly config: z.output<typeof databaseConfigSchema>) {}
|
|
339
|
+
|
|
340
|
+
getConnectionString() {
|
|
341
|
+
return `${this.config.host}:${this.config.port}`
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Usage with bound token
|
|
346
|
+
const container = new Container()
|
|
347
|
+
const config = await container.get(DatabaseConfig, {
|
|
348
|
+
host: 'localhost',
|
|
349
|
+
port: 5432,
|
|
350
|
+
username: 'admin',
|
|
351
|
+
password: 'secret',
|
|
352
|
+
})
|
|
353
|
+
console.log(config.getConnectionString()) // "localhost:5432"
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### Schema with Different Scopes
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// Singleton with schema (default)
|
|
360
|
+
@Injectable({ schema: apiConfigSchema })
|
|
361
|
+
class ApiConfig {
|
|
362
|
+
constructor(public readonly config: z.output<typeof apiConfigSchema>) {}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Transient with schema
|
|
366
|
+
@Injectable({
|
|
367
|
+
schema: loggerConfigSchema,
|
|
368
|
+
scope: InjectableScope.Transient,
|
|
369
|
+
})
|
|
370
|
+
class Logger {
|
|
371
|
+
constructor(public readonly config: z.output<typeof loggerConfigSchema>) {}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Request-scoped with schema
|
|
375
|
+
@Injectable({
|
|
376
|
+
schema: userContextSchema,
|
|
377
|
+
scope: InjectableScope.Request,
|
|
378
|
+
})
|
|
379
|
+
class UserContext {
|
|
380
|
+
constructor(public readonly context: z.output<typeof userContextSchema>) {}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### Using Schema-based Services as Dependencies
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
const dbConfigSchema = z.object({
|
|
388
|
+
connectionString: z.string(),
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
@Injectable({ schema: dbConfigSchema })
|
|
392
|
+
class DatabaseConfig {
|
|
393
|
+
constructor(public readonly config: z.output<typeof dbConfigSchema>) {}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@Injectable()
|
|
397
|
+
class DatabaseService {
|
|
398
|
+
// Inject with bound token
|
|
399
|
+
private dbConfig = inject(DatabaseConfig, {
|
|
400
|
+
connectionString: 'postgres://localhost:5432/myapp',
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
connect() {
|
|
404
|
+
return `Connecting to ${this.dbConfig.config.connectionString}`
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Or with async injection
|
|
409
|
+
@Injectable()
|
|
410
|
+
class AsyncDatabaseService {
|
|
411
|
+
private dbConfig = asyncInject(DatabaseConfig, {
|
|
412
|
+
connectionString: 'postgres://localhost:5432/myapp',
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
async connect() {
|
|
416
|
+
const config = await this.dbConfig
|
|
417
|
+
return `Connecting to ${config.config.connectionString}`
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### Complex Nested Schemas
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
const appConfigSchema = z.object({
|
|
426
|
+
database: z.object({
|
|
427
|
+
host: z.string(),
|
|
428
|
+
port: z.number(),
|
|
429
|
+
credentials: z.object({
|
|
430
|
+
username: z.string(),
|
|
431
|
+
password: z.string(),
|
|
432
|
+
}),
|
|
433
|
+
}),
|
|
434
|
+
cache: z.object({
|
|
435
|
+
enabled: z.boolean(),
|
|
436
|
+
ttl: z.number(),
|
|
437
|
+
}),
|
|
438
|
+
api: z.object({
|
|
439
|
+
baseUrl: z.string(),
|
|
440
|
+
timeout: z.number(),
|
|
441
|
+
}),
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
@Injectable({ schema: appConfigSchema })
|
|
445
|
+
class AppConfig {
|
|
446
|
+
constructor(public readonly config: z.output<typeof appConfigSchema>) {}
|
|
447
|
+
|
|
448
|
+
getDatabaseConfig() {
|
|
449
|
+
return this.config.database
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
getCacheConfig() {
|
|
453
|
+
return this.config.cache
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
getApiConfig() {
|
|
457
|
+
return this.config.api
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Usage
|
|
462
|
+
const container = new Container()
|
|
463
|
+
const config = await container.get(AppConfig, {
|
|
464
|
+
database: {
|
|
465
|
+
host: 'db.example.com',
|
|
466
|
+
port: 5432,
|
|
467
|
+
credentials: {
|
|
468
|
+
username: 'admin',
|
|
469
|
+
password: 'secret',
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
cache: {
|
|
473
|
+
enabled: true,
|
|
474
|
+
ttl: 300,
|
|
475
|
+
},
|
|
476
|
+
api: {
|
|
477
|
+
baseUrl: 'https://api.example.com',
|
|
478
|
+
timeout: 5000,
|
|
479
|
+
},
|
|
480
|
+
})
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
#### Schema vs Token with Schema
|
|
484
|
+
|
|
485
|
+
There are two ways to use schemas with `@Injectable`:
|
|
486
|
+
|
|
487
|
+
**Option 1: Direct Schema (Recommended for simplicity)**
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
@Injectable({ schema: configSchema })
|
|
491
|
+
class ConfigService {
|
|
492
|
+
constructor(public readonly config: z.output<typeof configSchema>) {}
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Option 2: Token with Schema (Use when you need to share the token)**
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
const CONFIG_TOKEN = InjectionToken.create('CONFIG', configSchema)
|
|
500
|
+
|
|
501
|
+
@Injectable({ token: CONFIG_TOKEN })
|
|
502
|
+
class ConfigService {
|
|
503
|
+
constructor(public readonly config: z.output<typeof configSchema>) {}
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
The direct schema approach is simpler and creates the injection token automatically. Use the token approach when you need to:
|
|
508
|
+
|
|
509
|
+
- Share the same token across multiple classes
|
|
510
|
+
- Reference the token in multiple places
|
|
511
|
+
- Have more control over the token name
|
|
512
|
+
|
|
305
513
|
## Advanced Usage
|
|
306
514
|
|
|
307
515
|
### Custom Registry
|
|
@@ -350,9 +558,11 @@ const newService = await container.get(MyService)
|
|
|
350
558
|
|
|
351
559
|
- `@Injectable(options?: InjectableOptions)` - Mark class as injectable
|
|
352
560
|
- Options:
|
|
353
|
-
- `scope?: InjectableScope` - Service scope (Singleton | Transient)
|
|
561
|
+
- `scope?: InjectableScope` - Service scope (Singleton | Transient | Request)
|
|
354
562
|
- `token?: InjectionToken` - Custom injection token
|
|
563
|
+
- `schema?: ZodSchema` - Zod schema for constructor arguments (alternative to token)
|
|
355
564
|
- `registry?: Registry` - Custom registry
|
|
565
|
+
- Note: Cannot use both `token` and `schema` options together
|
|
356
566
|
|
|
357
567
|
### Factory Decorator
|
|
358
568
|
|