@noxfly/noxus 2.4.0 → 3.0.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +403 -341
  2. package/dist/app-injector-Bz3Upc0y.d.mts +125 -0
  3. package/dist/app-injector-Bz3Upc0y.d.ts +125 -0
  4. package/dist/child.d.mts +48 -22
  5. package/dist/child.d.ts +48 -22
  6. package/dist/child.js +1114 -1239
  7. package/dist/child.mjs +1090 -1193
  8. package/dist/main.d.mts +304 -261
  9. package/dist/main.d.ts +304 -261
  10. package/dist/main.js +1473 -1873
  11. package/dist/main.mjs +1423 -1791
  12. package/dist/renderer.d.mts +113 -2
  13. package/dist/renderer.d.ts +113 -2
  14. package/dist/renderer.js +144 -132
  15. package/dist/renderer.mjs +143 -132
  16. package/dist/request-BlTtiHbi.d.ts +112 -0
  17. package/dist/request-qJ9EiDZc.d.mts +112 -0
  18. package/package.json +7 -7
  19. package/src/DI/app-injector.ts +95 -106
  20. package/src/DI/injector-explorer.ts +100 -81
  21. package/src/DI/token.ts +53 -0
  22. package/src/app.ts +141 -131
  23. package/src/bootstrap.ts +79 -40
  24. package/src/decorators/controller.decorator.ts +38 -27
  25. package/src/decorators/guards.decorator.ts +5 -64
  26. package/src/decorators/injectable.decorator.ts +68 -15
  27. package/src/decorators/method.decorator.ts +40 -81
  28. package/src/decorators/middleware.decorator.ts +5 -72
  29. package/src/index.ts +3 -0
  30. package/src/main.ts +4 -11
  31. package/src/non-electron-process.ts +0 -1
  32. package/src/preload-bridge.ts +1 -1
  33. package/src/renderer-client.ts +2 -2
  34. package/src/renderer-events.ts +1 -1
  35. package/src/request.ts +3 -3
  36. package/src/router.ts +221 -369
  37. package/src/routes.ts +78 -0
  38. package/src/socket.ts +4 -4
  39. package/src/window/window-manager.ts +255 -0
  40. package/tsconfig.json +5 -10
  41. package/tsup.config.ts +2 -2
  42. package/dist/app-injector-B3MvgV3k.d.mts +0 -95
  43. package/dist/app-injector-B3MvgV3k.d.ts +0 -95
  44. package/dist/index-BxWQVi6C.d.ts +0 -253
  45. package/dist/index-DQBQQfMw.d.mts +0 -253
  46. package/src/decorators/inject.decorator.ts +0 -24
  47. package/src/decorators/injectable.metadata.ts +0 -15
  48. package/src/decorators/module.decorator.ts +0 -75
package/dist/main.mjs CHANGED
@@ -4,457 +4,183 @@
4
4
  * @author NoxFly
5
5
  */
6
6
  var __defProp = Object.defineProperty;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
10
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
-
11
- // src/DI/app-injector.ts
12
- import "reflect-metadata";
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
-
26
- // src/exceptions.ts
27
- var _ResponseException = class _ResponseException extends Error {
28
- constructor(statusOrMessage, message) {
29
- let statusCode;
30
- if (typeof statusOrMessage === "number") {
31
- statusCode = statusOrMessage;
32
- } else if (typeof statusOrMessage === "string") {
33
- message = statusOrMessage;
34
- }
35
- super(message ?? "");
36
- __publicField(this, "status", 0);
37
- if (statusCode !== void 0) {
38
- this.status = statusCode;
39
- }
40
- this.name = this.constructor.name.replace(/([A-Z])/g, " $1");
41
- }
42
- };
43
- __name(_ResponseException, "ResponseException");
44
- var ResponseException = _ResponseException;
45
- var _BadRequestException = class _BadRequestException extends ResponseException {
46
- constructor() {
47
- super(...arguments);
48
- __publicField(this, "status", 400);
49
- }
50
- };
51
- __name(_BadRequestException, "BadRequestException");
52
- var BadRequestException = _BadRequestException;
53
- var _UnauthorizedException = class _UnauthorizedException extends ResponseException {
54
- constructor() {
55
- super(...arguments);
56
- __publicField(this, "status", 401);
57
- }
58
- };
59
- __name(_UnauthorizedException, "UnauthorizedException");
60
- var UnauthorizedException = _UnauthorizedException;
61
- var _PaymentRequiredException = class _PaymentRequiredException extends ResponseException {
62
- constructor() {
63
- super(...arguments);
64
- __publicField(this, "status", 402);
65
- }
66
- };
67
- __name(_PaymentRequiredException, "PaymentRequiredException");
68
- var PaymentRequiredException = _PaymentRequiredException;
69
- var _ForbiddenException = class _ForbiddenException extends ResponseException {
70
- constructor() {
71
- super(...arguments);
72
- __publicField(this, "status", 403);
73
- }
74
- };
75
- __name(_ForbiddenException, "ForbiddenException");
76
- var ForbiddenException = _ForbiddenException;
77
- var _NotFoundException = class _NotFoundException extends ResponseException {
78
- constructor() {
79
- super(...arguments);
80
- __publicField(this, "status", 404);
81
- }
82
- };
83
- __name(_NotFoundException, "NotFoundException");
84
- var NotFoundException = _NotFoundException;
85
- var _MethodNotAllowedException = class _MethodNotAllowedException extends ResponseException {
86
- constructor() {
87
- super(...arguments);
88
- __publicField(this, "status", 405);
89
- }
90
- };
91
- __name(_MethodNotAllowedException, "MethodNotAllowedException");
92
- var MethodNotAllowedException = _MethodNotAllowedException;
93
- var _NotAcceptableException = class _NotAcceptableException extends ResponseException {
94
- constructor() {
95
- super(...arguments);
96
- __publicField(this, "status", 406);
97
- }
98
- };
99
- __name(_NotAcceptableException, "NotAcceptableException");
100
- var NotAcceptableException = _NotAcceptableException;
101
- var _RequestTimeoutException = class _RequestTimeoutException extends ResponseException {
102
- constructor() {
103
- super(...arguments);
104
- __publicField(this, "status", 408);
105
- }
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
106
13
  };
107
- __name(_RequestTimeoutException, "RequestTimeoutException");
108
- var RequestTimeoutException = _RequestTimeoutException;
109
- var _ConflictException = class _ConflictException extends ResponseException {
110
- constructor() {
111
- super(...arguments);
112
- __publicField(this, "status", 409);
113
- }
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
114
17
  };
115
- __name(_ConflictException, "ConflictException");
116
- var ConflictException = _ConflictException;
117
- var _UpgradeRequiredException = class _UpgradeRequiredException extends ResponseException {
118
- constructor() {
119
- super(...arguments);
120
- __publicField(this, "status", 426);
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
121
23
  }
24
+ return to;
122
25
  };
123
- __name(_UpgradeRequiredException, "UpgradeRequiredException");
124
- var UpgradeRequiredException = _UpgradeRequiredException;
125
- var _TooManyRequestsException = class _TooManyRequestsException extends ResponseException {
126
- constructor() {
127
- super(...arguments);
128
- __publicField(this, "status", 429);
129
- }
130
- };
131
- __name(_TooManyRequestsException, "TooManyRequestsException");
132
- var TooManyRequestsException = _TooManyRequestsException;
133
- var _InternalServerException = class _InternalServerException extends ResponseException {
134
- constructor() {
135
- super(...arguments);
136
- __publicField(this, "status", 500);
137
- }
138
- };
139
- __name(_InternalServerException, "InternalServerException");
140
- var InternalServerException = _InternalServerException;
141
- var _NotImplementedException = class _NotImplementedException extends ResponseException {
142
- constructor() {
143
- super(...arguments);
144
- __publicField(this, "status", 501);
145
- }
146
- };
147
- __name(_NotImplementedException, "NotImplementedException");
148
- var NotImplementedException = _NotImplementedException;
149
- var _BadGatewayException = class _BadGatewayException extends ResponseException {
150
- constructor() {
151
- super(...arguments);
152
- __publicField(this, "status", 502);
153
- }
154
- };
155
- __name(_BadGatewayException, "BadGatewayException");
156
- var BadGatewayException = _BadGatewayException;
157
- var _ServiceUnavailableException = class _ServiceUnavailableException extends ResponseException {
158
- constructor() {
159
- super(...arguments);
160
- __publicField(this, "status", 503);
161
- }
162
- };
163
- __name(_ServiceUnavailableException, "ServiceUnavailableException");
164
- var ServiceUnavailableException = _ServiceUnavailableException;
165
- var _GatewayTimeoutException = class _GatewayTimeoutException extends ResponseException {
166
- constructor() {
167
- super(...arguments);
168
- __publicField(this, "status", 504);
169
- }
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var __decorateClass = (decorators, target, key, kind) => {
28
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
29
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
30
+ if (decorator = decorators[i])
31
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
32
+ if (kind && result) __defProp(target, key, result);
33
+ return result;
170
34
  };
171
- __name(_GatewayTimeoutException, "GatewayTimeoutException");
172
- var GatewayTimeoutException = _GatewayTimeoutException;
173
- var _HttpVersionNotSupportedException = class _HttpVersionNotSupportedException extends ResponseException {
174
- constructor() {
175
- super(...arguments);
176
- __publicField(this, "status", 505);
177
- }
178
- };
179
- __name(_HttpVersionNotSupportedException, "HttpVersionNotSupportedException");
180
- var HttpVersionNotSupportedException = _HttpVersionNotSupportedException;
181
- var _VariantAlsoNegotiatesException = class _VariantAlsoNegotiatesException extends ResponseException {
182
- constructor() {
183
- super(...arguments);
184
- __publicField(this, "status", 506);
185
- }
186
- };
187
- __name(_VariantAlsoNegotiatesException, "VariantAlsoNegotiatesException");
188
- var VariantAlsoNegotiatesException = _VariantAlsoNegotiatesException;
189
- var _InsufficientStorageException = class _InsufficientStorageException extends ResponseException {
190
- constructor() {
191
- super(...arguments);
192
- __publicField(this, "status", 507);
193
- }
194
- };
195
- __name(_InsufficientStorageException, "InsufficientStorageException");
196
- var InsufficientStorageException = _InsufficientStorageException;
197
- var _LoopDetectedException = class _LoopDetectedException extends ResponseException {
198
- constructor() {
199
- super(...arguments);
200
- __publicField(this, "status", 508);
201
- }
202
- };
203
- __name(_LoopDetectedException, "LoopDetectedException");
204
- var LoopDetectedException = _LoopDetectedException;
205
- var _NotExtendedException = class _NotExtendedException extends ResponseException {
206
- constructor() {
207
- super(...arguments);
208
- __publicField(this, "status", 510);
209
- }
210
- };
211
- __name(_NotExtendedException, "NotExtendedException");
212
- var NotExtendedException = _NotExtendedException;
213
- var _NetworkAuthenticationRequiredException = class _NetworkAuthenticationRequiredException extends ResponseException {
214
- constructor() {
215
- super(...arguments);
216
- __publicField(this, "status", 511);
217
- }
218
- };
219
- __name(_NetworkAuthenticationRequiredException, "NetworkAuthenticationRequiredException");
220
- var NetworkAuthenticationRequiredException = _NetworkAuthenticationRequiredException;
221
- var _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException extends ResponseException {
222
- constructor() {
223
- super(...arguments);
224
- __publicField(this, "status", 599);
225
- }
226
- };
227
- __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
228
- var NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
229
35
 
230
36
  // 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
37
  function forwardRef(fn) {
240
38
  return new ForwardReference(fn);
241
39
  }
242
- __name(forwardRef, "forwardRef");
243
-
244
- // src/DI/app-injector.ts
245
- var _AppInjector = class _AppInjector {
246
- constructor(name = null) {
247
- __publicField(this, "name");
248
- __publicField(this, "bindings", /* @__PURE__ */ new Map());
249
- __publicField(this, "singletons", /* @__PURE__ */ new Map());
250
- __publicField(this, "scoped", /* @__PURE__ */ new Map());
251
- this.name = name;
252
- }
253
- /**
254
- * Typically used to create a dependency injection scope
255
- * at the "scope" level (i.e., per-request lifetime).
256
- *
257
- * SHOULD NOT BE USED by anything else than the framework itself.
258
- */
259
- createScope() {
260
- const scope = new _AppInjector();
261
- scope.bindings = this.bindings;
262
- scope.singletons = this.singletons;
263
- return scope;
264
- }
265
- /**
266
- * Called when resolving a dependency,
267
- * i.e., retrieving the instance of a given class.
268
- */
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
- }
289
- const binding = this.bindings.get(target);
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}.
296
- Did you forget to use @Injectable() decorator ?`);
297
- }
298
- switch (binding.lifetime) {
299
- case "transient":
300
- return this.instantiate(binding.implementation);
301
- case "scope": {
302
- if (this.scoped.has(target)) {
303
- return this.scoped.get(target);
304
- }
305
- const instance = this.instantiate(binding.implementation);
306
- this.scoped.set(target, instance);
307
- return instance;
308
- }
309
- case "singleton": {
310
- if (binding.instance === void 0 && this.name === "root") {
311
- binding.instance = this.instantiate(binding.implementation);
312
- this.singletons.set(target, binding.instance);
313
- }
314
- return binding.instance;
40
+ var _ForwardReference, ForwardReference;
41
+ var init_forward_ref = __esm({
42
+ "src/utils/forward-ref.ts"() {
43
+ "use strict";
44
+ _ForwardReference = class _ForwardReference {
45
+ constructor(forwardRefFn) {
46
+ this.forwardRefFn = forwardRefFn;
315
47
  }
316
- }
317
- }
318
- /**
319
- * Instantiates a class, resolving its dependencies.
320
- */
321
- instantiate(target) {
322
- const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
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
- });
329
- return new target(...params);
48
+ };
49
+ __name(_ForwardReference, "ForwardReference");
50
+ ForwardReference = _ForwardReference;
51
+ __name(forwardRef, "forwardRef");
330
52
  }
331
- };
332
- __name(_AppInjector, "AppInjector");
333
- var AppInjector = _AppInjector;
334
- function inject(t) {
335
- return RootInjector.resolve(t);
336
- }
337
- __name(inject, "inject");
338
- var RootInjector = new AppInjector("root");
53
+ });
339
54
 
340
- // src/router.ts
341
- import "reflect-metadata";
342
-
343
- // src/decorators/guards.decorator.ts
344
- function Authorize(...guardClasses) {
345
- return (target, propertyKey) => {
346
- let key;
347
- if (propertyKey) {
348
- const ctrlName = target.constructor.name;
349
- const actionName = propertyKey;
350
- key = `${ctrlName}.${actionName}`;
351
- } else {
352
- const ctrlName = target.name;
353
- key = `${ctrlName}`;
354
- }
355
- if (authorizations.has(key)) {
356
- throw new Error(`Guard(s) already registered for ${key}`);
357
- }
358
- authorizations.set(key, guardClasses);
359
- };
360
- }
361
- __name(Authorize, "Authorize");
362
- function getGuardForController(controllerName) {
363
- const key = `${controllerName}`;
364
- return authorizations.get(key) ?? [];
55
+ // src/DI/token.ts
56
+ function token(target) {
57
+ return new Token(target);
365
58
  }
366
- __name(getGuardForController, "getGuardForController");
367
- function getGuardForControllerAction(controllerName, actionName) {
368
- const key = `${controllerName}.${actionName}`;
369
- return authorizations.get(key) ?? [];
370
- }
371
- __name(getGuardForControllerAction, "getGuardForControllerAction");
372
- var authorizations = /* @__PURE__ */ new Map();
373
-
374
- // src/decorators/injectable.metadata.ts
375
- var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY");
376
- function defineInjectableMetadata(target, lifetime) {
377
- Reflect.defineMetadata(INJECTABLE_METADATA_KEY, lifetime, target);
378
- }
379
- __name(defineInjectableMetadata, "defineInjectableMetadata");
380
- function getInjectableMetadata(target) {
381
- return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
382
- }
383
- __name(getInjectableMetadata, "getInjectableMetadata");
384
- function hasInjectableMetadata(target) {
385
- return Reflect.hasMetadata(INJECTABLE_METADATA_KEY, target);
386
- }
387
- __name(hasInjectableMetadata, "hasInjectableMetadata");
388
-
389
- // src/decorators/method.decorator.ts
390
- function createRouteDecorator(verb) {
391
- return (path2) => {
392
- return (target, propertyKey) => {
393
- const existingRoutes = Reflect.getMetadata(ROUTE_METADATA_KEY, target.constructor) || [];
394
- const metadata = {
395
- method: verb,
396
- path: path2.trim().replace(/^\/|\/$/g, ""),
397
- handler: propertyKey,
398
- guards: getGuardForControllerAction(target.constructor.__controllerName, propertyKey)
399
- };
400
- existingRoutes.push(metadata);
401
- Reflect.defineMetadata(ROUTE_METADATA_KEY, existingRoutes, target.constructor);
59
+ var _Token, Token;
60
+ var init_token = __esm({
61
+ "src/DI/token.ts"() {
62
+ "use strict";
63
+ _Token = class _Token {
64
+ constructor(target) {
65
+ this.target = target;
66
+ this.description = typeof target === "string" ? target : target.name;
67
+ }
68
+ toString() {
69
+ return `Token(${this.description})`;
70
+ }
402
71
  };
403
- };
72
+ __name(_Token, "Token");
73
+ Token = _Token;
74
+ __name(token, "token");
75
+ }
76
+ });
77
+
78
+ // src/DI/app-injector.ts
79
+ function keyOf(k) {
80
+ return k;
404
81
  }
405
- __name(createRouteDecorator, "createRouteDecorator");
406
- function getRouteMetadata(target) {
407
- return Reflect.getMetadata(ROUTE_METADATA_KEY, target) || [];
82
+ function inject(t) {
83
+ return RootInjector.resolve(t);
408
84
  }
409
- __name(getRouteMetadata, "getRouteMetadata");
410
- var Get = createRouteDecorator("GET");
411
- var Post = createRouteDecorator("POST");
412
- var Put = createRouteDecorator("PUT");
413
- var Patch = createRouteDecorator("PATCH");
414
- var Delete = createRouteDecorator("DELETE");
415
- var ROUTE_METADATA_KEY = Symbol("ROUTE_METADATA_KEY");
416
-
417
- // src/decorators/module.decorator.ts
418
- function Module(metadata) {
419
- return (target) => {
420
- const checkModule = /* @__PURE__ */ __name((arr, arrName) => {
421
- if (!arr) return;
422
- for (const clazz of arr) {
423
- if (!Reflect.getMetadata(MODULE_METADATA_KEY, clazz)) {
424
- throw new Error(`Class ${clazz.name} in ${arrName} must be decorated with @Module`);
425
- }
85
+ var _AppInjector, AppInjector, RootInjector;
86
+ var init_app_injector = __esm({
87
+ "src/DI/app-injector.ts"() {
88
+ "use strict";
89
+ init_forward_ref();
90
+ init_token();
91
+ __name(keyOf, "keyOf");
92
+ _AppInjector = class _AppInjector {
93
+ constructor(name = null) {
94
+ this.name = name;
95
+ this.bindings = /* @__PURE__ */ new Map();
96
+ this.singletons = /* @__PURE__ */ new Map();
97
+ this.scoped = /* @__PURE__ */ new Map();
426
98
  }
427
- }, "checkModule");
428
- const checkInjectable = /* @__PURE__ */ __name((arr) => {
429
- if (!arr) return;
430
- for (const clazz of arr) {
431
- if (!Reflect.getMetadata(INJECTABLE_METADATA_KEY, clazz)) {
432
- throw new Error(`Class ${clazz.name} in providers must be decorated with @Injectable`);
99
+ /**
100
+ * Creates a child scope for per-request lifetime resolution.
101
+ */
102
+ createScope() {
103
+ const scope = new _AppInjector();
104
+ scope.bindings = this.bindings;
105
+ scope.singletons = this.singletons;
106
+ return scope;
107
+ }
108
+ /**
109
+ * Registers a binding explicitly.
110
+ */
111
+ register(key, implementation, lifetime, deps = []) {
112
+ const k = keyOf(key);
113
+ if (!this.bindings.has(k)) {
114
+ this.bindings.set(k, { lifetime, implementation, deps });
433
115
  }
434
116
  }
435
- }, "checkInjectable");
436
- const checkController = /* @__PURE__ */ __name((arr) => {
437
- if (!arr) return;
438
- for (const clazz of arr) {
439
- if (!Reflect.getMetadata(CONTROLLER_METADATA_KEY, clazz)) {
440
- throw new Error(`Class ${clazz.name} in controllers must be decorated with @Controller`);
117
+ /**
118
+ * Resolves a dependency by token or class reference.
119
+ */
120
+ resolve(target) {
121
+ if (target instanceof ForwardReference) {
122
+ return this._resolveForwardRef(target);
123
+ }
124
+ const k = keyOf(target);
125
+ const binding = this.bindings.get(k);
126
+ if (!binding) {
127
+ const name = target instanceof Token ? target.description : target.name ?? "unknown";
128
+ throw new Error(
129
+ `[Noxus DI] No binding found for "${name}".
130
+ Did you forget to declare it in @Injectable({ deps }) or in bootstrapApplication({ singletons })?`
131
+ );
132
+ }
133
+ switch (binding.lifetime) {
134
+ case "transient":
135
+ return this._instantiate(binding);
136
+ case "scope": {
137
+ if (this.scoped.has(k)) return this.scoped.get(k);
138
+ const inst = this._instantiate(binding);
139
+ this.scoped.set(k, inst);
140
+ return inst;
141
+ }
142
+ case "singleton": {
143
+ if (this.singletons.has(k)) return this.singletons.get(k);
144
+ const inst = this._instantiate(binding);
145
+ this.singletons.set(k, inst);
146
+ if (binding.instance === void 0) {
147
+ binding.instance = inst;
148
+ }
149
+ return inst;
150
+ }
441
151
  }
442
152
  }
443
- }, "checkController");
444
- checkModule(metadata.imports, "imports");
445
- checkModule(metadata.exports, "exports");
446
- checkInjectable(metadata.providers);
447
- checkController(metadata.controllers);
448
- Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, target);
449
- Injectable("singleton")(target);
450
- };
451
- }
452
- __name(Module, "Module");
453
- function getModuleMetadata(target) {
454
- return Reflect.getMetadata(MODULE_METADATA_KEY, target);
455
- }
456
- __name(getModuleMetadata, "getModuleMetadata");
457
- var MODULE_METADATA_KEY = Symbol("MODULE_METADATA_KEY");
153
+ // -------------------------------------------------------------------------
154
+ _resolveForwardRef(ref) {
155
+ return new Proxy({}, {
156
+ get: /* @__PURE__ */ __name((_obj, prop, receiver) => {
157
+ const realType = ref.forwardRefFn();
158
+ const instance = this.resolve(realType);
159
+ const value = Reflect.get(instance, prop, receiver);
160
+ return typeof value === "function" ? value.bind(instance) : value;
161
+ }, "get"),
162
+ set: /* @__PURE__ */ __name((_obj, prop, value, receiver) => {
163
+ const realType = ref.forwardRefFn();
164
+ const instance = this.resolve(realType);
165
+ return Reflect.set(instance, prop, value, receiver);
166
+ }, "set"),
167
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
168
+ const realType = ref.forwardRefFn();
169
+ return realType.prototype;
170
+ }, "getPrototypeOf")
171
+ });
172
+ }
173
+ _instantiate(binding) {
174
+ const resolvedDeps = binding.deps.map((dep) => this.resolve(dep));
175
+ return new binding.implementation(...resolvedDeps);
176
+ }
177
+ };
178
+ __name(_AppInjector, "AppInjector");
179
+ AppInjector = _AppInjector;
180
+ RootInjector = new AppInjector("root");
181
+ __name(inject, "inject");
182
+ }
183
+ });
458
184
 
459
185
  // src/utils/logger.ts
460
186
  import * as fs from "fs";
@@ -463,7 +189,6 @@ function getPrettyTimestamp() {
463
189
  const now = /* @__PURE__ */ new Date();
464
190
  return `${now.getDate().toString().padStart(2, "0")}/${(now.getMonth() + 1).toString().padStart(2, "0")}/${now.getFullYear()} ${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}`;
465
191
  }
466
- __name(getPrettyTimestamp, "getPrettyTimestamp");
467
192
  function getLogPrefix(callee, messageType, color) {
468
193
  const timestamp = getPrettyTimestamp();
469
194
  const spaces = " ".repeat(10 - messageType.length);
@@ -476,7 +201,6 @@ function getLogPrefix(callee, messageType, color) {
476
201
  }
477
202
  return `${color}[APP] ${process.pid} - ${colReset}${timestamp}${spaces}${color}${messageType.toUpperCase()}${colReset} ${colCallee}[${callee}]${colReset}`;
478
203
  }
479
- __name(getLogPrefix, "getLogPrefix");
480
204
  function formatObject(prefix, arg, enableColor = true) {
481
205
  const json = JSON.stringify(arg, null, 2);
482
206
  let colStart = "";
@@ -490,7 +214,6 @@ function formatObject(prefix, arg, enableColor = true) {
490
214
  const prefixedJson = json.split("\n").map((line, idx) => idx === 0 ? `${colStart}${line}` : `${prefix} ${colLine}${line}`).join("\n") + colReset;
491
215
  return prefixedJson;
492
216
  }
493
- __name(formatObject, "formatObject");
494
217
  function formattedArgs(prefix, args, color) {
495
218
  let colReset = Logger.colors.initial;
496
219
  if (color === void 0) {
@@ -506,17 +229,14 @@ function formattedArgs(prefix, args, color) {
506
229
  return arg;
507
230
  });
508
231
  }
509
- __name(formattedArgs, "formattedArgs");
510
232
  function getCallee() {
511
233
  const stack = new Error().stack?.split("\n") ?? [];
512
234
  const caller = stack[3]?.trim().match(/at (.+?)(?:\..+)? .+$/)?.[1]?.replace("Object", "").replace(/^_/, "") || "App";
513
235
  return caller;
514
236
  }
515
- __name(getCallee, "getCallee");
516
237
  function canLog(level) {
517
238
  return logLevels.has(level);
518
239
  }
519
- __name(canLog, "canLog");
520
240
  function processLogQueue(filepath) {
521
241
  const state = fileStates.get(filepath);
522
242
  if (!state || state.isWriting || state.queue.length === 0) {
@@ -526,17 +246,13 @@ function processLogQueue(filepath) {
526
246
  const messagesToWrite = state.queue.join("\n") + "\n";
527
247
  state.queue = [];
528
248
  const dir = path.dirname(filepath);
529
- fs.mkdir(dir, {
530
- recursive: true
531
- }, (err) => {
249
+ fs.mkdir(dir, { recursive: true }, (err) => {
532
250
  if (err) {
533
251
  console.error(`[Logger] Failed to create directory ${dir}`, err);
534
252
  state.isWriting = false;
535
253
  return;
536
254
  }
537
- fs.appendFile(filepath, messagesToWrite, {
538
- encoding: "utf-8"
539
- }, (err2) => {
255
+ fs.appendFile(filepath, messagesToWrite, { encoding: "utf-8" }, (err2) => {
540
256
  state.isWriting = false;
541
257
  if (err2) {
542
258
  console.error(`[Logger] Failed to write log to ${filepath}`, err2);
@@ -547,19 +263,14 @@ function processLogQueue(filepath) {
547
263
  });
548
264
  });
549
265
  }
550
- __name(processLogQueue, "processLogQueue");
551
266
  function enqueue(filepath, message) {
552
267
  if (!fileStates.has(filepath)) {
553
- fileStates.set(filepath, {
554
- queue: [],
555
- isWriting: false
556
- });
268
+ fileStates.set(filepath, { queue: [], isWriting: false });
557
269
  }
558
270
  const state = fileStates.get(filepath);
559
271
  state.queue.push(message);
560
272
  processLogQueue(filepath);
561
273
  }
562
- __name(enqueue, "enqueue");
563
274
  function output(level, args) {
564
275
  if (!canLog(level)) {
565
276
  return;
@@ -580,323 +291,548 @@ function output(level, args) {
580
291
  }
581
292
  }
582
293
  }
583
- __name(output, "output");
584
- (function(Logger2) {
585
- function setLogLevel(level) {
586
- logLevels.clear();
587
- if (Array.isArray(level)) {
588
- for (const lvl of level) {
589
- logLevels.add(lvl);
590
- }
591
- } else {
592
- const targetRank = logLevelRank[level];
593
- for (const [lvl, rank] of Object.entries(logLevelRank)) {
594
- if (rank >= targetRank) {
595
- logLevels.add(lvl);
294
+ var Logger, fileSettings, fileStates, logLevels, logLevelRank, logLevelColors, logLevelChannel;
295
+ var init_logger = __esm({
296
+ "src/utils/logger.ts"() {
297
+ "use strict";
298
+ __name(getPrettyTimestamp, "getPrettyTimestamp");
299
+ __name(getLogPrefix, "getLogPrefix");
300
+ __name(formatObject, "formatObject");
301
+ __name(formattedArgs, "formattedArgs");
302
+ __name(getCallee, "getCallee");
303
+ __name(canLog, "canLog");
304
+ __name(processLogQueue, "processLogQueue");
305
+ __name(enqueue, "enqueue");
306
+ __name(output, "output");
307
+ ((Logger2) => {
308
+ function setLogLevel(level) {
309
+ logLevels.clear();
310
+ if (Array.isArray(level)) {
311
+ for (const lvl of level) {
312
+ logLevels.add(lvl);
313
+ }
314
+ } else {
315
+ const targetRank = logLevelRank[level];
316
+ for (const [lvl, rank] of Object.entries(logLevelRank)) {
317
+ if (rank >= targetRank) {
318
+ logLevels.add(lvl);
319
+ }
320
+ }
596
321
  }
597
322
  }
598
- }
599
- }
600
- __name(setLogLevel, "setLogLevel");
601
- Logger2.setLogLevel = setLogLevel;
602
- function log(...args) {
603
- output("log", args);
604
- }
605
- __name(log, "log");
606
- Logger2.log = log;
607
- function info(...args) {
608
- output("info", args);
609
- }
610
- __name(info, "info");
611
- Logger2.info = info;
612
- function warn(...args) {
613
- output("warn", args);
614
- }
615
- __name(warn, "warn");
616
- Logger2.warn = warn;
617
- function error(...args) {
618
- output("error", args);
619
- }
620
- __name(error, "error");
621
- Logger2.error = error;
622
- function errorStack(...args) {
623
- output("error", args);
624
- }
625
- __name(errorStack, "errorStack");
626
- Logger2.errorStack = errorStack;
627
- function debug(...args) {
628
- output("debug", args);
629
- }
630
- __name(debug, "debug");
631
- Logger2.debug = debug;
632
- function comment(...args) {
633
- output("comment", args);
634
- }
635
- __name(comment, "comment");
636
- Logger2.comment = comment;
637
- function critical(...args) {
638
- output("critical", args);
639
- }
640
- __name(critical, "critical");
641
- Logger2.critical = critical;
642
- function enableFileLogging(filepath, levels = [
643
- "debug",
644
- "comment",
645
- "log",
646
- "info",
647
- "warn",
648
- "error",
649
- "critical"
650
- ]) {
651
- for (const level of levels) {
652
- fileSettings.set(level, {
653
- filepath
654
- });
655
- }
656
- }
657
- __name(enableFileLogging, "enableFileLogging");
658
- Logger2.enableFileLogging = enableFileLogging;
659
- function disableFileLogging(levels = [
660
- "debug",
661
- "comment",
662
- "log",
663
- "info",
664
- "warn",
665
- "error",
666
- "critical"
667
- ]) {
668
- for (const level of levels) {
669
- fileSettings.delete(level);
670
- }
323
+ Logger2.setLogLevel = setLogLevel;
324
+ __name(setLogLevel, "setLogLevel");
325
+ function log(...args) {
326
+ output("log", args);
327
+ }
328
+ Logger2.log = log;
329
+ __name(log, "log");
330
+ function info(...args) {
331
+ output("info", args);
332
+ }
333
+ Logger2.info = info;
334
+ __name(info, "info");
335
+ function warn(...args) {
336
+ output("warn", args);
337
+ }
338
+ Logger2.warn = warn;
339
+ __name(warn, "warn");
340
+ function error(...args) {
341
+ output("error", args);
342
+ }
343
+ Logger2.error = error;
344
+ __name(error, "error");
345
+ function errorStack(...args) {
346
+ output("error", args);
347
+ }
348
+ Logger2.errorStack = errorStack;
349
+ __name(errorStack, "errorStack");
350
+ function debug(...args) {
351
+ output("debug", args);
352
+ }
353
+ Logger2.debug = debug;
354
+ __name(debug, "debug");
355
+ function comment(...args) {
356
+ output("comment", args);
357
+ }
358
+ Logger2.comment = comment;
359
+ __name(comment, "comment");
360
+ function critical(...args) {
361
+ output("critical", args);
362
+ }
363
+ Logger2.critical = critical;
364
+ __name(critical, "critical");
365
+ function enableFileLogging(filepath, levels = ["debug", "comment", "log", "info", "warn", "error", "critical"]) {
366
+ for (const level of levels) {
367
+ fileSettings.set(level, { filepath });
368
+ }
369
+ }
370
+ Logger2.enableFileLogging = enableFileLogging;
371
+ __name(enableFileLogging, "enableFileLogging");
372
+ function disableFileLogging(levels = ["debug", "comment", "log", "info", "warn", "error", "critical"]) {
373
+ for (const level of levels) {
374
+ fileSettings.delete(level);
375
+ }
376
+ }
377
+ Logger2.disableFileLogging = disableFileLogging;
378
+ __name(disableFileLogging, "disableFileLogging");
379
+ Logger2.colors = {
380
+ black: "\x1B[0;30m",
381
+ grey: "\x1B[0;37m",
382
+ red: "\x1B[0;31m",
383
+ green: "\x1B[0;32m",
384
+ brown: "\x1B[0;33m",
385
+ blue: "\x1B[0;34m",
386
+ purple: "\x1B[0;35m",
387
+ darkGrey: "\x1B[1;30m",
388
+ lightRed: "\x1B[1;31m",
389
+ lightGreen: "\x1B[1;32m",
390
+ yellow: "\x1B[1;33m",
391
+ lightBlue: "\x1B[1;34m",
392
+ magenta: "\x1B[1;35m",
393
+ cyan: "\x1B[1;36m",
394
+ white: "\x1B[1;37m",
395
+ initial: "\x1B[0m"
396
+ };
397
+ })(Logger || (Logger = {}));
398
+ fileSettings = /* @__PURE__ */ new Map();
399
+ fileStates = /* @__PURE__ */ new Map();
400
+ logLevels = /* @__PURE__ */ new Set();
401
+ logLevelRank = {
402
+ debug: 0,
403
+ comment: 1,
404
+ log: 2,
405
+ info: 3,
406
+ warn: 4,
407
+ error: 5,
408
+ critical: 6
409
+ };
410
+ logLevelColors = {
411
+ debug: Logger.colors.purple,
412
+ comment: Logger.colors.grey,
413
+ log: Logger.colors.green,
414
+ info: Logger.colors.blue,
415
+ warn: Logger.colors.brown,
416
+ error: Logger.colors.red,
417
+ critical: Logger.colors.lightRed
418
+ };
419
+ logLevelChannel = {
420
+ debug: console.debug,
421
+ comment: console.debug,
422
+ log: console.log,
423
+ info: console.info,
424
+ warn: console.warn,
425
+ error: console.error,
426
+ critical: console.error
427
+ };
428
+ Logger.setLogLevel("debug");
671
429
  }
672
- __name(disableFileLogging, "disableFileLogging");
673
- Logger2.disableFileLogging = disableFileLogging;
674
- Logger2.colors = {
675
- black: "\x1B[0;30m",
676
- grey: "\x1B[0;37m",
677
- red: "\x1B[0;31m",
678
- green: "\x1B[0;32m",
679
- brown: "\x1B[0;33m",
680
- blue: "\x1B[0;34m",
681
- purple: "\x1B[0;35m",
682
- darkGrey: "\x1B[1;30m",
683
- lightRed: "\x1B[1;31m",
684
- lightGreen: "\x1B[1;32m",
685
- yellow: "\x1B[1;33m",
686
- lightBlue: "\x1B[1;34m",
687
- magenta: "\x1B[1;35m",
688
- cyan: "\x1B[1;36m",
689
- white: "\x1B[1;37m",
690
- initial: "\x1B[0m"
691
- };
692
- })(Logger || (Logger = {}));
693
- var fileSettings = /* @__PURE__ */ new Map();
694
- var fileStates = /* @__PURE__ */ new Map();
695
- var logLevels = /* @__PURE__ */ new Set();
696
- var logLevelRank = {
697
- debug: 0,
698
- comment: 1,
699
- log: 2,
700
- info: 3,
701
- warn: 4,
702
- error: 5,
703
- critical: 6
704
- };
705
- var logLevelColors = {
706
- debug: Logger.colors.purple,
707
- comment: Logger.colors.grey,
708
- log: Logger.colors.green,
709
- info: Logger.colors.blue,
710
- warn: Logger.colors.brown,
711
- error: Logger.colors.red,
712
- critical: Logger.colors.lightRed
713
- };
714
- var logLevelChannel = {
715
- debug: console.debug,
716
- comment: console.debug,
717
- log: console.log,
718
- info: console.info,
719
- warn: console.warn,
720
- error: console.error,
721
- critical: console.error
722
- };
723
- Logger.setLogLevel("debug");
724
- var Logger;
430
+ });
725
431
 
726
432
  // src/DI/injector-explorer.ts
727
- var _InjectorExplorer = class _InjectorExplorer {
728
- /**
729
- * Enqueues a class for deferred registration.
730
- * Called by the @Injectable decorator at import time.
731
- *
732
- * If {@link processPending} has already been called (i.e. after bootstrap),
733
- * the class is registered immediately so that late dynamic imports
734
- * (e.g. middlewares loaded after bootstrap) work correctly.
735
- */
736
- static enqueue(target, lifetime) {
737
- if (_InjectorExplorer.processed) {
738
- _InjectorExplorer.registerImmediate(target, lifetime);
739
- return;
740
- }
741
- _InjectorExplorer.pending.push({
742
- target,
743
- lifetime
744
- });
745
- }
746
- /**
747
- * Processes all pending registrations in two phases:
748
- * 1. Register all bindings (no instantiation) so every dependency is known.
749
- * 2. Resolve singletons, register controllers and log module readiness.
750
- *
751
- * This two-phase approach makes the system resilient to import ordering:
752
- * all bindings exist before any singleton is instantiated.
753
- */
754
- static processPending() {
755
- const queue = _InjectorExplorer.pending;
756
- for (const { target, lifetime } of queue) {
757
- if (!RootInjector.bindings.has(target)) {
758
- RootInjector.bindings.set(target, {
759
- implementation: target,
760
- lifetime
761
- });
433
+ var _InjectorExplorer, InjectorExplorer;
434
+ var init_injector_explorer = __esm({
435
+ "src/DI/injector-explorer.ts"() {
436
+ "use strict";
437
+ init_app_injector();
438
+ init_logger();
439
+ _InjectorExplorer = class _InjectorExplorer {
440
+ // -------------------------------------------------------------------------
441
+ // Public API
442
+ // -------------------------------------------------------------------------
443
+ static enqueue(reg) {
444
+ if (_InjectorExplorer.processed && !_InjectorExplorer.accumulating) {
445
+ _InjectorExplorer._registerImmediate(reg);
446
+ return;
447
+ }
448
+ _InjectorExplorer.pending.push(reg);
762
449
  }
763
- }
764
- for (const { target, lifetime } of queue) {
765
- _InjectorExplorer.processRegistration(target, lifetime);
766
- }
767
- queue.length = 0;
768
- _InjectorExplorer.processed = true;
450
+ /**
451
+ * Two-phase flush of all pending registrations collected at startup.
452
+ * Called by bootstrapApplication after app.whenReady().
453
+ */
454
+ static processPending(singletonOverrides) {
455
+ const queue = [..._InjectorExplorer.pending];
456
+ _InjectorExplorer.pending.length = 0;
457
+ _InjectorExplorer._phaseOne(queue);
458
+ _InjectorExplorer._phaseTwo(queue, singletonOverrides);
459
+ _InjectorExplorer.processed = true;
460
+ }
461
+ /** Enters accumulation mode for lazy-loaded batches. */
462
+ static beginAccumulate() {
463
+ _InjectorExplorer.accumulating = true;
464
+ }
465
+ /**
466
+ * Exits accumulation mode and flushes queued registrations
467
+ * with the same two-phase guarantee as processPending.
468
+ */
469
+ static flushAccumulated(routeGuards = [], routeMiddlewares = [], pathPrefix = "") {
470
+ _InjectorExplorer.accumulating = false;
471
+ const queue = [..._InjectorExplorer.pending];
472
+ _InjectorExplorer.pending.length = 0;
473
+ _InjectorExplorer._phaseOne(queue);
474
+ for (const reg of queue) {
475
+ if (reg.isController) reg.pathPrefix = pathPrefix;
476
+ }
477
+ _InjectorExplorer._phaseTwo(queue, void 0, routeGuards, routeMiddlewares);
478
+ }
479
+ // -------------------------------------------------------------------------
480
+ // Private helpers
481
+ // -------------------------------------------------------------------------
482
+ /** Phase 1: register all bindings without instantiating anything. */
483
+ static _phaseOne(queue) {
484
+ for (const reg of queue) {
485
+ RootInjector.register(reg.key, reg.implementation, reg.lifetime, reg.deps);
486
+ }
487
+ }
488
+ /** Phase 2: resolve singletons and register controllers in the router. */
489
+ static _phaseTwo(queue, overrides, routeGuards = [], routeMiddlewares = []) {
490
+ for (const reg of queue) {
491
+ if (overrides?.has(reg.key)) {
492
+ const override = overrides.get(reg.key);
493
+ RootInjector.singletons.set(reg.key, override);
494
+ Logger.log(`Registered ${reg.implementation.name} as singleton (overridden)`);
495
+ continue;
496
+ }
497
+ if (reg.lifetime === "singleton") {
498
+ RootInjector.resolve(reg.key);
499
+ }
500
+ if (reg.isController) {
501
+ const { Router: Router2 } = (init_router(), __toCommonJS(router_exports));
502
+ const router = RootInjector.resolve(Router2);
503
+ router.registerController(reg.implementation, reg.pathPrefix ?? "", routeGuards, routeMiddlewares);
504
+ } else if (reg.lifetime !== "singleton") {
505
+ Logger.log(`Registered ${reg.implementation.name} as ${reg.lifetime}`);
506
+ }
507
+ }
508
+ }
509
+ static _registerImmediate(reg) {
510
+ RootInjector.register(reg.key, reg.implementation, reg.lifetime, reg.deps);
511
+ if (reg.lifetime === "singleton") {
512
+ RootInjector.resolve(reg.key);
513
+ }
514
+ if (reg.isController) {
515
+ const { Router: Router2 } = (init_router(), __toCommonJS(router_exports));
516
+ const router = RootInjector.resolve(Router2);
517
+ router.registerController(reg.implementation);
518
+ }
519
+ }
520
+ };
521
+ __name(_InjectorExplorer, "InjectorExplorer");
522
+ _InjectorExplorer.pending = [];
523
+ _InjectorExplorer.processed = false;
524
+ _InjectorExplorer.accumulating = false;
525
+ InjectorExplorer = _InjectorExplorer;
769
526
  }
770
- /**
771
- * Registers a single class immediately (post-bootstrap path).
772
- * Used for classes discovered via late dynamic imports.
773
- */
774
- static registerImmediate(target, lifetime) {
775
- if (RootInjector.bindings.has(target)) {
776
- return;
777
- }
778
- RootInjector.bindings.set(target, {
527
+ });
528
+
529
+ // src/decorators/controller.decorator.ts
530
+ function Controller(options = {}) {
531
+ return (target) => {
532
+ const meta = {
533
+ deps: options.deps ?? []
534
+ };
535
+ controllerMetaMap.set(target, meta);
536
+ InjectorExplorer.enqueue({
537
+ key: target,
779
538
  implementation: target,
780
- lifetime
539
+ lifetime: "scope",
540
+ deps: options.deps ?? [],
541
+ isController: true
781
542
  });
782
- _InjectorExplorer.processRegistration(target, lifetime);
783
- }
784
- /**
785
- * Performs phase-2 work for a single registration: resolve singletons,
786
- * register controllers, and log module readiness.
787
- */
788
- static processRegistration(target, lifetime) {
789
- if (lifetime === "singleton") {
790
- RootInjector.resolve(target);
791
- }
792
- if (getModuleMetadata(target)) {
793
- Logger.log(`${target.name} dependencies initialized`);
794
- return;
795
- }
796
- const controllerMeta = getControllerMetadata(target);
797
- if (controllerMeta) {
798
- const router = RootInjector.resolve(Router);
799
- router?.registerController(target);
800
- return;
801
- }
802
- if (getRouteMetadata(target).length > 0) {
803
- return;
804
- }
805
- if (getInjectableMetadata(target)) {
806
- Logger.log(`Registered ${target.name} as ${lifetime}`);
807
- }
808
- }
809
- };
810
- __name(_InjectorExplorer, "InjectorExplorer");
811
- __publicField(_InjectorExplorer, "pending", []);
812
- __publicField(_InjectorExplorer, "processed", false);
813
- var InjectorExplorer = _InjectorExplorer;
543
+ };
544
+ }
545
+ function getControllerMetadata(target) {
546
+ return controllerMetaMap.get(target);
547
+ }
548
+ var controllerMetaMap;
549
+ var init_controller_decorator = __esm({
550
+ "src/decorators/controller.decorator.ts"() {
551
+ "use strict";
552
+ init_injector_explorer();
553
+ controllerMetaMap = /* @__PURE__ */ new WeakMap();
554
+ __name(Controller, "Controller");
555
+ __name(getControllerMetadata, "getControllerMetadata");
556
+ }
557
+ });
814
558
 
815
559
  // src/decorators/injectable.decorator.ts
816
- function Injectable(lifetime = "scope") {
560
+ function Injectable(options = {}) {
561
+ const { lifetime = "scope", deps = [] } = options;
817
562
  return (target) => {
818
563
  if (typeof target !== "function" || !target.prototype) {
819
- throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`);
820
- }
821
- defineInjectableMetadata(target, lifetime);
822
- InjectorExplorer.enqueue(target, lifetime);
564
+ throw new Error(`@Injectable can only be applied to classes, not ${typeof target}`);
565
+ }
566
+ const key = target;
567
+ InjectorExplorer.enqueue({
568
+ key,
569
+ implementation: key,
570
+ lifetime,
571
+ deps,
572
+ isController: false
573
+ });
823
574
  };
824
575
  }
825
- __name(Injectable, "Injectable");
576
+ var init_injectable_decorator = __esm({
577
+ "src/decorators/injectable.decorator.ts"() {
578
+ "use strict";
579
+ init_injector_explorer();
580
+ init_token();
581
+ __name(Injectable, "Injectable");
582
+ }
583
+ });
826
584
 
827
- // src/decorators/controller.decorator.ts
828
- function Controller(path2) {
829
- return (target) => {
830
- const data = {
831
- path: path2,
832
- guards: getGuardForController(target.name)
585
+ // src/decorators/method.decorator.ts
586
+ function isAtomicHttpMethod(m) {
587
+ return typeof m === "string" && ATOMIC_METHODS.has(m);
588
+ }
589
+ function createRouteDecorator(verb) {
590
+ return (path2, options = {}) => {
591
+ return (target, propertyKey) => {
592
+ const ctor = target.constructor;
593
+ const existing = routeMetaMap.get(ctor) ?? [];
594
+ existing.push({
595
+ method: verb,
596
+ path: (path2 ?? "").trim().replace(/^\/|\/$/g, ""),
597
+ handler: propertyKey,
598
+ guards: options.guards ?? [],
599
+ middlewares: options.middlewares ?? []
600
+ });
601
+ routeMetaMap.set(ctor, existing);
833
602
  };
834
- Reflect.defineMetadata(CONTROLLER_METADATA_KEY, data, target);
835
- Injectable("scope")(target);
836
603
  };
837
604
  }
838
- __name(Controller, "Controller");
839
- function getControllerMetadata(target) {
840
- return Reflect.getMetadata(CONTROLLER_METADATA_KEY, target);
605
+ function getRouteMetadata(target) {
606
+ return routeMetaMap.get(target) ?? [];
841
607
  }
842
- __name(getControllerMetadata, "getControllerMetadata");
843
- var CONTROLLER_METADATA_KEY = Symbol("CONTROLLER_METADATA_KEY");
608
+ var ATOMIC_METHODS, routeMetaMap, Get, Post, Put, Patch, Delete;
609
+ var init_method_decorator = __esm({
610
+ "src/decorators/method.decorator.ts"() {
611
+ "use strict";
612
+ ATOMIC_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
613
+ __name(isAtomicHttpMethod, "isAtomicHttpMethod");
614
+ routeMetaMap = /* @__PURE__ */ new WeakMap();
615
+ __name(createRouteDecorator, "createRouteDecorator");
616
+ __name(getRouteMetadata, "getRouteMetadata");
617
+ Get = createRouteDecorator("GET");
618
+ Post = createRouteDecorator("POST");
619
+ Put = createRouteDecorator("PUT");
620
+ Patch = createRouteDecorator("PATCH");
621
+ Delete = createRouteDecorator("DELETE");
622
+ }
623
+ });
844
624
 
845
- // src/decorators/middleware.decorator.ts
846
- function UseMiddlewares(mdlw) {
847
- return (target, propertyKey) => {
848
- let key;
849
- if (propertyKey) {
850
- const ctrlName = target.constructor.name;
851
- const actionName = propertyKey;
852
- key = `${ctrlName}.${actionName}`;
853
- } else {
854
- const ctrlName = target.name;
855
- key = `${ctrlName}`;
856
- }
857
- if (middlewares.has(key)) {
858
- throw new Error(`Middlewares(s) already registered for ${key}`);
859
- }
860
- middlewares.set(key, mdlw);
861
- };
862
- }
863
- __name(UseMiddlewares, "UseMiddlewares");
864
- function getMiddlewaresForController(controllerName) {
865
- const key = `${controllerName}`;
866
- return middlewares.get(key) ?? [];
867
- }
868
- __name(getMiddlewaresForController, "getMiddlewaresForController");
869
- function getMiddlewaresForControllerAction(controllerName, actionName) {
870
- const key = `${controllerName}.${actionName}`;
871
- return middlewares.get(key) ?? [];
872
- }
873
- __name(getMiddlewaresForControllerAction, "getMiddlewaresForControllerAction");
874
- var middlewares = /* @__PURE__ */ new Map();
625
+ // src/exceptions.ts
626
+ var _ResponseException, ResponseException, _BadRequestException, BadRequestException, _UnauthorizedException, UnauthorizedException, _PaymentRequiredException, PaymentRequiredException, _ForbiddenException, ForbiddenException, _NotFoundException, NotFoundException, _MethodNotAllowedException, MethodNotAllowedException, _NotAcceptableException, NotAcceptableException, _RequestTimeoutException, RequestTimeoutException, _ConflictException, ConflictException, _UpgradeRequiredException, UpgradeRequiredException, _TooManyRequestsException, TooManyRequestsException, _InternalServerException, InternalServerException, _NotImplementedException, NotImplementedException, _BadGatewayException, BadGatewayException, _ServiceUnavailableException, ServiceUnavailableException, _GatewayTimeoutException, GatewayTimeoutException, _HttpVersionNotSupportedException, HttpVersionNotSupportedException, _VariantAlsoNegotiatesException, VariantAlsoNegotiatesException, _InsufficientStorageException, InsufficientStorageException, _LoopDetectedException, LoopDetectedException, _NotExtendedException, NotExtendedException, _NetworkAuthenticationRequiredException, NetworkAuthenticationRequiredException, _NetworkConnectTimeoutException, NetworkConnectTimeoutException;
627
+ var init_exceptions = __esm({
628
+ "src/exceptions.ts"() {
629
+ "use strict";
630
+ _ResponseException = class _ResponseException extends Error {
631
+ constructor(statusOrMessage, message) {
632
+ let statusCode;
633
+ if (typeof statusOrMessage === "number") {
634
+ statusCode = statusOrMessage;
635
+ } else if (typeof statusOrMessage === "string") {
636
+ message = statusOrMessage;
637
+ }
638
+ super(message ?? "");
639
+ this.status = 0;
640
+ if (statusCode !== void 0) {
641
+ this.status = statusCode;
642
+ }
643
+ this.name = this.constructor.name.replace(/([A-Z])/g, " $1");
644
+ }
645
+ };
646
+ __name(_ResponseException, "ResponseException");
647
+ ResponseException = _ResponseException;
648
+ _BadRequestException = class _BadRequestException extends ResponseException {
649
+ constructor() {
650
+ super(...arguments);
651
+ this.status = 400;
652
+ }
653
+ };
654
+ __name(_BadRequestException, "BadRequestException");
655
+ BadRequestException = _BadRequestException;
656
+ _UnauthorizedException = class _UnauthorizedException extends ResponseException {
657
+ constructor() {
658
+ super(...arguments);
659
+ this.status = 401;
660
+ }
661
+ };
662
+ __name(_UnauthorizedException, "UnauthorizedException");
663
+ UnauthorizedException = _UnauthorizedException;
664
+ _PaymentRequiredException = class _PaymentRequiredException extends ResponseException {
665
+ constructor() {
666
+ super(...arguments);
667
+ this.status = 402;
668
+ }
669
+ };
670
+ __name(_PaymentRequiredException, "PaymentRequiredException");
671
+ PaymentRequiredException = _PaymentRequiredException;
672
+ _ForbiddenException = class _ForbiddenException extends ResponseException {
673
+ constructor() {
674
+ super(...arguments);
675
+ this.status = 403;
676
+ }
677
+ };
678
+ __name(_ForbiddenException, "ForbiddenException");
679
+ ForbiddenException = _ForbiddenException;
680
+ _NotFoundException = class _NotFoundException extends ResponseException {
681
+ constructor() {
682
+ super(...arguments);
683
+ this.status = 404;
684
+ }
685
+ };
686
+ __name(_NotFoundException, "NotFoundException");
687
+ NotFoundException = _NotFoundException;
688
+ _MethodNotAllowedException = class _MethodNotAllowedException extends ResponseException {
689
+ constructor() {
690
+ super(...arguments);
691
+ this.status = 405;
692
+ }
693
+ };
694
+ __name(_MethodNotAllowedException, "MethodNotAllowedException");
695
+ MethodNotAllowedException = _MethodNotAllowedException;
696
+ _NotAcceptableException = class _NotAcceptableException extends ResponseException {
697
+ constructor() {
698
+ super(...arguments);
699
+ this.status = 406;
700
+ }
701
+ };
702
+ __name(_NotAcceptableException, "NotAcceptableException");
703
+ NotAcceptableException = _NotAcceptableException;
704
+ _RequestTimeoutException = class _RequestTimeoutException extends ResponseException {
705
+ constructor() {
706
+ super(...arguments);
707
+ this.status = 408;
708
+ }
709
+ };
710
+ __name(_RequestTimeoutException, "RequestTimeoutException");
711
+ RequestTimeoutException = _RequestTimeoutException;
712
+ _ConflictException = class _ConflictException extends ResponseException {
713
+ constructor() {
714
+ super(...arguments);
715
+ this.status = 409;
716
+ }
717
+ };
718
+ __name(_ConflictException, "ConflictException");
719
+ ConflictException = _ConflictException;
720
+ _UpgradeRequiredException = class _UpgradeRequiredException extends ResponseException {
721
+ constructor() {
722
+ super(...arguments);
723
+ this.status = 426;
724
+ }
725
+ };
726
+ __name(_UpgradeRequiredException, "UpgradeRequiredException");
727
+ UpgradeRequiredException = _UpgradeRequiredException;
728
+ _TooManyRequestsException = class _TooManyRequestsException extends ResponseException {
729
+ constructor() {
730
+ super(...arguments);
731
+ this.status = 429;
732
+ }
733
+ };
734
+ __name(_TooManyRequestsException, "TooManyRequestsException");
735
+ TooManyRequestsException = _TooManyRequestsException;
736
+ _InternalServerException = class _InternalServerException extends ResponseException {
737
+ constructor() {
738
+ super(...arguments);
739
+ this.status = 500;
740
+ }
741
+ };
742
+ __name(_InternalServerException, "InternalServerException");
743
+ InternalServerException = _InternalServerException;
744
+ _NotImplementedException = class _NotImplementedException extends ResponseException {
745
+ constructor() {
746
+ super(...arguments);
747
+ this.status = 501;
748
+ }
749
+ };
750
+ __name(_NotImplementedException, "NotImplementedException");
751
+ NotImplementedException = _NotImplementedException;
752
+ _BadGatewayException = class _BadGatewayException extends ResponseException {
753
+ constructor() {
754
+ super(...arguments);
755
+ this.status = 502;
756
+ }
757
+ };
758
+ __name(_BadGatewayException, "BadGatewayException");
759
+ BadGatewayException = _BadGatewayException;
760
+ _ServiceUnavailableException = class _ServiceUnavailableException extends ResponseException {
761
+ constructor() {
762
+ super(...arguments);
763
+ this.status = 503;
764
+ }
765
+ };
766
+ __name(_ServiceUnavailableException, "ServiceUnavailableException");
767
+ ServiceUnavailableException = _ServiceUnavailableException;
768
+ _GatewayTimeoutException = class _GatewayTimeoutException extends ResponseException {
769
+ constructor() {
770
+ super(...arguments);
771
+ this.status = 504;
772
+ }
773
+ };
774
+ __name(_GatewayTimeoutException, "GatewayTimeoutException");
775
+ GatewayTimeoutException = _GatewayTimeoutException;
776
+ _HttpVersionNotSupportedException = class _HttpVersionNotSupportedException extends ResponseException {
777
+ constructor() {
778
+ super(...arguments);
779
+ this.status = 505;
780
+ }
781
+ };
782
+ __name(_HttpVersionNotSupportedException, "HttpVersionNotSupportedException");
783
+ HttpVersionNotSupportedException = _HttpVersionNotSupportedException;
784
+ _VariantAlsoNegotiatesException = class _VariantAlsoNegotiatesException extends ResponseException {
785
+ constructor() {
786
+ super(...arguments);
787
+ this.status = 506;
788
+ }
789
+ };
790
+ __name(_VariantAlsoNegotiatesException, "VariantAlsoNegotiatesException");
791
+ VariantAlsoNegotiatesException = _VariantAlsoNegotiatesException;
792
+ _InsufficientStorageException = class _InsufficientStorageException extends ResponseException {
793
+ constructor() {
794
+ super(...arguments);
795
+ this.status = 507;
796
+ }
797
+ };
798
+ __name(_InsufficientStorageException, "InsufficientStorageException");
799
+ InsufficientStorageException = _InsufficientStorageException;
800
+ _LoopDetectedException = class _LoopDetectedException extends ResponseException {
801
+ constructor() {
802
+ super(...arguments);
803
+ this.status = 508;
804
+ }
805
+ };
806
+ __name(_LoopDetectedException, "LoopDetectedException");
807
+ LoopDetectedException = _LoopDetectedException;
808
+ _NotExtendedException = class _NotExtendedException extends ResponseException {
809
+ constructor() {
810
+ super(...arguments);
811
+ this.status = 510;
812
+ }
813
+ };
814
+ __name(_NotExtendedException, "NotExtendedException");
815
+ NotExtendedException = _NotExtendedException;
816
+ _NetworkAuthenticationRequiredException = class _NetworkAuthenticationRequiredException extends ResponseException {
817
+ constructor() {
818
+ super(...arguments);
819
+ this.status = 511;
820
+ }
821
+ };
822
+ __name(_NetworkAuthenticationRequiredException, "NetworkAuthenticationRequiredException");
823
+ NetworkAuthenticationRequiredException = _NetworkAuthenticationRequiredException;
824
+ _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException extends ResponseException {
825
+ constructor() {
826
+ super(...arguments);
827
+ this.status = 599;
828
+ }
829
+ };
830
+ __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
831
+ NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
832
+ }
833
+ });
875
834
 
876
835
  // src/request.ts
877
- import "reflect-metadata";
878
- var _Request = class _Request {
879
- constructor(event, senderId, id, method, path2, body) {
880
- __publicField(this, "event");
881
- __publicField(this, "senderId");
882
- __publicField(this, "id");
883
- __publicField(this, "method");
884
- __publicField(this, "path");
885
- __publicField(this, "body");
886
- __publicField(this, "context", RootInjector.createScope());
887
- __publicField(this, "params", {});
888
- this.event = event;
889
- this.senderId = senderId;
890
- this.id = id;
891
- this.method = method;
892
- this.path = path2;
893
- this.body = body;
894
- this.path = path2.replace(/^\/|\/$/g, "");
895
- }
896
- };
897
- __name(_Request, "Request");
898
- var Request = _Request;
899
- var RENDERER_EVENT_TYPE = "noxus:event";
900
836
  function createRendererEventMessage(event, payload) {
901
837
  return {
902
838
  type: RENDERER_EVENT_TYPE,
@@ -904,7 +840,6 @@ function createRendererEventMessage(event, payload) {
904
840
  payload
905
841
  };
906
842
  }
907
- __name(createRendererEventMessage, "createRendererEventMessage");
908
843
  function isRendererEventMessage(value) {
909
844
  if (value === null || typeof value !== "object") {
910
845
  return false;
@@ -912,572 +847,472 @@ function isRendererEventMessage(value) {
912
847
  const possibleMessage = value;
913
848
  return possibleMessage.type === RENDERER_EVENT_TYPE && typeof possibleMessage.event === "string";
914
849
  }
915
- __name(isRendererEventMessage, "isRendererEventMessage");
850
+ var _Request, Request, RENDERER_EVENT_TYPE;
851
+ var init_request = __esm({
852
+ "src/request.ts"() {
853
+ "use strict";
854
+ init_app_injector();
855
+ _Request = class _Request {
856
+ constructor(event, senderId, id, method, path2, body) {
857
+ this.event = event;
858
+ this.senderId = senderId;
859
+ this.id = id;
860
+ this.method = method;
861
+ this.path = path2;
862
+ this.body = body;
863
+ this.context = RootInjector.createScope();
864
+ this.params = {};
865
+ this.path = path2.replace(/^\/|\/$/g, "");
866
+ }
867
+ };
868
+ __name(_Request, "Request");
869
+ Request = _Request;
870
+ RENDERER_EVENT_TYPE = "noxus:event";
871
+ __name(createRendererEventMessage, "createRendererEventMessage");
872
+ __name(isRendererEventMessage, "isRendererEventMessage");
873
+ }
874
+ });
916
875
 
917
876
  // src/utils/radix-tree.ts
918
- var _a;
919
- var RadixNode = (_a = class {
920
- /**
921
- * Creates a new RadixNode.
922
- * @param segment - The segment of the path this node represents.
923
- */
924
- constructor(segment) {
925
- __publicField(this, "segment");
926
- __publicField(this, "children", []);
927
- __publicField(this, "value");
928
- __publicField(this, "isParam");
929
- __publicField(this, "paramName");
930
- this.segment = segment;
931
- this.isParam = segment.startsWith(":");
932
- if (this.isParam) {
933
- this.paramName = segment.slice(1);
934
- }
935
- }
936
- /**
937
- * Matches a child node against a given segment.
938
- * This method checks if the segment matches any of the children nodes.
939
- * @param segment - The segment to match against the children of this node.
940
- * @returns A child node that matches the segment, or undefined if no match is found.
941
- */
942
- matchChild(segment) {
943
- for (const child of this.children) {
944
- if (child.isParam || segment.startsWith(child.segment)) return child;
945
- }
946
- return void 0;
947
- }
948
- /**
949
- * Finds a child node that matches the segment exactly.
950
- * This method checks if there is a child node that matches the segment exactly.
951
- * @param segment - The segment to find an exact match for among the children of this node.
952
- * @returns A child node that matches the segment exactly, or undefined if no match is found.
953
- */
954
- findExactChild(segment) {
955
- return this.children.find((c) => c.segment === segment);
956
- }
957
- /**
958
- * Adds a child node to this node's children.
959
- * This method adds a new child node to the list of children for this node.
960
- * @param node - The child node to add to this node's children.
961
- */
962
- addChild(node) {
963
- this.children.push(node);
964
- }
965
- }, __name(_a, "RadixNode"), _a);
966
- var _RadixTree = class _RadixTree {
967
- constructor() {
968
- __publicField(this, "root", new RadixNode(""));
969
- }
970
- /**
971
- * Inserts a path and its associated value into the Radix Tree.
972
- * This method normalizes the path and inserts it into the tree, associating it with
973
- * @param path - The path to insert into the tree.
974
- * @param value - The value to associate with the path.
975
- */
976
- insert(path2, value) {
977
- const segments = this.normalize(path2);
978
- this.insertRecursive(this.root, segments, value);
979
- }
980
- /**
981
- * Recursively inserts a path into the Radix Tree.
982
- * This method traverses the tree and inserts the segments of the path, creating new nodes
983
- * @param node - The node to start inserting from.
984
- * @param segments - The segments of the path to insert.
985
- * @param value - The value to associate with the path.
986
- */
987
- insertRecursive(node, segments, value) {
988
- if (segments.length === 0) {
989
- node.value = value;
990
- return;
991
- }
992
- const segment = segments[0] ?? "";
993
- let child = node.children.find((c) => c.isParam === segment.startsWith(":") && (c.isParam || c.segment === segment));
994
- if (!child) {
995
- child = new RadixNode(segment);
996
- node.addChild(child);
997
- }
998
- this.insertRecursive(child, segments.slice(1), value);
999
- }
1000
- /**
1001
- * Searches for a path in the Radix Tree.
1002
- * This method normalizes the path and searches for it in the tree, returning the node
1003
- * @param path - The path to search for in the Radix Tree.
1004
- * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
1005
- */
1006
- search(path2) {
1007
- const segments = this.normalize(path2);
1008
- return this.searchRecursive(this.root, segments, {});
1009
- }
1010
- /**
1011
- * Recursively searches for a path in the Radix Tree.
1012
- * This method traverses the tree and searches for the segments of the path, collecting parameters
1013
- * @param node - The node to start searching from.
1014
- * @param segments - The segments of the path to search for.
1015
- * @param params - The parameters collected during the search.
1016
- * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
1017
- */
1018
- searchRecursive(node, segments, params) {
1019
- if (segments.length === 0) {
1020
- if (node.value !== void 0) {
1021
- return {
1022
- node,
1023
- params
1024
- };
1025
- }
1026
- return void 0;
1027
- }
1028
- const [segment, ...rest] = segments;
1029
- for (const child of node.children) {
1030
- if (child.isParam) {
1031
- const paramName = child.paramName;
1032
- const childParams = {
1033
- ...params,
1034
- [paramName]: segment ?? ""
1035
- };
1036
- if (rest.length === 0) {
1037
- return {
1038
- node: child,
1039
- params: childParams
1040
- };
877
+ var _RadixNode, RadixNode, _RadixTree, RadixTree;
878
+ var init_radix_tree = __esm({
879
+ "src/utils/radix-tree.ts"() {
880
+ "use strict";
881
+ _RadixNode = class _RadixNode {
882
+ /**
883
+ * Creates a new RadixNode.
884
+ * @param segment - The segment of the path this node represents.
885
+ */
886
+ constructor(segment) {
887
+ this.children = [];
888
+ this.segment = segment;
889
+ this.isParam = segment.startsWith(":");
890
+ if (this.isParam) {
891
+ this.paramName = segment.slice(1);
1041
892
  }
1042
- const result = this.searchRecursive(child, rest, childParams);
1043
- if (result) return result;
1044
- } else if (segment === child.segment) {
1045
- if (rest.length === 0) {
1046
- return {
1047
- node: child,
1048
- params
1049
- };
893
+ }
894
+ /**
895
+ * Matches a child node against a given segment.
896
+ * This method checks if the segment matches any of the children nodes.
897
+ * @param segment - The segment to match against the children of this node.
898
+ * @returns A child node that matches the segment, or undefined if no match is found.
899
+ */
900
+ matchChild(segment) {
901
+ for (const child of this.children) {
902
+ if (child.isParam || segment.startsWith(child.segment))
903
+ return child;
1050
904
  }
1051
- const result = this.searchRecursive(child, rest, params);
1052
- if (result) return result;
905
+ return void 0;
906
+ }
907
+ /**
908
+ * Finds a child node that matches the segment exactly.
909
+ * This method checks if there is a child node that matches the segment exactly.
910
+ * @param segment - The segment to find an exact match for among the children of this node.
911
+ * @returns A child node that matches the segment exactly, or undefined if no match is found.
912
+ */
913
+ findExactChild(segment) {
914
+ return this.children.find((c) => c.segment === segment);
915
+ }
916
+ /**
917
+ * Adds a child node to this node's children.
918
+ * This method adds a new child node to the list of children for this node.
919
+ * @param node - The child node to add to this node's children.
920
+ */
921
+ addChild(node) {
922
+ this.children.push(node);
1053
923
  }
1054
- }
1055
- return void 0;
1056
- }
1057
- /**
1058
- * Normalizes a path into an array of segments.
1059
- * This method removes leading and trailing slashes, splits the path by slashes, and
1060
- * @param path - The path to normalize.
1061
- * @returns An array of normalized path segments.
1062
- */
1063
- normalize(path2) {
1064
- const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
1065
- return [
1066
- "",
1067
- ...segments
1068
- ];
1069
- }
1070
- };
1071
- __name(_RadixTree, "RadixTree");
1072
- var RadixTree = _RadixTree;
1073
-
1074
- // src/router.ts
1075
- function _ts_decorate(decorators, target, key, desc) {
1076
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1077
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1078
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1079
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1080
- }
1081
- __name(_ts_decorate, "_ts_decorate");
1082
- var ATOMIC_HTTP_METHODS = /* @__PURE__ */ new Set([
1083
- "GET",
1084
- "POST",
1085
- "PUT",
1086
- "PATCH",
1087
- "DELETE"
1088
- ]);
1089
- function isAtomicHttpMethod(method) {
1090
- return typeof method === "string" && ATOMIC_HTTP_METHODS.has(method);
1091
- }
1092
- __name(isAtomicHttpMethod, "isAtomicHttpMethod");
1093
- var _Router = class _Router {
1094
- constructor() {
1095
- __publicField(this, "routes", new RadixTree());
1096
- __publicField(this, "rootMiddlewares", []);
1097
- }
1098
- /**
1099
- * Registers a controller class with the router.
1100
- * This method extracts the route metadata from the controller class and registers it in the routing tree.
1101
- * It also handles the guards and middlewares associated with the controller.
1102
- * @param controllerClass - The controller class to register.
1103
- */
1104
- registerController(controllerClass) {
1105
- const controllerMeta = getControllerMetadata(controllerClass);
1106
- const controllerGuards = getGuardForController(controllerClass.name);
1107
- const controllerMiddlewares = getMiddlewaresForController(controllerClass.name);
1108
- if (!controllerMeta) throw new Error(`Missing @Controller decorator on ${controllerClass.name}`);
1109
- const routeMetadata = getRouteMetadata(controllerClass);
1110
- for (const def of routeMetadata) {
1111
- const fullPath = `${controllerMeta.path}/${def.path}`.replace(/\/+/g, "/");
1112
- const routeGuards = getGuardForControllerAction(controllerClass.name, def.handler);
1113
- const routeMiddlewares = getMiddlewaresForControllerAction(controllerClass.name, def.handler);
1114
- const guards = /* @__PURE__ */ new Set([
1115
- ...controllerGuards,
1116
- ...routeGuards
1117
- ]);
1118
- const middlewares2 = /* @__PURE__ */ new Set([
1119
- ...controllerMiddlewares,
1120
- ...routeMiddlewares
1121
- ]);
1122
- const routeDef = {
1123
- method: def.method,
1124
- path: fullPath,
1125
- controller: controllerClass,
1126
- handler: def.handler,
1127
- guards: [
1128
- ...guards
1129
- ],
1130
- middlewares: [
1131
- ...middlewares2
1132
- ]
1133
- };
1134
- this.routes.insert(fullPath + "/" + def.method, routeDef);
1135
- const hasActionGuards = routeDef.guards.length > 0;
1136
- const actionGuardsInfo = hasActionGuards ? "<" + routeDef.guards.map((g) => g.name).join("|") + ">" : "";
1137
- Logger.log(`Mapped {${routeDef.method} /${fullPath}}${actionGuardsInfo} route`);
1138
- }
1139
- const hasCtrlGuards = controllerMeta.guards.length > 0;
1140
- const controllerGuardsInfo = hasCtrlGuards ? "<" + controllerMeta.guards.map((g) => g.name).join("|") + ">" : "";
1141
- Logger.log(`Mapped ${controllerClass.name}${controllerGuardsInfo} controller's routes`);
1142
- return this;
1143
- }
1144
- /**
1145
- * Defines a middleware for the root of the application.
1146
- * This method allows you to register a middleware that will be applied to all requests
1147
- * to the application, regardless of the controller or action.
1148
- * @param middleware - The middleware class to register.
1149
- */
1150
- defineRootMiddleware(middleware) {
1151
- this.rootMiddlewares.push(middleware);
1152
- return this;
1153
- }
1154
- /**
1155
- * Shuts down the message channel for a specific sender ID.
1156
- * This method closes the IPC channel for the specified sender ID and
1157
- * removes it from the messagePorts map.
1158
- * @param channelSenderId - The ID of the sender channel to shut down.
1159
- */
1160
- async handle(request) {
1161
- if (request.method === "BATCH") {
1162
- return this.handleBatch(request);
1163
- }
1164
- return this.handleAtomic(request);
1165
- }
1166
- async handleAtomic(request) {
1167
- Logger.comment(`> ${request.method} /${request.path}`);
1168
- const t0 = performance.now();
1169
- const response = {
1170
- requestId: request.id,
1171
- status: 200,
1172
- body: null
1173
924
  };
1174
- let isCritical = false;
1175
- try {
1176
- const routeDef = this.findRoute(request);
1177
- await this.resolveController(request, response, routeDef);
1178
- if (response.status > 400) {
1179
- throw new ResponseException(response.status, response.error);
1180
- }
1181
- } catch (error) {
1182
- response.body = void 0;
1183
- if (error instanceof ResponseException) {
1184
- response.status = error.status;
1185
- response.error = error.message;
1186
- response.stack = error.stack;
1187
- } else if (error instanceof Error) {
1188
- isCritical = true;
1189
- response.status = 500;
1190
- response.error = error.message || "Internal Server Error";
1191
- response.stack = error.stack || "No stack trace available";
1192
- } else {
1193
- isCritical = true;
1194
- response.status = 500;
1195
- response.error = "Unknown error occurred";
1196
- response.stack = "No stack trace available";
1197
- }
1198
- } finally {
1199
- const t1 = performance.now();
1200
- const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`;
1201
- if (response.status < 400) {
1202
- Logger.log(message);
1203
- } else if (response.status < 500) {
1204
- Logger.warn(message);
1205
- } else {
1206
- if (isCritical) {
1207
- Logger.critical(message);
1208
- } else {
1209
- Logger.error(message);
925
+ __name(_RadixNode, "RadixNode");
926
+ RadixNode = _RadixNode;
927
+ _RadixTree = class _RadixTree {
928
+ constructor() {
929
+ this.root = new RadixNode("");
930
+ }
931
+ /**
932
+ * Inserts a path and its associated value into the Radix Tree.
933
+ * This method normalizes the path and inserts it into the tree, associating it with
934
+ * @param path - The path to insert into the tree.
935
+ * @param value - The value to associate with the path.
936
+ */
937
+ insert(path2, value) {
938
+ const segments = this.normalize(path2);
939
+ this.insertRecursive(this.root, segments, value);
940
+ }
941
+ /**
942
+ * Recursively inserts a path into the Radix Tree.
943
+ * This method traverses the tree and inserts the segments of the path, creating new nodes
944
+ * @param node - The node to start inserting from.
945
+ * @param segments - The segments of the path to insert.
946
+ * @param value - The value to associate with the path.
947
+ */
948
+ insertRecursive(node, segments, value) {
949
+ if (segments.length === 0) {
950
+ node.value = value;
951
+ return;
1210
952
  }
953
+ const segment = segments[0] ?? "";
954
+ let child = node.children.find(
955
+ (c) => c.isParam === segment.startsWith(":") && (c.isParam || c.segment === segment)
956
+ );
957
+ if (!child) {
958
+ child = new RadixNode(segment);
959
+ node.addChild(child);
960
+ }
961
+ this.insertRecursive(child, segments.slice(1), value);
1211
962
  }
1212
- if (response.error !== void 0) {
1213
- if (isCritical) {
1214
- Logger.critical(response.error);
1215
- } else {
1216
- Logger.error(response.error);
963
+ /**
964
+ * Searches for a path in the Radix Tree.
965
+ * This method normalizes the path and searches for it in the tree, returning the node
966
+ * @param path - The path to search for in the Radix Tree.
967
+ * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
968
+ */
969
+ search(path2) {
970
+ const segments = this.normalize(path2);
971
+ return this.searchRecursive(this.root, segments, {});
972
+ }
973
+ /**
974
+ * Recursively searches for a path in the Radix Tree.
975
+ * This method traverses the tree and searches for the segments of the path, collecting parameters
976
+ * @param node - The node to start searching from.
977
+ * @param segments - The segments of the path to search for.
978
+ * @param params - The parameters collected during the search.
979
+ * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
980
+ */
981
+ searchRecursive(node, segments, params) {
982
+ if (segments.length === 0) {
983
+ if (node.value !== void 0) {
984
+ return {
985
+ node,
986
+ params
987
+ };
988
+ }
989
+ return void 0;
1217
990
  }
1218
- if (response.stack !== void 0) {
1219
- Logger.errorStack(response.stack);
991
+ const [segment, ...rest] = segments;
992
+ for (const child of node.children) {
993
+ if (child.isParam) {
994
+ const paramName = child.paramName;
995
+ const childParams = {
996
+ ...params,
997
+ [paramName]: segment ?? ""
998
+ };
999
+ if (rest.length === 0) {
1000
+ return {
1001
+ node: child,
1002
+ params: childParams
1003
+ };
1004
+ }
1005
+ const result = this.searchRecursive(child, rest, childParams);
1006
+ if (result)
1007
+ return result;
1008
+ } else if (segment === child.segment) {
1009
+ if (rest.length === 0) {
1010
+ return {
1011
+ node: child,
1012
+ params
1013
+ };
1014
+ }
1015
+ const result = this.searchRecursive(child, rest, params);
1016
+ if (result)
1017
+ return result;
1018
+ }
1220
1019
  }
1020
+ return void 0;
1221
1021
  }
1222
- return response;
1223
- }
1224
- }
1225
- async handleBatch(request) {
1226
- Logger.comment(`> ${request.method} /${request.path}`);
1227
- const t0 = performance.now();
1228
- const response = {
1229
- requestId: request.id,
1230
- status: 200,
1231
- body: {
1232
- responses: []
1022
+ /**
1023
+ * Normalizes a path into an array of segments.
1024
+ * This method removes leading and trailing slashes, splits the path by slashes, and
1025
+ * @param path - The path to normalize.
1026
+ * @returns An array of normalized path segments.
1027
+ */
1028
+ normalize(path2) {
1029
+ const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
1030
+ return ["", ...segments];
1233
1031
  }
1234
1032
  };
1235
- let isCritical = false;
1236
- try {
1237
- const payload = this.normalizeBatchPayload(request.body);
1238
- const batchPromises = payload.requests.map((item, index) => {
1239
- const subRequestId = item.requestId ?? `${request.id}:${index}`;
1240
- const atomicRequest = new Request(request.event, request.senderId, subRequestId, item.method, item.path, item.body);
1241
- return this.handleAtomic(atomicRequest);
1242
- });
1243
- response.body.responses = await Promise.all(batchPromises);
1244
- } catch (error) {
1245
- response.body = void 0;
1246
- if (error instanceof ResponseException) {
1247
- response.status = error.status;
1248
- response.error = error.message;
1249
- response.stack = error.stack;
1250
- } else if (error instanceof Error) {
1251
- isCritical = true;
1252
- response.status = 500;
1253
- response.error = error.message || "Internal Server Error";
1254
- response.stack = error.stack || "No stack trace available";
1255
- } else {
1256
- isCritical = true;
1257
- response.status = 500;
1258
- response.error = "Unknown error occurred";
1259
- response.stack = "No stack trace available";
1260
- }
1261
- } finally {
1262
- const t1 = performance.now();
1263
- const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`;
1264
- if (response.status < 400) {
1265
- Logger.log(message);
1266
- } else if (response.status < 500) {
1267
- Logger.warn(message);
1268
- } else {
1269
- if (isCritical) {
1270
- Logger.critical(message);
1271
- } else {
1272
- Logger.error(message);
1273
- }
1033
+ __name(_RadixTree, "RadixTree");
1034
+ RadixTree = _RadixTree;
1035
+ }
1036
+ });
1037
+
1038
+ // src/router.ts
1039
+ var router_exports = {};
1040
+ __export(router_exports, {
1041
+ Router: () => Router
1042
+ });
1043
+ var Router;
1044
+ var init_router = __esm({
1045
+ "src/router.ts"() {
1046
+ "use strict";
1047
+ init_controller_decorator();
1048
+ init_injectable_decorator();
1049
+ init_method_decorator();
1050
+ init_injector_explorer();
1051
+ init_exceptions();
1052
+ init_request();
1053
+ init_logger();
1054
+ init_radix_tree();
1055
+ Router = class {
1056
+ constructor() {
1057
+ this.routes = new RadixTree();
1058
+ this.rootMiddlewares = [];
1059
+ this.lazyRoutes = /* @__PURE__ */ new Map();
1274
1060
  }
1275
- if (response.error !== void 0) {
1276
- if (isCritical) {
1277
- Logger.critical(response.error);
1278
- } else {
1279
- Logger.error(response.error);
1061
+ // -------------------------------------------------------------------------
1062
+ // Registration
1063
+ // -------------------------------------------------------------------------
1064
+ registerController(controllerClass, pathPrefix, routeGuards = [], routeMiddlewares = []) {
1065
+ const meta = getControllerMetadata(controllerClass);
1066
+ if (!meta) {
1067
+ throw new Error(`[Noxus] Missing @Controller decorator on ${controllerClass.name}`);
1280
1068
  }
1281
- if (response.stack !== void 0) {
1282
- Logger.errorStack(response.stack);
1069
+ const routeMeta = getRouteMetadata(controllerClass);
1070
+ for (const def of routeMeta) {
1071
+ const fullPath = `${pathPrefix}/${def.path}`.replace(/\/+/g, "/").replace(/\/$/, "") || "/";
1072
+ const guards = [.../* @__PURE__ */ new Set([...routeGuards, ...def.guards])];
1073
+ const middlewares = [.../* @__PURE__ */ new Set([...routeMiddlewares, ...def.middlewares])];
1074
+ const routeDef = {
1075
+ method: def.method,
1076
+ path: fullPath,
1077
+ controller: controllerClass,
1078
+ handler: def.handler,
1079
+ guards,
1080
+ middlewares
1081
+ };
1082
+ this.routes.insert(fullPath + "/" + def.method, routeDef);
1083
+ const guardInfo = guards.length ? `<${guards.map((g) => g.name).join("|")}>` : "";
1084
+ Logger.log(`Mapped {${def.method} /${fullPath}}${guardInfo} route`);
1283
1085
  }
1086
+ const ctrlGuardInfo = routeGuards.length ? `<${routeGuards.map((g) => g.name).join("|")}>` : "";
1087
+ Logger.log(`Mapped ${controllerClass.name}${ctrlGuardInfo} controller's routes`);
1088
+ return this;
1284
1089
  }
1285
- return response;
1286
- }
1287
- }
1288
- normalizeBatchPayload(body) {
1289
- if (body === null || typeof body !== "object") {
1290
- throw new BadRequestException("Batch payload must be an object containing a requests array.");
1291
- }
1292
- const possiblePayload = body;
1293
- const { requests } = possiblePayload;
1294
- if (!Array.isArray(requests)) {
1295
- throw new BadRequestException("Batch payload must define a requests array.");
1296
- }
1297
- const normalizedRequests = requests.map((entry, index) => this.normalizeBatchItem(entry, index));
1298
- return {
1299
- requests: normalizedRequests
1300
- };
1301
- }
1302
- normalizeBatchItem(entry, index) {
1303
- if (entry === null || typeof entry !== "object") {
1304
- throw new BadRequestException(`Batch request at index ${index} must be an object.`);
1305
- }
1306
- const { requestId, path: path2, method, body } = entry;
1307
- if (requestId !== void 0 && typeof requestId !== "string") {
1308
- throw new BadRequestException(`Batch request at index ${index} has an invalid requestId.`);
1309
- }
1310
- if (typeof path2 !== "string" || path2.length === 0) {
1311
- throw new BadRequestException(`Batch request at index ${index} must define a non-empty path.`);
1312
- }
1313
- if (typeof method !== "string") {
1314
- throw new BadRequestException(`Batch request at index ${index} must define an HTTP method.`);
1315
- }
1316
- const normalizedMethod = method.toUpperCase();
1317
- if (!isAtomicHttpMethod(normalizedMethod)) {
1318
- throw new BadRequestException(`Batch request at index ${index} uses the unsupported method ${method}.`);
1319
- }
1320
- return {
1321
- requestId,
1322
- path: path2,
1323
- method: normalizedMethod,
1324
- body
1325
- };
1326
- }
1327
- /**
1328
- * Finds the route definition for a given request.
1329
- * This method searches the routing tree for a matching route based on the request's path and method.
1330
- * If no matching route is found, it throws a NotFoundException.
1331
- * @param request - The Request object containing the method and path to search for.
1332
- * @returns The IRouteDefinition for the matched route.
1333
- */
1334
- findRoute(request) {
1335
- const matchedRoutes = this.routes.search(request.path);
1336
- if (matchedRoutes?.node === void 0 || matchedRoutes.node.children.length === 0) {
1337
- throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1338
- }
1339
- const routeDef = matchedRoutes.node.findExactChild(request.method);
1340
- if (routeDef?.value === void 0) {
1341
- throw new MethodNotAllowedException(`Method Not Allowed for ${request.method} ${request.path}`);
1342
- }
1343
- return routeDef.value;
1344
- }
1345
- /**
1346
- * Resolves the controller for a given route definition.
1347
- * This method creates an instance of the controller class and prepares the request parameters.
1348
- * It also runs the request pipeline, which includes executing middlewares and guards.
1349
- * @param request - The Request object containing the request data.
1350
- * @param response - The IResponse object to populate with the response data.
1351
- * @param routeDef - The IRouteDefinition for the matched route.
1352
- * @return A Promise that resolves when the controller action has been executed.
1353
- * @throws UnauthorizedException if the request is not authorized by the guards.
1354
- */
1355
- async resolveController(request, response, routeDef) {
1356
- const controllerInstance = request.context.resolve(routeDef.controller);
1357
- Object.assign(request.params, this.extractParams(request.path, routeDef.path));
1358
- await this.runRequestPipeline(request, response, routeDef, controllerInstance);
1359
- }
1360
- /**
1361
- * Runs the request pipeline for a given request.
1362
- * This method executes the middlewares and guards associated with the route,
1363
- * and finally calls the controller action.
1364
- * @param request - The Request object containing the request data.
1365
- * @param response - The IResponse object to populate with the response data.
1366
- * @param routeDef - The IRouteDefinition for the matched route.
1367
- * @param controllerInstance - The instance of the controller class.
1368
- * @return A Promise that resolves when the request pipeline has been executed.
1369
- * @throws ResponseException if the response status is not successful.
1370
- */
1371
- async runRequestPipeline(request, response, routeDef, controllerInstance) {
1372
- const middlewares2 = [
1373
- .../* @__PURE__ */ new Set([
1374
- ...this.rootMiddlewares,
1375
- ...routeDef.middlewares
1376
- ])
1377
- ];
1378
- const middlewareMaxIndex = middlewares2.length - 1;
1379
- const guardsMaxIndex = middlewareMaxIndex + routeDef.guards.length;
1380
- let index = -1;
1381
- const dispatch = /* @__PURE__ */ __name(async (i) => {
1382
- if (i <= index) throw new Error("next() called multiple times");
1383
- index = i;
1384
- if (i <= middlewareMaxIndex) {
1385
- const nextFn = dispatch.bind(null, i + 1);
1386
- await this.runMiddleware(request, response, nextFn, middlewares2[i]);
1387
- if (response.status >= 400) {
1388
- throw new ResponseException(response.status, response.error);
1090
+ registerLazyRoute(pathPrefix, load, guards = [], middlewares = []) {
1091
+ const normalized = pathPrefix.replace(/^\/+|\/+$/g, "");
1092
+ this.lazyRoutes.set(normalized, { load, guards, middlewares, loading: null, loaded: false });
1093
+ Logger.log(`Registered lazy route prefix {${normalized}}`);
1094
+ return this;
1095
+ }
1096
+ defineRootMiddleware(middleware) {
1097
+ this.rootMiddlewares.push(middleware);
1098
+ return this;
1099
+ }
1100
+ // -------------------------------------------------------------------------
1101
+ // Request handling
1102
+ // -------------------------------------------------------------------------
1103
+ async handle(request) {
1104
+ return request.method === "BATCH" ? this.handleBatch(request) : this.handleAtomic(request);
1105
+ }
1106
+ async handleAtomic(request) {
1107
+ Logger.comment(`> ${request.method} /${request.path}`);
1108
+ const t0 = performance.now();
1109
+ const response = { requestId: request.id, status: 200, body: null };
1110
+ let isCritical = false;
1111
+ try {
1112
+ const routeDef = await this.findRoute(request);
1113
+ await this.resolveController(request, response, routeDef);
1114
+ if (response.status >= 400) throw new ResponseException(response.status, response.error);
1115
+ } catch (error) {
1116
+ this.fillErrorResponse(response, error, (c) => {
1117
+ isCritical = c;
1118
+ });
1119
+ } finally {
1120
+ this.logResponse(request, response, performance.now() - t0, isCritical);
1121
+ return response;
1122
+ }
1123
+ }
1124
+ async handleBatch(request) {
1125
+ Logger.comment(`> ${request.method} /${request.path}`);
1126
+ const t0 = performance.now();
1127
+ const response = {
1128
+ requestId: request.id,
1129
+ status: 200,
1130
+ body: { responses: [] }
1131
+ };
1132
+ let isCritical = false;
1133
+ try {
1134
+ const payload = this.normalizeBatchPayload(request.body);
1135
+ response.body.responses = await Promise.all(
1136
+ payload.requests.map((item, i) => {
1137
+ const id = item.requestId ?? `${request.id}:${i}`;
1138
+ return this.handleAtomic(new Request(request.event, request.senderId, id, item.method, item.path, item.body));
1139
+ })
1140
+ );
1141
+ } catch (error) {
1142
+ this.fillErrorResponse(response, error, (c) => {
1143
+ isCritical = c;
1144
+ });
1145
+ } finally {
1146
+ this.logResponse(request, response, performance.now() - t0, isCritical);
1147
+ return response;
1389
1148
  }
1390
- return;
1391
1149
  }
1392
- if (i <= guardsMaxIndex) {
1393
- const guardIndex = i - middlewares2.length;
1394
- const guardType = routeDef.guards[guardIndex];
1395
- await this.runGuard(request, guardType);
1396
- await dispatch(i + 1);
1397
- return;
1150
+ // -------------------------------------------------------------------------
1151
+ // Route resolution
1152
+ // -------------------------------------------------------------------------
1153
+ tryFindRoute(request) {
1154
+ const matched = this.routes.search(request.path);
1155
+ if (!matched?.node || matched.node.children.length === 0) return void 0;
1156
+ return matched.node.findExactChild(request.method)?.value;
1398
1157
  }
1399
- const action = controllerInstance[routeDef.handler];
1400
- response.body = await action.call(controllerInstance, request, response);
1401
- if (response.body === void 0) {
1402
- response.body = {};
1158
+ async findRoute(request) {
1159
+ const direct = this.tryFindRoute(request);
1160
+ if (direct) return direct;
1161
+ await this.tryLoadLazyRoute(request.path);
1162
+ const afterLazy = this.tryFindRoute(request);
1163
+ if (afterLazy) return afterLazy;
1164
+ throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1403
1165
  }
1404
- }, "dispatch");
1405
- await dispatch(0);
1406
- }
1407
- /**
1408
- * Runs a middleware function in the request pipeline.
1409
- * This method creates an instance of the middleware and invokes its `invoke` method,
1410
- * passing the request, response, and next function.
1411
- * @param request - The Request object containing the request data.
1412
- * @param response - The IResponse object to populate with the response data.
1413
- * @param next - The NextFunction to call to continue the middleware chain.
1414
- * @param middlewareType - The type of the middleware to run.
1415
- * @return A Promise that resolves when the middleware has been executed.
1416
- */
1417
- async runMiddleware(request, response, next, middlewareType) {
1418
- const middleware = request.context.resolve(middlewareType);
1419
- await middleware.invoke(request, response, next);
1420
- }
1421
- /**
1422
- * Runs a guard to check if the request is authorized.
1423
- * This method creates an instance of the guard and calls its `canActivate` method.
1424
- * If the guard returns false, it throws an UnauthorizedException.
1425
- * @param request - The Request object containing the request data.
1426
- * @param guardType - The type of the guard to run.
1427
- * @return A Promise that resolves if the guard allows the request, or throws an UnauthorizedException if not.
1428
- * @throws UnauthorizedException if the guard denies access to the request.
1429
- */
1430
- async runGuard(request, guardType) {
1431
- const guard = request.context.resolve(guardType);
1432
- const allowed = await guard.canActivate(request);
1433
- if (!allowed) throw new UnauthorizedException(`Unauthorized for ${request.method} ${request.path}`);
1434
- }
1435
- /**
1436
- * Extracts parameters from the actual request path based on the template path.
1437
- * This method splits the actual path and the template path into segments,
1438
- * then maps the segments to parameters based on the template.
1439
- * @param actual - The actual request path.
1440
- * @param template - The template path to extract parameters from.
1441
- * @returns An object containing the extracted parameters.
1442
- */
1443
- extractParams(actual, template) {
1444
- const aParts = actual.split("/");
1445
- const tParts = template.split("/");
1446
- const params = {};
1447
- tParts.forEach((part, i) => {
1448
- if (part.startsWith(":")) {
1449
- params[part.slice(1)] = aParts[i] ?? "";
1166
+ async tryLoadLazyRoute(requestPath) {
1167
+ const firstSegment = requestPath.replace(/^\/+/, "").split("/")[0] ?? "";
1168
+ for (const [prefix, entry] of this.lazyRoutes) {
1169
+ if (entry.loaded) continue;
1170
+ const normalized = requestPath.replace(/^\/+/, "");
1171
+ if (normalized === prefix || normalized.startsWith(prefix + "/") || firstSegment === prefix) {
1172
+ if (!entry.loading) entry.loading = this.loadLazyModule(prefix, entry);
1173
+ await entry.loading;
1174
+ return;
1175
+ }
1176
+ }
1450
1177
  }
1451
- });
1452
- return params;
1178
+ async loadLazyModule(prefix, entry) {
1179
+ const t0 = performance.now();
1180
+ InjectorExplorer.beginAccumulate();
1181
+ await entry.load?.();
1182
+ entry.loading = null;
1183
+ entry.load = null;
1184
+ InjectorExplorer.flushAccumulated(entry.guards, entry.middlewares, prefix);
1185
+ entry.loaded = true;
1186
+ Logger.info(`Lazy-loaded module for prefix {${prefix}} in ${Math.round(performance.now() - t0)}ms`);
1187
+ }
1188
+ // -------------------------------------------------------------------------
1189
+ // Pipeline
1190
+ // -------------------------------------------------------------------------
1191
+ async resolveController(request, response, routeDef) {
1192
+ const instance = request.context.resolve(routeDef.controller);
1193
+ Object.assign(request.params, this.extractParams(request.path, routeDef.path));
1194
+ await this.runPipeline(request, response, routeDef, instance);
1195
+ }
1196
+ async runPipeline(request, response, routeDef, controllerInstance) {
1197
+ const middlewares = [.../* @__PURE__ */ new Set([...this.rootMiddlewares, ...routeDef.middlewares])];
1198
+ const mwMax = middlewares.length - 1;
1199
+ const guardMax = mwMax + routeDef.guards.length;
1200
+ let index = -1;
1201
+ const dispatch = /* @__PURE__ */ __name(async (i) => {
1202
+ if (i <= index) throw new Error("next() called multiple times");
1203
+ index = i;
1204
+ if (i <= mwMax) {
1205
+ await this.runMiddleware(request, response, dispatch.bind(null, i + 1), middlewares[i]);
1206
+ if (response.status >= 400) throw new ResponseException(response.status, response.error);
1207
+ return;
1208
+ }
1209
+ if (i <= guardMax) {
1210
+ await this.runGuard(request, routeDef.guards[i - middlewares.length]);
1211
+ await dispatch(i + 1);
1212
+ return;
1213
+ }
1214
+ const action = controllerInstance[routeDef.handler];
1215
+ response.body = await action.call(controllerInstance, request, response);
1216
+ if (response.body === void 0) response.body = {};
1217
+ }, "dispatch");
1218
+ await dispatch(0);
1219
+ }
1220
+ async runMiddleware(request, response, next, middleware) {
1221
+ await middleware(request, response, next);
1222
+ }
1223
+ async runGuard(request, guard) {
1224
+ if (!await guard(request)) {
1225
+ throw new UnauthorizedException(`Unauthorized for ${request.method} ${request.path}`);
1226
+ }
1227
+ }
1228
+ // -------------------------------------------------------------------------
1229
+ // Utilities
1230
+ // -------------------------------------------------------------------------
1231
+ extractParams(actual, template) {
1232
+ const aParts = actual.split("/");
1233
+ const tParts = template.split("/");
1234
+ const params = {};
1235
+ tParts.forEach((part, i) => {
1236
+ if (part.startsWith(":")) params[part.slice(1)] = aParts[i] ?? "";
1237
+ });
1238
+ return params;
1239
+ }
1240
+ normalizeBatchPayload(body) {
1241
+ if (body === null || typeof body !== "object") {
1242
+ throw new BadRequestException("Batch payload must be an object containing a requests array.");
1243
+ }
1244
+ const { requests } = body;
1245
+ if (!Array.isArray(requests)) throw new BadRequestException("Batch payload must define a requests array.");
1246
+ return { requests: requests.map((e, i) => this.normalizeBatchItem(e, i)) };
1247
+ }
1248
+ normalizeBatchItem(entry, index) {
1249
+ if (entry === null || typeof entry !== "object") throw new BadRequestException(`Batch request at index ${index} must be an object.`);
1250
+ const { requestId, path: path2, method, body } = entry;
1251
+ if (requestId !== void 0 && typeof requestId !== "string") throw new BadRequestException(`Batch request at index ${index} has an invalid requestId.`);
1252
+ if (typeof path2 !== "string" || !path2.length) throw new BadRequestException(`Batch request at index ${index} must define a non-empty path.`);
1253
+ if (typeof method !== "string") throw new BadRequestException(`Batch request at index ${index} must define an HTTP method.`);
1254
+ const normalized = method.toUpperCase();
1255
+ if (!isAtomicHttpMethod(normalized)) throw new BadRequestException(`Batch request at index ${index} uses unsupported method ${method}.`);
1256
+ return { requestId, path: path2, method: normalized, body };
1257
+ }
1258
+ fillErrorResponse(response, error, setCritical) {
1259
+ response.body = void 0;
1260
+ if (error instanceof ResponseException) {
1261
+ response.status = error.status;
1262
+ response.error = error.message;
1263
+ response.stack = error.stack;
1264
+ } else if (error instanceof Error) {
1265
+ setCritical(true);
1266
+ response.status = 500;
1267
+ response.error = error.message || "Internal Server Error";
1268
+ response.stack = error.stack;
1269
+ } else {
1270
+ setCritical(true);
1271
+ response.status = 500;
1272
+ response.error = "Unknown error occurred";
1273
+ }
1274
+ }
1275
+ logResponse(request, response, ms, isCritical) {
1276
+ const msg = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(ms)}ms${Logger.colors.initial}`;
1277
+ if (response.status < 400) Logger.log(msg);
1278
+ else if (response.status < 500) Logger.warn(msg);
1279
+ else isCritical ? Logger.critical(msg) : Logger.error(msg);
1280
+ if (response.error) {
1281
+ isCritical ? Logger.critical(response.error) : Logger.error(response.error);
1282
+ if (response.stack) Logger.errorStack(response.stack);
1283
+ }
1284
+ }
1285
+ };
1286
+ __name(Router, "Router");
1287
+ Router = __decorateClass([
1288
+ Injectable({ lifetime: "singleton" })
1289
+ ], Router);
1453
1290
  }
1454
- };
1455
- __name(_Router, "Router");
1456
- var Router = _Router;
1457
- Router = _ts_decorate([
1458
- Injectable("singleton")
1459
- ], Router);
1291
+ });
1292
+
1293
+ // src/main.ts
1294
+ init_app_injector();
1295
+ init_token();
1296
+ init_router();
1460
1297
 
1461
1298
  // src/app.ts
1462
- import { app, BrowserWindow, ipcMain, MessageChannelMain } from "electron/main";
1299
+ init_injectable_decorator();
1300
+ init_app_injector();
1301
+ init_injector_explorer();
1302
+ init_request();
1303
+ init_router();
1304
+ import { app, BrowserWindow as BrowserWindow2, ipcMain, MessageChannelMain } from "electron/main";
1463
1305
 
1464
1306
  // src/socket.ts
1465
- function _ts_decorate2(decorators, target, key, desc) {
1466
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1467
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1468
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1469
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1470
- }
1471
- __name(_ts_decorate2, "_ts_decorate");
1472
- var _NoxSocket = class _NoxSocket {
1307
+ init_injectable_decorator();
1308
+ init_request();
1309
+ init_logger();
1310
+ var NoxSocket = class {
1473
1311
  constructor() {
1474
- __publicField(this, "channels", /* @__PURE__ */ new Map());
1312
+ this.channels = /* @__PURE__ */ new Map();
1475
1313
  }
1476
1314
  register(senderId, requestChannel, socketChannel) {
1477
- this.channels.set(senderId, {
1478
- request: requestChannel,
1479
- socket: socketChannel
1480
- });
1315
+ this.channels.set(senderId, { request: requestChannel, socket: socketChannel });
1481
1316
  }
1482
1317
  get(senderId) {
1483
1318
  return this.channels.get(senderId);
@@ -1486,9 +1321,7 @@ var _NoxSocket = class _NoxSocket {
1486
1321
  this.channels.delete(senderId);
1487
1322
  }
1488
1323
  getSenderIds() {
1489
- return [
1490
- ...this.channels.keys()
1491
- ];
1324
+ return [...this.channels.keys()];
1492
1325
  }
1493
1326
  emit(eventName, payload, targetSenderIds) {
1494
1327
  const normalizedEvent = eventName.trim();
@@ -1513,39 +1346,196 @@ var _NoxSocket = class _NoxSocket {
1513
1346
  return delivered;
1514
1347
  }
1515
1348
  emitToRenderer(senderId, eventName, payload) {
1516
- return this.emit(eventName, payload, [
1517
- senderId
1518
- ]) > 0;
1349
+ return this.emit(eventName, payload, [senderId]) > 0;
1519
1350
  }
1520
1351
  };
1521
- __name(_NoxSocket, "NoxSocket");
1522
- var NoxSocket = _NoxSocket;
1523
- NoxSocket = _ts_decorate2([
1524
- Injectable("singleton")
1352
+ __name(NoxSocket, "NoxSocket");
1353
+ NoxSocket = __decorateClass([
1354
+ Injectable({ lifetime: "singleton" })
1525
1355
  ], NoxSocket);
1526
1356
 
1527
1357
  // src/app.ts
1528
- function _ts_decorate3(decorators, target, key, desc) {
1529
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1530
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1531
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1532
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1533
- }
1534
- __name(_ts_decorate3, "_ts_decorate");
1535
- function _ts_metadata(k, v) {
1536
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1537
- }
1538
- __name(_ts_metadata, "_ts_metadata");
1539
- var _NoxApp = class _NoxApp {
1540
- constructor(router, socket) {
1541
- __publicField(this, "router");
1542
- __publicField(this, "socket");
1543
- __publicField(this, "app");
1544
- __publicField(this, "mainWindow");
1545
- /**
1546
- *
1547
- */
1548
- __publicField(this, "onRendererMessage", /* @__PURE__ */ __name(async (event) => {
1358
+ init_logger();
1359
+
1360
+ // src/window/window-manager.ts
1361
+ init_injectable_decorator();
1362
+ init_logger();
1363
+ import { BrowserWindow, screen } from "electron/main";
1364
+ var WindowManager = class {
1365
+ constructor() {
1366
+ this._windows = /* @__PURE__ */ new Map();
1367
+ }
1368
+ // -------------------------------------------------------------------------
1369
+ // Creation
1370
+ // -------------------------------------------------------------------------
1371
+ /**
1372
+ * Creates a BrowserWindow, optionally performs an animated expand to the
1373
+ * work area, and registers it in the manager.
1374
+ *
1375
+ * If expandToWorkArea is true:
1376
+ * 1. The window is created at the given initial size (defaults to 600×600, centered).
1377
+ * 2. An animated setBounds expands it to the full work area.
1378
+ * 3. The returned promise resolves only after the animation, so callers
1379
+ * can safely call win.loadFile() without the viewbox freeze.
1380
+ *
1381
+ * @param config Window configuration.
1382
+ * @param isMain Mark this window as the main window (accessible via getMain()).
1383
+ */
1384
+ async create(config, isMain = false) {
1385
+ const {
1386
+ expandToWorkArea = false,
1387
+ expandAnimationDuration = 600,
1388
+ ...bwOptions
1389
+ } = config;
1390
+ const win = new BrowserWindow({ show: false, ...bwOptions });
1391
+ this._register(win, isMain);
1392
+ if (expandToWorkArea) {
1393
+ await this._expandToWorkArea(win, expandAnimationDuration);
1394
+ }
1395
+ win.once("ready-to-show", () => win.show());
1396
+ Logger.log(`[WindowManager] Created window #${win.id}${isMain ? " (main)" : ""}`);
1397
+ return win;
1398
+ }
1399
+ /**
1400
+ * Creates the initial "splash" window that is shown immediately after
1401
+ * app.whenReady(). It is displayed instantly (show: true, no preload
1402
+ * loading) and then expanded to the work area with animation.
1403
+ *
1404
+ * After the animation completes you can call win.loadFile() without
1405
+ * experiencing the viewbox freeze.
1406
+ *
1407
+ * This is the recommended way to get pixels on screen as fast as possible.
1408
+ *
1409
+ * @example
1410
+ * const win = await wm.createSplash({
1411
+ * webPreferences: { preload: path.join(__dirname, 'preload.js') }
1412
+ * });
1413
+ * win.loadFile('index.html');
1414
+ */
1415
+ async createSplash(options = {}) {
1416
+ const { animationDuration = 600, ...bwOptions } = options;
1417
+ const win = new BrowserWindow({
1418
+ width: 600,
1419
+ height: 600,
1420
+ center: true,
1421
+ frame: false,
1422
+ show: true,
1423
+ ...bwOptions
1424
+ });
1425
+ this._register(win, true);
1426
+ Logger.log(`[WindowManager] Splash window #${win.id} created`);
1427
+ await this._expandToWorkArea(win, animationDuration);
1428
+ return win;
1429
+ }
1430
+ // -------------------------------------------------------------------------
1431
+ // Accessors
1432
+ // -------------------------------------------------------------------------
1433
+ /** Returns all currently open windows. */
1434
+ getAll() {
1435
+ return [...this._windows.values()];
1436
+ }
1437
+ /** Returns the window designated as main, or undefined. */
1438
+ getMain() {
1439
+ return this._mainWindowId !== void 0 ? this._windows.get(this._mainWindowId) : void 0;
1440
+ }
1441
+ /** Returns a window by its Electron id, or undefined. */
1442
+ getById(id) {
1443
+ return this._windows.get(id);
1444
+ }
1445
+ /** Returns the number of open windows. */
1446
+ get count() {
1447
+ return this._windows.size;
1448
+ }
1449
+ // -------------------------------------------------------------------------
1450
+ // Actions
1451
+ // -------------------------------------------------------------------------
1452
+ /** Closes and destroys a window by id. */
1453
+ close(id) {
1454
+ const win = this._windows.get(id);
1455
+ if (!win) {
1456
+ Logger.warn(`[WindowManager] Window #${id} not found`);
1457
+ return;
1458
+ }
1459
+ win.destroy();
1460
+ }
1461
+ /** Closes all windows. */
1462
+ closeAll() {
1463
+ for (const win of this._windows.values()) {
1464
+ win.destroy();
1465
+ }
1466
+ }
1467
+ /**
1468
+ * Sends a message to a specific window via webContents.send.
1469
+ * @param id Target window id.
1470
+ * @param channel IPC channel name.
1471
+ * @param args Payload.
1472
+ */
1473
+ send(id, channel, ...args) {
1474
+ const win = this._windows.get(id);
1475
+ if (!win || win.isDestroyed()) {
1476
+ Logger.warn(`[WindowManager] Cannot send to window #${id}: not found or destroyed`);
1477
+ return;
1478
+ }
1479
+ win.webContents.send(channel, ...args);
1480
+ }
1481
+ /**
1482
+ * Broadcasts a message to all open windows.
1483
+ */
1484
+ broadcast(channel, ...args) {
1485
+ for (const win of this._windows.values()) {
1486
+ if (!win.isDestroyed()) win.webContents.send(channel, ...args);
1487
+ }
1488
+ }
1489
+ // -------------------------------------------------------------------------
1490
+ // Private
1491
+ // -------------------------------------------------------------------------
1492
+ _register(win, isMain) {
1493
+ this._windows.set(win.id, win);
1494
+ if (isMain && this._mainWindowId === void 0) {
1495
+ this._mainWindowId = win.id;
1496
+ }
1497
+ win.once("closed", () => {
1498
+ this._windows.delete(win.id);
1499
+ if (this._mainWindowId === win.id) this._mainWindowId = void 0;
1500
+ Logger.log(`[WindowManager] Window #${win.id} closed`);
1501
+ });
1502
+ }
1503
+ /**
1504
+ * Animates the window to the full work area of the primary display.
1505
+ * Resolves only after the animation is complete, so that content loaded
1506
+ * afterward gets the correct surface size (no viewbox freeze).
1507
+ */
1508
+ _expandToWorkArea(win, animationDuration) {
1509
+ return new Promise((resolve) => {
1510
+ const { x, y, width, height } = screen.getPrimaryDisplay().workArea;
1511
+ win.setBounds({ x, y, width, height }, true);
1512
+ let resolved = false;
1513
+ const done = /* @__PURE__ */ __name(() => {
1514
+ if (resolved) return;
1515
+ resolved = true;
1516
+ win.removeListener("resize", done);
1517
+ resolve();
1518
+ }, "done");
1519
+ win.once("resize", done);
1520
+ setTimeout(done, animationDuration + 100);
1521
+ });
1522
+ }
1523
+ };
1524
+ __name(WindowManager, "WindowManager");
1525
+ WindowManager = __decorateClass([
1526
+ Injectable({ lifetime: "singleton" })
1527
+ ], WindowManager);
1528
+
1529
+ // src/app.ts
1530
+ var NoxApp = class {
1531
+ constructor() {
1532
+ this.router = inject(Router);
1533
+ this.socket = inject(NoxSocket);
1534
+ this.windowManager = inject(WindowManager);
1535
+ // -------------------------------------------------------------------------
1536
+ // IPC
1537
+ // -------------------------------------------------------------------------
1538
+ this.onRendererMessage = /* @__PURE__ */ __name(async (event) => {
1549
1539
  const { senderId, requestId, path: path2, method, body } = event.data;
1550
1540
  const channels = this.socket.get(senderId);
1551
1541
  if (!channels) {
@@ -1561,19 +1551,15 @@ var _NoxApp = class _NoxApp {
1561
1551
  requestId,
1562
1552
  status: 500,
1563
1553
  body: null,
1564
- error: err.message || "Internal Server Error"
1554
+ error: err instanceof Error ? err.message : "Internal Server Error"
1565
1555
  };
1566
1556
  channels.request.port1.postMessage(response);
1567
1557
  }
1568
- }, "onRendererMessage"));
1569
- this.router = router;
1570
- this.socket = socket;
1558
+ }, "onRendererMessage");
1571
1559
  }
1572
- /**
1573
- * Initializes the NoxApp instance.
1574
- * This method sets up the IPC communication, registers event listeners,
1575
- * and prepares the application for use.
1576
- */
1560
+ // -------------------------------------------------------------------------
1561
+ // Initialisation
1562
+ // -------------------------------------------------------------------------
1577
1563
  async init() {
1578
1564
  ipcMain.on("gimme-my-port", this.giveTheRendererAPort.bind(this));
1579
1565
  app.once("activate", this.onAppActivated.bind(this));
@@ -1581,12 +1567,59 @@ var _NoxApp = class _NoxApp {
1581
1567
  console.log("");
1582
1568
  return this;
1583
1569
  }
1570
+ // -------------------------------------------------------------------------
1571
+ // Public API
1572
+ // -------------------------------------------------------------------------
1573
+ /**
1574
+ * Registers a lazy route. The file behind this prefix is dynamically
1575
+ * imported on the first IPC request that targets it.
1576
+ *
1577
+ * The import function should NOT statically reference heavy modules —
1578
+ * the whole point is to defer their loading.
1579
+ *
1580
+ * @example
1581
+ * noxApp.lazy('auth', () => import('./modules/auth/auth.controller.js'));
1582
+ * noxApp.lazy('reporting', () => import('./modules/reporting/index.js'));
1583
+ */
1584
+ lazy(pathPrefix, load, guards = [], middlewares = []) {
1585
+ this.router.registerLazyRoute(pathPrefix, load, guards, middlewares);
1586
+ return this;
1587
+ }
1588
+ /**
1589
+ * Eagerly loads a set of modules (controllers + services) before start().
1590
+ * Use this for modules that provide services needed by your IApp.onReady().
1591
+ *
1592
+ * All imports run in parallel; DI is flushed with the two-phase guarantee.
1593
+ */
1594
+ async load(importFns) {
1595
+ InjectorExplorer.beginAccumulate();
1596
+ await Promise.all(importFns.map((fn) => fn()));
1597
+ InjectorExplorer.flushAccumulated();
1598
+ return this;
1599
+ }
1600
+ /**
1601
+ * Registers a global middleware applied to every route.
1602
+ */
1603
+ use(middleware) {
1604
+ this.router.defineRootMiddleware(middleware);
1605
+ return this;
1606
+ }
1607
+ /**
1608
+ * Sets the application service (implements IApp) that receives lifecycle events.
1609
+ * @param appClass - Class decorated with @Injectable that implements IApp.
1610
+ */
1611
+ configure(appClass) {
1612
+ this.appService = inject(appClass);
1613
+ return this;
1614
+ }
1584
1615
  /**
1585
- * Handles the request from the renderer process.
1586
- * This method creates a Request object from the IPC event data,
1587
- * processes it through the Router, and sends the response back
1588
- * to the renderer process using the MessageChannel.
1616
+ * Calls IApp.onReady(). Should be called after configure() and any lazy()
1617
+ * registrations are set up.
1589
1618
  */
1619
+ start() {
1620
+ this.appService?.onReady();
1621
+ return this;
1622
+ }
1590
1623
  giveTheRendererAPort(event) {
1591
1624
  const senderId = event.sender.id;
1592
1625
  if (this.socket.get(senderId)) {
@@ -1597,33 +1630,29 @@ var _NoxApp = class _NoxApp {
1597
1630
  requestChannel.port1.on("message", this.onRendererMessage);
1598
1631
  requestChannel.port1.start();
1599
1632
  socketChannel.port1.start();
1633
+ event.sender.once("destroyed", () => this.shutdownChannel(senderId));
1600
1634
  this.socket.register(senderId, requestChannel, socketChannel);
1601
- event.sender.postMessage("port", {
1602
- senderId
1603
- }, [
1604
- requestChannel.port2,
1605
- socketChannel.port2
1606
- ]);
1635
+ event.sender.postMessage("port", { senderId }, [requestChannel.port2, socketChannel.port2]);
1607
1636
  }
1608
- /**
1609
- * MacOS specific behavior.
1610
- */
1637
+ // -------------------------------------------------------------------------
1638
+ // Lifecycle
1639
+ // -------------------------------------------------------------------------
1611
1640
  onAppActivated() {
1612
- if (process.platform === "darwin" && BrowserWindow.getAllWindows().length === 0) {
1613
- this.app?.onActivated();
1641
+ if (process.platform === "darwin" && BrowserWindow2.getAllWindows().length === 0) {
1642
+ this.appService?.onActivated();
1614
1643
  }
1615
1644
  }
1616
- /**
1617
- * Shuts down the message channel for a specific sender ID.
1618
- * This method closes the IPC channel for the specified sender ID and
1619
- * removes it from the messagePorts map.
1620
- * @param channelSenderId - The ID of the sender channel to shut down.
1621
- * @param remove - Whether to remove the channel from the messagePorts map.
1622
- */
1645
+ async onAllWindowsClosed() {
1646
+ for (const senderId of this.socket.getSenderIds()) {
1647
+ this.shutdownChannel(senderId);
1648
+ }
1649
+ Logger.info("All windows closed, shutting down application...");
1650
+ await this.appService?.dispose();
1651
+ if (process.platform !== "darwin") app.quit();
1652
+ }
1623
1653
  shutdownChannel(channelSenderId) {
1624
1654
  const channels = this.socket.get(channelSenderId);
1625
1655
  if (!channels) {
1626
- Logger.warn(`No message channel found for sender ID: ${channelSenderId}`);
1627
1656
  return;
1628
1657
  }
1629
1658
  channels.request.port1.off("message", this.onRendererMessage);
@@ -1633,458 +1662,66 @@ var _NoxApp = class _NoxApp {
1633
1662
  channels.socket.port2.close();
1634
1663
  this.socket.unregister(channelSenderId);
1635
1664
  }
1636
- /**
1637
- * Handles the application shutdown process.
1638
- * This method is called when all windows are closed, and it cleans up the message channels
1639
- */
1640
- async onAllWindowsClosed() {
1641
- for (const senderId of this.socket.getSenderIds()) {
1642
- this.shutdownChannel(senderId);
1643
- }
1644
- Logger.info("All windows closed, shutting down application...");
1645
- await this.app?.dispose();
1646
- if (process.platform !== "darwin") {
1647
- app.quit();
1648
- }
1649
- }
1650
- // ---
1651
- /**
1652
- * Sets the main BrowserWindow that was created early by bootstrapApplication.
1653
- * This window will be passed to IApp.onReady when start() is called.
1654
- * @param window - The BrowserWindow created during bootstrap.
1655
- */
1656
- setMainWindow(window2) {
1657
- this.mainWindow = window2;
1658
- }
1659
- /**
1660
- * Configures the NoxApp instance with the provided application class.
1661
- * This method allows you to set the application class that will handle lifecycle events.
1662
- * @param app - The application class to configure.
1663
- * @returns NoxApp instance for method chaining.
1664
- */
1665
- configure(app3) {
1666
- this.app = inject(app3);
1667
- return this;
1668
- }
1669
- /**
1670
- * Registers a middleware for the root of the application.
1671
- * This method allows you to define a middleware that will be applied to all requests
1672
- * @param middleware - The middleware class to register.
1673
- * @returns NoxApp instance for method chaining.
1674
- */
1675
- use(middleware) {
1676
- this.router.defineRootMiddleware(middleware);
1677
- return this;
1678
- }
1679
- /**
1680
- * Should be called after the bootstrapApplication function is called.
1681
- * Passes the early-created BrowserWindow (if any) to the configured IApp service.
1682
- * @returns NoxApp instance for method chaining.
1683
- */
1684
- start() {
1685
- this.app?.onReady(this.mainWindow);
1686
- return this;
1687
- }
1688
1665
  };
1689
- __name(_NoxApp, "NoxApp");
1690
- var NoxApp = _NoxApp;
1691
- NoxApp = _ts_decorate3([
1692
- Injectable("singleton"),
1693
- _ts_metadata("design:type", Function),
1694
- _ts_metadata("design:paramtypes", [
1695
- typeof Router === "undefined" ? Object : Router,
1696
- typeof NoxSocket === "undefined" ? Object : NoxSocket
1697
- ])
1666
+ __name(NoxApp, "NoxApp");
1667
+ NoxApp = __decorateClass([
1668
+ Injectable({ lifetime: "singleton", deps: [Router, NoxSocket, WindowManager] })
1698
1669
  ], NoxApp);
1699
1670
 
1700
1671
  // src/bootstrap.ts
1701
- import { app as app2, BrowserWindow as BrowserWindow2 } from "electron/main";
1702
- async function bootstrapApplication(rootModule, options) {
1703
- if (!getModuleMetadata(rootModule)) {
1704
- throw new Error(`Root module must be decorated with @Module`);
1705
- }
1672
+ import { app as app2 } from "electron/main";
1673
+ init_app_injector();
1674
+ init_injector_explorer();
1675
+ async function bootstrapApplication(config = {}) {
1706
1676
  await app2.whenReady();
1707
- let mainWindow;
1708
- if (options?.window) {
1709
- mainWindow = new BrowserWindow2(options.window);
1677
+ const overrides = /* @__PURE__ */ new Map();
1678
+ for (const { token: token2, useValue } of config.singletons ?? []) {
1679
+ overrides.set(token2, useValue);
1680
+ RootInjector.singletons.set(token2, useValue);
1710
1681
  }
1711
- InjectorExplorer.processPending();
1682
+ InjectorExplorer.processPending(overrides);
1712
1683
  const noxApp = inject(NoxApp);
1713
- if (mainWindow) {
1714
- noxApp.setMainWindow(mainWindow);
1684
+ if (config.routes?.length) {
1685
+ for (const route of config.routes) {
1686
+ noxApp.lazy(route.path, route.load, route.guards, route.middlewares);
1687
+ }
1688
+ }
1689
+ if (config.eagerLoad?.length) {
1690
+ await noxApp.load(config.eagerLoad);
1715
1691
  }
1716
1692
  await noxApp.init();
1717
1693
  return noxApp;
1718
1694
  }
1719
1695
  __name(bootstrapApplication, "bootstrapApplication");
1720
1696
 
1721
- // src/preload-bridge.ts
1722
- import { contextBridge, ipcRenderer } from "electron/renderer";
1723
- var DEFAULT_EXPOSE_NAME = "noxus";
1724
- var DEFAULT_INIT_EVENT = "init-port";
1725
- var DEFAULT_REQUEST_CHANNEL = "gimme-my-port";
1726
- var DEFAULT_RESPONSE_CHANNEL = "port";
1727
- function exposeNoxusBridge(options = {}) {
1728
- const { exposeAs = DEFAULT_EXPOSE_NAME, initMessageType = DEFAULT_INIT_EVENT, requestChannel = DEFAULT_REQUEST_CHANNEL, responseChannel = DEFAULT_RESPONSE_CHANNEL, targetWindow = window } = options;
1729
- const api = {
1730
- requestPort: /* @__PURE__ */ __name(() => {
1731
- ipcRenderer.send(requestChannel);
1732
- ipcRenderer.once(responseChannel, (event, message) => {
1733
- const ports = (event.ports ?? []).filter((port) => port !== void 0);
1734
- if (ports.length === 0) {
1735
- console.error("[Noxus] No MessagePort received from main process.");
1736
- return;
1737
- }
1738
- for (const port of ports) {
1739
- try {
1740
- port.start();
1741
- } catch (error) {
1742
- console.error("[Noxus] Failed to start MessagePort.", error);
1743
- }
1744
- }
1745
- targetWindow.postMessage({
1746
- type: initMessageType,
1747
- senderId: message?.senderId
1748
- }, "*", ports);
1749
- });
1750
- }, "requestPort")
1751
- };
1752
- contextBridge.exposeInMainWorld(exposeAs, api);
1753
- return api;
1754
- }
1755
- __name(exposeNoxusBridge, "exposeNoxusBridge");
1756
-
1757
- // src/renderer-events.ts
1758
- var _RendererEventRegistry = class _RendererEventRegistry {
1759
- constructor() {
1760
- __publicField(this, "listeners", /* @__PURE__ */ new Map());
1761
- }
1762
- /**
1763
- *
1764
- */
1765
- subscribe(eventName, handler) {
1766
- const normalizedEventName = eventName.trim();
1767
- if (normalizedEventName.length === 0) {
1768
- throw new Error("Renderer event name must be a non-empty string.");
1769
- }
1770
- const handlers = this.listeners.get(normalizedEventName) ?? /* @__PURE__ */ new Set();
1771
- handlers.add(handler);
1772
- this.listeners.set(normalizedEventName, handlers);
1773
- return {
1774
- unsubscribe: /* @__PURE__ */ __name(() => this.unsubscribe(normalizedEventName, handler), "unsubscribe")
1775
- };
1776
- }
1777
- /**
1778
- *
1779
- */
1780
- unsubscribe(eventName, handler) {
1781
- const handlers = this.listeners.get(eventName);
1782
- if (!handlers) {
1783
- return;
1784
- }
1785
- handlers.delete(handler);
1786
- if (handlers.size === 0) {
1787
- this.listeners.delete(eventName);
1788
- }
1789
- }
1790
- /**
1791
- *
1792
- */
1793
- clear(eventName) {
1794
- if (eventName) {
1795
- this.listeners.delete(eventName);
1796
- return;
1797
- }
1798
- this.listeners.clear();
1799
- }
1800
- /**
1801
- *
1802
- */
1803
- dispatch(message) {
1804
- const handlers = this.listeners.get(message.event);
1805
- if (!handlers || handlers.size === 0) {
1806
- return;
1807
- }
1808
- handlers.forEach((handler) => {
1809
- try {
1810
- handler(message.payload);
1811
- } catch (error) {
1812
- console.error(`[Noxus] Renderer event handler for "${message.event}" threw an error.`, error);
1813
- }
1814
- });
1815
- }
1816
- /**
1817
- *
1818
- */
1819
- tryDispatchFromMessageEvent(event) {
1820
- if (!isRendererEventMessage(event.data)) {
1821
- return false;
1822
- }
1823
- this.dispatch(event.data);
1824
- return true;
1825
- }
1826
- /**
1827
- *
1828
- */
1829
- hasHandlers(eventName) {
1830
- const handlers = this.listeners.get(eventName);
1831
- return !!handlers && handlers.size > 0;
1832
- }
1833
- };
1834
- __name(_RendererEventRegistry, "RendererEventRegistry");
1835
- var RendererEventRegistry = _RendererEventRegistry;
1697
+ // src/main.ts
1698
+ init_exceptions();
1699
+ init_controller_decorator();
1700
+ init_injectable_decorator();
1701
+ init_method_decorator();
1702
+ init_logger();
1703
+ init_forward_ref();
1704
+ init_request();
1836
1705
 
1837
- // src/renderer-client.ts
1838
- var DEFAULT_INIT_EVENT2 = "init-port";
1839
- var DEFAULT_BRIDGE_NAMES = [
1840
- "noxus",
1841
- "ipcRenderer"
1842
- ];
1843
- function defaultRequestId() {
1844
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1845
- return crypto.randomUUID();
1846
- }
1847
- return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
1848
- }
1849
- __name(defaultRequestId, "defaultRequestId");
1850
- function normalizeBridgeNames(preferred) {
1851
- const names = [];
1852
- const add = /* @__PURE__ */ __name((name) => {
1853
- if (!name) return;
1854
- if (!names.includes(name)) {
1855
- names.push(name);
1856
- }
1857
- }, "add");
1858
- if (Array.isArray(preferred)) {
1859
- for (const name of preferred) {
1860
- add(name);
1861
- }
1862
- } else {
1863
- add(preferred);
1864
- }
1865
- for (const fallback of DEFAULT_BRIDGE_NAMES) {
1866
- add(fallback);
1867
- }
1868
- return names;
1869
- }
1870
- __name(normalizeBridgeNames, "normalizeBridgeNames");
1871
- function resolveBridgeFromWindow(windowRef, preferred) {
1872
- const names = normalizeBridgeNames(preferred);
1873
- const globalRef = windowRef;
1874
- if (!globalRef) {
1875
- return null;
1876
- }
1877
- for (const name of names) {
1878
- const candidate = globalRef[name];
1879
- if (candidate && typeof candidate.requestPort === "function") {
1880
- return candidate;
1881
- }
1882
- }
1883
- return null;
1706
+ // src/routes.ts
1707
+ function defineRoutes(routes) {
1708
+ const paths = routes.map((r) => r.path.replace(/^\/+|\/+$/g, ""));
1709
+ const duplicates = paths.filter((p, i) => paths.indexOf(p) !== i);
1710
+ if (duplicates.length > 0) {
1711
+ throw new Error(
1712
+ `[Noxus] Duplicate route prefixes detected: ${[...new Set(duplicates)].map((d) => `"${d}"`).join(", ")}`
1713
+ );
1714
+ }
1715
+ return routes.map((r) => ({
1716
+ ...r,
1717
+ path: r.path.replace(/^\/+|\/+$/g, "")
1718
+ }));
1884
1719
  }
1885
- __name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
1886
- var _NoxRendererClient = class _NoxRendererClient {
1887
- constructor(options = {}) {
1888
- __publicField(this, "events", new RendererEventRegistry());
1889
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
1890
- __publicField(this, "requestPort");
1891
- __publicField(this, "socketPort");
1892
- __publicField(this, "senderId");
1893
- __publicField(this, "bridge");
1894
- __publicField(this, "initMessageType");
1895
- __publicField(this, "windowRef");
1896
- __publicField(this, "generateRequestId");
1897
- __publicField(this, "isReady", false);
1898
- __publicField(this, "setupPromise");
1899
- __publicField(this, "setupResolve");
1900
- __publicField(this, "setupReject");
1901
- __publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
1902
- if (event.data?.type !== this.initMessageType) {
1903
- return;
1904
- }
1905
- if (!Array.isArray(event.ports) || event.ports.length < 2) {
1906
- const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
1907
- console.error(error);
1908
- this.setupReject?.(error);
1909
- this.resetSetupState();
1910
- return;
1911
- }
1912
- this.windowRef.removeEventListener("message", this.onWindowMessage);
1913
- this.requestPort = event.ports[0];
1914
- this.socketPort = event.ports[1];
1915
- this.senderId = event.data.senderId;
1916
- if (this.requestPort === void 0 || this.socketPort === void 0) {
1917
- const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
1918
- console.error(error);
1919
- this.setupReject?.(error);
1920
- this.resetSetupState();
1921
- return;
1922
- }
1923
- this.attachRequestPort(this.requestPort);
1924
- this.attachSocketPort(this.socketPort);
1925
- this.isReady = true;
1926
- this.setupResolve?.();
1927
- this.resetSetupState(true);
1928
- }, "onWindowMessage"));
1929
- __publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
1930
- if (this.events.tryDispatchFromMessageEvent(event)) {
1931
- return;
1932
- }
1933
- console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
1934
- }, "onSocketMessage"));
1935
- __publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
1936
- if (this.events.tryDispatchFromMessageEvent(event)) {
1937
- return;
1938
- }
1939
- const response = event.data;
1940
- if (!response || typeof response.requestId !== "string") {
1941
- console.error("[Noxus] Renderer received an invalid response payload.", response);
1942
- return;
1943
- }
1944
- const pending = this.pendingRequests.get(response.requestId);
1945
- if (!pending) {
1946
- console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
1947
- return;
1948
- }
1949
- this.pendingRequests.delete(response.requestId);
1950
- this.onRequestCompleted(pending, response);
1951
- if (response.status >= 400) {
1952
- pending.reject(response);
1953
- return;
1954
- }
1955
- pending.resolve(response.body);
1956
- }, "onRequestMessage"));
1957
- this.windowRef = options.windowRef ?? window;
1958
- const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
1959
- this.bridge = resolvedBridge ?? null;
1960
- this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT2;
1961
- this.generateRequestId = options.generateRequestId ?? defaultRequestId;
1962
- }
1963
- async setup() {
1964
- if (this.isReady) {
1965
- return Promise.resolve();
1966
- }
1967
- if (this.setupPromise) {
1968
- return this.setupPromise;
1969
- }
1970
- if (!this.bridge || typeof this.bridge.requestPort !== "function") {
1971
- throw new Error("[Noxus] Renderer bridge is missing requestPort().");
1972
- }
1973
- this.setupPromise = new Promise((resolve, reject) => {
1974
- this.setupResolve = resolve;
1975
- this.setupReject = reject;
1976
- });
1977
- this.windowRef.addEventListener("message", this.onWindowMessage);
1978
- this.bridge.requestPort();
1979
- return this.setupPromise;
1980
- }
1981
- dispose() {
1982
- this.windowRef.removeEventListener("message", this.onWindowMessage);
1983
- this.requestPort?.close();
1984
- this.socketPort?.close();
1985
- this.requestPort = void 0;
1986
- this.socketPort = void 0;
1987
- this.senderId = void 0;
1988
- this.isReady = false;
1989
- this.pendingRequests.clear();
1990
- }
1991
- async request(request) {
1992
- const senderId = this.senderId;
1993
- const requestId = this.generateRequestId();
1994
- if (senderId === void 0) {
1995
- return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
1996
- }
1997
- const readinessError = this.validateReady(requestId);
1998
- if (readinessError) {
1999
- return Promise.reject(readinessError);
2000
- }
2001
- const message = {
2002
- requestId,
2003
- senderId,
2004
- ...request
2005
- };
2006
- return new Promise((resolve, reject) => {
2007
- const pending = {
2008
- resolve,
2009
- reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
2010
- request: message,
2011
- submittedAt: Date.now()
2012
- };
2013
- this.pendingRequests.set(message.requestId, pending);
2014
- this.requestPort.postMessage(message);
2015
- });
2016
- }
2017
- async batch(requests) {
2018
- return this.request({
2019
- method: "BATCH",
2020
- path: "",
2021
- body: {
2022
- requests
2023
- }
2024
- });
2025
- }
2026
- getSenderId() {
2027
- return this.senderId;
2028
- }
2029
- onRequestCompleted(pending, response) {
2030
- if (typeof console.groupCollapsed === "function") {
2031
- console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
2032
- }
2033
- if (response.error) {
2034
- console.error("error message:", response.error);
2035
- }
2036
- if (response.body !== void 0) {
2037
- console.info("response:", response.body);
2038
- }
2039
- console.info("request:", pending.request);
2040
- console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
2041
- if (typeof console.groupCollapsed === "function") {
2042
- console.groupEnd();
2043
- }
2044
- }
2045
- attachRequestPort(port) {
2046
- port.onmessage = this.onRequestMessage;
2047
- port.start();
2048
- }
2049
- attachSocketPort(port) {
2050
- port.onmessage = this.onSocketMessage;
2051
- port.start();
2052
- }
2053
- validateReady(requestId) {
2054
- if (!this.isElectronEnvironment()) {
2055
- return this.createErrorResponse(requestId, "Not running in Electron environment");
2056
- }
2057
- if (!this.requestPort) {
2058
- return this.createErrorResponse(requestId, "MessagePort is not available");
2059
- }
2060
- return void 0;
2061
- }
2062
- createErrorResponse(requestId, message) {
2063
- return {
2064
- status: 500,
2065
- requestId,
2066
- error: message
2067
- };
2068
- }
2069
- resetSetupState(success = false) {
2070
- if (!success) {
2071
- this.setupPromise = void 0;
2072
- }
2073
- this.setupResolve = void 0;
2074
- this.setupReject = void 0;
2075
- }
2076
- isElectronEnvironment() {
2077
- return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
2078
- }
2079
- };
2080
- __name(_NoxRendererClient, "NoxRendererClient");
2081
- var NoxRendererClient = _NoxRendererClient;
1720
+ __name(defineRoutes, "defineRoutes");
2082
1721
  export {
2083
1722
  AppInjector,
2084
- Authorize,
2085
1723
  BadGatewayException,
2086
1724
  BadRequestException,
2087
- CONTROLLER_METADATA_KEY,
2088
1725
  ConflictException,
2089
1726
  Controller,
2090
1727
  Delete,
@@ -2093,17 +1730,12 @@ export {
2093
1730
  GatewayTimeoutException,
2094
1731
  Get,
2095
1732
  HttpVersionNotSupportedException,
2096
- INJECTABLE_METADATA_KEY,
2097
- INJECT_METADATA_KEY,
2098
- Inject,
2099
1733
  Injectable,
2100
1734
  InsufficientStorageException,
2101
1735
  InternalServerException,
2102
1736
  Logger,
2103
1737
  LoopDetectedException,
2104
- MODULE_METADATA_KEY,
2105
1738
  MethodNotAllowedException,
2106
- Module,
2107
1739
  NetworkAuthenticationRequiredException,
2108
1740
  NetworkConnectTimeoutException,
2109
1741
  NotAcceptableException,
@@ -2111,45 +1743,45 @@ export {
2111
1743
  NotFoundException,
2112
1744
  NotImplementedException,
2113
1745
  NoxApp,
2114
- NoxRendererClient,
2115
1746
  NoxSocket,
2116
1747
  Patch,
2117
1748
  PaymentRequiredException,
2118
1749
  Post,
2119
1750
  Put,
2120
1751
  RENDERER_EVENT_TYPE,
2121
- ROUTE_METADATA_KEY,
2122
- RendererEventRegistry,
2123
1752
  Request,
2124
1753
  RequestTimeoutException,
2125
1754
  ResponseException,
2126
1755
  RootInjector,
2127
1756
  Router,
2128
1757
  ServiceUnavailableException,
1758
+ Token,
2129
1759
  TooManyRequestsException,
2130
1760
  UnauthorizedException,
2131
1761
  UpgradeRequiredException,
2132
- UseMiddlewares,
2133
1762
  VariantAlsoNegotiatesException,
1763
+ WindowManager,
2134
1764
  bootstrapApplication,
2135
1765
  createRendererEventMessage,
2136
- exposeNoxusBridge,
1766
+ defineRoutes,
2137
1767
  forwardRef,
2138
1768
  getControllerMetadata,
2139
- getGuardForController,
2140
- getGuardForControllerAction,
2141
- getInjectableMetadata,
2142
- getMiddlewaresForController,
2143
- getMiddlewaresForControllerAction,
2144
- getModuleMetadata,
2145
1769
  getRouteMetadata,
2146
- hasInjectableMetadata,
2147
1770
  inject,
2148
- isRendererEventMessage
1771
+ isAtomicHttpMethod,
1772
+ isRendererEventMessage,
1773
+ token
2149
1774
  };
2150
1775
  /**
2151
1776
  * @copyright 2025 NoxFly
2152
1777
  * @license MIT
2153
1778
  * @author NoxFly
2154
1779
  */
1780
+ /**
1781
+ * @copyright 2025 NoxFly
1782
+ * @license MIT
1783
+ * @author NoxFly
1784
+ *
1785
+ * Entry point for Electron main-process consumers.
1786
+ */
2155
1787
  //# sourceMappingURL=main.mjs.map