@navios/openapi-bun 0.8.0 → 0.9.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.
- package/CHANGELOG.md +8 -0
- package/dist/src/controllers/openapi-json.controller.d.mts +1 -1
- package/dist/src/controllers/openapi-json.controller.d.mts.map +1 -1
- package/dist/src/controllers/openapi-ui.controller.d.mts +1 -1
- package/dist/src/controllers/openapi-ui.controller.d.mts.map +1 -1
- package/dist/src/controllers/openapi-yaml.controller.d.mts +1 -1
- package/dist/src/controllers/openapi-yaml.controller.d.mts.map +1 -1
- package/dist/src/openapi-bun.plugin.d.mts.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/index.cjs +19 -2632
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +1 -2
- package/lib/index.d.cts.map +1 -1
- package/lib/index.d.mts +1 -2
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +19 -2632
- package/lib/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/controllers/openapi-json.controller.mts +2 -5
- package/src/controllers/openapi-ui.controller.mts +2 -4
- package/src/controllers/openapi-yaml.controller.mts +2 -4
- package/src/openapi-bun.plugin.mts +2 -14
package/lib/index.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
let node_async_hooks = require("node:async_hooks");
|
|
2
1
|
let _navios_builder = require("@navios/builder");
|
|
3
2
|
let _navios_core = require("@navios/core");
|
|
4
3
|
let _navios_openapi = require("@navios/openapi");
|
|
@@ -6,2616 +5,6 @@ let zod = require("zod");
|
|
|
6
5
|
let yaml = require("yaml");
|
|
7
6
|
let _scalar_core_libs_html_rendering = require("@scalar/core/libs/html-rendering");
|
|
8
7
|
|
|
9
|
-
//#region ../di/lib/container-DAKOvAgr.mjs
|
|
10
|
-
let InjectableScope = /* @__PURE__ */ function(InjectableScope$1) {
|
|
11
|
-
/**
|
|
12
|
-
* Singleton scope: The instance is created once and shared across the application.
|
|
13
|
-
*/ InjectableScope$1["Singleton"] = "Singleton";
|
|
14
|
-
/**
|
|
15
|
-
* Instance scope: A new instance is created for each injection.
|
|
16
|
-
*/ InjectableScope$1["Transient"] = "Transient";
|
|
17
|
-
/**
|
|
18
|
-
* Request scope: The instance is created once per request and shared within that request context.
|
|
19
|
-
*/ InjectableScope$1["Request"] = "Request";
|
|
20
|
-
return InjectableScope$1;
|
|
21
|
-
}({});
|
|
22
|
-
let InjectableType = /* @__PURE__ */ function(InjectableType$1) {
|
|
23
|
-
InjectableType$1["Class"] = "Class";
|
|
24
|
-
InjectableType$1["Factory"] = "Factory";
|
|
25
|
-
return InjectableType$1;
|
|
26
|
-
}({});
|
|
27
|
-
var InjectionToken$2 = class InjectionToken$3 {
|
|
28
|
-
name;
|
|
29
|
-
schema;
|
|
30
|
-
id = globalThis.crypto.randomUUID();
|
|
31
|
-
formattedName = null;
|
|
32
|
-
constructor(name, schema) {
|
|
33
|
-
this.name = name;
|
|
34
|
-
this.schema = schema;
|
|
35
|
-
}
|
|
36
|
-
static create(name, schema) {
|
|
37
|
-
return new InjectionToken$3(name, schema);
|
|
38
|
-
}
|
|
39
|
-
static bound(token, value) {
|
|
40
|
-
return new BoundInjectionToken(token, value);
|
|
41
|
-
}
|
|
42
|
-
static factory(token, factory) {
|
|
43
|
-
return new FactoryInjectionToken(token, factory);
|
|
44
|
-
}
|
|
45
|
-
static refineType(token) {
|
|
46
|
-
return token;
|
|
47
|
-
}
|
|
48
|
-
toString() {
|
|
49
|
-
if (this.formattedName) return this.formattedName;
|
|
50
|
-
const { name } = this;
|
|
51
|
-
if (typeof name === "function") this.formattedName = `${name.name}(${this.id})`;
|
|
52
|
-
else if (typeof name === "symbol") this.formattedName = `${name.toString()}(${this.id})`;
|
|
53
|
-
else this.formattedName = `${name}(${this.id})`;
|
|
54
|
-
return this.formattedName;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
var BoundInjectionToken = class {
|
|
58
|
-
token;
|
|
59
|
-
value;
|
|
60
|
-
id;
|
|
61
|
-
name;
|
|
62
|
-
schema;
|
|
63
|
-
constructor(token, value) {
|
|
64
|
-
this.token = token;
|
|
65
|
-
this.value = value;
|
|
66
|
-
this.name = token.name;
|
|
67
|
-
this.id = token.id;
|
|
68
|
-
this.schema = token.schema;
|
|
69
|
-
}
|
|
70
|
-
toString() {
|
|
71
|
-
return this.token.toString();
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
var FactoryInjectionToken = class {
|
|
75
|
-
token;
|
|
76
|
-
factory;
|
|
77
|
-
value;
|
|
78
|
-
resolved = false;
|
|
79
|
-
id;
|
|
80
|
-
name;
|
|
81
|
-
schema;
|
|
82
|
-
constructor(token, factory) {
|
|
83
|
-
this.token = token;
|
|
84
|
-
this.factory = factory;
|
|
85
|
-
this.name = token.name;
|
|
86
|
-
this.id = token.id;
|
|
87
|
-
this.schema = token.schema;
|
|
88
|
-
}
|
|
89
|
-
async resolve(ctx) {
|
|
90
|
-
if (!this.value) {
|
|
91
|
-
this.value = await this.factory(ctx);
|
|
92
|
-
this.resolved = true;
|
|
93
|
-
}
|
|
94
|
-
return this.value;
|
|
95
|
-
}
|
|
96
|
-
toString() {
|
|
97
|
-
return this.token.toString();
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
var Registry = class {
|
|
101
|
-
parent;
|
|
102
|
-
factories = /* @__PURE__ */ new Map();
|
|
103
|
-
constructor(parent) {
|
|
104
|
-
this.parent = parent;
|
|
105
|
-
}
|
|
106
|
-
has(token) {
|
|
107
|
-
if (this.factories.has(token.id)) return true;
|
|
108
|
-
if (this.parent) return this.parent.has(token);
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
get(token) {
|
|
112
|
-
const factory = this.factories.get(token.id);
|
|
113
|
-
if (!factory) {
|
|
114
|
-
if (this.parent) return this.parent.get(token);
|
|
115
|
-
throw new Error(`[Registry] No factory found for ${token.toString()}`);
|
|
116
|
-
}
|
|
117
|
-
return factory;
|
|
118
|
-
}
|
|
119
|
-
set(token, scope, target, type) {
|
|
120
|
-
this.factories.set(token.id, {
|
|
121
|
-
scope,
|
|
122
|
-
originalToken: token,
|
|
123
|
-
target,
|
|
124
|
-
type
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
delete(token) {
|
|
128
|
-
this.factories.delete(token.id);
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Updates the scope of an already registered factory.
|
|
132
|
-
* This is useful when you need to dynamically change a service's scope
|
|
133
|
-
* (e.g., when a singleton controller has request-scoped dependencies).
|
|
134
|
-
*
|
|
135
|
-
* @param token The injection token to update
|
|
136
|
-
* @param scope The new scope to set
|
|
137
|
-
* @returns true if the scope was updated, false if the token was not found
|
|
138
|
-
*/ updateScope(token, scope) {
|
|
139
|
-
const factory = this.factories.get(token.id);
|
|
140
|
-
if (factory) {
|
|
141
|
-
factory.scope = scope;
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
if (this.parent) return this.parent.updateScope(token, scope);
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
const globalRegistry = new Registry();
|
|
149
|
-
const InjectableTokenMeta = Symbol.for("InjectableTokenMeta");
|
|
150
|
-
function Injectable$1({ scope = InjectableScope.Singleton, token, schema, registry = globalRegistry } = {}) {
|
|
151
|
-
return (target, context) => {
|
|
152
|
-
if (context && context.kind !== "class" || target instanceof Function && !context) throw new Error("[ServiceLocator] @Injectable decorator can only be used on classes.");
|
|
153
|
-
if (schema && token) throw new Error("[ServiceLocator] @Injectable decorator cannot have both a token and a schema");
|
|
154
|
-
let injectableToken = token ?? InjectionToken$2.create(target, schema);
|
|
155
|
-
registry.set(injectableToken, scope, target, InjectableType.Class);
|
|
156
|
-
target[InjectableTokenMeta] = injectableToken;
|
|
157
|
-
return target;
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
let DIErrorCode = /* @__PURE__ */ function(DIErrorCode$1) {
|
|
161
|
-
DIErrorCode$1["FactoryNotFound"] = "FactoryNotFound";
|
|
162
|
-
DIErrorCode$1["FactoryTokenNotResolved"] = "FactoryTokenNotResolved";
|
|
163
|
-
DIErrorCode$1["InstanceNotFound"] = "InstanceNotFound";
|
|
164
|
-
DIErrorCode$1["InstanceDestroying"] = "InstanceDestroying";
|
|
165
|
-
DIErrorCode$1["CircularDependency"] = "CircularDependency";
|
|
166
|
-
DIErrorCode$1["UnknownError"] = "UnknownError";
|
|
167
|
-
return DIErrorCode$1;
|
|
168
|
-
}({});
|
|
169
|
-
var DIError = class DIError$1 extends Error {
|
|
170
|
-
context;
|
|
171
|
-
constructor(code, message, context) {
|
|
172
|
-
super(message);
|
|
173
|
-
this.code = code;
|
|
174
|
-
this.message = message;
|
|
175
|
-
this.context = context;
|
|
176
|
-
}
|
|
177
|
-
static factoryNotFound(name) {
|
|
178
|
-
return new DIError$1(DIErrorCode.FactoryNotFound, `Factory ${name} not found`, { name });
|
|
179
|
-
}
|
|
180
|
-
static factoryTokenNotResolved(token) {
|
|
181
|
-
return new DIError$1(DIErrorCode.FactoryTokenNotResolved, `Factory token not resolved: ${token?.toString() ?? "unknown"}`, { token });
|
|
182
|
-
}
|
|
183
|
-
static instanceNotFound(name) {
|
|
184
|
-
return new DIError$1(DIErrorCode.InstanceNotFound, `Instance ${name} not found`, { name });
|
|
185
|
-
}
|
|
186
|
-
static instanceDestroying(name) {
|
|
187
|
-
return new DIError$1(DIErrorCode.InstanceDestroying, `Instance ${name} destroying`, { name });
|
|
188
|
-
}
|
|
189
|
-
static unknown(message, context) {
|
|
190
|
-
if (message instanceof Error) return new DIError$1(DIErrorCode.UnknownError, message.message, {
|
|
191
|
-
...context,
|
|
192
|
-
parent: message
|
|
193
|
-
});
|
|
194
|
-
return new DIError$1(DIErrorCode.UnknownError, message, context);
|
|
195
|
-
}
|
|
196
|
-
static circularDependency(cycle) {
|
|
197
|
-
const cycleStr = cycle.join(" -> ");
|
|
198
|
-
return new DIError$1(DIErrorCode.CircularDependency, `Circular dependency detected: ${cycleStr}`, { cycle });
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
const isProduction$1 = process.env.NODE_ENV === "production";
|
|
202
|
-
let loadedModule = null;
|
|
203
|
-
function getModule() {
|
|
204
|
-
if (loadedModule) return loadedModule;
|
|
205
|
-
if (isProduction$1) {
|
|
206
|
-
class NoopLocalStorage {
|
|
207
|
-
run(_store, fn) {
|
|
208
|
-
return fn();
|
|
209
|
-
}
|
|
210
|
-
getStore() {}
|
|
211
|
-
}
|
|
212
|
-
loadedModule = {
|
|
213
|
-
createAsyncLocalStorage: () => new NoopLocalStorage(),
|
|
214
|
-
isUsingNativeAsyncLocalStorage: () => false
|
|
215
|
-
};
|
|
216
|
-
} else loadedModule = {
|
|
217
|
-
createAsyncLocalStorage: () => new node_async_hooks.AsyncLocalStorage(),
|
|
218
|
-
isUsingNativeAsyncLocalStorage: () => true
|
|
219
|
-
};
|
|
220
|
-
return loadedModule;
|
|
221
|
-
}
|
|
222
|
-
function createAsyncLocalStorage() {
|
|
223
|
-
return getModule().createAsyncLocalStorage();
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* AsyncLocalStorage for tracking the current resolution context.
|
|
227
|
-
*
|
|
228
|
-
* This allows tracking which service is being instantiated even across
|
|
229
|
-
* async boundaries (like when inject() is called inside a constructor).
|
|
230
|
-
* Essential for circular dependency detection.
|
|
231
|
-
*
|
|
232
|
-
* The actual implementation varies by environment:
|
|
233
|
-
* - Production: No-op (returns undefined, run() just calls fn directly)
|
|
234
|
-
* - Development: Real AsyncLocalStorage with full async tracking
|
|
235
|
-
* - Browser: SyncLocalStorage for synchronous-only tracking
|
|
236
|
-
*/ let resolutionContext = null;
|
|
237
|
-
function getResolutionContext() {
|
|
238
|
-
if (!resolutionContext) resolutionContext = createAsyncLocalStorage();
|
|
239
|
-
return resolutionContext;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Runs a function within a resolution context.
|
|
243
|
-
*
|
|
244
|
-
* The context tracks which holder is currently being instantiated,
|
|
245
|
-
* allowing circular dependency detection to work correctly.
|
|
246
|
-
*
|
|
247
|
-
* @param waiterHolder The holder being instantiated
|
|
248
|
-
* @param getHolder Function to retrieve holders by name
|
|
249
|
-
* @param fn The function to run within the context
|
|
250
|
-
*/ function withResolutionContext(waiterHolder, getHolder, fn) {
|
|
251
|
-
return getResolutionContext().run({
|
|
252
|
-
waiterHolder,
|
|
253
|
-
getHolder
|
|
254
|
-
}, fn);
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Gets the current resolution context, if any.
|
|
258
|
-
*
|
|
259
|
-
* Returns undefined if we're not inside a resolution context
|
|
260
|
-
* (e.g., when resolving a top-level service that has no parent).
|
|
261
|
-
*/ function getCurrentResolutionContext() {
|
|
262
|
-
return getResolutionContext().getStore();
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Runs a function outside any resolution context.
|
|
266
|
-
*
|
|
267
|
-
* This is useful for async injections that should not participate
|
|
268
|
-
* in circular dependency detection since they don't block.
|
|
269
|
-
*
|
|
270
|
-
* @param fn The function to run without resolution context
|
|
271
|
-
*/ function withoutResolutionContext(fn) {
|
|
272
|
-
return getResolutionContext().run(void 0, fn);
|
|
273
|
-
}
|
|
274
|
-
function getInjectors() {
|
|
275
|
-
let currentFactoryContext = null;
|
|
276
|
-
function provideFactoryContext$1(context) {
|
|
277
|
-
const original = currentFactoryContext;
|
|
278
|
-
currentFactoryContext = context;
|
|
279
|
-
return original;
|
|
280
|
-
}
|
|
281
|
-
function getFactoryContext() {
|
|
282
|
-
if (!currentFactoryContext) throw new Error("[Injector] Trying to access injection context outside of a injectable context");
|
|
283
|
-
return currentFactoryContext;
|
|
284
|
-
}
|
|
285
|
-
let promiseCollector = null;
|
|
286
|
-
let injectState = null;
|
|
287
|
-
function getRequest(token, args, skipCycleTracking = false) {
|
|
288
|
-
if (!injectState) throw new Error("[Injector] Trying to make a request outside of a injectable context");
|
|
289
|
-
if (injectState.isFrozen) {
|
|
290
|
-
const idx = injectState.currentIndex++;
|
|
291
|
-
const request$1 = injectState.requests[idx];
|
|
292
|
-
if (request$1.token !== token) throw new Error(`[Injector] Wrong token order. Expected ${request$1.token.toString()} but got ${token.toString()}`);
|
|
293
|
-
return request$1;
|
|
294
|
-
}
|
|
295
|
-
let result = null;
|
|
296
|
-
let error = null;
|
|
297
|
-
const doInject = () => getFactoryContext().inject(token, args).then((r) => {
|
|
298
|
-
result = r;
|
|
299
|
-
return r;
|
|
300
|
-
}).catch((e) => {
|
|
301
|
-
error = e;
|
|
302
|
-
});
|
|
303
|
-
const request = {
|
|
304
|
-
token,
|
|
305
|
-
promise: skipCycleTracking ? withoutResolutionContext(doInject) : doInject(),
|
|
306
|
-
get result() {
|
|
307
|
-
return result;
|
|
308
|
-
},
|
|
309
|
-
get error() {
|
|
310
|
-
return error;
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
injectState.requests.push(request);
|
|
314
|
-
injectState.currentIndex++;
|
|
315
|
-
return request;
|
|
316
|
-
}
|
|
317
|
-
function asyncInject$1(token, args) {
|
|
318
|
-
if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
|
|
319
|
-
const request = getRequest(token[InjectableTokenMeta] ?? token, args, true);
|
|
320
|
-
return request.promise.then((result) => {
|
|
321
|
-
if (request.error) throw request.error;
|
|
322
|
-
return result;
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
function wrapSyncInit$1(cb) {
|
|
326
|
-
return (previousState) => {
|
|
327
|
-
const promises = [];
|
|
328
|
-
const originalPromiseCollector = promiseCollector;
|
|
329
|
-
const originalInjectState = injectState;
|
|
330
|
-
injectState = previousState ? {
|
|
331
|
-
...previousState,
|
|
332
|
-
currentIndex: 0
|
|
333
|
-
} : {
|
|
334
|
-
currentIndex: 0,
|
|
335
|
-
isFrozen: false,
|
|
336
|
-
requests: []
|
|
337
|
-
};
|
|
338
|
-
promiseCollector = (promise) => {
|
|
339
|
-
promises.push(promise);
|
|
340
|
-
};
|
|
341
|
-
const result = cb();
|
|
342
|
-
promiseCollector = originalPromiseCollector;
|
|
343
|
-
const newInjectState = {
|
|
344
|
-
...injectState,
|
|
345
|
-
isFrozen: true
|
|
346
|
-
};
|
|
347
|
-
injectState = originalInjectState;
|
|
348
|
-
return [
|
|
349
|
-
result,
|
|
350
|
-
promises,
|
|
351
|
-
newInjectState
|
|
352
|
-
];
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
function inject$1$1(token, args) {
|
|
356
|
-
const realToken = token[InjectableTokenMeta] ?? token;
|
|
357
|
-
if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
|
|
358
|
-
const instance = getFactoryContext().container.tryGetSync(realToken, args);
|
|
359
|
-
if (!instance) {
|
|
360
|
-
const request = getRequest(realToken, args);
|
|
361
|
-
if (request.error) throw request.error;
|
|
362
|
-
else if (request.result) return request.result;
|
|
363
|
-
if (promiseCollector) promiseCollector(request.promise);
|
|
364
|
-
return new Proxy({}, { get() {
|
|
365
|
-
throw new Error(`[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`);
|
|
366
|
-
} });
|
|
367
|
-
}
|
|
368
|
-
return instance;
|
|
369
|
-
}
|
|
370
|
-
function optional$1(token, args) {
|
|
371
|
-
try {
|
|
372
|
-
return inject$1$1(token, args);
|
|
373
|
-
} catch {
|
|
374
|
-
return null;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return {
|
|
378
|
-
asyncInject: asyncInject$1,
|
|
379
|
-
inject: inject$1$1,
|
|
380
|
-
optional: optional$1,
|
|
381
|
-
wrapSyncInit: wrapSyncInit$1,
|
|
382
|
-
provideFactoryContext: provideFactoryContext$1
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
function getInjectableToken(target) {
|
|
386
|
-
const token = target[InjectableTokenMeta];
|
|
387
|
-
if (!token) throw new Error(`[ServiceLocator] Class ${target.name} is not decorated with @Injectable.`);
|
|
388
|
-
return token;
|
|
389
|
-
}
|
|
390
|
-
const defaultInjectors = getInjectors();
|
|
391
|
-
const asyncInject = defaultInjectors.asyncInject;
|
|
392
|
-
const inject$4 = defaultInjectors.inject;
|
|
393
|
-
const optional = defaultInjectors.optional;
|
|
394
|
-
const wrapSyncInit = defaultInjectors.wrapSyncInit;
|
|
395
|
-
const provideFactoryContext = defaultInjectors.provideFactoryContext;
|
|
396
|
-
/**
|
|
397
|
-
* Whether we're running in production mode.
|
|
398
|
-
* In production, circular dependency detection is skipped for performance.
|
|
399
|
-
*/ const isProduction = process.env.NODE_ENV === "production";
|
|
400
|
-
/**
|
|
401
|
-
* Detects circular dependencies by analyzing the waitingFor relationships
|
|
402
|
-
* between service holders.
|
|
403
|
-
*
|
|
404
|
-
* Uses BFS to traverse the waitingFor graph starting from a target holder
|
|
405
|
-
* and checks if following the chain leads back to the waiter, indicating a circular dependency.
|
|
406
|
-
*
|
|
407
|
-
* Note: In production (NODE_ENV === 'production'), detection is skipped for performance.
|
|
408
|
-
*/ var CircularDetector = class {
|
|
409
|
-
/**
|
|
410
|
-
* Detects if waiting for `targetName` from `waiterName` would create a cycle.
|
|
411
|
-
*
|
|
412
|
-
* This works by checking if `targetName` (or any holder in its waitingFor chain)
|
|
413
|
-
* is currently waiting for `waiterName`. If so, waiting would create a deadlock.
|
|
414
|
-
*
|
|
415
|
-
* In production mode, this always returns null to skip the BFS traversal overhead.
|
|
416
|
-
*
|
|
417
|
-
* @param waiterName The name of the holder that wants to wait
|
|
418
|
-
* @param targetName The name of the holder being waited on
|
|
419
|
-
* @param getHolder Function to retrieve a holder by name
|
|
420
|
-
* @returns The cycle path if a cycle is detected, null otherwise
|
|
421
|
-
*/ static detectCycle(waiterName, targetName, getHolder) {
|
|
422
|
-
if (isProduction) return null;
|
|
423
|
-
const visited = /* @__PURE__ */ new Set();
|
|
424
|
-
const queue = [{
|
|
425
|
-
name: targetName,
|
|
426
|
-
path: [waiterName, targetName]
|
|
427
|
-
}];
|
|
428
|
-
while (queue.length > 0) {
|
|
429
|
-
const { name: currentName, path } = queue.shift();
|
|
430
|
-
if (currentName === waiterName) return path;
|
|
431
|
-
if (visited.has(currentName)) continue;
|
|
432
|
-
visited.add(currentName);
|
|
433
|
-
const holder = getHolder(currentName);
|
|
434
|
-
if (!holder) continue;
|
|
435
|
-
for (const waitingForName of holder.waitingFor) if (!visited.has(waitingForName)) queue.push({
|
|
436
|
-
name: waitingForName,
|
|
437
|
-
path: [...path, waitingForName]
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Formats a cycle path into a human-readable string.
|
|
444
|
-
*
|
|
445
|
-
* @param cycle The cycle path (array of service names)
|
|
446
|
-
* @returns Formatted string like "ServiceA -> ServiceB -> ServiceA"
|
|
447
|
-
*/ static formatCycle(cycle) {
|
|
448
|
-
return cycle.join(" -> ");
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
/**
|
|
452
|
-
* Represents the lifecycle status of an instance holder.
|
|
453
|
-
*/ let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
|
|
454
|
-
/** Instance has been successfully created and is ready for use */ InstanceStatus$1["Created"] = "created";
|
|
455
|
-
/** Instance is currently being created (async initialization in progress) */ InstanceStatus$1["Creating"] = "creating";
|
|
456
|
-
/** Instance is being destroyed (cleanup in progress) */ InstanceStatus$1["Destroying"] = "destroying";
|
|
457
|
-
/** Instance creation failed with an error */ InstanceStatus$1["Error"] = "error";
|
|
458
|
-
return InstanceStatus$1;
|
|
459
|
-
}({});
|
|
460
|
-
/**
|
|
461
|
-
* Abstract base class providing common functionality for managing InstanceHolder objects.
|
|
462
|
-
*
|
|
463
|
-
* Provides shared patterns for holder storage, creation, and lifecycle management
|
|
464
|
-
* used by both singleton (HolderManager) and request-scoped (RequestContext) managers.
|
|
465
|
-
*/ var BaseHolderManager = class BaseHolderManager$1 {
|
|
466
|
-
logger;
|
|
467
|
-
_holders;
|
|
468
|
-
/**
|
|
469
|
-
* Reverse dependency index: maps a dependency name to the set of holder names that depend on it.
|
|
470
|
-
* This allows O(1) lookup of dependents instead of O(n) iteration.
|
|
471
|
-
*/ _dependents;
|
|
472
|
-
constructor(logger = null) {
|
|
473
|
-
this.logger = logger;
|
|
474
|
-
this._holders = /* @__PURE__ */ new Map();
|
|
475
|
-
this._dependents = /* @__PURE__ */ new Map();
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Protected getter for accessing the holders map from subclasses.
|
|
479
|
-
*/ get holders() {
|
|
480
|
-
return this._holders;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Deletes a holder by name and cleans up the reverse dependency index.
|
|
484
|
-
* @param name The name of the holder to delete
|
|
485
|
-
* @returns true if the holder was deleted, false if it didn't exist
|
|
486
|
-
*/ delete(name) {
|
|
487
|
-
const holder = this._holders.get(name);
|
|
488
|
-
if (holder) this.removeFromDependentsIndex(name, holder.deps);
|
|
489
|
-
return this._holders.delete(name);
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Registers a holder's dependencies in the reverse index.
|
|
493
|
-
* Call this after creating a holder with dependencies.
|
|
494
|
-
* @param holderName The name of the holder that has dependencies
|
|
495
|
-
* @param deps The set of dependency names
|
|
496
|
-
*/ registerDependencies(holderName, deps) {
|
|
497
|
-
for (const dep of deps) {
|
|
498
|
-
let dependents = this._dependents.get(dep);
|
|
499
|
-
if (!dependents) {
|
|
500
|
-
dependents = /* @__PURE__ */ new Set();
|
|
501
|
-
this._dependents.set(dep, dependents);
|
|
502
|
-
}
|
|
503
|
-
dependents.add(holderName);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Removes a holder from the reverse dependency index.
|
|
508
|
-
* @param holderName The name of the holder to remove
|
|
509
|
-
* @param deps The set of dependency names to clean up
|
|
510
|
-
*/ removeFromDependentsIndex(holderName, deps) {
|
|
511
|
-
for (const dep of deps) {
|
|
512
|
-
const dependents = this._dependents.get(dep);
|
|
513
|
-
if (dependents) {
|
|
514
|
-
dependents.delete(holderName);
|
|
515
|
-
if (dependents.size === 0) this._dependents.delete(dep);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Gets all holder names that depend on the given instance name.
|
|
521
|
-
* O(1) lookup using the reverse dependency index.
|
|
522
|
-
* @param instanceName The instance name to find dependents for
|
|
523
|
-
* @returns Array of holder names that depend on this instance
|
|
524
|
-
*/ getDependents(instanceName) {
|
|
525
|
-
const dependents = this._dependents.get(instanceName);
|
|
526
|
-
return dependents ? Array.from(dependents) : [];
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Filters holders based on a predicate function.
|
|
530
|
-
* @param predicate Function to test each holder
|
|
531
|
-
* @returns A new Map containing only the holders that match the predicate
|
|
532
|
-
* @deprecated Use forEachHolder() for iteration to avoid allocations
|
|
533
|
-
*/ filter(predicate) {
|
|
534
|
-
const result = /* @__PURE__ */ new Map();
|
|
535
|
-
for (const [key, value] of this._holders) if (predicate(value, key)) result.set(key, value);
|
|
536
|
-
return result;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Iterates over holders with a callback. More efficient than filter() as it
|
|
540
|
-
* avoids creating intermediate arrays and Maps.
|
|
541
|
-
* @param callback Function called for each holder with (holder, name)
|
|
542
|
-
*/ forEachHolder(callback) {
|
|
543
|
-
for (const [name, holder] of this._holders) callback(holder, name);
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Finds the first holder matching a predicate. More efficient than filter()
|
|
547
|
-
* when only one result is needed.
|
|
548
|
-
* @param predicate Function to test each holder
|
|
549
|
-
* @returns The first matching holder or undefined
|
|
550
|
-
*/ findHolder(predicate) {
|
|
551
|
-
for (const [name, holder] of this._holders) if (predicate(holder, name)) return holder;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Clears all holders from this manager and the reverse dependency index.
|
|
555
|
-
*/ clear() {
|
|
556
|
-
this._holders.clear();
|
|
557
|
-
this._dependents.clear();
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Gets the number of holders currently managed.
|
|
561
|
-
*/ size() {
|
|
562
|
-
return this._holders.size;
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* Creates a new holder with Creating status and a deferred creation promise.
|
|
566
|
-
* This is useful for creating placeholder holders that can be fulfilled later.
|
|
567
|
-
* @param name The name of the instance
|
|
568
|
-
* @param type The injectable type
|
|
569
|
-
* @param scope The injectable scope
|
|
570
|
-
* @param deps Optional set of dependencies
|
|
571
|
-
* @returns A tuple containing the deferred promise and the holder
|
|
572
|
-
*/ createCreatingHolder(name, type, scope, deps = /* @__PURE__ */ new Set()) {
|
|
573
|
-
const deferred = Promise.withResolvers();
|
|
574
|
-
return [deferred, {
|
|
575
|
-
status: InstanceStatus.Creating,
|
|
576
|
-
name,
|
|
577
|
-
instance: null,
|
|
578
|
-
creationPromise: deferred.promise,
|
|
579
|
-
destroyPromise: null,
|
|
580
|
-
type,
|
|
581
|
-
scope,
|
|
582
|
-
deps,
|
|
583
|
-
destroyListeners: [],
|
|
584
|
-
createdAt: Date.now(),
|
|
585
|
-
waitingFor: /* @__PURE__ */ new Set()
|
|
586
|
-
}];
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Creates a new holder with Created status and an actual instance.
|
|
590
|
-
* This is useful for creating holders that already have their instance ready.
|
|
591
|
-
* @param name The name of the instance
|
|
592
|
-
* @param instance The actual instance to store
|
|
593
|
-
* @param type The injectable type
|
|
594
|
-
* @param scope The injectable scope
|
|
595
|
-
* @param deps Optional set of dependencies
|
|
596
|
-
* @returns The created holder
|
|
597
|
-
*/ createCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set()) {
|
|
598
|
-
return {
|
|
599
|
-
status: InstanceStatus.Created,
|
|
600
|
-
name,
|
|
601
|
-
instance,
|
|
602
|
-
creationPromise: null,
|
|
603
|
-
destroyPromise: null,
|
|
604
|
-
type,
|
|
605
|
-
scope,
|
|
606
|
-
deps,
|
|
607
|
-
destroyListeners: [],
|
|
608
|
-
createdAt: Date.now(),
|
|
609
|
-
waitingFor: /* @__PURE__ */ new Set()
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Gets all holder names currently managed.
|
|
614
|
-
*/ getAllNames() {
|
|
615
|
-
return Array.from(this._holders.keys());
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Gets all holders currently managed.
|
|
619
|
-
*/ getAllHolders() {
|
|
620
|
-
return Array.from(this._holders.values());
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Checks if this manager has any holders.
|
|
624
|
-
*/ isEmpty() {
|
|
625
|
-
return this._holders.size === 0;
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* Waits for a holder to be ready and returns the appropriate result.
|
|
629
|
-
* This is a shared utility used by both singleton and request-scoped resolution.
|
|
630
|
-
*
|
|
631
|
-
* @param holder The holder to wait for
|
|
632
|
-
* @param waiterHolder Optional holder that is doing the waiting (for circular dependency detection)
|
|
633
|
-
* @param getHolder Optional function to retrieve holders by name (required if waiterHolder is provided)
|
|
634
|
-
* @returns A promise that resolves with [undefined, holder] on success or [DIError] on failure
|
|
635
|
-
*/ static async waitForHolderReady(holder, waiterHolder, getHolder) {
|
|
636
|
-
switch (holder.status) {
|
|
637
|
-
case InstanceStatus.Creating:
|
|
638
|
-
if (waiterHolder && getHolder) {
|
|
639
|
-
const cycle = CircularDetector.detectCycle(waiterHolder.name, holder.name, getHolder);
|
|
640
|
-
if (cycle) return [DIError.circularDependency(cycle)];
|
|
641
|
-
if (process.env.NODE_ENV !== "production") waiterHolder.waitingFor.add(holder.name);
|
|
642
|
-
}
|
|
643
|
-
try {
|
|
644
|
-
await holder.creationPromise;
|
|
645
|
-
} finally {
|
|
646
|
-
if (process.env.NODE_ENV !== "production") {
|
|
647
|
-
if (waiterHolder) waiterHolder.waitingFor.delete(holder.name);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
return BaseHolderManager$1.waitForHolderReady(holder, waiterHolder, getHolder);
|
|
651
|
-
case InstanceStatus.Destroying: return [DIError.instanceDestroying(holder.name)];
|
|
652
|
-
case InstanceStatus.Error: return [holder.instance];
|
|
653
|
-
case InstanceStatus.Created: return [void 0, holder];
|
|
654
|
-
default: return [DIError.instanceNotFound("unknown")];
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
/**
|
|
659
|
-
* Default implementation of RequestContext.
|
|
660
|
-
*
|
|
661
|
-
* Extends BaseHolderManager to provide holder management functionality
|
|
662
|
-
* with request-specific metadata and lifecycle support.
|
|
663
|
-
*/ var DefaultRequestContext = class extends BaseHolderManager {
|
|
664
|
-
requestId;
|
|
665
|
-
priority;
|
|
666
|
-
metadata = /* @__PURE__ */ new Map();
|
|
667
|
-
createdAt = Date.now();
|
|
668
|
-
constructor(requestId, priority = 100, initialMetadata) {
|
|
669
|
-
super(null), this.requestId = requestId, this.priority = priority;
|
|
670
|
-
if (initialMetadata) Object.entries(initialMetadata).forEach(([key, value]) => {
|
|
671
|
-
this.metadata.set(key, value);
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Public getter for holders to maintain interface compatibility.
|
|
676
|
-
*/ get holders() {
|
|
677
|
-
return this._holders;
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Gets a holder by name. For RequestContext, this is a simple lookup.
|
|
681
|
-
*/ get(name) {
|
|
682
|
-
return this._holders.get(name);
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* Sets a holder by name.
|
|
686
|
-
*/ set(name, holder) {
|
|
687
|
-
this._holders.set(name, holder);
|
|
688
|
-
}
|
|
689
|
-
/**
|
|
690
|
-
* Checks if a holder exists by name.
|
|
691
|
-
*/ has(name) {
|
|
692
|
-
return this._holders.has(name);
|
|
693
|
-
}
|
|
694
|
-
addInstance(instanceName, instance, holder) {
|
|
695
|
-
if (instanceName instanceof InjectionToken$2) {
|
|
696
|
-
const name = instanceName.toString();
|
|
697
|
-
const createdHolder = this.createCreatedHolder(name, instance, InjectableType.Class, InjectableScope.Singleton, /* @__PURE__ */ new Set());
|
|
698
|
-
this._holders.set(name, createdHolder);
|
|
699
|
-
} else {
|
|
700
|
-
if (!holder) throw new Error("Holder is required when adding an instance by name");
|
|
701
|
-
this._holders.set(instanceName, holder);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
clear() {
|
|
705
|
-
super.clear();
|
|
706
|
-
this.metadata.clear();
|
|
707
|
-
}
|
|
708
|
-
getMetadata(key) {
|
|
709
|
-
return this.metadata.get(key);
|
|
710
|
-
}
|
|
711
|
-
setMetadata(key, value) {
|
|
712
|
-
this.metadata.set(key, value);
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
/**
|
|
716
|
-
* Storage implementation for Request-scoped services.
|
|
717
|
-
*
|
|
718
|
-
* Wraps a RequestContext instance from a ScopedContainer and provides
|
|
719
|
-
* the IHolderStorage interface. This allows the InstanceResolver to work
|
|
720
|
-
* with request-scoped storage using the same interface as singleton storage.
|
|
721
|
-
*/ var RequestStorage = class {
|
|
722
|
-
scope = InjectableScope.Request;
|
|
723
|
-
constructor(contextHolder, holderManager) {
|
|
724
|
-
this.contextHolder = contextHolder;
|
|
725
|
-
this.holderManager = holderManager;
|
|
726
|
-
}
|
|
727
|
-
get(instanceName) {
|
|
728
|
-
const holder = this.contextHolder.get(instanceName);
|
|
729
|
-
if (!holder) return null;
|
|
730
|
-
switch (holder.status) {
|
|
731
|
-
case InstanceStatus.Destroying: return [DIError.instanceDestroying(instanceName), holder];
|
|
732
|
-
case InstanceStatus.Error: return [holder.instance, holder];
|
|
733
|
-
case InstanceStatus.Creating:
|
|
734
|
-
case InstanceStatus.Created: return [void 0, holder];
|
|
735
|
-
default: return null;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
set(instanceName, holder) {
|
|
739
|
-
this.contextHolder.set(instanceName, holder);
|
|
740
|
-
}
|
|
741
|
-
delete(instanceName) {
|
|
742
|
-
return this.contextHolder.delete(instanceName);
|
|
743
|
-
}
|
|
744
|
-
createHolder(instanceName, type, deps) {
|
|
745
|
-
return this.holderManager.createCreatingHolder(instanceName, type, this.scope, deps);
|
|
746
|
-
}
|
|
747
|
-
handles(scope) {
|
|
748
|
-
return scope === InjectableScope.Request;
|
|
749
|
-
}
|
|
750
|
-
getAllNames() {
|
|
751
|
-
const names = [];
|
|
752
|
-
for (const [name] of this.contextHolder.holders) names.push(name);
|
|
753
|
-
return names;
|
|
754
|
-
}
|
|
755
|
-
forEach(callback) {
|
|
756
|
-
for (const [name, holder] of this.contextHolder.holders) callback(name, holder);
|
|
757
|
-
}
|
|
758
|
-
findByInstance(instance) {
|
|
759
|
-
for (const holder of this.contextHolder.holders.values()) if (holder.instance === instance) return holder;
|
|
760
|
-
return null;
|
|
761
|
-
}
|
|
762
|
-
findDependents(instanceName) {
|
|
763
|
-
const requestDependents = this.contextHolder.getDependents(instanceName);
|
|
764
|
-
const singletonDependents = this.holderManager.getDependents(instanceName);
|
|
765
|
-
if (requestDependents.length === 0) return singletonDependents;
|
|
766
|
-
if (singletonDependents.length === 0) return requestDependents;
|
|
767
|
-
return [...requestDependents, ...singletonDependents];
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
/**
|
|
771
|
-
* Request-scoped dependency injection container.
|
|
772
|
-
*
|
|
773
|
-
* Wraps a parent Container and provides isolated request-scoped instances
|
|
774
|
-
* while delegating singleton and transient resolution to the parent.
|
|
775
|
-
* This design eliminates race conditions that can occur with async operations
|
|
776
|
-
* when multiple requests are processed concurrently.
|
|
777
|
-
*/ var ScopedContainer = class {
|
|
778
|
-
parent;
|
|
779
|
-
registry;
|
|
780
|
-
requestId;
|
|
781
|
-
requestContextHolder;
|
|
782
|
-
holderStorage;
|
|
783
|
-
disposed = false;
|
|
784
|
-
constructor(parent, registry, requestId, metadata, priority = 100) {
|
|
785
|
-
this.parent = parent;
|
|
786
|
-
this.registry = registry;
|
|
787
|
-
this.requestId = requestId;
|
|
788
|
-
this.requestContextHolder = new DefaultRequestContext(requestId, priority, metadata);
|
|
789
|
-
this.holderStorage = new RequestStorage(this.requestContextHolder, this.parent.getServiceLocator().getManager());
|
|
790
|
-
}
|
|
791
|
-
/**
|
|
792
|
-
* Gets the request context holder for this scoped container.
|
|
793
|
-
*/ getRequestContextHolder() {
|
|
794
|
-
return this.requestContextHolder;
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Gets the holder storage for this scoped container.
|
|
798
|
-
* Used by InstanceResolver for request-scoped resolution.
|
|
799
|
-
*/ getHolderStorage() {
|
|
800
|
-
return this.holderStorage;
|
|
801
|
-
}
|
|
802
|
-
/**
|
|
803
|
-
* Gets the request ID for this scoped container.
|
|
804
|
-
*/ getRequestId() {
|
|
805
|
-
return this.requestId;
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Gets the parent container.
|
|
809
|
-
*/ getParent() {
|
|
810
|
-
return this.parent;
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Gets metadata from the request context.
|
|
814
|
-
*/ getMetadata(key) {
|
|
815
|
-
return this.requestContextHolder.getMetadata(key);
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Sets metadata on the request context.
|
|
819
|
-
*/ setMetadata(key, value) {
|
|
820
|
-
this.requestContextHolder.setMetadata(key, value);
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Adds a pre-prepared instance to the request context.
|
|
824
|
-
*/ addInstance(token, instance) {
|
|
825
|
-
this.requestContextHolder.addInstance(token, instance);
|
|
826
|
-
}
|
|
827
|
-
async get(token, args) {
|
|
828
|
-
if (this.disposed) throw DIError.unknown(`ScopedContainer for request ${this.requestId} has been disposed`);
|
|
829
|
-
const actualToken = this.parent.getServiceLocator().getTokenProcessor().normalizeToken(token);
|
|
830
|
-
if (this.isRequestScoped(actualToken)) return this.resolveRequestScoped(actualToken, args);
|
|
831
|
-
return this.parent.getWithContext(token, args, this);
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Invalidates a service and its dependencies.
|
|
835
|
-
* For request-scoped services, invalidation is handled within this context.
|
|
836
|
-
*/ async invalidate(service) {
|
|
837
|
-
const holder = this.holderStorage.findByInstance(service);
|
|
838
|
-
if (holder) {
|
|
839
|
-
await this.parent.getServiceLocator().getInvalidator().invalidateWithStorage(holder.name, this.holderStorage, 1, { emitEvents: false });
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
await this.parent.invalidate(service);
|
|
843
|
-
}
|
|
844
|
-
/**
|
|
845
|
-
* Checks if a service is registered.
|
|
846
|
-
*/ isRegistered(token) {
|
|
847
|
-
return this.parent.isRegistered(token);
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Disposes this scoped container and cleans up all request-scoped instances.
|
|
851
|
-
* This is an alias for endRequest() for IContainer compatibility.
|
|
852
|
-
*/ async dispose() {
|
|
853
|
-
await this.endRequest();
|
|
854
|
-
}
|
|
855
|
-
/**
|
|
856
|
-
* Ends the request and cleans up all request-scoped instances.
|
|
857
|
-
* Uses the invalidation system to properly cascade to dependent singletons.
|
|
858
|
-
*/ async endRequest() {
|
|
859
|
-
if (this.disposed) return;
|
|
860
|
-
this.disposed = true;
|
|
861
|
-
await this.parent.getServiceLocator().getInvalidator().clearAllWithStorage(this.holderStorage, {
|
|
862
|
-
waitForSettlement: true,
|
|
863
|
-
maxRounds: 10
|
|
864
|
-
});
|
|
865
|
-
this.requestContextHolder.clear();
|
|
866
|
-
this.parent.removeActiveRequest(this.requestId);
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* Waits for all pending operations to complete.
|
|
870
|
-
*/ async ready() {
|
|
871
|
-
await this.parent.ready();
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* @internal
|
|
875
|
-
* Attempts to get an instance synchronously if it already exists and is ready.
|
|
876
|
-
* For request-scoped services, checks this container's context first.
|
|
877
|
-
* For other services, delegates to the parent container.
|
|
878
|
-
*
|
|
879
|
-
* Returns null if the instance doesn't exist or is not yet ready (still creating).
|
|
880
|
-
*/ tryGetSync(token, args) {
|
|
881
|
-
const actualToken = this.parent.getServiceLocator().getTokenProcessor().normalizeToken(token);
|
|
882
|
-
if (this.isRequestScoped(actualToken)) {
|
|
883
|
-
const instanceName = this.parent.getServiceLocator().getInstanceIdentifier(token, args);
|
|
884
|
-
const holder = this.requestContextHolder.get(instanceName);
|
|
885
|
-
if (holder && holder.status === InstanceStatus.Created) return holder.instance;
|
|
886
|
-
return null;
|
|
887
|
-
}
|
|
888
|
-
return this.parent.tryGetSync(token, args);
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* Checks if a token is for a request-scoped service.
|
|
892
|
-
*/ isRequestScoped(token) {
|
|
893
|
-
const realToken = this.parent.getServiceLocator().getTokenProcessor().getRealToken(token);
|
|
894
|
-
if (!this.registry.has(realToken)) return false;
|
|
895
|
-
return this.registry.get(realToken).scope === InjectableScope.Request;
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Resolves a request-scoped service from this container's context.
|
|
899
|
-
* Uses locking to prevent duplicate initialization during concurrent resolution.
|
|
900
|
-
*/ async resolveRequestScoped(token, args) {
|
|
901
|
-
const instanceName = this.parent.getServiceLocator().getInstanceIdentifier(token, args);
|
|
902
|
-
const existingHolder = this.requestContextHolder.get(instanceName);
|
|
903
|
-
if (existingHolder) if (existingHolder.status === InstanceStatus.Error) this.requestContextHolder.delete(instanceName);
|
|
904
|
-
else {
|
|
905
|
-
const [error, readyHolder] = await BaseHolderManager.waitForHolderReady(existingHolder);
|
|
906
|
-
if (error) throw error;
|
|
907
|
-
return readyHolder.instance;
|
|
908
|
-
}
|
|
909
|
-
return this.parent.resolveForRequest(token, args, this);
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Stores an instance in the request context.
|
|
913
|
-
* Called by Container during request-scoped service resolution.
|
|
914
|
-
*/ storeRequestInstance(instanceName, instance, holder) {
|
|
915
|
-
this.requestContextHolder.addInstance(instanceName, instance, holder);
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Gets an existing instance from the request context.
|
|
919
|
-
* Called by Container during resolution to check for existing instances.
|
|
920
|
-
*/ getRequestInstance(instanceName) {
|
|
921
|
-
return this.requestContextHolder.get(instanceName);
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Generates a prefixed event name for request-scoped services.
|
|
925
|
-
* Format: {requestId}:{instanceName}
|
|
926
|
-
*/ getPrefixedEventName(instanceName) {
|
|
927
|
-
return `${this.requestId}:${instanceName}`;
|
|
928
|
-
}
|
|
929
|
-
};
|
|
930
|
-
/**
|
|
931
|
-
* Storage implementation for Singleton-scoped services.
|
|
932
|
-
*
|
|
933
|
-
* Wraps a HolderManager instance and provides the IHolderStorage interface.
|
|
934
|
-
* This allows the InstanceResolver to work with singleton storage
|
|
935
|
-
* using the same interface as request-scoped storage.
|
|
936
|
-
*/ var SingletonStorage = class {
|
|
937
|
-
scope = InjectableScope.Singleton;
|
|
938
|
-
constructor(manager) {
|
|
939
|
-
this.manager = manager;
|
|
940
|
-
}
|
|
941
|
-
get(instanceName) {
|
|
942
|
-
const [error, holder] = this.manager.get(instanceName);
|
|
943
|
-
if (!error) return [void 0, holder];
|
|
944
|
-
switch (error.code) {
|
|
945
|
-
case DIErrorCode.InstanceNotFound: return null;
|
|
946
|
-
case DIErrorCode.InstanceDestroying: return [error, holder];
|
|
947
|
-
default: return [error];
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
set(instanceName, holder) {
|
|
951
|
-
this.manager.set(instanceName, holder);
|
|
952
|
-
}
|
|
953
|
-
delete(instanceName) {
|
|
954
|
-
return this.manager.delete(instanceName);
|
|
955
|
-
}
|
|
956
|
-
createHolder(instanceName, type, deps) {
|
|
957
|
-
return this.manager.createCreatingHolder(instanceName, type, this.scope, deps);
|
|
958
|
-
}
|
|
959
|
-
handles(scope) {
|
|
960
|
-
return scope === InjectableScope.Singleton;
|
|
961
|
-
}
|
|
962
|
-
getAllNames() {
|
|
963
|
-
return this.manager.getAllNames();
|
|
964
|
-
}
|
|
965
|
-
forEach(callback) {
|
|
966
|
-
this.manager.forEachHolder((holder, name) => callback(name, holder));
|
|
967
|
-
}
|
|
968
|
-
findByInstance(instance) {
|
|
969
|
-
return this.manager.findHolder((h) => h.instance === instance) ?? null;
|
|
970
|
-
}
|
|
971
|
-
findDependents(instanceName) {
|
|
972
|
-
return this.manager.getDependents(instanceName);
|
|
973
|
-
}
|
|
974
|
-
};
|
|
975
|
-
/**
|
|
976
|
-
* Resolves instances from tokens, handling caching, creation, and scope rules.
|
|
977
|
-
*
|
|
978
|
-
* Uses the Storage Strategy pattern for unified singleton/request-scoped handling.
|
|
979
|
-
* Coordinates with Instantiator for actual service creation.
|
|
980
|
-
*/ var InstanceResolver = class {
|
|
981
|
-
registry;
|
|
982
|
-
manager;
|
|
983
|
-
instantiator;
|
|
984
|
-
tokenProcessor;
|
|
985
|
-
logger;
|
|
986
|
-
serviceLocator;
|
|
987
|
-
singletonStorage;
|
|
988
|
-
constructor(registry, manager, instantiator, tokenProcessor, logger = null, serviceLocator) {
|
|
989
|
-
this.registry = registry;
|
|
990
|
-
this.manager = manager;
|
|
991
|
-
this.instantiator = instantiator;
|
|
992
|
-
this.tokenProcessor = tokenProcessor;
|
|
993
|
-
this.logger = logger;
|
|
994
|
-
this.serviceLocator = serviceLocator;
|
|
995
|
-
this.singletonStorage = new SingletonStorage(manager);
|
|
996
|
-
}
|
|
997
|
-
/**
|
|
998
|
-
* Resolves an instance for the given token and arguments.
|
|
999
|
-
* This method is used for singleton and transient services.
|
|
1000
|
-
*
|
|
1001
|
-
* @param token The injection token
|
|
1002
|
-
* @param args Optional arguments
|
|
1003
|
-
* @param contextContainer The container to use for creating FactoryContext
|
|
1004
|
-
*/ async resolveInstance(token, args, contextContainer) {
|
|
1005
|
-
return this.resolveWithStorage(token, args, contextContainer, this.singletonStorage);
|
|
1006
|
-
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Resolves a request-scoped instance for a ScopedContainer.
|
|
1009
|
-
* The service will be stored in the ScopedContainer's request context.
|
|
1010
|
-
*
|
|
1011
|
-
* @param token The injection token
|
|
1012
|
-
* @param args Optional arguments
|
|
1013
|
-
* @param scopedContainer The ScopedContainer that owns the request context
|
|
1014
|
-
*/ async resolveRequestScopedInstance(token, args, scopedContainer) {
|
|
1015
|
-
return this.resolveWithStorage(token, args, scopedContainer, scopedContainer.getHolderStorage(), scopedContainer);
|
|
1016
|
-
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Unified resolution method that works with any IHolderStorage.
|
|
1019
|
-
* This eliminates duplication between singleton and request-scoped resolution.
|
|
1020
|
-
*
|
|
1021
|
-
* IMPORTANT: The check-and-store logic is carefully designed to avoid race conditions.
|
|
1022
|
-
* The storage check and holder creation must happen synchronously (no awaits between).
|
|
1023
|
-
*
|
|
1024
|
-
* @param token The injection token
|
|
1025
|
-
* @param args Optional arguments
|
|
1026
|
-
* @param contextContainer The container for FactoryContext
|
|
1027
|
-
* @param storage The storage strategy to use
|
|
1028
|
-
* @param scopedContainer Optional scoped container for request-scoped services
|
|
1029
|
-
*/ async resolveWithStorage(token, args, contextContainer, storage, scopedContainer) {
|
|
1030
|
-
const [err, data] = await this.resolveTokenAndPrepareInstanceName(token, args, contextContainer);
|
|
1031
|
-
if (err) return [err];
|
|
1032
|
-
const { instanceName, validatedArgs, realToken } = data;
|
|
1033
|
-
const getResult = storage.get(instanceName);
|
|
1034
|
-
if (getResult !== null) {
|
|
1035
|
-
const [error, holder$1] = getResult;
|
|
1036
|
-
if (!error && holder$1) {
|
|
1037
|
-
const readyResult = await this.waitForInstanceReady(holder$1);
|
|
1038
|
-
if (readyResult[0]) return [readyResult[0]];
|
|
1039
|
-
return [void 0, readyResult[1].instance];
|
|
1040
|
-
}
|
|
1041
|
-
if (error) {
|
|
1042
|
-
const handledResult = await this.handleStorageError(instanceName, error, holder$1, storage);
|
|
1043
|
-
if (handledResult) return handledResult;
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
const [createError, holder] = await this.createAndStoreInstance(instanceName, realToken, validatedArgs, contextContainer, storage, scopedContainer);
|
|
1047
|
-
if (createError) return [createError];
|
|
1048
|
-
return [void 0, holder.instance];
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Handles storage error states (destroying, error, etc.).
|
|
1052
|
-
* Returns a result if handled, null if should proceed with creation.
|
|
1053
|
-
*/ async handleStorageError(instanceName, error, holder, storage) {
|
|
1054
|
-
switch (error.code) {
|
|
1055
|
-
case DIErrorCode.InstanceDestroying:
|
|
1056
|
-
this.logger?.log(`[InstanceResolver] Instance ${instanceName} is being destroyed, waiting...`);
|
|
1057
|
-
if (holder?.destroyPromise) await holder.destroyPromise;
|
|
1058
|
-
const newResult = storage.get(instanceName);
|
|
1059
|
-
if (newResult !== null && !newResult[0]) {
|
|
1060
|
-
const readyResult = await this.waitForInstanceReady(newResult[1]);
|
|
1061
|
-
if (readyResult[0]) return [readyResult[0]];
|
|
1062
|
-
return [void 0, readyResult[1].instance];
|
|
1063
|
-
}
|
|
1064
|
-
return null;
|
|
1065
|
-
default:
|
|
1066
|
-
if (holder) {
|
|
1067
|
-
this.logger?.log(`[InstanceResolver] Removing failed instance ${instanceName} from storage to allow retry`);
|
|
1068
|
-
storage.delete(instanceName);
|
|
1069
|
-
}
|
|
1070
|
-
return null;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1074
|
-
* Creates a new instance and stores it using the provided storage strategy.
|
|
1075
|
-
* This unified method replaces instantiateServiceFromRegistry and createRequestScopedInstance.
|
|
1076
|
-
*
|
|
1077
|
-
* For transient services, the instance is created but not stored (no caching).
|
|
1078
|
-
*/ async createAndStoreInstance(instanceName, realToken, args, contextContainer, storage, scopedContainer) {
|
|
1079
|
-
this.logger?.log(`[InstanceResolver]#createAndStoreInstance() Creating instance for ${instanceName}`);
|
|
1080
|
-
if (!this.registry.has(realToken)) return [DIError.factoryNotFound(realToken.name.toString())];
|
|
1081
|
-
const ctx = this.createFactoryContext(contextContainer);
|
|
1082
|
-
const record = this.registry.get(realToken);
|
|
1083
|
-
const { scope, type } = record;
|
|
1084
|
-
if (scope === InjectableScope.Transient) return this.createTransientInstance(instanceName, record, args, ctx);
|
|
1085
|
-
const [deferred, holder] = this.manager.createCreatingHolder(instanceName, type, scope, ctx.deps);
|
|
1086
|
-
storage.set(instanceName, holder);
|
|
1087
|
-
const getHolder = (name) => {
|
|
1088
|
-
const storageResult = storage.get(name);
|
|
1089
|
-
if (storageResult !== null) {
|
|
1090
|
-
const [, storageHolder] = storageResult;
|
|
1091
|
-
if (storageHolder) return storageHolder;
|
|
1092
|
-
}
|
|
1093
|
-
const [, managerHolder] = this.manager.get(name);
|
|
1094
|
-
return managerHolder;
|
|
1095
|
-
};
|
|
1096
|
-
withResolutionContext(holder, getHolder, () => {
|
|
1097
|
-
this.instantiator.instantiateService(ctx, record, args).then(async (result) => {
|
|
1098
|
-
const [error, instance] = result.length === 2 ? result : [result[0], void 0];
|
|
1099
|
-
await this.handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer);
|
|
1100
|
-
}).catch(async (error) => {
|
|
1101
|
-
await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
|
|
1102
|
-
}).catch(() => {});
|
|
1103
|
-
});
|
|
1104
|
-
return this.waitForInstanceReady(holder);
|
|
1105
|
-
}
|
|
1106
|
-
/**
|
|
1107
|
-
* Creates a transient instance without storage or locking.
|
|
1108
|
-
* Each call creates a new instance.
|
|
1109
|
-
*/ async createTransientInstance(instanceName, record, args, ctx) {
|
|
1110
|
-
this.logger?.log(`[InstanceResolver]#createTransientInstance() Creating transient instance for ${instanceName}`);
|
|
1111
|
-
const tempHolder = {
|
|
1112
|
-
status: InstanceStatus.Creating,
|
|
1113
|
-
name: instanceName,
|
|
1114
|
-
instance: null,
|
|
1115
|
-
creationPromise: null,
|
|
1116
|
-
destroyPromise: null,
|
|
1117
|
-
type: record.type,
|
|
1118
|
-
scope: InjectableScope.Transient,
|
|
1119
|
-
deps: ctx.deps,
|
|
1120
|
-
destroyListeners: [],
|
|
1121
|
-
createdAt: Date.now(),
|
|
1122
|
-
waitingFor: /* @__PURE__ */ new Set()
|
|
1123
|
-
};
|
|
1124
|
-
const getHolder = (name) => {
|
|
1125
|
-
const [, managerHolder] = this.manager.get(name);
|
|
1126
|
-
return managerHolder;
|
|
1127
|
-
};
|
|
1128
|
-
const [error, instance] = await withResolutionContext(tempHolder, getHolder, () => this.instantiator.instantiateService(ctx, record, args));
|
|
1129
|
-
if (error) return [error];
|
|
1130
|
-
return [void 0, {
|
|
1131
|
-
status: InstanceStatus.Created,
|
|
1132
|
-
name: instanceName,
|
|
1133
|
-
instance,
|
|
1134
|
-
creationPromise: null,
|
|
1135
|
-
destroyPromise: null,
|
|
1136
|
-
type: record.type,
|
|
1137
|
-
scope: InjectableScope.Transient,
|
|
1138
|
-
deps: ctx.deps,
|
|
1139
|
-
destroyListeners: ctx.getDestroyListeners(),
|
|
1140
|
-
createdAt: Date.now(),
|
|
1141
|
-
waitingFor: /* @__PURE__ */ new Set()
|
|
1142
|
-
}];
|
|
1143
|
-
}
|
|
1144
|
-
/**
|
|
1145
|
-
* Gets a synchronous instance (for sync operations).
|
|
1146
|
-
*/ getSyncInstance(token, args, contextContainer) {
|
|
1147
|
-
const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
|
|
1148
|
-
if (err) return null;
|
|
1149
|
-
const instanceName = this.tokenProcessor.generateInstanceName(actualToken, validatedArgs);
|
|
1150
|
-
if ("getRequestInstance" in contextContainer) {
|
|
1151
|
-
const requestHolder = contextContainer.getRequestInstance(instanceName);
|
|
1152
|
-
if (requestHolder) return requestHolder.instance;
|
|
1153
|
-
}
|
|
1154
|
-
const [error, holder] = this.manager.get(instanceName);
|
|
1155
|
-
if (error) return null;
|
|
1156
|
-
return holder.instance;
|
|
1157
|
-
}
|
|
1158
|
-
/**
|
|
1159
|
-
* Internal method to resolve token args and create instance name.
|
|
1160
|
-
* Handles factory token resolution and validation.
|
|
1161
|
-
*/ async resolveTokenAndPrepareInstanceName(token, args, contextContainer) {
|
|
1162
|
-
const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
|
|
1163
|
-
if (err instanceof DIError && err.code === DIErrorCode.UnknownError) return [err];
|
|
1164
|
-
else if (err instanceof DIError && err.code === DIErrorCode.FactoryTokenNotResolved && actualToken instanceof FactoryInjectionToken) {
|
|
1165
|
-
this.logger?.log(`[InstanceResolver]#resolveTokenAndPrepareInstanceName() Factory token not resolved, resolving it`);
|
|
1166
|
-
await actualToken.resolve(this.createFactoryContext(contextContainer));
|
|
1167
|
-
return this.resolveTokenAndPrepareInstanceName(token, void 0, contextContainer);
|
|
1168
|
-
}
|
|
1169
|
-
return [void 0, {
|
|
1170
|
-
instanceName: this.tokenProcessor.generateInstanceName(actualToken, validatedArgs),
|
|
1171
|
-
validatedArgs,
|
|
1172
|
-
actualToken,
|
|
1173
|
-
realToken: actualToken instanceof BoundInjectionToken || actualToken instanceof FactoryInjectionToken ? actualToken.token : actualToken
|
|
1174
|
-
}];
|
|
1175
|
-
}
|
|
1176
|
-
/**
|
|
1177
|
-
* Waits for an instance holder to be ready and returns the appropriate result.
|
|
1178
|
-
* Uses the shared utility from BaseHolderManager.
|
|
1179
|
-
* Passes the current resolution context for circular dependency detection.
|
|
1180
|
-
*/ waitForInstanceReady(holder) {
|
|
1181
|
-
const ctx = getCurrentResolutionContext();
|
|
1182
|
-
return BaseHolderManager.waitForHolderReady(holder, ctx?.waiterHolder, ctx?.getHolder);
|
|
1183
|
-
}
|
|
1184
|
-
/**
|
|
1185
|
-
* Handles the result of service instantiation.
|
|
1186
|
-
*/ async handleInstantiationResult(instanceName, holder, ctx, deferred, scope, error, instance, scopedContainer) {
|
|
1187
|
-
holder.destroyListeners = ctx.getDestroyListeners();
|
|
1188
|
-
holder.creationPromise = null;
|
|
1189
|
-
if (error) await this.handleInstantiationError(instanceName, holder, deferred, scope, error);
|
|
1190
|
-
else await this.handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer);
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Handles successful service instantiation.
|
|
1194
|
-
*/ async handleInstantiationSuccess(instanceName, holder, ctx, deferred, instance, scopedContainer) {
|
|
1195
|
-
holder.instance = instance;
|
|
1196
|
-
holder.status = InstanceStatus.Created;
|
|
1197
|
-
if (ctx.deps.size > 0) if (scopedContainer) scopedContainer.getRequestContextHolder().registerDependencies(instanceName, ctx.deps);
|
|
1198
|
-
else this.manager.registerDependencies(instanceName, ctx.deps);
|
|
1199
|
-
if (ctx.deps.size > 0) ctx.deps.forEach((dependency) => {
|
|
1200
|
-
holder.destroyListeners.push(this.serviceLocator.getEventBus().on(dependency, "destroy", () => {
|
|
1201
|
-
this.logger?.log(`[InstanceResolver] Dependency ${dependency} destroyed, invalidating ${instanceName}`);
|
|
1202
|
-
this.serviceLocator.getInvalidator().invalidate(instanceName);
|
|
1203
|
-
}));
|
|
1204
|
-
if (scopedContainer) {
|
|
1205
|
-
const prefixedDependency = scopedContainer.getPrefixedEventName(dependency);
|
|
1206
|
-
holder.destroyListeners.push(this.serviceLocator.getEventBus().on(prefixedDependency, "destroy", () => {
|
|
1207
|
-
this.logger?.log(`[InstanceResolver] Request-scoped dependency ${dependency} destroyed, invalidating ${instanceName}`);
|
|
1208
|
-
scopedContainer.invalidate(instance);
|
|
1209
|
-
}));
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
this.logger?.log(`[InstanceResolver] Instance ${instanceName} created successfully`);
|
|
1213
|
-
deferred.resolve([void 0, instance]);
|
|
1214
|
-
}
|
|
1215
|
-
/**
|
|
1216
|
-
* Handles service instantiation errors.
|
|
1217
|
-
*/ async handleInstantiationError(instanceName, holder, deferred, scope, error) {
|
|
1218
|
-
this.logger?.error(`[InstanceResolver] Error creating instance for ${instanceName}`, error);
|
|
1219
|
-
holder.status = InstanceStatus.Error;
|
|
1220
|
-
holder.instance = error;
|
|
1221
|
-
holder.creationPromise = null;
|
|
1222
|
-
if (scope === InjectableScope.Singleton) {
|
|
1223
|
-
this.logger?.log(`[InstanceResolver] Singleton ${instanceName} failed, will be invalidated`);
|
|
1224
|
-
this.serviceLocator.getInvalidator().invalidate(instanceName).catch(() => {});
|
|
1225
|
-
}
|
|
1226
|
-
deferred.reject(error);
|
|
1227
|
-
}
|
|
1228
|
-
/**
|
|
1229
|
-
* Creates a factory context for dependency injection during service instantiation.
|
|
1230
|
-
*/ createFactoryContext(contextContainer) {
|
|
1231
|
-
return this.tokenProcessor.createFactoryContext(contextContainer);
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
/**
|
|
1235
|
-
* Creates service instances from registry records.
|
|
1236
|
-
*
|
|
1237
|
-
* Handles both class-based (@Injectable) and factory-based (@Factory) services,
|
|
1238
|
-
* managing the instantiation lifecycle including sync initialization retries
|
|
1239
|
-
* and lifecycle hook invocation (onServiceInit, onServiceDestroy).
|
|
1240
|
-
*/ var Instantiator = class {
|
|
1241
|
-
injectors;
|
|
1242
|
-
constructor(injectors) {
|
|
1243
|
-
this.injectors = injectors;
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* Instantiates a service based on its registry record.
|
|
1247
|
-
* @param ctx The factory context for dependency injection
|
|
1248
|
-
* @param record The factory record from the registry
|
|
1249
|
-
* @param args Optional arguments for the service
|
|
1250
|
-
* @returns Promise resolving to [undefined, instance] or [error]
|
|
1251
|
-
*/ async instantiateService(ctx, record, args = void 0) {
|
|
1252
|
-
try {
|
|
1253
|
-
switch (record.type) {
|
|
1254
|
-
case InjectableType.Class: return this.instantiateClass(ctx, record, args);
|
|
1255
|
-
case InjectableType.Factory: return this.instantiateFactory(ctx, record, args);
|
|
1256
|
-
default: throw DIError.unknown(`[Instantiator] Unknown service type: ${record.type}`);
|
|
1257
|
-
}
|
|
1258
|
-
} catch (error) {
|
|
1259
|
-
return [error instanceof DIError ? error : DIError.unknown(String(error))];
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
/**
|
|
1263
|
-
* Instantiates a class-based service (Injectable decorator).
|
|
1264
|
-
* @param ctx The factory context for dependency injection
|
|
1265
|
-
* @param record The factory record from the registry
|
|
1266
|
-
* @param args Optional arguments for the service constructor
|
|
1267
|
-
* @returns Promise resolving to [undefined, instance] or [error]
|
|
1268
|
-
*/ async instantiateClass(ctx, record, args) {
|
|
1269
|
-
try {
|
|
1270
|
-
const tryLoad = this.injectors.wrapSyncInit(() => {
|
|
1271
|
-
const original = this.injectors.provideFactoryContext(ctx);
|
|
1272
|
-
let result = new record.target(...args ? [args] : []);
|
|
1273
|
-
this.injectors.provideFactoryContext(original);
|
|
1274
|
-
return result;
|
|
1275
|
-
});
|
|
1276
|
-
let [instance, promises, injectState] = tryLoad();
|
|
1277
|
-
if (promises.length > 0) {
|
|
1278
|
-
if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
|
|
1279
|
-
const newRes = tryLoad(injectState);
|
|
1280
|
-
instance = newRes[0];
|
|
1281
|
-
promises = newRes[1];
|
|
1282
|
-
}
|
|
1283
|
-
if (promises.length > 0) {
|
|
1284
|
-
console.error(`[Instantiator] ${record.target.name} has problem with it's definition.
|
|
1285
|
-
|
|
1286
|
-
One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
|
|
1287
|
-
|
|
1288
|
-
Please use inject asyncInject of inject to load those dependencies.`);
|
|
1289
|
-
throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
|
|
1290
|
-
}
|
|
1291
|
-
if ("onServiceInit" in instance) await instance.onServiceInit();
|
|
1292
|
-
if ("onServiceDestroy" in instance) ctx.addDestroyListener(async () => {
|
|
1293
|
-
await instance.onServiceDestroy();
|
|
1294
|
-
});
|
|
1295
|
-
return [void 0, instance];
|
|
1296
|
-
} catch (error) {
|
|
1297
|
-
return [error instanceof DIError ? error : DIError.unknown(String(error))];
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
/**
|
|
1301
|
-
* Instantiates a factory-based service (Factory decorator).
|
|
1302
|
-
* @param ctx The factory context for dependency injection
|
|
1303
|
-
* @param record The factory record from the registry
|
|
1304
|
-
* @param args Optional arguments for the factory
|
|
1305
|
-
* @returns Promise resolving to [undefined, instance] or [error]
|
|
1306
|
-
*/ async instantiateFactory(ctx, record, args) {
|
|
1307
|
-
try {
|
|
1308
|
-
const tryLoad = this.injectors.wrapSyncInit(() => {
|
|
1309
|
-
const original = this.injectors.provideFactoryContext(ctx);
|
|
1310
|
-
let result = new record.target();
|
|
1311
|
-
this.injectors.provideFactoryContext(original);
|
|
1312
|
-
return result;
|
|
1313
|
-
});
|
|
1314
|
-
let [builder$3, promises, injectState] = tryLoad();
|
|
1315
|
-
if (promises.length > 0) {
|
|
1316
|
-
if ((await Promise.allSettled(promises)).some((result) => result.status === "rejected")) throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
|
|
1317
|
-
const newRes = tryLoad(injectState);
|
|
1318
|
-
builder$3 = newRes[0];
|
|
1319
|
-
promises = newRes[1];
|
|
1320
|
-
}
|
|
1321
|
-
if (promises.length > 0) {
|
|
1322
|
-
console.error(`[Instantiator] ${record.target.name} has problem with it's definition.
|
|
1323
|
-
|
|
1324
|
-
One or more of the dependencies are registered as a InjectableScope.Instance and are used with inject.
|
|
1325
|
-
|
|
1326
|
-
Please use asyncInject instead of inject to load those dependencies.`);
|
|
1327
|
-
throw DIError.unknown(`[Instantiator] Service ${record.target.name} cannot be instantiated.`);
|
|
1328
|
-
}
|
|
1329
|
-
if (typeof builder$3.create !== "function") throw DIError.unknown(`[Instantiator] Factory ${record.target.name} does not implement the create method.`);
|
|
1330
|
-
return [void 0, await builder$3.create(ctx, args)];
|
|
1331
|
-
} catch (error) {
|
|
1332
|
-
return [error instanceof DIError ? error : DIError.unknown(String(error))];
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
};
|
|
1336
|
-
/**
|
|
1337
|
-
* Manages graceful service cleanup with dependency-aware invalidation.
|
|
1338
|
-
*
|
|
1339
|
-
* Ensures services are destroyed in the correct order based on their dependencies.
|
|
1340
|
-
* Works with any IHolderStorage implementation, enabling unified invalidation
|
|
1341
|
-
* for both singleton and request-scoped services.
|
|
1342
|
-
*/ var Invalidator = class {
|
|
1343
|
-
eventBus;
|
|
1344
|
-
logger;
|
|
1345
|
-
storage;
|
|
1346
|
-
constructor(manager, eventBus, logger = null) {
|
|
1347
|
-
this.eventBus = eventBus;
|
|
1348
|
-
this.logger = logger;
|
|
1349
|
-
this.storage = new SingletonStorage(manager);
|
|
1350
|
-
}
|
|
1351
|
-
/**
|
|
1352
|
-
* Invalidates a service and all its dependencies.
|
|
1353
|
-
* Works with the configured storage (singleton by default).
|
|
1354
|
-
*/ invalidate(service, round = 1) {
|
|
1355
|
-
return this.invalidateWithStorage(service, this.storage, round);
|
|
1356
|
-
}
|
|
1357
|
-
/**
|
|
1358
|
-
* Invalidates a service using a specific storage.
|
|
1359
|
-
* This allows request-scoped invalidation using a RequestStorage.
|
|
1360
|
-
*
|
|
1361
|
-
* @param service The instance name to invalidate
|
|
1362
|
-
* @param storage The storage to use for this invalidation
|
|
1363
|
-
* @param round Current invalidation round (for recursion limiting)
|
|
1364
|
-
* @param options Additional options for invalidation behavior
|
|
1365
|
-
*/ async invalidateWithStorage(service, storage, round = 1, options = {}) {
|
|
1366
|
-
const { cascade = true, _invalidating = /* @__PURE__ */ new Set() } = options;
|
|
1367
|
-
if (_invalidating.has(service)) {
|
|
1368
|
-
this.logger?.log(`[Invalidator] Skipping ${service} - already being invalidated in this chain`);
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
this.logger?.log(`[Invalidator] Starting invalidation process for ${service}`);
|
|
1372
|
-
const result = storage.get(service);
|
|
1373
|
-
if (result === null) return;
|
|
1374
|
-
_invalidating.add(service);
|
|
1375
|
-
const optionsWithTracking = {
|
|
1376
|
-
...options,
|
|
1377
|
-
_invalidating
|
|
1378
|
-
};
|
|
1379
|
-
if (cascade) {
|
|
1380
|
-
const dependents = storage.findDependents(service);
|
|
1381
|
-
for (const dependentName of dependents) await this.invalidateWithStorage(dependentName, storage, round, optionsWithTracking);
|
|
1382
|
-
}
|
|
1383
|
-
const [, holder] = result;
|
|
1384
|
-
if (holder) await this.invalidateHolderWithStorage(service, holder, storage, round, optionsWithTracking);
|
|
1385
|
-
}
|
|
1386
|
-
/**
|
|
1387
|
-
* Gracefully clears all services using invalidation logic.
|
|
1388
|
-
* This method respects service dependencies and ensures proper cleanup order.
|
|
1389
|
-
* Services that depend on others will be invalidated first, then their dependencies.
|
|
1390
|
-
*/ async clearAll(options = {}) {
|
|
1391
|
-
return this.clearAllWithStorage(this.storage, options);
|
|
1392
|
-
}
|
|
1393
|
-
/**
|
|
1394
|
-
* Gracefully clears all services in a specific storage.
|
|
1395
|
-
* This allows clearing request-scoped services using a RequestStorage.
|
|
1396
|
-
*/ async clearAllWithStorage(storage, options = {}) {
|
|
1397
|
-
const { maxRounds = 10, waitForSettlement = true } = options;
|
|
1398
|
-
this.logger?.log("[Invalidator] Starting graceful clearing of all services");
|
|
1399
|
-
if (waitForSettlement) {
|
|
1400
|
-
this.logger?.log("[Invalidator] Waiting for all services to settle...");
|
|
1401
|
-
await this.readyWithStorage(storage);
|
|
1402
|
-
}
|
|
1403
|
-
const allServiceNames = storage.getAllNames();
|
|
1404
|
-
if (allServiceNames.length === 0) this.logger?.log("[Invalidator] No services to clear");
|
|
1405
|
-
else {
|
|
1406
|
-
this.logger?.log(`[Invalidator] Found ${allServiceNames.length} services to clear: ${allServiceNames.join(", ")}`);
|
|
1407
|
-
await this.clearServicesWithDependencyAwarenessForStorage(allServiceNames, maxRounds, storage);
|
|
1408
|
-
}
|
|
1409
|
-
this.logger?.log("[Invalidator] Graceful clearing completed");
|
|
1410
|
-
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Waits for all services to settle (either created, destroyed, or error state).
|
|
1413
|
-
*/ async ready() {
|
|
1414
|
-
return this.readyWithStorage(this.storage);
|
|
1415
|
-
}
|
|
1416
|
-
/**
|
|
1417
|
-
* Waits for all services in a specific storage to settle.
|
|
1418
|
-
*/ async readyWithStorage(storage) {
|
|
1419
|
-
const holders = [];
|
|
1420
|
-
storage.forEach((_, holder) => holders.push(holder));
|
|
1421
|
-
await Promise.all(holders.map((holder) => this.waitForHolderToSettle(holder)));
|
|
1422
|
-
}
|
|
1423
|
-
/**
|
|
1424
|
-
* Invalidates a single holder using a specific storage.
|
|
1425
|
-
*/ async invalidateHolderWithStorage(key, holder, storage, round, options = {}) {
|
|
1426
|
-
const { emitEvents = true, onInvalidated } = options;
|
|
1427
|
-
await this.invalidateHolderByStatus(holder, round, {
|
|
1428
|
-
context: key,
|
|
1429
|
-
onCreationError: () => this.logger?.error(`[Invalidator] ${key} creation triggered too many invalidation rounds`),
|
|
1430
|
-
onRecursiveInvalidate: () => this.invalidateWithStorage(key, storage, round + 1, options),
|
|
1431
|
-
onDestroy: () => this.destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated)
|
|
1432
|
-
});
|
|
1433
|
-
}
|
|
1434
|
-
/**
|
|
1435
|
-
* Common invalidation logic for holders based on their status.
|
|
1436
|
-
*/ async invalidateHolderByStatus(holder, round, options) {
|
|
1437
|
-
switch (holder.status) {
|
|
1438
|
-
case InstanceStatus.Destroying:
|
|
1439
|
-
await holder.destroyPromise;
|
|
1440
|
-
break;
|
|
1441
|
-
case InstanceStatus.Creating:
|
|
1442
|
-
await holder.creationPromise;
|
|
1443
|
-
if (round > 3) {
|
|
1444
|
-
options.onCreationError();
|
|
1445
|
-
return;
|
|
1446
|
-
}
|
|
1447
|
-
await options.onRecursiveInvalidate();
|
|
1448
|
-
break;
|
|
1449
|
-
default:
|
|
1450
|
-
await options.onDestroy();
|
|
1451
|
-
break;
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
/**
|
|
1455
|
-
* Destroys a holder using a specific storage.
|
|
1456
|
-
*/ async destroyHolderWithStorage(key, holder, storage, emitEvents, onInvalidated) {
|
|
1457
|
-
holder.status = InstanceStatus.Destroying;
|
|
1458
|
-
this.logger?.log(`[Invalidator] Invalidating ${key} and notifying listeners`);
|
|
1459
|
-
holder.destroyPromise = Promise.all(holder.destroyListeners.map((listener) => listener())).then(async () => {
|
|
1460
|
-
holder.destroyListeners = [];
|
|
1461
|
-
holder.deps.clear();
|
|
1462
|
-
storage.delete(key);
|
|
1463
|
-
if (emitEvents && this.eventBus) await this.emitInstanceEvent(key, "destroy");
|
|
1464
|
-
if (onInvalidated) await onInvalidated(key);
|
|
1465
|
-
});
|
|
1466
|
-
await holder.destroyPromise;
|
|
1467
|
-
}
|
|
1468
|
-
/**
|
|
1469
|
-
* Waits for a holder to settle (either created, destroyed, or error state).
|
|
1470
|
-
*/ async waitForHolderToSettle(holder) {
|
|
1471
|
-
switch (holder.status) {
|
|
1472
|
-
case InstanceStatus.Creating:
|
|
1473
|
-
await holder.creationPromise;
|
|
1474
|
-
break;
|
|
1475
|
-
case InstanceStatus.Destroying:
|
|
1476
|
-
await holder.destroyPromise;
|
|
1477
|
-
break;
|
|
1478
|
-
case InstanceStatus.Created:
|
|
1479
|
-
case InstanceStatus.Error: break;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
/**
|
|
1483
|
-
* Clears services with dependency awareness for a specific storage.
|
|
1484
|
-
*/ async clearServicesWithDependencyAwarenessForStorage(serviceNames, maxRounds, storage) {
|
|
1485
|
-
const clearedServices = /* @__PURE__ */ new Set();
|
|
1486
|
-
let round = 1;
|
|
1487
|
-
while (clearedServices.size < serviceNames.length && round <= maxRounds) {
|
|
1488
|
-
this.logger?.log(`[Invalidator] Clearing round ${round}/${maxRounds}, ${clearedServices.size}/${serviceNames.length} services cleared`);
|
|
1489
|
-
const servicesToClearThisRound = this.findServicesReadyForClearingInStorage(serviceNames, clearedServices, storage);
|
|
1490
|
-
if (servicesToClearThisRound.length === 0) {
|
|
1491
|
-
const remainingServices = serviceNames.filter((name) => !clearedServices.has(name));
|
|
1492
|
-
if (remainingServices.length > 0) {
|
|
1493
|
-
this.logger?.warn(`[Invalidator] No services ready for clearing, forcing cleanup of remaining: ${remainingServices.join(", ")}`);
|
|
1494
|
-
await this.forceClearServicesInStorage(remainingServices, storage);
|
|
1495
|
-
remainingServices.forEach((name) => clearedServices.add(name));
|
|
1496
|
-
}
|
|
1497
|
-
break;
|
|
1498
|
-
}
|
|
1499
|
-
const clearPromises = servicesToClearThisRound.map(async (serviceName) => {
|
|
1500
|
-
try {
|
|
1501
|
-
await this.invalidateWithStorage(serviceName, storage, round);
|
|
1502
|
-
clearedServices.add(serviceName);
|
|
1503
|
-
this.logger?.log(`[Invalidator] Successfully cleared service: ${serviceName}`);
|
|
1504
|
-
} catch (error) {
|
|
1505
|
-
this.logger?.error(`[Invalidator] Error clearing service ${serviceName}:`, error);
|
|
1506
|
-
clearedServices.add(serviceName);
|
|
1507
|
-
}
|
|
1508
|
-
});
|
|
1509
|
-
await Promise.all(clearPromises);
|
|
1510
|
-
round++;
|
|
1511
|
-
}
|
|
1512
|
-
if (clearedServices.size < serviceNames.length) this.logger?.warn(`[Invalidator] Clearing completed after ${maxRounds} rounds, but ${serviceNames.length - clearedServices.size} services may not have been properly cleared`);
|
|
1513
|
-
}
|
|
1514
|
-
/**
|
|
1515
|
-
* Finds services that are ready to be cleared in the current round.
|
|
1516
|
-
* A service is ready if all its dependencies have already been cleared.
|
|
1517
|
-
*/ findServicesReadyForClearingInStorage(allServiceNames, clearedServices, storage) {
|
|
1518
|
-
return allServiceNames.filter((serviceName) => {
|
|
1519
|
-
if (clearedServices.has(serviceName)) return false;
|
|
1520
|
-
const result = storage.get(serviceName);
|
|
1521
|
-
if (result === null || result[0]) return true;
|
|
1522
|
-
const [, holder] = result;
|
|
1523
|
-
return !Array.from(holder.deps).some((dep) => !clearedServices.has(dep));
|
|
1524
|
-
});
|
|
1525
|
-
}
|
|
1526
|
-
/**
|
|
1527
|
-
* Force clears services that couldn't be cleared through normal dependency resolution.
|
|
1528
|
-
* This handles edge cases like circular dependencies.
|
|
1529
|
-
*/ async forceClearServicesInStorage(serviceNames, storage) {
|
|
1530
|
-
const promises = serviceNames.map(async (serviceName) => {
|
|
1531
|
-
try {
|
|
1532
|
-
const result = storage.get(serviceName);
|
|
1533
|
-
if (result !== null && !result[0]) {
|
|
1534
|
-
const [, holder] = result;
|
|
1535
|
-
await this.destroyHolderWithStorage(serviceName, holder, storage, true);
|
|
1536
|
-
}
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
this.logger?.error(`[Invalidator] Error force clearing service ${serviceName}:`, error);
|
|
1539
|
-
}
|
|
1540
|
-
});
|
|
1541
|
-
await Promise.all(promises);
|
|
1542
|
-
}
|
|
1543
|
-
/**
|
|
1544
|
-
* Emits events to listeners for instance lifecycle events.
|
|
1545
|
-
*/ emitInstanceEvent(name, event = "create") {
|
|
1546
|
-
if (!this.eventBus) return Promise.resolve();
|
|
1547
|
-
this.logger?.log(`[Invalidator]#emitInstanceEvent() Notifying listeners for ${name} with event ${event}`);
|
|
1548
|
-
return this.eventBus.emit(name, event);
|
|
1549
|
-
}
|
|
1550
|
-
};
|
|
1551
|
-
/**
|
|
1552
|
-
* Event bus for service lifecycle events (create, destroy, etc.).
|
|
1553
|
-
*
|
|
1554
|
-
* Enables loose coupling between services by allowing them to subscribe
|
|
1555
|
-
* to lifecycle events of their dependencies without direct references.
|
|
1556
|
-
* Used primarily for invalidation cascading.
|
|
1557
|
-
*/ var LifecycleEventBus = class {
|
|
1558
|
-
logger;
|
|
1559
|
-
listeners = /* @__PURE__ */ new Map();
|
|
1560
|
-
constructor(logger = null) {
|
|
1561
|
-
this.logger = logger;
|
|
1562
|
-
}
|
|
1563
|
-
on(ns, event, listener) {
|
|
1564
|
-
this.logger?.debug(`[LifecycleEventBus]#on(): ns:${ns} event:${event}`);
|
|
1565
|
-
if (!this.listeners.has(ns)) this.listeners.set(ns, /* @__PURE__ */ new Map());
|
|
1566
|
-
const nsEvents = this.listeners.get(ns);
|
|
1567
|
-
if (!nsEvents.has(event)) nsEvents.set(event, /* @__PURE__ */ new Set());
|
|
1568
|
-
nsEvents.get(event).add(listener);
|
|
1569
|
-
return () => {
|
|
1570
|
-
nsEvents.get(event)?.delete(listener);
|
|
1571
|
-
if (nsEvents.get(event)?.size === 0) nsEvents.delete(event);
|
|
1572
|
-
if (nsEvents.size === 0) this.listeners.delete(ns);
|
|
1573
|
-
};
|
|
1574
|
-
}
|
|
1575
|
-
async emit(key, event) {
|
|
1576
|
-
if (!this.listeners.has(key)) return;
|
|
1577
|
-
const events = this.listeners.get(key);
|
|
1578
|
-
this.logger?.debug(`[LifecycleEventBus]#emit(): ${key}:${event}`);
|
|
1579
|
-
return await Promise.allSettled([...events.get(event) ?? []].map((listener) => listener(event))).then((results) => {
|
|
1580
|
-
const res = results.filter((result) => result.status === "rejected").map((result) => {
|
|
1581
|
-
this.logger?.warn(`[LifecycleEventBus]#emit(): ${key}:${event} rejected with`, result.reason);
|
|
1582
|
-
return result;
|
|
1583
|
-
});
|
|
1584
|
-
if (res.length > 0) return Promise.reject(res);
|
|
1585
|
-
return results;
|
|
1586
|
-
});
|
|
1587
|
-
}
|
|
1588
|
-
};
|
|
1589
|
-
/**
|
|
1590
|
-
* Manages the storage and retrieval of singleton instance holders.
|
|
1591
|
-
*
|
|
1592
|
-
* Provides CRUD operations and filtering for the holder map.
|
|
1593
|
-
* Handles holder state validation (destroying, error states) on retrieval.
|
|
1594
|
-
*/ var HolderManager = class extends BaseHolderManager {
|
|
1595
|
-
constructor(logger = null) {
|
|
1596
|
-
super(logger);
|
|
1597
|
-
}
|
|
1598
|
-
get(name) {
|
|
1599
|
-
const holder = this._holders.get(name);
|
|
1600
|
-
if (holder) {
|
|
1601
|
-
if (holder.status === InstanceStatus.Destroying) {
|
|
1602
|
-
this.logger?.log(`[HolderManager]#get() Instance ${holder.name} is destroying`);
|
|
1603
|
-
return [DIError.instanceDestroying(holder.name), holder];
|
|
1604
|
-
} else if (holder.status === InstanceStatus.Error) {
|
|
1605
|
-
this.logger?.log(`[HolderManager]#get() Instance ${holder.name} is in error state`);
|
|
1606
|
-
return [holder.instance, holder];
|
|
1607
|
-
}
|
|
1608
|
-
return [void 0, holder];
|
|
1609
|
-
} else {
|
|
1610
|
-
this.logger?.log(`[HolderManager]#get() Instance ${name} not found`);
|
|
1611
|
-
return [DIError.instanceNotFound(name)];
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
set(name, holder) {
|
|
1615
|
-
this._holders.set(name, holder);
|
|
1616
|
-
}
|
|
1617
|
-
has(name) {
|
|
1618
|
-
const [error, holder] = this.get(name);
|
|
1619
|
-
if (!error) return [void 0, true];
|
|
1620
|
-
if (error.code === DIErrorCode.InstanceDestroying) return [error];
|
|
1621
|
-
return [void 0, !!holder];
|
|
1622
|
-
}
|
|
1623
|
-
/**
|
|
1624
|
-
* Creates a new holder with Created status and stores it.
|
|
1625
|
-
* This is useful for creating holders that already have their instance ready.
|
|
1626
|
-
* @param name The name of the instance
|
|
1627
|
-
* @param instance The actual instance to store
|
|
1628
|
-
* @param type The injectable type
|
|
1629
|
-
* @param scope The injectable scope
|
|
1630
|
-
* @param deps Optional set of dependencies
|
|
1631
|
-
* @returns The created holder
|
|
1632
|
-
*/ storeCreatedHolder(name, instance, type, scope, deps = /* @__PURE__ */ new Set()) {
|
|
1633
|
-
const holder = this.createCreatedHolder(name, instance, type, scope, deps);
|
|
1634
|
-
this._holders.set(name, holder);
|
|
1635
|
-
return holder;
|
|
1636
|
-
}
|
|
1637
|
-
};
|
|
1638
|
-
/**
|
|
1639
|
-
* Simple LRU cache for instance name generation.
|
|
1640
|
-
* Uses a Map which maintains insertion order for efficient LRU eviction.
|
|
1641
|
-
*/ var InstanceNameCache = class {
|
|
1642
|
-
cache = /* @__PURE__ */ new Map();
|
|
1643
|
-
maxSize;
|
|
1644
|
-
constructor(maxSize = 1e3) {
|
|
1645
|
-
this.maxSize = maxSize;
|
|
1646
|
-
}
|
|
1647
|
-
get(key) {
|
|
1648
|
-
const value = this.cache.get(key);
|
|
1649
|
-
if (value !== void 0) {
|
|
1650
|
-
this.cache.delete(key);
|
|
1651
|
-
this.cache.set(key, value);
|
|
1652
|
-
}
|
|
1653
|
-
return value;
|
|
1654
|
-
}
|
|
1655
|
-
set(key, value) {
|
|
1656
|
-
if (this.cache.has(key)) this.cache.delete(key);
|
|
1657
|
-
else if (this.cache.size >= this.maxSize) {
|
|
1658
|
-
const firstKey = this.cache.keys().next().value;
|
|
1659
|
-
if (firstKey !== void 0) this.cache.delete(firstKey);
|
|
1660
|
-
}
|
|
1661
|
-
this.cache.set(key, value);
|
|
1662
|
-
}
|
|
1663
|
-
clear() {
|
|
1664
|
-
this.cache.clear();
|
|
1665
|
-
}
|
|
1666
|
-
};
|
|
1667
|
-
/**
|
|
1668
|
-
* Handles token validation, normalization, and instance name generation.
|
|
1669
|
-
*
|
|
1670
|
-
* Provides utilities for resolving tokens to their underlying InjectionToken,
|
|
1671
|
-
* validating arguments against schemas, and generating unique instance identifiers.
|
|
1672
|
-
*/ var TokenProcessor = class {
|
|
1673
|
-
logger;
|
|
1674
|
-
instanceNameCache = new InstanceNameCache();
|
|
1675
|
-
constructor(logger = null) {
|
|
1676
|
-
this.logger = logger;
|
|
1677
|
-
}
|
|
1678
|
-
/**
|
|
1679
|
-
* Normalizes a token to an InjectionToken.
|
|
1680
|
-
* Handles class constructors by getting their injectable token.
|
|
1681
|
-
*
|
|
1682
|
-
* @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
|
|
1683
|
-
* @returns The normalized InjectionTokenType
|
|
1684
|
-
*/ normalizeToken(token) {
|
|
1685
|
-
if (typeof token === "function") return getInjectableToken(token);
|
|
1686
|
-
return token;
|
|
1687
|
-
}
|
|
1688
|
-
/**
|
|
1689
|
-
* Gets the underlying "real" token from wrapped tokens.
|
|
1690
|
-
* For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.
|
|
1691
|
-
* For other tokens, returns the token itself.
|
|
1692
|
-
*
|
|
1693
|
-
* @param token The token to unwrap
|
|
1694
|
-
* @returns The underlying InjectionToken
|
|
1695
|
-
*/ getRealToken(token) {
|
|
1696
|
-
if (token instanceof BoundInjectionToken || token instanceof FactoryInjectionToken) return token.token;
|
|
1697
|
-
return token;
|
|
1698
|
-
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Convenience method that normalizes a token and then gets the real token.
|
|
1701
|
-
* Useful for checking registry entries where you need the actual registered token.
|
|
1702
|
-
*
|
|
1703
|
-
* @param token Any injectable type
|
|
1704
|
-
* @returns The underlying InjectionToken
|
|
1705
|
-
*/ getRegistryToken(token) {
|
|
1706
|
-
return this.getRealToken(this.normalizeToken(token));
|
|
1707
|
-
}
|
|
1708
|
-
/**
|
|
1709
|
-
* Validates and resolves token arguments, handling factory token resolution and validation.
|
|
1710
|
-
*/ validateAndResolveTokenArgs(token, args) {
|
|
1711
|
-
let actualToken = token;
|
|
1712
|
-
if (typeof token === "function") actualToken = getInjectableToken(token);
|
|
1713
|
-
let realArgs = args;
|
|
1714
|
-
if (actualToken instanceof BoundInjectionToken) realArgs = actualToken.value;
|
|
1715
|
-
else if (actualToken instanceof FactoryInjectionToken) if (actualToken.resolved) realArgs = actualToken.value;
|
|
1716
|
-
else return [DIError.factoryTokenNotResolved(token.name), { actualToken }];
|
|
1717
|
-
if (!actualToken.schema) return [void 0, {
|
|
1718
|
-
actualToken,
|
|
1719
|
-
validatedArgs: realArgs
|
|
1720
|
-
}];
|
|
1721
|
-
const validatedArgs = actualToken.schema?.safeParse(realArgs);
|
|
1722
|
-
if (validatedArgs && !validatedArgs.success) {
|
|
1723
|
-
this.logger?.error(`[TokenProcessor]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`, validatedArgs.error);
|
|
1724
|
-
return [DIError.unknown(validatedArgs.error), { actualToken }];
|
|
1725
|
-
}
|
|
1726
|
-
return [void 0, {
|
|
1727
|
-
actualToken,
|
|
1728
|
-
validatedArgs: validatedArgs?.data
|
|
1729
|
-
}];
|
|
1730
|
-
}
|
|
1731
|
-
/**
|
|
1732
|
-
* Generates a unique instance name based on token and arguments.
|
|
1733
|
-
* Results are cached using an LRU cache for performance.
|
|
1734
|
-
*/ generateInstanceName(token, args) {
|
|
1735
|
-
if (!args) return token.toString();
|
|
1736
|
-
const tokenStr = token.toString();
|
|
1737
|
-
const cacheKey = `${tokenStr}:${JSON.stringify(args)}`;
|
|
1738
|
-
const cached = this.instanceNameCache.get(cacheKey);
|
|
1739
|
-
if (cached !== void 0) return cached;
|
|
1740
|
-
const result = `${tokenStr}:${Object.entries(args).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}=${this.formatArgValue(value)}`).join(",").replaceAll(/"/g, "").replaceAll(/:/g, "=")}`;
|
|
1741
|
-
this.instanceNameCache.set(cacheKey, result);
|
|
1742
|
-
return result;
|
|
1743
|
-
}
|
|
1744
|
-
/**
|
|
1745
|
-
* Formats a single argument value for instance name generation.
|
|
1746
|
-
*/ formatArgValue(value) {
|
|
1747
|
-
if (typeof value === "function") return `fn_${value.name}(${value.length})`;
|
|
1748
|
-
if (typeof value === "symbol") return value.toString();
|
|
1749
|
-
return JSON.stringify(value).slice(0, 40);
|
|
1750
|
-
}
|
|
1751
|
-
/**
|
|
1752
|
-
* Creates a factory context for dependency injection during service instantiation.
|
|
1753
|
-
* @param container The container instance (Container or ScopedContainer) for dependency resolution
|
|
1754
|
-
* @param onDependencyResolved Callback when a dependency is resolved, receives the instance name
|
|
1755
|
-
*/ createFactoryContext(container, onDependencyResolved) {
|
|
1756
|
-
const destroyListeners = /* @__PURE__ */ new Set();
|
|
1757
|
-
const deps = /* @__PURE__ */ new Set();
|
|
1758
|
-
function addDestroyListener(listener) {
|
|
1759
|
-
destroyListeners.add(listener);
|
|
1760
|
-
}
|
|
1761
|
-
function getDestroyListeners() {
|
|
1762
|
-
return Array.from(destroyListeners);
|
|
1763
|
-
}
|
|
1764
|
-
const self = this;
|
|
1765
|
-
return {
|
|
1766
|
-
async inject(token, args) {
|
|
1767
|
-
const actualToken = typeof token === "function" ? getInjectableToken(token) : token;
|
|
1768
|
-
const instanceName = self.generateInstanceName(actualToken, args);
|
|
1769
|
-
deps.add(instanceName);
|
|
1770
|
-
if (onDependencyResolved) onDependencyResolved(instanceName);
|
|
1771
|
-
return container.get(token, args);
|
|
1772
|
-
},
|
|
1773
|
-
addDestroyListener,
|
|
1774
|
-
getDestroyListeners,
|
|
1775
|
-
container,
|
|
1776
|
-
deps
|
|
1777
|
-
};
|
|
1778
|
-
}
|
|
1779
|
-
};
|
|
1780
|
-
/**
|
|
1781
|
-
* Core DI engine that coordinates service instantiation, resolution, and lifecycle.
|
|
1782
|
-
*
|
|
1783
|
-
* Acts as the central orchestrator for dependency injection operations,
|
|
1784
|
-
* delegating to specialized components (InstanceResolver, Instantiator, Invalidator)
|
|
1785
|
-
* for specific tasks.
|
|
1786
|
-
*/ var ServiceLocator = class {
|
|
1787
|
-
registry;
|
|
1788
|
-
logger;
|
|
1789
|
-
injectors;
|
|
1790
|
-
eventBus;
|
|
1791
|
-
manager;
|
|
1792
|
-
instantiator;
|
|
1793
|
-
tokenProcessor;
|
|
1794
|
-
invalidator;
|
|
1795
|
-
instanceResolver;
|
|
1796
|
-
constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
|
|
1797
|
-
this.registry = registry;
|
|
1798
|
-
this.logger = logger;
|
|
1799
|
-
this.injectors = injectors;
|
|
1800
|
-
this.eventBus = new LifecycleEventBus(logger);
|
|
1801
|
-
this.manager = new HolderManager(logger);
|
|
1802
|
-
this.instantiator = new Instantiator(injectors);
|
|
1803
|
-
this.tokenProcessor = new TokenProcessor(logger);
|
|
1804
|
-
this.invalidator = new Invalidator(this.manager, this.eventBus, logger);
|
|
1805
|
-
this.instanceResolver = new InstanceResolver(this.registry, this.manager, this.instantiator, this.tokenProcessor, logger, this);
|
|
1806
|
-
}
|
|
1807
|
-
getEventBus() {
|
|
1808
|
-
return this.eventBus;
|
|
1809
|
-
}
|
|
1810
|
-
getManager() {
|
|
1811
|
-
return this.manager;
|
|
1812
|
-
}
|
|
1813
|
-
getInvalidator() {
|
|
1814
|
-
return this.invalidator;
|
|
1815
|
-
}
|
|
1816
|
-
getTokenProcessor() {
|
|
1817
|
-
return this.tokenProcessor;
|
|
1818
|
-
}
|
|
1819
|
-
getInstanceIdentifier(token, args) {
|
|
1820
|
-
const [err, { actualToken, validatedArgs }] = this.tokenProcessor.validateAndResolveTokenArgs(token, args);
|
|
1821
|
-
if (err) throw err;
|
|
1822
|
-
return this.tokenProcessor.generateInstanceName(actualToken, validatedArgs);
|
|
1823
|
-
}
|
|
1824
|
-
/**
|
|
1825
|
-
* Gets or creates an instance for the given token.
|
|
1826
|
-
* @param token The injection token
|
|
1827
|
-
* @param args Optional arguments
|
|
1828
|
-
* @param contextContainer The container to use for creating FactoryContext
|
|
1829
|
-
*/ async getInstance(token, args, contextContainer) {
|
|
1830
|
-
const [err, data] = await this.instanceResolver.resolveInstance(token, args, contextContainer);
|
|
1831
|
-
if (err) return [err];
|
|
1832
|
-
return [void 0, data];
|
|
1833
|
-
}
|
|
1834
|
-
/**
|
|
1835
|
-
* Gets or throws an instance for the given token.
|
|
1836
|
-
* @param token The injection token
|
|
1837
|
-
* @param args Optional arguments
|
|
1838
|
-
* @param contextContainer The container to use for creating FactoryContext
|
|
1839
|
-
*/ async getOrThrowInstance(token, args, contextContainer) {
|
|
1840
|
-
const [error, instance] = await this.getInstance(token, args, contextContainer);
|
|
1841
|
-
if (error) throw error;
|
|
1842
|
-
return instance;
|
|
1843
|
-
}
|
|
1844
|
-
/**
|
|
1845
|
-
* Resolves a request-scoped service for a ScopedContainer.
|
|
1846
|
-
* The service will be stored in the ScopedContainer's request context.
|
|
1847
|
-
*
|
|
1848
|
-
* @param token The injection token
|
|
1849
|
-
* @param args Optional arguments
|
|
1850
|
-
* @param scopedContainer The ScopedContainer that owns the request context
|
|
1851
|
-
*/ async resolveRequestScoped(token, args, scopedContainer) {
|
|
1852
|
-
const [err, data] = await this.instanceResolver.resolveRequestScopedInstance(token, args, scopedContainer);
|
|
1853
|
-
if (err) throw err;
|
|
1854
|
-
return data;
|
|
1855
|
-
}
|
|
1856
|
-
getSyncInstance(token, args, contextContainer) {
|
|
1857
|
-
return this.instanceResolver.getSyncInstance(token, args, contextContainer);
|
|
1858
|
-
}
|
|
1859
|
-
invalidate(service, round = 1) {
|
|
1860
|
-
return this.invalidator.invalidate(service, round);
|
|
1861
|
-
}
|
|
1862
|
-
/**
|
|
1863
|
-
* Gracefully clears all services in the ServiceLocator using invalidation logic.
|
|
1864
|
-
* This method respects service dependencies and ensures proper cleanup order.
|
|
1865
|
-
* Services that depend on others will be invalidated first, then their dependencies.
|
|
1866
|
-
*
|
|
1867
|
-
* @param options Optional configuration for the clearing process
|
|
1868
|
-
* @returns Promise that resolves when all services have been cleared
|
|
1869
|
-
*/ async clearAll(options = {}) {
|
|
1870
|
-
return this.invalidator.clearAll(options);
|
|
1871
|
-
}
|
|
1872
|
-
/**
|
|
1873
|
-
* Waits for all services to settle (either created, destroyed, or error state).
|
|
1874
|
-
*/ async ready() {
|
|
1875
|
-
return this.invalidator.ready();
|
|
1876
|
-
}
|
|
1877
|
-
/**
|
|
1878
|
-
* Helper method for InstanceResolver to generate instance names.
|
|
1879
|
-
* This is needed for the factory context creation.
|
|
1880
|
-
*/ generateInstanceName(token, args) {
|
|
1881
|
-
return this.tokenProcessor.generateInstanceName(token, args);
|
|
1882
|
-
}
|
|
1883
|
-
};
|
|
1884
|
-
function applyDecs2203RFactory$5() {
|
|
1885
|
-
function createAddInitializerMethod(initializers, decoratorFinishedRef) {
|
|
1886
|
-
return function addInitializer(initializer) {
|
|
1887
|
-
assertNotFinished(decoratorFinishedRef, "addInitializer");
|
|
1888
|
-
assertCallable(initializer, "An initializer");
|
|
1889
|
-
initializers.push(initializer);
|
|
1890
|
-
};
|
|
1891
|
-
}
|
|
1892
|
-
function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
|
|
1893
|
-
var kindStr;
|
|
1894
|
-
switch (kind) {
|
|
1895
|
-
case 1:
|
|
1896
|
-
kindStr = "accessor";
|
|
1897
|
-
break;
|
|
1898
|
-
case 2:
|
|
1899
|
-
kindStr = "method";
|
|
1900
|
-
break;
|
|
1901
|
-
case 3:
|
|
1902
|
-
kindStr = "getter";
|
|
1903
|
-
break;
|
|
1904
|
-
case 4:
|
|
1905
|
-
kindStr = "setter";
|
|
1906
|
-
break;
|
|
1907
|
-
default: kindStr = "field";
|
|
1908
|
-
}
|
|
1909
|
-
var ctx = {
|
|
1910
|
-
kind: kindStr,
|
|
1911
|
-
name: isPrivate ? "#" + name : name,
|
|
1912
|
-
static: isStatic,
|
|
1913
|
-
private: isPrivate,
|
|
1914
|
-
metadata
|
|
1915
|
-
};
|
|
1916
|
-
var decoratorFinishedRef = { v: false };
|
|
1917
|
-
ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
|
|
1918
|
-
var get, set;
|
|
1919
|
-
if (kind === 0) if (isPrivate) {
|
|
1920
|
-
get = desc.get;
|
|
1921
|
-
set = desc.set;
|
|
1922
|
-
} else {
|
|
1923
|
-
get = function() {
|
|
1924
|
-
return this[name];
|
|
1925
|
-
};
|
|
1926
|
-
set = function(v) {
|
|
1927
|
-
this[name] = v;
|
|
1928
|
-
};
|
|
1929
|
-
}
|
|
1930
|
-
else if (kind === 2) get = function() {
|
|
1931
|
-
return desc.value;
|
|
1932
|
-
};
|
|
1933
|
-
else {
|
|
1934
|
-
if (kind === 1 || kind === 3) get = function() {
|
|
1935
|
-
return desc.get.call(this);
|
|
1936
|
-
};
|
|
1937
|
-
if (kind === 1 || kind === 4) set = function(v) {
|
|
1938
|
-
desc.set.call(this, v);
|
|
1939
|
-
};
|
|
1940
|
-
}
|
|
1941
|
-
ctx.access = get && set ? {
|
|
1942
|
-
get,
|
|
1943
|
-
set
|
|
1944
|
-
} : get ? { get } : { set };
|
|
1945
|
-
try {
|
|
1946
|
-
return dec(value, ctx);
|
|
1947
|
-
} finally {
|
|
1948
|
-
decoratorFinishedRef.v = true;
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
function assertNotFinished(decoratorFinishedRef, fnName) {
|
|
1952
|
-
if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
|
|
1953
|
-
}
|
|
1954
|
-
function assertCallable(fn, hint) {
|
|
1955
|
-
if (typeof fn !== "function") throw new TypeError(hint + " must be a function");
|
|
1956
|
-
}
|
|
1957
|
-
function assertValidReturnValue(kind, value) {
|
|
1958
|
-
var type = typeof value;
|
|
1959
|
-
if (kind === 1) {
|
|
1960
|
-
if (type !== "object" || value === null) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
|
1961
|
-
if (value.get !== void 0) assertCallable(value.get, "accessor.get");
|
|
1962
|
-
if (value.set !== void 0) assertCallable(value.set, "accessor.set");
|
|
1963
|
-
if (value.init !== void 0) assertCallable(value.init, "accessor.init");
|
|
1964
|
-
} else if (type !== "function") {
|
|
1965
|
-
var hint;
|
|
1966
|
-
if (kind === 0) hint = "field";
|
|
1967
|
-
else if (kind === 10) hint = "class";
|
|
1968
|
-
else hint = "method";
|
|
1969
|
-
throw new TypeError(hint + " decorators must return a function or void 0");
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
|
|
1973
|
-
var decs = decInfo[0];
|
|
1974
|
-
var desc, init, value;
|
|
1975
|
-
if (isPrivate) if (kind === 0 || kind === 1) desc = {
|
|
1976
|
-
get: decInfo[3],
|
|
1977
|
-
set: decInfo[4]
|
|
1978
|
-
};
|
|
1979
|
-
else if (kind === 3) desc = { get: decInfo[3] };
|
|
1980
|
-
else if (kind === 4) desc = { set: decInfo[3] };
|
|
1981
|
-
else desc = { value: decInfo[3] };
|
|
1982
|
-
else if (kind !== 0) desc = Object.getOwnPropertyDescriptor(base, name);
|
|
1983
|
-
if (kind === 1) value = {
|
|
1984
|
-
get: desc.get,
|
|
1985
|
-
set: desc.set
|
|
1986
|
-
};
|
|
1987
|
-
else if (kind === 2) value = desc.value;
|
|
1988
|
-
else if (kind === 3) value = desc.get;
|
|
1989
|
-
else if (kind === 4) value = desc.set;
|
|
1990
|
-
var newValue, get, set;
|
|
1991
|
-
if (typeof decs === "function") {
|
|
1992
|
-
newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
1993
|
-
if (newValue !== void 0) {
|
|
1994
|
-
assertValidReturnValue(kind, newValue);
|
|
1995
|
-
if (kind === 0) init = newValue;
|
|
1996
|
-
else if (kind === 1) {
|
|
1997
|
-
init = newValue.init;
|
|
1998
|
-
get = newValue.get || value.get;
|
|
1999
|
-
set = newValue.set || value.set;
|
|
2000
|
-
value = {
|
|
2001
|
-
get,
|
|
2002
|
-
set
|
|
2003
|
-
};
|
|
2004
|
-
} else value = newValue;
|
|
2005
|
-
}
|
|
2006
|
-
} else for (var i = decs.length - 1; i >= 0; i--) {
|
|
2007
|
-
var dec = decs[i];
|
|
2008
|
-
newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
2009
|
-
if (newValue !== void 0) {
|
|
2010
|
-
assertValidReturnValue(kind, newValue);
|
|
2011
|
-
var newInit;
|
|
2012
|
-
if (kind === 0) newInit = newValue;
|
|
2013
|
-
else if (kind === 1) {
|
|
2014
|
-
newInit = newValue.init;
|
|
2015
|
-
get = newValue.get || value.get;
|
|
2016
|
-
set = newValue.set || value.set;
|
|
2017
|
-
value = {
|
|
2018
|
-
get,
|
|
2019
|
-
set
|
|
2020
|
-
};
|
|
2021
|
-
} else value = newValue;
|
|
2022
|
-
if (newInit !== void 0) if (init === void 0) init = newInit;
|
|
2023
|
-
else if (typeof init === "function") init = [init, newInit];
|
|
2024
|
-
else init.push(newInit);
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
if (kind === 0 || kind === 1) {
|
|
2028
|
-
if (init === void 0) init = function(instance, init$1) {
|
|
2029
|
-
return init$1;
|
|
2030
|
-
};
|
|
2031
|
-
else if (typeof init !== "function") {
|
|
2032
|
-
var ownInitializers = init;
|
|
2033
|
-
init = function(instance, init$1) {
|
|
2034
|
-
var value$1 = init$1;
|
|
2035
|
-
for (var i$1 = 0; i$1 < ownInitializers.length; i$1++) value$1 = ownInitializers[i$1].call(instance, value$1);
|
|
2036
|
-
return value$1;
|
|
2037
|
-
};
|
|
2038
|
-
} else {
|
|
2039
|
-
var originalInitializer = init;
|
|
2040
|
-
init = function(instance, init$1) {
|
|
2041
|
-
return originalInitializer.call(instance, init$1);
|
|
2042
|
-
};
|
|
2043
|
-
}
|
|
2044
|
-
ret.push(init);
|
|
2045
|
-
}
|
|
2046
|
-
if (kind !== 0) {
|
|
2047
|
-
if (kind === 1) {
|
|
2048
|
-
desc.get = value.get;
|
|
2049
|
-
desc.set = value.set;
|
|
2050
|
-
} else if (kind === 2) desc.value = value;
|
|
2051
|
-
else if (kind === 3) desc.get = value;
|
|
2052
|
-
else if (kind === 4) desc.set = value;
|
|
2053
|
-
if (isPrivate) if (kind === 1) {
|
|
2054
|
-
ret.push(function(instance, args) {
|
|
2055
|
-
return value.get.call(instance, args);
|
|
2056
|
-
});
|
|
2057
|
-
ret.push(function(instance, args) {
|
|
2058
|
-
return value.set.call(instance, args);
|
|
2059
|
-
});
|
|
2060
|
-
} else if (kind === 2) ret.push(value);
|
|
2061
|
-
else ret.push(function(instance, args) {
|
|
2062
|
-
return value.call(instance, args);
|
|
2063
|
-
});
|
|
2064
|
-
else Object.defineProperty(base, name, desc);
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
function applyMemberDecs(Class, decInfos, metadata) {
|
|
2068
|
-
var ret = [];
|
|
2069
|
-
var protoInitializers;
|
|
2070
|
-
var staticInitializers;
|
|
2071
|
-
var existingProtoNonFields = /* @__PURE__ */ new Map();
|
|
2072
|
-
var existingStaticNonFields = /* @__PURE__ */ new Map();
|
|
2073
|
-
for (var i = 0; i < decInfos.length; i++) {
|
|
2074
|
-
var decInfo = decInfos[i];
|
|
2075
|
-
if (!Array.isArray(decInfo)) continue;
|
|
2076
|
-
var kind = decInfo[1];
|
|
2077
|
-
var name = decInfo[2];
|
|
2078
|
-
var isPrivate = decInfo.length > 3;
|
|
2079
|
-
var isStatic = kind >= 5;
|
|
2080
|
-
var base;
|
|
2081
|
-
var initializers;
|
|
2082
|
-
if (isStatic) {
|
|
2083
|
-
base = Class;
|
|
2084
|
-
kind = kind - 5;
|
|
2085
|
-
staticInitializers = staticInitializers || [];
|
|
2086
|
-
initializers = staticInitializers;
|
|
2087
|
-
} else {
|
|
2088
|
-
base = Class.prototype;
|
|
2089
|
-
protoInitializers = protoInitializers || [];
|
|
2090
|
-
initializers = protoInitializers;
|
|
2091
|
-
}
|
|
2092
|
-
if (kind !== 0 && !isPrivate) {
|
|
2093
|
-
var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
|
|
2094
|
-
var existingKind = existingNonFields.get(name) || 0;
|
|
2095
|
-
if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
|
|
2096
|
-
else if (!existingKind && kind > 2) existingNonFields.set(name, kind);
|
|
2097
|
-
else existingNonFields.set(name, true);
|
|
2098
|
-
}
|
|
2099
|
-
applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
|
|
2100
|
-
}
|
|
2101
|
-
pushInitializers(ret, protoInitializers);
|
|
2102
|
-
pushInitializers(ret, staticInitializers);
|
|
2103
|
-
return ret;
|
|
2104
|
-
}
|
|
2105
|
-
function pushInitializers(ret, initializers) {
|
|
2106
|
-
if (initializers) ret.push(function(instance) {
|
|
2107
|
-
for (var i = 0; i < initializers.length; i++) initializers[i].call(instance);
|
|
2108
|
-
return instance;
|
|
2109
|
-
});
|
|
2110
|
-
}
|
|
2111
|
-
function applyClassDecs(targetClass, classDecs, metadata) {
|
|
2112
|
-
if (classDecs.length > 0) {
|
|
2113
|
-
var initializers = [];
|
|
2114
|
-
var newClass = targetClass;
|
|
2115
|
-
var name = targetClass.name;
|
|
2116
|
-
for (var i = classDecs.length - 1; i >= 0; i--) {
|
|
2117
|
-
var decoratorFinishedRef = { v: false };
|
|
2118
|
-
try {
|
|
2119
|
-
var nextNewClass = classDecs[i](newClass, {
|
|
2120
|
-
kind: "class",
|
|
2121
|
-
name,
|
|
2122
|
-
addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
|
|
2123
|
-
metadata
|
|
2124
|
-
});
|
|
2125
|
-
} finally {
|
|
2126
|
-
decoratorFinishedRef.v = true;
|
|
2127
|
-
}
|
|
2128
|
-
if (nextNewClass !== void 0) {
|
|
2129
|
-
assertValidReturnValue(10, nextNewClass);
|
|
2130
|
-
newClass = nextNewClass;
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
return [defineMetadata(newClass, metadata), function() {
|
|
2134
|
-
for (var i$1 = 0; i$1 < initializers.length; i$1++) initializers[i$1].call(newClass);
|
|
2135
|
-
}];
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
function defineMetadata(Class, metadata) {
|
|
2139
|
-
return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
|
|
2140
|
-
configurable: true,
|
|
2141
|
-
enumerable: true,
|
|
2142
|
-
value: metadata
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
|
|
2146
|
-
if (parentClass !== void 0) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
|
|
2147
|
-
var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
|
|
2148
|
-
var e = applyMemberDecs(targetClass, memberDecs, metadata);
|
|
2149
|
-
if (!classDecs.length) defineMetadata(targetClass, metadata);
|
|
2150
|
-
return {
|
|
2151
|
-
e,
|
|
2152
|
-
get c() {
|
|
2153
|
-
return applyClassDecs(targetClass, classDecs, metadata);
|
|
2154
|
-
}
|
|
2155
|
-
};
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2158
|
-
function _apply_decs_2203_r$5(targetClass, memberDecs, classDecs, parentClass) {
|
|
2159
|
-
return (_apply_decs_2203_r$5 = applyDecs2203RFactory$5())(targetClass, memberDecs, classDecs, parentClass);
|
|
2160
|
-
}
|
|
2161
|
-
var _dec$2, _initClass$2;
|
|
2162
|
-
let _Container;
|
|
2163
|
-
_dec$2 = Injectable$1();
|
|
2164
|
-
(class {
|
|
2165
|
-
registry;
|
|
2166
|
-
logger;
|
|
2167
|
-
injectors;
|
|
2168
|
-
static {
|
|
2169
|
-
({c: [_Container, _initClass$2]} = _apply_decs_2203_r$5(this, [], [_dec$2]));
|
|
2170
|
-
}
|
|
2171
|
-
constructor(registry = globalRegistry, logger = null, injectors = defaultInjectors) {
|
|
2172
|
-
this.registry = registry;
|
|
2173
|
-
this.logger = logger;
|
|
2174
|
-
this.injectors = injectors;
|
|
2175
|
-
this.serviceLocator = new ServiceLocator(registry, logger, injectors);
|
|
2176
|
-
this.registerSelf();
|
|
2177
|
-
}
|
|
2178
|
-
serviceLocator;
|
|
2179
|
-
activeRequestIds = /* @__PURE__ */ new Set();
|
|
2180
|
-
registerSelf() {
|
|
2181
|
-
const token = getInjectableToken(_Container);
|
|
2182
|
-
const instanceName = this.serviceLocator.getInstanceIdentifier(token);
|
|
2183
|
-
this.serviceLocator.getManager().storeCreatedHolder(instanceName, this, InjectableType.Class, InjectableScope.Singleton);
|
|
2184
|
-
}
|
|
2185
|
-
async get(token, args) {
|
|
2186
|
-
const realToken = this.serviceLocator.getTokenProcessor().getRegistryToken(token);
|
|
2187
|
-
if (this.registry.has(realToken)) {
|
|
2188
|
-
if (this.registry.get(realToken).scope === InjectableScope.Request) throw DIError.unknown(`Cannot resolve request-scoped service "${String(realToken.name)}" from Container. Use beginRequest() to create a ScopedContainer for request-scoped services.`);
|
|
2189
|
-
}
|
|
2190
|
-
return this.serviceLocator.getOrThrowInstance(token, args, this);
|
|
2191
|
-
}
|
|
2192
|
-
/**
|
|
2193
|
-
* Gets an instance with a specific container context.
|
|
2194
|
-
* Used by ScopedContainer to delegate singleton/transient resolution
|
|
2195
|
-
* while maintaining the correct container context for nested inject() calls.
|
|
2196
|
-
*
|
|
2197
|
-
* @internal
|
|
2198
|
-
*/ async getWithContext(token, args, contextContainer) {
|
|
2199
|
-
return this.serviceLocator.getOrThrowInstance(token, args, contextContainer);
|
|
2200
|
-
}
|
|
2201
|
-
/**
|
|
2202
|
-
* Resolves a request-scoped service for a ScopedContainer.
|
|
2203
|
-
* The service will be stored in the ScopedContainer's request context.
|
|
2204
|
-
*
|
|
2205
|
-
* @internal
|
|
2206
|
-
*/ async resolveForRequest(token, args, scopedContainer) {
|
|
2207
|
-
return this.serviceLocator.resolveRequestScoped(token, args, scopedContainer);
|
|
2208
|
-
}
|
|
2209
|
-
/**
|
|
2210
|
-
* Gets the underlying ServiceLocator instance for advanced usage
|
|
2211
|
-
*/ getServiceLocator() {
|
|
2212
|
-
return this.serviceLocator;
|
|
2213
|
-
}
|
|
2214
|
-
/**
|
|
2215
|
-
* Gets the registry
|
|
2216
|
-
*/ getRegistry() {
|
|
2217
|
-
return this.registry;
|
|
2218
|
-
}
|
|
2219
|
-
/**
|
|
2220
|
-
* Invalidates a service and its dependencies
|
|
2221
|
-
*/ async invalidate(service) {
|
|
2222
|
-
const holder = this.getHolderByInstance(service);
|
|
2223
|
-
if (holder) await this.serviceLocator.invalidate(holder.name);
|
|
2224
|
-
}
|
|
2225
|
-
/**
|
|
2226
|
-
* Gets a service holder by instance (reverse lookup)
|
|
2227
|
-
*/ getHolderByInstance(instance) {
|
|
2228
|
-
const holderMap = Array.from(this.serviceLocator.getManager().filter((holder) => holder.instance === instance).values());
|
|
2229
|
-
return holderMap.length > 0 ? holderMap[0] : null;
|
|
2230
|
-
}
|
|
2231
|
-
/**
|
|
2232
|
-
* Checks if a service is registered in the container
|
|
2233
|
-
*/ isRegistered(token) {
|
|
2234
|
-
try {
|
|
2235
|
-
return this.serviceLocator.getInstanceIdentifier(token) !== null;
|
|
2236
|
-
} catch {
|
|
2237
|
-
return false;
|
|
2238
|
-
}
|
|
2239
|
-
}
|
|
2240
|
-
/**
|
|
2241
|
-
* Disposes the container and cleans up all resources
|
|
2242
|
-
*/ async dispose() {
|
|
2243
|
-
await this.serviceLocator.clearAll();
|
|
2244
|
-
}
|
|
2245
|
-
/**
|
|
2246
|
-
* Waits for all pending operations to complete
|
|
2247
|
-
*/ async ready() {
|
|
2248
|
-
await this.serviceLocator.ready();
|
|
2249
|
-
}
|
|
2250
|
-
/**
|
|
2251
|
-
* @internal
|
|
2252
|
-
* Attempts to get an instance synchronously if it already exists.
|
|
2253
|
-
* Returns null if the instance doesn't exist or is not ready.
|
|
2254
|
-
*/ tryGetSync(token, args) {
|
|
2255
|
-
return this.serviceLocator.getSyncInstance(token, args, this);
|
|
2256
|
-
}
|
|
2257
|
-
/**
|
|
2258
|
-
* Begins a new request context and returns a ScopedContainer.
|
|
2259
|
-
*
|
|
2260
|
-
* The ScopedContainer provides isolated request-scoped service resolution
|
|
2261
|
-
* while delegating singleton and transient services to this Container.
|
|
2262
|
-
*
|
|
2263
|
-
* @param requestId Unique identifier for this request
|
|
2264
|
-
* @param metadata Optional metadata for the request
|
|
2265
|
-
* @param priority Priority for resolution (higher = more priority)
|
|
2266
|
-
* @returns A ScopedContainer for this request
|
|
2267
|
-
*/ beginRequest(requestId, metadata, priority = 100) {
|
|
2268
|
-
if (this.activeRequestIds.has(requestId)) throw DIError.unknown(`Request context "${requestId}" already exists. Use a unique request ID.`);
|
|
2269
|
-
this.activeRequestIds.add(requestId);
|
|
2270
|
-
this.logger?.log(`[Container] Started request context: ${requestId}`);
|
|
2271
|
-
return new ScopedContainer(this, this.registry, requestId, metadata, priority);
|
|
2272
|
-
}
|
|
2273
|
-
/**
|
|
2274
|
-
* Removes a request ID from the active set.
|
|
2275
|
-
* Called by ScopedContainer when the request ends.
|
|
2276
|
-
*
|
|
2277
|
-
* @internal
|
|
2278
|
-
*/ removeActiveRequest(requestId) {
|
|
2279
|
-
this.activeRequestIds.delete(requestId);
|
|
2280
|
-
this.logger?.log(`[Container] Ended request context: ${requestId}`);
|
|
2281
|
-
}
|
|
2282
|
-
/**
|
|
2283
|
-
* Gets the set of active request IDs.
|
|
2284
|
-
*/ getActiveRequestIds() {
|
|
2285
|
-
return this.activeRequestIds;
|
|
2286
|
-
}
|
|
2287
|
-
/**
|
|
2288
|
-
* Checks if a request ID is currently active.
|
|
2289
|
-
*/ hasActiveRequest(requestId) {
|
|
2290
|
-
return this.activeRequestIds.has(requestId);
|
|
2291
|
-
}
|
|
2292
|
-
/**
|
|
2293
|
-
* Clears all instances and bindings from the container.
|
|
2294
|
-
* This is useful for testing or resetting the container state.
|
|
2295
|
-
*/ clear() {
|
|
2296
|
-
return this.serviceLocator.clearAll();
|
|
2297
|
-
}
|
|
2298
|
-
static {
|
|
2299
|
-
_initClass$2();
|
|
2300
|
-
}
|
|
2301
|
-
});
|
|
2302
|
-
|
|
2303
|
-
//#endregion
|
|
2304
|
-
//#region ../di/lib/index.mjs
|
|
2305
|
-
function applyDecs2203RFactory$4() {
|
|
2306
|
-
function createAddInitializerMethod(initializers, decoratorFinishedRef) {
|
|
2307
|
-
return function addInitializer(initializer) {
|
|
2308
|
-
assertNotFinished(decoratorFinishedRef, "addInitializer");
|
|
2309
|
-
assertCallable(initializer, "An initializer");
|
|
2310
|
-
initializers.push(initializer);
|
|
2311
|
-
};
|
|
2312
|
-
}
|
|
2313
|
-
function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
|
|
2314
|
-
var kindStr;
|
|
2315
|
-
switch (kind) {
|
|
2316
|
-
case 1:
|
|
2317
|
-
kindStr = "accessor";
|
|
2318
|
-
break;
|
|
2319
|
-
case 2:
|
|
2320
|
-
kindStr = "method";
|
|
2321
|
-
break;
|
|
2322
|
-
case 3:
|
|
2323
|
-
kindStr = "getter";
|
|
2324
|
-
break;
|
|
2325
|
-
case 4:
|
|
2326
|
-
kindStr = "setter";
|
|
2327
|
-
break;
|
|
2328
|
-
default: kindStr = "field";
|
|
2329
|
-
}
|
|
2330
|
-
var ctx = {
|
|
2331
|
-
kind: kindStr,
|
|
2332
|
-
name: isPrivate ? "#" + name : name,
|
|
2333
|
-
static: isStatic,
|
|
2334
|
-
private: isPrivate,
|
|
2335
|
-
metadata
|
|
2336
|
-
};
|
|
2337
|
-
var decoratorFinishedRef = { v: false };
|
|
2338
|
-
ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
|
|
2339
|
-
var get, set;
|
|
2340
|
-
if (kind === 0) if (isPrivate) {
|
|
2341
|
-
get = desc.get;
|
|
2342
|
-
set = desc.set;
|
|
2343
|
-
} else {
|
|
2344
|
-
get = function() {
|
|
2345
|
-
return this[name];
|
|
2346
|
-
};
|
|
2347
|
-
set = function(v) {
|
|
2348
|
-
this[name] = v;
|
|
2349
|
-
};
|
|
2350
|
-
}
|
|
2351
|
-
else if (kind === 2) get = function() {
|
|
2352
|
-
return desc.value;
|
|
2353
|
-
};
|
|
2354
|
-
else {
|
|
2355
|
-
if (kind === 1 || kind === 3) get = function() {
|
|
2356
|
-
return desc.get.call(this);
|
|
2357
|
-
};
|
|
2358
|
-
if (kind === 1 || kind === 4) set = function(v) {
|
|
2359
|
-
desc.set.call(this, v);
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
ctx.access = get && set ? {
|
|
2363
|
-
get,
|
|
2364
|
-
set
|
|
2365
|
-
} : get ? { get } : { set };
|
|
2366
|
-
try {
|
|
2367
|
-
return dec(value, ctx);
|
|
2368
|
-
} finally {
|
|
2369
|
-
decoratorFinishedRef.v = true;
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
function assertNotFinished(decoratorFinishedRef, fnName) {
|
|
2373
|
-
if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
|
|
2374
|
-
}
|
|
2375
|
-
function assertCallable(fn, hint) {
|
|
2376
|
-
if (typeof fn !== "function") throw new TypeError(hint + " must be a function");
|
|
2377
|
-
}
|
|
2378
|
-
function assertValidReturnValue(kind, value) {
|
|
2379
|
-
var type = typeof value;
|
|
2380
|
-
if (kind === 1) {
|
|
2381
|
-
if (type !== "object" || value === null) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
|
2382
|
-
if (value.get !== void 0) assertCallable(value.get, "accessor.get");
|
|
2383
|
-
if (value.set !== void 0) assertCallable(value.set, "accessor.set");
|
|
2384
|
-
if (value.init !== void 0) assertCallable(value.init, "accessor.init");
|
|
2385
|
-
} else if (type !== "function") {
|
|
2386
|
-
var hint;
|
|
2387
|
-
if (kind === 0) hint = "field";
|
|
2388
|
-
else if (kind === 10) hint = "class";
|
|
2389
|
-
else hint = "method";
|
|
2390
|
-
throw new TypeError(hint + " decorators must return a function or void 0");
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
|
|
2394
|
-
var decs = decInfo[0];
|
|
2395
|
-
var desc, init, value;
|
|
2396
|
-
if (isPrivate) if (kind === 0 || kind === 1) desc = {
|
|
2397
|
-
get: decInfo[3],
|
|
2398
|
-
set: decInfo[4]
|
|
2399
|
-
};
|
|
2400
|
-
else if (kind === 3) desc = { get: decInfo[3] };
|
|
2401
|
-
else if (kind === 4) desc = { set: decInfo[3] };
|
|
2402
|
-
else desc = { value: decInfo[3] };
|
|
2403
|
-
else if (kind !== 0) desc = Object.getOwnPropertyDescriptor(base, name);
|
|
2404
|
-
if (kind === 1) value = {
|
|
2405
|
-
get: desc.get,
|
|
2406
|
-
set: desc.set
|
|
2407
|
-
};
|
|
2408
|
-
else if (kind === 2) value = desc.value;
|
|
2409
|
-
else if (kind === 3) value = desc.get;
|
|
2410
|
-
else if (kind === 4) value = desc.set;
|
|
2411
|
-
var newValue, get, set;
|
|
2412
|
-
if (typeof decs === "function") {
|
|
2413
|
-
newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
2414
|
-
if (newValue !== void 0) {
|
|
2415
|
-
assertValidReturnValue(kind, newValue);
|
|
2416
|
-
if (kind === 0) init = newValue;
|
|
2417
|
-
else if (kind === 1) {
|
|
2418
|
-
init = newValue.init;
|
|
2419
|
-
get = newValue.get || value.get;
|
|
2420
|
-
set = newValue.set || value.set;
|
|
2421
|
-
value = {
|
|
2422
|
-
get,
|
|
2423
|
-
set
|
|
2424
|
-
};
|
|
2425
|
-
} else value = newValue;
|
|
2426
|
-
}
|
|
2427
|
-
} else for (var i = decs.length - 1; i >= 0; i--) {
|
|
2428
|
-
var dec = decs[i];
|
|
2429
|
-
newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
2430
|
-
if (newValue !== void 0) {
|
|
2431
|
-
assertValidReturnValue(kind, newValue);
|
|
2432
|
-
var newInit;
|
|
2433
|
-
if (kind === 0) newInit = newValue;
|
|
2434
|
-
else if (kind === 1) {
|
|
2435
|
-
newInit = newValue.init;
|
|
2436
|
-
get = newValue.get || value.get;
|
|
2437
|
-
set = newValue.set || value.set;
|
|
2438
|
-
value = {
|
|
2439
|
-
get,
|
|
2440
|
-
set
|
|
2441
|
-
};
|
|
2442
|
-
} else value = newValue;
|
|
2443
|
-
if (newInit !== void 0) if (init === void 0) init = newInit;
|
|
2444
|
-
else if (typeof init === "function") init = [init, newInit];
|
|
2445
|
-
else init.push(newInit);
|
|
2446
|
-
}
|
|
2447
|
-
}
|
|
2448
|
-
if (kind === 0 || kind === 1) {
|
|
2449
|
-
if (init === void 0) init = function(instance, init$1) {
|
|
2450
|
-
return init$1;
|
|
2451
|
-
};
|
|
2452
|
-
else if (typeof init !== "function") {
|
|
2453
|
-
var ownInitializers = init;
|
|
2454
|
-
init = function(instance, init$1) {
|
|
2455
|
-
var value$1 = init$1;
|
|
2456
|
-
for (var i$1 = 0; i$1 < ownInitializers.length; i$1++) value$1 = ownInitializers[i$1].call(instance, value$1);
|
|
2457
|
-
return value$1;
|
|
2458
|
-
};
|
|
2459
|
-
} else {
|
|
2460
|
-
var originalInitializer = init;
|
|
2461
|
-
init = function(instance, init$1) {
|
|
2462
|
-
return originalInitializer.call(instance, init$1);
|
|
2463
|
-
};
|
|
2464
|
-
}
|
|
2465
|
-
ret.push(init);
|
|
2466
|
-
}
|
|
2467
|
-
if (kind !== 0) {
|
|
2468
|
-
if (kind === 1) {
|
|
2469
|
-
desc.get = value.get;
|
|
2470
|
-
desc.set = value.set;
|
|
2471
|
-
} else if (kind === 2) desc.value = value;
|
|
2472
|
-
else if (kind === 3) desc.get = value;
|
|
2473
|
-
else if (kind === 4) desc.set = value;
|
|
2474
|
-
if (isPrivate) if (kind === 1) {
|
|
2475
|
-
ret.push(function(instance, args) {
|
|
2476
|
-
return value.get.call(instance, args);
|
|
2477
|
-
});
|
|
2478
|
-
ret.push(function(instance, args) {
|
|
2479
|
-
return value.set.call(instance, args);
|
|
2480
|
-
});
|
|
2481
|
-
} else if (kind === 2) ret.push(value);
|
|
2482
|
-
else ret.push(function(instance, args) {
|
|
2483
|
-
return value.call(instance, args);
|
|
2484
|
-
});
|
|
2485
|
-
else Object.defineProperty(base, name, desc);
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
function applyMemberDecs(Class, decInfos, metadata) {
|
|
2489
|
-
var ret = [];
|
|
2490
|
-
var protoInitializers;
|
|
2491
|
-
var staticInitializers;
|
|
2492
|
-
var existingProtoNonFields = /* @__PURE__ */ new Map();
|
|
2493
|
-
var existingStaticNonFields = /* @__PURE__ */ new Map();
|
|
2494
|
-
for (var i = 0; i < decInfos.length; i++) {
|
|
2495
|
-
var decInfo = decInfos[i];
|
|
2496
|
-
if (!Array.isArray(decInfo)) continue;
|
|
2497
|
-
var kind = decInfo[1];
|
|
2498
|
-
var name = decInfo[2];
|
|
2499
|
-
var isPrivate = decInfo.length > 3;
|
|
2500
|
-
var isStatic = kind >= 5;
|
|
2501
|
-
var base;
|
|
2502
|
-
var initializers;
|
|
2503
|
-
if (isStatic) {
|
|
2504
|
-
base = Class;
|
|
2505
|
-
kind = kind - 5;
|
|
2506
|
-
staticInitializers = staticInitializers || [];
|
|
2507
|
-
initializers = staticInitializers;
|
|
2508
|
-
} else {
|
|
2509
|
-
base = Class.prototype;
|
|
2510
|
-
protoInitializers = protoInitializers || [];
|
|
2511
|
-
initializers = protoInitializers;
|
|
2512
|
-
}
|
|
2513
|
-
if (kind !== 0 && !isPrivate) {
|
|
2514
|
-
var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
|
|
2515
|
-
var existingKind = existingNonFields.get(name) || 0;
|
|
2516
|
-
if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
|
|
2517
|
-
else if (!existingKind && kind > 2) existingNonFields.set(name, kind);
|
|
2518
|
-
else existingNonFields.set(name, true);
|
|
2519
|
-
}
|
|
2520
|
-
applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
|
|
2521
|
-
}
|
|
2522
|
-
pushInitializers(ret, protoInitializers);
|
|
2523
|
-
pushInitializers(ret, staticInitializers);
|
|
2524
|
-
return ret;
|
|
2525
|
-
}
|
|
2526
|
-
function pushInitializers(ret, initializers) {
|
|
2527
|
-
if (initializers) ret.push(function(instance) {
|
|
2528
|
-
for (var i = 0; i < initializers.length; i++) initializers[i].call(instance);
|
|
2529
|
-
return instance;
|
|
2530
|
-
});
|
|
2531
|
-
}
|
|
2532
|
-
function applyClassDecs(targetClass, classDecs, metadata) {
|
|
2533
|
-
if (classDecs.length > 0) {
|
|
2534
|
-
var initializers = [];
|
|
2535
|
-
var newClass = targetClass;
|
|
2536
|
-
var name = targetClass.name;
|
|
2537
|
-
for (var i = classDecs.length - 1; i >= 0; i--) {
|
|
2538
|
-
var decoratorFinishedRef = { v: false };
|
|
2539
|
-
try {
|
|
2540
|
-
var nextNewClass = classDecs[i](newClass, {
|
|
2541
|
-
kind: "class",
|
|
2542
|
-
name,
|
|
2543
|
-
addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
|
|
2544
|
-
metadata
|
|
2545
|
-
});
|
|
2546
|
-
} finally {
|
|
2547
|
-
decoratorFinishedRef.v = true;
|
|
2548
|
-
}
|
|
2549
|
-
if (nextNewClass !== void 0) {
|
|
2550
|
-
assertValidReturnValue(10, nextNewClass);
|
|
2551
|
-
newClass = nextNewClass;
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
return [defineMetadata(newClass, metadata), function() {
|
|
2555
|
-
for (var i$1 = 0; i$1 < initializers.length; i$1++) initializers[i$1].call(newClass);
|
|
2556
|
-
}];
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
function defineMetadata(Class, metadata) {
|
|
2560
|
-
return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
|
|
2561
|
-
configurable: true,
|
|
2562
|
-
enumerable: true,
|
|
2563
|
-
value: metadata
|
|
2564
|
-
});
|
|
2565
|
-
}
|
|
2566
|
-
return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
|
|
2567
|
-
if (parentClass !== void 0) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
|
|
2568
|
-
var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
|
|
2569
|
-
var e = applyMemberDecs(targetClass, memberDecs, metadata);
|
|
2570
|
-
if (!classDecs.length) defineMetadata(targetClass, metadata);
|
|
2571
|
-
return {
|
|
2572
|
-
e,
|
|
2573
|
-
get c() {
|
|
2574
|
-
return applyClassDecs(targetClass, classDecs, metadata);
|
|
2575
|
-
}
|
|
2576
|
-
};
|
|
2577
|
-
};
|
|
2578
|
-
}
|
|
2579
|
-
function _apply_decs_2203_r$4(targetClass, memberDecs, classDecs, parentClass) {
|
|
2580
|
-
return (_apply_decs_2203_r$4 = applyDecs2203RFactory$4())(targetClass, memberDecs, classDecs, parentClass);
|
|
2581
|
-
}
|
|
2582
|
-
var _dec$1, _initClass$1;
|
|
2583
|
-
let _EventEmitter;
|
|
2584
|
-
_dec$1 = Injectable$1({ scope: InjectableScope.Transient });
|
|
2585
|
-
(class {
|
|
2586
|
-
static {
|
|
2587
|
-
({c: [_EventEmitter, _initClass$1]} = _apply_decs_2203_r$4(this, [], [_dec$1]));
|
|
2588
|
-
}
|
|
2589
|
-
listeners = /* @__PURE__ */ new Map();
|
|
2590
|
-
on(event, listener) {
|
|
2591
|
-
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
2592
|
-
this.listeners.get(event).add(listener);
|
|
2593
|
-
return () => {
|
|
2594
|
-
this.off(event, listener);
|
|
2595
|
-
};
|
|
2596
|
-
}
|
|
2597
|
-
off(event, listener) {
|
|
2598
|
-
if (!this.listeners.has(event)) return;
|
|
2599
|
-
this.listeners.get(event).delete(listener);
|
|
2600
|
-
if (this.listeners.get(event).size === 0) this.listeners.delete(event);
|
|
2601
|
-
}
|
|
2602
|
-
once(event, listener) {
|
|
2603
|
-
const off = this.on(event, (...args) => {
|
|
2604
|
-
off();
|
|
2605
|
-
listener(...args);
|
|
2606
|
-
});
|
|
2607
|
-
return off;
|
|
2608
|
-
}
|
|
2609
|
-
async emit(event, ...args) {
|
|
2610
|
-
if (!this.listeners.has(event)) return;
|
|
2611
|
-
return Promise.all(Array.from(this.listeners.get(event)).map((listener) => listener(...args)));
|
|
2612
|
-
}
|
|
2613
|
-
static {
|
|
2614
|
-
_initClass$1();
|
|
2615
|
-
}
|
|
2616
|
-
});
|
|
2617
|
-
|
|
2618
|
-
//#endregion
|
|
2619
8
|
//#region src/tokens/openapi-options.token.mts
|
|
2620
9
|
/**
|
|
2621
10
|
* Injection token for OpenAPI plugin options.
|
|
@@ -3243,28 +632,28 @@ function _apply_decs_2203_r$2(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
3243
632
|
* @param jsonPath - The path to serve the OpenAPI JSON (e.g., '/openapi.json')
|
|
3244
633
|
* @returns A controller class that serves the OpenAPI document as JSON
|
|
3245
634
|
*/ function createOpenApiJsonController(jsonPath) {
|
|
3246
|
-
var _dec$
|
|
635
|
+
var _dec$1, _dec1, _initClass$1, _dec2, _initProto;
|
|
3247
636
|
const endpoint = (0, _navios_builder.builder)().declareEndpoint({
|
|
3248
637
|
method: "GET",
|
|
3249
638
|
url: jsonPath,
|
|
3250
639
|
responseSchema: openApiDocumentSchema
|
|
3251
640
|
});
|
|
3252
641
|
let _OpenApiJsonController;
|
|
3253
|
-
_dec$
|
|
642
|
+
_dec$1 = (0, _navios_openapi.ApiExclude)(), _dec1 = (0, _navios_core.Controller)(), _dec2 = (0, _navios_core.Endpoint)(endpoint);
|
|
3254
643
|
class OpenApiJsonController {
|
|
3255
644
|
static {
|
|
3256
|
-
({e: [_initProto], c: [_OpenApiJsonController, _initClass$
|
|
645
|
+
({e: [_initProto], c: [_OpenApiJsonController, _initClass$1]} = _apply_decs_2203_r$2(this, [[
|
|
3257
646
|
_dec2,
|
|
3258
647
|
2,
|
|
3259
648
|
"getJson"
|
|
3260
|
-
]], [_dec$
|
|
649
|
+
]], [_dec$1, _dec1]));
|
|
3261
650
|
}
|
|
3262
651
|
documentService = (_initProto(this), (0, _navios_core.inject)(OpenApiDocumentServiceToken));
|
|
3263
|
-
async getJson(
|
|
652
|
+
async getJson() {
|
|
3264
653
|
return this.documentService.getDocument();
|
|
3265
654
|
}
|
|
3266
655
|
static {
|
|
3267
|
-
_initClass$
|
|
656
|
+
_initClass$1();
|
|
3268
657
|
}
|
|
3269
658
|
}
|
|
3270
659
|
return _OpenApiJsonController;
|
|
@@ -3556,24 +945,24 @@ function _apply_decs_2203_r$1(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
3556
945
|
* @param jsonPath - The path to the OpenAPI JSON spec (used by Scalar to load the spec)
|
|
3557
946
|
* @returns A controller class that serves the Scalar API Reference UI
|
|
3558
947
|
*/ function createOpenApiUiController(docsPath, jsonPath) {
|
|
3559
|
-
var _dec$
|
|
948
|
+
var _dec$1, _dec1, _initClass$1, _dec2, _dec3, _initProto;
|
|
3560
949
|
const endpoint = (0, _navios_builder.builder)().declareStream({
|
|
3561
950
|
method: "GET",
|
|
3562
951
|
url: docsPath
|
|
3563
952
|
});
|
|
3564
953
|
let _OpenApiUiController;
|
|
3565
|
-
_dec$
|
|
954
|
+
_dec$1 = (0, _navios_openapi.ApiExclude)(), _dec1 = (0, _navios_core.Controller)(), _dec2 = (0, _navios_core.Stream)(endpoint), _dec3 = (0, _navios_openapi.ApiStream)({ contentType: "text/html" });
|
|
3566
955
|
class OpenApiUiController {
|
|
3567
956
|
static {
|
|
3568
|
-
({e: [_initProto], c: [_OpenApiUiController, _initClass$
|
|
957
|
+
({e: [_initProto], c: [_OpenApiUiController, _initClass$1]} = _apply_decs_2203_r$1(this, [[
|
|
3569
958
|
[_dec2, _dec3],
|
|
3570
959
|
2,
|
|
3571
960
|
"getUi"
|
|
3572
|
-
]], [_dec$
|
|
961
|
+
]], [_dec$1, _dec1]));
|
|
3573
962
|
}
|
|
3574
963
|
options = (_initProto(this), (0, _navios_core.inject)(OpenApiOptionsToken));
|
|
3575
964
|
html = null;
|
|
3576
|
-
async getUi(
|
|
965
|
+
async getUi() {
|
|
3577
966
|
if (!this.html) this.html = this.generateHtml();
|
|
3578
967
|
return new Response(this.html, { headers: { "Content-Type": "text/html; charset=utf-8" } });
|
|
3579
968
|
}
|
|
@@ -3592,7 +981,7 @@ function _apply_decs_2203_r$1(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
3592
981
|
});
|
|
3593
982
|
}
|
|
3594
983
|
static {
|
|
3595
|
-
_initClass$
|
|
984
|
+
_initClass$1();
|
|
3596
985
|
}
|
|
3597
986
|
}
|
|
3598
987
|
return _OpenApiUiController;
|
|
@@ -3884,28 +1273,28 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
3884
1273
|
* @param yamlPath - The path to serve the OpenAPI YAML (e.g., '/openapi.yaml')
|
|
3885
1274
|
* @returns A controller class that serves the OpenAPI document as YAML
|
|
3886
1275
|
*/ function createOpenApiYamlController(yamlPath) {
|
|
3887
|
-
var _dec$
|
|
1276
|
+
var _dec$1, _dec1, _initClass$1, _dec2, _dec3, _initProto;
|
|
3888
1277
|
const endpoint = (0, _navios_builder.builder)().declareStream({
|
|
3889
1278
|
method: "GET",
|
|
3890
1279
|
url: yamlPath
|
|
3891
1280
|
});
|
|
3892
1281
|
let _OpenApiYamlController;
|
|
3893
|
-
_dec$
|
|
1282
|
+
_dec$1 = (0, _navios_openapi.ApiExclude)(), _dec1 = (0, _navios_core.Controller)(), _dec2 = (0, _navios_core.Stream)(endpoint), _dec3 = (0, _navios_openapi.ApiStream)({ contentType: "text/yaml" });
|
|
3894
1283
|
class OpenApiYamlController {
|
|
3895
1284
|
static {
|
|
3896
|
-
({e: [_initProto], c: [_OpenApiYamlController, _initClass$
|
|
1285
|
+
({e: [_initProto], c: [_OpenApiYamlController, _initClass$1]} = _apply_decs_2203_r(this, [[
|
|
3897
1286
|
[_dec2, _dec3],
|
|
3898
1287
|
2,
|
|
3899
1288
|
"getYaml"
|
|
3900
|
-
]], [_dec$
|
|
1289
|
+
]], [_dec$1, _dec1]));
|
|
3901
1290
|
}
|
|
3902
1291
|
documentService = (_initProto(this), (0, _navios_core.inject)(OpenApiDocumentServiceToken));
|
|
3903
|
-
async getYaml(
|
|
1292
|
+
async getYaml() {
|
|
3904
1293
|
const yaml$1 = this.documentService.getYamlDocument();
|
|
3905
1294
|
return new Response(yaml$1, { headers: { "Content-Type": "text/yaml; charset=utf-8" } });
|
|
3906
1295
|
}
|
|
3907
1296
|
static {
|
|
3908
|
-
_initClass$
|
|
1297
|
+
_initClass$1();
|
|
3909
1298
|
}
|
|
3910
1299
|
}
|
|
3911
1300
|
return _OpenApiYamlController;
|
|
@@ -3997,9 +1386,7 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
3997
1386
|
/**
|
|
3998
1387
|
* Registers the plugin options in the DI container.
|
|
3999
1388
|
*/ registerOptions(context, options) {
|
|
4000
|
-
|
|
4001
|
-
const instanceName = locator.getInstanceIdentifier(OpenApiOptionsToken);
|
|
4002
|
-
locator.getManager().storeCreatedHolder(instanceName, options, InjectableType.Class, InjectableScope.Singleton);
|
|
1389
|
+
context.container.addInstance(OpenApiOptionsToken, options);
|
|
4003
1390
|
}
|
|
4004
1391
|
/**
|
|
4005
1392
|
* Registers and initializes the document service.
|