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