@navios/core 0.1.15 → 0.2.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.
- package/dist/_tsup-dts-rollup.d.mts +96 -425
- package/dist/_tsup-dts-rollup.d.ts +96 -425
- package/dist/index.d.mts +54 -44
- package/dist/index.d.ts +54 -44
- package/dist/index.js +111 -1023
- package/dist/index.mjs +113 -982
- package/package.json +5 -4
- package/src/adapters/endpoint-adapter.service.mts +3 -6
- package/src/adapters/handler-adapter.interface.mts +1 -1
- package/src/adapters/multipart-adapter.service.mts +2 -1
- package/src/adapters/stream-adapter.service.mts +3 -7
- package/src/attribute.factory.mts +1 -1
- package/src/config/config.provider.mts +13 -11
- package/src/decorators/controller.decorator.mts +3 -6
- package/src/decorators/endpoint.decorator.mts +17 -10
- package/src/decorators/module.decorator.mts +3 -6
- package/src/decorators/multipart.decorator.mts +17 -10
- package/src/decorators/stream.decorator.mts +17 -10
- package/src/decorators/use-guards.decorator.mts +3 -2
- package/src/index.mts +1 -1
- package/src/logger/console-logger.service.mts +3 -2
- package/src/logger/logger.factory.mts +4 -5
- package/src/logger/logger.service.mts +2 -1
- package/src/metadata/controller.metadata.mts +3 -2
- package/src/metadata/handler.metadata.mts +1 -4
- package/src/metadata/index.mts +0 -1
- package/src/metadata/module.metadata.mts +3 -2
- package/src/navios.application.mts +9 -8
- package/src/navios.factory.mts +4 -2
- package/src/services/controller-adapter.service.mts +13 -12
- package/src/services/guard-runner.service.mts +4 -6
- package/src/services/module-loader.service.mts +4 -2
- package/src/tokens/application.token.mts +1 -1
- package/src/tokens/execution-context.token.mts +2 -1
- package/src/tokens/reply.token.mts +1 -1
- package/src/tokens/request.token.mts +1 -1
- package/src/metadata/injectable.metadata.mts +0 -11
- package/src/service-locator/__tests__/injectable.spec.mts +0 -171
- package/src/service-locator/__tests__/injection-token.spec.mts +0 -129
- package/src/service-locator/decorators/get-injectable-token.mts +0 -19
- package/src/service-locator/decorators/index.mts +0 -2
- package/src/service-locator/decorators/injectable.decorator.mts +0 -113
- package/src/service-locator/enums/index.mts +0 -1
- package/src/service-locator/enums/injectable-scope.enum.mts +0 -10
- package/src/service-locator/errors/errors.enum.mts +0 -8
- package/src/service-locator/errors/factory-not-found.mts +0 -8
- package/src/service-locator/errors/factory-token-not-resolved.mts +0 -10
- package/src/service-locator/errors/index.mts +0 -7
- package/src/service-locator/errors/instance-destroying.mts +0 -8
- package/src/service-locator/errors/instance-expired.mts +0 -8
- package/src/service-locator/errors/instance-not-found.mts +0 -8
- package/src/service-locator/errors/unknown-error.mts +0 -15
- package/src/service-locator/event-emitter.mts +0 -107
- package/src/service-locator/index.mts +0 -15
- package/src/service-locator/inject.mts +0 -42
- package/src/service-locator/injection-token.mts +0 -92
- package/src/service-locator/injector.mts +0 -18
- package/src/service-locator/interfaces/factory.interface.mts +0 -11
- package/src/service-locator/override.mts +0 -22
- package/src/service-locator/proxy-service-locator.mts +0 -99
- package/src/service-locator/resolve-service.mts +0 -46
- package/src/service-locator/service-locator-abstract-factory-context.mts +0 -23
- package/src/service-locator/service-locator-event-bus.mts +0 -96
- package/src/service-locator/service-locator-instance-holder.mts +0 -63
- package/src/service-locator/service-locator-manager.mts +0 -89
- package/src/service-locator/service-locator.mts +0 -535
- package/src/service-locator/sync-injector.mts +0 -66
|
@@ -1,535 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
3
|
-
import type { AnyZodObject, z, ZodOptional } from 'zod'
|
|
4
|
-
|
|
5
|
-
import type { ServiceLocatorAbstractFactoryContext } from './service-locator-abstract-factory-context.mjs'
|
|
6
|
-
import type { ServiceLocatorInstanceHolder } from './service-locator-instance-holder.mjs'
|
|
7
|
-
|
|
8
|
-
import { InjectableScope } from './enums/index.mjs'
|
|
9
|
-
import {
|
|
10
|
-
ErrorsEnum,
|
|
11
|
-
FactoryNotFound,
|
|
12
|
-
FactoryTokenNotResolved,
|
|
13
|
-
UnknownError,
|
|
14
|
-
} from './errors/index.mjs'
|
|
15
|
-
import {
|
|
16
|
-
BoundInjectionToken,
|
|
17
|
-
FactoryInjectionToken,
|
|
18
|
-
getInjectableToken,
|
|
19
|
-
} from './index.mjs'
|
|
20
|
-
import { InjectionToken } from './injection-token.mjs'
|
|
21
|
-
import { ServiceLocatorEventBus } from './service-locator-event-bus.mjs'
|
|
22
|
-
import {
|
|
23
|
-
ServiceLocatorInstanceHolderKind,
|
|
24
|
-
ServiceLocatorInstanceHolderStatus,
|
|
25
|
-
} from './service-locator-instance-holder.mjs'
|
|
26
|
-
import { ServiceLocatorManager } from './service-locator-manager.mjs'
|
|
27
|
-
|
|
28
|
-
export class ServiceLocator {
|
|
29
|
-
private abstractFactories: Map<
|
|
30
|
-
InjectionToken<any, any>,
|
|
31
|
-
(ctx: ServiceLocatorAbstractFactoryContext, ...args: any) => Promise<any>
|
|
32
|
-
> = new Map()
|
|
33
|
-
private instanceFactories: Map<
|
|
34
|
-
InjectionToken<any, any>,
|
|
35
|
-
(ctx: ServiceLocatorAbstractFactoryContext, ...args: any) => Promise<any>
|
|
36
|
-
> = new Map()
|
|
37
|
-
|
|
38
|
-
private readonly eventBus: ServiceLocatorEventBus
|
|
39
|
-
private readonly manager: ServiceLocatorManager
|
|
40
|
-
|
|
41
|
-
constructor(private readonly logger: Console | null = null) {
|
|
42
|
-
this.eventBus = new ServiceLocatorEventBus(logger)
|
|
43
|
-
this.manager = new ServiceLocatorManager(logger)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getEventBus() {
|
|
47
|
-
return this.eventBus
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public registerInstance<Instance>(
|
|
51
|
-
token: InjectionToken<Instance, undefined>,
|
|
52
|
-
instance: Instance,
|
|
53
|
-
): void {
|
|
54
|
-
const instanceName = this.getInstanceIdentifier(token, undefined)
|
|
55
|
-
this.manager.set(instanceName, {
|
|
56
|
-
name: instanceName,
|
|
57
|
-
instance,
|
|
58
|
-
status: ServiceLocatorInstanceHolderStatus.Created,
|
|
59
|
-
kind: ServiceLocatorInstanceHolderKind.Instance,
|
|
60
|
-
createdAt: Date.now(),
|
|
61
|
-
ttl: Infinity,
|
|
62
|
-
deps: [],
|
|
63
|
-
destroyListeners: [],
|
|
64
|
-
effects: [],
|
|
65
|
-
destroyPromise: null,
|
|
66
|
-
creationPromise: null,
|
|
67
|
-
})
|
|
68
|
-
this.eventBus.emit(instanceName, 'create')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public removeInstance<Instance>(token: InjectionToken<Instance, undefined>) {
|
|
72
|
-
const instanceName = this.getInstanceIdentifier(token, undefined)
|
|
73
|
-
return this.invalidate(instanceName)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
public registerAbstractFactory<
|
|
77
|
-
Instance,
|
|
78
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
79
|
-
>(
|
|
80
|
-
token: InjectionToken<Instance, Schema>,
|
|
81
|
-
factory: (
|
|
82
|
-
ctx: ServiceLocatorAbstractFactoryContext,
|
|
83
|
-
values: Schema extends AnyZodObject ? z.output<Schema> : undefined,
|
|
84
|
-
) => Promise<Instance>,
|
|
85
|
-
type: InjectableScope = InjectableScope.Singleton,
|
|
86
|
-
) {
|
|
87
|
-
this.logger?.log(
|
|
88
|
-
`[ServiceLocator]#registerAbstractFactory(): Registering abstract factory for ${name}`,
|
|
89
|
-
)
|
|
90
|
-
if (type === InjectableScope.Instance) {
|
|
91
|
-
this.instanceFactories.set(token, factory)
|
|
92
|
-
this.abstractFactories.delete(token)
|
|
93
|
-
} else {
|
|
94
|
-
this.abstractFactories.set(token, factory)
|
|
95
|
-
this.instanceFactories.delete(token)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private resolveTokenArgs<
|
|
100
|
-
Instance,
|
|
101
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
102
|
-
>(
|
|
103
|
-
token: InjectionToken<Instance, Schema>,
|
|
104
|
-
args: Schema extends AnyZodObject
|
|
105
|
-
? z.input<Schema>
|
|
106
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
107
|
-
? z.input<Schema> | undefined
|
|
108
|
-
: undefined,
|
|
109
|
-
):
|
|
110
|
-
| [
|
|
111
|
-
undefined,
|
|
112
|
-
Schema extends AnyZodObject
|
|
113
|
-
? z.input<Schema>
|
|
114
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
115
|
-
? z.input<Schema> | undefined
|
|
116
|
-
: undefined,
|
|
117
|
-
]
|
|
118
|
-
| [FactoryTokenNotResolved | UnknownError] {
|
|
119
|
-
let realArgs = args
|
|
120
|
-
if (token instanceof BoundInjectionToken) {
|
|
121
|
-
realArgs = token.value
|
|
122
|
-
} else if (token instanceof FactoryInjectionToken) {
|
|
123
|
-
if (token.resolved) {
|
|
124
|
-
realArgs = token.value
|
|
125
|
-
} else {
|
|
126
|
-
return [new FactoryTokenNotResolved(token.name)]
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (!token.schema) {
|
|
130
|
-
return [undefined, realArgs]
|
|
131
|
-
}
|
|
132
|
-
const validatedArgs = token.schema?.safeParse(realArgs)
|
|
133
|
-
if (validatedArgs && !validatedArgs.success) {
|
|
134
|
-
this.logger?.error(
|
|
135
|
-
`[ServiceLocator]#getInstance(): Error validating args for ${token.name.toString()}`,
|
|
136
|
-
validatedArgs.error,
|
|
137
|
-
)
|
|
138
|
-
return [new UnknownError(validatedArgs.error)]
|
|
139
|
-
}
|
|
140
|
-
// @ts-expect-error We return correct type
|
|
141
|
-
return [undefined, validatedArgs?.data]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
public getInstanceIdentifier<
|
|
145
|
-
Instance,
|
|
146
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
147
|
-
>(
|
|
148
|
-
token: InjectionToken<Instance, Schema>,
|
|
149
|
-
args: Schema extends AnyZodObject
|
|
150
|
-
? z.input<Schema>
|
|
151
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
152
|
-
? z.input<Schema> | undefined
|
|
153
|
-
: undefined,
|
|
154
|
-
): string {
|
|
155
|
-
const [err, realArgs] = this.resolveTokenArgs(token, args)
|
|
156
|
-
if (err) {
|
|
157
|
-
throw err
|
|
158
|
-
}
|
|
159
|
-
return this.makeInstanceName(token, realArgs)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
public async getInstance<
|
|
163
|
-
Instance,
|
|
164
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
165
|
-
>(
|
|
166
|
-
token: InjectionToken<Instance, Schema>,
|
|
167
|
-
args: Schema extends AnyZodObject
|
|
168
|
-
? z.input<Schema>
|
|
169
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
170
|
-
? z.input<Schema> | undefined
|
|
171
|
-
: undefined,
|
|
172
|
-
): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]> {
|
|
173
|
-
const [err, realArgs] = this.resolveTokenArgs(token, args)
|
|
174
|
-
if (err instanceof UnknownError) {
|
|
175
|
-
throw err
|
|
176
|
-
} else if (
|
|
177
|
-
err instanceof FactoryTokenNotResolved &&
|
|
178
|
-
token instanceof FactoryInjectionToken
|
|
179
|
-
) {
|
|
180
|
-
await token.resolve()
|
|
181
|
-
return this.getInstance(token, args)
|
|
182
|
-
}
|
|
183
|
-
const instanceName = this.makeInstanceName(token, realArgs)
|
|
184
|
-
const [error, holder] = this.manager.get(instanceName)
|
|
185
|
-
if (!error) {
|
|
186
|
-
if (holder.status === ServiceLocatorInstanceHolderStatus.Creating) {
|
|
187
|
-
// @ts-expect-error TS2322 We should redefine the instance name type
|
|
188
|
-
return holder.creationPromise
|
|
189
|
-
} else if (
|
|
190
|
-
holder.status === ServiceLocatorInstanceHolderStatus.Destroying
|
|
191
|
-
) {
|
|
192
|
-
// Should never happen
|
|
193
|
-
return [new UnknownError(ErrorsEnum.InstanceDestroying)]
|
|
194
|
-
}
|
|
195
|
-
// @ts-expect-error We should redefine the instance name type
|
|
196
|
-
return [undefined, holder.instance]
|
|
197
|
-
}
|
|
198
|
-
switch (error.code) {
|
|
199
|
-
case ErrorsEnum.InstanceDestroying:
|
|
200
|
-
this.logger?.log(
|
|
201
|
-
`[ServiceLocator]#getInstance() TTL expired for ${holder?.name}`,
|
|
202
|
-
)
|
|
203
|
-
await holder?.destroyPromise
|
|
204
|
-
//Maybe we already have a new instance
|
|
205
|
-
return this.getInstance<Instance, Schema>(token, args)
|
|
206
|
-
|
|
207
|
-
case ErrorsEnum.InstanceExpired:
|
|
208
|
-
this.logger?.log(
|
|
209
|
-
`[ServiceLocator]#getInstance() TTL expired for ${holder?.name}`,
|
|
210
|
-
)
|
|
211
|
-
await this.invalidate(instanceName)
|
|
212
|
-
//Maybe we already have a new instance
|
|
213
|
-
return this.getInstance<Instance, Schema>(token, args)
|
|
214
|
-
case ErrorsEnum.InstanceNotFound:
|
|
215
|
-
break
|
|
216
|
-
default:
|
|
217
|
-
return [error]
|
|
218
|
-
}
|
|
219
|
-
// @ts-expect-error TS2322 It's validated
|
|
220
|
-
return this.createInstance(instanceName, token, realArgs)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
public async getOrThrowInstance<
|
|
224
|
-
Instance,
|
|
225
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
226
|
-
>(
|
|
227
|
-
token: InjectionToken<Instance, Schema>,
|
|
228
|
-
args: Schema extends AnyZodObject
|
|
229
|
-
? z.input<Schema>
|
|
230
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
231
|
-
? z.input<Schema> | undefined
|
|
232
|
-
: undefined,
|
|
233
|
-
): Promise<Instance> {
|
|
234
|
-
const [error, instance] = await this.getInstance(token, args)
|
|
235
|
-
if (error) {
|
|
236
|
-
throw error
|
|
237
|
-
}
|
|
238
|
-
return instance
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
private notifyListeners(
|
|
242
|
-
name: string,
|
|
243
|
-
event: 'create' | 'destroy' = 'create',
|
|
244
|
-
) {
|
|
245
|
-
this.logger?.log(
|
|
246
|
-
`[ServiceLocator]#notifyListeners() Notifying listeners for ${name} with event ${event}`,
|
|
247
|
-
)
|
|
248
|
-
return this.eventBus.emit(name, event)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
private async createInstance<
|
|
252
|
-
Instance,
|
|
253
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
254
|
-
>(
|
|
255
|
-
instanceName: string,
|
|
256
|
-
token: InjectionToken<Instance, Schema>,
|
|
257
|
-
args: Schema extends AnyZodObject
|
|
258
|
-
? z.input<Schema>
|
|
259
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
260
|
-
? z.input<Schema> | undefined
|
|
261
|
-
: undefined,
|
|
262
|
-
): Promise<[undefined, Instance] | [FactoryNotFound | UnknownError]> {
|
|
263
|
-
this.logger?.log(
|
|
264
|
-
`[ServiceLocator]#createInstance() Creating instance for ${instanceName}`,
|
|
265
|
-
)
|
|
266
|
-
let realToken =
|
|
267
|
-
token instanceof BoundInjectionToken ||
|
|
268
|
-
token instanceof FactoryInjectionToken
|
|
269
|
-
? token.token
|
|
270
|
-
: token
|
|
271
|
-
if (
|
|
272
|
-
this.abstractFactories.has(realToken) ||
|
|
273
|
-
this.instanceFactories.has(realToken)
|
|
274
|
-
) {
|
|
275
|
-
return this.createInstanceFromAbstractFactory(
|
|
276
|
-
instanceName,
|
|
277
|
-
realToken,
|
|
278
|
-
args,
|
|
279
|
-
)
|
|
280
|
-
} else {
|
|
281
|
-
return [new FactoryNotFound(realToken.name.toString())]
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
private async createInstanceFromAbstractFactory<
|
|
286
|
-
Instance,
|
|
287
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
288
|
-
Args extends Schema extends AnyZodObject
|
|
289
|
-
? z.input<Schema>
|
|
290
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
291
|
-
? z.input<Schema> | undefined
|
|
292
|
-
: undefined,
|
|
293
|
-
>(
|
|
294
|
-
instanceName: string,
|
|
295
|
-
token: InjectionToken<Instance, Schema>,
|
|
296
|
-
args: Args,
|
|
297
|
-
): Promise<[undefined, Instance] | [FactoryNotFound]> {
|
|
298
|
-
this.logger?.log(
|
|
299
|
-
`[ServiceLocator]#createInstanceFromAbstractFactory(): Creating instance for ${instanceName} from abstract factory`,
|
|
300
|
-
)
|
|
301
|
-
const ctx = this.createContextForAbstractFactory(instanceName)
|
|
302
|
-
let shouldStore = true
|
|
303
|
-
let abstractFactory = this.abstractFactories.get(token)
|
|
304
|
-
if (!abstractFactory) {
|
|
305
|
-
abstractFactory = this.instanceFactories.get(token)
|
|
306
|
-
shouldStore = false
|
|
307
|
-
if (!abstractFactory) {
|
|
308
|
-
return [new FactoryNotFound(token.name.toString())]
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
const holder: ServiceLocatorInstanceHolder<Instance> = {
|
|
312
|
-
name: instanceName,
|
|
313
|
-
instance: null,
|
|
314
|
-
status: ServiceLocatorInstanceHolderStatus.Creating,
|
|
315
|
-
kind: ServiceLocatorInstanceHolderKind.AbstractFactory,
|
|
316
|
-
// @ts-expect-error TS2322 This is correct type
|
|
317
|
-
creationPromise: abstractFactory(ctx, args)
|
|
318
|
-
.then(async (instance: Instance) => {
|
|
319
|
-
holder.instance = instance
|
|
320
|
-
holder.status = ServiceLocatorInstanceHolderStatus.Created
|
|
321
|
-
holder.deps = ctx.getDependencies()
|
|
322
|
-
holder.destroyListeners = ctx.getDestroyListeners()
|
|
323
|
-
holder.ttl = ctx.getTtl()
|
|
324
|
-
if (holder.deps.length > 0) {
|
|
325
|
-
this.logger?.log(
|
|
326
|
-
`[ServiceLocator]#createInstanceFromAbstractFactory(): Adding subscriptions for ${instanceName} dependencies for their invalidations: ${holder.deps.join(
|
|
327
|
-
', ',
|
|
328
|
-
)}`,
|
|
329
|
-
)
|
|
330
|
-
holder.deps.forEach((dependency) => {
|
|
331
|
-
holder.destroyListeners.push(
|
|
332
|
-
this.eventBus.on(dependency, 'destroy', () =>
|
|
333
|
-
this.invalidate(instanceName),
|
|
334
|
-
),
|
|
335
|
-
)
|
|
336
|
-
})
|
|
337
|
-
}
|
|
338
|
-
if (holder.ttl === 0 || !shouldStore) {
|
|
339
|
-
// One time instance
|
|
340
|
-
await this.invalidate(instanceName)
|
|
341
|
-
}
|
|
342
|
-
await this.notifyListeners(instanceName)
|
|
343
|
-
return [undefined, instance as Instance]
|
|
344
|
-
})
|
|
345
|
-
.catch((error) => {
|
|
346
|
-
this.logger?.error(
|
|
347
|
-
`[ServiceLocator]#createInstanceFromAbstractFactory(): Error creating instance for ${instanceName}`,
|
|
348
|
-
error,
|
|
349
|
-
)
|
|
350
|
-
return [new UnknownError(error)]
|
|
351
|
-
}),
|
|
352
|
-
effects: [],
|
|
353
|
-
deps: [],
|
|
354
|
-
destroyListeners: [],
|
|
355
|
-
createdAt: Date.now(),
|
|
356
|
-
ttl: Infinity,
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (shouldStore) {
|
|
360
|
-
this.manager.set(instanceName, holder)
|
|
361
|
-
}
|
|
362
|
-
// @ts-expect-error TS2322 This is correct type
|
|
363
|
-
return holder.creationPromise
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
private createContextForAbstractFactory(
|
|
367
|
-
instanceName: string,
|
|
368
|
-
): ServiceLocatorAbstractFactoryContext {
|
|
369
|
-
const dependencies = new Set<string>()
|
|
370
|
-
const destroyListeners = new Set<() => void>()
|
|
371
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
372
|
-
const self = this
|
|
373
|
-
|
|
374
|
-
function invalidate(name = instanceName) {
|
|
375
|
-
return self.invalidate(name)
|
|
376
|
-
}
|
|
377
|
-
function addEffect(listener: () => void) {
|
|
378
|
-
destroyListeners.add(listener)
|
|
379
|
-
}
|
|
380
|
-
let ttl = Infinity
|
|
381
|
-
function setTtl(value: number) {
|
|
382
|
-
ttl = value
|
|
383
|
-
}
|
|
384
|
-
function getTtl() {
|
|
385
|
-
return ttl
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function on(key: string, event: string, listener: (event: string) => void) {
|
|
389
|
-
destroyListeners.add(self.eventBus.on(key, event, listener))
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return {
|
|
393
|
-
// @ts-expect-error This is correct type
|
|
394
|
-
async inject(token, args) {
|
|
395
|
-
let injectionToken = token
|
|
396
|
-
if (typeof token === 'function') {
|
|
397
|
-
injectionToken = getInjectableToken(token)
|
|
398
|
-
}
|
|
399
|
-
if (injectionToken instanceof InjectionToken) {
|
|
400
|
-
const validatedArgs = token.schema
|
|
401
|
-
? token.schema.safeParse(args)
|
|
402
|
-
: undefined
|
|
403
|
-
const instanceName = self.makeInstanceName(token, validatedArgs)
|
|
404
|
-
dependencies.add(instanceName)
|
|
405
|
-
return self.getOrThrowInstance(injectionToken, args)
|
|
406
|
-
}
|
|
407
|
-
throw new Error(
|
|
408
|
-
`[ServiceLocator]#inject(): Invalid token type: ${typeof token}. Expected a class or an InjectionToken.`,
|
|
409
|
-
)
|
|
410
|
-
},
|
|
411
|
-
invalidate,
|
|
412
|
-
eventBus: self.eventBus,
|
|
413
|
-
on: on as ServiceLocatorEventBus['on'],
|
|
414
|
-
getDependencies: () => Array.from(dependencies),
|
|
415
|
-
addEffect,
|
|
416
|
-
getDestroyListeners: () => Array.from(destroyListeners),
|
|
417
|
-
setTtl,
|
|
418
|
-
getTtl,
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
public getSyncInstance<
|
|
423
|
-
Instance,
|
|
424
|
-
Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
|
|
425
|
-
>(
|
|
426
|
-
token: InjectionToken<Instance, Schema>,
|
|
427
|
-
args: Schema extends AnyZodObject
|
|
428
|
-
? z.input<Schema>
|
|
429
|
-
: Schema extends ZodOptional<AnyZodObject>
|
|
430
|
-
? z.input<Schema> | undefined
|
|
431
|
-
: undefined,
|
|
432
|
-
): Instance | null {
|
|
433
|
-
const [err, realArgs] = this.resolveTokenArgs(token, args)
|
|
434
|
-
if (err) {
|
|
435
|
-
return null
|
|
436
|
-
}
|
|
437
|
-
const instanceName = this.makeInstanceName(token, realArgs)
|
|
438
|
-
const [error, holder] = this.manager.get(instanceName)
|
|
439
|
-
if (error) {
|
|
440
|
-
return null
|
|
441
|
-
}
|
|
442
|
-
return holder.instance as Instance
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
invalidate(service: string, round = 1): Promise<any> {
|
|
446
|
-
this.logger?.log(
|
|
447
|
-
`[ServiceLocator]#invalidate(): Starting Invalidating process of ${service}`,
|
|
448
|
-
)
|
|
449
|
-
const toInvalidate = this.manager.filter(
|
|
450
|
-
(holder) => holder.name === service || holder.deps.includes(service),
|
|
451
|
-
)
|
|
452
|
-
const promises = []
|
|
453
|
-
for (const [key, holder] of toInvalidate.entries()) {
|
|
454
|
-
if (holder.status === ServiceLocatorInstanceHolderStatus.Destroying) {
|
|
455
|
-
this.logger?.trace(
|
|
456
|
-
`[ServiceLocator]#invalidate(): ${key} is already being destroyed`,
|
|
457
|
-
)
|
|
458
|
-
promises.push(holder.destroyPromise)
|
|
459
|
-
continue
|
|
460
|
-
}
|
|
461
|
-
if (holder.status === ServiceLocatorInstanceHolderStatus.Creating) {
|
|
462
|
-
this.logger?.trace(
|
|
463
|
-
`[ServiceLocator]#invalidate(): ${key} is being created, waiting for creation to finish`,
|
|
464
|
-
)
|
|
465
|
-
promises.push(
|
|
466
|
-
holder.creationPromise?.then(() => {
|
|
467
|
-
if (round > 3) {
|
|
468
|
-
this.logger?.error(
|
|
469
|
-
`[ServiceLocator]#invalidate(): ${key} creation is triggering a new invalidation round, but it is still not created`,
|
|
470
|
-
)
|
|
471
|
-
return
|
|
472
|
-
}
|
|
473
|
-
return this.invalidate(key, round + 1)
|
|
474
|
-
}),
|
|
475
|
-
)
|
|
476
|
-
continue
|
|
477
|
-
}
|
|
478
|
-
// @ts-expect-error TS2322 we are changing the status
|
|
479
|
-
holder.status = ServiceLocatorInstanceHolderStatus.Destroying
|
|
480
|
-
this.logger?.log(
|
|
481
|
-
`[ServiceLocator]#invalidate(): Invalidating ${key} and notifying listeners`,
|
|
482
|
-
)
|
|
483
|
-
// @ts-expect-error TS2322 we are changing the status
|
|
484
|
-
holder.destroyPromise = Promise.all(
|
|
485
|
-
holder.destroyListeners.map((listener) => listener()),
|
|
486
|
-
).then(async () => {
|
|
487
|
-
this.manager.delete(key)
|
|
488
|
-
await this.notifyListeners(key, 'destroy')
|
|
489
|
-
})
|
|
490
|
-
promises.push(holder.destroyPromise)
|
|
491
|
-
}
|
|
492
|
-
return Promise.all(promises)
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async ready() {
|
|
496
|
-
return Promise.all(
|
|
497
|
-
Array.from(this.manager.filter(() => true)).map(([, holder]) => {
|
|
498
|
-
if (holder.status === ServiceLocatorInstanceHolderStatus.Creating) {
|
|
499
|
-
return holder.creationPromise?.then(() => null)
|
|
500
|
-
}
|
|
501
|
-
if (holder.status === ServiceLocatorInstanceHolderStatus.Destroying) {
|
|
502
|
-
return holder.destroyPromise.then(() => null)
|
|
503
|
-
}
|
|
504
|
-
return Promise.resolve(null)
|
|
505
|
-
}),
|
|
506
|
-
).then(() => null)
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
makeInstanceName(token: InjectionToken<any, any>, args: any) {
|
|
510
|
-
let stringifiedArgs = args
|
|
511
|
-
? ':' +
|
|
512
|
-
JSON.stringify(args, (_, value) => {
|
|
513
|
-
if (typeof value === 'function') {
|
|
514
|
-
return `function:${value.name}(${value.length})`
|
|
515
|
-
}
|
|
516
|
-
if (typeof value === 'symbol') {
|
|
517
|
-
return value.toString()
|
|
518
|
-
}
|
|
519
|
-
return value
|
|
520
|
-
})
|
|
521
|
-
.replaceAll(/"/g, '')
|
|
522
|
-
.replaceAll(/:/g, '=')
|
|
523
|
-
.replaceAll(/,/g, '|')
|
|
524
|
-
: ''
|
|
525
|
-
const { name } = token
|
|
526
|
-
if (typeof name === 'function') {
|
|
527
|
-
const className = name.name
|
|
528
|
-
return `${className}(${token.id})${stringifiedArgs}`
|
|
529
|
-
} else if (typeof name === 'symbol') {
|
|
530
|
-
return `${name.toString()}(${token.id})${stringifiedArgs}`
|
|
531
|
-
} else {
|
|
532
|
-
return `${name}(${token.id})${stringifiedArgs}`
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { AnyZodObject, z, ZodOptional } from 'zod'
|
|
2
|
-
|
|
3
|
-
import type { ClassType } from './injection-token.mjs'
|
|
4
|
-
|
|
5
|
-
import { getInjectableToken } from './decorators/index.mjs'
|
|
6
|
-
import { InjectionToken } from './injection-token.mjs'
|
|
7
|
-
import { getServiceLocator } from './injector.mjs'
|
|
8
|
-
|
|
9
|
-
let promiseCollector: null | ((promise: Promise<any>) => void) = null
|
|
10
|
-
|
|
11
|
-
export function syncInject<T extends ClassType>(token: T): InstanceType<T>
|
|
12
|
-
// Not supported by TypeScript yet
|
|
13
|
-
// export function syncInject<
|
|
14
|
-
// R,
|
|
15
|
-
// T extends ClassType & {
|
|
16
|
-
// [InjectableTokenMeta]: InjectionToken<R, undefined>
|
|
17
|
-
// },
|
|
18
|
-
// >(token: T): R
|
|
19
|
-
// export function syncInject<
|
|
20
|
-
// R,
|
|
21
|
-
// S extends AnyZodObject,
|
|
22
|
-
// T extends ClassType & {
|
|
23
|
-
// [InjectableTokenMeta]: InjectionToken<R, S>
|
|
24
|
-
// },
|
|
25
|
-
// >(token: T, args: z.input<S>): R
|
|
26
|
-
export function syncInject<T, S extends AnyZodObject>(
|
|
27
|
-
token: InjectionToken<T, S>,
|
|
28
|
-
args: z.input<S>,
|
|
29
|
-
): T
|
|
30
|
-
export function syncInject<T, S extends ZodOptional<AnyZodObject>>(
|
|
31
|
-
token: InjectionToken<T, S>,
|
|
32
|
-
args: z.input<S>,
|
|
33
|
-
): T
|
|
34
|
-
|
|
35
|
-
export function syncInject<T>(token: InjectionToken<T, undefined>): T
|
|
36
|
-
export function syncInject<
|
|
37
|
-
T,
|
|
38
|
-
Token extends InjectionToken<T>,
|
|
39
|
-
S extends AnyZodObject | unknown = Token['schema'],
|
|
40
|
-
>(token: Token, args?: S extends AnyZodObject ? z.input<S> : never): T {
|
|
41
|
-
let realToken: InjectionToken<T, S> = token
|
|
42
|
-
if (!(token instanceof InjectionToken)) {
|
|
43
|
-
realToken = getInjectableToken(token) as InjectionToken<T, S>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const instance = getServiceLocator().getSyncInstance(realToken, args)
|
|
47
|
-
if (!instance) {
|
|
48
|
-
if (promiseCollector) {
|
|
49
|
-
const promise = getServiceLocator().getInstance(realToken, args)
|
|
50
|
-
promiseCollector(promise)
|
|
51
|
-
} else {
|
|
52
|
-
throw new Error(
|
|
53
|
-
`[ServiceLocator] No instance found for ${realToken.name.toString()}`,
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return instance as unknown as T
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function setPromiseCollector(
|
|
61
|
-
collector: null | ((promise: Promise<any>) => void),
|
|
62
|
-
): typeof promiseCollector {
|
|
63
|
-
const original = promiseCollector
|
|
64
|
-
promiseCollector = collector
|
|
65
|
-
return original
|
|
66
|
-
}
|