@navios/di 0.1.10 → 0.1.12

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