@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,274 @@
1
+ # Container
2
+
3
+ The `Container` class is the main entry point for dependency injection in Navios DI. It provides a simplified, high-level API for managing services and their dependencies.
4
+
5
+ ## Overview
6
+
7
+ The Container wraps a `ServiceLocator` instance and provides convenient methods for:
8
+
9
+ - Getting service instances
10
+ - Invalidating services and their dependencies
11
+ - Managing service lifecycle
12
+ - Accessing the underlying service locator for advanced usage
13
+
14
+ ## Basic Usage
15
+
16
+ ### Creating a Container
17
+
18
+ ```typescript
19
+ import { Container } from '@navios/di'
20
+
21
+ // Create with default registry
22
+ const container = new Container()
23
+
24
+ // Create with custom registry
25
+ const customRegistry = new Registry()
26
+ const container = new Container(customRegistry)
27
+
28
+ // Create with custom registry and logger
29
+ const mockLogger = {
30
+ log: console.log,
31
+ error: console.error,
32
+ warn: console.warn,
33
+ info: console.info,
34
+ debug: console.debug,
35
+ }
36
+ const container = new Container(customRegistry, mockLogger)
37
+ ```
38
+
39
+ ### Getting Service Instances
40
+
41
+ The `get` method is the primary way to retrieve service instances:
42
+
43
+ ```typescript
44
+ import { Container, Injectable } from '@navios/di'
45
+
46
+ @Injectable()
47
+ class UserService {
48
+ getUsers() {
49
+ return ['Alice', 'Bob', 'Charlie']
50
+ }
51
+ }
52
+
53
+ const container = new Container()
54
+ const userService = await container.get(UserService)
55
+ console.log(userService.getUsers()) // ['Alice', 'Bob', 'Charlie']
56
+ ```
57
+
58
+ ### Type-Safe Service Resolution
59
+
60
+ The Container provides full type safety for service resolution:
61
+
62
+ ```typescript
63
+ // Simple class injection
64
+ const service: UserService = await container.get(UserService)
65
+
66
+ // Injection token with schema
67
+ const config = await container.get(CONFIG_TOKEN, {
68
+ apiUrl: 'https://api.example.com',
69
+ timeout: 5000,
70
+ })
71
+
72
+ // Bound injection token
73
+ const boundService = await container.get(BoundConfigToken)
74
+
75
+ // Factory injection token
76
+ const factoryService = await container.get(FactoryConfigToken)
77
+ ```
78
+
79
+ ## Advanced Usage
80
+
81
+ ### Service Invalidation
82
+
83
+ The `invalidate` method allows you to remove a service and its dependencies from the container:
84
+
85
+ ```typescript
86
+ @Injectable()
87
+ class CacheService {
88
+ private cache = new Map()
89
+
90
+ set(key: string, value: any) {
91
+ this.cache.set(key, value)
92
+ }
93
+
94
+ get(key: string) {
95
+ return this.cache.get(key)
96
+ }
97
+ }
98
+
99
+ const container = new Container()
100
+ const cacheService = await container.get(CacheService)
101
+
102
+ // Use the service
103
+ cacheService.set('user:123', { name: 'Alice' })
104
+
105
+ // Invalidate the service
106
+ await container.invalidate(cacheService)
107
+
108
+ // Next access will create a new instance
109
+ const newCacheService = await container.get(CacheService)
110
+ console.log(newCacheService.get('user:123')) // undefined (new instance)
111
+ ```
112
+
113
+ ### Waiting for Operations
114
+
115
+ The `ready` method waits for all pending operations to complete:
116
+
117
+ ```typescript
118
+ const container = new Container()
119
+
120
+ // Start multiple async operations
121
+ const promises = [
122
+ container.get(UserService),
123
+ container.get(EmailService),
124
+ container.get(DatabaseService),
125
+ ]
126
+
127
+ // Wait for all to complete
128
+ await container.ready()
129
+
130
+ // All services are now ready
131
+ const [userService, emailService, dbService] = await Promise.all(promises)
132
+ ```
133
+
134
+ ### Accessing the Service Locator
135
+
136
+ For advanced usage, you can access the underlying `ServiceLocator`:
137
+
138
+ ```typescript
139
+ const container = new Container()
140
+ const serviceLocator = container.getServiceLocator()
141
+
142
+ // Use advanced ServiceLocator methods
143
+ const instance = await serviceLocator.getOrThrowInstance(UserService)
144
+ ```
145
+
146
+ ## Best Practices
147
+
148
+ ### 1. Use Container for Application Setup
149
+
150
+ ```typescript
151
+ // app.ts
152
+ import { Container } from '@navios/di'
153
+
154
+ async function bootstrap() {
155
+ const container = new Container()
156
+
157
+ // Initialize core services
158
+ await container.get(DatabaseService)
159
+ await container.get(CacheService)
160
+ await container.get(EmailService)
161
+
162
+ // Start the application
163
+ const app = await container.get(ApplicationService)
164
+ await app.start()
165
+
166
+ return container
167
+ }
168
+
169
+ const container = await bootstrap()
170
+ ```
171
+
172
+ ### 2. Invalidate Services When Needed
173
+
174
+ ```typescript
175
+ // When configuration changes
176
+ await container.invalidate(configService)
177
+
178
+ // When cache needs clearing
179
+ await container.invalidate(cacheService)
180
+
181
+ // When user logs out
182
+ await container.invalidate(userSessionService)
183
+ ```
184
+
185
+ ### 3. Handle Errors Gracefully
186
+
187
+ ```typescript
188
+ try {
189
+ const service = await container.get(NonExistentService)
190
+ } catch (error) {
191
+ if (error instanceof InstanceNotFoundError) {
192
+ console.error('Service not registered:', error.message)
193
+ } else {
194
+ console.error('Unexpected error:', error)
195
+ }
196
+ }
197
+ ```
198
+
199
+ ### 4. Use Custom Registries for Modularity
200
+
201
+ ```typescript
202
+ // Create separate registries for different modules
203
+ const userRegistry = new Registry()
204
+ const paymentRegistry = new Registry()
205
+
206
+ // Register services in their respective registries
207
+ @Injectable({ registry: userRegistry })
208
+ class UserService {}
209
+
210
+ @Injectable({ registry: paymentRegistry })
211
+ class PaymentService {}
212
+
213
+ // Create containers with specific registries
214
+ const userContainer = new Container(userRegistry)
215
+ const paymentContainer = new Container(paymentRegistry)
216
+ ```
217
+
218
+ ## API Reference
219
+
220
+ ### Constructor
221
+
222
+ ```typescript
223
+ constructor(registry?: Registry, logger?: Console | null)
224
+ ```
225
+
226
+ - `registry`: Optional registry instance (defaults to global registry)
227
+ - `logger`: Optional logger instance for debugging
228
+
229
+ ### Methods
230
+
231
+ #### `get<T>(token: T): Promise<InstanceType<T>>`
232
+
233
+ Gets a service instance from the container.
234
+
235
+ **Overloads:**
236
+
237
+ - `get<T extends ClassType>(token: T): Promise<InstanceType<T>>`
238
+ - `get<T, S extends InjectionTokenSchemaType>(token: InjectionToken<T, S>, args: z.input<S>): Promise<T>`
239
+ - `get<T>(token: InjectionToken<T, undefined>): Promise<T>`
240
+ - `get<T>(token: BoundInjectionToken<T, any>): Promise<T>`
241
+ - `get<T>(token: FactoryInjectionToken<T, any>): Promise<T>`
242
+
243
+ #### `invalidate(service: unknown): Promise<void>`
244
+
245
+ Invalidates a service and its dependencies.
246
+
247
+ #### `ready(): Promise<void>`
248
+
249
+ Waits for all pending operations to complete.
250
+
251
+ #### `getServiceLocator(): ServiceLocator`
252
+
253
+ Returns the underlying ServiceLocator instance.
254
+
255
+ ## Error Handling
256
+
257
+ The Container can throw various errors:
258
+
259
+ - `InstanceNotFoundError`: When a service is not registered
260
+ - `InstanceExpiredError`: When a service instance has expired
261
+ - `InstanceDestroyingError`: When trying to access a service being destroyed
262
+ - `UnknownError`: For unexpected errors
263
+
264
+ ```typescript
265
+ import { InstanceNotFoundError } from '@navios/di'
266
+
267
+ try {
268
+ const service = await container.get(UnregisteredService)
269
+ } catch (error) {
270
+ if (error instanceof InstanceNotFoundError) {
271
+ console.error('Service not found:', error.message)
272
+ }
273
+ }
274
+ ```
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Basic Usage Example
3
+ *
4
+ * This example demonstrates the fundamental concepts of Navios DI:
5
+ * - Service registration with @Injectable
6
+ * - Dependency injection with asyncInject and inject
7
+ * - Container usage
8
+ */
9
+
10
+ import { asyncInject, Container, inject, Injectable } from '@navios/di'
11
+
12
+ // 1. Create a simple service
13
+ @Injectable()
14
+ class LoggerService {
15
+ log(message: string) {
16
+ console.log(`[LOG] ${new Date().toISOString()} - ${message}`)
17
+ }
18
+ }
19
+
20
+ // 2. Create a service that depends on LoggerService
21
+ @Injectable()
22
+ class UserService {
23
+ private readonly logger = inject(LoggerService)
24
+
25
+ createUser(name: string, email: string) {
26
+ this.logger.log(`Creating user: ${name}`)
27
+ return { id: Math.random().toString(36), name, email }
28
+ }
29
+ }
30
+
31
+ // 3. Create a service that uses async injection
32
+ @Injectable()
33
+ class EmailService {
34
+ private readonly logger = asyncInject(LoggerService)
35
+
36
+ async sendEmail(to: string, subject: string, body: string) {
37
+ const logger = await this.logger
38
+ logger.log(`Sending email to ${to}`)
39
+
40
+ // Simulate email sending
41
+ await new Promise((resolve) => setTimeout(resolve, 100))
42
+
43
+ return { success: true, messageId: Math.random().toString(36) }
44
+ }
45
+ }
46
+
47
+ // 4. Create a service that orchestrates other services
48
+ @Injectable()
49
+ class UserRegistrationService {
50
+ private readonly userService = inject(UserService)
51
+ private readonly emailService = inject(EmailService)
52
+ private readonly logger = inject(LoggerService)
53
+
54
+ async registerUser(name: string, email: string) {
55
+ this.logger.log(`Starting user registration for ${name}`)
56
+
57
+ // Create user
58
+ const user = this.userService.createUser(name, email)
59
+
60
+ // Send welcome email
61
+ await this.emailService.sendEmail(
62
+ email,
63
+ 'Welcome!',
64
+ `Hello ${name}, welcome to our platform!`,
65
+ )
66
+
67
+ this.logger.log(`User registration completed for ${name}`)
68
+
69
+ return user
70
+ }
71
+ }
72
+
73
+ // 5. Usage example
74
+ async function main() {
75
+ console.log('=== Basic Usage Example ===\n')
76
+
77
+ // Create container
78
+ const container = new Container()
79
+
80
+ // Get the registration service (all dependencies will be automatically injected)
81
+ const registrationService = await container.get(UserRegistrationService)
82
+
83
+ // Register a user
84
+ const user = await registrationService.registerUser(
85
+ 'Alice',
86
+ 'alice@example.com',
87
+ )
88
+
89
+ console.log('\nRegistered user:', user)
90
+ }
91
+
92
+ // Run the example
93
+ if (require.main === module) {
94
+ main().catch(console.error)
95
+ }
96
+
97
+ export { LoggerService, UserService, EmailService, UserRegistrationService }
@@ -0,0 +1,318 @@
1
+ import type { Factorable, FactorableWithArgs, FactoryContext } from '@navios/di'
2
+
3
+ import {
4
+ Container,
5
+ Factory,
6
+ inject,
7
+ Injectable,
8
+ InjectableScope,
9
+ InjectionToken,
10
+ } from '@navios/di'
11
+
12
+ import { z } from 'zod'
13
+
14
+ const container = new Container()
15
+
16
+ /**
17
+ * Factory Pattern Example
18
+ *
19
+ * This example demonstrates:
20
+ * - Using @Factory decorator
21
+ * - Factory with dependencies
22
+ * - Factory with configuration
23
+ * - Factory with different scopes
24
+ */
25
+
26
+ // 1. Simple factory without dependencies
27
+ @Factory()
28
+ class RandomIdFactory {
29
+ create() {
30
+ return {
31
+ id: Math.random().toString(36).substr(2, 9),
32
+ createdAt: new Date(),
33
+ }
34
+ }
35
+ }
36
+
37
+ // 2. Factory with dependencies
38
+ @Injectable()
39
+ class LoggerService {
40
+ log(message: string) {
41
+ console.log(`[LOG] ${message}`)
42
+ }
43
+ }
44
+
45
+ @Factory()
46
+ class DatabaseConnectionFactory {
47
+ private readonly logger = inject(LoggerService)
48
+
49
+ create() {
50
+ this.logger.log('Creating database connection...')
51
+
52
+ return {
53
+ host: 'localhost',
54
+ port: 5432,
55
+ connected: false,
56
+ connect: async () => {
57
+ this.logger.log('Connecting to database...')
58
+ await new Promise((resolve) => setTimeout(resolve, 100))
59
+ this.logger.log('Database connected successfully')
60
+ return { connected: true }
61
+ },
62
+ disconnect: async () => {
63
+ this.logger.log('Disconnecting from database...')
64
+ return { connected: false }
65
+ },
66
+ }
67
+ }
68
+ }
69
+
70
+ // 3. Factory with configuration schema
71
+ const emailConfigSchema = z.object({
72
+ provider: z.enum(['smtp', 'sendgrid', 'ses']),
73
+ apiKey: z.string(),
74
+ fromEmail: z.string().email(),
75
+ })
76
+
77
+ type EmailConfig = z.infer<typeof emailConfigSchema>
78
+
79
+ interface EmailService {
80
+ sendEmail(
81
+ to: string,
82
+ subject: string,
83
+ body: string,
84
+ ): Promise<{ success: boolean; provider: string }>
85
+ }
86
+
87
+ const EMAIL_CONFIG_TOKEN = InjectionToken.create<
88
+ EmailService,
89
+ typeof emailConfigSchema
90
+ >('EMAIL_CONFIG', emailConfigSchema)
91
+
92
+ @Factory({ token: EMAIL_CONFIG_TOKEN })
93
+ class EmailServiceFactory
94
+ implements FactorableWithArgs<EmailService, typeof emailConfigSchema>
95
+ {
96
+ create(ctx: FactoryContext, config: z.infer<typeof emailConfigSchema>) {
97
+ switch (config.provider) {
98
+ case 'smtp':
99
+ return new SmtpEmailService(config)
100
+ case 'sendgrid':
101
+ return new SendGridEmailService(config)
102
+ case 'ses':
103
+ return new SesEmailService(config)
104
+ default:
105
+ throw new Error(`Unsupported email provider: ${config.provider}`)
106
+ }
107
+ }
108
+ }
109
+
110
+ // Email service implementations
111
+ class SmtpEmailService implements EmailService {
112
+ constructor(private config: EmailConfig) {}
113
+
114
+ async sendEmail(to: string, subject: string, body: string) {
115
+ console.log(`SMTP email sent to ${to}: ${subject}`)
116
+ return { success: true, provider: 'smtp' }
117
+ }
118
+ }
119
+
120
+ class SendGridEmailService {
121
+ constructor(private config: EmailConfig) {}
122
+
123
+ async sendEmail(to: string, subject: string, body: string) {
124
+ console.log(`SendGrid email sent to ${to}: ${subject}`)
125
+ return { success: true, provider: 'sendgrid' }
126
+ }
127
+ }
128
+
129
+ class SesEmailService {
130
+ constructor(private config: EmailConfig) {}
131
+
132
+ async sendEmail(to: string, subject: string, body: string) {
133
+ console.log(`SES email sent to ${to}: ${subject}`)
134
+ return { success: true, provider: 'ses' }
135
+ }
136
+ }
137
+
138
+ // 4. Factory with transient scope
139
+
140
+ interface UserSession {
141
+ sessionId: string
142
+ userId: string | null
143
+ loginTime: Date
144
+ isActive: boolean
145
+ login(userId: string): void
146
+ logout(): void
147
+ getSessionInfo(): Pick<
148
+ UserSession,
149
+ 'sessionId' | 'userId' | 'loginTime' | 'isActive'
150
+ >
151
+ }
152
+
153
+ @Factory({ scope: InjectableScope.Transient })
154
+ class UserSessionFactory implements Factorable<UserSession> {
155
+ create() {
156
+ return {
157
+ sessionId: Math.random().toString(36),
158
+ userId: null,
159
+ loginTime: new Date(),
160
+ isActive: false,
161
+
162
+ login(userId: string) {
163
+ this.userId = userId
164
+ this.isActive = true
165
+ this.loginTime = new Date()
166
+ },
167
+
168
+ logout() {
169
+ this.userId = null
170
+ this.isActive = false
171
+ },
172
+
173
+ getSessionInfo() {
174
+ return {
175
+ sessionId: this.sessionId,
176
+ userId: this.userId,
177
+ loginTime: this.loginTime,
178
+ isActive: this.isActive,
179
+ }
180
+ },
181
+ } satisfies UserSession
182
+ }
183
+ }
184
+
185
+ // 5. Factory with complex object creation
186
+ @Injectable()
187
+ class ConfigService {
188
+ getDatabaseConfig() {
189
+ return {
190
+ host: 'localhost',
191
+ port: 5432,
192
+ database: 'myapp',
193
+ }
194
+ }
195
+
196
+ getCacheConfig() {
197
+ return {
198
+ host: 'localhost',
199
+ port: 6379,
200
+ ttl: 3600,
201
+ }
202
+ }
203
+ }
204
+
205
+ @Factory()
206
+ class ApplicationContextFactory {
207
+ private readonly config = inject(ConfigService)
208
+
209
+ create() {
210
+ const dbConfig = this.config.getDatabaseConfig()
211
+ const cacheConfig = this.config.getCacheConfig()
212
+
213
+ return {
214
+ database: {
215
+ ...dbConfig,
216
+ connectionString: `postgresql://${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`,
217
+ },
218
+ cache: {
219
+ ...cacheConfig,
220
+ connectionString: `redis://${cacheConfig.host}:${cacheConfig.port}`,
221
+ },
222
+ environment: process.env.NODE_ENV || 'development',
223
+ version: '1.0.0',
224
+ initializedAt: new Date(),
225
+ }
226
+ }
227
+ }
228
+
229
+ // 6. Usage examples
230
+ async function demonstrateSimpleFactory() {
231
+ console.log('=== Simple Factory Example ===\n')
232
+
233
+ const idFactory = await container.get(RandomIdFactory)
234
+ console.log('Generated ID:', idFactory)
235
+ }
236
+
237
+ async function demonstrateFactoryWithDependencies() {
238
+ console.log('\n=== Factory with Dependencies Example ===\n')
239
+
240
+ const dbFactory = await container.get(DatabaseConnectionFactory)
241
+ console.log('Database connection:', dbFactory)
242
+
243
+ const connection = await dbFactory.connect()
244
+ console.log('Connection result:', connection)
245
+ }
246
+
247
+ async function demonstrateFactoryWithConfiguration() {
248
+ console.log('\n=== Factory with Configuration Example ===\n')
249
+
250
+ // Create different email services based on configuration
251
+ const smtpEmail = await container.get(EMAIL_CONFIG_TOKEN, {
252
+ provider: 'smtp',
253
+ apiKey: 'smtp_key',
254
+ fromEmail: 'noreply@example.com',
255
+ })
256
+
257
+ const sendgridEmail = await container.get(EMAIL_CONFIG_TOKEN, {
258
+ provider: 'sendgrid',
259
+ apiKey: 'sg_key',
260
+ fromEmail: 'noreply@example.com',
261
+ })
262
+
263
+ await smtpEmail.sendEmail('user@example.com', 'Test', 'Hello from SMTP')
264
+ await sendgridEmail.sendEmail(
265
+ 'user@example.com',
266
+ 'Test',
267
+ 'Hello from SendGrid',
268
+ )
269
+ }
270
+
271
+ async function demonstrateTransientFactory() {
272
+ console.log('\n=== Transient Factory Example ===\n')
273
+
274
+ // Create multiple sessions
275
+ const session1 = await container.get(UserSessionFactory)
276
+ const session2 = await container.get(UserSessionFactory)
277
+
278
+ session1.login('user1')
279
+ session2.login('user2')
280
+
281
+ console.log('Session 1:', session1.getSessionInfo())
282
+ console.log('Session 2:', session2.getSessionInfo())
283
+
284
+ // Verify they are different instances
285
+ console.log('Different sessions:', session1.sessionId !== session2.sessionId)
286
+ }
287
+
288
+ async function demonstrateComplexFactory() {
289
+ console.log('\n=== Complex Factory Example ===\n')
290
+
291
+ const appContext = await container.get(ApplicationContextFactory)
292
+ console.log('Application context:', JSON.stringify(appContext, null, 2))
293
+ }
294
+
295
+ // Main function
296
+ async function main() {
297
+ await demonstrateSimpleFactory()
298
+ await demonstrateFactoryWithDependencies()
299
+ await demonstrateFactoryWithConfiguration()
300
+ await demonstrateTransientFactory()
301
+ await demonstrateComplexFactory()
302
+ }
303
+
304
+ // Run the example
305
+ if (require.main === module) {
306
+ main().catch(console.error)
307
+ }
308
+
309
+ export {
310
+ RandomIdFactory,
311
+ DatabaseConnectionFactory,
312
+ EmailServiceFactory,
313
+ UserSessionFactory,
314
+ ApplicationContextFactory,
315
+ SmtpEmailService,
316
+ SendGridEmailService,
317
+ SesEmailService,
318
+ }