@navios/di 0.1.10 → 0.1.12
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/docs/concepts/injectable.md +182 -0
- package/docs/concepts/injection-token.md +145 -0
- package/lib/_tsup-dts-rollup.d.mts +558 -0
- package/lib/_tsup-dts-rollup.d.ts +558 -0
- package/lib/index.d.mts +61 -433
- package/lib/index.d.ts +61 -433
- package/lib/index.js +861 -692
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +858 -668
- package/lib/index.mjs.map +1 -1
- package/package.json +4 -4
- package/project.json +4 -1
- package/src/__tests__/injectable.spec.mts +46 -2
- package/src/__tests__/service-locator.spec.mts +35 -0
- package/src/decorators/injectable.decorator.mts +24 -16
- package/src/injector.mts +2 -1
- package/src/resolve-service.mts +2 -2
- package/src/service-locator.mts +29 -18
- package/src/utils/get-injectors.mts +10 -2
- package/tsconfig.json +1 -1
- package/tsup.config.mts +12 -0
- package/lib/index.d.mts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/tsdown.config.mts +0 -10
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# @Injectable decorator
|
|
2
|
+
|
|
3
|
+
The `@Injectable` decorator is used to define a class or a factory class as an injectable service.
|
|
4
|
+
|
|
5
|
+
## Parameters
|
|
6
|
+
|
|
7
|
+
The `@Injectable` decorator accepts the following fields in its options:
|
|
8
|
+
|
|
9
|
+
- `token`: The injection token to use for the service. If not provided, will create a new token using the class itself.
|
|
10
|
+
- `scope`: The lifetime of the service. Accepts `InjectableScope.Singleton` or `InjectableScope.Instance`. By default, it will be `InjectableScope.Singleton`.
|
|
11
|
+
- `type`: The type of the service. Accepts `InjectableType.Class` or `InjectableType.Factory`. By default, it will be `InjectableType.Class`.
|
|
12
|
+
- `registry`: The registry to use for the service. Uses the default registry if not provided.
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
Injectable can be used as a class decorator or a factory decorator.
|
|
17
|
+
|
|
18
|
+
Inside a class that you're decorating with `@Injectable` you can use `inject` and `syncInject` functions to inject the services.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
@Injectable()
|
|
22
|
+
class GreeterService {
|
|
23
|
+
sayHello(name: string) {
|
|
24
|
+
return `Hello ${name}`
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Injectable()
|
|
29
|
+
class UserService {
|
|
30
|
+
private readonly greeterService = syncInject(GreeterService)
|
|
31
|
+
|
|
32
|
+
makeGreeting(name: string) {
|
|
33
|
+
return this.greeterService.sayHello(name)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Please note that `syncInject` can be used only with services that are created with `InjectableScope.Singleton`.
|
|
39
|
+
|
|
40
|
+
If you need to inject a service that is created with `InjectableScope.Instance`, you can use `inject` function. and it will return a Promise.
|
|
41
|
+
|
|
42
|
+
For example:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
@Injectable({ scope: InjectableScope.Instance })
|
|
46
|
+
class GreeterService {
|
|
47
|
+
private readonly createdAt = new Date()
|
|
48
|
+
|
|
49
|
+
sayHello(name: string) {
|
|
50
|
+
return `Hello ${name} ${this.createdAt.toISOString()}`
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Injectable()
|
|
55
|
+
class UserService {
|
|
56
|
+
private readonly greeterService = inject(GreeterService)
|
|
57
|
+
|
|
58
|
+
async makeGreeting(name: string) {
|
|
59
|
+
const service = await this.greeterService
|
|
60
|
+
return service.sayHello(name)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Examples
|
|
66
|
+
|
|
67
|
+
### Simple class
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
@Injectable()
|
|
71
|
+
class GreeterService {
|
|
72
|
+
sayHello(name: string) {
|
|
73
|
+
return `Hello ${name}`
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const greeterService = await inject(GreeterService)
|
|
78
|
+
console.log(greeterService.sayHello('John'))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Simple Factory
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
@Injectable({ type: InjectableType.Factory })
|
|
85
|
+
class GreeterServiceFactory {
|
|
86
|
+
create() {
|
|
87
|
+
return new GreeterService()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const greeterService = await inject(GreeterServiceFactory)
|
|
92
|
+
console.log(greeterService.sayHello('John'))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Class with token
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
export interface GreeterServiceInterface {
|
|
99
|
+
sayHello(name: string): string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const GreeterServiceParams = z.object({
|
|
103
|
+
context: z.string(),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
export const GREETER_SERVICE = InjectionToken.create<
|
|
107
|
+
GreeterServiceInterface,
|
|
108
|
+
typeof GreeterServiceParams
|
|
109
|
+
>('GreeterService', GreeterServiceParams)
|
|
110
|
+
|
|
111
|
+
@Injectable({ token: GREETER_SERVICE })
|
|
112
|
+
class GreeterService {
|
|
113
|
+
constructor(private readonly config: z.infer<typeof GreeterServiceParams>) {}
|
|
114
|
+
|
|
115
|
+
sayHello(name: string) {
|
|
116
|
+
return `Hello ${name} ${this.config.context}`
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const greeterService = await inject(GREETER_SERVICE, { context: 'World' })
|
|
121
|
+
console.log(greeterService.sayHello('John'))
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Factory with token
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
export interface GreeterServiceInterface {
|
|
128
|
+
sayHello(name: string): string
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const GreeterServiceParams = z.object({
|
|
132
|
+
context: z.string(),
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
export const GREETER_SERVICE = InjectionToken.create<
|
|
136
|
+
GreeterServiceInterface,
|
|
137
|
+
typeof GreeterServiceParams
|
|
138
|
+
>('GreeterService', GreeterServiceParams)
|
|
139
|
+
|
|
140
|
+
@Injectable({ type: InjectableType.Factory, token: GREETER_SERVICE })
|
|
141
|
+
class GreeterServiceFactory {
|
|
142
|
+
create(ctx: FactoryContext, args: z.infer<typeof GreeterServiceParams>) {
|
|
143
|
+
return new GreeterService(args)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const greeterService = await inject(GREETER_SERVICE, { context: 'World' })
|
|
148
|
+
console.log(greeterService.sayHello('John'))
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## InjectableScope
|
|
152
|
+
|
|
153
|
+
The `InjectableScope` enum defines the scope of the service.
|
|
154
|
+
|
|
155
|
+
- `InjectableScope.Singleton`: The service will be created once and reused.
|
|
156
|
+
- `InjectableScope.Instance`: The service will be created every time it is injected.
|
|
157
|
+
|
|
158
|
+
## InjectableType
|
|
159
|
+
|
|
160
|
+
The `InjectableType` enum defines the type of the service.
|
|
161
|
+
|
|
162
|
+
- `InjectableType.Class`: The service will be a class.
|
|
163
|
+
- `InjectableType.Factory`: The service will be a factory.
|
|
164
|
+
|
|
165
|
+
## Registry
|
|
166
|
+
|
|
167
|
+
The `Registry` is the registry of the service. It is used to store the service and its dependencies.
|
|
168
|
+
|
|
169
|
+
## FactoryContext
|
|
170
|
+
|
|
171
|
+
The `FactoryContext` is the context of the factory. It is used to add additional information to the factory.
|
|
172
|
+
|
|
173
|
+
Context API:
|
|
174
|
+
|
|
175
|
+
- `inject`: Injects the service, same as global inject, but additionally it will track the dependencies of the service.
|
|
176
|
+
- `on`: Adds a listener to the service locator event bus.
|
|
177
|
+
- `getDependencies`: Returns the dependencies of the service.
|
|
178
|
+
- `invalidate`: Invalidates self and all the services that depend on it.
|
|
179
|
+
- `addEffect`: Adds an effect to the service. Effect is a function that will be called when the service is invalidated.
|
|
180
|
+
- `setTtl`: Sets the ttl of the service.
|
|
181
|
+
- `getTtl`: Returns the ttl of the service.
|
|
182
|
+
- `locator`: Returns the service locator you are currently in.
|
|
@@ -0,0 +1,145 @@
|
|
|
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.
|