@noxfly/noxus 2.1.1 → 2.3.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/dist/main.js CHANGED
@@ -47,10 +47,13 @@ __export(main_exports, {
47
47
  Controller: () => Controller,
48
48
  Delete: () => Delete,
49
49
  ForbiddenException: () => ForbiddenException,
50
+ ForwardReference: () => ForwardReference,
50
51
  GatewayTimeoutException: () => GatewayTimeoutException,
51
52
  Get: () => Get,
52
53
  HttpVersionNotSupportedException: () => HttpVersionNotSupportedException,
53
54
  INJECTABLE_METADATA_KEY: () => INJECTABLE_METADATA_KEY,
55
+ INJECT_METADATA_KEY: () => INJECT_METADATA_KEY,
56
+ Inject: () => Inject,
54
57
  Injectable: () => Injectable,
55
58
  InsufficientStorageException: () => InsufficientStorageException,
56
59
  InternalServerException: () => InternalServerException,
@@ -89,6 +92,7 @@ __export(main_exports, {
89
92
  bootstrapApplication: () => bootstrapApplication,
90
93
  createRendererEventMessage: () => createRendererEventMessage,
91
94
  exposeNoxusBridge: () => exposeNoxusBridge,
95
+ forwardRef: () => forwardRef,
92
96
  getControllerMetadata: () => getControllerMetadata,
93
97
  getGuardForController: () => getGuardForController,
94
98
  getGuardForControllerAction: () => getGuardForControllerAction,
@@ -104,7 +108,19 @@ __export(main_exports, {
104
108
  module.exports = __toCommonJS(main_exports);
105
109
 
106
110
  // src/DI/app-injector.ts
111
+ var import_reflect_metadata2 = require("reflect-metadata");
112
+
113
+ // src/decorators/inject.decorator.ts
107
114
  var import_reflect_metadata = require("reflect-metadata");
115
+ var INJECT_METADATA_KEY = "custom:inject";
116
+ function Inject(token) {
117
+ return (target, propertyKey, parameterIndex) => {
118
+ const existingParameters = Reflect.getOwnMetadata(INJECT_METADATA_KEY, target) || [];
119
+ existingParameters[parameterIndex] = token;
120
+ Reflect.defineMetadata(INJECT_METADATA_KEY, existingParameters, target);
121
+ };
122
+ }
123
+ __name(Inject, "Inject");
108
124
 
109
125
  // src/exceptions.ts
110
126
  var _ResponseException = class _ResponseException extends Error {
@@ -310,6 +326,20 @@ var _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException exte
310
326
  __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
311
327
  var NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
312
328
 
329
+ // src/utils/forward-ref.ts
330
+ var _ForwardReference = class _ForwardReference {
331
+ constructor(forwardRefFn) {
332
+ __publicField(this, "forwardRefFn");
333
+ this.forwardRefFn = forwardRefFn;
334
+ }
335
+ };
336
+ __name(_ForwardReference, "ForwardReference");
337
+ var ForwardReference = _ForwardReference;
338
+ function forwardRef(fn) {
339
+ return new ForwardReference(fn);
340
+ }
341
+ __name(forwardRef, "forwardRef");
342
+
313
343
  // src/DI/app-injector.ts
314
344
  var _AppInjector = class _AppInjector {
315
345
  constructor(name = null) {
@@ -336,9 +366,34 @@ var _AppInjector = class _AppInjector {
336
366
  * i.e., retrieving the instance of a given class.
337
367
  */
338
368
  resolve(target) {
369
+ if (target instanceof ForwardReference) {
370
+ return new Proxy({}, {
371
+ get: /* @__PURE__ */ __name((obj, prop, receiver) => {
372
+ const realType = target.forwardRefFn();
373
+ const instance = this.resolve(realType);
374
+ const value = Reflect.get(instance, prop, receiver);
375
+ return typeof value === "function" ? value.bind(instance) : value;
376
+ }, "get"),
377
+ set: /* @__PURE__ */ __name((obj, prop, value, receiver) => {
378
+ const realType = target.forwardRefFn();
379
+ const instance = this.resolve(realType);
380
+ return Reflect.set(instance, prop, value, receiver);
381
+ }, "set"),
382
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
383
+ const realType = target.forwardRefFn();
384
+ return realType.prototype;
385
+ }, "getPrototypeOf")
386
+ });
387
+ }
339
388
  const binding = this.bindings.get(target);
340
- if (!binding) throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${target.name}.
389
+ if (!binding) {
390
+ if (target === void 0) {
391
+ throw new InternalServerException("Failed to resolve a dependency injection : Undefined target type.\nThis might be caused by a circular dependency.");
392
+ }
393
+ const name = target.name || "unknown";
394
+ throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${name}.
341
395
  Did you forget to use @Injectable() decorator ?`);
396
+ }
342
397
  switch (binding.lifetime) {
343
398
  case "transient":
344
399
  return this.instantiate(binding.implementation);
@@ -360,11 +415,16 @@ Did you forget to use @Injectable() decorator ?`);
360
415
  }
361
416
  }
362
417
  /**
363
- *
418
+ * Instantiates a class, resolving its dependencies.
364
419
  */
365
420
  instantiate(target) {
366
421
  const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
367
- const params = paramTypes.map((p) => this.resolve(p));
422
+ const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
423
+ const params = paramTypes.map((paramType, index) => {
424
+ const overrideToken = injectParams[index];
425
+ const actualToken = overrideToken !== void 0 ? overrideToken : paramType;
426
+ return this.resolve(actualToken);
427
+ });
368
428
  return new target(...params);
369
429
  }
370
430
  };
@@ -377,7 +437,7 @@ __name(inject, "inject");
377
437
  var RootInjector = new AppInjector("root");
378
438
 
379
439
  // src/router.ts
380
- var import_reflect_metadata3 = require("reflect-metadata");
440
+ var import_reflect_metadata4 = require("reflect-metadata");
381
441
 
382
442
  // src/decorators/guards.decorator.ts
383
443
  function Authorize(...guardClasses) {
@@ -864,7 +924,7 @@ __name(getMiddlewaresForControllerAction, "getMiddlewaresForControllerAction");
864
924
  var middlewares = /* @__PURE__ */ new Map();
865
925
 
866
926
  // src/request.ts
867
- var import_reflect_metadata2 = require("reflect-metadata");
927
+ var import_reflect_metadata3 = require("reflect-metadata");
868
928
  var _Request = class _Request {
869
929
  constructor(event, senderId, id, method, path2, body) {
870
930
  __publicField(this, "event");
@@ -2063,10 +2123,13 @@ var NoxRendererClient = _NoxRendererClient;
2063
2123
  Controller,
2064
2124
  Delete,
2065
2125
  ForbiddenException,
2126
+ ForwardReference,
2066
2127
  GatewayTimeoutException,
2067
2128
  Get,
2068
2129
  HttpVersionNotSupportedException,
2069
2130
  INJECTABLE_METADATA_KEY,
2131
+ INJECT_METADATA_KEY,
2132
+ Inject,
2070
2133
  Injectable,
2071
2134
  InsufficientStorageException,
2072
2135
  InternalServerException,
@@ -2105,6 +2168,7 @@ var NoxRendererClient = _NoxRendererClient;
2105
2168
  bootstrapApplication,
2106
2169
  createRendererEventMessage,
2107
2170
  exposeNoxusBridge,
2171
+ forwardRef,
2108
2172
  getControllerMetadata,
2109
2173
  getGuardForController,
2110
2174
  getGuardForControllerAction,
package/dist/main.mjs CHANGED
@@ -11,6 +11,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
11
11
  // src/DI/app-injector.ts
12
12
  import "reflect-metadata";
13
13
 
14
+ // src/decorators/inject.decorator.ts
15
+ import "reflect-metadata";
16
+ var INJECT_METADATA_KEY = "custom:inject";
17
+ function Inject(token) {
18
+ return (target, propertyKey, parameterIndex) => {
19
+ const existingParameters = Reflect.getOwnMetadata(INJECT_METADATA_KEY, target) || [];
20
+ existingParameters[parameterIndex] = token;
21
+ Reflect.defineMetadata(INJECT_METADATA_KEY, existingParameters, target);
22
+ };
23
+ }
24
+ __name(Inject, "Inject");
25
+
14
26
  // src/exceptions.ts
15
27
  var _ResponseException = class _ResponseException extends Error {
16
28
  constructor(statusOrMessage, message) {
@@ -215,6 +227,20 @@ var _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException exte
215
227
  __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
216
228
  var NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
217
229
 
230
+ // src/utils/forward-ref.ts
231
+ var _ForwardReference = class _ForwardReference {
232
+ constructor(forwardRefFn) {
233
+ __publicField(this, "forwardRefFn");
234
+ this.forwardRefFn = forwardRefFn;
235
+ }
236
+ };
237
+ __name(_ForwardReference, "ForwardReference");
238
+ var ForwardReference = _ForwardReference;
239
+ function forwardRef(fn) {
240
+ return new ForwardReference(fn);
241
+ }
242
+ __name(forwardRef, "forwardRef");
243
+
218
244
  // src/DI/app-injector.ts
219
245
  var _AppInjector = class _AppInjector {
220
246
  constructor(name = null) {
@@ -241,9 +267,34 @@ var _AppInjector = class _AppInjector {
241
267
  * i.e., retrieving the instance of a given class.
242
268
  */
243
269
  resolve(target) {
270
+ if (target instanceof ForwardReference) {
271
+ return new Proxy({}, {
272
+ get: /* @__PURE__ */ __name((obj, prop, receiver) => {
273
+ const realType = target.forwardRefFn();
274
+ const instance = this.resolve(realType);
275
+ const value = Reflect.get(instance, prop, receiver);
276
+ return typeof value === "function" ? value.bind(instance) : value;
277
+ }, "get"),
278
+ set: /* @__PURE__ */ __name((obj, prop, value, receiver) => {
279
+ const realType = target.forwardRefFn();
280
+ const instance = this.resolve(realType);
281
+ return Reflect.set(instance, prop, value, receiver);
282
+ }, "set"),
283
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
284
+ const realType = target.forwardRefFn();
285
+ return realType.prototype;
286
+ }, "getPrototypeOf")
287
+ });
288
+ }
244
289
  const binding = this.bindings.get(target);
245
- if (!binding) throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${target.name}.
290
+ if (!binding) {
291
+ if (target === void 0) {
292
+ throw new InternalServerException("Failed to resolve a dependency injection : Undefined target type.\nThis might be caused by a circular dependency.");
293
+ }
294
+ const name = target.name || "unknown";
295
+ throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${name}.
246
296
  Did you forget to use @Injectable() decorator ?`);
297
+ }
247
298
  switch (binding.lifetime) {
248
299
  case "transient":
249
300
  return this.instantiate(binding.implementation);
@@ -265,11 +316,16 @@ Did you forget to use @Injectable() decorator ?`);
265
316
  }
266
317
  }
267
318
  /**
268
- *
319
+ * Instantiates a class, resolving its dependencies.
269
320
  */
270
321
  instantiate(target) {
271
322
  const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
272
- const params = paramTypes.map((p) => this.resolve(p));
323
+ const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
324
+ const params = paramTypes.map((paramType, index) => {
325
+ const overrideToken = injectParams[index];
326
+ const actualToken = overrideToken !== void 0 ? overrideToken : paramType;
327
+ return this.resolve(actualToken);
328
+ });
273
329
  return new target(...params);
274
330
  }
275
331
  };
@@ -1967,10 +2023,13 @@ export {
1967
2023
  Controller,
1968
2024
  Delete,
1969
2025
  ForbiddenException,
2026
+ ForwardReference,
1970
2027
  GatewayTimeoutException,
1971
2028
  Get,
1972
2029
  HttpVersionNotSupportedException,
1973
2030
  INJECTABLE_METADATA_KEY,
2031
+ INJECT_METADATA_KEY,
2032
+ Inject,
1974
2033
  Injectable,
1975
2034
  InsufficientStorageException,
1976
2035
  InternalServerException,
@@ -2009,6 +2068,7 @@ export {
2009
2068
  bootstrapApplication,
2010
2069
  createRendererEventMessage,
2011
2070
  exposeNoxusBridge,
2071
+ forwardRef,
2012
2072
  getControllerMetadata,
2013
2073
  getGuardForController,
2014
2074
  getGuardForControllerAction,
@@ -1 +1,2 @@
1
- export { p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, b as IPortRequester, t as IRendererEventMessage, o as IRequest, I as IResponse, N as NoxRendererClient, s as RENDERER_EVENT_TYPE, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, R as Request, u as createRendererEventMessage, v as isRendererEventMessage } from './index-CI3OMzNR.mjs';
1
+ export { l as IBatchRequestItem, m as IBatchRequestPayload, n as IBatchResponsePayload, b as IPortRequester, p as IRendererEventMessage, k as IRequest, I as IResponse, N as NoxRendererClient, o as RENDERER_EVENT_TYPE, v as RendererClientOptions, s as RendererEventHandler, u as RendererEventRegistry, t as RendererEventSubscription, R as Request, q as createRendererEventMessage, r as isRendererEventMessage } from './index-DQBQQfMw.mjs';
2
+ import './app-injector-B3MvgV3k.mjs';
@@ -1 +1,2 @@
1
- export { p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, b as IPortRequester, t as IRendererEventMessage, o as IRequest, I as IResponse, N as NoxRendererClient, s as RENDERER_EVENT_TYPE, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, R as Request, u as createRendererEventMessage, v as isRendererEventMessage } from './index-CI3OMzNR.js';
1
+ export { l as IBatchRequestItem, m as IBatchRequestPayload, n as IBatchResponsePayload, b as IPortRequester, p as IRendererEventMessage, k as IRequest, I as IResponse, N as NoxRendererClient, o as RENDERER_EVENT_TYPE, v as RendererClientOptions, s as RendererEventHandler, u as RendererEventRegistry, t as RendererEventSubscription, R as Request, q as createRendererEventMessage, r as isRendererEventMessage } from './index-BxWQVi6C.js';
2
+ import './app-injector-B3MvgV3k.js';
package/dist/renderer.js CHANGED
@@ -38,10 +38,14 @@ __export(src_exports, {
38
38
  module.exports = __toCommonJS(src_exports);
39
39
 
40
40
  // src/request.ts
41
- var import_reflect_metadata2 = require("reflect-metadata");
41
+ var import_reflect_metadata3 = require("reflect-metadata");
42
42
 
43
43
  // src/DI/app-injector.ts
44
+ var import_reflect_metadata2 = require("reflect-metadata");
45
+
46
+ // src/decorators/inject.decorator.ts
44
47
  var import_reflect_metadata = require("reflect-metadata");
48
+ var INJECT_METADATA_KEY = "custom:inject";
45
49
 
46
50
  // src/exceptions.ts
47
51
  var _ResponseException = class _ResponseException extends Error {
@@ -71,6 +75,16 @@ var _InternalServerException = class _InternalServerException extends ResponseEx
71
75
  __name(_InternalServerException, "InternalServerException");
72
76
  var InternalServerException = _InternalServerException;
73
77
 
78
+ // src/utils/forward-ref.ts
79
+ var _ForwardReference = class _ForwardReference {
80
+ constructor(forwardRefFn) {
81
+ __publicField(this, "forwardRefFn");
82
+ this.forwardRefFn = forwardRefFn;
83
+ }
84
+ };
85
+ __name(_ForwardReference, "ForwardReference");
86
+ var ForwardReference = _ForwardReference;
87
+
74
88
  // src/DI/app-injector.ts
75
89
  var _AppInjector = class _AppInjector {
76
90
  constructor(name = null) {
@@ -97,9 +111,34 @@ var _AppInjector = class _AppInjector {
97
111
  * i.e., retrieving the instance of a given class.
98
112
  */
99
113
  resolve(target) {
114
+ if (target instanceof ForwardReference) {
115
+ return new Proxy({}, {
116
+ get: /* @__PURE__ */ __name((obj, prop, receiver) => {
117
+ const realType = target.forwardRefFn();
118
+ const instance = this.resolve(realType);
119
+ const value = Reflect.get(instance, prop, receiver);
120
+ return typeof value === "function" ? value.bind(instance) : value;
121
+ }, "get"),
122
+ set: /* @__PURE__ */ __name((obj, prop, value, receiver) => {
123
+ const realType = target.forwardRefFn();
124
+ const instance = this.resolve(realType);
125
+ return Reflect.set(instance, prop, value, receiver);
126
+ }, "set"),
127
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
128
+ const realType = target.forwardRefFn();
129
+ return realType.prototype;
130
+ }, "getPrototypeOf")
131
+ });
132
+ }
100
133
  const binding = this.bindings.get(target);
101
- if (!binding) throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${target.name}.
134
+ if (!binding) {
135
+ if (target === void 0) {
136
+ throw new InternalServerException("Failed to resolve a dependency injection : Undefined target type.\nThis might be caused by a circular dependency.");
137
+ }
138
+ const name = target.name || "unknown";
139
+ throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${name}.
102
140
  Did you forget to use @Injectable() decorator ?`);
141
+ }
103
142
  switch (binding.lifetime) {
104
143
  case "transient":
105
144
  return this.instantiate(binding.implementation);
@@ -121,11 +160,16 @@ Did you forget to use @Injectable() decorator ?`);
121
160
  }
122
161
  }
123
162
  /**
124
- *
163
+ * Instantiates a class, resolving its dependencies.
125
164
  */
126
165
  instantiate(target) {
127
166
  const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
128
- const params = paramTypes.map((p) => this.resolve(p));
167
+ const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
168
+ const params = paramTypes.map((paramType, index) => {
169
+ const overrideToken = injectParams[index];
170
+ const actualToken = overrideToken !== void 0 ? overrideToken : paramType;
171
+ return this.resolve(actualToken);
172
+ });
129
173
  return new target(...params);
130
174
  }
131
175
  };
package/dist/renderer.mjs CHANGED
@@ -14,6 +14,10 @@ import "reflect-metadata";
14
14
  // src/DI/app-injector.ts
15
15
  import "reflect-metadata";
16
16
 
17
+ // src/decorators/inject.decorator.ts
18
+ import "reflect-metadata";
19
+ var INJECT_METADATA_KEY = "custom:inject";
20
+
17
21
  // src/exceptions.ts
18
22
  var _ResponseException = class _ResponseException extends Error {
19
23
  constructor(statusOrMessage, message) {
@@ -42,6 +46,16 @@ var _InternalServerException = class _InternalServerException extends ResponseEx
42
46
  __name(_InternalServerException, "InternalServerException");
43
47
  var InternalServerException = _InternalServerException;
44
48
 
49
+ // src/utils/forward-ref.ts
50
+ var _ForwardReference = class _ForwardReference {
51
+ constructor(forwardRefFn) {
52
+ __publicField(this, "forwardRefFn");
53
+ this.forwardRefFn = forwardRefFn;
54
+ }
55
+ };
56
+ __name(_ForwardReference, "ForwardReference");
57
+ var ForwardReference = _ForwardReference;
58
+
45
59
  // src/DI/app-injector.ts
46
60
  var _AppInjector = class _AppInjector {
47
61
  constructor(name = null) {
@@ -68,9 +82,34 @@ var _AppInjector = class _AppInjector {
68
82
  * i.e., retrieving the instance of a given class.
69
83
  */
70
84
  resolve(target) {
85
+ if (target instanceof ForwardReference) {
86
+ return new Proxy({}, {
87
+ get: /* @__PURE__ */ __name((obj, prop, receiver) => {
88
+ const realType = target.forwardRefFn();
89
+ const instance = this.resolve(realType);
90
+ const value = Reflect.get(instance, prop, receiver);
91
+ return typeof value === "function" ? value.bind(instance) : value;
92
+ }, "get"),
93
+ set: /* @__PURE__ */ __name((obj, prop, value, receiver) => {
94
+ const realType = target.forwardRefFn();
95
+ const instance = this.resolve(realType);
96
+ return Reflect.set(instance, prop, value, receiver);
97
+ }, "set"),
98
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
99
+ const realType = target.forwardRefFn();
100
+ return realType.prototype;
101
+ }, "getPrototypeOf")
102
+ });
103
+ }
71
104
  const binding = this.bindings.get(target);
72
- if (!binding) throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${target.name}.
105
+ if (!binding) {
106
+ if (target === void 0) {
107
+ throw new InternalServerException("Failed to resolve a dependency injection : Undefined target type.\nThis might be caused by a circular dependency.");
108
+ }
109
+ const name = target.name || "unknown";
110
+ throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${name}.
73
111
  Did you forget to use @Injectable() decorator ?`);
112
+ }
74
113
  switch (binding.lifetime) {
75
114
  case "transient":
76
115
  return this.instantiate(binding.implementation);
@@ -92,11 +131,16 @@ Did you forget to use @Injectable() decorator ?`);
92
131
  }
93
132
  }
94
133
  /**
95
- *
134
+ * Instantiates a class, resolving its dependencies.
96
135
  */
97
136
  instantiate(target) {
98
137
  const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
99
- const params = paramTypes.map((p) => this.resolve(p));
138
+ const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
139
+ const params = paramTypes.map((paramType, index) => {
140
+ const overrideToken = injectParams[index];
141
+ const actualToken = overrideToken !== void 0 ? overrideToken : paramType;
142
+ return this.resolve(actualToken);
143
+ });
100
144
  return new target(...params);
101
145
  }
102
146
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noxfly/noxus",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "main": "dist/main.js",
5
5
  "module": "dist/main.mjs",
6
6
  "types": "dist/main.d.ts",
@@ -26,6 +26,11 @@
26
26
  "types": "./dist/main.d.ts",
27
27
  "import": "./dist/main.mjs",
28
28
  "require": "./dist/main.js"
29
+ },
30
+ "./child": {
31
+ "types": "./dist/child.d.ts",
32
+ "import": "./dist/child.mjs",
33
+ "require": "./dist/child.js"
29
34
  }
30
35
  },
31
36
  "scripts": {
@@ -5,7 +5,9 @@
5
5
  */
6
6
 
7
7
  import 'reflect-metadata';
8
+ import { INJECT_METADATA_KEY } from 'src/decorators/inject.decorator';
8
9
  import { InternalServerException } from 'src/exceptions';
10
+ import { ForwardReference } from 'src/utils/forward-ref';
9
11
  import { Type } from 'src/utils/types';
10
12
 
11
13
  /**
@@ -61,28 +63,59 @@ export class AppInjector {
61
63
  * Called when resolving a dependency,
62
64
  * i.e., retrieving the instance of a given class.
63
65
  */
64
- public resolve<T extends Type<unknown>>(target: T): InstanceType<T> {
66
+ public resolve<T>(target: Type<T> | ForwardReference<T>): T {
67
+ if (target instanceof ForwardReference) {
68
+ return new Proxy({}, {
69
+ get: (obj, prop, receiver) => {
70
+ const realType = target.forwardRefFn();
71
+ const instance = this.resolve(realType) as any;
72
+ const value = Reflect.get(instance, prop, receiver);
73
+
74
+ return typeof value === 'function' ? value.bind(instance) : value;
75
+ },
76
+ set: (obj, prop, value, receiver) => {
77
+ const realType = target.forwardRefFn();
78
+ const instance = this.resolve(realType) as any;
79
+ return Reflect.set(instance, prop, value, receiver);
80
+ },
81
+ getPrototypeOf: () => {
82
+ const realType = target.forwardRefFn();
83
+ return (realType as any).prototype;
84
+ }
85
+ }) as T;
86
+ }
87
+
65
88
  const binding = this.bindings.get(target);
66
89
 
67
- if(!binding)
90
+ if(!binding) {
91
+ if(target === undefined) {
92
+ throw new InternalServerException(
93
+ "Failed to resolve a dependency injection : Undefined target type.\n"
94
+ + "This might be caused by a circular dependency."
95
+ );
96
+ }
97
+
98
+ const name = target.name || "unknown";
99
+
68
100
  throw new InternalServerException(
69
- `Failed to resolve a dependency injection : No binding for type ${target.name}.\n`
101
+ `Failed to resolve a dependency injection : No binding for type ${name}.\n`
70
102
  + `Did you forget to use @Injectable() decorator ?`
71
103
  );
104
+ }
72
105
 
73
106
  switch(binding.lifetime) {
74
107
  case 'transient':
75
- return this.instantiate(binding.implementation) as InstanceType<T>;
108
+ return this.instantiate(binding.implementation) as T;
76
109
 
77
110
  case 'scope': {
78
111
  if(this.scoped.has(target)) {
79
- return this.scoped.get(target) as InstanceType<T>;
112
+ return this.scoped.get(target) as T;
80
113
  }
81
114
 
82
115
  const instance = this.instantiate(binding.implementation);
83
116
  this.scoped.set(target, instance);
84
117
 
85
- return instance as InstanceType<T>;
118
+ return instance as T;
86
119
  }
87
120
 
88
121
  case 'singleton': {
@@ -91,17 +124,25 @@ export class AppInjector {
91
124
  this.singletons.set(target, binding.instance);
92
125
  }
93
126
 
94
- return binding.instance as InstanceType<T>;
127
+ return binding.instance as T;
95
128
  }
96
129
  }
97
130
  }
98
131
 
99
132
  /**
100
- *
133
+ * Instantiates a class, resolving its dependencies.
101
134
  */
102
135
  private instantiate<T extends Type<unknown>>(target: T): InstanceType<T> {
103
136
  const paramTypes = Reflect.getMetadata('design:paramtypes', target) || [];
104
- const params = paramTypes.map((p: any) => this.resolve(p));
137
+ const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
138
+
139
+ const params = paramTypes.map((paramType: any, index: number) => {
140
+ const overrideToken = injectParams[index];
141
+ const actualToken = overrideToken !== undefined ? overrideToken : paramType;
142
+
143
+ return this.resolve(actualToken);
144
+ });
145
+
105
146
  return new target(...params) as InstanceType<T>;
106
147
  }
107
148
  }
@@ -114,7 +155,7 @@ export class AppInjector {
114
155
  * @returns An instance of the type.
115
156
  * @throws If the type is not registered in the dependency injection system.
116
157
  */
117
- export function inject<T>(t: Type<T>): T {
158
+ export function inject<T>(t: Type<T> | ForwardReference<T>): T {
118
159
  return RootInjector.resolve(t);
119
160
  }
120
161
 
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @copyright 2025 NoxFly
3
+ * @license MIT
4
+ * @author NoxFly
5
+ */
6
+
7
+ import 'reflect-metadata';
8
+
9
+ export const INJECT_METADATA_KEY = 'custom:inject';
10
+
11
+ /**
12
+ * Decorator to manually inject a dependency.
13
+ * Useful for handling circular dependencies with `forwardRef` or injecting specific tokens.
14
+ *
15
+ * @param token The token or forward reference to inject.
16
+ */
17
+ export function Inject(token: any): ParameterDecorator {
18
+ return (target, propertyKey, parameterIndex) => {
19
+ // target is the constructor for constructor parameters
20
+ const existingParameters = Reflect.getOwnMetadata(INJECT_METADATA_KEY, target) || [];
21
+ existingParameters[parameterIndex] = token;
22
+ Reflect.defineMetadata(INJECT_METADATA_KEY, existingParameters, target);
23
+ };
24
+ }
package/src/main.ts CHANGED
@@ -19,11 +19,13 @@ export * from './decorators/middleware.decorator';
19
19
  export * from './decorators/guards.decorator';
20
20
  export * from './decorators/controller.decorator';
21
21
  export * from './decorators/injectable.decorator';
22
+ export * from './decorators/inject.decorator';
22
23
  export * from './decorators/method.decorator';
23
24
  export * from './decorators/module.decorator';
24
25
  export * from './preload-bridge';
25
26
  export * from './utils/logger';
26
27
  export * from './utils/types';
28
+ export * from './utils/forward-ref';
27
29
  export * from './request';
28
30
  export * from './renderer-events';
29
31
  export * from './renderer-client';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @copyright 2025 NoxFly
3
+ * @license MIT
4
+ * @author NoxFly
5
+ */
6
+
7
+ /**
8
+ * Entry point for nodeJS non-electron process consumers.
9
+ * For instance, if main process creates a child process that
10
+ * wants to use Logger and DI.
11
+ * Child processes must not try to communicate with the renderer
12
+ * process.
13
+ * order of exports here matters and can affect module resolution.
14
+ * Please be cautious when modifying.
15
+ */
16
+
17
+ export * from './DI/app-injector';
18
+ export * from './exceptions';
19
+ export * from './decorators/injectable.decorator';
20
+ export * from './decorators/inject.decorator';
21
+ export * from './utils/logger';
22
+ export * from './utils/types';
23
+ export * from './utils/forward-ref';