@navios/di 0.2.1 → 0.3.1

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 +494 -145
  17. package/lib/_tsup-dts-rollup.d.ts +494 -145
  18. package/lib/index.d.mts +26 -12
  19. package/lib/index.d.ts +26 -12
  20. package/lib/index.js +1021 -470
  21. package/lib/index.js.map +1 -1
  22. package/lib/index.mjs +1011 -461
  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 +427 -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 +174 -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,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