@navios/di 0.5.0 → 0.6.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/CHANGELOG.md +146 -0
- package/README.md +196 -219
- package/docs/README.md +69 -11
- package/docs/api-reference.md +281 -117
- package/docs/container.md +220 -56
- package/docs/examples/request-scope-example.mts +2 -2
- package/docs/factory.md +3 -8
- package/docs/getting-started.md +37 -8
- package/docs/migration.md +318 -37
- package/docs/request-contexts.md +263 -175
- package/docs/scopes.md +79 -42
- package/lib/browser/index.d.mts +1577 -0
- package/lib/browser/index.d.mts.map +1 -0
- package/lib/browser/index.mjs +3012 -0
- package/lib/browser/index.mjs.map +1 -0
- package/lib/index-S_qX2VLI.d.mts +1211 -0
- package/lib/index-S_qX2VLI.d.mts.map +1 -0
- package/lib/index-fKPuT65j.d.cts +1206 -0
- package/lib/index-fKPuT65j.d.cts.map +1 -0
- package/lib/index.cjs +389 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +376 -0
- package/lib/index.d.cts.map +1 -0
- package/lib/index.d.mts +371 -78
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +325 -63
- package/lib/index.mjs.map +1 -1
- package/lib/testing/index.cjs +9 -0
- package/lib/testing/index.d.cts +2 -0
- package/lib/testing/index.d.mts +2 -2
- package/lib/testing/index.mjs +2 -72
- package/lib/testing-BMGmmxH7.cjs +2895 -0
- package/lib/testing-BMGmmxH7.cjs.map +1 -0
- package/lib/testing-DCXz8AJD.mjs +2655 -0
- package/lib/testing-DCXz8AJD.mjs.map +1 -0
- package/package.json +26 -4
- package/project.json +2 -2
- package/src/__tests__/async-local-storage.browser.spec.mts +240 -0
- package/src/__tests__/async-local-storage.spec.mts +333 -0
- package/src/__tests__/container.spec.mts +30 -25
- package/src/__tests__/e2e.browser.spec.mts +790 -0
- package/src/__tests__/e2e.spec.mts +1222 -0
- package/src/__tests__/errors.spec.mts +6 -6
- package/src/__tests__/factory.spec.mts +1 -1
- package/src/__tests__/get-injectors.spec.mts +1 -1
- package/src/__tests__/injectable.spec.mts +1 -1
- package/src/__tests__/injection-token.spec.mts +1 -1
- package/src/__tests__/library-findings.spec.mts +563 -0
- package/src/__tests__/registry.spec.mts +2 -2
- package/src/__tests__/request-scope.spec.mts +266 -274
- package/src/__tests__/service-instantiator.spec.mts +19 -17
- package/src/__tests__/service-locator-event-bus.spec.mts +9 -9
- package/src/__tests__/service-locator-manager.spec.mts +15 -15
- package/src/__tests__/service-locator.spec.mts +167 -244
- package/src/__tests__/unified-api.spec.mts +27 -27
- package/src/__type-tests__/factory.spec-d.mts +2 -2
- package/src/__type-tests__/inject.spec-d.mts +2 -2
- package/src/__type-tests__/injectable.spec-d.mts +1 -1
- package/src/browser.mts +16 -0
- package/src/container/container.mts +319 -0
- package/src/container/index.mts +2 -0
- package/src/container/scoped-container.mts +350 -0
- package/src/decorators/factory.decorator.mts +4 -4
- package/src/decorators/injectable.decorator.mts +5 -5
- package/src/errors/di-error.mts +13 -7
- package/src/errors/index.mts +0 -8
- package/src/index.mts +156 -15
- package/src/interfaces/container.interface.mts +82 -0
- package/src/interfaces/factory.interface.mts +2 -2
- package/src/interfaces/index.mts +1 -0
- package/src/internal/context/async-local-storage.mts +120 -0
- package/src/internal/context/factory-context.mts +18 -0
- package/src/internal/context/index.mts +3 -0
- package/src/{request-context-holder.mts → internal/context/request-context.mts} +40 -27
- package/src/internal/context/resolution-context.mts +63 -0
- package/src/internal/context/sync-local-storage.mts +51 -0
- package/src/internal/core/index.mts +5 -0
- package/src/internal/core/instance-resolver.mts +641 -0
- package/src/{service-instantiator.mts → internal/core/instantiator.mts} +31 -27
- package/src/internal/core/invalidator.mts +437 -0
- package/src/internal/core/service-locator.mts +202 -0
- package/src/{token-processor.mts → internal/core/token-processor.mts} +79 -60
- package/src/{base-instance-holder-manager.mts → internal/holder/base-holder-manager.mts} +91 -21
- package/src/internal/holder/holder-manager.mts +85 -0
- package/src/internal/holder/holder-storage.interface.mts +116 -0
- package/src/internal/holder/index.mts +6 -0
- package/src/internal/holder/instance-holder.mts +109 -0
- package/src/internal/holder/request-storage.mts +134 -0
- package/src/internal/holder/singleton-storage.mts +105 -0
- package/src/internal/index.mts +4 -0
- package/src/internal/lifecycle/circular-detector.mts +77 -0
- package/src/internal/lifecycle/index.mts +2 -0
- package/src/{service-locator-event-bus.mts → internal/lifecycle/lifecycle-event-bus.mts} +12 -5
- package/src/testing/__tests__/test-container.spec.mts +2 -2
- package/src/testing/test-container.mts +4 -4
- package/src/token/index.mts +2 -0
- package/src/{injection-token.mts → token/injection-token.mts} +1 -1
- package/src/{registry.mts → token/registry.mts} +1 -1
- package/src/utils/get-injectable-token.mts +1 -1
- package/src/utils/get-injectors.mts +32 -15
- package/src/utils/types.mts +1 -1
- package/tsdown.config.mts +67 -0
- package/lib/_tsup-dts-rollup.d.mts +0 -1283
- package/lib/_tsup-dts-rollup.d.ts +0 -1283
- package/lib/chunk-44F3LXW5.mjs +0 -2043
- package/lib/chunk-44F3LXW5.mjs.map +0 -1
- package/lib/index.d.ts +0 -78
- package/lib/index.js +0 -2127
- package/lib/index.js.map +0 -1
- package/lib/testing/index.d.ts +0 -2
- package/lib/testing/index.js +0 -2060
- package/lib/testing/index.js.map +0 -1
- package/lib/testing/index.mjs.map +0 -1
- package/src/container.mts +0 -227
- package/src/factory-context.mts +0 -8
- package/src/instance-resolver.mts +0 -559
- package/src/request-context-manager.mts +0 -149
- package/src/service-invalidator.mts +0 -429
- package/src/service-locator-instance-holder.mts +0 -70
- package/src/service-locator-manager.mts +0 -85
- package/src/service-locator.mts +0 -246
- package/tsup.config.mts +0 -12
- /package/src/{injector.mts → injectors.mts} +0 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import type { z, ZodType } from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
import type { Container } from './container.mjs'
|
|
4
|
+
import type {
|
|
5
|
+
BoundInjectionToken,
|
|
6
|
+
ClassType,
|
|
7
|
+
ClassTypeWithArgument,
|
|
8
|
+
FactoryInjectionToken,
|
|
9
|
+
InjectionToken,
|
|
10
|
+
InjectionTokenSchemaType,
|
|
11
|
+
} from '../token/injection-token.mjs'
|
|
12
|
+
import type { IContainer } from '../interfaces/container.interface.mjs'
|
|
13
|
+
import type { IHolderStorage } from '../internal/holder/holder-storage.interface.mjs'
|
|
14
|
+
import type { Factorable } from '../interfaces/factory.interface.mjs'
|
|
15
|
+
import type { Registry } from '../token/registry.mjs'
|
|
16
|
+
import type { RequestContext } from '../internal/context/request-context.mjs'
|
|
17
|
+
import type { InstanceHolder } from '../internal/holder/instance-holder.mjs'
|
|
18
|
+
import type { Join, UnionToArray } from '../utils/types.mjs'
|
|
19
|
+
|
|
20
|
+
import { BaseHolderManager } from '../internal/holder/base-holder-manager.mjs'
|
|
21
|
+
import { InjectableScope } from '../enums/index.mjs'
|
|
22
|
+
import { DIError } from '../errors/index.mjs'
|
|
23
|
+
import { DefaultRequestContext } from '../internal/context/request-context.mjs'
|
|
24
|
+
import { RequestStorage } from '../internal/holder/request-storage.mjs'
|
|
25
|
+
import { InstanceStatus } from '../internal/holder/instance-holder.mjs'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Request-scoped dependency injection container.
|
|
29
|
+
*
|
|
30
|
+
* Wraps a parent Container and provides isolated request-scoped instances
|
|
31
|
+
* while delegating singleton and transient resolution to the parent.
|
|
32
|
+
* This design eliminates race conditions that can occur with async operations
|
|
33
|
+
* when multiple requests are processed concurrently.
|
|
34
|
+
*/
|
|
35
|
+
export class ScopedContainer implements IContainer {
|
|
36
|
+
private readonly requestContextHolder: RequestContext
|
|
37
|
+
private readonly holderStorage: IHolderStorage
|
|
38
|
+
private disposed = false
|
|
39
|
+
|
|
40
|
+
constructor(
|
|
41
|
+
private readonly parent: Container,
|
|
42
|
+
private readonly registry: Registry,
|
|
43
|
+
public readonly requestId: string,
|
|
44
|
+
metadata?: Record<string, any>,
|
|
45
|
+
priority: number = 100,
|
|
46
|
+
) {
|
|
47
|
+
this.requestContextHolder = new DefaultRequestContext(
|
|
48
|
+
requestId,
|
|
49
|
+
priority,
|
|
50
|
+
metadata,
|
|
51
|
+
)
|
|
52
|
+
// Create storage once and reuse for all resolutions
|
|
53
|
+
this.holderStorage = new RequestStorage(
|
|
54
|
+
this.requestContextHolder,
|
|
55
|
+
this.parent.getServiceLocator().getManager(),
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gets the request context holder for this scoped container.
|
|
61
|
+
*/
|
|
62
|
+
getRequestContextHolder(): RequestContext {
|
|
63
|
+
return this.requestContextHolder
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets the holder storage for this scoped container.
|
|
68
|
+
* Used by InstanceResolver for request-scoped resolution.
|
|
69
|
+
*/
|
|
70
|
+
getHolderStorage(): IHolderStorage {
|
|
71
|
+
return this.holderStorage
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets the request ID for this scoped container.
|
|
76
|
+
*/
|
|
77
|
+
getRequestId(): string {
|
|
78
|
+
return this.requestId
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Gets the parent container.
|
|
83
|
+
*/
|
|
84
|
+
getParent(): Container {
|
|
85
|
+
return this.parent
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Gets metadata from the request context.
|
|
90
|
+
*/
|
|
91
|
+
getMetadata(key: string): any | undefined {
|
|
92
|
+
return this.requestContextHolder.getMetadata(key)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Sets metadata on the request context.
|
|
97
|
+
*/
|
|
98
|
+
setMetadata(key: string, value: any): void {
|
|
99
|
+
this.requestContextHolder.setMetadata(key, value)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Adds a pre-prepared instance to the request context.
|
|
104
|
+
*/
|
|
105
|
+
addInstance(token: InjectionToken<any, undefined>, instance: any): void {
|
|
106
|
+
this.requestContextHolder.addInstance(token, instance)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Gets an instance from the container.
|
|
111
|
+
* Request-scoped services are resolved from this container's context.
|
|
112
|
+
* All other services are delegated to the parent container.
|
|
113
|
+
*/
|
|
114
|
+
// #1 Simple class
|
|
115
|
+
get<T extends ClassType>(
|
|
116
|
+
token: T,
|
|
117
|
+
): InstanceType<T> extends Factorable<infer R>
|
|
118
|
+
? Promise<R>
|
|
119
|
+
: Promise<InstanceType<T>>
|
|
120
|
+
// #1.1 Simple class with args
|
|
121
|
+
get<T extends ClassTypeWithArgument<R>, R>(
|
|
122
|
+
token: T,
|
|
123
|
+
args: R,
|
|
124
|
+
): Promise<InstanceType<T>>
|
|
125
|
+
// #2 Token with required Schema
|
|
126
|
+
get<T, S extends InjectionTokenSchemaType>(
|
|
127
|
+
token: InjectionToken<T, S>,
|
|
128
|
+
args: z.input<S>,
|
|
129
|
+
): Promise<T>
|
|
130
|
+
// #3 Token with optional Schema
|
|
131
|
+
get<T, S extends InjectionTokenSchemaType, R extends boolean>(
|
|
132
|
+
token: InjectionToken<T, S, R>,
|
|
133
|
+
): R extends false
|
|
134
|
+
? Promise<T>
|
|
135
|
+
: S extends ZodType<infer Type>
|
|
136
|
+
? `Error: Your token requires args: ${Join<
|
|
137
|
+
UnionToArray<keyof Type>,
|
|
138
|
+
', '
|
|
139
|
+
>}`
|
|
140
|
+
: 'Error: Your token requires args'
|
|
141
|
+
// #4 Token with no Schema
|
|
142
|
+
get<T>(token: InjectionToken<T, undefined>): Promise<T>
|
|
143
|
+
get<T>(token: BoundInjectionToken<T, any>): Promise<T>
|
|
144
|
+
get<T>(token: FactoryInjectionToken<T, any>): Promise<T>
|
|
145
|
+
|
|
146
|
+
async get(
|
|
147
|
+
token:
|
|
148
|
+
| ClassType
|
|
149
|
+
| InjectionToken<any>
|
|
150
|
+
| BoundInjectionToken<any, any>
|
|
151
|
+
| FactoryInjectionToken<any, any>,
|
|
152
|
+
args?: unknown,
|
|
153
|
+
): Promise<any> {
|
|
154
|
+
if (this.disposed) {
|
|
155
|
+
throw DIError.unknown(
|
|
156
|
+
`ScopedContainer for request ${this.requestId} has been disposed`,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Get the actual injection token using TokenProcessor for consistency
|
|
161
|
+
const tokenProcessor = this.parent.getServiceLocator().getTokenProcessor()
|
|
162
|
+
const actualToken = tokenProcessor.normalizeToken(token)
|
|
163
|
+
|
|
164
|
+
// Check if this is a request-scoped service
|
|
165
|
+
if (this.isRequestScoped(actualToken)) {
|
|
166
|
+
return this.resolveRequestScoped(actualToken, args)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Delegate to parent for singleton/transient services
|
|
170
|
+
// Pass this ScopedContainer so nested inject() calls work correctly
|
|
171
|
+
return this.parent.getWithContext(token, args, this)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Invalidates a service and its dependencies.
|
|
176
|
+
* For request-scoped services, invalidation is handled within this context.
|
|
177
|
+
*/
|
|
178
|
+
async invalidate(service: unknown): Promise<void> {
|
|
179
|
+
// Check if the service is in our request context
|
|
180
|
+
const holder = this.holderStorage.findByInstance(service)
|
|
181
|
+
if (holder) {
|
|
182
|
+
// Use the shared Invalidator with our request-scoped storage
|
|
183
|
+
await this.parent
|
|
184
|
+
.getServiceLocator()
|
|
185
|
+
.getInvalidator()
|
|
186
|
+
.invalidateWithStorage(holder.name, this.holderStorage, 1, {
|
|
187
|
+
emitEvents: false, // Request-scoped services don't emit global events
|
|
188
|
+
})
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Delegate to parent for singleton services
|
|
193
|
+
await this.parent.invalidate(service)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Checks if a service is registered.
|
|
198
|
+
*/
|
|
199
|
+
isRegistered(token: any): boolean {
|
|
200
|
+
return this.parent.isRegistered(token)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Disposes this scoped container and cleans up all request-scoped instances.
|
|
205
|
+
* This is an alias for endRequest() for IContainer compatibility.
|
|
206
|
+
*/
|
|
207
|
+
async dispose(): Promise<void> {
|
|
208
|
+
await this.endRequest()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Ends the request and cleans up all request-scoped instances.
|
|
213
|
+
* Uses the invalidation system to properly cascade to dependent singletons.
|
|
214
|
+
*/
|
|
215
|
+
async endRequest(): Promise<void> {
|
|
216
|
+
if (this.disposed) {
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.disposed = true
|
|
221
|
+
|
|
222
|
+
// Use clearAllWithStorage to properly invalidate all request-scoped services
|
|
223
|
+
// This will cascade invalidation to singletons that depend on request-scoped services
|
|
224
|
+
await this.parent
|
|
225
|
+
.getServiceLocator()
|
|
226
|
+
.getInvalidator()
|
|
227
|
+
.clearAllWithStorage(this.holderStorage, {
|
|
228
|
+
waitForSettlement: true,
|
|
229
|
+
maxRounds: 10,
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// Clear the context (any remaining holders that weren't invalidated)
|
|
233
|
+
this.requestContextHolder.clear()
|
|
234
|
+
|
|
235
|
+
// Remove from parent's active requests
|
|
236
|
+
this.parent.removeActiveRequest(this.requestId)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Waits for all pending operations to complete.
|
|
241
|
+
*/
|
|
242
|
+
async ready(): Promise<void> {
|
|
243
|
+
await this.parent.ready()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @internal
|
|
248
|
+
* Attempts to get an instance synchronously if it already exists and is ready.
|
|
249
|
+
* For request-scoped services, checks this container's context first.
|
|
250
|
+
* For other services, delegates to the parent container.
|
|
251
|
+
*
|
|
252
|
+
* Returns null if the instance doesn't exist or is not yet ready (still creating).
|
|
253
|
+
*/
|
|
254
|
+
tryGetSync<T>(token: any, args?: any): T | null {
|
|
255
|
+
const tokenProcessor = this.parent.getServiceLocator().getTokenProcessor()
|
|
256
|
+
const actualToken = tokenProcessor.normalizeToken(token)
|
|
257
|
+
|
|
258
|
+
// Check if this is a request-scoped service
|
|
259
|
+
if (this.isRequestScoped(actualToken)) {
|
|
260
|
+
const serviceLocator = this.parent.getServiceLocator()
|
|
261
|
+
const instanceName = serviceLocator.getInstanceIdentifier(token, args)
|
|
262
|
+
const holder = this.requestContextHolder.get(instanceName)
|
|
263
|
+
// Only return if holder exists AND is in Created status
|
|
264
|
+
if (
|
|
265
|
+
holder &&
|
|
266
|
+
holder.status === InstanceStatus.Created
|
|
267
|
+
) {
|
|
268
|
+
return holder.instance as T
|
|
269
|
+
}
|
|
270
|
+
return null
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Delegate to parent for non-request-scoped
|
|
274
|
+
return this.parent.tryGetSync(token, args)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Checks if a token is for a request-scoped service.
|
|
279
|
+
*/
|
|
280
|
+
private isRequestScoped(token: any): boolean {
|
|
281
|
+
// Handle BoundInjectionToken and FactoryInjectionToken using TokenProcessor
|
|
282
|
+
const tokenProcessor = this.parent.getServiceLocator().getTokenProcessor()
|
|
283
|
+
const realToken = tokenProcessor.getRealToken(token)
|
|
284
|
+
|
|
285
|
+
if (!this.registry.has(realToken)) {
|
|
286
|
+
return false
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const record = this.registry.get(realToken)
|
|
290
|
+
return record.scope === InjectableScope.Request
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Resolves a request-scoped service from this container's context.
|
|
295
|
+
* Uses locking to prevent duplicate initialization during concurrent resolution.
|
|
296
|
+
*/
|
|
297
|
+
private async resolveRequestScoped(token: any, args: unknown): Promise<any> {
|
|
298
|
+
// Get the instance name
|
|
299
|
+
const serviceLocator = this.parent.getServiceLocator()
|
|
300
|
+
const instanceName = serviceLocator.getInstanceIdentifier(token, args)
|
|
301
|
+
|
|
302
|
+
// Check if we already have this instance (or one is being created)
|
|
303
|
+
const existingHolder = this.requestContextHolder.get(instanceName)
|
|
304
|
+
if (existingHolder) {
|
|
305
|
+
// Wait for the holder to be ready if it's still being created
|
|
306
|
+
// This prevents race conditions where multiple concurrent calls
|
|
307
|
+
// might try to create the same service
|
|
308
|
+
const [error, readyHolder] =
|
|
309
|
+
await BaseHolderManager.waitForHolderReady(existingHolder)
|
|
310
|
+
if (error) {
|
|
311
|
+
throw error
|
|
312
|
+
}
|
|
313
|
+
return readyHolder.instance
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Create new instance using parent's resolution mechanism
|
|
317
|
+
// but store it in our request context
|
|
318
|
+
return this.parent.resolveForRequest(token, args, this)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Stores an instance in the request context.
|
|
323
|
+
* Called by Container during request-scoped service resolution.
|
|
324
|
+
*/
|
|
325
|
+
storeRequestInstance(
|
|
326
|
+
instanceName: string,
|
|
327
|
+
instance: any,
|
|
328
|
+
holder: InstanceHolder,
|
|
329
|
+
): void {
|
|
330
|
+
this.requestContextHolder.addInstance(instanceName, instance, holder)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Gets an existing instance from the request context.
|
|
335
|
+
* Called by Container during resolution to check for existing instances.
|
|
336
|
+
*/
|
|
337
|
+
getRequestInstance(
|
|
338
|
+
instanceName: string,
|
|
339
|
+
): InstanceHolder | undefined {
|
|
340
|
+
return this.requestContextHolder.get(instanceName)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Generates a prefixed event name for request-scoped services.
|
|
345
|
+
* Format: {requestId}:{instanceName}
|
|
346
|
+
*/
|
|
347
|
+
getPrefixedEventName(instanceName: string): string {
|
|
348
|
+
return `${this.requestId}:${instanceName}`
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ClassTypeWithInstance,
|
|
3
3
|
InjectionTokenSchemaType,
|
|
4
|
-
} from '../injection-token.mjs'
|
|
4
|
+
} from '../token/injection-token.mjs'
|
|
5
5
|
import type { Factorable, FactorableWithArgs } from '../interfaces/index.mjs'
|
|
6
|
-
import type { Registry } from '../registry.mjs'
|
|
6
|
+
import type { Registry } from '../token/registry.mjs'
|
|
7
7
|
|
|
8
8
|
import { InjectableScope, InjectableType } from '../enums/index.mjs'
|
|
9
|
-
import { InjectionToken } from '../injection-token.mjs'
|
|
10
|
-
import { globalRegistry } from '../registry.mjs'
|
|
9
|
+
import { InjectionToken } from '../token/injection-token.mjs'
|
|
10
|
+
import { globalRegistry } from '../token/registry.mjs'
|
|
11
11
|
import { InjectableTokenMeta } from '../symbols/index.mjs'
|
|
12
12
|
|
|
13
13
|
export interface FactoryOptions {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { z
|
|
1
|
+
import { z } from 'zod/v4'
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
BaseInjectionTokenSchemaType,
|
|
@@ -11,12 +11,12 @@ import type {
|
|
|
11
11
|
ClassTypeWithoutArguments,
|
|
12
12
|
InjectionTokenSchemaType,
|
|
13
13
|
OptionalInjectionTokenSchemaType,
|
|
14
|
-
} from '../injection-token.mjs'
|
|
15
|
-
import type { Registry } from '../registry.mjs'
|
|
14
|
+
} from '../token/injection-token.mjs'
|
|
15
|
+
import type { Registry } from '../token/registry.mjs'
|
|
16
16
|
|
|
17
17
|
import { InjectableScope, InjectableType } from '../enums/index.mjs'
|
|
18
|
-
import { InjectionToken } from '../injection-token.mjs'
|
|
19
|
-
import { globalRegistry } from '../registry.mjs'
|
|
18
|
+
import { InjectionToken } from '../token/injection-token.mjs'
|
|
19
|
+
import { globalRegistry } from '../token/registry.mjs'
|
|
20
20
|
import { InjectableTokenMeta } from '../symbols/index.mjs'
|
|
21
21
|
|
|
22
22
|
export interface InjectableOptions {
|
package/src/errors/di-error.mts
CHANGED
|
@@ -3,21 +3,18 @@ export enum DIErrorCode {
|
|
|
3
3
|
FactoryTokenNotResolved = 'FactoryTokenNotResolved',
|
|
4
4
|
InstanceNotFound = 'InstanceNotFound',
|
|
5
5
|
InstanceDestroying = 'InstanceDestroying',
|
|
6
|
+
CircularDependency = 'CircularDependency',
|
|
6
7
|
UnknownError = 'UnknownError',
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export class DIError
|
|
10
|
-
public readonly code: DIErrorCode
|
|
10
|
+
export class DIError {
|
|
11
11
|
public readonly context?: Record<string, unknown>
|
|
12
12
|
|
|
13
13
|
constructor(
|
|
14
|
-
code: DIErrorCode,
|
|
15
|
-
message: string,
|
|
14
|
+
public readonly code: DIErrorCode,
|
|
15
|
+
public readonly message: string,
|
|
16
16
|
context?: Record<string, unknown>,
|
|
17
17
|
) {
|
|
18
|
-
super(message)
|
|
19
|
-
this.name = 'DIError'
|
|
20
|
-
this.code = code
|
|
21
18
|
this.context = context
|
|
22
19
|
}
|
|
23
20
|
|
|
@@ -66,4 +63,13 @@ export class DIError extends Error {
|
|
|
66
63
|
}
|
|
67
64
|
return new DIError(DIErrorCode.UnknownError, message, context)
|
|
68
65
|
}
|
|
66
|
+
|
|
67
|
+
static circularDependency(cycle: string[]): DIError {
|
|
68
|
+
const cycleStr = cycle.join(' -> ')
|
|
69
|
+
return new DIError(
|
|
70
|
+
DIErrorCode.CircularDependency,
|
|
71
|
+
`Circular dependency detected: ${cycleStr}`,
|
|
72
|
+
{ cycle },
|
|
73
|
+
)
|
|
74
|
+
}
|
|
69
75
|
}
|
package/src/errors/index.mts
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
1
|
export * from './di-error.mjs'
|
|
2
|
-
|
|
3
|
-
// Legacy exports for backward compatibility (deprecated)
|
|
4
|
-
export { DIError as FactoryNotFound } from './di-error.mjs'
|
|
5
|
-
export { DIError as FactoryTokenNotResolved } from './di-error.mjs'
|
|
6
|
-
export { DIError as InstanceDestroying } from './di-error.mjs'
|
|
7
|
-
export { DIError as InstanceNotFound } from './di-error.mjs'
|
|
8
|
-
export { DIError as UnknownError } from './di-error.mjs'
|
|
9
|
-
export { DIErrorCode as ErrorsEnum } from './di-error.mjs'
|
package/src/index.mts
CHANGED
|
@@ -1,19 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @navios/di - Dependency Injection Library
|
|
3
|
+
*
|
|
4
|
+
* This library provides a flexible dependency injection system with support for:
|
|
5
|
+
* - Singleton and request-scoped services
|
|
6
|
+
* - Factory-based and class-based service instantiation
|
|
7
|
+
* - Circular dependency detection
|
|
8
|
+
* - Schema validation for service arguments
|
|
9
|
+
* - Lifecycle hooks (onServiceInit, onServiceDestroy)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// PUBLIC API - Container
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export { Container } from './container/container.mjs'
|
|
17
|
+
export { ScopedContainer } from './container/scoped-container.mjs'
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// PUBLIC API - Tokens
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
InjectionToken,
|
|
25
|
+
BoundInjectionToken,
|
|
26
|
+
FactoryInjectionToken,
|
|
27
|
+
type ClassType,
|
|
28
|
+
type ClassTypeWithoutArguments,
|
|
29
|
+
type ClassTypeWithArgument,
|
|
30
|
+
type ClassTypeWithOptionalArgument,
|
|
31
|
+
type ClassTypeWithInstance,
|
|
32
|
+
type ClassTypeWithInstanceAndArgument,
|
|
33
|
+
type ClassTypeWithInstanceAndOptionalArgument,
|
|
34
|
+
type AnyInjectableType,
|
|
35
|
+
type InjectionTokenType,
|
|
36
|
+
type InjectionTokenSchemaType,
|
|
37
|
+
} from './token/injection-token.mjs'
|
|
38
|
+
|
|
39
|
+
export { Registry, globalRegistry, type FactoryRecord } from './token/registry.mjs'
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// PUBLIC API - Decorators
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
1
45
|
export * from './decorators/index.mjs'
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// PUBLIC API - Enums
|
|
49
|
+
// ============================================================================
|
|
50
|
+
|
|
2
51
|
export * from './enums/index.mjs'
|
|
3
|
-
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// PUBLIC API - Interfaces
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
4
57
|
export * from './interfaces/index.mjs'
|
|
58
|
+
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// PUBLIC API - Errors
|
|
61
|
+
// ============================================================================
|
|
62
|
+
|
|
63
|
+
export * from './errors/index.mjs'
|
|
64
|
+
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// PUBLIC API - Utilities
|
|
67
|
+
// ============================================================================
|
|
68
|
+
|
|
5
69
|
export * from './utils/index.mjs'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export * from './
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
70
|
+
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// PUBLIC API - Symbols
|
|
73
|
+
// ============================================================================
|
|
74
|
+
|
|
75
|
+
export * from './symbols/index.mjs'
|
|
76
|
+
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// PUBLIC API - Event Emitter
|
|
79
|
+
// ============================================================================
|
|
80
|
+
|
|
81
|
+
export { EventEmitter } from './event-emitter.mjs'
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// PUBLIC API - Injectors
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
defaultInjectors,
|
|
89
|
+
asyncInject,
|
|
90
|
+
inject,
|
|
91
|
+
optional,
|
|
92
|
+
wrapSyncInit,
|
|
93
|
+
provideFactoryContext,
|
|
94
|
+
} from './injectors.mjs'
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// PUBLIC API - Testing
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
export * from './testing/index.mjs'
|
|
101
|
+
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// INTERNAL API (exported for advanced use cases)
|
|
104
|
+
// ============================================================================
|
|
105
|
+
|
|
106
|
+
// Context types
|
|
107
|
+
export type { FactoryContext } from './internal/context/factory-context.mjs'
|
|
108
|
+
export {
|
|
109
|
+
type RequestContext,
|
|
110
|
+
type RequestContextHolder,
|
|
111
|
+
DefaultRequestContext,
|
|
112
|
+
createRequestContext,
|
|
113
|
+
} from './internal/context/request-context.mjs'
|
|
114
|
+
export {
|
|
115
|
+
type ResolutionContextData,
|
|
116
|
+
resolutionContext,
|
|
117
|
+
withResolutionContext,
|
|
118
|
+
getCurrentResolutionContext,
|
|
119
|
+
withoutResolutionContext,
|
|
120
|
+
} from './internal/context/resolution-context.mjs'
|
|
121
|
+
|
|
122
|
+
// Holder types
|
|
123
|
+
export {
|
|
124
|
+
InstanceStatus,
|
|
125
|
+
type InstanceHolder,
|
|
126
|
+
type InstanceEffect,
|
|
127
|
+
type InstanceDestroyListener,
|
|
128
|
+
type InstanceHolderCreating,
|
|
129
|
+
type InstanceHolderCreated,
|
|
130
|
+
type InstanceHolderDestroying,
|
|
131
|
+
type InstanceHolderError,
|
|
132
|
+
} from './internal/holder/instance-holder.mjs'
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
BaseHolderManager,
|
|
136
|
+
type HolderReadyResult,
|
|
137
|
+
} from './internal/holder/base-holder-manager.mjs'
|
|
138
|
+
|
|
139
|
+
export { HolderManager } from './internal/holder/holder-manager.mjs'
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
type HolderGetResult,
|
|
143
|
+
type IHolderStorage,
|
|
144
|
+
} from './internal/holder/holder-storage.interface.mjs'
|
|
145
|
+
|
|
146
|
+
export { SingletonStorage } from './internal/holder/singleton-storage.mjs'
|
|
147
|
+
|
|
148
|
+
export { RequestStorage } from './internal/holder/request-storage.mjs'
|
|
149
|
+
|
|
150
|
+
// Lifecycle
|
|
151
|
+
export { LifecycleEventBus } from './internal/lifecycle/lifecycle-event-bus.mjs'
|
|
152
|
+
|
|
153
|
+
export { CircularDetector } from './internal/lifecycle/circular-detector.mjs'
|
|
154
|
+
|
|
155
|
+
// Core engine
|
|
156
|
+
export { ServiceLocator } from './internal/core/service-locator.mjs'
|
|
157
|
+
export { InstanceResolver } from './internal/core/instance-resolver.mjs'
|
|
158
|
+
export { Instantiator } from './internal/core/instantiator.mjs'
|
|
159
|
+
export { Invalidator } from './internal/core/invalidator.mjs'
|
|
160
|
+
export { TokenProcessor } from './internal/core/token-processor.mjs'
|