@noxfly/noxus 3.0.0-dev.2 → 3.0.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -86,116 +86,6 @@ var init_token = __esm({
86
86
  }
87
87
  });
88
88
 
89
- // src/DI/app-injector.ts
90
- function keyOf(k) {
91
- return k;
92
- }
93
- function inject(t) {
94
- return RootInjector.resolve(t);
95
- }
96
- var _AppInjector, AppInjector, RootInjector;
97
- var init_app_injector = __esm({
98
- "src/DI/app-injector.ts"() {
99
- "use strict";
100
- init_forward_ref();
101
- init_token();
102
- __name(keyOf, "keyOf");
103
- _AppInjector = class _AppInjector {
104
- constructor(name = null) {
105
- this.name = name;
106
- this.bindings = /* @__PURE__ */ new Map();
107
- this.singletons = /* @__PURE__ */ new Map();
108
- this.scoped = /* @__PURE__ */ new Map();
109
- }
110
- /**
111
- * Creates a child scope for per-request lifetime resolution.
112
- */
113
- createScope() {
114
- const scope = new _AppInjector();
115
- scope.bindings = this.bindings;
116
- scope.singletons = this.singletons;
117
- return scope;
118
- }
119
- /**
120
- * Registers a binding explicitly.
121
- */
122
- register(key, implementation, lifetime, deps = []) {
123
- const k = keyOf(key);
124
- if (!this.bindings.has(k)) {
125
- this.bindings.set(k, { lifetime, implementation, deps });
126
- }
127
- }
128
- /**
129
- * Resolves a dependency by token or class reference.
130
- */
131
- resolve(target) {
132
- if (target instanceof ForwardReference) {
133
- return this._resolveForwardRef(target);
134
- }
135
- const k = keyOf(target);
136
- if (this.singletons.has(k)) {
137
- return this.singletons.get(k);
138
- }
139
- const binding = this.bindings.get(k);
140
- if (!binding) {
141
- const name = target instanceof Token ? target.description : target.name ?? "unknown";
142
- throw new Error(
143
- `[Noxus DI] No binding found for "${name}".
144
- Did you forget to declare it in @Injectable({ deps }) or in bootstrapApplication({ singletons })?`
145
- );
146
- }
147
- switch (binding.lifetime) {
148
- case "transient":
149
- return this._instantiate(binding);
150
- case "scope": {
151
- if (this.scoped.has(k)) return this.scoped.get(k);
152
- const inst = this._instantiate(binding);
153
- this.scoped.set(k, inst);
154
- return inst;
155
- }
156
- case "singleton": {
157
- if (this.singletons.has(k)) return this.singletons.get(k);
158
- const inst = this._instantiate(binding);
159
- this.singletons.set(k, inst);
160
- if (binding.instance === void 0) {
161
- binding.instance = inst;
162
- }
163
- return inst;
164
- }
165
- }
166
- }
167
- // -------------------------------------------------------------------------
168
- _resolveForwardRef(ref) {
169
- return new Proxy({}, {
170
- get: /* @__PURE__ */ __name((_obj, prop, receiver) => {
171
- const realType = ref.forwardRefFn();
172
- const instance = this.resolve(realType);
173
- const value = Reflect.get(instance, prop, receiver);
174
- return typeof value === "function" ? value.bind(instance) : value;
175
- }, "get"),
176
- set: /* @__PURE__ */ __name((_obj, prop, value, receiver) => {
177
- const realType = ref.forwardRefFn();
178
- const instance = this.resolve(realType);
179
- return Reflect.set(instance, prop, value, receiver);
180
- }, "set"),
181
- getPrototypeOf: /* @__PURE__ */ __name(() => {
182
- const realType = ref.forwardRefFn();
183
- return realType.prototype;
184
- }, "getPrototypeOf")
185
- });
186
- }
187
- _instantiate(binding) {
188
- const resolvedDeps = binding.deps.map((dep) => this.resolve(dep));
189
- return new binding.implementation(...resolvedDeps);
190
- }
191
- };
192
- __name(_AppInjector, "AppInjector");
193
- AppInjector = _AppInjector;
194
- RootInjector = new AppInjector("root");
195
- __name(inject, "inject");
196
- }
197
- });
198
-
199
89
  // src/utils/logger.ts
200
90
  function getPrettyTimestamp() {
201
91
  const now = /* @__PURE__ */ new Date();
@@ -444,6 +334,10 @@ var init_logger = __esm({
444
334
  });
445
335
 
446
336
  // src/DI/injector-explorer.ts
337
+ var injector_explorer_exports = {};
338
+ __export(injector_explorer_exports, {
339
+ InjectorExplorer: () => InjectorExplorer
340
+ });
447
341
  var _InjectorExplorer, InjectorExplorer;
448
342
  var init_injector_explorer = __esm({
449
343
  "src/DI/injector-explorer.ts"() {
@@ -454,6 +348,13 @@ var init_injector_explorer = __esm({
454
348
  // -------------------------------------------------------------------------
455
349
  // Public API
456
350
  // -------------------------------------------------------------------------
351
+ /**
352
+ * Sets the callback used to register controllers.
353
+ * Must be called once before processPending (typically by bootstrapApplication).
354
+ */
355
+ static setControllerRegistrar(registrar) {
356
+ _InjectorExplorer.controllerRegistrar = registrar;
357
+ }
457
358
  static enqueue(reg) {
458
359
  if (_InjectorExplorer.processed && !_InjectorExplorer.accumulating) {
459
360
  _InjectorExplorer._registerImmediate(reg);
@@ -479,16 +380,37 @@ var init_injector_explorer = __esm({
479
380
  /**
480
381
  * Exits accumulation mode and flushes queued registrations
481
382
  * with the same two-phase guarantee as processPending.
383
+ * Serialised through a lock to prevent concurrent lazy loads from corrupting the queue.
482
384
  */
483
385
  static flushAccumulated(routeGuards = [], routeMiddlewares = [], pathPrefix = "") {
484
- _InjectorExplorer.accumulating = false;
485
- const queue = [..._InjectorExplorer.pending];
386
+ _InjectorExplorer.loadingLock = _InjectorExplorer.loadingLock.then(() => {
387
+ _InjectorExplorer.accumulating = false;
388
+ const queue = [..._InjectorExplorer.pending];
389
+ _InjectorExplorer.pending.length = 0;
390
+ _InjectorExplorer._phaseOne(queue);
391
+ for (const reg of queue) {
392
+ if (reg.isController) reg.pathPrefix = pathPrefix;
393
+ }
394
+ _InjectorExplorer._phaseTwo(queue, void 0, routeGuards, routeMiddlewares);
395
+ });
396
+ return _InjectorExplorer.loadingLock;
397
+ }
398
+ /**
399
+ * Returns a Promise that resolves once all pending flushAccumulated calls
400
+ * have completed. Useful for awaiting lazy-load serialisation.
401
+ */
402
+ static waitForFlush() {
403
+ return _InjectorExplorer.loadingLock;
404
+ }
405
+ /**
406
+ * Resets the explorer state. Intended for tests only.
407
+ */
408
+ static reset() {
486
409
  _InjectorExplorer.pending.length = 0;
487
- _InjectorExplorer._phaseOne(queue);
488
- for (const reg of queue) {
489
- if (reg.isController) reg.pathPrefix = pathPrefix;
490
- }
491
- _InjectorExplorer._phaseTwo(queue, void 0, routeGuards, routeMiddlewares);
410
+ _InjectorExplorer.processed = false;
411
+ _InjectorExplorer.accumulating = false;
412
+ _InjectorExplorer.loadingLock = Promise.resolve();
413
+ _InjectorExplorer.controllerRegistrar = null;
492
414
  }
493
415
  // -------------------------------------------------------------------------
494
416
  // Private helpers
@@ -499,8 +421,15 @@ var init_injector_explorer = __esm({
499
421
  RootInjector.register(reg.key, reg.implementation, reg.lifetime, reg.deps);
500
422
  }
501
423
  }
502
- /** Phase 2: resolve singletons and register controllers in the router. */
424
+ /** Phase 2: validate deps, resolve singletons and register controllers via the registrar callback. */
503
425
  static _phaseTwo(queue, overrides, routeGuards = [], routeMiddlewares = []) {
426
+ for (const reg of queue) {
427
+ for (const dep of reg.deps) {
428
+ if (!RootInjector.bindings.has(dep) && !RootInjector.singletons.has(dep)) {
429
+ Logger.warn(`[Noxus DI] "${reg.implementation.name}" declares dep "${dep.name ?? dep}" which has no binding`);
430
+ }
431
+ }
432
+ }
504
433
  for (const reg of queue) {
505
434
  if (overrides?.has(reg.key)) {
506
435
  const override = overrides.get(reg.key);
@@ -512,9 +441,15 @@ var init_injector_explorer = __esm({
512
441
  RootInjector.resolve(reg.key);
513
442
  }
514
443
  if (reg.isController) {
515
- const { Router: Router2 } = (init_router(), __toCommonJS(router_exports));
516
- const router = RootInjector.resolve(Router2);
517
- router.registerController(reg.implementation, reg.pathPrefix ?? "", routeGuards, routeMiddlewares);
444
+ if (!_InjectorExplorer.controllerRegistrar) {
445
+ throw new Error("[Noxus DI] No controller registrar set. Call InjectorExplorer.setControllerRegistrar() before processing.");
446
+ }
447
+ _InjectorExplorer.controllerRegistrar(
448
+ reg.implementation,
449
+ reg.pathPrefix ?? "",
450
+ routeGuards,
451
+ routeMiddlewares
452
+ );
518
453
  } else if (reg.lifetime !== "singleton") {
519
454
  Logger.log(`Registered ${reg.implementation.name} as ${reg.lifetime}`);
520
455
  }
@@ -525,10 +460,8 @@ var init_injector_explorer = __esm({
525
460
  if (reg.lifetime === "singleton") {
526
461
  RootInjector.resolve(reg.key);
527
462
  }
528
- if (reg.isController) {
529
- const { Router: Router2 } = (init_router(), __toCommonJS(router_exports));
530
- const router = RootInjector.resolve(Router2);
531
- router.registerController(reg.implementation);
463
+ if (reg.isController && _InjectorExplorer.controllerRegistrar) {
464
+ _InjectorExplorer.controllerRegistrar(reg.implementation, "", [], []);
532
465
  }
533
466
  }
534
467
  };
@@ -536,11 +469,193 @@ var init_injector_explorer = __esm({
536
469
  _InjectorExplorer.pending = [];
537
470
  _InjectorExplorer.processed = false;
538
471
  _InjectorExplorer.accumulating = false;
472
+ _InjectorExplorer.loadingLock = Promise.resolve();
473
+ _InjectorExplorer.controllerRegistrar = null;
539
474
  InjectorExplorer = _InjectorExplorer;
540
475
  }
541
476
  });
542
477
 
478
+ // src/DI/app-injector.ts
479
+ function keyOf(k) {
480
+ return k;
481
+ }
482
+ function resetRootInjector() {
483
+ RootInjector.bindings.clear();
484
+ RootInjector.singletons.clear();
485
+ RootInjector.scoped.clear();
486
+ const { InjectorExplorer: InjectorExplorer2 } = (init_injector_explorer(), __toCommonJS(injector_explorer_exports));
487
+ InjectorExplorer2.reset();
488
+ }
489
+ function inject(t) {
490
+ return RootInjector.resolve(t);
491
+ }
492
+ var _AppInjector, AppInjector, RootInjector;
493
+ var init_app_injector = __esm({
494
+ "src/DI/app-injector.ts"() {
495
+ "use strict";
496
+ init_forward_ref();
497
+ init_token();
498
+ __name(keyOf, "keyOf");
499
+ _AppInjector = class _AppInjector {
500
+ constructor(name = null) {
501
+ this.name = name;
502
+ this.bindings = /* @__PURE__ */ new Map();
503
+ this.singletons = /* @__PURE__ */ new Map();
504
+ this.scoped = /* @__PURE__ */ new Map();
505
+ }
506
+ /**
507
+ * Creates a child scope for per-request lifetime resolution.
508
+ */
509
+ createScope() {
510
+ const scope = new _AppInjector();
511
+ scope.bindings = this.bindings;
512
+ scope.singletons = this.singletons;
513
+ return scope;
514
+ }
515
+ /**
516
+ * Registers a binding explicitly.
517
+ */
518
+ register(key, implementation, lifetime, deps = []) {
519
+ const k = keyOf(key);
520
+ if (!this.bindings.has(k)) {
521
+ this.bindings.set(k, { lifetime, implementation, deps });
522
+ }
523
+ }
524
+ /**
525
+ * Resolves a dependency by token or class reference.
526
+ */
527
+ resolve(target) {
528
+ if (target instanceof ForwardReference) {
529
+ return this._resolveForwardRef(target);
530
+ }
531
+ const k = keyOf(target);
532
+ if (this.singletons.has(k)) {
533
+ return this.singletons.get(k);
534
+ }
535
+ const binding = this.bindings.get(k);
536
+ if (!binding) {
537
+ const name = target instanceof Token ? target.description : target.name ?? "unknown";
538
+ throw new Error(
539
+ `[Noxus DI] No binding found for "${name}".
540
+ Did you forget to declare it in @Injectable({ deps }) or in bootstrapApplication({ singletons })?`
541
+ );
542
+ }
543
+ switch (binding.lifetime) {
544
+ case "transient":
545
+ return this._instantiate(binding);
546
+ case "scope": {
547
+ if (this.scoped.has(k)) return this.scoped.get(k);
548
+ const inst = this._instantiate(binding);
549
+ this.scoped.set(k, inst);
550
+ return inst;
551
+ }
552
+ case "singleton": {
553
+ if (this.singletons.has(k)) return this.singletons.get(k);
554
+ const inst = this._instantiate(binding);
555
+ this.singletons.set(k, inst);
556
+ if (binding.instance === void 0) {
557
+ binding.instance = inst;
558
+ }
559
+ return inst;
560
+ }
561
+ }
562
+ }
563
+ // -------------------------------------------------------------------------
564
+ _resolveForwardRef(ref) {
565
+ let resolved;
566
+ return new Proxy({}, {
567
+ get: /* @__PURE__ */ __name((_obj, prop, receiver) => {
568
+ resolved ?? (resolved = this.resolve(ref.forwardRefFn()));
569
+ const value = Reflect.get(resolved, prop, receiver);
570
+ return typeof value === "function" ? value.bind(resolved) : value;
571
+ }, "get"),
572
+ set: /* @__PURE__ */ __name((_obj, prop, value, receiver) => {
573
+ resolved ?? (resolved = this.resolve(ref.forwardRefFn()));
574
+ return Reflect.set(resolved, prop, value, receiver);
575
+ }, "set"),
576
+ getPrototypeOf: /* @__PURE__ */ __name(() => {
577
+ resolved ?? (resolved = this.resolve(ref.forwardRefFn()));
578
+ return Object.getPrototypeOf(resolved);
579
+ }, "getPrototypeOf")
580
+ });
581
+ }
582
+ _instantiate(binding) {
583
+ const resolvedDeps = binding.deps.map((dep) => this.resolve(dep));
584
+ return new binding.implementation(...resolvedDeps);
585
+ }
586
+ };
587
+ __name(_AppInjector, "AppInjector");
588
+ AppInjector = _AppInjector;
589
+ RootInjector = new AppInjector("root");
590
+ __name(resetRootInjector, "resetRootInjector");
591
+ __name(inject, "inject");
592
+ }
593
+ });
594
+
595
+ // src/main.ts
596
+ var main_exports = {};
597
+ __export(main_exports, {
598
+ AppInjector: () => AppInjector,
599
+ BadGatewayException: () => BadGatewayException,
600
+ BadRequestException: () => BadRequestException,
601
+ ConflictException: () => ConflictException,
602
+ Controller: () => Controller,
603
+ Delete: () => Delete,
604
+ ForbiddenException: () => ForbiddenException,
605
+ ForwardReference: () => ForwardReference,
606
+ GatewayTimeoutException: () => GatewayTimeoutException,
607
+ Get: () => Get,
608
+ HttpVersionNotSupportedException: () => HttpVersionNotSupportedException,
609
+ Injectable: () => Injectable,
610
+ InsufficientStorageException: () => InsufficientStorageException,
611
+ InternalServerException: () => InternalServerException,
612
+ Logger: () => Logger,
613
+ LoopDetectedException: () => LoopDetectedException,
614
+ MethodNotAllowedException: () => MethodNotAllowedException,
615
+ NetworkAuthenticationRequiredException: () => NetworkAuthenticationRequiredException,
616
+ NetworkConnectTimeoutException: () => NetworkConnectTimeoutException,
617
+ NotAcceptableException: () => NotAcceptableException,
618
+ NotExtendedException: () => NotExtendedException,
619
+ NotFoundException: () => NotFoundException,
620
+ NotImplementedException: () => NotImplementedException,
621
+ NoxApp: () => NoxApp,
622
+ NoxSocket: () => NoxSocket,
623
+ Patch: () => Patch,
624
+ PaymentRequiredException: () => PaymentRequiredException,
625
+ Post: () => Post,
626
+ Put: () => Put,
627
+ RENDERER_EVENT_TYPE: () => RENDERER_EVENT_TYPE,
628
+ Request: () => Request,
629
+ RequestTimeoutException: () => RequestTimeoutException,
630
+ ResponseException: () => ResponseException,
631
+ RootInjector: () => RootInjector,
632
+ Router: () => Router,
633
+ ServiceUnavailableException: () => ServiceUnavailableException,
634
+ Token: () => Token,
635
+ TooManyRequestsException: () => TooManyRequestsException,
636
+ UnauthorizedException: () => UnauthorizedException,
637
+ UpgradeRequiredException: () => UpgradeRequiredException,
638
+ VariantAlsoNegotiatesException: () => VariantAlsoNegotiatesException,
639
+ WindowManager: () => WindowManager,
640
+ bootstrapApplication: () => bootstrapApplication,
641
+ createRendererEventMessage: () => createRendererEventMessage,
642
+ defineRoutes: () => defineRoutes,
643
+ forwardRef: () => forwardRef,
644
+ getControllerMetadata: () => getControllerMetadata,
645
+ getRouteMetadata: () => getRouteMetadata,
646
+ inject: () => inject,
647
+ isAtomicHttpMethod: () => isAtomicHttpMethod,
648
+ isRendererEventMessage: () => isRendererEventMessage,
649
+ resetRootInjector: () => resetRootInjector,
650
+ token: () => token
651
+ });
652
+ module.exports = __toCommonJS(main_exports);
653
+ init_app_injector();
654
+ init_token();
655
+
543
656
  // src/decorators/controller.decorator.ts
657
+ init_injector_explorer();
658
+ var controllerMetaMap = /* @__PURE__ */ new WeakMap();
544
659
  function Controller(options = {}) {
545
660
  return (target) => {
546
661
  const meta = {
@@ -556,21 +671,15 @@ function Controller(options = {}) {
556
671
  });
557
672
  };
558
673
  }
674
+ __name(Controller, "Controller");
559
675
  function getControllerMetadata(target) {
560
676
  return controllerMetaMap.get(target);
561
677
  }
562
- var controllerMetaMap;
563
- var init_controller_decorator = __esm({
564
- "src/decorators/controller.decorator.ts"() {
565
- "use strict";
566
- init_injector_explorer();
567
- controllerMetaMap = /* @__PURE__ */ new WeakMap();
568
- __name(Controller, "Controller");
569
- __name(getControllerMetadata, "getControllerMetadata");
570
- }
571
- });
678
+ __name(getControllerMetadata, "getControllerMetadata");
572
679
 
573
680
  // src/decorators/injectable.decorator.ts
681
+ init_injector_explorer();
682
+ init_token();
574
683
  function Injectable(options = {}) {
575
684
  const { lifetime = "scope", deps = [] } = options;
576
685
  return (target) => {
@@ -587,19 +696,15 @@ function Injectable(options = {}) {
587
696
  });
588
697
  };
589
698
  }
590
- var init_injectable_decorator = __esm({
591
- "src/decorators/injectable.decorator.ts"() {
592
- "use strict";
593
- init_injector_explorer();
594
- init_token();
595
- __name(Injectable, "Injectable");
596
- }
597
- });
699
+ __name(Injectable, "Injectable");
598
700
 
599
701
  // src/decorators/method.decorator.ts
702
+ var ATOMIC_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
600
703
  function isAtomicHttpMethod(m) {
601
704
  return typeof m === "string" && ATOMIC_METHODS.has(m);
602
705
  }
706
+ __name(isAtomicHttpMethod, "isAtomicHttpMethod");
707
+ var routeMetaMap = /* @__PURE__ */ new WeakMap();
603
708
  function createRouteDecorator(verb) {
604
709
  return (path2, options = {}) => {
605
710
  return (target, propertyKey) => {
@@ -616,399 +721,416 @@ function createRouteDecorator(verb) {
616
721
  };
617
722
  };
618
723
  }
724
+ __name(createRouteDecorator, "createRouteDecorator");
619
725
  function getRouteMetadata(target) {
620
726
  return routeMetaMap.get(target) ?? [];
621
727
  }
622
- var ATOMIC_METHODS, routeMetaMap, Get, Post, Put, Patch, Delete;
623
- var init_method_decorator = __esm({
624
- "src/decorators/method.decorator.ts"() {
625
- "use strict";
626
- ATOMIC_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
627
- __name(isAtomicHttpMethod, "isAtomicHttpMethod");
628
- routeMetaMap = /* @__PURE__ */ new WeakMap();
629
- __name(createRouteDecorator, "createRouteDecorator");
630
- __name(getRouteMetadata, "getRouteMetadata");
631
- Get = createRouteDecorator("GET");
632
- Post = createRouteDecorator("POST");
633
- Put = createRouteDecorator("PUT");
634
- Patch = createRouteDecorator("PATCH");
635
- Delete = createRouteDecorator("DELETE");
636
- }
637
- });
728
+ __name(getRouteMetadata, "getRouteMetadata");
729
+ var Get = createRouteDecorator("GET");
730
+ var Post = createRouteDecorator("POST");
731
+ var Put = createRouteDecorator("PUT");
732
+ var Patch = createRouteDecorator("PATCH");
733
+ var Delete = createRouteDecorator("DELETE");
734
+
735
+ // src/internal/router.ts
736
+ init_injector_explorer();
737
+ init_logger();
638
738
 
639
739
  // src/utils/radix-tree.ts
640
- var _RadixNode, RadixNode, _RadixTree, RadixTree;
641
- var init_radix_tree = __esm({
642
- "src/utils/radix-tree.ts"() {
643
- "use strict";
644
- _RadixNode = class _RadixNode {
645
- /**
646
- * Creates a new RadixNode.
647
- * @param segment - The segment of the path this node represents.
648
- */
649
- constructor(segment) {
650
- this.children = [];
651
- this.segment = segment;
652
- this.isParam = segment.startsWith(":");
653
- if (this.isParam) {
654
- this.paramName = segment.slice(1);
655
- }
656
- }
657
- /**
658
- * Matches a child node against a given segment.
659
- * This method checks if the segment matches any of the children nodes.
660
- * @param segment - The segment to match against the children of this node.
661
- * @returns A child node that matches the segment, or undefined if no match is found.
662
- */
663
- matchChild(segment) {
664
- for (const child of this.children) {
665
- if (child.isParam || segment.startsWith(child.segment))
666
- return child;
667
- }
668
- return void 0;
669
- }
670
- /**
671
- * Finds a child node that matches the segment exactly.
672
- * This method checks if there is a child node that matches the segment exactly.
673
- * @param segment - The segment to find an exact match for among the children of this node.
674
- * @returns A child node that matches the segment exactly, or undefined if no match is found.
675
- */
676
- findExactChild(segment) {
677
- return this.children.find((c) => c.segment === segment);
678
- }
679
- /**
680
- * Adds a child node to this node's children.
681
- * This method adds a new child node to the list of children for this node.
682
- * @param node - The child node to add to this node's children.
683
- */
684
- addChild(node) {
685
- this.children.push(node);
686
- }
687
- };
688
- __name(_RadixNode, "RadixNode");
689
- RadixNode = _RadixNode;
690
- _RadixTree = class _RadixTree {
691
- constructor() {
692
- this.root = new RadixNode("");
740
+ var _RadixNode = class _RadixNode {
741
+ /**
742
+ * Creates a new RadixNode.
743
+ * @param segment - The segment of the path this node represents.
744
+ */
745
+ constructor(segment) {
746
+ this.children = [];
747
+ this.segment = segment;
748
+ this.isParam = segment.startsWith(":");
749
+ if (this.isParam) {
750
+ this.paramName = segment.slice(1);
751
+ }
752
+ }
753
+ /**
754
+ * Matches a child node against a given segment.
755
+ * This method checks if the segment matches any of the children nodes.
756
+ * @param segment - The segment to match against the children of this node.
757
+ * @returns A child node that matches the segment, or undefined if no match is found.
758
+ */
759
+ matchChild(segment) {
760
+ for (const child of this.children) {
761
+ if (child.isParam || segment.startsWith(child.segment))
762
+ return child;
763
+ }
764
+ return void 0;
765
+ }
766
+ /**
767
+ * Finds a child node that matches the segment exactly.
768
+ * This method checks if there is a child node that matches the segment exactly.
769
+ * @param segment - The segment to find an exact match for among the children of this node.
770
+ * @returns A child node that matches the segment exactly, or undefined if no match is found.
771
+ */
772
+ findExactChild(segment) {
773
+ return this.children.find((c) => c.segment === segment);
774
+ }
775
+ /**
776
+ * Adds a child node to this node's children.
777
+ * This method adds a new child node to the list of children for this node.
778
+ * @param node - The child node to add to this node's children.
779
+ */
780
+ addChild(node) {
781
+ this.children.push(node);
782
+ }
783
+ };
784
+ __name(_RadixNode, "RadixNode");
785
+ var RadixNode = _RadixNode;
786
+ var _RadixTree = class _RadixTree {
787
+ constructor() {
788
+ this.root = new RadixNode("");
789
+ }
790
+ /**
791
+ * Inserts a path and its associated value into the Radix Tree.
792
+ * This method normalizes the path and inserts it into the tree, associating it with
793
+ * @param path - The path to insert into the tree.
794
+ * @param value - The value to associate with the path.
795
+ */
796
+ insert(path2, value) {
797
+ const segments = this.normalize(path2);
798
+ this.insertRecursive(this.root, segments, value);
799
+ }
800
+ /**
801
+ * Recursively inserts a path into the Radix Tree.
802
+ * This method traverses the tree and inserts the segments of the path, creating new nodes
803
+ * @param node - The node to start inserting from.
804
+ * @param segments - The segments of the path to insert.
805
+ * @param value - The value to associate with the path.
806
+ */
807
+ insertRecursive(node, segments, value) {
808
+ if (segments.length === 0) {
809
+ node.value = value;
810
+ return;
811
+ }
812
+ const segment = segments[0] ?? "";
813
+ let child = node.children.find(
814
+ (c) => c.isParam === segment.startsWith(":") && (c.isParam || c.segment === segment)
815
+ );
816
+ if (!child) {
817
+ child = new RadixNode(segment);
818
+ node.addChild(child);
819
+ }
820
+ this.insertRecursive(child, segments.slice(1), value);
821
+ }
822
+ /**
823
+ * Searches for a path in the Radix Tree.
824
+ * This method normalizes the path and searches for it in the tree, returning the node
825
+ * @param path - The path to search for in the Radix Tree.
826
+ * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
827
+ */
828
+ search(path2) {
829
+ const segments = this.normalize(path2);
830
+ return this.searchRecursive(this.root, segments, {});
831
+ }
832
+ collectValues(node, values = []) {
833
+ if (!node) {
834
+ node = this.root;
835
+ }
836
+ if (node.value !== void 0) {
837
+ values.push(node.value);
838
+ }
839
+ for (const child of node.children) {
840
+ this.collectValues(child, values);
841
+ }
842
+ return values;
843
+ }
844
+ /**
845
+ * Recursively searches for a path in the Radix Tree.
846
+ * This method traverses the tree and searches for the segments of the path, collecting parameters
847
+ * @param node - The node to start searching from.
848
+ * @param segments - The segments of the path to search for.
849
+ * @param params - The parameters collected during the search.
850
+ * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
851
+ */
852
+ searchRecursive(node, segments, params) {
853
+ if (segments.length === 0) {
854
+ if (node.value !== void 0) {
855
+ return {
856
+ node,
857
+ params
858
+ };
693
859
  }
694
- /**
695
- * Inserts a path and its associated value into the Radix Tree.
696
- * This method normalizes the path and inserts it into the tree, associating it with
697
- * @param path - The path to insert into the tree.
698
- * @param value - The value to associate with the path.
699
- */
700
- insert(path2, value) {
701
- const segments = this.normalize(path2);
702
- this.insertRecursive(this.root, segments, value);
860
+ return void 0;
861
+ }
862
+ const [segment, ...rest] = segments;
863
+ const staticChildren = [];
864
+ const paramChildren = [];
865
+ for (const child of node.children) {
866
+ if (child.isParam) {
867
+ paramChildren.push(child);
868
+ } else if (segment === child.segment) {
869
+ staticChildren.push(child);
703
870
  }
704
- /**
705
- * Recursively inserts a path into the Radix Tree.
706
- * This method traverses the tree and inserts the segments of the path, creating new nodes
707
- * @param node - The node to start inserting from.
708
- * @param segments - The segments of the path to insert.
709
- * @param value - The value to associate with the path.
710
- */
711
- insertRecursive(node, segments, value) {
712
- if (segments.length === 0) {
713
- node.value = value;
714
- return;
715
- }
716
- const segment = segments[0] ?? "";
717
- let child = node.children.find(
718
- (c) => c.isParam === segment.startsWith(":") && (c.isParam || c.segment === segment)
719
- );
720
- if (!child) {
721
- child = new RadixNode(segment);
722
- node.addChild(child);
871
+ }
872
+ for (const child of staticChildren) {
873
+ if (rest.length === 0) {
874
+ if (child.value !== void 0 || child.children.length > 0) {
875
+ return { node: child, params };
723
876
  }
724
- this.insertRecursive(child, segments.slice(1), value);
725
877
  }
726
- /**
727
- * Searches for a path in the Radix Tree.
728
- * This method normalizes the path and searches for it in the tree, returning the node
729
- * @param path - The path to search for in the Radix Tree.
730
- * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
731
- */
732
- search(path2) {
733
- const segments = this.normalize(path2);
734
- return this.searchRecursive(this.root, segments, {});
735
- }
736
- /**
737
- * Recursively searches for a path in the Radix Tree.
738
- * This method traverses the tree and searches for the segments of the path, collecting parameters
739
- * @param node - The node to start searching from.
740
- * @param segments - The segments of the path to search for.
741
- * @param params - The parameters collected during the search.
742
- * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
743
- */
744
- searchRecursive(node, segments, params) {
745
- if (segments.length === 0) {
746
- if (node.value !== void 0) {
747
- return {
748
- node,
749
- params
750
- };
751
- }
752
- return void 0;
753
- }
754
- const [segment, ...rest] = segments;
755
- for (const child of node.children) {
756
- if (child.isParam) {
757
- const paramName = child.paramName;
758
- const childParams = {
759
- ...params,
760
- [paramName]: segment ?? ""
761
- };
762
- if (rest.length === 0) {
763
- return {
764
- node: child,
765
- params: childParams
766
- };
767
- }
768
- const result = this.searchRecursive(child, rest, childParams);
769
- if (result)
770
- return result;
771
- } else if (segment === child.segment) {
772
- if (rest.length === 0) {
773
- return {
774
- node: child,
775
- params
776
- };
777
- }
778
- const result = this.searchRecursive(child, rest, params);
779
- if (result)
780
- return result;
781
- }
878
+ const result = this.searchRecursive(child, rest, params);
879
+ if (result) return result;
880
+ }
881
+ for (const child of paramChildren) {
882
+ const paramName = child.paramName;
883
+ const childParams = {
884
+ ...params,
885
+ [paramName]: segment ?? ""
886
+ };
887
+ if (rest.length === 0) {
888
+ if (child.value !== void 0 || child.children.length > 0) {
889
+ return { node: child, params: childParams };
782
890
  }
783
- return void 0;
784
- }
785
- /**
786
- * Normalizes a path into an array of segments.
787
- * This method removes leading and trailing slashes, splits the path by slashes, and
788
- * @param path - The path to normalize.
789
- * @returns An array of normalized path segments.
790
- */
791
- normalize(path2) {
792
- const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
793
- return ["", ...segments];
794
891
  }
795
- };
796
- __name(_RadixTree, "RadixTree");
797
- RadixTree = _RadixTree;
892
+ const result = this.searchRecursive(child, rest, childParams);
893
+ if (result) return result;
894
+ }
895
+ return void 0;
798
896
  }
799
- });
897
+ /**
898
+ * Normalizes a path into an array of segments.
899
+ * This method removes leading and trailing slashes, splits the path by slashes, and
900
+ * @param path - The path to normalize.
901
+ * @returns An array of normalized path segments.
902
+ */
903
+ normalize(path2) {
904
+ const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
905
+ return ["", ...segments];
906
+ }
907
+ };
908
+ __name(_RadixTree, "RadixTree");
909
+ var RadixTree = _RadixTree;
800
910
 
801
911
  // src/internal/exceptions.ts
802
- 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;
803
- var init_exceptions = __esm({
804
- "src/internal/exceptions.ts"() {
805
- "use strict";
806
- _ResponseException = class _ResponseException extends Error {
807
- constructor(statusOrMessage, message) {
808
- let statusCode;
809
- if (typeof statusOrMessage === "number") {
810
- statusCode = statusOrMessage;
811
- } else if (typeof statusOrMessage === "string") {
812
- message = statusOrMessage;
813
- }
814
- super(message ?? "");
815
- this.status = 0;
816
- if (statusCode !== void 0) {
817
- this.status = statusCode;
818
- }
819
- this.name = this.constructor.name.replace(/([A-Z])/g, " $1");
820
- }
821
- };
822
- __name(_ResponseException, "ResponseException");
823
- ResponseException = _ResponseException;
824
- _BadRequestException = class _BadRequestException extends ResponseException {
825
- constructor() {
826
- super(...arguments);
827
- this.status = 400;
828
- }
829
- };
830
- __name(_BadRequestException, "BadRequestException");
831
- BadRequestException = _BadRequestException;
832
- _UnauthorizedException = class _UnauthorizedException extends ResponseException {
833
- constructor() {
834
- super(...arguments);
835
- this.status = 401;
836
- }
837
- };
838
- __name(_UnauthorizedException, "UnauthorizedException");
839
- UnauthorizedException = _UnauthorizedException;
840
- _PaymentRequiredException = class _PaymentRequiredException extends ResponseException {
841
- constructor() {
842
- super(...arguments);
843
- this.status = 402;
844
- }
845
- };
846
- __name(_PaymentRequiredException, "PaymentRequiredException");
847
- PaymentRequiredException = _PaymentRequiredException;
848
- _ForbiddenException = class _ForbiddenException extends ResponseException {
849
- constructor() {
850
- super(...arguments);
851
- this.status = 403;
852
- }
853
- };
854
- __name(_ForbiddenException, "ForbiddenException");
855
- ForbiddenException = _ForbiddenException;
856
- _NotFoundException = class _NotFoundException extends ResponseException {
857
- constructor() {
858
- super(...arguments);
859
- this.status = 404;
860
- }
861
- };
862
- __name(_NotFoundException, "NotFoundException");
863
- NotFoundException = _NotFoundException;
864
- _MethodNotAllowedException = class _MethodNotAllowedException extends ResponseException {
865
- constructor() {
866
- super(...arguments);
867
- this.status = 405;
868
- }
869
- };
870
- __name(_MethodNotAllowedException, "MethodNotAllowedException");
871
- MethodNotAllowedException = _MethodNotAllowedException;
872
- _NotAcceptableException = class _NotAcceptableException extends ResponseException {
873
- constructor() {
874
- super(...arguments);
875
- this.status = 406;
876
- }
877
- };
878
- __name(_NotAcceptableException, "NotAcceptableException");
879
- NotAcceptableException = _NotAcceptableException;
880
- _RequestTimeoutException = class _RequestTimeoutException extends ResponseException {
881
- constructor() {
882
- super(...arguments);
883
- this.status = 408;
884
- }
885
- };
886
- __name(_RequestTimeoutException, "RequestTimeoutException");
887
- RequestTimeoutException = _RequestTimeoutException;
888
- _ConflictException = class _ConflictException extends ResponseException {
889
- constructor() {
890
- super(...arguments);
891
- this.status = 409;
892
- }
893
- };
894
- __name(_ConflictException, "ConflictException");
895
- ConflictException = _ConflictException;
896
- _UpgradeRequiredException = class _UpgradeRequiredException extends ResponseException {
897
- constructor() {
898
- super(...arguments);
899
- this.status = 426;
900
- }
901
- };
902
- __name(_UpgradeRequiredException, "UpgradeRequiredException");
903
- UpgradeRequiredException = _UpgradeRequiredException;
904
- _TooManyRequestsException = class _TooManyRequestsException extends ResponseException {
905
- constructor() {
906
- super(...arguments);
907
- this.status = 429;
908
- }
909
- };
910
- __name(_TooManyRequestsException, "TooManyRequestsException");
911
- TooManyRequestsException = _TooManyRequestsException;
912
- _InternalServerException = class _InternalServerException extends ResponseException {
913
- constructor() {
914
- super(...arguments);
915
- this.status = 500;
916
- }
917
- };
918
- __name(_InternalServerException, "InternalServerException");
919
- InternalServerException = _InternalServerException;
920
- _NotImplementedException = class _NotImplementedException extends ResponseException {
921
- constructor() {
922
- super(...arguments);
923
- this.status = 501;
924
- }
925
- };
926
- __name(_NotImplementedException, "NotImplementedException");
927
- NotImplementedException = _NotImplementedException;
928
- _BadGatewayException = class _BadGatewayException extends ResponseException {
929
- constructor() {
930
- super(...arguments);
931
- this.status = 502;
932
- }
933
- };
934
- __name(_BadGatewayException, "BadGatewayException");
935
- BadGatewayException = _BadGatewayException;
936
- _ServiceUnavailableException = class _ServiceUnavailableException extends ResponseException {
937
- constructor() {
938
- super(...arguments);
939
- this.status = 503;
940
- }
941
- };
942
- __name(_ServiceUnavailableException, "ServiceUnavailableException");
943
- ServiceUnavailableException = _ServiceUnavailableException;
944
- _GatewayTimeoutException = class _GatewayTimeoutException extends ResponseException {
945
- constructor() {
946
- super(...arguments);
947
- this.status = 504;
948
- }
949
- };
950
- __name(_GatewayTimeoutException, "GatewayTimeoutException");
951
- GatewayTimeoutException = _GatewayTimeoutException;
952
- _HttpVersionNotSupportedException = class _HttpVersionNotSupportedException extends ResponseException {
953
- constructor() {
954
- super(...arguments);
955
- this.status = 505;
956
- }
957
- };
958
- __name(_HttpVersionNotSupportedException, "HttpVersionNotSupportedException");
959
- HttpVersionNotSupportedException = _HttpVersionNotSupportedException;
960
- _VariantAlsoNegotiatesException = class _VariantAlsoNegotiatesException extends ResponseException {
961
- constructor() {
962
- super(...arguments);
963
- this.status = 506;
964
- }
965
- };
966
- __name(_VariantAlsoNegotiatesException, "VariantAlsoNegotiatesException");
967
- VariantAlsoNegotiatesException = _VariantAlsoNegotiatesException;
968
- _InsufficientStorageException = class _InsufficientStorageException extends ResponseException {
969
- constructor() {
970
- super(...arguments);
971
- this.status = 507;
972
- }
973
- };
974
- __name(_InsufficientStorageException, "InsufficientStorageException");
975
- InsufficientStorageException = _InsufficientStorageException;
976
- _LoopDetectedException = class _LoopDetectedException extends ResponseException {
977
- constructor() {
978
- super(...arguments);
979
- this.status = 508;
980
- }
981
- };
982
- __name(_LoopDetectedException, "LoopDetectedException");
983
- LoopDetectedException = _LoopDetectedException;
984
- _NotExtendedException = class _NotExtendedException extends ResponseException {
985
- constructor() {
986
- super(...arguments);
987
- this.status = 510;
988
- }
989
- };
990
- __name(_NotExtendedException, "NotExtendedException");
991
- NotExtendedException = _NotExtendedException;
992
- _NetworkAuthenticationRequiredException = class _NetworkAuthenticationRequiredException extends ResponseException {
993
- constructor() {
994
- super(...arguments);
995
- this.status = 511;
996
- }
997
- };
998
- __name(_NetworkAuthenticationRequiredException, "NetworkAuthenticationRequiredException");
999
- NetworkAuthenticationRequiredException = _NetworkAuthenticationRequiredException;
1000
- _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException extends ResponseException {
1001
- constructor() {
1002
- super(...arguments);
1003
- this.status = 599;
1004
- }
1005
- };
1006
- __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
1007
- NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
912
+ var _ResponseException = class _ResponseException extends Error {
913
+ constructor(statusOrMessage, message) {
914
+ let statusCode;
915
+ if (typeof statusOrMessage === "number") {
916
+ statusCode = statusOrMessage;
917
+ } else if (typeof statusOrMessage === "string") {
918
+ message = statusOrMessage;
919
+ }
920
+ super(message ?? "");
921
+ this.status = 0;
922
+ if (statusCode !== void 0) {
923
+ this.status = statusCode;
924
+ }
925
+ this.name = this.constructor.name.replace(/([A-Z])/g, " $1");
926
+ }
927
+ };
928
+ __name(_ResponseException, "ResponseException");
929
+ var ResponseException = _ResponseException;
930
+ var _BadRequestException = class _BadRequestException extends ResponseException {
931
+ constructor() {
932
+ super(...arguments);
933
+ this.status = 400;
934
+ }
935
+ };
936
+ __name(_BadRequestException, "BadRequestException");
937
+ var BadRequestException = _BadRequestException;
938
+ var _UnauthorizedException = class _UnauthorizedException extends ResponseException {
939
+ constructor() {
940
+ super(...arguments);
941
+ this.status = 401;
942
+ }
943
+ };
944
+ __name(_UnauthorizedException, "UnauthorizedException");
945
+ var UnauthorizedException = _UnauthorizedException;
946
+ var _PaymentRequiredException = class _PaymentRequiredException extends ResponseException {
947
+ constructor() {
948
+ super(...arguments);
949
+ this.status = 402;
950
+ }
951
+ };
952
+ __name(_PaymentRequiredException, "PaymentRequiredException");
953
+ var PaymentRequiredException = _PaymentRequiredException;
954
+ var _ForbiddenException = class _ForbiddenException extends ResponseException {
955
+ constructor() {
956
+ super(...arguments);
957
+ this.status = 403;
958
+ }
959
+ };
960
+ __name(_ForbiddenException, "ForbiddenException");
961
+ var ForbiddenException = _ForbiddenException;
962
+ var _NotFoundException = class _NotFoundException extends ResponseException {
963
+ constructor() {
964
+ super(...arguments);
965
+ this.status = 404;
966
+ }
967
+ };
968
+ __name(_NotFoundException, "NotFoundException");
969
+ var NotFoundException = _NotFoundException;
970
+ var _MethodNotAllowedException = class _MethodNotAllowedException extends ResponseException {
971
+ constructor() {
972
+ super(...arguments);
973
+ this.status = 405;
1008
974
  }
1009
- });
975
+ };
976
+ __name(_MethodNotAllowedException, "MethodNotAllowedException");
977
+ var MethodNotAllowedException = _MethodNotAllowedException;
978
+ var _NotAcceptableException = class _NotAcceptableException extends ResponseException {
979
+ constructor() {
980
+ super(...arguments);
981
+ this.status = 406;
982
+ }
983
+ };
984
+ __name(_NotAcceptableException, "NotAcceptableException");
985
+ var NotAcceptableException = _NotAcceptableException;
986
+ var _RequestTimeoutException = class _RequestTimeoutException extends ResponseException {
987
+ constructor() {
988
+ super(...arguments);
989
+ this.status = 408;
990
+ }
991
+ };
992
+ __name(_RequestTimeoutException, "RequestTimeoutException");
993
+ var RequestTimeoutException = _RequestTimeoutException;
994
+ var _ConflictException = class _ConflictException extends ResponseException {
995
+ constructor() {
996
+ super(...arguments);
997
+ this.status = 409;
998
+ }
999
+ };
1000
+ __name(_ConflictException, "ConflictException");
1001
+ var ConflictException = _ConflictException;
1002
+ var _UpgradeRequiredException = class _UpgradeRequiredException extends ResponseException {
1003
+ constructor() {
1004
+ super(...arguments);
1005
+ this.status = 426;
1006
+ }
1007
+ };
1008
+ __name(_UpgradeRequiredException, "UpgradeRequiredException");
1009
+ var UpgradeRequiredException = _UpgradeRequiredException;
1010
+ var _TooManyRequestsException = class _TooManyRequestsException extends ResponseException {
1011
+ constructor() {
1012
+ super(...arguments);
1013
+ this.status = 429;
1014
+ }
1015
+ };
1016
+ __name(_TooManyRequestsException, "TooManyRequestsException");
1017
+ var TooManyRequestsException = _TooManyRequestsException;
1018
+ var _InternalServerException = class _InternalServerException extends ResponseException {
1019
+ constructor() {
1020
+ super(...arguments);
1021
+ this.status = 500;
1022
+ }
1023
+ };
1024
+ __name(_InternalServerException, "InternalServerException");
1025
+ var InternalServerException = _InternalServerException;
1026
+ var _NotImplementedException = class _NotImplementedException extends ResponseException {
1027
+ constructor() {
1028
+ super(...arguments);
1029
+ this.status = 501;
1030
+ }
1031
+ };
1032
+ __name(_NotImplementedException, "NotImplementedException");
1033
+ var NotImplementedException = _NotImplementedException;
1034
+ var _BadGatewayException = class _BadGatewayException extends ResponseException {
1035
+ constructor() {
1036
+ super(...arguments);
1037
+ this.status = 502;
1038
+ }
1039
+ };
1040
+ __name(_BadGatewayException, "BadGatewayException");
1041
+ var BadGatewayException = _BadGatewayException;
1042
+ var _ServiceUnavailableException = class _ServiceUnavailableException extends ResponseException {
1043
+ constructor() {
1044
+ super(...arguments);
1045
+ this.status = 503;
1046
+ }
1047
+ };
1048
+ __name(_ServiceUnavailableException, "ServiceUnavailableException");
1049
+ var ServiceUnavailableException = _ServiceUnavailableException;
1050
+ var _GatewayTimeoutException = class _GatewayTimeoutException extends ResponseException {
1051
+ constructor() {
1052
+ super(...arguments);
1053
+ this.status = 504;
1054
+ }
1055
+ };
1056
+ __name(_GatewayTimeoutException, "GatewayTimeoutException");
1057
+ var GatewayTimeoutException = _GatewayTimeoutException;
1058
+ var _HttpVersionNotSupportedException = class _HttpVersionNotSupportedException extends ResponseException {
1059
+ constructor() {
1060
+ super(...arguments);
1061
+ this.status = 505;
1062
+ }
1063
+ };
1064
+ __name(_HttpVersionNotSupportedException, "HttpVersionNotSupportedException");
1065
+ var HttpVersionNotSupportedException = _HttpVersionNotSupportedException;
1066
+ var _VariantAlsoNegotiatesException = class _VariantAlsoNegotiatesException extends ResponseException {
1067
+ constructor() {
1068
+ super(...arguments);
1069
+ this.status = 506;
1070
+ }
1071
+ };
1072
+ __name(_VariantAlsoNegotiatesException, "VariantAlsoNegotiatesException");
1073
+ var VariantAlsoNegotiatesException = _VariantAlsoNegotiatesException;
1074
+ var _InsufficientStorageException = class _InsufficientStorageException extends ResponseException {
1075
+ constructor() {
1076
+ super(...arguments);
1077
+ this.status = 507;
1078
+ }
1079
+ };
1080
+ __name(_InsufficientStorageException, "InsufficientStorageException");
1081
+ var InsufficientStorageException = _InsufficientStorageException;
1082
+ var _LoopDetectedException = class _LoopDetectedException extends ResponseException {
1083
+ constructor() {
1084
+ super(...arguments);
1085
+ this.status = 508;
1086
+ }
1087
+ };
1088
+ __name(_LoopDetectedException, "LoopDetectedException");
1089
+ var LoopDetectedException = _LoopDetectedException;
1090
+ var _NotExtendedException = class _NotExtendedException extends ResponseException {
1091
+ constructor() {
1092
+ super(...arguments);
1093
+ this.status = 510;
1094
+ }
1095
+ };
1096
+ __name(_NotExtendedException, "NotExtendedException");
1097
+ var NotExtendedException = _NotExtendedException;
1098
+ var _NetworkAuthenticationRequiredException = class _NetworkAuthenticationRequiredException extends ResponseException {
1099
+ constructor() {
1100
+ super(...arguments);
1101
+ this.status = 511;
1102
+ }
1103
+ };
1104
+ __name(_NetworkAuthenticationRequiredException, "NetworkAuthenticationRequiredException");
1105
+ var NetworkAuthenticationRequiredException = _NetworkAuthenticationRequiredException;
1106
+ var _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException extends ResponseException {
1107
+ constructor() {
1108
+ super(...arguments);
1109
+ this.status = 599;
1110
+ }
1111
+ };
1112
+ __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException");
1113
+ var NetworkConnectTimeoutException = _NetworkConnectTimeoutException;
1010
1114
 
1011
1115
  // src/internal/request.ts
1116
+ init_app_injector();
1117
+ var _Request = class _Request {
1118
+ constructor(event, senderId, id, method, path2, body, query) {
1119
+ this.event = event;
1120
+ this.senderId = senderId;
1121
+ this.id = id;
1122
+ this.method = method;
1123
+ this.path = path2;
1124
+ this.body = body;
1125
+ this.context = RootInjector.createScope();
1126
+ this.params = {};
1127
+ this.path = path2.replace(/^\/|\/$/g, "");
1128
+ this.query = query ?? {};
1129
+ }
1130
+ };
1131
+ __name(_Request, "Request");
1132
+ var Request = _Request;
1133
+ var RENDERER_EVENT_TYPE = "noxus:event";
1012
1134
  function createRendererEventMessage(event, payload) {
1013
1135
  return {
1014
1136
  type: RENDERER_EVENT_TYPE,
@@ -1016,6 +1138,7 @@ function createRendererEventMessage(event, payload) {
1016
1138
  payload
1017
1139
  };
1018
1140
  }
1141
+ __name(createRendererEventMessage, "createRendererEventMessage");
1019
1142
  function isRendererEventMessage(value) {
1020
1143
  if (value === null || typeof value !== "object") {
1021
1144
  return false;
@@ -1023,362 +1146,268 @@ function isRendererEventMessage(value) {
1023
1146
  const possibleMessage = value;
1024
1147
  return possibleMessage.type === RENDERER_EVENT_TYPE && typeof possibleMessage.event === "string";
1025
1148
  }
1026
- var _Request, Request, RENDERER_EVENT_TYPE;
1027
- var init_request = __esm({
1028
- "src/internal/request.ts"() {
1029
- "use strict";
1030
- init_app_injector();
1031
- _Request = class _Request {
1032
- constructor(event, senderId, id, method, path2, body) {
1033
- this.event = event;
1034
- this.senderId = senderId;
1035
- this.id = id;
1036
- this.method = method;
1037
- this.path = path2;
1038
- this.body = body;
1039
- this.context = RootInjector.createScope();
1040
- this.params = {};
1041
- this.path = path2.replace(/^\/|\/$/g, "");
1042
- }
1043
- };
1044
- __name(_Request, "Request");
1045
- Request = _Request;
1046
- RENDERER_EVENT_TYPE = "noxus:event";
1047
- __name(createRendererEventMessage, "createRendererEventMessage");
1048
- __name(isRendererEventMessage, "isRendererEventMessage");
1049
- }
1050
- });
1149
+ __name(isRendererEventMessage, "isRendererEventMessage");
1051
1150
 
1052
1151
  // src/internal/router.ts
1053
- var router_exports = {};
1054
- __export(router_exports, {
1055
- Router: () => Router
1056
- });
1057
- var Router;
1058
- var init_router = __esm({
1059
- "src/internal/router.ts"() {
1060
- "use strict";
1061
- init_controller_decorator();
1062
- init_injectable_decorator();
1063
- init_method_decorator();
1064
- init_injector_explorer();
1065
- init_logger();
1066
- init_radix_tree();
1067
- init_exceptions();
1068
- init_request();
1069
- Router = class {
1070
- constructor() {
1071
- this.routes = new RadixTree();
1072
- this.rootMiddlewares = [];
1073
- this.lazyRoutes = /* @__PURE__ */ new Map();
1074
- }
1075
- // -------------------------------------------------------------------------
1076
- // Registration
1077
- // -------------------------------------------------------------------------
1078
- registerController(controllerClass, pathPrefix, routeGuards = [], routeMiddlewares = []) {
1079
- const meta = getControllerMetadata(controllerClass);
1080
- if (!meta) {
1081
- throw new Error(`[Noxus] Missing @Controller decorator on ${controllerClass.name}`);
1082
- }
1083
- const routeMeta = getRouteMetadata(controllerClass);
1084
- for (const def of routeMeta) {
1085
- const fullPath = `${pathPrefix}/${def.path}`.replace(/\/+/g, "/").replace(/\/$/, "") || "/";
1086
- const guards = [.../* @__PURE__ */ new Set([...routeGuards, ...def.guards])];
1087
- const middlewares = [.../* @__PURE__ */ new Set([...routeMiddlewares, ...def.middlewares])];
1088
- const routeDef = {
1089
- method: def.method,
1090
- path: fullPath,
1091
- controller: controllerClass,
1092
- handler: def.handler,
1093
- guards,
1094
- middlewares
1095
- };
1096
- this.routes.insert(fullPath + "/" + def.method, routeDef);
1097
- const guardInfo = guards.length ? `<${guards.map((g) => g.name).join("|")}>` : "";
1098
- Logger.log(`Mapped {${def.method} /${fullPath}}${guardInfo} route`);
1099
- }
1100
- const ctrlGuardInfo = routeGuards.length ? `<${routeGuards.map((g) => g.name).join("|")}>` : "";
1101
- Logger.log(`Mapped ${controllerClass.name}${ctrlGuardInfo} controller's routes`);
1102
- return this;
1103
- }
1104
- registerLazyRoute(pathPrefix, load, guards = [], middlewares = []) {
1105
- const normalized = pathPrefix.replace(/^\/+|\/+$/g, "");
1106
- this.lazyRoutes.set(normalized, { load, guards, middlewares, loading: null, loaded: false });
1107
- Logger.log(`Registered lazy route prefix {${normalized}}`);
1108
- return this;
1109
- }
1110
- defineRootMiddleware(middleware) {
1111
- this.rootMiddlewares.push(middleware);
1112
- return this;
1113
- }
1114
- // -------------------------------------------------------------------------
1115
- // Request handling
1116
- // -------------------------------------------------------------------------
1117
- async handle(request) {
1118
- return request.method === "BATCH" ? this.handleBatch(request) : this.handleAtomic(request);
1119
- }
1120
- async handleAtomic(request) {
1121
- Logger.comment(`> ${request.method} /${request.path}`);
1122
- const t0 = performance.now();
1123
- const response = { requestId: request.id, status: 200, body: null };
1124
- let isCritical = false;
1125
- try {
1126
- const routeDef = await this.findRoute(request);
1127
- await this.resolveController(request, response, routeDef);
1128
- if (response.status >= 400) throw new ResponseException(response.status, response.error);
1129
- } catch (error) {
1130
- this.fillErrorResponse(response, error, (c) => {
1131
- isCritical = c;
1132
- });
1133
- } finally {
1134
- this.logResponse(request, response, performance.now() - t0, isCritical);
1135
- return response;
1136
- }
1137
- }
1138
- async handleBatch(request) {
1139
- Logger.comment(`> ${request.method} /${request.path}`);
1140
- const t0 = performance.now();
1141
- const response = {
1142
- requestId: request.id,
1143
- status: 200,
1144
- body: { responses: [] }
1145
- };
1146
- let isCritical = false;
1147
- try {
1148
- const payload = this.normalizeBatchPayload(request.body);
1149
- response.body.responses = await Promise.all(
1150
- payload.requests.map((item, i) => {
1151
- const id = item.requestId ?? `${request.id}:${i}`;
1152
- return this.handleAtomic(new Request(request.event, request.senderId, id, item.method, item.path, item.body));
1153
- })
1154
- );
1155
- } catch (error) {
1156
- this.fillErrorResponse(response, error, (c) => {
1157
- isCritical = c;
1158
- });
1159
- } finally {
1160
- this.logResponse(request, response, performance.now() - t0, isCritical);
1161
- return response;
1162
- }
1163
- }
1164
- // -------------------------------------------------------------------------
1165
- // Route resolution
1166
- // -------------------------------------------------------------------------
1167
- tryFindRoute(request) {
1168
- const matched = this.routes.search(request.path);
1169
- if (!matched?.node || matched.node.children.length === 0) return void 0;
1170
- return matched.node.findExactChild(request.method)?.value;
1171
- }
1172
- async findRoute(request) {
1173
- const direct = this.tryFindRoute(request);
1174
- if (direct) return direct;
1175
- await this.tryLoadLazyRoute(request.path);
1176
- const afterLazy = this.tryFindRoute(request);
1177
- if (afterLazy) return afterLazy;
1178
- throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1179
- }
1180
- async tryLoadLazyRoute(requestPath) {
1181
- const firstSegment = requestPath.replace(/^\/+/, "").split("/")[0] ?? "";
1182
- for (const [prefix, entry] of this.lazyRoutes) {
1183
- if (entry.loaded) continue;
1184
- const normalized = requestPath.replace(/^\/+/, "");
1185
- if (normalized === prefix || normalized.startsWith(prefix + "/") || firstSegment === prefix) {
1186
- if (!entry.loading) entry.loading = this.loadLazyModule(prefix, entry);
1187
- await entry.loading;
1188
- return;
1189
- }
1190
- }
1191
- }
1192
- async loadLazyModule(prefix, entry) {
1193
- const t0 = performance.now();
1194
- InjectorExplorer.beginAccumulate();
1195
- await entry.load?.();
1196
- entry.loading = null;
1197
- entry.load = null;
1198
- InjectorExplorer.flushAccumulated(entry.guards, entry.middlewares, prefix);
1199
- entry.loaded = true;
1200
- Logger.info(`Lazy-loaded module for prefix {${prefix}} in ${Math.round(performance.now() - t0)}ms`);
1201
- }
1202
- // -------------------------------------------------------------------------
1203
- // Pipeline
1204
- // -------------------------------------------------------------------------
1205
- async resolveController(request, response, routeDef) {
1206
- const instance = request.context.resolve(routeDef.controller);
1207
- Object.assign(request.params, this.extractParams(request.path, routeDef.path));
1208
- await this.runPipeline(request, response, routeDef, instance);
1209
- }
1210
- async runPipeline(request, response, routeDef, controllerInstance) {
1211
- const middlewares = [.../* @__PURE__ */ new Set([...this.rootMiddlewares, ...routeDef.middlewares])];
1212
- const mwMax = middlewares.length - 1;
1213
- const guardMax = mwMax + routeDef.guards.length;
1214
- let index = -1;
1215
- const dispatch = /* @__PURE__ */ __name(async (i) => {
1216
- if (i <= index) throw new Error("next() called multiple times");
1217
- index = i;
1218
- if (i <= mwMax) {
1219
- await this.runMiddleware(request, response, dispatch.bind(null, i + 1), middlewares[i]);
1220
- if (response.status >= 400) throw new ResponseException(response.status, response.error);
1221
- return;
1222
- }
1223
- if (i <= guardMax) {
1224
- await this.runGuard(request, routeDef.guards[i - middlewares.length]);
1225
- await dispatch(i + 1);
1226
- return;
1227
- }
1228
- const action = controllerInstance[routeDef.handler];
1229
- response.body = await action.call(controllerInstance, request, response);
1230
- if (response.body === void 0) response.body = {};
1231
- }, "dispatch");
1232
- await dispatch(0);
1233
- }
1234
- async runMiddleware(request, response, next, middleware) {
1235
- await middleware(request, response, next);
1236
- }
1237
- async runGuard(request, guard) {
1238
- if (!await guard(request)) {
1239
- throw new UnauthorizedException(`Unauthorized for ${request.method} ${request.path}`);
1240
- }
1241
- }
1242
- // -------------------------------------------------------------------------
1243
- // Utilities
1244
- // -------------------------------------------------------------------------
1245
- extractParams(actual, template) {
1246
- const aParts = actual.split("/");
1247
- const tParts = template.split("/");
1248
- const params = {};
1249
- tParts.forEach((part, i) => {
1250
- if (part.startsWith(":")) params[part.slice(1)] = aParts[i] ?? "";
1251
- });
1252
- return params;
1253
- }
1254
- normalizeBatchPayload(body) {
1255
- if (body === null || typeof body !== "object") {
1256
- throw new BadRequestException("Batch payload must be an object containing a requests array.");
1257
- }
1258
- const { requests } = body;
1259
- if (!Array.isArray(requests)) throw new BadRequestException("Batch payload must define a requests array.");
1260
- return { requests: requests.map((e, i) => this.normalizeBatchItem(e, i)) };
1261
- }
1262
- normalizeBatchItem(entry, index) {
1263
- if (entry === null || typeof entry !== "object") throw new BadRequestException(`Batch request at index ${index} must be an object.`);
1264
- const { requestId, path: path2, method, body } = entry;
1265
- if (requestId !== void 0 && typeof requestId !== "string") throw new BadRequestException(`Batch request at index ${index} has an invalid requestId.`);
1266
- if (typeof path2 !== "string" || !path2.length) throw new BadRequestException(`Batch request at index ${index} must define a non-empty path.`);
1267
- if (typeof method !== "string") throw new BadRequestException(`Batch request at index ${index} must define an HTTP method.`);
1268
- const normalized = method.toUpperCase();
1269
- if (!isAtomicHttpMethod(normalized)) throw new BadRequestException(`Batch request at index ${index} uses unsupported method ${method}.`);
1270
- return { requestId, path: path2, method: normalized, body };
1152
+ var Router = class {
1153
+ constructor() {
1154
+ this.routes = new RadixTree();
1155
+ this.rootMiddlewares = [];
1156
+ this.lazyRoutes = /* @__PURE__ */ new Map();
1157
+ }
1158
+ // -------------------------------------------------------------------------
1159
+ // Registration
1160
+ // -------------------------------------------------------------------------
1161
+ registerController(controllerClass, pathPrefix, routeGuards = [], routeMiddlewares = []) {
1162
+ const meta = getControllerMetadata(controllerClass);
1163
+ if (!meta) {
1164
+ throw new Error(`[Noxus] Missing @Controller decorator on ${controllerClass.name}`);
1165
+ }
1166
+ const routeMeta = getRouteMetadata(controllerClass);
1167
+ for (const def of routeMeta) {
1168
+ const fullPath = `${pathPrefix}/${def.path}`.replace(/\/+/g, "/").replace(/\/$/, "") || "/";
1169
+ const guards = [.../* @__PURE__ */ new Set([...routeGuards, ...def.guards])];
1170
+ const middlewares = [.../* @__PURE__ */ new Set([...routeMiddlewares, ...def.middlewares])];
1171
+ const routeDef = {
1172
+ method: def.method,
1173
+ path: fullPath,
1174
+ controller: controllerClass,
1175
+ handler: def.handler,
1176
+ guards,
1177
+ middlewares
1178
+ };
1179
+ this.routes.insert(fullPath + "/" + def.method, routeDef);
1180
+ const guardInfo = guards.length ? `<${guards.map((g) => g.name).join("|")}>` : "";
1181
+ Logger.log(`Mapped {${def.method} /${fullPath}}${guardInfo} route`);
1182
+ }
1183
+ const ctrlGuardInfo = routeGuards.length ? `<${routeGuards.map((g) => g.name).join("|")}>` : "";
1184
+ Logger.log(`Mapped ${controllerClass.name}${ctrlGuardInfo} controller's routes`);
1185
+ return this;
1186
+ }
1187
+ registerLazyRoute(pathPrefix, load, guards = [], middlewares = []) {
1188
+ const normalized = pathPrefix.replace(/^\/+|\/+$/g, "");
1189
+ this.lazyRoutes.set(normalized, { load, guards, middlewares, loading: null, loaded: false });
1190
+ Logger.log(`Registered lazy route prefix {${normalized}}`);
1191
+ return this;
1192
+ }
1193
+ defineRootMiddleware(middleware) {
1194
+ this.rootMiddlewares.push(middleware);
1195
+ return this;
1196
+ }
1197
+ getRegisteredRoutes() {
1198
+ const allRoutes = this.routes.collectValues();
1199
+ return allRoutes.map((r) => ({ method: r.method, path: r.path }));
1200
+ }
1201
+ getLazyRoutes() {
1202
+ return [...this.lazyRoutes.entries()].map(([prefix, entry]) => ({
1203
+ prefix,
1204
+ loaded: entry.loaded
1205
+ }));
1206
+ }
1207
+ // -------------------------------------------------------------------------
1208
+ // Request handling
1209
+ // -------------------------------------------------------------------------
1210
+ async handle(request) {
1211
+ return request.method === "BATCH" ? this.handleBatch(request) : this.handleAtomic(request);
1212
+ }
1213
+ async handleAtomic(request) {
1214
+ Logger.comment(`> ${request.method} /${request.path}`);
1215
+ const t0 = performance.now();
1216
+ const response = { requestId: request.id, status: 200, body: null };
1217
+ let isCritical = false;
1218
+ try {
1219
+ const routeDef = await this.findRoute(request);
1220
+ await this.resolveController(request, response, routeDef);
1221
+ if (response.status >= 400) throw new ResponseException(response.status, response.error);
1222
+ } catch (error) {
1223
+ this.fillErrorResponse(response, error, (c) => {
1224
+ isCritical = c;
1225
+ });
1226
+ } finally {
1227
+ this.logResponse(request, response, performance.now() - t0, isCritical);
1228
+ return response;
1229
+ }
1230
+ }
1231
+ async handleBatch(request) {
1232
+ Logger.comment(`> ${request.method} /${request.path}`);
1233
+ const t0 = performance.now();
1234
+ const response = {
1235
+ requestId: request.id,
1236
+ status: 200,
1237
+ body: { responses: [] }
1238
+ };
1239
+ let isCritical = false;
1240
+ try {
1241
+ const payload = this.normalizeBatchPayload(request.body);
1242
+ response.body.responses = await Promise.all(
1243
+ payload.requests.map((item, i) => {
1244
+ const id = item.requestId ?? `${request.id}:${i}`;
1245
+ return this.handleAtomic(new Request(request.event, request.senderId, id, item.method, item.path, item.body, item.query));
1246
+ })
1247
+ );
1248
+ } catch (error) {
1249
+ this.fillErrorResponse(response, error, (c) => {
1250
+ isCritical = c;
1251
+ });
1252
+ } finally {
1253
+ this.logResponse(request, response, performance.now() - t0, isCritical);
1254
+ return response;
1255
+ }
1256
+ }
1257
+ // -------------------------------------------------------------------------
1258
+ // Route resolution
1259
+ // -------------------------------------------------------------------------
1260
+ tryFindRoute(request) {
1261
+ const matched = this.routes.search(request.path);
1262
+ if (!matched?.node || matched.node.children.length === 0) return void 0;
1263
+ return matched.node.findExactChild(request.method)?.value;
1264
+ }
1265
+ async findRoute(request) {
1266
+ const direct = this.tryFindRoute(request);
1267
+ if (direct) return direct;
1268
+ await this.tryLoadLazyRoute(request.path);
1269
+ const afterLazy = this.tryFindRoute(request);
1270
+ if (afterLazy) return afterLazy;
1271
+ throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1272
+ }
1273
+ async tryLoadLazyRoute(requestPath) {
1274
+ const firstSegment = requestPath.replace(/^\/+/, "").split("/")[0] ?? "";
1275
+ for (const [prefix, entry] of this.lazyRoutes) {
1276
+ if (entry.loaded) continue;
1277
+ const normalized = requestPath.replace(/^\/+/, "");
1278
+ if (normalized === prefix || normalized.startsWith(prefix + "/") || firstSegment === prefix) {
1279
+ if (!entry.loading) entry.loading = this.loadLazyModule(prefix, entry);
1280
+ await entry.loading;
1281
+ return;
1271
1282
  }
1272
- fillErrorResponse(response, error, setCritical) {
1273
- response.body = void 0;
1274
- if (error instanceof ResponseException) {
1275
- response.status = error.status;
1276
- response.error = error.message;
1277
- response.stack = error.stack;
1278
- } else if (error instanceof Error) {
1279
- setCritical(true);
1280
- response.status = 500;
1281
- response.error = error.message || "Internal Server Error";
1282
- response.stack = error.stack;
1283
- } else {
1284
- setCritical(true);
1285
- response.status = 500;
1286
- response.error = "Unknown error occurred";
1287
- }
1283
+ }
1284
+ }
1285
+ async loadLazyModule(prefix, entry) {
1286
+ const t0 = performance.now();
1287
+ InjectorExplorer.beginAccumulate();
1288
+ await entry.load?.();
1289
+ entry.loading = null;
1290
+ entry.load = null;
1291
+ await InjectorExplorer.flushAccumulated(entry.guards, entry.middlewares, prefix);
1292
+ entry.loaded = true;
1293
+ Logger.info(`Lazy-loaded module for prefix {${prefix}} in ${Math.round(performance.now() - t0)}ms`);
1294
+ }
1295
+ // -------------------------------------------------------------------------
1296
+ // Pipeline
1297
+ // -------------------------------------------------------------------------
1298
+ async resolveController(request, response, routeDef) {
1299
+ const instance = request.context.resolve(routeDef.controller);
1300
+ Object.assign(request.params, this.extractParams(request.path, routeDef.path));
1301
+ await this.runPipeline(request, response, routeDef, instance);
1302
+ }
1303
+ async runPipeline(request, response, routeDef, controllerInstance) {
1304
+ const middlewares = [.../* @__PURE__ */ new Set([...this.rootMiddlewares, ...routeDef.middlewares])];
1305
+ const mwMax = middlewares.length - 1;
1306
+ const guardMax = mwMax + routeDef.guards.length;
1307
+ let index = -1;
1308
+ const dispatch = /* @__PURE__ */ __name(async (i) => {
1309
+ if (i <= index) throw new Error("next() called multiple times");
1310
+ index = i;
1311
+ if (i <= mwMax) {
1312
+ await this.runMiddleware(request, response, dispatch.bind(null, i + 1), middlewares[i]);
1313
+ if (response.status >= 400) throw new ResponseException(response.status, response.error);
1314
+ return;
1288
1315
  }
1289
- logResponse(request, response, ms, isCritical) {
1290
- const msg = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(ms)}ms${Logger.colors.initial}`;
1291
- if (response.status < 400) Logger.log(msg);
1292
- else if (response.status < 500) Logger.warn(msg);
1293
- else isCritical ? Logger.critical(msg) : Logger.error(msg);
1294
- if (response.error) {
1295
- isCritical ? Logger.critical(response.error) : Logger.error(response.error);
1296
- if (response.stack) Logger.errorStack(response.stack);
1297
- }
1316
+ if (i <= guardMax) {
1317
+ await this.runGuard(request, routeDef.guards[i - middlewares.length]);
1318
+ await dispatch(i + 1);
1319
+ return;
1298
1320
  }
1299
- };
1300
- __name(Router, "Router");
1301
- Router = __decorateClass([
1302
- Injectable({ lifetime: "singleton" })
1303
- ], Router);
1321
+ const action = controllerInstance[routeDef.handler];
1322
+ response.body = await action.call(controllerInstance, request, response);
1323
+ if (response.body === void 0) response.body = {};
1324
+ }, "dispatch");
1325
+ await dispatch(0);
1304
1326
  }
1305
- });
1306
-
1307
- // src/main.ts
1308
- var main_exports = {};
1309
- __export(main_exports, {
1310
- AppInjector: () => AppInjector,
1311
- BadGatewayException: () => BadGatewayException,
1312
- BadRequestException: () => BadRequestException,
1313
- ConflictException: () => ConflictException,
1314
- Controller: () => Controller,
1315
- Delete: () => Delete,
1316
- ForbiddenException: () => ForbiddenException,
1317
- ForwardReference: () => ForwardReference,
1318
- GatewayTimeoutException: () => GatewayTimeoutException,
1319
- Get: () => Get,
1320
- HttpVersionNotSupportedException: () => HttpVersionNotSupportedException,
1321
- Injectable: () => Injectable,
1322
- InsufficientStorageException: () => InsufficientStorageException,
1323
- InternalServerException: () => InternalServerException,
1324
- Logger: () => Logger,
1325
- LoopDetectedException: () => LoopDetectedException,
1326
- MethodNotAllowedException: () => MethodNotAllowedException,
1327
- NetworkAuthenticationRequiredException: () => NetworkAuthenticationRequiredException,
1328
- NetworkConnectTimeoutException: () => NetworkConnectTimeoutException,
1329
- NotAcceptableException: () => NotAcceptableException,
1330
- NotExtendedException: () => NotExtendedException,
1331
- NotFoundException: () => NotFoundException,
1332
- NotImplementedException: () => NotImplementedException,
1333
- NoxApp: () => NoxApp,
1334
- NoxSocket: () => NoxSocket,
1335
- Patch: () => Patch,
1336
- PaymentRequiredException: () => PaymentRequiredException,
1337
- Post: () => Post,
1338
- Put: () => Put,
1339
- RENDERER_EVENT_TYPE: () => RENDERER_EVENT_TYPE,
1340
- Request: () => Request,
1341
- RequestTimeoutException: () => RequestTimeoutException,
1342
- ResponseException: () => ResponseException,
1343
- RootInjector: () => RootInjector,
1344
- Router: () => Router,
1345
- ServiceUnavailableException: () => ServiceUnavailableException,
1346
- Token: () => Token,
1347
- TooManyRequestsException: () => TooManyRequestsException,
1348
- UnauthorizedException: () => UnauthorizedException,
1349
- UpgradeRequiredException: () => UpgradeRequiredException,
1350
- VariantAlsoNegotiatesException: () => VariantAlsoNegotiatesException,
1351
- WindowManager: () => WindowManager,
1352
- bootstrapApplication: () => bootstrapApplication,
1353
- createRendererEventMessage: () => createRendererEventMessage,
1354
- defineRoutes: () => defineRoutes,
1355
- forwardRef: () => forwardRef,
1356
- getControllerMetadata: () => getControllerMetadata,
1357
- getRouteMetadata: () => getRouteMetadata,
1358
- inject: () => inject,
1359
- isAtomicHttpMethod: () => isAtomicHttpMethod,
1360
- isRendererEventMessage: () => isRendererEventMessage,
1361
- token: () => token
1362
- });
1363
- module.exports = __toCommonJS(main_exports);
1364
- init_app_injector();
1365
- init_token();
1366
- init_router();
1327
+ async runMiddleware(request, response, next, middleware) {
1328
+ await middleware(request, response, next);
1329
+ }
1330
+ async runGuard(request, guard) {
1331
+ if (!await guard(request)) {
1332
+ throw new UnauthorizedException(`Unauthorized for ${request.method} ${request.path}`);
1333
+ }
1334
+ }
1335
+ // -------------------------------------------------------------------------
1336
+ // Utilities
1337
+ // -------------------------------------------------------------------------
1338
+ extractParams(actual, template) {
1339
+ const aParts = actual.split("/");
1340
+ const tParts = template.split("/");
1341
+ const params = {};
1342
+ tParts.forEach((part, i) => {
1343
+ if (part.startsWith(":")) params[part.slice(1)] = aParts[i] ?? "";
1344
+ });
1345
+ return params;
1346
+ }
1347
+ normalizeBatchPayload(body) {
1348
+ if (body === null || typeof body !== "object") {
1349
+ throw new BadRequestException("Batch payload must be an object containing a requests array.");
1350
+ }
1351
+ const { requests } = body;
1352
+ if (!Array.isArray(requests)) throw new BadRequestException("Batch payload must define a requests array.");
1353
+ return { requests: requests.map((e, i) => this.normalizeBatchItem(e, i)) };
1354
+ }
1355
+ normalizeBatchItem(entry, index) {
1356
+ if (entry === null || typeof entry !== "object") throw new BadRequestException(`Batch request at index ${index} must be an object.`);
1357
+ const { requestId, path: path2, method, body } = entry;
1358
+ if (requestId !== void 0 && typeof requestId !== "string") throw new BadRequestException(`Batch request at index ${index} has an invalid requestId.`);
1359
+ if (typeof path2 !== "string" || !path2.length) throw new BadRequestException(`Batch request at index ${index} must define a non-empty path.`);
1360
+ if (typeof method !== "string") throw new BadRequestException(`Batch request at index ${index} must define an HTTP method.`);
1361
+ const normalized = method.toUpperCase();
1362
+ if (!isAtomicHttpMethod(normalized)) throw new BadRequestException(`Batch request at index ${index} uses unsupported method ${method}.`);
1363
+ return { requestId, path: path2, method: normalized, body };
1364
+ }
1365
+ fillErrorResponse(response, error, setCritical) {
1366
+ response.body = void 0;
1367
+ if (error instanceof ResponseException) {
1368
+ response.status = error.status;
1369
+ response.error = error.message;
1370
+ response.stack = error.stack;
1371
+ } else if (error instanceof Error) {
1372
+ setCritical(true);
1373
+ response.status = 500;
1374
+ response.error = error.message || "Internal Server Error";
1375
+ response.stack = error.stack;
1376
+ } else {
1377
+ setCritical(true);
1378
+ response.status = 500;
1379
+ response.error = "Unknown error occurred";
1380
+ }
1381
+ }
1382
+ logResponse(request, response, ms, isCritical) {
1383
+ const msg = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(ms)}ms${Logger.colors.initial}`;
1384
+ if (response.status < 400) Logger.log(msg);
1385
+ else if (response.status < 500) Logger.warn(msg);
1386
+ else isCritical ? Logger.critical(msg) : Logger.error(msg);
1387
+ if (response.error) {
1388
+ isCritical ? Logger.critical(response.error) : Logger.error(response.error);
1389
+ if (response.stack) Logger.errorStack(response.stack);
1390
+ }
1391
+ }
1392
+ };
1393
+ __name(Router, "Router");
1394
+ Router = __decorateClass([
1395
+ Injectable({ lifetime: "singleton" })
1396
+ ], Router);
1367
1397
 
1368
1398
  // src/internal/app.ts
1369
1399
  var import_main2 = require("electron/main");
1370
- init_injectable_decorator();
1371
1400
  init_app_injector();
1372
1401
  init_injector_explorer();
1373
1402
  init_logger();
1374
1403
 
1375
1404
  // src/window/window-manager.ts
1376
1405
  var import_main = require("electron/main");
1377
- init_injectable_decorator();
1378
1406
  init_logger();
1379
1407
  var WindowManager = class {
1380
1408
  constructor() {
1381
1409
  this._windows = /* @__PURE__ */ new Map();
1410
+ this.listeners = /* @__PURE__ */ new Map();
1382
1411
  }
1383
1412
  // -------------------------------------------------------------------------
1384
1413
  // Creation
@@ -1428,18 +1457,24 @@ var WindowManager = class {
1428
1457
  * win.loadFile('index.html');
1429
1458
  */
1430
1459
  async createSplash(options = {}) {
1431
- const { animationDuration = 600, ...bwOptions } = options;
1460
+ const {
1461
+ animationDuration = 10,
1462
+ expandToWorkArea = true,
1463
+ ...bwOptions
1464
+ } = options;
1432
1465
  const win = new import_main.BrowserWindow({
1433
1466
  width: 600,
1434
1467
  height: 600,
1435
1468
  center: true,
1436
- frame: false,
1437
1469
  show: true,
1438
1470
  ...bwOptions
1439
1471
  });
1440
1472
  this._register(win, true);
1441
1473
  Logger.log(`[WindowManager] Splash window #${win.id} created`);
1442
- await this._expandToWorkArea(win, animationDuration);
1474
+ if (expandToWorkArea) {
1475
+ await (() => new Promise((r) => setTimeout(r, 500)))();
1476
+ await this._expandToWorkArea(win, animationDuration);
1477
+ }
1443
1478
  return win;
1444
1479
  }
1445
1480
  // -------------------------------------------------------------------------
@@ -1498,10 +1533,24 @@ var WindowManager = class {
1498
1533
  */
1499
1534
  broadcast(channel, ...args) {
1500
1535
  for (const win of this._windows.values()) {
1501
- if (!win.isDestroyed()) win.webContents.send(channel, ...args);
1536
+ if (!win.isDestroyed()) {
1537
+ win.webContents.send(channel, ...args);
1538
+ }
1502
1539
  }
1503
1540
  }
1504
1541
  // -------------------------------------------------------------------------
1542
+ // Events
1543
+ // -------------------------------------------------------------------------
1544
+ on(event, handler) {
1545
+ const set = this.listeners.get(event) ?? /* @__PURE__ */ new Set();
1546
+ set.add(handler);
1547
+ this.listeners.set(event, set);
1548
+ return () => set.delete(handler);
1549
+ }
1550
+ _emit(event, win) {
1551
+ this.listeners.get(event)?.forEach((h) => h(win));
1552
+ }
1553
+ // -------------------------------------------------------------------------
1505
1554
  // Private
1506
1555
  // -------------------------------------------------------------------------
1507
1556
  _register(win, isMain) {
@@ -1509,10 +1558,16 @@ var WindowManager = class {
1509
1558
  if (isMain && this._mainWindowId === void 0) {
1510
1559
  this._mainWindowId = win.id;
1511
1560
  }
1561
+ this._emit("created", win);
1562
+ win.on("focus", () => this._emit("focused", win));
1563
+ win.on("blur", () => this._emit("blurred", win));
1512
1564
  win.once("closed", () => {
1513
1565
  this._windows.delete(win.id);
1514
- if (this._mainWindowId === win.id) this._mainWindowId = void 0;
1566
+ if (this._mainWindowId === win.id) {
1567
+ this._mainWindowId = void 0;
1568
+ }
1515
1569
  Logger.log(`[WindowManager] Window #${win.id} closed`);
1570
+ this._emit("closed", win);
1516
1571
  });
1517
1572
  }
1518
1573
  /**
@@ -1522,17 +1577,18 @@ var WindowManager = class {
1522
1577
  */
1523
1578
  _expandToWorkArea(win, animationDuration) {
1524
1579
  return new Promise((resolve) => {
1525
- const { x, y, width, height } = import_main.screen.getPrimaryDisplay().workArea;
1526
- win.setBounds({ x, y, width, height }, true);
1580
+ win.maximize();
1527
1581
  let resolved = false;
1528
1582
  const done = /* @__PURE__ */ __name(() => {
1529
- if (resolved) return;
1583
+ if (resolved) {
1584
+ return;
1585
+ }
1530
1586
  resolved = true;
1531
1587
  win.removeListener("resize", done);
1532
1588
  resolve();
1533
1589
  }, "done");
1534
1590
  win.once("resize", done);
1535
- setTimeout(done, animationDuration + 100);
1591
+ setTimeout(done, animationDuration);
1536
1592
  });
1537
1593
  }
1538
1594
  };
@@ -1541,14 +1597,8 @@ WindowManager = __decorateClass([
1541
1597
  Injectable({ lifetime: "singleton" })
1542
1598
  ], WindowManager);
1543
1599
 
1544
- // src/internal/app.ts
1545
- init_request();
1546
- init_router();
1547
-
1548
1600
  // src/internal/socket.ts
1549
- init_injectable_decorator();
1550
1601
  init_logger();
1551
- init_request();
1552
1602
  var NoxSocket = class {
1553
1603
  constructor() {
1554
1604
  this.channels = /* @__PURE__ */ new Map();
@@ -1571,7 +1621,6 @@ var NoxSocket = class {
1571
1621
  throw new Error("Renderer event name must be a non-empty string.");
1572
1622
  }
1573
1623
  const recipients = targetSenderIds ?? this.getSenderIds();
1574
- let delivered = 0;
1575
1624
  for (const senderId of recipients) {
1576
1625
  const channel = this.channels.get(senderId);
1577
1626
  if (!channel) {
@@ -1580,15 +1629,17 @@ var NoxSocket = class {
1580
1629
  }
1581
1630
  try {
1582
1631
  channel.socket.port1.postMessage(createRendererEventMessage(normalizedEvent, payload));
1583
- delivered++;
1584
1632
  } catch (error) {
1585
1633
  Logger.error(`[Noxus] Failed to emit "${normalizedEvent}" to sender ${senderId}.`, error);
1586
1634
  }
1587
1635
  }
1588
- return delivered;
1589
1636
  }
1590
1637
  emitToRenderer(senderId, eventName, payload) {
1591
- return this.emit(eventName, payload, [senderId]) > 0;
1638
+ if (!this.channels.has(senderId)) {
1639
+ return false;
1640
+ }
1641
+ this.emit(eventName, payload, [senderId]);
1642
+ return true;
1592
1643
  }
1593
1644
  };
1594
1645
  __name(NoxSocket, "NoxSocket");
@@ -1598,22 +1649,22 @@ NoxSocket = __decorateClass([
1598
1649
 
1599
1650
  // src/internal/app.ts
1600
1651
  var NoxApp = class {
1601
- constructor() {
1602
- this.router = inject(Router);
1603
- this.socket = inject(NoxSocket);
1604
- this.windowManager = inject(WindowManager);
1652
+ constructor(router, socket, windowManager) {
1653
+ this.router = router;
1654
+ this.socket = socket;
1655
+ this.windowManager = windowManager;
1605
1656
  // -------------------------------------------------------------------------
1606
1657
  // IPC
1607
1658
  // -------------------------------------------------------------------------
1608
1659
  this.onRendererMessage = /* @__PURE__ */ __name(async (event) => {
1609
- const { senderId, requestId, path: path2, method, body } = event.data;
1660
+ const { senderId, requestId, path: path2, method, body, query } = event.data;
1610
1661
  const channels = this.socket.get(senderId);
1611
1662
  if (!channels) {
1612
1663
  Logger.error(`No message channel found for sender ID: ${senderId}`);
1613
1664
  return;
1614
1665
  }
1615
1666
  try {
1616
- const request = new Request(event, senderId, requestId, method, path2, body);
1667
+ const request = new Request(event, senderId, requestId, method, path2, body, query);
1617
1668
  const response = await this.router.handle(request);
1618
1669
  channels.request.port1.postMessage(response);
1619
1670
  } catch (err) {
@@ -1664,7 +1715,7 @@ var NoxApp = class {
1664
1715
  async load(importFns) {
1665
1716
  InjectorExplorer.beginAccumulate();
1666
1717
  await Promise.all(importFns.map((fn) => fn()));
1667
- InjectorExplorer.flushAccumulated();
1718
+ await InjectorExplorer.flushAccumulated();
1668
1719
  return this;
1669
1720
  }
1670
1721
  /**
@@ -1742,18 +1793,34 @@ NoxApp = __decorateClass([
1742
1793
  var import_main3 = require("electron/main");
1743
1794
  init_app_injector();
1744
1795
  init_injector_explorer();
1796
+ init_logger();
1745
1797
  async function bootstrapApplication(config = {}) {
1746
1798
  await import_main3.app.whenReady();
1799
+ if (config.logLevel !== void 0) {
1800
+ if (config.logLevel === "none") {
1801
+ Logger.setLogLevel([]);
1802
+ } else if (Array.isArray(config.logLevel)) {
1803
+ Logger.setLogLevel(config.logLevel);
1804
+ } else {
1805
+ Logger.setLogLevel(config.logLevel);
1806
+ }
1807
+ }
1747
1808
  const overrides = /* @__PURE__ */ new Map();
1748
1809
  for (const { token: token2, useValue } of config.singletons ?? []) {
1749
1810
  overrides.set(token2, useValue);
1750
1811
  RootInjector.singletons.set(token2, useValue);
1751
1812
  }
1813
+ InjectorExplorer.setControllerRegistrar((controllerClass, pathPrefix, routeGuards, routeMiddlewares) => {
1814
+ const router = inject(Router);
1815
+ router.registerController(controllerClass, pathPrefix, routeGuards, routeMiddlewares);
1816
+ });
1752
1817
  InjectorExplorer.processPending(overrides);
1753
1818
  const noxApp = inject(NoxApp);
1754
1819
  if (config.routes?.length) {
1755
1820
  for (const route of config.routes) {
1756
- noxApp.lazy(route.path, route.load, route.guards, route.middlewares);
1821
+ if (route.load) {
1822
+ noxApp.lazy(route.path, route.load, route.guards, route.middlewares);
1823
+ }
1757
1824
  }
1758
1825
  }
1759
1826
  if (config.eagerLoad?.length) {
@@ -1765,29 +1832,53 @@ async function bootstrapApplication(config = {}) {
1765
1832
  __name(bootstrapApplication, "bootstrapApplication");
1766
1833
 
1767
1834
  // src/main.ts
1768
- init_exceptions();
1769
- init_controller_decorator();
1770
- init_injectable_decorator();
1771
- init_method_decorator();
1772
1835
  init_logger();
1773
1836
  init_forward_ref();
1774
- init_request();
1775
1837
 
1776
1838
  // src/internal/routes.ts
1777
1839
  function defineRoutes(routes) {
1778
- const paths = routes.map((r) => r.path.replace(/^\/+|\/+$/g, ""));
1840
+ const flat = flattenRoutes(routes);
1841
+ const paths = flat.map((r) => r.path);
1779
1842
  const duplicates = paths.filter((p, i) => paths.indexOf(p) !== i);
1780
1843
  if (duplicates.length > 0) {
1781
1844
  throw new Error(
1782
1845
  `[Noxus] Duplicate route prefixes detected: ${[...new Set(duplicates)].map((d) => `"${d}"`).join(", ")}`
1783
1846
  );
1784
1847
  }
1785
- return routes.map((r) => ({
1786
- ...r,
1787
- path: r.path.replace(/^\/+|\/+$/g, "")
1788
- }));
1848
+ const sorted = [...paths].sort();
1849
+ for (let i = 0; i < sorted.length - 1; i++) {
1850
+ const a = sorted[i];
1851
+ const b = sorted[i + 1];
1852
+ if (b.startsWith(a + "/")) {
1853
+ throw new Error(
1854
+ `[Noxus] Overlapping route prefixes detected: "${a}" and "${b}". Use nested children under "${a}" instead of declaring both as top-level routes.`
1855
+ );
1856
+ }
1857
+ }
1858
+ return flat;
1789
1859
  }
1790
1860
  __name(defineRoutes, "defineRoutes");
1861
+ function flattenRoutes(routes, parentPath = "", parentGuards = [], parentMiddlewares = []) {
1862
+ const result = [];
1863
+ for (const route of routes) {
1864
+ const path2 = [parentPath, route.path.replace(/^\/+|\/+$/g, "")].filter(Boolean).join("/");
1865
+ const guards = [.../* @__PURE__ */ new Set([...parentGuards, ...route.guards ?? []])];
1866
+ const middlewares = [.../* @__PURE__ */ new Set([...parentMiddlewares, ...route.middlewares ?? []])];
1867
+ if (route.load) {
1868
+ result.push({ ...route, path: path2, guards, middlewares });
1869
+ }
1870
+ if (route.children?.length) {
1871
+ result.push(...flattenRoutes(route.children, path2, guards, middlewares));
1872
+ }
1873
+ if (!route.load && !route.children?.length) {
1874
+ throw new Error(
1875
+ `[Noxus] Route "${path2}" has neither a load function nor children. It must have at least one of them.`
1876
+ );
1877
+ }
1878
+ }
1879
+ return result;
1880
+ }
1881
+ __name(flattenRoutes, "flattenRoutes");
1791
1882
  // Annotate the CommonJS export names for ESM import in node:
1792
1883
  0 && (module.exports = {
1793
1884
  AppInjector,
@@ -1841,6 +1932,7 @@ __name(defineRoutes, "defineRoutes");
1841
1932
  inject,
1842
1933
  isAtomicHttpMethod,
1843
1934
  isRendererEventMessage,
1935
+ resetRootInjector,
1844
1936
  token
1845
1937
  });
1846
1938
  /**