@navios/di 0.2.0 → 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 +301 -39
  2. package/docs/README.md +122 -49
  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 +495 -150
  17. package/lib/_tsup-dts-rollup.d.ts +495 -150
  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 +24 -9
  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 +550 -395
  55. package/src/utils/defer.mts +73 -0
  56. package/src/utils/get-injectors.mts +93 -80
  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
@@ -1,145 +0,0 @@
1
- # Injection Token
2
-
3
- Injection tokens are used to identify and retrieve services from the dependency injection container. They are typically defined as constants and used to inject services into classes.
4
-
5
- ## Creating an Injection Token
6
-
7
- To create an injection token, you can use the `InjectionToken` class from the `@navios/di` or `@navios/core` package. Here's an example:
8
-
9
- ```ts
10
- import { InjectionToken } from '@navios/di'
11
-
12
- export const GREETER_SERVICE =
13
- InjectionToken.create<GreeterService>('GreeterService')
14
-
15
- @Injectable({ token: GREETER_SERVICE })
16
- class GreeterService {}
17
- ```
18
-
19
- ## Using an Injection Token
20
-
21
- To use an injection token, you can inject it into a class or a function.
22
-
23
- ```ts
24
- import { inject } from '@navios/di'
25
-
26
- const greeterService = await inject(GREETER_SERVICE)
27
- ```
28
-
29
- or
30
-
31
- ```ts
32
- @Injectable()
33
- class UserService {
34
- private readonly greeterService = inject(GREETER_SERVICE) // This will be a Promise<GreeterService>
35
- private readonly greeterServiceSync = syncInject(GREETER_SERVICE) // This will be a GreeterService
36
- }
37
- ```
38
-
39
- ## Adding a parameter to the injection token
40
-
41
- You can add a parameter to the injection token to make it more specific.
42
-
43
- ```ts
44
- import { z } from 'zod'
45
-
46
- const GreeterServiceParams = z.object({
47
- context: z.string(),
48
- })
49
-
50
- export const GREETER_SERVICE = InjectionToken.create<
51
- GreeterService,
52
- typeof GreeterServiceParams
53
- >('GreeterService', GreeterServiceParams)
54
-
55
- @Injectable({ token: GREETER_SERVICE })
56
- class GreeterService {}
57
-
58
- const greeterService = await inject(GREETER_SERVICE, { context: 'Hello' })
59
- ```
60
-
61
- ## Providing a value to an injection token
62
-
63
- You can provide a value to an injection token by using the `bound` function.
64
-
65
- ```ts
66
- import { inject, InjectionToken } from '@navios/di'
67
-
68
- const helloGreeterService = InjectionToken.bound(GREETER_SERVICE, {
69
- context: 'Hello',
70
- })
71
-
72
- const greeterService = await inject(helloGreeterService)
73
- ```
74
-
75
- ## Providing a factory to an injection token
76
-
77
- You can provide a factory to an injection token by using the `factory` function.
78
-
79
- It is useful, when you need to bind a value to a result of another service (e.g. a configuration).
80
-
81
- ```ts
82
- import { inject, InjectionToken } from '@navios/di'
83
-
84
- @Injectable()
85
- class GreeterConfigService {
86
- getContext() {
87
- return 'Hello'
88
- }
89
- }
90
- const helloGreeterService = InjectionToken.factory(
91
- GREETER_SERVICE,
92
- async () => {
93
- const config = await inject(GreeterConfigService)
94
- return { context: config.getContext() }
95
- },
96
- )
97
-
98
- const greeterService = await inject(helloGreeterService)
99
- ```
100
-
101
- ## API
102
-
103
- ### `InjectionToken.create`
104
-
105
- Creates a new injection token.
106
-
107
- Generic arguments:
108
-
109
- - `T`: The type of the value to bind to the injection token.
110
- - `P`: Zod schema type of the parameters of the injection token.
111
-
112
- Arguments:
113
-
114
- - `name: string | Class | symbol`: The name of the injection token.
115
- - `params: ZodSchema | undefined`: The parameters of the injection token.
116
-
117
- Returns:
118
-
119
- - `InjectionToken`: The new injection token.
120
-
121
- ### `InjectionToken.bound`
122
-
123
- Creates a new injection token that is bound to a value.
124
-
125
- Arguments:
126
-
127
- - `token: InjectionToken`: The injection token to bind.
128
- - `value: any`: The value to bind to the injection token.
129
-
130
- Returns:
131
-
132
- - `BoundInjectionToken`: The new injection token.
133
-
134
- ### `InjectionToken.factory`
135
-
136
- Creates a new injection token that is a factory.
137
-
138
- Arguments:
139
-
140
- - `token: InjectionToken`: The injection token to bind.
141
- - `factory: () => Promise<any>`: The factory to bind to the injection token.
142
-
143
- Returns:
144
-
145
- - `FactoryInjectionToken`: The new injection token.
@@ -1,83 +0,0 @@
1
- import type { z, ZodObject, ZodOptional } from 'zod/v4'
2
-
3
- import type { FactoryContext } from './factory-context.mjs'
4
- import type {
5
- BoundInjectionToken,
6
- FactoryInjectionToken,
7
- InjectionToken,
8
- } from './injection-token.mjs'
9
- import type { ServiceLocatorEventBus } from './service-locator-event-bus.mjs'
10
- import type { ServiceLocator } from './service-locator.mjs'
11
-
12
- export class ProxyServiceLocator implements ServiceLocator {
13
- constructor(
14
- private readonly serviceLocator: ServiceLocator,
15
- private readonly ctx: FactoryContext,
16
- ) {}
17
-
18
- getEventBus(): ServiceLocatorEventBus {
19
- return this.serviceLocator.getEventBus()
20
- }
21
-
22
- // @ts-expect-error We don't need all the properties of the class
23
- public getInstance(
24
- token:
25
- | InjectionToken<any, any>
26
- | BoundInjectionToken<any, any>
27
- | FactoryInjectionToken<any, any>,
28
- args?: any,
29
- ) {
30
- // @ts-expect-error We don't need all the properties of the class
31
- return this.ctx.inject(token, args).then(
32
- (instance) => {
33
- return [undefined, instance]
34
- },
35
- (error) => {
36
- return [error]
37
- },
38
- )
39
- }
40
- public getOrThrowInstance<
41
- Instance,
42
- Schema extends ZodObject<any> | ZodOptional<ZodObject<any>> | undefined,
43
- >(
44
- token: InjectionToken<Instance, Schema>,
45
- args: Schema extends ZodObject<any>
46
- ? z.input<Schema>
47
- : Schema extends ZodOptional<ZodObject<any>>
48
- ? z.input<Schema> | undefined
49
- : undefined,
50
- ): Promise<Instance> {
51
- return this.ctx.inject(token, args)
52
- }
53
- public getSyncInstance<
54
- Instance,
55
- Schema extends ZodObject<any> | ZodOptional<ZodObject<any>> | undefined,
56
- >(
57
- token: InjectionToken<Instance, Schema>,
58
- args: Schema extends ZodObject<any>
59
- ? z.input<Schema>
60
- : Schema extends ZodOptional<ZodObject<any>>
61
- ? z.input<Schema> | undefined
62
- : undefined,
63
- ): Instance | null {
64
- return this.serviceLocator.getSyncInstance<Instance, Schema>(token, args)
65
- }
66
- invalidate(service: string, round?: number): Promise<any> {
67
- return this.serviceLocator.invalidate(service, round)
68
- }
69
- ready(): Promise<null> {
70
- return this.serviceLocator.ready()
71
- }
72
- makeInstanceName(token: InjectionToken<any, any>, args: any): string {
73
- return this.serviceLocator.makeInstanceName(token, args)
74
- }
75
- }
76
-
77
- export function makeProxyServiceLocator(
78
- serviceLocator: ServiceLocator,
79
- ctx: FactoryContext,
80
- ): ServiceLocator {
81
- // @ts-expect-error We don't need all the properties of the class
82
- return new ProxyServiceLocator(serviceLocator, ctx)
83
- }
@@ -1,41 +0,0 @@
1
- import type { FactoryContext } from './factory-context.mjs'
2
- import type { ClassType } from './injection-token.mjs'
3
-
4
- import { makeProxyServiceLocator } from './proxy-service-locator.mjs'
5
- import { getInjectors } from './utils/index.mjs'
6
-
7
- export async function resolveService<T extends ClassType>(
8
- ctx: FactoryContext,
9
- target: T,
10
- args: any[] = [],
11
- ): Promise<InstanceType<T>> {
12
- const { wrapSyncInit, provideServiceLocator } = getInjectors({
13
- baseLocator: ctx.locator,
14
- })
15
- const proxyServiceLocator = makeProxyServiceLocator(ctx.locator, ctx)
16
- const tryLoad = wrapSyncInit(() => {
17
- const original = provideServiceLocator(proxyServiceLocator)
18
- let result = new target(...args)
19
- provideServiceLocator(original)
20
- return result
21
- })
22
- let [instance, promises] = tryLoad()
23
- if (promises.length > 0) {
24
- await Promise.allSettled(promises)
25
- const newRes = tryLoad()
26
- instance = newRes[0]
27
- promises = newRes[1]
28
- }
29
- if (promises.length > 0) {
30
- console.error(`[ServiceLocator] ${target.name} has problem with it's definition.
31
-
32
- One or more of the dependencies are registered as a InjectableScope.Instance and are used with syncInject.
33
-
34
- Please use inject instead of syncInject to load those dependencies.`)
35
- throw new Error(
36
- `[ServiceLocator] Service ${target.name} cannot be instantiated.`,
37
- )
38
- }
39
-
40
- return instance
41
- }