@navios/di 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +211 -1
  2. package/coverage/clover.xml +1912 -1277
  3. package/coverage/coverage-final.json +37 -28
  4. package/coverage/docs/examples/basic-usage.mts.html +1 -1
  5. package/coverage/docs/examples/factory-pattern.mts.html +1 -1
  6. package/coverage/docs/examples/index.html +1 -1
  7. package/coverage/docs/examples/injection-tokens.mts.html +1 -1
  8. package/coverage/docs/examples/request-scope-example.mts.html +1 -1
  9. package/coverage/docs/examples/service-lifecycle.mts.html +1 -1
  10. package/coverage/index.html +71 -41
  11. package/coverage/lib/_tsup-dts-rollup.d.mts.html +682 -43
  12. package/coverage/lib/index.d.mts.html +7 -4
  13. package/coverage/lib/index.html +5 -5
  14. package/coverage/lib/testing/index.d.mts.html +91 -0
  15. package/coverage/lib/testing/index.html +116 -0
  16. package/coverage/src/base-instance-holder-manager.mts.html +589 -0
  17. package/coverage/src/container.mts.html +257 -74
  18. package/coverage/src/decorators/factory.decorator.mts.html +1 -1
  19. package/coverage/src/decorators/index.html +1 -1
  20. package/coverage/src/decorators/index.mts.html +1 -1
  21. package/coverage/src/decorators/injectable.decorator.mts.html +20 -20
  22. package/coverage/src/enums/index.html +1 -1
  23. package/coverage/src/enums/index.mts.html +1 -1
  24. package/coverage/src/enums/injectable-scope.enum.mts.html +1 -1
  25. package/coverage/src/enums/injectable-type.enum.mts.html +1 -1
  26. package/coverage/src/errors/di-error.mts.html +292 -0
  27. package/coverage/src/errors/errors.enum.mts.html +30 -21
  28. package/coverage/src/errors/factory-not-found.mts.html +31 -22
  29. package/coverage/src/errors/factory-token-not-resolved.mts.html +29 -26
  30. package/coverage/src/errors/index.html +56 -41
  31. package/coverage/src/errors/index.mts.html +15 -9
  32. package/coverage/src/errors/instance-destroying.mts.html +31 -22
  33. package/coverage/src/errors/instance-expired.mts.html +31 -22
  34. package/coverage/src/errors/instance-not-found.mts.html +31 -22
  35. package/coverage/src/errors/unknown-error.mts.html +31 -43
  36. package/coverage/src/event-emitter.mts.html +14 -14
  37. package/coverage/src/factory-context.mts.html +1 -1
  38. package/coverage/src/index.html +121 -46
  39. package/coverage/src/index.mts.html +7 -4
  40. package/coverage/src/injection-token.mts.html +28 -28
  41. package/coverage/src/injector.mts.html +1 -1
  42. package/coverage/src/instance-resolver.mts.html +1762 -0
  43. package/coverage/src/interfaces/factory.interface.mts.html +1 -1
  44. package/coverage/src/interfaces/index.html +1 -1
  45. package/coverage/src/interfaces/index.mts.html +1 -1
  46. package/coverage/src/interfaces/on-service-destroy.interface.mts.html +1 -1
  47. package/coverage/src/interfaces/on-service-init.interface.mts.html +1 -1
  48. package/coverage/src/registry.mts.html +28 -28
  49. package/coverage/src/request-context-holder.mts.html +183 -102
  50. package/coverage/src/request-context-manager.mts.html +532 -0
  51. package/coverage/src/service-instantiator.mts.html +49 -49
  52. package/coverage/src/service-invalidator.mts.html +1372 -0
  53. package/coverage/src/service-locator-event-bus.mts.html +48 -48
  54. package/coverage/src/service-locator-instance-holder.mts.html +2 -14
  55. package/coverage/src/service-locator-manager.mts.html +71 -335
  56. package/coverage/src/service-locator.mts.html +240 -2328
  57. package/coverage/src/symbols/index.html +1 -1
  58. package/coverage/src/symbols/index.mts.html +1 -1
  59. package/coverage/src/symbols/injectable-token.mts.html +1 -1
  60. package/coverage/src/testing/index.html +131 -0
  61. package/coverage/src/testing/index.mts.html +88 -0
  62. package/coverage/src/testing/test-container.mts.html +445 -0
  63. package/coverage/src/token-processor.mts.html +607 -0
  64. package/coverage/src/utils/defer.mts.html +28 -214
  65. package/coverage/src/utils/get-injectable-token.mts.html +7 -7
  66. package/coverage/src/utils/get-injectors.mts.html +99 -99
  67. package/coverage/src/utils/index.html +15 -15
  68. package/coverage/src/utils/index.mts.html +4 -7
  69. package/coverage/src/utils/types.mts.html +1 -1
  70. package/docs/injectable.md +51 -11
  71. package/docs/scopes.md +63 -29
  72. package/lib/_tsup-dts-rollup.d.mts +447 -212
  73. package/lib/_tsup-dts-rollup.d.ts +447 -212
  74. package/lib/chunk-44F3LXW5.mjs +2043 -0
  75. package/lib/chunk-44F3LXW5.mjs.map +1 -0
  76. package/lib/index.d.mts +6 -4
  77. package/lib/index.d.ts +6 -4
  78. package/lib/index.js +1199 -773
  79. package/lib/index.js.map +1 -1
  80. package/lib/index.mjs +4 -1599
  81. package/lib/index.mjs.map +1 -1
  82. package/lib/testing/index.d.mts +2 -0
  83. package/lib/testing/index.d.ts +2 -0
  84. package/lib/testing/index.js +2060 -0
  85. package/lib/testing/index.js.map +1 -0
  86. package/lib/testing/index.mjs +73 -0
  87. package/lib/testing/index.mjs.map +1 -0
  88. package/package.json +11 -1
  89. package/src/__tests__/container.spec.mts +47 -13
  90. package/src/__tests__/errors.spec.mts +53 -27
  91. package/src/__tests__/injectable.spec.mts +73 -0
  92. package/src/__tests__/request-scope.spec.mts +0 -2
  93. package/src/__tests__/service-locator-manager.spec.mts +12 -82
  94. package/src/__tests__/service-locator.spec.mts +1009 -1
  95. package/src/__type-tests__/inject.spec-d.mts +30 -7
  96. package/src/__type-tests__/injectable.spec-d.mts +76 -37
  97. package/src/base-instance-holder-manager.mts +2 -9
  98. package/src/container.mts +70 -10
  99. package/src/decorators/injectable.decorator.mts +29 -5
  100. package/src/errors/di-error.mts +69 -0
  101. package/src/errors/index.mts +9 -7
  102. package/src/injection-token.mts +1 -0
  103. package/src/injector.mts +2 -0
  104. package/src/instance-resolver.mts +559 -0
  105. package/src/request-context-holder.mts +0 -2
  106. package/src/request-context-manager.mts +149 -0
  107. package/src/service-invalidator.mts +429 -0
  108. package/src/service-locator-instance-holder.mts +0 -4
  109. package/src/service-locator-manager.mts +10 -40
  110. package/src/service-locator.mts +86 -782
  111. package/src/testing/README.md +80 -0
  112. package/src/testing/__tests__/test-container.spec.mts +173 -0
  113. package/src/testing/index.mts +1 -0
  114. package/src/testing/test-container.mts +120 -0
  115. package/src/token-processor.mts +174 -0
  116. package/src/utils/get-injectors.mts +161 -24
  117. package/src/utils/index.mts +0 -1
  118. package/src/utils/types.mts +12 -8
  119. package/tsup.config.mts +1 -1
  120. package/src/__tests__/defer.spec.mts +0 -166
  121. package/src/errors/errors.enum.mts +0 -8
  122. package/src/errors/factory-not-found.mts +0 -8
  123. package/src/errors/factory-token-not-resolved.mts +0 -10
  124. package/src/errors/instance-destroying.mts +0 -8
  125. package/src/errors/instance-expired.mts +0 -8
  126. package/src/errors/instance-not-found.mts +0 -8
  127. package/src/errors/unknown-error.mts +0 -15
  128. package/src/utils/defer.mts +0 -73
package/lib/index.mjs CHANGED
@@ -1,162 +1,5 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
5
- var __typeError = (msg) => {
6
- throw TypeError(msg);
7
- };
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
- var __decoratorStart = (base) => [, , , __create(null)];
11
- var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
12
- var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
13
- var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
14
- var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
15
- var __runInitializers = (array, flags, self, value) => {
16
- for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) fns[i].call(self) ;
17
- return value;
18
- };
19
- var __decorateElement = (array, flags, name, decorators, target, extra) => {
20
- var it, done, ctx, k = flags & 7, p = false;
21
- var j = 0;
22
- var extraInitializers = array[j] || (array[j] = []);
23
- var desc = k && ((target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(target , name));
24
- __name(target, name);
25
- for (var i = decorators.length - 1; i >= 0; i--) {
26
- ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
27
- it = (0, decorators[i])(target, ctx), done._ = 1;
28
- __expectFn(it) && (target = it);
29
- }
30
- return __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
31
- };
32
-
33
- // src/enums/injectable-scope.enum.mts
34
- var InjectableScope = /* @__PURE__ */ ((InjectableScope5) => {
35
- InjectableScope5["Singleton"] = "Singleton";
36
- InjectableScope5["Transient"] = "Transient";
37
- InjectableScope5["Request"] = "Request";
38
- return InjectableScope5;
39
- })(InjectableScope || {});
40
-
41
- // src/enums/injectable-type.enum.mts
42
- var InjectableType = /* @__PURE__ */ ((InjectableType5) => {
43
- InjectableType5["Class"] = "Class";
44
- InjectableType5["Factory"] = "Factory";
45
- return InjectableType5;
46
- })(InjectableType || {});
47
-
48
- // src/injection-token.mts
49
- var InjectionToken = class _InjectionToken {
50
- constructor(name, schema) {
51
- this.name = name;
52
- this.schema = schema;
53
- }
54
- id = globalThis.crypto.randomUUID();
55
- formattedName = null;
56
- static create(name, schema) {
57
- return new _InjectionToken(name, schema);
58
- }
59
- static bound(token, value) {
60
- return new BoundInjectionToken(token, value);
61
- }
62
- static factory(token, factory) {
63
- return new FactoryInjectionToken(token, factory);
64
- }
65
- static refineType(token) {
66
- return token;
67
- }
68
- toString() {
69
- if (this.formattedName) {
70
- return this.formattedName;
71
- }
72
- const { name } = this;
73
- if (typeof name === "function") {
74
- const className = name.name;
75
- this.formattedName = `${className}(${this.id})`;
76
- } else if (typeof name === "symbol") {
77
- this.formattedName = `${name.toString()}(${this.id})`;
78
- } else {
79
- this.formattedName = `${name}(${this.id})`;
80
- }
81
- return this.formattedName;
82
- }
83
- };
84
- var BoundInjectionToken = class {
85
- constructor(token, value) {
86
- this.token = token;
87
- this.value = value;
88
- this.name = token.name;
89
- this.id = token.id;
90
- this.schema = token.schema;
91
- }
92
- id;
93
- name;
94
- schema;
95
- toString() {
96
- return this.token.toString();
97
- }
98
- };
99
- var FactoryInjectionToken = class {
100
- constructor(token, factory) {
101
- this.token = token;
102
- this.factory = factory;
103
- this.name = token.name;
104
- this.id = token.id;
105
- this.schema = token.schema;
106
- }
107
- value;
108
- resolved = false;
109
- id;
110
- name;
111
- schema;
112
- async resolve(ctx) {
113
- if (!this.value) {
114
- this.value = await this.factory(ctx);
115
- this.resolved = true;
116
- }
117
- return this.value;
118
- }
119
- toString() {
120
- return this.token.toString();
121
- }
122
- };
123
-
124
- // src/registry.mts
125
- var Registry = class {
126
- constructor(parent) {
127
- this.parent = parent;
128
- }
129
- factories = /* @__PURE__ */ new Map();
130
- has(token) {
131
- if (this.factories.has(token.id)) {
132
- return true;
133
- }
134
- if (this.parent) {
135
- return this.parent.has(token);
136
- }
137
- return false;
138
- }
139
- get(token) {
140
- const factory = this.factories.get(token.id);
141
- if (!factory) {
142
- if (this.parent) {
143
- return this.parent.get(token);
144
- }
145
- throw new Error(`[Registry] No factory found for ${token.toString()}`);
146
- }
147
- return factory;
148
- }
149
- set(token, scope, target, type) {
150
- this.factories.set(token.id, { scope, originalToken: token, target, type });
151
- }
152
- delete(token) {
153
- this.factories.delete(token.id);
154
- }
155
- };
156
- var globalRegistry = new Registry();
157
-
158
- // src/symbols/injectable-token.mts
159
- var InjectableTokenMeta = Symbol.for("InjectableTokenMeta");
1
+ import { Injectable, __decoratorStart, __decorateElement, __runInitializers, InjectionToken, globalRegistry, InjectableTokenMeta } from './chunk-44F3LXW5.mjs';
2
+ export { BaseInstanceHolderManager, BoundInjectionToken, Container, DIError, DIErrorCode, DefaultRequestContextHolder, DIErrorCode as ErrorsEnum, FactoryInjectionToken, DIError as FactoryNotFound, DIError as FactoryTokenNotResolved, Injectable, InjectableScope, InjectableTokenMeta, InjectableType, InjectionToken, DIError as InstanceDestroying, DIError as InstanceNotFound, Registry, ServiceInstantiator, ServiceLocator, ServiceLocatorEventBus, ServiceLocatorInstanceHolderStatus, ServiceLocatorManager, DIError as UnknownError, asyncInject, createRequestContextHolder, defaultInjectors, getInjectableToken, getInjectors, globalRegistry, inject, optional, provideFactoryContext, wrapSyncInit } from './chunk-44F3LXW5.mjs';
160
3
 
161
4
  // src/decorators/factory.decorator.mts
162
5
  function Factory({
@@ -176,392 +19,6 @@ function Factory({
176
19
  return target;
177
20
  };
178
21
  }
179
- function Injectable({
180
- scope = "Singleton" /* Singleton */,
181
- token,
182
- registry = globalRegistry
183
- } = {}) {
184
- return (target, context) => {
185
- if (context && context.kind !== "class" || target instanceof Function && !context) {
186
- throw new Error(
187
- "[ServiceLocator] @Injectable decorator can only be used on classes."
188
- );
189
- }
190
- let injectableToken = token ?? InjectionToken.create(target);
191
- registry.set(injectableToken, scope, target, "Class" /* Class */);
192
- target[InjectableTokenMeta] = injectableToken;
193
- return target;
194
- };
195
- }
196
-
197
- // src/errors/errors.enum.mts
198
- var ErrorsEnum = /* @__PURE__ */ ((ErrorsEnum2) => {
199
- ErrorsEnum2["InstanceExpired"] = "InstanceExpired";
200
- ErrorsEnum2["InstanceNotFound"] = "InstanceNotFound";
201
- ErrorsEnum2["InstanceDestroying"] = "InstanceDestroying";
202
- ErrorsEnum2["UnknownError"] = "UnknownError";
203
- ErrorsEnum2["FactoryNotFound"] = "FactoryNotFound";
204
- ErrorsEnum2["FactoryTokenNotResolved"] = "FactoryTokenNotResolved";
205
- return ErrorsEnum2;
206
- })(ErrorsEnum || {});
207
-
208
- // src/errors/factory-not-found.mts
209
- var FactoryNotFound = class extends Error {
210
- constructor(name) {
211
- super(`Factory ${name} not found`);
212
- this.name = name;
213
- }
214
- code = "FactoryNotFound" /* FactoryNotFound */;
215
- };
216
-
217
- // src/errors/factory-token-not-resolved.mts
218
- var FactoryTokenNotResolved = class extends Error {
219
- code = "FactoryTokenNotResolved" /* FactoryTokenNotResolved */;
220
- constructor(name) {
221
- super(`Factory token not resolved: ${name.toString()}`);
222
- }
223
- };
224
-
225
- // src/errors/instance-destroying.mts
226
- var InstanceDestroying = class extends Error {
227
- constructor(name) {
228
- super(`Instance ${name} destroying`);
229
- this.name = name;
230
- }
231
- code = "InstanceDestroying" /* InstanceDestroying */;
232
- };
233
-
234
- // src/errors/instance-expired.mts
235
- var InstanceExpired = class extends Error {
236
- constructor(name) {
237
- super(`Instance ${name} expired`);
238
- this.name = name;
239
- }
240
- code = "InstanceExpired" /* InstanceExpired */;
241
- };
242
-
243
- // src/errors/instance-not-found.mts
244
- var InstanceNotFound = class extends Error {
245
- constructor(name) {
246
- super(`Instance ${name} not found`);
247
- this.name = name;
248
- }
249
- code = "InstanceNotFound" /* InstanceNotFound */;
250
- };
251
-
252
- // src/errors/unknown-error.mts
253
- var UnknownError = class extends Error {
254
- code = "UnknownError" /* UnknownError */;
255
- parent;
256
- constructor(message) {
257
- if (message instanceof Error) {
258
- super(message.message);
259
- this.parent = message;
260
- return;
261
- }
262
- super(message);
263
- }
264
- };
265
-
266
- // src/utils/get-injectors.mts
267
- function getInjectors() {
268
- let currentFactoryContext = null;
269
- function provideFactoryContext2(context) {
270
- const original = currentFactoryContext;
271
- currentFactoryContext = context;
272
- return original;
273
- }
274
- function getFactoryContext() {
275
- if (!currentFactoryContext) {
276
- throw new Error(
277
- "[Injector] Trying to access injection context outside of a injectable context"
278
- );
279
- }
280
- return currentFactoryContext;
281
- }
282
- let promiseCollector = null;
283
- let injectState = null;
284
- function asyncInject2(token, args) {
285
- if (!injectState) {
286
- throw new Error(
287
- "[Injector] Trying to access inject outside of a injectable context"
288
- );
289
- }
290
- if (injectState.isFrozen) {
291
- const idx = injectState.currentIndex++;
292
- const request = injectState.requests[idx];
293
- if (request.token !== token) {
294
- throw new Error(
295
- `[Injector] Wrong token order. Expected ${request.token.toString()} but got ${token.toString()}`
296
- );
297
- }
298
- return request.promise;
299
- }
300
- const promise = getFactoryContext().inject(token, args);
301
- injectState.requests.push({
302
- token,
303
- promise
304
- });
305
- injectState.currentIndex++;
306
- return promise;
307
- }
308
- function wrapSyncInit2(cb) {
309
- return (previousState) => {
310
- const promises = [];
311
- const originalPromiseCollector = promiseCollector;
312
- const originalInjectState = injectState;
313
- injectState = previousState ? {
314
- ...previousState,
315
- currentIndex: 0
316
- } : {
317
- currentIndex: 0,
318
- isFrozen: false,
319
- requests: []
320
- };
321
- promiseCollector = (promise) => {
322
- promises.push(promise);
323
- };
324
- const result = cb();
325
- promiseCollector = originalPromiseCollector;
326
- const newInjectState = {
327
- ...injectState,
328
- isFrozen: true
329
- };
330
- injectState = originalInjectState;
331
- return [result, promises, newInjectState];
332
- };
333
- }
334
- function inject2(token, args) {
335
- const realToken = token[InjectableTokenMeta] ?? token;
336
- const instance = getFactoryContext().locator.getSyncInstance(
337
- realToken,
338
- args
339
- );
340
- if (!instance) {
341
- if (promiseCollector) {
342
- const promise = getFactoryContext().inject(realToken, args);
343
- promiseCollector(promise);
344
- } else {
345
- throw new Error(`[Injector] Cannot initiate ${realToken.toString()}`);
346
- }
347
- return new Proxy(
348
- {},
349
- {
350
- get() {
351
- throw new Error(
352
- `[Injector] Trying to access ${realToken.toString()} before it's initialized, please use asyncInject() instead of inject() or do not use the value outside of class methods`
353
- );
354
- }
355
- }
356
- );
357
- }
358
- return instance;
359
- }
360
- const injectors = {
361
- asyncInject: asyncInject2,
362
- inject: inject2,
363
- wrapSyncInit: wrapSyncInit2,
364
- provideFactoryContext: provideFactoryContext2
365
- };
366
- return injectors;
367
- }
368
-
369
- // src/utils/get-injectable-token.mts
370
- function getInjectableToken(target) {
371
- const token = target[InjectableTokenMeta];
372
- if (!token) {
373
- throw new Error(
374
- `[ServiceLocator] Class ${target.name} is not decorated with @Injectable.`
375
- );
376
- }
377
- return token;
378
- }
379
-
380
- // src/utils/defer.mts
381
- var Deferred = class {
382
- promise;
383
- _resolve;
384
- _reject;
385
- _isResolved = false;
386
- _isRejected = false;
387
- constructor() {
388
- this.promise = new Promise((resolve, reject) => {
389
- this._resolve = resolve;
390
- this._reject = reject;
391
- });
392
- }
393
- /**
394
- * Resolves the deferred promise with the given value.
395
- * @param value The value to resolve with
396
- * @throws Error if the promise has already been resolved or rejected
397
- */
398
- resolve(value) {
399
- if (this._isResolved || this._isRejected) {
400
- throw new Error("Deferred promise has already been resolved or rejected");
401
- }
402
- this._isResolved = true;
403
- this._resolve(value);
404
- }
405
- /**
406
- * Rejects the deferred promise with the given reason.
407
- * @param reason The reason for rejection
408
- * @throws Error if the promise has already been resolved or rejected
409
- */
410
- reject(reason) {
411
- if (this._isResolved || this._isRejected) {
412
- throw new Error("Deferred promise has already been resolved or rejected");
413
- }
414
- this._isRejected = true;
415
- this._reject(reason);
416
- }
417
- /**
418
- * Returns true if the promise has been resolved.
419
- */
420
- get isResolved() {
421
- return this._isResolved;
422
- }
423
- /**
424
- * Returns true if the promise has been rejected.
425
- */
426
- get isRejected() {
427
- return this._isRejected;
428
- }
429
- /**
430
- * Returns true if the promise has been settled (resolved or rejected).
431
- */
432
- get isSettled() {
433
- return this._isResolved || this._isRejected;
434
- }
435
- };
436
- function createDeferred() {
437
- return new Deferred();
438
- }
439
-
440
- // src/service-locator-instance-holder.mts
441
- var ServiceLocatorInstanceHolderStatus = /* @__PURE__ */ ((ServiceLocatorInstanceHolderStatus3) => {
442
- ServiceLocatorInstanceHolderStatus3["Created"] = "created";
443
- ServiceLocatorInstanceHolderStatus3["Creating"] = "creating";
444
- ServiceLocatorInstanceHolderStatus3["Destroying"] = "destroying";
445
- ServiceLocatorInstanceHolderStatus3["Error"] = "error";
446
- return ServiceLocatorInstanceHolderStatus3;
447
- })(ServiceLocatorInstanceHolderStatus || {});
448
-
449
- // src/base-instance-holder-manager.mts
450
- var BaseInstanceHolderManager = class {
451
- constructor(logger = null) {
452
- this.logger = logger;
453
- this._holders = /* @__PURE__ */ new Map();
454
- }
455
- _holders;
456
- /**
457
- * Protected getter for accessing the holders map from subclasses.
458
- */
459
- get holders() {
460
- return this._holders;
461
- }
462
- /**
463
- * Deletes a holder by name.
464
- * @param name The name of the holder to delete
465
- * @returns true if the holder was deleted, false if it didn't exist
466
- */
467
- delete(name) {
468
- return this._holders.delete(name);
469
- }
470
- /**
471
- * Filters holders based on a predicate function.
472
- * @param predicate Function to test each holder
473
- * @returns A new Map containing only the holders that match the predicate
474
- */
475
- filter(predicate) {
476
- return new Map(
477
- [...this._holders].filter(([key, value]) => predicate(value, key))
478
- );
479
- }
480
- /**
481
- * Clears all holders from this manager.
482
- */
483
- clear() {
484
- this._holders.clear();
485
- }
486
- /**
487
- * Gets the number of holders currently managed.
488
- */
489
- size() {
490
- return this._holders.size;
491
- }
492
- /**
493
- * Creates a new holder with Creating status and a deferred creation promise.
494
- * This is useful for creating placeholder holders that can be fulfilled later.
495
- * @param name The name of the instance
496
- * @param type The injectable type
497
- * @param scope The injectable scope
498
- * @param deps Optional set of dependencies
499
- * @param ttl Optional time-to-live in milliseconds (defaults to Infinity)
500
- * @returns A tuple containing the deferred promise and the holder
501
- */
502
- createCreatingHolder(name, type, scope, deps = /* @__PURE__ */ new Set(), ttl = Infinity) {
503
- const deferred = createDeferred();
504
- const holder = {
505
- status: "creating" /* Creating */,
506
- name,
507
- instance: null,
508
- creationPromise: deferred.promise,
509
- destroyPromise: null,
510
- type,
511
- scope,
512
- deps,
513
- destroyListeners: [],
514
- createdAt: Date.now(),
515
- ttl
516
- };
517
- return [deferred, holder];
518
- }
519
- /**
520
- * Creates a new holder with Created status and an actual instance.
521
- * This is useful for creating holders that already have their instance ready.
522
- * @param name The name of the instance
523
- * @param instance The actual instance to store
524
- * @param type The injectable type
525
- * @param scope The injectable scope
526
- * @param deps Optional set of dependencies
527
- * @param ttl Optional time-to-live in milliseconds (defaults to Infinity)
528
- * @returns The created holder
529
- */
530
- createCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set(), ttl = Infinity) {
531
- const holder = {
532
- status: "created" /* Created */,
533
- name,
534
- instance,
535
- creationPromise: null,
536
- destroyPromise: null,
537
- type,
538
- scope,
539
- deps,
540
- destroyListeners: [],
541
- createdAt: Date.now(),
542
- ttl
543
- };
544
- return holder;
545
- }
546
- /**
547
- * Gets all holder names currently managed.
548
- */
549
- getAllNames() {
550
- return Array.from(this._holders.keys());
551
- }
552
- /**
553
- * Gets all holders currently managed.
554
- */
555
- getAllHolders() {
556
- return Array.from(this._holders.values());
557
- }
558
- /**
559
- * Checks if this manager has any holders.
560
- */
561
- isEmpty() {
562
- return this._holders.size === 0;
563
- }
564
- };
565
22
 
566
23
  // src/event-emitter.mts
567
24
  var _EventEmitter_decorators, _init;
@@ -604,1062 +61,10 @@ var EventEmitter = class {
604
61
  );
605
62
  }
606
63
  };
607
- _init = __decoratorStart();
64
+ _init = __decoratorStart(null);
608
65
  EventEmitter = __decorateElement(_init, 0, "EventEmitter", _EventEmitter_decorators, EventEmitter);
609
66
  __runInitializers(_init, 1, EventEmitter);
610
67
 
611
- // src/injector.mts
612
- var defaultInjectors = getInjectors();
613
- var asyncInject = defaultInjectors.asyncInject;
614
- var inject = defaultInjectors.inject;
615
- var wrapSyncInit = defaultInjectors.wrapSyncInit;
616
- var provideFactoryContext = defaultInjectors.provideFactoryContext;
617
-
618
- // src/service-instantiator.mts
619
- var ServiceInstantiator = class {
620
- constructor(injectors) {
621
- this.injectors = injectors;
622
- }
623
- /**
624
- * Instantiates a service based on its registry record.
625
- * @param ctx The factory context for dependency injection
626
- * @param record The factory record from the registry
627
- * @param args Optional arguments for the service
628
- * @returns Promise resolving to [undefined, instance] or [error]
629
- */
630
- async instantiateService(ctx, record, args = void 0) {
631
- try {
632
- switch (record.type) {
633
- case "Class" /* Class */:
634
- return this.instantiateClass(ctx, record, args);
635
- case "Factory" /* Factory */:
636
- return this.instantiateFactory(ctx, record, args);
637
- default:
638
- throw new Error(
639
- `[ServiceInstantiator] Unknown service type: ${record.type}`
640
- );
641
- }
642
- } catch (error) {
643
- return [error instanceof Error ? error : new Error(String(error))];
644
- }
645
- }
646
- /**
647
- * Instantiates a class-based service (Injectable decorator).
648
- * @param ctx The factory context for dependency injection
649
- * @param record The factory record from the registry
650
- * @param args Optional arguments for the service constructor
651
- * @returns Promise resolving to [undefined, instance] or [error]
652
- */
653
- async instantiateClass(ctx, record, args) {
654
- try {
655
- const tryLoad = this.injectors.wrapSyncInit(() => {
656
- const original = this.injectors.provideFactoryContext(ctx);
657
- let result = new record.target(...args ? [args] : []);
658
- this.injectors.provideFactoryContext(original);
659
- return result;
660
- });
661
- let [instance, promises, injectState] = tryLoad();
662
- if (promises.length > 0) {
663
- const results = await Promise.allSettled(promises);
664
- if (results.some((result) => result.status === "rejected")) {
665
- throw new Error(
666
- `[ServiceInstantiator] Service ${record.target.name} cannot be instantiated.`
667
- );
668
- }
669
- const newRes = tryLoad(injectState);
670
- instance = newRes[0];
671
- promises = newRes[1];
672
- }
673
- if (promises.length > 0) {
674
- console.error(`[ServiceInstantiator] ${record.target.name} has problem with it's definition.
675
-
676
- One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
677
-
678
- Please use inject asyncInject of inject to load those dependencies.`);
679
- throw new Error(
680
- `[ServiceInstantiator] Service ${record.target.name} cannot be instantiated.`
681
- );
682
- }
683
- if ("onServiceInit" in instance) {
684
- await instance.onServiceInit();
685
- }
686
- if ("onServiceDestroy" in instance) {
687
- ctx.addDestroyListener(async () => {
688
- await instance.onServiceDestroy();
689
- });
690
- }
691
- return [void 0, instance];
692
- } catch (error) {
693
- return [error instanceof Error ? error : new Error(String(error))];
694
- }
695
- }
696
- /**
697
- * Instantiates a factory-based service (Factory decorator).
698
- * @param ctx The factory context for dependency injection
699
- * @param record The factory record from the registry
700
- * @param args Optional arguments for the factory
701
- * @returns Promise resolving to [undefined, instance] or [error]
702
- */
703
- async instantiateFactory(ctx, record, args) {
704
- try {
705
- const tryLoad = this.injectors.wrapSyncInit(() => {
706
- const original = this.injectors.provideFactoryContext(ctx);
707
- let result = new record.target();
708
- this.injectors.provideFactoryContext(original);
709
- return result;
710
- });
711
- let [builder, promises, injectState] = tryLoad();
712
- if (promises.length > 0) {
713
- const results = await Promise.allSettled(promises);
714
- if (results.some((result) => result.status === "rejected")) {
715
- throw new Error(
716
- `[ServiceInstantiator] Service ${record.target.name} cannot be instantiated.`
717
- );
718
- }
719
- const newRes = tryLoad(injectState);
720
- builder = newRes[0];
721
- promises = newRes[1];
722
- }
723
- if (promises.length > 0) {
724
- console.error(`[ServiceInstantiator] ${record.target.name} has problem with it's definition.
725
-
726
- One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
727
-
728
- Please use asyncInject instead of inject to load those dependencies.`);
729
- throw new Error(
730
- `[ServiceInstantiator] Service ${record.target.name} cannot be instantiated.`
731
- );
732
- }
733
- if (typeof builder.create !== "function") {
734
- throw new Error(
735
- `[ServiceInstantiator] Factory ${record.target.name} does not implement the create method.`
736
- );
737
- }
738
- const instance = await builder.create(ctx, args);
739
- return [void 0, instance];
740
- } catch (error) {
741
- return [error instanceof Error ? error : new Error(String(error))];
742
- }
743
- }
744
- };
745
-
746
- // src/request-context-holder.mts
747
- var DefaultRequestContextHolder = class extends BaseInstanceHolderManager {
748
- constructor(requestId, priority = 100, initialMetadata) {
749
- super(null);
750
- this.requestId = requestId;
751
- this.priority = priority;
752
- if (initialMetadata) {
753
- Object.entries(initialMetadata).forEach(([key, value]) => {
754
- this.metadata.set(key, value);
755
- });
756
- }
757
- }
758
- metadata = /* @__PURE__ */ new Map();
759
- createdAt = Date.now();
760
- /**
761
- * Public getter for holders to maintain interface compatibility.
762
- */
763
- get holders() {
764
- return this._holders;
765
- }
766
- /**
767
- * Gets a holder by name. For RequestContextHolder, this is a simple lookup.
768
- */
769
- get(name) {
770
- return this._holders.get(name);
771
- }
772
- /**
773
- * Sets a holder by name.
774
- */
775
- set(name, holder) {
776
- this._holders.set(name, holder);
777
- }
778
- /**
779
- * Checks if a holder exists by name.
780
- */
781
- has(name) {
782
- return this._holders.has(name);
783
- }
784
- addInstance(instanceName, instance, holder) {
785
- if (instanceName instanceof InjectionToken) {
786
- const name = instanceName.toString();
787
- const createdHolder = this.createCreatedHolder(
788
- name,
789
- instance,
790
- "Class" /* Class */,
791
- "Singleton" /* Singleton */,
792
- /* @__PURE__ */ new Set(),
793
- Infinity
794
- );
795
- this._holders.set(name, createdHolder);
796
- } else {
797
- if (!holder) {
798
- throw new Error("Holder is required when adding an instance by name");
799
- }
800
- this._holders.set(instanceName, holder);
801
- }
802
- }
803
- clear() {
804
- super.clear();
805
- this.metadata.clear();
806
- }
807
- getMetadata(key) {
808
- return this.metadata.get(key);
809
- }
810
- setMetadata(key, value) {
811
- this.metadata.set(key, value);
812
- }
813
- };
814
- function createRequestContextHolder(requestId, priority = 100, initialMetadata) {
815
- return new DefaultRequestContextHolder(requestId, priority, initialMetadata);
816
- }
817
-
818
- // src/service-locator-event-bus.mts
819
- var ServiceLocatorEventBus = class {
820
- constructor(logger = null) {
821
- this.logger = logger;
822
- }
823
- listeners = /* @__PURE__ */ new Map();
824
- on(ns, event, listener) {
825
- this.logger?.debug(`[ServiceLocatorEventBus]#on(): ns:${ns} event:${event}`);
826
- if (!this.listeners.has(ns)) {
827
- this.listeners.set(ns, /* @__PURE__ */ new Map());
828
- }
829
- const nsEvents = this.listeners.get(ns);
830
- if (!nsEvents.has(event)) {
831
- nsEvents.set(event, /* @__PURE__ */ new Set());
832
- }
833
- nsEvents.get(event).add(listener);
834
- return () => {
835
- nsEvents.get(event).delete(listener);
836
- if (nsEvents.get(event)?.size === 0) {
837
- nsEvents.delete(event);
838
- }
839
- if (nsEvents.size === 0) {
840
- this.listeners.delete(ns);
841
- }
842
- };
843
- }
844
- async emit(key, event) {
845
- if (!this.listeners.has(key)) {
846
- return;
847
- }
848
- const events = this.listeners.get(key);
849
- this.logger?.debug(`[ServiceLocatorEventBus]#emit(): ${key}:${event}`);
850
- const res = await Promise.allSettled(
851
- [...events.get(event) ?? []].map((listener) => listener(event))
852
- ).then((results) => {
853
- const res2 = results.filter((result) => result.status === "rejected").map((result) => {
854
- this.logger?.warn(
855
- `[ServiceLocatorEventBus]#emit(): ${key}:${event} rejected with`,
856
- result.reason
857
- );
858
- return result;
859
- });
860
- if (res2.length > 0) {
861
- return Promise.reject(res2);
862
- }
863
- return results;
864
- });
865
- return res;
866
- }
867
- };
868
-
869
- // src/service-locator-manager.mts
870
- var ServiceLocatorManager = class extends BaseInstanceHolderManager {
871
- constructor(logger = null) {
872
- super(logger);
873
- }
874
- get(name) {
875
- const holder = this._holders.get(name);
876
- if (holder) {
877
- if (holder.ttl !== Infinity) {
878
- const now = Date.now();
879
- if (now - holder.createdAt > holder.ttl) {
880
- this.logger?.log(
881
- `[ServiceLocatorManager]#getInstanceHolder() TTL expired for ${holder.name}`
882
- );
883
- return [new InstanceExpired(holder.name), holder];
884
- }
885
- } else if (holder.status === "destroying" /* Destroying */) {
886
- this.logger?.log(
887
- `[ServiceLocatorManager]#getInstanceHolder() Instance ${holder.name} is destroying`
888
- );
889
- return [new InstanceDestroying(holder.name), holder];
890
- } else if (holder.status === "error" /* Error */) {
891
- this.logger?.log(
892
- `[ServiceLocatorManager]#getInstanceHolder() Instance ${holder.name} is in error state`
893
- );
894
- return [holder.instance, holder];
895
- }
896
- return [void 0, holder];
897
- } else {
898
- this.logger?.log(
899
- `[ServiceLocatorManager]#getInstanceHolder() Instance ${name} not found`
900
- );
901
- return [new InstanceNotFound(name)];
902
- }
903
- }
904
- set(name, holder) {
905
- this._holders.set(name, holder);
906
- }
907
- has(name) {
908
- const [error, holder] = this.get(name);
909
- if (!error) {
910
- return [void 0, true];
911
- }
912
- if (["InstanceExpired" /* InstanceExpired */, "InstanceDestroying" /* InstanceDestroying */].includes(
913
- error.code
914
- )) {
915
- return [error];
916
- }
917
- return [void 0, !!holder];
918
- }
919
- // delete and filter methods are inherited from BaseInstanceHolderManager
920
- // createCreatingHolder method is inherited from BaseInstanceHolderManager
921
- /**
922
- * Creates a new holder with Created status and an actual instance.
923
- * This is useful for creating holders that already have their instance ready.
924
- * @param name The name of the instance
925
- * @param instance The actual instance to store
926
- * @param type The injectable type
927
- * @param scope The injectable scope
928
- * @param deps Optional set of dependencies
929
- * @param ttl Optional time-to-live in milliseconds (defaults to Infinity)
930
- * @returns The created holder
931
- */
932
- storeCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set(), ttl = Infinity) {
933
- const holder = this.createCreatedHolder(
934
- name,
935
- instance,
936
- type,
937
- scope,
938
- deps,
939
- ttl
940
- );
941
- this._holders.set(name, holder);
942
- return holder;
943
- }
944
- };
945
-
946
- // src/service-locator.mts
947
- var ServiceLocator = class {
948
- constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
949
- this.registry = registry;
950
- this.logger = logger;
951
- this.injectors = injectors;
952
- this.eventBus = new ServiceLocatorEventBus(logger);
953
- this.manager = new ServiceLocatorManager(logger);
954
- this.serviceInstantiator = new ServiceInstantiator(injectors);
955
- }
956
- eventBus;
957
- manager;
958
- serviceInstantiator;
959
- requestContexts = /* @__PURE__ */ new Map();
960
- currentRequestContext = null;
961
- // ============================================================================
962
- // PUBLIC METHODS
963
- // ============================================================================
964
- getEventBus() {
965
- return this.eventBus;
966
- }
967
- getManager() {
968
- return this.manager;
969
- }
970
- getInstanceIdentifier(token, args) {
971
- const [err, { actualToken, validatedArgs }] = this.validateAndResolveTokenArgs(token, args);
972
- if (err) {
973
- throw err;
974
- }
975
- return this.generateInstanceName(actualToken, validatedArgs);
976
- }
977
- async getInstance(token, args, onPrepare) {
978
- const [err, data] = await this.resolveTokenAndPrepareInstanceName(
979
- token,
980
- args
981
- );
982
- if (err) {
983
- return [err];
984
- }
985
- const { instanceName, validatedArgs, actualToken, realToken } = data;
986
- onPrepare?.({ instanceName, actualToken, validatedArgs });
987
- const [error, holder] = await this.retrieveOrCreateInstanceByInstanceName(
988
- instanceName,
989
- realToken,
990
- validatedArgs
991
- );
992
- if (error) {
993
- return [error];
994
- }
995
- return [void 0, holder.instance];
996
- }
997
- async getOrThrowInstance(token, args) {
998
- const [error, instance] = await this.getInstance(token, args);
999
- if (error) {
1000
- throw error;
1001
- }
1002
- return instance;
1003
- }
1004
- getSyncInstance(token, args) {
1005
- const [err, { actualToken, validatedArgs }] = this.validateAndResolveTokenArgs(token, args);
1006
- if (err) {
1007
- return null;
1008
- }
1009
- const instanceName = this.generateInstanceName(actualToken, validatedArgs);
1010
- if (this.currentRequestContext) {
1011
- const requestHolder = this.currentRequestContext.get(instanceName);
1012
- if (requestHolder) {
1013
- return requestHolder.instance;
1014
- }
1015
- }
1016
- const [error, holder] = this.manager.get(instanceName);
1017
- if (error) {
1018
- return null;
1019
- }
1020
- return holder.instance;
1021
- }
1022
- invalidate(service, round = 1) {
1023
- this.logger?.log(
1024
- `[ServiceLocator] Starting invalidation process for ${service}`
1025
- );
1026
- const toInvalidate = this.manager.filter(
1027
- (holder) => holder.name === service || holder.deps.has(service)
1028
- );
1029
- const promises = [];
1030
- for (const [key, holder] of toInvalidate.entries()) {
1031
- promises.push(this.invalidateHolder(key, holder, round));
1032
- }
1033
- return Promise.all(promises);
1034
- }
1035
- /**
1036
- * Invalidates a single holder based on its current status.
1037
- */
1038
- async invalidateHolder(key, holder, round) {
1039
- switch (holder.status) {
1040
- case "destroying" /* Destroying */:
1041
- this.logger?.trace(`[ServiceLocator] ${key} is already being destroyed`);
1042
- await holder.destroyPromise;
1043
- break;
1044
- case "creating" /* Creating */:
1045
- this.logger?.trace(
1046
- `[ServiceLocator] ${key} is being created, waiting...`
1047
- );
1048
- await holder.creationPromise;
1049
- if (round > 3) {
1050
- this.logger?.error(
1051
- `[ServiceLocator] ${key} creation triggered too many invalidation rounds`
1052
- );
1053
- return;
1054
- }
1055
- await this.invalidate(key, round + 1);
1056
- break;
1057
- default:
1058
- await this.destroyHolder(key, holder);
1059
- break;
1060
- }
1061
- }
1062
- /**
1063
- * Destroys a holder and cleans up its resources.
1064
- */
1065
- async destroyHolder(key, holder) {
1066
- holder.status = "destroying" /* Destroying */;
1067
- this.logger?.log(
1068
- `[ServiceLocator] Invalidating ${key} and notifying listeners`
1069
- );
1070
- holder.destroyPromise = Promise.all(
1071
- holder.destroyListeners.map((listener) => listener())
1072
- ).then(async () => {
1073
- this.manager.delete(key);
1074
- await this.emitInstanceEvent(key, "destroy");
1075
- });
1076
- await holder.destroyPromise;
1077
- }
1078
- async ready() {
1079
- const holders = Array.from(this.manager.filter(() => true)).map(
1080
- ([, holder]) => holder
1081
- );
1082
- await Promise.all(
1083
- holders.map((holder) => this.waitForHolderToSettle(holder))
1084
- );
1085
- }
1086
- /**
1087
- * Waits for a holder to settle (either created, destroyed, or error state).
1088
- */
1089
- async waitForHolderToSettle(holder) {
1090
- switch (holder.status) {
1091
- case "creating" /* Creating */:
1092
- await holder.creationPromise;
1093
- break;
1094
- case "destroying" /* Destroying */:
1095
- await holder.destroyPromise;
1096
- break;
1097
- }
1098
- }
1099
- // ============================================================================
1100
- // REQUEST CONTEXT MANAGEMENT
1101
- // ============================================================================
1102
- /**
1103
- * Begins a new request context with the given parameters.
1104
- * @param requestId Unique identifier for this request
1105
- * @param metadata Optional metadata for the request
1106
- * @param priority Priority for resolution (higher = more priority)
1107
- * @returns The created request context holder
1108
- */
1109
- beginRequest(requestId, metadata, priority = 100) {
1110
- if (this.requestContexts.has(requestId)) {
1111
- throw new Error(
1112
- `[ServiceLocator] Request context ${requestId} already exists`
1113
- );
1114
- }
1115
- const contextHolder = new DefaultRequestContextHolder(
1116
- requestId,
1117
- priority,
1118
- metadata
1119
- );
1120
- this.requestContexts.set(requestId, contextHolder);
1121
- this.currentRequestContext = contextHolder;
1122
- this.logger?.log(`[ServiceLocator] Started request context: ${requestId}`);
1123
- return contextHolder;
1124
- }
1125
- /**
1126
- * Ends a request context and cleans up all associated instances.
1127
- * @param requestId The request ID to end
1128
- */
1129
- async endRequest(requestId) {
1130
- const contextHolder = this.requestContexts.get(requestId);
1131
- if (!contextHolder) {
1132
- this.logger?.warn(
1133
- `[ServiceLocator] Request context ${requestId} not found`
1134
- );
1135
- return;
1136
- }
1137
- this.logger?.log(`[ServiceLocator] Ending request context: ${requestId}`);
1138
- const cleanupPromises = [];
1139
- for (const [, holder] of contextHolder.holders) {
1140
- if (holder.destroyListeners.length > 0) {
1141
- cleanupPromises.push(
1142
- Promise.all(holder.destroyListeners.map((listener) => listener()))
1143
- );
1144
- }
1145
- }
1146
- await Promise.all(cleanupPromises);
1147
- contextHolder.clear();
1148
- this.requestContexts.delete(requestId);
1149
- if (this.currentRequestContext === contextHolder) {
1150
- this.currentRequestContext = Array.from(this.requestContexts.values()).at(-1) ?? null;
1151
- }
1152
- this.logger?.log(`[ServiceLocator] Request context ${requestId} ended`);
1153
- }
1154
- /**
1155
- * Gets the current request context.
1156
- * @returns The current request context holder or null
1157
- */
1158
- getCurrentRequestContext() {
1159
- return this.currentRequestContext;
1160
- }
1161
- /**
1162
- * Sets the current request context.
1163
- * @param requestId The request ID to set as current
1164
- */
1165
- setCurrentRequestContext(requestId) {
1166
- const contextHolder = this.requestContexts.get(requestId);
1167
- if (!contextHolder) {
1168
- throw new Error(`[ServiceLocator] Request context ${requestId} not found`);
1169
- }
1170
- this.currentRequestContext = contextHolder;
1171
- }
1172
- // ============================================================================
1173
- // PRIVATE METHODS
1174
- // ============================================================================
1175
- /**
1176
- * Validates and resolves token arguments, handling factory token resolution and validation.
1177
- */
1178
- validateAndResolveTokenArgs(token, args) {
1179
- let actualToken = token;
1180
- if (typeof token === "function") {
1181
- actualToken = getInjectableToken(token);
1182
- }
1183
- let realArgs = args;
1184
- if (actualToken instanceof BoundInjectionToken) {
1185
- realArgs = actualToken.value;
1186
- } else if (actualToken instanceof FactoryInjectionToken) {
1187
- if (actualToken.resolved) {
1188
- realArgs = actualToken.value;
1189
- } else {
1190
- return [new FactoryTokenNotResolved(token.name), { actualToken }];
1191
- }
1192
- }
1193
- if (!actualToken.schema) {
1194
- return [void 0, { actualToken, validatedArgs: realArgs }];
1195
- }
1196
- const validatedArgs = actualToken.schema?.safeParse(realArgs);
1197
- if (validatedArgs && !validatedArgs.success) {
1198
- this.logger?.error(
1199
- `[ServiceLocator]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`,
1200
- validatedArgs.error
1201
- );
1202
- return [new UnknownError(validatedArgs.error), { actualToken }];
1203
- }
1204
- return [void 0, { actualToken, validatedArgs: validatedArgs?.data }];
1205
- }
1206
- /**
1207
- * Internal method to resolve token args and create instance name.
1208
- * Handles factory token resolution and validation.
1209
- */
1210
- async resolveTokenAndPrepareInstanceName(token, args) {
1211
- const [err, { actualToken, validatedArgs }] = this.validateAndResolveTokenArgs(token, args);
1212
- if (err instanceof UnknownError) {
1213
- return [err];
1214
- } else if (err instanceof FactoryTokenNotResolved && actualToken instanceof FactoryInjectionToken) {
1215
- this.logger?.log(
1216
- `[ServiceLocator]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`
1217
- );
1218
- await actualToken.resolve(this.createFactoryContext());
1219
- return this.resolveTokenAndPrepareInstanceName(token);
1220
- }
1221
- const instanceName = this.generateInstanceName(actualToken, validatedArgs);
1222
- const realToken = actualToken instanceof BoundInjectionToken || actualToken instanceof FactoryInjectionToken ? actualToken.token : actualToken;
1223
- return [void 0, { instanceName, validatedArgs, actualToken, realToken }];
1224
- }
1225
- /**
1226
- * Gets an instance by its instance name, handling all the logic after instance name creation.
1227
- */
1228
- async retrieveOrCreateInstanceByInstanceName(instanceName, realToken, realArgs) {
1229
- const existingHolder = await this.tryGetExistingInstance(
1230
- instanceName,
1231
- realToken
1232
- );
1233
- if (existingHolder) {
1234
- return existingHolder;
1235
- }
1236
- const result = await this.createNewInstance(
1237
- instanceName,
1238
- realToken,
1239
- realArgs
1240
- );
1241
- if (result[0]) {
1242
- return [result[0]];
1243
- }
1244
- const [, holder] = result;
1245
- return this.waitForInstanceReady(holder);
1246
- }
1247
- /**
1248
- * Attempts to retrieve an existing instance, handling request-scoped and singleton instances.
1249
- * Returns null if no instance exists and a new one should be created.
1250
- */
1251
- async tryGetExistingInstance(instanceName, realToken) {
1252
- const requestResult = await this.tryGetRequestScopedInstance(
1253
- instanceName,
1254
- realToken
1255
- );
1256
- if (requestResult) {
1257
- return requestResult;
1258
- }
1259
- return this.tryGetSingletonInstance(instanceName);
1260
- }
1261
- /**
1262
- * Attempts to get a request-scoped instance if applicable.
1263
- */
1264
- async tryGetRequestScopedInstance(instanceName, realToken) {
1265
- if (!this.registry.has(realToken)) {
1266
- return null;
1267
- }
1268
- const record = this.registry.get(realToken);
1269
- if (record.scope !== "Request" /* Request */) {
1270
- return null;
1271
- }
1272
- if (!this.currentRequestContext) {
1273
- this.logger?.log(
1274
- `[ServiceLocator] No current request context available for request-scoped service ${instanceName}`
1275
- );
1276
- return [new UnknownError("InstanceNotFound" /* InstanceNotFound */)];
1277
- }
1278
- const requestHolder = this.currentRequestContext.get(instanceName);
1279
- if (!requestHolder) {
1280
- return null;
1281
- }
1282
- return this.waitForInstanceReady(requestHolder);
1283
- }
1284
- /**
1285
- * Attempts to get a singleton instance from the manager.
1286
- */
1287
- async tryGetSingletonInstance(instanceName) {
1288
- const [error, holder] = this.manager.get(instanceName);
1289
- if (!error) {
1290
- return this.waitForInstanceReady(holder);
1291
- }
1292
- switch (error.code) {
1293
- case "InstanceDestroying" /* InstanceDestroying */:
1294
- this.logger?.log(
1295
- `[ServiceLocator] Instance ${instanceName} is being destroyed, waiting...`
1296
- );
1297
- await holder?.destroyPromise;
1298
- return this.tryGetSingletonInstance(instanceName);
1299
- case "InstanceExpired" /* InstanceExpired */:
1300
- this.logger?.log(
1301
- `[ServiceLocator] Instance ${instanceName} expired, invalidating...`
1302
- );
1303
- await this.invalidate(instanceName);
1304
- return this.tryGetSingletonInstance(instanceName);
1305
- case "InstanceNotFound" /* InstanceNotFound */:
1306
- return null;
1307
- // Instance doesn't exist, should create new one
1308
- default:
1309
- return [error];
1310
- }
1311
- }
1312
- /**
1313
- * Waits for an instance holder to be ready and returns the appropriate result.
1314
- */
1315
- async waitForInstanceReady(holder) {
1316
- switch (holder.status) {
1317
- case "creating" /* Creating */:
1318
- await holder.creationPromise;
1319
- return this.waitForInstanceReady(holder);
1320
- case "destroying" /* Destroying */:
1321
- return [new UnknownError("InstanceDestroying" /* InstanceDestroying */)];
1322
- case "error" /* Error */:
1323
- return [holder.instance];
1324
- case "created" /* Created */:
1325
- return [void 0, holder];
1326
- default:
1327
- return [new UnknownError("InstanceNotFound" /* InstanceNotFound */)];
1328
- }
1329
- }
1330
- /**
1331
- * Emits events to listeners for instance lifecycle events.
1332
- */
1333
- emitInstanceEvent(name, event = "create") {
1334
- this.logger?.log(
1335
- `[ServiceLocator]#emitInstanceEvent() Notifying listeners for ${name} with event ${event}`
1336
- );
1337
- return this.eventBus.emit(name, event);
1338
- }
1339
- /**
1340
- * Creates a new instance for the given token and arguments.
1341
- */
1342
- async createNewInstance(instanceName, realToken, args) {
1343
- this.logger?.log(
1344
- `[ServiceLocator]#createNewInstance() Creating instance for ${instanceName}`
1345
- );
1346
- if (this.registry.has(realToken)) {
1347
- return this.instantiateServiceFromRegistry(
1348
- instanceName,
1349
- realToken,
1350
- args
1351
- );
1352
- } else {
1353
- return [new FactoryNotFound(realToken.name.toString())];
1354
- }
1355
- }
1356
- /**
1357
- * Instantiates a service from the registry using the service instantiator.
1358
- */
1359
- instantiateServiceFromRegistry(instanceName, token, args) {
1360
- this.logger?.log(
1361
- `[ServiceLocator]#instantiateServiceFromRegistry(): Creating instance for ${instanceName} from abstract factory`
1362
- );
1363
- const ctx = this.createFactoryContext(
1364
- this.currentRequestContext || void 0
1365
- );
1366
- let record = this.registry.get(token);
1367
- let { scope, type } = record;
1368
- const [deferred, holder] = this.manager.createCreatingHolder(
1369
- instanceName,
1370
- type,
1371
- scope,
1372
- ctx.deps,
1373
- Infinity
1374
- );
1375
- this.serviceInstantiator.instantiateService(ctx, record, args).then(async ([error, instance]) => {
1376
- await this.handleInstantiationResult(
1377
- instanceName,
1378
- holder,
1379
- ctx,
1380
- deferred,
1381
- scope,
1382
- error,
1383
- instance
1384
- );
1385
- }).catch(async (error) => {
1386
- await this.handleInstantiationError(
1387
- instanceName,
1388
- holder,
1389
- deferred,
1390
- scope,
1391
- error
1392
- );
1393
- });
1394
- this.storeInstanceByScope(scope, instanceName, holder);
1395
- return [void 0, holder];
1396
- }
1397
- /**
1398
- * Handles the result of service instantiation.
1399
- */
1400
- async handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance) {
1401
- holder.destroyListeners = ctx.getDestroyListeners();
1402
- holder.creationPromise = null;
1403
- if (error) {
1404
- await this.handleInstantiationError(
1405
- instanceName,
1406
- holder,
1407
- deferred,
1408
- scope,
1409
- error
1410
- );
1411
- } else {
1412
- await this.handleInstantiationSuccess(
1413
- instanceName,
1414
- holder,
1415
- ctx,
1416
- deferred,
1417
- instance
1418
- );
1419
- }
1420
- }
1421
- /**
1422
- * Handles successful service instantiation.
1423
- */
1424
- async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance) {
1425
- holder.instance = instance;
1426
- holder.status = "created" /* Created */;
1427
- if (ctx.deps.size > 0) {
1428
- ctx.deps.forEach((dependency) => {
1429
- holder.destroyListeners.push(
1430
- this.eventBus.on(
1431
- dependency,
1432
- "destroy",
1433
- () => this.invalidate(instanceName)
1434
- )
1435
- );
1436
- });
1437
- }
1438
- await this.emitInstanceEvent(instanceName);
1439
- deferred.resolve([void 0, instance]);
1440
- }
1441
- /**
1442
- * Handles service instantiation errors.
1443
- */
1444
- async handleInstantiationError(instanceName, holder, deferred, scope, error) {
1445
- this.logger?.error(
1446
- `[ServiceLocator] Error creating instance for ${instanceName}`,
1447
- error
1448
- );
1449
- holder.status = "error" /* Error */;
1450
- holder.instance = error;
1451
- holder.creationPromise = null;
1452
- if (scope === "Singleton" /* Singleton */) {
1453
- setTimeout(() => this.invalidate(instanceName), 10);
1454
- }
1455
- deferred.reject(error);
1456
- }
1457
- /**
1458
- * Stores an instance holder based on its scope.
1459
- */
1460
- storeInstanceByScope(scope, instanceName, holder) {
1461
- switch (scope) {
1462
- case "Singleton" /* Singleton */:
1463
- this.logger?.debug(
1464
- `[ServiceLocator] Setting singleton instance for ${instanceName}`
1465
- );
1466
- this.manager.set(instanceName, holder);
1467
- break;
1468
- case "Request" /* Request */:
1469
- if (this.currentRequestContext) {
1470
- this.logger?.debug(
1471
- `[ServiceLocator] Setting request-scoped instance for ${instanceName}`
1472
- );
1473
- this.currentRequestContext.addInstance(
1474
- instanceName,
1475
- holder.instance,
1476
- holder
1477
- );
1478
- }
1479
- break;
1480
- }
1481
- }
1482
- /**
1483
- * Tries to get a pre-prepared instance from request contexts.
1484
- */
1485
- tryGetPrePreparedInstance(instanceName, contextHolder, deps) {
1486
- if (contextHolder && contextHolder.priority > 0) {
1487
- const prePreparedInstance = contextHolder.get(instanceName)?.instance;
1488
- if (prePreparedInstance !== void 0) {
1489
- this.logger?.debug(
1490
- `[ServiceLocator] Using pre-prepared instance ${instanceName} from request context ${contextHolder.requestId}`
1491
- );
1492
- deps.add(instanceName);
1493
- return prePreparedInstance;
1494
- }
1495
- }
1496
- if (this.currentRequestContext && this.currentRequestContext !== contextHolder) {
1497
- const prePreparedInstance = this.currentRequestContext.get(instanceName)?.instance;
1498
- if (prePreparedInstance !== void 0) {
1499
- this.logger?.debug(
1500
- `[ServiceLocator] Using pre-prepared instance ${instanceName} from current request context ${this.currentRequestContext.requestId}`
1501
- );
1502
- deps.add(instanceName);
1503
- return prePreparedInstance;
1504
- }
1505
- }
1506
- return void 0;
1507
- }
1508
- /**
1509
- * Creates a factory context for dependency injection during service instantiation.
1510
- * @param contextHolder Optional request context holder for priority-based resolution
1511
- */
1512
- createFactoryContext(contextHolder) {
1513
- const destroyListeners = /* @__PURE__ */ new Set();
1514
- const deps = /* @__PURE__ */ new Set();
1515
- const self = this;
1516
- function addDestroyListener(listener) {
1517
- destroyListeners.add(listener);
1518
- }
1519
- function getDestroyListeners() {
1520
- return Array.from(destroyListeners);
1521
- }
1522
- return {
1523
- // @ts-expect-error This is correct type
1524
- async inject(token, args) {
1525
- const instanceName = self.generateInstanceName(token, args);
1526
- const prePreparedInstance = self.tryGetPrePreparedInstance(
1527
- instanceName,
1528
- contextHolder,
1529
- deps
1530
- );
1531
- if (prePreparedInstance !== void 0) {
1532
- return prePreparedInstance;
1533
- }
1534
- const [error, instance] = await self.getInstance(
1535
- token,
1536
- args,
1537
- ({ instanceName: instanceName2 }) => {
1538
- deps.add(instanceName2);
1539
- }
1540
- );
1541
- if (error) {
1542
- throw error;
1543
- }
1544
- return instance;
1545
- },
1546
- addDestroyListener,
1547
- getDestroyListeners,
1548
- locator: self,
1549
- deps
1550
- };
1551
- }
1552
- /**
1553
- * Generates a unique instance name based on token and arguments.
1554
- */
1555
- generateInstanceName(token, args) {
1556
- if (!args) {
1557
- return token.toString();
1558
- }
1559
- const formattedArgs = Object.entries(args).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}=${this.formatArgValue(value)}`).join(",");
1560
- return `${token.toString()}:${formattedArgs.replaceAll(/"/g, "").replaceAll(/:/g, "=")}`;
1561
- }
1562
- /**
1563
- * Formats a single argument value for instance name generation.
1564
- */
1565
- formatArgValue(value) {
1566
- if (typeof value === "function") {
1567
- return `fn_${value.name}(${value.length})`;
1568
- }
1569
- if (typeof value === "symbol") {
1570
- return value.toString();
1571
- }
1572
- return JSON.stringify(value).slice(0, 40);
1573
- }
1574
- };
1575
-
1576
- // src/container.mts
1577
- var _Container_decorators, _init2;
1578
- _Container_decorators = [Injectable()];
1579
- var _Container = class _Container {
1580
- serviceLocator;
1581
- constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
1582
- this.serviceLocator = new ServiceLocator(registry, logger, injectors);
1583
- this.registerSelf();
1584
- }
1585
- registerSelf() {
1586
- const token = getInjectableToken(_Container);
1587
- const instanceName = this.serviceLocator.getInstanceIdentifier(token);
1588
- this.serviceLocator.getManager().storeCreatedHolder(
1589
- instanceName,
1590
- this,
1591
- "Class" /* Class */,
1592
- "Singleton" /* Singleton */
1593
- );
1594
- }
1595
- async get(token, args) {
1596
- return this.serviceLocator.getOrThrowInstance(token, args);
1597
- }
1598
- /**
1599
- * Gets the underlying ServiceLocator instance for advanced usage
1600
- */
1601
- getServiceLocator() {
1602
- return this.serviceLocator;
1603
- }
1604
- /**
1605
- * Invalidates a service and its dependencies
1606
- */
1607
- async invalidate(service) {
1608
- const holderMap = this.serviceLocator.getManager().filter((holder2) => holder2.instance === service);
1609
- if (holderMap.size === 0) {
1610
- return;
1611
- }
1612
- const holder = holderMap.values().next().value;
1613
- if (holder) {
1614
- await this.serviceLocator.invalidate(holder.name);
1615
- }
1616
- }
1617
- /**
1618
- * Waits for all pending operations to complete
1619
- */
1620
- async ready() {
1621
- await this.serviceLocator.ready();
1622
- }
1623
- // ============================================================================
1624
- // REQUEST CONTEXT MANAGEMENT
1625
- // ============================================================================
1626
- /**
1627
- * Begins a new request context with the given parameters.
1628
- * @param requestId Unique identifier for this request
1629
- * @param metadata Optional metadata for the request
1630
- * @param priority Priority for resolution (higher = more priority)
1631
- * @returns The created request context holder
1632
- */
1633
- beginRequest(requestId, metadata, priority = 100) {
1634
- return this.serviceLocator.beginRequest(requestId, metadata, priority);
1635
- }
1636
- /**
1637
- * Ends a request context and cleans up all associated instances.
1638
- * @param requestId The request ID to end
1639
- */
1640
- async endRequest(requestId) {
1641
- await this.serviceLocator.endRequest(requestId);
1642
- }
1643
- /**
1644
- * Gets the current request context.
1645
- * @returns The current request context holder or null
1646
- */
1647
- getCurrentRequestContext() {
1648
- return this.serviceLocator.getCurrentRequestContext();
1649
- }
1650
- /**
1651
- * Sets the current request context.
1652
- * @param requestId The request ID to set as current
1653
- */
1654
- setCurrentRequestContext(requestId) {
1655
- this.serviceLocator.setCurrentRequestContext(requestId);
1656
- }
1657
- };
1658
- _init2 = __decoratorStart();
1659
- _Container = __decorateElement(_init2, 0, "Container", _Container_decorators, _Container);
1660
- __runInitializers(_init2, 1, _Container);
1661
- var Container = _Container;
1662
-
1663
- export { BaseInstanceHolderManager, BoundInjectionToken, Container, DefaultRequestContextHolder, Deferred, ErrorsEnum, EventEmitter, Factory, FactoryInjectionToken, FactoryNotFound, FactoryTokenNotResolved, Injectable, InjectableScope, InjectableTokenMeta, InjectableType, InjectionToken, InstanceDestroying, InstanceExpired, InstanceNotFound, Registry, ServiceInstantiator, ServiceLocator, ServiceLocatorEventBus, ServiceLocatorInstanceHolderStatus, ServiceLocatorManager, UnknownError, asyncInject, createDeferred, createRequestContextHolder, defaultInjectors, getInjectableToken, getInjectors, globalRegistry, inject, provideFactoryContext, wrapSyncInit };
68
+ export { EventEmitter, Factory };
1664
69
  //# sourceMappingURL=index.mjs.map
1665
70
  //# sourceMappingURL=index.mjs.map