@navios/di 0.2.1 → 0.3.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 (62) hide show
  1. package/README.md +299 -38
  2. package/docs/README.md +121 -48
  3. package/docs/api-reference.md +763 -0
  4. package/docs/container.md +274 -0
  5. package/docs/examples/basic-usage.mts +97 -0
  6. package/docs/examples/factory-pattern.mts +318 -0
  7. package/docs/examples/injection-tokens.mts +225 -0
  8. package/docs/examples/request-scope-example.mts +254 -0
  9. package/docs/examples/service-lifecycle.mts +359 -0
  10. package/docs/factory.md +584 -0
  11. package/docs/getting-started.md +308 -0
  12. package/docs/injectable.md +496 -0
  13. package/docs/injection-tokens.md +400 -0
  14. package/docs/lifecycle.md +539 -0
  15. package/docs/scopes.md +749 -0
  16. package/lib/_tsup-dts-rollup.d.mts +490 -145
  17. package/lib/_tsup-dts-rollup.d.ts +490 -145
  18. package/lib/index.d.mts +26 -12
  19. package/lib/index.d.ts +26 -12
  20. package/lib/index.js +993 -462
  21. package/lib/index.js.map +1 -1
  22. package/lib/index.mjs +983 -453
  23. package/lib/index.mjs.map +1 -1
  24. package/package.json +2 -2
  25. package/project.json +10 -2
  26. package/src/__tests__/container.spec.mts +1301 -0
  27. package/src/__tests__/factory.spec.mts +137 -0
  28. package/src/__tests__/injectable.spec.mts +32 -88
  29. package/src/__tests__/injection-token.spec.mts +333 -17
  30. package/src/__tests__/request-scope.spec.mts +263 -0
  31. package/src/__type-tests__/factory.spec-d.mts +65 -0
  32. package/src/__type-tests__/inject.spec-d.mts +27 -28
  33. package/src/__type-tests__/injectable.spec-d.mts +42 -206
  34. package/src/container.mts +167 -0
  35. package/src/decorators/factory.decorator.mts +79 -0
  36. package/src/decorators/index.mts +1 -0
  37. package/src/decorators/injectable.decorator.mts +6 -56
  38. package/src/enums/injectable-scope.enum.mts +5 -1
  39. package/src/event-emitter.mts +18 -20
  40. package/src/factory-context.mts +2 -10
  41. package/src/index.mts +3 -2
  42. package/src/injection-token.mts +19 -4
  43. package/src/injector.mts +8 -20
  44. package/src/interfaces/factory.interface.mts +3 -3
  45. package/src/interfaces/index.mts +2 -0
  46. package/src/interfaces/on-service-destroy.interface.mts +3 -0
  47. package/src/interfaces/on-service-init.interface.mts +3 -0
  48. package/src/registry.mts +7 -16
  49. package/src/request-context-holder.mts +145 -0
  50. package/src/service-instantiator.mts +158 -0
  51. package/src/service-locator-event-bus.mts +0 -28
  52. package/src/service-locator-instance-holder.mts +27 -16
  53. package/src/service-locator-manager.mts +84 -0
  54. package/src/service-locator.mts +548 -393
  55. package/src/utils/defer.mts +73 -0
  56. package/src/utils/get-injectors.mts +91 -78
  57. package/src/utils/index.mts +2 -0
  58. package/src/utils/types.mts +52 -0
  59. package/docs/concepts/injectable.md +0 -182
  60. package/docs/concepts/injection-token.md +0 -145
  61. package/src/proxy-service-locator.mts +0 -83
  62. package/src/resolve-service.mts +0 -41
@@ -0,0 +1,763 @@
1
+ # API Reference
2
+
3
+ Complete API reference for Navios DI library.
4
+
5
+ ## Core Classes
6
+
7
+ ### Container
8
+
9
+ The main entry point for dependency injection.
10
+
11
+ ```typescript
12
+ class Container {
13
+ constructor(registry?: Registry, logger?: Console | null)
14
+
15
+ get<T>(token: T): Promise<InstanceType<T>>
16
+ get<T, S extends InjectionTokenSchemaType>(
17
+ token: InjectionToken<T, S>,
18
+ args: z.input<S>,
19
+ ): Promise<T>
20
+ get<T>(token: InjectionToken<T, undefined>): Promise<T>
21
+ get<T>(token: BoundInjectionToken<T, any>): Promise<T>
22
+ get<T>(token: FactoryInjectionToken<T, any>): Promise<T>
23
+
24
+ invalidate(service: unknown): Promise<void>
25
+ ready(): Promise<void>
26
+ getServiceLocator(): ServiceLocator
27
+
28
+ // Request Context Management
29
+ beginRequest(
30
+ requestId: string,
31
+ metadata?: Record<string, any>,
32
+ priority?: number,
33
+ ): RequestContextHolder
34
+ endRequest(requestId: string): Promise<void>
35
+ setCurrentRequestContext(requestId: string): void
36
+ }
37
+ ```
38
+
39
+ **Constructor Parameters:**
40
+
41
+ - `registry?: Registry` - Optional registry instance (defaults to global registry)
42
+ - `logger?: Console | null` - Optional logger for debugging
43
+
44
+ **Methods:**
45
+
46
+ - `get<T>(token: T)` - Get a service instance
47
+ - `invalidate(service: unknown)` - Invalidate a service and its dependencies
48
+ - `ready()` - Wait for all pending operations to complete
49
+ - `getServiceLocator()` - Get the underlying ServiceLocator instance
50
+
51
+ **Request Context Management:**
52
+
53
+ - `beginRequest(requestId: string, metadata?: Record<string, any>, priority?: number)` - Begin a new request context
54
+ - `endRequest(requestId: string)` - End a request context and clean up instances
55
+ - `setCurrentRequestContext(requestId: string)` - Switch to a different request context
56
+
57
+ ### InjectionToken
58
+
59
+ Token-based dependency resolution.
60
+
61
+ ```typescript
62
+ class InjectionToken<
63
+ T,
64
+ S extends InjectionTokenSchemaType | unknown = unknown,
65
+ Required extends boolean = S extends ZodOptional<ZodObject>
66
+ ? false
67
+ : S extends ZodOptional<ZodRecord>
68
+ ? false
69
+ : S extends ZodObject
70
+ ? true
71
+ : S extends ZodRecord
72
+ ? true
73
+ : false,
74
+ > {
75
+ public id: string
76
+ public readonly name: string | symbol | ClassType
77
+ public readonly schema: ZodObject | undefined
78
+
79
+ constructor(name: string | symbol | ClassType, schema: ZodObject | undefined)
80
+
81
+ static create<T extends ClassType>(
82
+ name: T,
83
+ ): InjectionToken<InstanceType<T>, undefined>
84
+ static create<T extends ClassType, Schema extends InjectionTokenSchemaType>(
85
+ name: T,
86
+ schema: Schema,
87
+ ): Schema['_def']['type'] extends 'ZodOptional'
88
+ ? InjectionToken<InstanceType<T>, Schema, false>
89
+ : InjectionToken<InstanceType<T>, Schema, true>
90
+ static create<T>(name: string | symbol): InjectionToken<T, undefined>
91
+ static create<T, Schema extends InjectionTokenSchemaType>(
92
+ name: string | any,
93
+ schema: Schema,
94
+ ): InjectionToken<T, Schema>
95
+
96
+ static bound<T, S extends InjectionTokenSchemaType>(
97
+ token: InjectionToken<T, S>,
98
+ value: z.input<S>,
99
+ ): BoundInjectionToken<T, S>
100
+ static factory<T, S extends InjectionTokenSchemaType>(
101
+ token: InjectionToken<T, S>,
102
+ factory: () => Promise<z.input<S>>,
103
+ ): FactoryInjectionToken<T, S>
104
+ static refineType<T>(
105
+ token: BoundInjectionToken<any, any>,
106
+ ): BoundInjectionToken<T, any>
107
+
108
+ toString(): string
109
+ }
110
+ ```
111
+
112
+ **Static Methods:**
113
+
114
+ - `create<T>(name: string | symbol)` - Create a simple injection token
115
+ - `create<T, S>(name: string | symbol, schema: S)` - Create a token with schema
116
+ - `bound<T, S>(token: InjectionToken<T, S>, value: z.input<S>)` - Create a bound token
117
+ - `factory<T, S>(token: InjectionToken<T, S>, factory: (ctx: FactoryContext) => Promise<z.input<S>>)` - Create a factory token
118
+
119
+ ### BoundInjectionToken
120
+
121
+ Pre-configured injection token.
122
+
123
+ ```typescript
124
+ class BoundInjectionToken<T, S extends InjectionTokenSchemaType> {
125
+ public id: string
126
+ public name: string | symbol | ClassType
127
+ public schema: InjectionTokenSchemaType
128
+
129
+ constructor(token: InjectionToken<T, S>, value: z.input<S>)
130
+
131
+ toString(): string
132
+ }
133
+ ```
134
+
135
+ ### FactoryInjectionToken
136
+
137
+ Dynamically resolved injection token.
138
+
139
+ ```typescript
140
+ class FactoryInjectionToken<T, S extends InjectionTokenSchemaType> {
141
+ public value?: z.input<S>
142
+ public resolved: boolean
143
+ public id: string
144
+ public name: string | symbol | ClassType
145
+ public schema: InjectionTokenSchemaType
146
+
147
+ constructor(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>)
148
+
149
+ resolve(): Promise<z.input<S>>
150
+ toString(): string
151
+ }
152
+ ```
153
+
154
+ ## Decorators
155
+
156
+ ### Injectable
157
+
158
+ Mark a class as injectable service.
159
+
160
+ ```typescript
161
+ function Injectable(): <T extends ClassType>(
162
+ target: T,
163
+ context?: ClassDecoratorContext,
164
+ ) => T
165
+ function Injectable(options: {
166
+ scope?: InjectableScope
167
+ registry: Registry
168
+ }): <T extends ClassType>(target: T, context?: ClassDecoratorContext) => T
169
+ function Injectable(options: {
170
+ scope: InjectableScope
171
+ }): <T extends ClassType>(target: T, context?: ClassDecoratorContext) => T
172
+ function Injectable<Type, Schema>(options: {
173
+ scope?: InjectableScope
174
+ token: InjectionToken<Type, Schema>
175
+ registry?: Registry
176
+ }): Schema extends BaseInjectionTokenSchemaType
177
+ ? Type extends undefined
178
+ ? <T extends ClassTypeWithArgument<z.output<Schema>>>(
179
+ target: T,
180
+ context?: ClassDecoratorContext,
181
+ ) => T
182
+ : <T extends ClassTypeWithInstanceAndArgument<Type, z.output<Schema>>>(
183
+ target: T,
184
+ context?: ClassDecoratorContext,
185
+ ) => T
186
+ : Schema extends OptionalInjectionTokenSchemaType
187
+ ? Type extends undefined
188
+ ? <T extends ClassTypeWithOptionalArgument<z.output<Schema>>>(
189
+ target: T,
190
+ context?: ClassDecoratorContext,
191
+ ) => T
192
+ : <
193
+ T extends ClassTypeWithInstanceAndOptionalArgument<
194
+ Type,
195
+ z.output<Schema>
196
+ >,
197
+ >(
198
+ target: T,
199
+ context?: ClassDecoratorContext,
200
+ ) => T
201
+ : Schema extends undefined
202
+ ? <R extends ClassTypeWithInstance<Type>>(
203
+ target: R,
204
+ context?: ClassDecoratorContext,
205
+ ) => R
206
+ : never
207
+ ```
208
+
209
+ **Options:**
210
+
211
+ - `scope?: InjectableScope` - Service scope (default: Singleton)
212
+ - `token?: InjectionToken<any, any>` - Custom injection token
213
+ - `registry?: Registry` - Custom registry
214
+
215
+ ### Factory
216
+
217
+ Mark a class as factory service.
218
+
219
+ ```typescript
220
+ function Factory<R>(options?: {
221
+ scope?: InjectableScope
222
+ registry?: Registry
223
+ }): <T extends ClassTypeWithInstance<Factorable<R>>>(
224
+ target: T,
225
+ context?: ClassDecoratorContext,
226
+ ) => T
227
+ function Factory<R, S>(options: {
228
+ scope?: InjectableScope
229
+ token: InjectionToken<R, S>
230
+ registry?: Registry
231
+ }): R extends undefined
232
+ ? never
233
+ : S extends InjectionTokenSchemaType
234
+ ? <T extends ClassTypeWithInstance<FactorableWithArgs<R, S>>>(
235
+ target: T,
236
+ context?: ClassDecoratorContext,
237
+ ) => T
238
+ : S extends undefined
239
+ ? <T extends ClassTypeWithInstance<Factorable<R>>>(
240
+ target: T,
241
+ context?: ClassDecoratorContext,
242
+ ) => T
243
+ : never
244
+ ```
245
+
246
+ **Options:**
247
+
248
+ - `scope?: InjectableScope` - Factory scope (default: Singleton)
249
+ - `token?: InjectionToken<any, any>` - Custom injection token
250
+ - `registry?: Registry` - Custom registry
251
+
252
+ ## Enums
253
+
254
+ ### InjectableScope
255
+
256
+ Service lifetime scope.
257
+
258
+ ```typescript
259
+ enum InjectableScope {
260
+ Singleton = 'Singleton', // One instance shared across the application
261
+ Transient = 'Transient', // New instance created for each injection
262
+ Request = 'Request', // One instance per request context
263
+ }
264
+ ```
265
+
266
+ ### InjectableType
267
+
268
+ Service type.
269
+
270
+ ```typescript
271
+ enum InjectableType {
272
+ Class = 'Class', // Regular service class
273
+ Factory = 'Factory', // Factory service class
274
+ }
275
+ ```
276
+
277
+ ## Interfaces
278
+
279
+ ### OnServiceInit
280
+
281
+ Service initialization hook.
282
+
283
+ ```typescript
284
+ interface OnServiceInit {
285
+ onServiceInit(): Promise<void> | void
286
+ }
287
+ ```
288
+
289
+ ### OnServiceDestroy
290
+
291
+ Service cleanup hook.
292
+
293
+ ```typescript
294
+ interface OnServiceDestroy {
295
+ onServiceDestroy(): Promise<void> | void
296
+ }
297
+ ```
298
+
299
+ ### Factorable
300
+
301
+ Factory interface for simple factories.
302
+
303
+ ```typescript
304
+ interface Factorable<T> {
305
+ create(): T
306
+ }
307
+ ```
308
+
309
+ ### FactorableWithArgs
310
+
311
+ Factory interface for factories with arguments.
312
+
313
+ ```typescript
314
+ interface FactorableWithArgs<T, S> {
315
+ create(args: z.input<S>): T
316
+ }
317
+ ```
318
+
319
+ ### FactoryContext
320
+
321
+ Context provided to factory methods.
322
+
323
+ ```typescript
324
+ interface FactoryContext {
325
+ inject<T>(token: T): Promise<T>
326
+ locator: ServiceLocator
327
+ on(event: string, listener: Function): void
328
+ getDependencies(): any[]
329
+ invalidate(): Promise<void>
330
+ addEffect(effect: Function): void
331
+ setTtl(ttl: number): void
332
+ getTtl(): number | null
333
+ }
334
+ ```
335
+
336
+ ### RequestContextHolder
337
+
338
+ Request context holder for managing request-scoped instances.
339
+
340
+ ```typescript
341
+ interface RequestContextHolder {
342
+ readonly requestId: string
343
+ readonly priority: number
344
+ readonly createdAt: number
345
+ readonly instances: Map<string, any>
346
+ readonly metadata: Map<string, any>
347
+
348
+ addInstance(
349
+ instanceName: string,
350
+ instance: any,
351
+ holder: ServiceLocatorInstanceHolder,
352
+ ): void
353
+ getInstance(instanceName: string): any | undefined
354
+ hasInstance(instanceName: string): boolean
355
+ clear(): void
356
+ getMetadata(key: string): any | undefined
357
+ setMetadata(key: string, value: any): void
358
+ }
359
+ ```
360
+
361
+ ## Functions
362
+
363
+ ### asyncInject
364
+
365
+ Asynchronous dependency injection.
366
+
367
+ ```typescript
368
+ function asyncInject<T extends ClassType>(
369
+ token: T,
370
+ ): InstanceType<T> extends Factorable<infer R>
371
+ ? Promise<R>
372
+ : Promise<InstanceType<T>>
373
+ function asyncInject<T, S extends InjectionTokenSchemaType>(
374
+ token: InjectionToken<T, S>,
375
+ args: z.input<S>,
376
+ ): Promise<T>
377
+ function asyncInject<T, S extends InjectionTokenSchemaType, R extends boolean>(
378
+ token: InjectionToken<T, S, R>,
379
+ ): R extends false
380
+ ? Promise<T>
381
+ : S extends ZodType<infer Type>
382
+ ? `Error: Your token requires args: ${Join<UnionToArray<keyof Type>, ', '>}`
383
+ : 'Error: Your token requires args'
384
+ function asyncInject<T>(token: InjectionToken<T, undefined>): Promise<T>
385
+ function asyncInject<T>(token: BoundInjectionToken<T, any>): Promise<T>
386
+ function asyncInject<T>(token: FactoryInjectionToken<T, any>): Promise<T>
387
+ ```
388
+
389
+ ### inject
390
+
391
+ Synchronous dependency injection (singleton only).
392
+
393
+ ```typescript
394
+ function inject<T extends ClassType>(
395
+ token: T,
396
+ ): InstanceType<T> extends Factorable<infer R> ? R : InstanceType<T>
397
+ function inject<T, S extends InjectionTokenSchemaType>(
398
+ token: InjectionToken<T, S>,
399
+ args: z.input<S>,
400
+ ): T
401
+ function inject<T, S extends InjectionTokenSchemaType, R extends boolean>(
402
+ token: InjectionToken<T, S, R>,
403
+ ): R extends false
404
+ ? T
405
+ : S extends ZodType<infer Type>
406
+ ? `Error: Your token requires args: ${Join<UnionToArray<keyof Type>, ', '>}`
407
+ : 'Error: Your token requires args'
408
+ function inject<T>(token: InjectionToken<T, undefined>): T
409
+ function inject<T>(token: BoundInjectionToken<T, any>): T
410
+ function inject<T>(token: FactoryInjectionToken<T, any>): T
411
+ ```
412
+
413
+ ## Types
414
+
415
+ ### ClassType
416
+
417
+ Base class type.
418
+
419
+ ```typescript
420
+ type ClassType = new (...args: any[]) => any
421
+ ```
422
+
423
+ ### ClassTypeWithArgument
424
+
425
+ Class type with required argument.
426
+
427
+ ```typescript
428
+ type ClassTypeWithArgument<Arg> = new (arg: Arg) => any
429
+ ```
430
+
431
+ ### ClassTypeWithOptionalArgument
432
+
433
+ Class type with optional argument.
434
+
435
+ ```typescript
436
+ type ClassTypeWithOptionalArgument<Arg> = new (arg?: Arg) => any
437
+ ```
438
+
439
+ ### ClassTypeWithInstance
440
+
441
+ Class type with specific instance type.
442
+
443
+ ```typescript
444
+ type ClassTypeWithInstance<T> = new (...args: any[]) => T
445
+ ```
446
+
447
+ ### ClassTypeWithInstanceAndArgument
448
+
449
+ Class type with instance and required argument.
450
+
451
+ ```typescript
452
+ type ClassTypeWithInstanceAndArgument<T, Arg> = new (arg: Arg) => T
453
+ ```
454
+
455
+ ### ClassTypeWithInstanceAndOptionalArgument
456
+
457
+ Class type with instance and optional argument.
458
+
459
+ ```typescript
460
+ type ClassTypeWithInstanceAndOptionalArgument<T, Arg> = new (arg?: Arg) => T
461
+ ```
462
+
463
+ ### InjectionTokenSchemaType
464
+
465
+ Schema type for injection tokens.
466
+
467
+ ```typescript
468
+ type InjectionTokenSchemaType =
469
+ | BaseInjectionTokenSchemaType
470
+ | OptionalInjectionTokenSchemaType
471
+ ```
472
+
473
+ ### BaseInjectionTokenSchemaType
474
+
475
+ Base schema type.
476
+
477
+ ```typescript
478
+ type BaseInjectionTokenSchemaType = ZodObject | ZodRecord
479
+ ```
480
+
481
+ ### OptionalInjectionTokenSchemaType
482
+
483
+ Optional schema type.
484
+
485
+ ```typescript
486
+ type OptionalInjectionTokenSchemaType =
487
+ | ZodOptional<ZodObject>
488
+ | ZodOptional<ZodRecord>
489
+ ```
490
+
491
+ ### AnyInjectableType
492
+
493
+ Union of all injectable types.
494
+
495
+ ```typescript
496
+ type AnyInjectableType =
497
+ | ClassType
498
+ | InjectionToken<any, any>
499
+ | BoundInjectionToken<any, any>
500
+ | FactoryInjectionToken<any, any>
501
+ ```
502
+
503
+ ### InjectionTokenType
504
+
505
+ Union of injection token types.
506
+
507
+ ```typescript
508
+ type InjectionTokenType =
509
+ | InjectionToken<any, any>
510
+ | BoundInjectionToken<any, any>
511
+ | FactoryInjectionToken<any, any>
512
+ ```
513
+
514
+ ## Scope Compatibility
515
+
516
+ ### Injection Method Compatibility
517
+
518
+ | Scope | inject | asyncInject |
519
+ | --------- | ---------------- | ------------ |
520
+ | Singleton | ✅ Supported | ✅ Supported |
521
+ | Transient | ❌ Not Supported | ✅ Supported |
522
+ | Request | ✅ Supported | ✅ Supported |
523
+
524
+ **Note:** The `inject` function only works with Singleton and Request scopes because it requires synchronous resolution. Transient services must use `asyncInject` since they create new instances on each injection.
525
+
526
+ ## Error Classes
527
+
528
+ ### InstanceNotFoundError
529
+
530
+ Thrown when a service instance is not found.
531
+
532
+ ```typescript
533
+ class InstanceNotFoundError extends Error {
534
+ constructor(message: string)
535
+ }
536
+ ```
537
+
538
+ ### InstanceExpiredError
539
+
540
+ Thrown when a service instance has expired.
541
+
542
+ ```typescript
543
+ class InstanceExpiredError extends Error {
544
+ constructor(message: string)
545
+ }
546
+ ```
547
+
548
+ ### InstanceDestroyingError
549
+
550
+ Thrown when trying to access a service being destroyed.
551
+
552
+ ```typescript
553
+ class InstanceDestroyingError extends Error {
554
+ constructor(message: string)
555
+ }
556
+ ```
557
+
558
+ ### FactoryNotFoundError
559
+
560
+ Thrown when a factory is not found.
561
+
562
+ ```typescript
563
+ class FactoryNotFoundError extends Error {
564
+ constructor(message: string)
565
+ }
566
+ ```
567
+
568
+ ### FactoryTokenNotResolvedError
569
+
570
+ Thrown when a factory token cannot be resolved.
571
+
572
+ ```typescript
573
+ class FactoryTokenNotResolvedError extends Error {
574
+ constructor(message: string)
575
+ }
576
+ ```
577
+
578
+ ### UnknownError
579
+
580
+ Thrown for unexpected errors.
581
+
582
+ ```typescript
583
+ class UnknownError extends Error {
584
+ constructor(message: string)
585
+ }
586
+ ```
587
+
588
+ ## Usage Examples
589
+
590
+ ### Basic Service Registration
591
+
592
+ ```typescript
593
+ import { Container, inject, Injectable } from '@navios/di'
594
+
595
+ @Injectable()
596
+ class UserService {
597
+ getUsers() {
598
+ return ['Alice', 'Bob', 'Charlie']
599
+ }
600
+ }
601
+
602
+ const container = new Container()
603
+ const userService = await container.get(UserService)
604
+ ```
605
+
606
+ ### Service with Dependencies
607
+
608
+ ```typescript
609
+ import { inject, Injectable } from '@navios/di'
610
+
611
+ @Injectable()
612
+ class EmailService {
613
+ sendEmail(to: string, subject: string) {
614
+ return `Email sent to ${to}: ${subject}`
615
+ }
616
+ }
617
+
618
+ @Injectable()
619
+ class UserService {
620
+ private readonly emailService = inject(EmailService)
621
+
622
+ async createUser(name: string, email: string) {
623
+ await this.emailService.sendEmail(email, 'Welcome!', `Hello ${name}!`)
624
+ return { id: Math.random().toString(36), name, email }
625
+ }
626
+ }
627
+ ```
628
+
629
+ ### Injection Token Usage
630
+
631
+ ```typescript
632
+ import { inject, Injectable, InjectionToken } from '@navios/di'
633
+
634
+ import { z } from 'zod'
635
+
636
+ const configSchema = z.object({
637
+ apiUrl: z.string(),
638
+ timeout: z.number(),
639
+ })
640
+
641
+ const CONFIG_TOKEN = InjectionToken.create<Config, typeof configSchema>(
642
+ 'APP_CONFIG',
643
+ configSchema,
644
+ )
645
+
646
+ @Injectable({ token: CONFIG_TOKEN })
647
+ class ConfigService {
648
+ constructor(private config: z.infer<typeof configSchema>) {}
649
+
650
+ getApiUrl() {
651
+ return this.config.apiUrl
652
+ }
653
+ }
654
+
655
+ const config = await container.get(CONFIG_TOKEN, {
656
+ apiUrl: 'https://api.example.com',
657
+ timeout: 5000,
658
+ })
659
+ ```
660
+
661
+ ### Factory Usage
662
+
663
+ ```typescript
664
+ import { Factory, Injectable } from '@navios/di'
665
+
666
+ @Factory()
667
+ class DatabaseConnectionFactory {
668
+ create() {
669
+ return {
670
+ host: 'localhost',
671
+ port: 5432,
672
+ connected: true,
673
+ }
674
+ }
675
+ }
676
+
677
+ const connection = await container.get(DatabaseConnectionFactory)
678
+ ```
679
+
680
+ ### Service Lifecycle
681
+
682
+ ```typescript
683
+ import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
684
+
685
+ @Injectable()
686
+ class DatabaseService implements OnServiceInit, OnServiceDestroy {
687
+ private connection: any = null
688
+
689
+ async onServiceInit() {
690
+ console.log('Connecting to database...')
691
+ this.connection = await this.connect()
692
+ }
693
+
694
+ async onServiceDestroy() {
695
+ console.log('Disconnecting from database...')
696
+ if (this.connection) {
697
+ await this.connection.close()
698
+ }
699
+ }
700
+
701
+ private async connect() {
702
+ return { connected: true }
703
+ }
704
+ }
705
+ ```
706
+
707
+ ### Request Scope Usage
708
+
709
+ ```typescript
710
+ import { Container, inject, Injectable, InjectableScope } from '@navios/di'
711
+
712
+ @Injectable({ scope: InjectableScope.Request })
713
+ class RequestContext {
714
+ private readonly requestId = Math.random().toString(36)
715
+ private readonly startTime = Date.now()
716
+
717
+ getRequestId() {
718
+ return this.requestId
719
+ }
720
+
721
+ getDuration() {
722
+ return Date.now() - this.startTime
723
+ }
724
+ }
725
+
726
+ @Injectable({ scope: InjectableScope.Request })
727
+ class UserSession {
728
+ private readonly context = inject(RequestContext)
729
+ private readonly userId: string
730
+
731
+ constructor(userId: string) {
732
+ this.userId = userId
733
+ }
734
+
735
+ getUserId() {
736
+ return this.userId
737
+ }
738
+
739
+ async getRequestInfo() {
740
+ const ctx = await this.context
741
+ return {
742
+ userId: this.userId,
743
+ requestId: ctx.getRequestId(),
744
+ duration: ctx.getDuration(),
745
+ }
746
+ }
747
+ }
748
+
749
+ // Usage
750
+ const container = new Container()
751
+
752
+ // Begin request context
753
+ container.beginRequest('req-123', { userId: 'user123' })
754
+
755
+ // Get request-scoped instances
756
+ const session1 = await container.get(UserSession)
757
+ const session2 = await container.get(UserSession)
758
+
759
+ console.log(session1 === session2) // true - same instance within request
760
+
761
+ // End request context
762
+ await container.endRequest('req-123')
763
+ ```