@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.
- package/README.md +301 -39
- package/docs/README.md +122 -49
- package/docs/api-reference.md +763 -0
- package/docs/container.md +274 -0
- package/docs/examples/basic-usage.mts +97 -0
- package/docs/examples/factory-pattern.mts +318 -0
- package/docs/examples/injection-tokens.mts +225 -0
- package/docs/examples/request-scope-example.mts +254 -0
- package/docs/examples/service-lifecycle.mts +359 -0
- package/docs/factory.md +584 -0
- package/docs/getting-started.md +308 -0
- package/docs/injectable.md +496 -0
- package/docs/injection-tokens.md +400 -0
- package/docs/lifecycle.md +539 -0
- package/docs/scopes.md +749 -0
- package/lib/_tsup-dts-rollup.d.mts +495 -150
- package/lib/_tsup-dts-rollup.d.ts +495 -150
- package/lib/index.d.mts +26 -12
- package/lib/index.d.ts +26 -12
- package/lib/index.js +993 -462
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +983 -453
- package/lib/index.mjs.map +1 -1
- package/package.json +2 -2
- package/project.json +10 -2
- package/src/__tests__/container.spec.mts +1301 -0
- package/src/__tests__/factory.spec.mts +137 -0
- package/src/__tests__/injectable.spec.mts +32 -88
- package/src/__tests__/injection-token.spec.mts +333 -17
- package/src/__tests__/request-scope.spec.mts +263 -0
- package/src/__type-tests__/factory.spec-d.mts +65 -0
- package/src/__type-tests__/inject.spec-d.mts +27 -28
- package/src/__type-tests__/injectable.spec-d.mts +42 -206
- package/src/container.mts +167 -0
- package/src/decorators/factory.decorator.mts +79 -0
- package/src/decorators/index.mts +1 -0
- package/src/decorators/injectable.decorator.mts +6 -56
- package/src/enums/injectable-scope.enum.mts +5 -1
- package/src/event-emitter.mts +18 -20
- package/src/factory-context.mts +2 -10
- package/src/index.mts +3 -2
- package/src/injection-token.mts +24 -9
- package/src/injector.mts +8 -20
- package/src/interfaces/factory.interface.mts +3 -3
- package/src/interfaces/index.mts +2 -0
- package/src/interfaces/on-service-destroy.interface.mts +3 -0
- package/src/interfaces/on-service-init.interface.mts +3 -0
- package/src/registry.mts +7 -16
- package/src/request-context-holder.mts +145 -0
- package/src/service-instantiator.mts +158 -0
- package/src/service-locator-event-bus.mts +0 -28
- package/src/service-locator-instance-holder.mts +27 -16
- package/src/service-locator-manager.mts +84 -0
- package/src/service-locator.mts +550 -395
- package/src/utils/defer.mts +73 -0
- package/src/utils/get-injectors.mts +93 -80
- package/src/utils/index.mts +2 -0
- package/src/utils/types.mts +52 -0
- package/docs/concepts/injectable.md +0 -182
- package/docs/concepts/injection-token.md +0 -145
- package/src/proxy-service-locator.mts +0 -83
- package/src/resolve-service.mts +0 -41
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide will help you get up and running with Navios DI quickly. We'll cover installation, basic setup, and your first dependency injection example.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install Navios DI using your preferred package manager:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# npm
|
|
11
|
+
npm install @navios/di
|
|
12
|
+
|
|
13
|
+
# yarn
|
|
14
|
+
yarn add @navios/di
|
|
15
|
+
|
|
16
|
+
# pnpm
|
|
17
|
+
pnpm add @navios/di
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- Node.js 18+
|
|
23
|
+
- TypeScript 4.5+
|
|
24
|
+
- A modern TypeScript project
|
|
25
|
+
|
|
26
|
+
## Basic Setup
|
|
27
|
+
|
|
28
|
+
### 1. Make sure Legacy Decorators disabled
|
|
29
|
+
|
|
30
|
+
Make sure your `tsconfig.json` has legacy decorators disabled:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"compilerOptions": {
|
|
35
|
+
"target": "ES2022",
|
|
36
|
+
"module": "ESNext",
|
|
37
|
+
"moduleResolution": "node16"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Import the Library
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { asyncInject, Container, inject, Injectable } from '@navios/di'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Your First Example
|
|
49
|
+
|
|
50
|
+
Let's create a simple example with a user service that depends on an email service:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { asyncInject, Container, inject, Injectable } from '@navios/di'
|
|
54
|
+
|
|
55
|
+
// 1. Create an email service
|
|
56
|
+
@Injectable()
|
|
57
|
+
class EmailService {
|
|
58
|
+
async sendEmail(to: string, subject: string, body: string) {
|
|
59
|
+
console.log(`Sending email to ${to}`)
|
|
60
|
+
console.log(`Subject: ${subject}`)
|
|
61
|
+
console.log(`Body: ${body}`)
|
|
62
|
+
return { success: true, messageId: Math.random().toString(36) }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 2. Create a user service that depends on the email service
|
|
67
|
+
@Injectable()
|
|
68
|
+
class UserService {
|
|
69
|
+
private readonly emailService = inject(EmailService)
|
|
70
|
+
|
|
71
|
+
async createUser(name: string, email: string) {
|
|
72
|
+
console.log(`Creating user: ${name}`)
|
|
73
|
+
|
|
74
|
+
// Send welcome email
|
|
75
|
+
await this.emailService.sendEmail(
|
|
76
|
+
email,
|
|
77
|
+
'Welcome!',
|
|
78
|
+
`Hello ${name}, welcome to our platform!`,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return { id: Math.random().toString(36), name, email }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 3. Use the services
|
|
86
|
+
async function main() {
|
|
87
|
+
const container = new Container()
|
|
88
|
+
|
|
89
|
+
// Get the user service (email service will be automatically injected)
|
|
90
|
+
const userService = await container.get(UserService)
|
|
91
|
+
|
|
92
|
+
// Create a user
|
|
93
|
+
const user = await userService.createUser('Alice', 'alice@example.com')
|
|
94
|
+
console.log('Created user:', user)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Run the example
|
|
98
|
+
main().catch(console.error)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Understanding the Example
|
|
102
|
+
|
|
103
|
+
### Service Registration
|
|
104
|
+
|
|
105
|
+
The `@Injectable()` decorator tells Navios DI that this class can be injected into other services:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
@Injectable()
|
|
109
|
+
class EmailService {
|
|
110
|
+
// Service implementation
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Dependency Injection
|
|
115
|
+
|
|
116
|
+
The `inject()` function injects a dependency synchronously:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
@Injectable()
|
|
120
|
+
class UserService {
|
|
121
|
+
private readonly emailService = inject(EmailService)
|
|
122
|
+
// ^^^^^^^^^^^^
|
|
123
|
+
// Dependency injection
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Container Usage
|
|
128
|
+
|
|
129
|
+
The `Container` class manages all your services:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const container = new Container()
|
|
133
|
+
const userService = await container.get(UserService)
|
|
134
|
+
// ^^^^^^^^^^^^
|
|
135
|
+
// Get service instance
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Alternative Injection Methods
|
|
139
|
+
|
|
140
|
+
### Asynchronous Injection
|
|
141
|
+
|
|
142
|
+
Use `asyncInject()` for asynchronous dependency resolution:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
@Injectable()
|
|
146
|
+
class UserService {
|
|
147
|
+
private readonly emailService = asyncInject(EmailService)
|
|
148
|
+
|
|
149
|
+
async createUser(name: string, email: string) {
|
|
150
|
+
const emailService = await this.emailService
|
|
151
|
+
// ^^^^^^^^^^^^^^^^^^^^^^^
|
|
152
|
+
// Await the dependency
|
|
153
|
+
await emailService.sendEmail(email, 'Welcome!', `Hello ${name}!`)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Service Scopes
|
|
159
|
+
|
|
160
|
+
### Singleton (Default)
|
|
161
|
+
|
|
162
|
+
Services are singletons by default - one instance shared across the application:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
@Injectable() // Same as @Injectable({ scope: InjectableScope.Singleton })
|
|
166
|
+
class SingletonService {
|
|
167
|
+
private readonly id = Math.random()
|
|
168
|
+
|
|
169
|
+
getId() {
|
|
170
|
+
return this.id
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Both instances will have the same ID
|
|
175
|
+
const service1 = await container.get(SingletonService)
|
|
176
|
+
const service2 = await container.get(SingletonService)
|
|
177
|
+
console.log(service1.getId() === service2.getId()) // true
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Transient
|
|
181
|
+
|
|
182
|
+
Create a new instance for each injection:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { InjectableScope } from '@navios/di'
|
|
186
|
+
|
|
187
|
+
@Injectable({ scope: InjectableScope.Transient })
|
|
188
|
+
class TransientService {
|
|
189
|
+
private readonly id = Math.random()
|
|
190
|
+
|
|
191
|
+
getId() {
|
|
192
|
+
return this.id
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Each instance will have a different ID
|
|
197
|
+
const service1 = await container.get(TransientService)
|
|
198
|
+
const service2 = await container.get(TransientService)
|
|
199
|
+
console.log(service1.getId() === service2.getId()) // false
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Next Steps
|
|
203
|
+
|
|
204
|
+
Now that you have the basics down, explore these topics:
|
|
205
|
+
|
|
206
|
+
- **[Container](./container.md)** - Learn about the Container API
|
|
207
|
+
- **[Injectable Decorator](./injectable.md)** - Deep dive into service registration
|
|
208
|
+
- **[Factory Decorator](./factory.md)** - Create services using factory pattern
|
|
209
|
+
- **[Injection Tokens](./injection-tokens.md)** - Flexible dependency resolution
|
|
210
|
+
- **[Service Lifecycle](./lifecycle.md)** - Initialization and cleanup hooks
|
|
211
|
+
|
|
212
|
+
## Common Patterns
|
|
213
|
+
|
|
214
|
+
### Configuration Service
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { Injectable, InjectionToken } from '@navios/di'
|
|
218
|
+
|
|
219
|
+
import { z } from 'zod'
|
|
220
|
+
|
|
221
|
+
const configSchema = z.object({
|
|
222
|
+
apiUrl: z.string(),
|
|
223
|
+
timeout: z.number(),
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const CONFIG_TOKEN = InjectionToken.create<ConfigService, typeof configSchema>(
|
|
227
|
+
'APP_CONFIG',
|
|
228
|
+
configSchema,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
@Injectable({ token: CONFIG_TOKEN })
|
|
232
|
+
class ConfigService {
|
|
233
|
+
constructor(private config: z.infer<typeof configSchema>) {}
|
|
234
|
+
|
|
235
|
+
getApiUrl() {
|
|
236
|
+
return this.config.apiUrl
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
getTimeout() {
|
|
240
|
+
return this.config.timeout
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Usage
|
|
245
|
+
const config = await container.get(CONFIG_TOKEN, {
|
|
246
|
+
apiUrl: 'https://api.example.com',
|
|
247
|
+
timeout: 5000,
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Service with Lifecycle
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
255
|
+
|
|
256
|
+
@Injectable()
|
|
257
|
+
class DatabaseService implements OnServiceInit, OnServiceDestroy {
|
|
258
|
+
private connection: any = null
|
|
259
|
+
|
|
260
|
+
async onServiceInit() {
|
|
261
|
+
console.log('Connecting to database...')
|
|
262
|
+
this.connection = await this.connect()
|
|
263
|
+
console.log('Database connected')
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async onServiceDestroy() {
|
|
267
|
+
console.log('Disconnecting from database...')
|
|
268
|
+
if (this.connection) {
|
|
269
|
+
await this.connection.close()
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private async connect() {
|
|
274
|
+
// Database connection logic
|
|
275
|
+
return { connected: true }
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Troubleshooting
|
|
281
|
+
|
|
282
|
+
### Common Issues
|
|
283
|
+
|
|
284
|
+
**Decorators not working:**
|
|
285
|
+
|
|
286
|
+
- Ensure `experimentalDecorators: false` in `tsconfig.json`
|
|
287
|
+
- Make sure you're using TypeScript 5+
|
|
288
|
+
|
|
289
|
+
**Circular dependencies:**
|
|
290
|
+
|
|
291
|
+
- Use `asyncInject()` instead of `inject()` for circular dependencies
|
|
292
|
+
- Consider restructuring your services to avoid circular references
|
|
293
|
+
|
|
294
|
+
**Services not found:**
|
|
295
|
+
|
|
296
|
+
- Make sure services are decorated with `@Injectable()`
|
|
297
|
+
- Check that services are imported before use
|
|
298
|
+
|
|
299
|
+
**Type errors:**
|
|
300
|
+
|
|
301
|
+
- Ensure proper TypeScript configuration
|
|
302
|
+
- Use proper type annotations for injected services
|
|
303
|
+
|
|
304
|
+
### Getting Help
|
|
305
|
+
|
|
306
|
+
- Check the [API Reference](./api-reference.md)
|
|
307
|
+
- Look at [Advanced Patterns](./advanced-patterns.md)
|
|
308
|
+
- Review the [Examples](./examples/) folder
|