@navios/di 0.1.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.
Files changed (41) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +2 -0
  3. package/dist/_tsup-dts-rollup.d.mts +536 -0
  4. package/dist/_tsup-dts-rollup.d.ts +536 -0
  5. package/dist/index.d.mts +54 -0
  6. package/dist/index.d.ts +54 -0
  7. package/dist/index.js +1019 -0
  8. package/dist/index.mjs +960 -0
  9. package/package.json +46 -0
  10. package/src/__tests__/injectable.spec.mts +167 -0
  11. package/src/__tests__/injection-token.spec.mts +127 -0
  12. package/src/decorators/index.mts +1 -0
  13. package/src/decorators/injectable.decorator.mts +107 -0
  14. package/src/enums/index.mts +2 -0
  15. package/src/enums/injectable-scope.enum.mts +10 -0
  16. package/src/enums/injectable-type.enum.mts +4 -0
  17. package/src/errors/errors.enum.mts +8 -0
  18. package/src/errors/factory-not-found.mts +8 -0
  19. package/src/errors/factory-token-not-resolved.mts +10 -0
  20. package/src/errors/index.mts +7 -0
  21. package/src/errors/instance-destroying.mts +8 -0
  22. package/src/errors/instance-expired.mts +8 -0
  23. package/src/errors/instance-not-found.mts +8 -0
  24. package/src/errors/unknown-error.mts +15 -0
  25. package/src/event-emitter.mts +107 -0
  26. package/src/factory-context.mts +16 -0
  27. package/src/index.mts +16 -0
  28. package/src/injection-token.mts +130 -0
  29. package/src/injector.mts +19 -0
  30. package/src/interfaces/factory.interface.mts +11 -0
  31. package/src/interfaces/index.mts +1 -0
  32. package/src/proxy-service-locator.mts +83 -0
  33. package/src/registry.mts +65 -0
  34. package/src/resolve-service.mts +43 -0
  35. package/src/service-locator-event-bus.mts +96 -0
  36. package/src/service-locator-instance-holder.mts +63 -0
  37. package/src/service-locator-manager.mts +89 -0
  38. package/src/service-locator.mts +571 -0
  39. package/src/utils/get-injectable-token.mts +19 -0
  40. package/src/utils/get-injectors.mts +133 -0
  41. package/src/utils/index.mts +2 -0
package/dist/index.js ADDED
@@ -0,0 +1,1019 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/di/src/index.mts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ BoundInjectionToken: () => BoundInjectionToken,
24
+ ErrorsEnum: () => ErrorsEnum,
25
+ EventEmitter: () => EventEmitter,
26
+ FactoryInjectionToken: () => FactoryInjectionToken,
27
+ FactoryNotFound: () => FactoryNotFound,
28
+ FactoryTokenNotResolved: () => FactoryTokenNotResolved,
29
+ Injectable: () => Injectable,
30
+ InjectableScope: () => InjectableScope,
31
+ InjectableTokenMeta: () => InjectableTokenMeta,
32
+ InjectableType: () => InjectableType,
33
+ InjectionToken: () => InjectionToken,
34
+ InjectorsBase: () => InjectorsBase,
35
+ InstanceDestroying: () => InstanceDestroying,
36
+ InstanceExpired: () => InstanceExpired,
37
+ InstanceNotFound: () => InstanceNotFound,
38
+ ProxyServiceLocator: () => ProxyServiceLocator,
39
+ Registry: () => Registry,
40
+ ServiceLocator: () => ServiceLocator,
41
+ ServiceLocatorEventBus: () => ServiceLocatorEventBus,
42
+ ServiceLocatorInstanceHolderKind: () => ServiceLocatorInstanceHolderKind,
43
+ ServiceLocatorInstanceHolderStatus: () => ServiceLocatorInstanceHolderStatus,
44
+ ServiceLocatorManager: () => ServiceLocatorManager,
45
+ UnknownError: () => UnknownError,
46
+ getGlobalServiceLocator: () => getGlobalServiceLocator,
47
+ getInjectableToken: () => getInjectableToken,
48
+ getInjectors: () => getInjectors,
49
+ globalRegistry: () => globalRegistry,
50
+ inject: () => inject,
51
+ makeProxyServiceLocator: () => makeProxyServiceLocator,
52
+ provideServiceLocator: () => provideServiceLocator,
53
+ resolveService: () => resolveService,
54
+ syncInject: () => syncInject,
55
+ wrapSyncInit: () => wrapSyncInit
56
+ });
57
+ module.exports = __toCommonJS(src_exports);
58
+
59
+ // packages/di/src/decorators/injectable.decorator.mts
60
+ var import_common2 = require("@navios/common");
61
+
62
+ // packages/di/src/enums/injectable-scope.enum.mts
63
+ var InjectableScope = /* @__PURE__ */ ((InjectableScope3) => {
64
+ InjectableScope3["Singleton"] = "Singleton";
65
+ InjectableScope3["Instance"] = "Instance";
66
+ return InjectableScope3;
67
+ })(InjectableScope || {});
68
+
69
+ // packages/di/src/enums/injectable-type.enum.mts
70
+ var InjectableType = /* @__PURE__ */ ((InjectableType2) => {
71
+ InjectableType2["Class"] = "Class";
72
+ InjectableType2["Factory"] = "Factory";
73
+ return InjectableType2;
74
+ })(InjectableType || {});
75
+
76
+ // packages/di/src/injection-token.mts
77
+ var import_crypto = require("crypto");
78
+ var import_zod = require("zod");
79
+ var InjectionToken = class _InjectionToken {
80
+ constructor(name, schema) {
81
+ this.name = name;
82
+ this.schema = schema;
83
+ }
84
+ id = (0, import_crypto.randomUUID)();
85
+ formattedName = null;
86
+ static create(name, schema) {
87
+ return new _InjectionToken(name, schema);
88
+ }
89
+ static bound(token, value) {
90
+ return new BoundInjectionToken(token, value);
91
+ }
92
+ static factory(token, factory) {
93
+ return new FactoryInjectionToken(token, factory);
94
+ }
95
+ static refineType(token) {
96
+ return token;
97
+ }
98
+ toString() {
99
+ if (this.formattedName) {
100
+ return this.formattedName;
101
+ }
102
+ const { name } = this;
103
+ if (typeof name === "function") {
104
+ const className = name.name;
105
+ this.formattedName = `${className}(${this.id})`;
106
+ } else if (typeof name === "symbol") {
107
+ this.formattedName = `${name.toString()}(${this.id})`;
108
+ } else {
109
+ this.formattedName = `${name}(${this.id})`;
110
+ }
111
+ return this.formattedName;
112
+ }
113
+ };
114
+ var BoundInjectionToken = class {
115
+ constructor(token, value) {
116
+ this.token = token;
117
+ this.value = value;
118
+ this.name = token.name;
119
+ this.id = token.id;
120
+ this.schema = token.schema;
121
+ }
122
+ id;
123
+ name;
124
+ schema;
125
+ toString() {
126
+ return this.token.toString();
127
+ }
128
+ };
129
+ var FactoryInjectionToken = class {
130
+ constructor(token, factory) {
131
+ this.token = token;
132
+ this.factory = factory;
133
+ this.name = token.name;
134
+ this.id = token.id;
135
+ this.schema = token.schema;
136
+ }
137
+ value;
138
+ resolved = false;
139
+ id;
140
+ name;
141
+ schema;
142
+ async resolve() {
143
+ if (!this.value) {
144
+ this.value = await this.factory();
145
+ this.resolved = true;
146
+ }
147
+ return this.value;
148
+ }
149
+ toString() {
150
+ return this.token.toString();
151
+ }
152
+ };
153
+
154
+ // packages/di/src/registry.mts
155
+ var import_zod2 = require("zod");
156
+ var Registry = class {
157
+ constructor(parent) {
158
+ this.parent = parent;
159
+ }
160
+ factories = /* @__PURE__ */ new Map();
161
+ has(token) {
162
+ if (this.factories.has(token.id)) {
163
+ return true;
164
+ }
165
+ if (this.parent) {
166
+ return this.parent.has(token);
167
+ }
168
+ return false;
169
+ }
170
+ get(token) {
171
+ const factory = this.factories.get(token.id);
172
+ if (!factory) {
173
+ if (this.parent) {
174
+ return this.parent.get(token);
175
+ }
176
+ throw new Error(`[Registry] No factory found for ${token.toString()}`);
177
+ }
178
+ return factory;
179
+ }
180
+ set(token, factory, scope) {
181
+ this.factories.set(token.id, { factory, scope, originalToken: token });
182
+ }
183
+ delete(token) {
184
+ this.factories.delete(token.id);
185
+ }
186
+ };
187
+ var globalRegistry = new Registry();
188
+
189
+ // packages/di/src/resolve-service.mts
190
+ var import_common = require("@navios/common");
191
+
192
+ // packages/di/src/proxy-service-locator.mts
193
+ var ProxyServiceLocator = class {
194
+ constructor(serviceLocator, ctx) {
195
+ this.serviceLocator = serviceLocator;
196
+ this.ctx = ctx;
197
+ }
198
+ getEventBus() {
199
+ return this.serviceLocator.getEventBus();
200
+ }
201
+ // @ts-expect-error We don't need all the properties of the class
202
+ getInstance(token, args) {
203
+ return this.ctx.inject(token, args).then(
204
+ (instance) => {
205
+ return [void 0, instance];
206
+ },
207
+ (error) => {
208
+ return [error];
209
+ }
210
+ );
211
+ }
212
+ getOrThrowInstance(token, args) {
213
+ return this.ctx.inject(token, args);
214
+ }
215
+ getSyncInstance(token, args) {
216
+ return this.serviceLocator.getSyncInstance(token, args);
217
+ }
218
+ invalidate(service, round) {
219
+ return this.serviceLocator.invalidate(service, round);
220
+ }
221
+ ready() {
222
+ return this.serviceLocator.ready();
223
+ }
224
+ makeInstanceName(token, args) {
225
+ return this.serviceLocator.makeInstanceName(token, args);
226
+ }
227
+ };
228
+ function makeProxyServiceLocator(serviceLocator, ctx) {
229
+ return new ProxyServiceLocator(serviceLocator, ctx);
230
+ }
231
+
232
+ // packages/di/src/utils/get-injectors.mts
233
+ var InjectorsBase = /* @__PURE__ */ new Map();
234
+ function getInjectors({ baseLocator }) {
235
+ if (InjectorsBase.has(baseLocator)) {
236
+ return InjectorsBase.get(baseLocator);
237
+ }
238
+ let currentLocator = baseLocator;
239
+ function getServiceLocator() {
240
+ if (!currentLocator) {
241
+ throw new Error(
242
+ "[Injector] Service locator is not initialized. Please provide the service locator before using the @Injectable decorator."
243
+ );
244
+ }
245
+ return currentLocator;
246
+ }
247
+ function provideServiceLocator2(locator) {
248
+ const original = currentLocator;
249
+ currentLocator = locator;
250
+ return original;
251
+ }
252
+ function inject2(token, args) {
253
+ const realToken = token[InjectableTokenMeta] ?? token;
254
+ return getServiceLocator().getOrThrowInstance(realToken, args);
255
+ }
256
+ let promiseCollector = null;
257
+ function wrapSyncInit2(cb) {
258
+ return () => {
259
+ const promises = [];
260
+ const originalPromiseCollector = promiseCollector;
261
+ promiseCollector = (promise) => {
262
+ promises.push(promise);
263
+ };
264
+ const result = cb();
265
+ promiseCollector = originalPromiseCollector;
266
+ return [result, promises];
267
+ };
268
+ }
269
+ function syncInject2(token, args) {
270
+ const realToken = token[InjectableTokenMeta] ?? token;
271
+ const instance = getServiceLocator().getSyncInstance(realToken, args);
272
+ if (!instance) {
273
+ if (promiseCollector) {
274
+ const promise = getServiceLocator().getInstance(realToken, args);
275
+ promiseCollector(promise);
276
+ } else {
277
+ throw new Error(`[Injector] Cannot initiate ${realToken.toString()}`);
278
+ }
279
+ }
280
+ return instance;
281
+ }
282
+ const injectors = {
283
+ inject: inject2,
284
+ syncInject: syncInject2,
285
+ wrapSyncInit: wrapSyncInit2,
286
+ provideServiceLocator: provideServiceLocator2
287
+ };
288
+ InjectorsBase.set(baseLocator, injectors);
289
+ return injectors;
290
+ }
291
+
292
+ // packages/di/src/utils/get-injectable-token.mts
293
+ function getInjectableToken(target) {
294
+ const token = target[InjectableTokenMeta];
295
+ if (!token) {
296
+ throw new Error(
297
+ `[ServiceLocator] Class ${target.name} is not decorated with @Injectable.`
298
+ );
299
+ }
300
+ return token;
301
+ }
302
+
303
+ // packages/di/src/resolve-service.mts
304
+ async function resolveService(ctx, target, args = []) {
305
+ const proxyServiceLocator = makeProxyServiceLocator(ctx.locator, ctx);
306
+ const { wrapSyncInit: wrapSyncInit2, provideServiceLocator: provideServiceLocator2 } = getInjectors({
307
+ baseLocator: ctx.locator
308
+ });
309
+ const tryLoad = wrapSyncInit2(() => {
310
+ const original = provideServiceLocator2(proxyServiceLocator);
311
+ let result = new target(...args);
312
+ provideServiceLocator2(original);
313
+ return result;
314
+ });
315
+ let [instance, promises] = tryLoad();
316
+ if (promises.length > 0) {
317
+ await Promise.all(promises);
318
+ const newRes = tryLoad();
319
+ instance = newRes[0];
320
+ promises = newRes[1];
321
+ }
322
+ if (promises.length > 0) {
323
+ console.error(`[ServiceLocator] ${target.name} has problem with it's definition.
324
+
325
+ One or more of the dependencies are registered as a InjectableScope.Instance and are used with syncInject.
326
+
327
+ Please use inject instead of syncInject to load those dependencies.`);
328
+ throw new import_common.NaviosException(
329
+ `[ServiceLocator] Service ${target.name} cannot be instantiated.`
330
+ );
331
+ }
332
+ return instance;
333
+ }
334
+
335
+ // packages/di/src/decorators/injectable.decorator.mts
336
+ var InjectableTokenMeta = Symbol.for("InjectableTokenMeta");
337
+ function Injectable({
338
+ scope = "Singleton" /* Singleton */,
339
+ type = "Class" /* Class */,
340
+ token,
341
+ registry = globalRegistry
342
+ } = {}) {
343
+ return (target, context) => {
344
+ if (context.kind !== "class") {
345
+ throw new Error(
346
+ "[ServiceLocator] @Injectable decorator can only be used on classes."
347
+ );
348
+ }
349
+ let injectableToken = token ?? InjectionToken.create(target);
350
+ if (type === "Class" /* Class */) {
351
+ registry.set(
352
+ injectableToken,
353
+ async (ctx) => resolveService(ctx, target),
354
+ scope
355
+ );
356
+ } else if (type === "Factory" /* Factory */) {
357
+ registry.set(
358
+ injectableToken,
359
+ async (ctx, args) => {
360
+ const builder = await resolveService(ctx, target);
361
+ if (typeof builder.create !== "function") {
362
+ throw new import_common2.NaviosException(
363
+ `[ServiceLocator] Factory ${target.name} does not implement the create method.`
364
+ );
365
+ }
366
+ return builder.create(ctx, args);
367
+ },
368
+ scope
369
+ );
370
+ }
371
+ target[InjectableTokenMeta] = injectableToken;
372
+ return target;
373
+ };
374
+ }
375
+
376
+ // packages/di/src/errors/errors.enum.mts
377
+ var ErrorsEnum = /* @__PURE__ */ ((ErrorsEnum2) => {
378
+ ErrorsEnum2["InstanceExpired"] = "InstanceExpired";
379
+ ErrorsEnum2["InstanceNotFound"] = "InstanceNotFound";
380
+ ErrorsEnum2["InstanceDestroying"] = "InstanceDestroying";
381
+ ErrorsEnum2["UnknownError"] = "UnknownError";
382
+ ErrorsEnum2["FactoryNotFound"] = "FactoryNotFound";
383
+ ErrorsEnum2["FactoryTokenNotResolved"] = "FactoryTokenNotResolved";
384
+ return ErrorsEnum2;
385
+ })(ErrorsEnum || {});
386
+
387
+ // packages/di/src/errors/factory-not-found.mts
388
+ var FactoryNotFound = class extends Error {
389
+ constructor(name) {
390
+ super(`Factory ${name} not found`);
391
+ this.name = name;
392
+ }
393
+ code = "FactoryNotFound" /* FactoryNotFound */;
394
+ };
395
+
396
+ // packages/di/src/errors/factory-token-not-resolved.mts
397
+ var FactoryTokenNotResolved = class extends Error {
398
+ code = "FactoryTokenNotResolved" /* FactoryTokenNotResolved */;
399
+ constructor(name) {
400
+ super(`Factory token not resolved: ${name.toString()}`);
401
+ }
402
+ };
403
+
404
+ // packages/di/src/errors/instance-destroying.mts
405
+ var InstanceDestroying = class extends Error {
406
+ constructor(name) {
407
+ super(`Instance ${name} destroying`);
408
+ this.name = name;
409
+ }
410
+ code = "InstanceDestroying" /* InstanceDestroying */;
411
+ };
412
+
413
+ // packages/di/src/errors/instance-expired.mts
414
+ var InstanceExpired = class extends Error {
415
+ constructor(name) {
416
+ super(`Instance ${name} expired`);
417
+ this.name = name;
418
+ }
419
+ code = "InstanceExpired" /* InstanceExpired */;
420
+ };
421
+
422
+ // packages/di/src/errors/instance-not-found.mts
423
+ var InstanceNotFound = class extends Error {
424
+ constructor(name) {
425
+ super(`Instance ${name} not found`);
426
+ this.name = name;
427
+ }
428
+ code = "InstanceNotFound" /* InstanceNotFound */;
429
+ };
430
+
431
+ // packages/di/src/errors/unknown-error.mts
432
+ var UnknownError = class extends Error {
433
+ code = "UnknownError" /* UnknownError */;
434
+ parent;
435
+ constructor(message) {
436
+ if (message instanceof Error) {
437
+ super(message.message);
438
+ this.parent = message;
439
+ return;
440
+ }
441
+ super(message);
442
+ }
443
+ };
444
+
445
+ // packages/di/src/interfaces/factory.interface.mts
446
+ var import_zod3 = require("zod");
447
+
448
+ // packages/di/src/event-emitter.mts
449
+ var EventEmitter = class {
450
+ listeners = /* @__PURE__ */ new Map();
451
+ on(event, listener) {
452
+ if (!this.listeners.has(event)) {
453
+ this.listeners.set(event, /* @__PURE__ */ new Set());
454
+ }
455
+ this.listeners.get(event).add(listener);
456
+ return () => {
457
+ this.off(event, listener);
458
+ };
459
+ }
460
+ off(event, listener) {
461
+ if (!this.listeners.has(event)) {
462
+ return;
463
+ }
464
+ this.listeners.get(event).delete(listener);
465
+ if (this.listeners.get(event).size === 0) {
466
+ this.listeners.delete(event);
467
+ }
468
+ }
469
+ once(event, listener) {
470
+ const off = this.on(event, (...args) => {
471
+ off();
472
+ listener(...args);
473
+ });
474
+ return off;
475
+ }
476
+ async emit(event, ...args) {
477
+ if (!this.listeners.has(event)) {
478
+ return;
479
+ }
480
+ return Promise.all(Array.from(this.listeners.get(event)).map((listener) => listener(...args)));
481
+ }
482
+ addChannel(ns, event, target) {
483
+ return this.on(event, (...args) => target.emit(ns, event, ...args));
484
+ }
485
+ };
486
+
487
+ // packages/di/src/service-locator-event-bus.mts
488
+ var ServiceLocatorEventBus = class {
489
+ constructor(logger = null) {
490
+ this.logger = logger;
491
+ }
492
+ listeners = /* @__PURE__ */ new Map();
493
+ on(ns, event, listener) {
494
+ var _a;
495
+ (_a = this.logger) == null ? void 0 : _a.debug(`[ServiceLocatorEventBus]#on(): ns:${ns} event:${event}`);
496
+ if (!this.listeners.has(ns)) {
497
+ this.listeners.set(ns, /* @__PURE__ */ new Map());
498
+ }
499
+ const nsEvents = this.listeners.get(ns);
500
+ if (!nsEvents.has(event)) {
501
+ nsEvents.set(event, /* @__PURE__ */ new Set());
502
+ }
503
+ nsEvents.get(event).add(listener);
504
+ return () => {
505
+ var _a2;
506
+ nsEvents.get(event).delete(listener);
507
+ if (((_a2 = nsEvents.get(event)) == null ? void 0 : _a2.size) === 0) {
508
+ nsEvents.delete(event);
509
+ }
510
+ if (nsEvents.size === 0) {
511
+ this.listeners.delete(ns);
512
+ }
513
+ };
514
+ }
515
+ async emit(key, event) {
516
+ var _a, _b, _c;
517
+ if (!this.listeners.has(key)) {
518
+ return;
519
+ }
520
+ const events = this.listeners.get(key);
521
+ const preEvent = `pre:${event}`;
522
+ const postEvent = `post:${event}`;
523
+ (_a = this.logger) == null ? void 0 : _a.debug(`[ServiceLocatorEventBus]#emit(): ${key}:${preEvent}`);
524
+ await Promise.allSettled(
525
+ [...events.get(preEvent) ?? []].map((listener) => listener(preEvent))
526
+ ).then((results) => {
527
+ results.filter((result) => result.status === "rejected").forEach((result) => {
528
+ var _a2;
529
+ (_a2 = this.logger) == null ? void 0 : _a2.warn(
530
+ `[ServiceLocatorEventBus]#emit(): ${key}:${preEvent} rejected with`,
531
+ result.reason
532
+ );
533
+ });
534
+ });
535
+ (_b = this.logger) == null ? void 0 : _b.debug(`[ServiceLocatorEventBus]#emit(): ${key}:${event}`);
536
+ const res = await Promise.allSettled(
537
+ [...events.get(event) ?? []].map((listener) => listener(event))
538
+ ).then((results) => {
539
+ const res2 = results.filter((result) => result.status === "rejected").map((result) => {
540
+ var _a2;
541
+ (_a2 = this.logger) == null ? void 0 : _a2.warn(
542
+ `[ServiceLocatorEventBus]#emit(): ${key}:${event} rejected with`,
543
+ result.reason
544
+ );
545
+ return result;
546
+ });
547
+ if (res2.length > 0) {
548
+ return Promise.reject(res2);
549
+ }
550
+ return results;
551
+ });
552
+ (_c = this.logger) == null ? void 0 : _c.debug(`[ServiceLocatorEventBus]#emit(): ${key}:${postEvent}`);
553
+ await Promise.allSettled(
554
+ [...events.get(postEvent) ?? []].map((listener) => listener(postEvent))
555
+ ).then((results) => {
556
+ results.filter((result) => result.status === "rejected").forEach((result) => {
557
+ var _a2;
558
+ (_a2 = this.logger) == null ? void 0 : _a2.warn(
559
+ `[ServiceLocatorEventBus]#emit(): ${key}:${postEvent} rejected with`,
560
+ result.reason
561
+ );
562
+ });
563
+ });
564
+ return res;
565
+ }
566
+ };
567
+
568
+ // packages/di/src/service-locator-instance-holder.mts
569
+ var ServiceLocatorInstanceHolderKind = /* @__PURE__ */ ((ServiceLocatorInstanceHolderKind2) => {
570
+ ServiceLocatorInstanceHolderKind2["Instance"] = "instance";
571
+ ServiceLocatorInstanceHolderKind2["Factory"] = "factory";
572
+ ServiceLocatorInstanceHolderKind2["AbstractFactory"] = "abstractFactory";
573
+ return ServiceLocatorInstanceHolderKind2;
574
+ })(ServiceLocatorInstanceHolderKind || {});
575
+ var ServiceLocatorInstanceHolderStatus = /* @__PURE__ */ ((ServiceLocatorInstanceHolderStatus2) => {
576
+ ServiceLocatorInstanceHolderStatus2["Created"] = "created";
577
+ ServiceLocatorInstanceHolderStatus2["Creating"] = "creating";
578
+ ServiceLocatorInstanceHolderStatus2["Destroying"] = "destroying";
579
+ return ServiceLocatorInstanceHolderStatus2;
580
+ })(ServiceLocatorInstanceHolderStatus || {});
581
+
582
+ // packages/di/src/service-locator-manager.mts
583
+ var ServiceLocatorManager = class {
584
+ constructor(logger = null) {
585
+ this.logger = logger;
586
+ }
587
+ instancesHolders = /* @__PURE__ */ new Map();
588
+ get(name) {
589
+ var _a, _b, _c;
590
+ const holder = this.instancesHolders.get(name);
591
+ if (holder) {
592
+ if (holder.ttl !== Infinity) {
593
+ const now = Date.now();
594
+ if (now - holder.createdAt > holder.ttl) {
595
+ (_a = this.logger) == null ? void 0 : _a.log(
596
+ `[ServiceLocatorManager]#getInstanceHolder() TTL expired for ${holder.name}`
597
+ );
598
+ return [new InstanceExpired(holder.name), holder];
599
+ }
600
+ } else if (holder.status === "destroying" /* Destroying */) {
601
+ (_b = this.logger) == null ? void 0 : _b.log(
602
+ `[ServiceLocatorManager]#getInstanceHolder() Instance ${holder.name} is destroying`
603
+ );
604
+ return [new InstanceDestroying(holder.name), holder];
605
+ }
606
+ return [void 0, holder];
607
+ } else {
608
+ (_c = this.logger) == null ? void 0 : _c.log(
609
+ `[ServiceLocatorManager]#getInstanceHolder() Instance ${name} not found`
610
+ );
611
+ return [new InstanceNotFound(name)];
612
+ }
613
+ }
614
+ set(name, holder) {
615
+ this.instancesHolders.set(name, holder);
616
+ }
617
+ has(name) {
618
+ const [error, holder] = this.get(name);
619
+ if (!error) {
620
+ return [void 0, true];
621
+ }
622
+ if (["InstanceExpired" /* InstanceExpired */, "InstanceDestroying" /* InstanceDestroying */].includes(
623
+ error.code
624
+ )) {
625
+ return [error];
626
+ }
627
+ return [void 0, !!holder];
628
+ }
629
+ delete(name) {
630
+ return this.instancesHolders.delete(name);
631
+ }
632
+ filter(predicate) {
633
+ return new Map(
634
+ [...this.instancesHolders].filter(
635
+ ([key, value]) => predicate(value, key)
636
+ )
637
+ );
638
+ }
639
+ };
640
+
641
+ // packages/di/src/service-locator.mts
642
+ var ServiceLocator = class {
643
+ constructor(registry = globalRegistry, logger = null) {
644
+ this.registry = registry;
645
+ this.logger = logger;
646
+ this.eventBus = new ServiceLocatorEventBus(logger);
647
+ this.manager = new ServiceLocatorManager(logger);
648
+ }
649
+ eventBus;
650
+ manager;
651
+ getEventBus() {
652
+ return this.eventBus;
653
+ }
654
+ storeInstance(instance, token, args) {
655
+ const instanceName = this.getInstanceIdentifier(token, args);
656
+ this.manager.set(instanceName, {
657
+ name: instanceName,
658
+ instance,
659
+ status: "created" /* Created */,
660
+ kind: "instance" /* Instance */,
661
+ createdAt: Date.now(),
662
+ ttl: Infinity,
663
+ deps: [],
664
+ destroyListeners: [],
665
+ effects: [],
666
+ destroyPromise: null,
667
+ creationPromise: null
668
+ });
669
+ this.notifyListeners(instanceName);
670
+ }
671
+ removeInstance(token, args) {
672
+ const instanceName = this.getInstanceIdentifier(token, args);
673
+ return this.invalidate(instanceName);
674
+ }
675
+ resolveTokenArgs(token, args) {
676
+ var _a, _b;
677
+ let realArgs = args;
678
+ if (token instanceof BoundInjectionToken) {
679
+ realArgs = token.value;
680
+ } else if (token instanceof FactoryInjectionToken) {
681
+ if (token.resolved) {
682
+ realArgs = token.value;
683
+ } else {
684
+ return [new FactoryTokenNotResolved(token.name)];
685
+ }
686
+ }
687
+ if (!token.schema) {
688
+ return [void 0, realArgs];
689
+ }
690
+ const validatedArgs = (_a = token.schema) == null ? void 0 : _a.safeParse(realArgs);
691
+ if (validatedArgs && !validatedArgs.success) {
692
+ (_b = this.logger) == null ? void 0 : _b.error(
693
+ `[ServiceLocator]#getInstance(): Error validating args for ${token.name.toString()}`,
694
+ validatedArgs.error
695
+ );
696
+ return [new UnknownError(validatedArgs.error)];
697
+ }
698
+ return [void 0, validatedArgs == null ? void 0 : validatedArgs.data];
699
+ }
700
+ getInstanceIdentifier(token, args) {
701
+ const [err, realArgs] = this.resolveTokenArgs(
702
+ token,
703
+ args
704
+ );
705
+ if (err) {
706
+ throw err;
707
+ }
708
+ return this.makeInstanceName(token, realArgs);
709
+ }
710
+ async getInstance(token, args) {
711
+ var _a, _b;
712
+ const [err, realArgs] = this.resolveTokenArgs(token, args);
713
+ if (err instanceof UnknownError) {
714
+ return [err];
715
+ } else if (err instanceof FactoryTokenNotResolved && token instanceof FactoryInjectionToken) {
716
+ await token.resolve();
717
+ return this.getInstance(token, args);
718
+ }
719
+ const instanceName = this.makeInstanceName(token, realArgs);
720
+ const [error, holder] = this.manager.get(instanceName);
721
+ if (!error) {
722
+ if (holder.status === "creating" /* Creating */) {
723
+ return holder.creationPromise;
724
+ } else if (holder.status === "destroying" /* Destroying */) {
725
+ return [new UnknownError("InstanceDestroying" /* InstanceDestroying */)];
726
+ }
727
+ return [void 0, holder.instance];
728
+ }
729
+ switch (error.code) {
730
+ case "InstanceDestroying" /* InstanceDestroying */:
731
+ (_a = this.logger) == null ? void 0 : _a.log(
732
+ `[ServiceLocator]#getInstance() TTL expired for ${holder == null ? void 0 : holder.name}`
733
+ );
734
+ await (holder == null ? void 0 : holder.destroyPromise);
735
+ return this.getInstance(token, args);
736
+ case "InstanceExpired" /* InstanceExpired */:
737
+ (_b = this.logger) == null ? void 0 : _b.log(
738
+ `[ServiceLocator]#getInstance() TTL expired for ${holder == null ? void 0 : holder.name}`
739
+ );
740
+ await this.invalidate(instanceName);
741
+ return this.getInstance(token, args);
742
+ case "InstanceNotFound" /* InstanceNotFound */:
743
+ break;
744
+ default:
745
+ return [error];
746
+ }
747
+ return this.createInstance(instanceName, token, realArgs);
748
+ }
749
+ async getOrThrowInstance(token, args) {
750
+ const [error, instance] = await this.getInstance(token, args);
751
+ if (error) {
752
+ throw error;
753
+ }
754
+ return instance;
755
+ }
756
+ notifyListeners(name, event = "create") {
757
+ var _a;
758
+ (_a = this.logger) == null ? void 0 : _a.log(
759
+ `[ServiceLocator]#notifyListeners() Notifying listeners for ${name} with event ${event}`
760
+ );
761
+ return this.eventBus.emit(name, event);
762
+ }
763
+ async createInstance(instanceName, token, args) {
764
+ var _a;
765
+ (_a = this.logger) == null ? void 0 : _a.log(
766
+ `[ServiceLocator]#createInstance() Creating instance for ${instanceName}`
767
+ );
768
+ let realToken = token instanceof BoundInjectionToken || token instanceof FactoryInjectionToken ? token.token : token;
769
+ if (this.registry.has(realToken)) {
770
+ return this.resolveInstance(instanceName, realToken, args);
771
+ } else {
772
+ return [new FactoryNotFound(realToken.name.toString())];
773
+ }
774
+ }
775
+ async resolveInstance(instanceName, token, args) {
776
+ var _a;
777
+ (_a = this.logger) == null ? void 0 : _a.log(
778
+ `[ServiceLocator]#resolveInstance(): Creating instance for ${instanceName} from abstract factory`
779
+ );
780
+ const ctx = this.createFactoryContext(instanceName);
781
+ let { factory, scope } = this.registry.get(token);
782
+ const holder = {
783
+ name: instanceName,
784
+ instance: null,
785
+ status: "creating" /* Creating */,
786
+ kind: "abstractFactory" /* AbstractFactory */,
787
+ // @ts-expect-error TS2322 This is correct type
788
+ creationPromise: factory(ctx, args).then(async (instance) => {
789
+ var _a2;
790
+ holder.instance = instance;
791
+ holder.status = "created" /* Created */;
792
+ holder.deps = ctx.getDependencies();
793
+ holder.destroyListeners = ctx.getDestroyListeners();
794
+ holder.ttl = ctx.getTtl();
795
+ if (holder.deps.length > 0) {
796
+ (_a2 = this.logger) == null ? void 0 : _a2.log(
797
+ `[ServiceLocator]#createInstanceFromAbstractFactory(): Adding subscriptions for ${instanceName} dependencies for their invalidations: ${holder.deps.join(
798
+ ", "
799
+ )}`
800
+ );
801
+ holder.deps.forEach((dependency) => {
802
+ holder.destroyListeners.push(
803
+ this.eventBus.on(
804
+ dependency,
805
+ "destroy",
806
+ () => this.invalidate(instanceName)
807
+ )
808
+ );
809
+ });
810
+ }
811
+ if (holder.ttl === 0 || scope === "Instance" /* Instance */) {
812
+ await this.invalidate(instanceName);
813
+ }
814
+ await this.notifyListeners(instanceName);
815
+ return [void 0, instance];
816
+ }).catch((error) => {
817
+ var _a2;
818
+ (_a2 = this.logger) == null ? void 0 : _a2.error(
819
+ `[ServiceLocator]#createInstanceFromAbstractFactory(): Error creating instance for ${instanceName}`,
820
+ error
821
+ );
822
+ return [new UnknownError(error)];
823
+ }),
824
+ effects: [],
825
+ deps: [],
826
+ destroyListeners: [],
827
+ createdAt: Date.now(),
828
+ ttl: Infinity
829
+ };
830
+ if (scope === "Singleton" /* Singleton */) {
831
+ this.manager.set(instanceName, holder);
832
+ }
833
+ return holder.creationPromise;
834
+ }
835
+ createFactoryContext(instanceName) {
836
+ const dependencies = /* @__PURE__ */ new Set();
837
+ const destroyListeners = /* @__PURE__ */ new Set();
838
+ const self = this;
839
+ function invalidate(name = instanceName) {
840
+ return self.invalidate(name);
841
+ }
842
+ function addEffect(listener) {
843
+ destroyListeners.add(listener);
844
+ }
845
+ let ttl = Infinity;
846
+ function setTtl(value) {
847
+ ttl = value;
848
+ }
849
+ function getTtl() {
850
+ return ttl;
851
+ }
852
+ function on(key, event, listener) {
853
+ destroyListeners.add(self.eventBus.on(key, event, listener));
854
+ }
855
+ return {
856
+ // @ts-expect-error This is correct type
857
+ async inject(token, args) {
858
+ let injectionToken = token;
859
+ if (typeof token === "function") {
860
+ injectionToken = getInjectableToken(token);
861
+ }
862
+ if (injectionToken instanceof InjectionToken) {
863
+ const validatedArgs = token.schema ? token.schema.safeParse(args) : void 0;
864
+ const instanceName2 = self.makeInstanceName(token, validatedArgs);
865
+ dependencies.add(instanceName2);
866
+ return self.getOrThrowInstance(injectionToken, args);
867
+ }
868
+ throw new Error(
869
+ `[ServiceLocator]#inject(): Invalid token type: ${typeof token}. Expected a class or an InjectionToken.`
870
+ );
871
+ },
872
+ invalidate,
873
+ on,
874
+ getDependencies: () => Array.from(dependencies),
875
+ addEffect,
876
+ getDestroyListeners: () => Array.from(destroyListeners),
877
+ setTtl,
878
+ getTtl,
879
+ locator: self
880
+ };
881
+ }
882
+ getSyncInstance(token, args) {
883
+ const [err, realArgs] = this.resolveTokenArgs(token, args);
884
+ if (err) {
885
+ return null;
886
+ }
887
+ const instanceName = this.makeInstanceName(token, realArgs);
888
+ const [error, holder] = this.manager.get(instanceName);
889
+ if (error) {
890
+ return null;
891
+ }
892
+ return holder.instance;
893
+ }
894
+ invalidate(service, round = 1) {
895
+ var _a, _b, _c, _d, _e;
896
+ (_a = this.logger) == null ? void 0 : _a.log(
897
+ `[ServiceLocator]#invalidate(): Starting Invalidating process of ${service}`
898
+ );
899
+ const toInvalidate = this.manager.filter(
900
+ (holder) => holder.name === service || holder.deps.includes(service)
901
+ );
902
+ const promises = [];
903
+ for (const [key, holder] of toInvalidate.entries()) {
904
+ if (holder.status === "destroying" /* Destroying */) {
905
+ (_b = this.logger) == null ? void 0 : _b.trace(
906
+ `[ServiceLocator]#invalidate(): ${key} is already being destroyed`
907
+ );
908
+ promises.push(holder.destroyPromise);
909
+ continue;
910
+ }
911
+ if (holder.status === "creating" /* Creating */) {
912
+ (_c = this.logger) == null ? void 0 : _c.trace(
913
+ `[ServiceLocator]#invalidate(): ${key} is being created, waiting for creation to finish`
914
+ );
915
+ promises.push(
916
+ (_d = holder.creationPromise) == null ? void 0 : _d.then(() => {
917
+ var _a2;
918
+ if (round > 3) {
919
+ (_a2 = this.logger) == null ? void 0 : _a2.error(
920
+ `[ServiceLocator]#invalidate(): ${key} creation is triggering a new invalidation round, but it is still not created`
921
+ );
922
+ return;
923
+ }
924
+ return this.invalidate(key, round + 1);
925
+ })
926
+ );
927
+ continue;
928
+ }
929
+ holder.status = "destroying" /* Destroying */;
930
+ (_e = this.logger) == null ? void 0 : _e.log(
931
+ `[ServiceLocator]#invalidate(): Invalidating ${key} and notifying listeners`
932
+ );
933
+ holder.destroyPromise = Promise.all(
934
+ holder.destroyListeners.map((listener) => listener())
935
+ ).then(async () => {
936
+ this.manager.delete(key);
937
+ await this.notifyListeners(key, "destroy");
938
+ });
939
+ promises.push(holder.destroyPromise);
940
+ }
941
+ return Promise.all(promises);
942
+ }
943
+ async ready() {
944
+ return Promise.all(
945
+ Array.from(this.manager.filter(() => true)).map(([, holder]) => {
946
+ var _a;
947
+ if (holder.status === "creating" /* Creating */) {
948
+ return (_a = holder.creationPromise) == null ? void 0 : _a.then(() => null);
949
+ }
950
+ if (holder.status === "destroying" /* Destroying */) {
951
+ return holder.destroyPromise.then(() => null);
952
+ }
953
+ return Promise.resolve(null);
954
+ })
955
+ ).then(() => null);
956
+ }
957
+ makeInstanceName(token, args) {
958
+ const formattedArgs = args ? ":" + JSON.stringify(args, (_, value) => {
959
+ if (typeof value === "function") {
960
+ return `function:${value.name}(${value.length})`;
961
+ }
962
+ if (typeof value === "symbol") {
963
+ return value.toString();
964
+ }
965
+ return value;
966
+ }).replaceAll(/"/g, "").replaceAll(/:/g, "=").replaceAll(/,/g, "|") : "";
967
+ return `${token.toString()}${formattedArgs}`;
968
+ }
969
+ };
970
+
971
+ // packages/di/src/injector.mts
972
+ var globalServiceLocator = new ServiceLocator();
973
+ function getGlobalServiceLocator() {
974
+ if (!globalServiceLocator) {
975
+ throw new Error(
976
+ "[ServiceLocator] Service locator is not initialized. Please provide the service locator before using the @Injectable decorator."
977
+ );
978
+ }
979
+ return globalServiceLocator;
980
+ }
981
+ var { inject, syncInject, wrapSyncInit, provideServiceLocator } = getInjectors({
982
+ baseLocator: globalServiceLocator
983
+ });
984
+ // Annotate the CommonJS export names for ESM import in node:
985
+ 0 && (module.exports = {
986
+ BoundInjectionToken,
987
+ ErrorsEnum,
988
+ EventEmitter,
989
+ FactoryInjectionToken,
990
+ FactoryNotFound,
991
+ FactoryTokenNotResolved,
992
+ Injectable,
993
+ InjectableScope,
994
+ InjectableTokenMeta,
995
+ InjectableType,
996
+ InjectionToken,
997
+ InjectorsBase,
998
+ InstanceDestroying,
999
+ InstanceExpired,
1000
+ InstanceNotFound,
1001
+ ProxyServiceLocator,
1002
+ Registry,
1003
+ ServiceLocator,
1004
+ ServiceLocatorEventBus,
1005
+ ServiceLocatorInstanceHolderKind,
1006
+ ServiceLocatorInstanceHolderStatus,
1007
+ ServiceLocatorManager,
1008
+ UnknownError,
1009
+ getGlobalServiceLocator,
1010
+ getInjectableToken,
1011
+ getInjectors,
1012
+ globalRegistry,
1013
+ inject,
1014
+ makeProxyServiceLocator,
1015
+ provideServiceLocator,
1016
+ resolveService,
1017
+ syncInject,
1018
+ wrapSyncInit
1019
+ });