@noxfly/noxus 1.2.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.mjs CHANGED
@@ -315,14 +315,29 @@ function getGuardForControllerAction(controllerName, actionName) {
315
315
  __name(getGuardForControllerAction, "getGuardForControllerAction");
316
316
  var authorizations = /* @__PURE__ */ new Map();
317
317
 
318
+ // src/decorators/injectable.metadata.ts
319
+ var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY");
320
+ function defineInjectableMetadata(target, lifetime) {
321
+ Reflect.defineMetadata(INJECTABLE_METADATA_KEY, lifetime, target);
322
+ }
323
+ __name(defineInjectableMetadata, "defineInjectableMetadata");
324
+ function getInjectableMetadata(target) {
325
+ return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
326
+ }
327
+ __name(getInjectableMetadata, "getInjectableMetadata");
328
+ function hasInjectableMetadata(target) {
329
+ return Reflect.hasMetadata(INJECTABLE_METADATA_KEY, target);
330
+ }
331
+ __name(hasInjectableMetadata, "hasInjectableMetadata");
332
+
318
333
  // src/decorators/method.decorator.ts
319
334
  function createRouteDecorator(verb) {
320
- return (path) => {
335
+ return (path2) => {
321
336
  return (target, propertyKey) => {
322
337
  const existingRoutes = Reflect.getMetadata(ROUTE_METADATA_KEY, target.constructor) || [];
323
338
  const metadata = {
324
339
  method: verb,
325
- path: path.trim().replace(/^\/|\/$/g, ""),
340
+ path: path2.trim().replace(/^\/|\/$/g, ""),
326
341
  handler: propertyKey,
327
342
  guards: getGuardForControllerAction(target.constructor.__controllerName, propertyKey)
328
343
  };
@@ -386,6 +401,8 @@ __name(getModuleMetadata, "getModuleMetadata");
386
401
  var MODULE_METADATA_KEY = Symbol("MODULE_METADATA_KEY");
387
402
 
388
403
  // src/utils/logger.ts
404
+ import * as fs from "fs";
405
+ import * as path from "path";
389
406
  function getPrettyTimestamp() {
390
407
  const now = /* @__PURE__ */ new Date();
391
408
  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")}`;
@@ -394,21 +411,41 @@ __name(getPrettyTimestamp, "getPrettyTimestamp");
394
411
  function getLogPrefix(callee, messageType, color) {
395
412
  const timestamp = getPrettyTimestamp();
396
413
  const spaces = " ".repeat(10 - messageType.length);
397
- return `${color}[APP] ${process.pid} - ${Logger.colors.initial}${timestamp}${spaces}${color}${messageType.toUpperCase()}${Logger.colors.initial} ${Logger.colors.yellow}[${callee}]${Logger.colors.initial}`;
414
+ let colReset = Logger.colors.initial;
415
+ let colCallee = Logger.colors.yellow;
416
+ if (color === void 0) {
417
+ color = "";
418
+ colReset = "";
419
+ colCallee = "";
420
+ }
421
+ return `${color}[APP] ${process.pid} - ${colReset}${timestamp}${spaces}${color}${messageType.toUpperCase()}${colReset} ${colCallee}[${callee}]${colReset}`;
398
422
  }
399
423
  __name(getLogPrefix, "getLogPrefix");
400
- function formatObject(prefix, arg) {
424
+ function formatObject(prefix, arg, enableColor = true) {
401
425
  const json = JSON.stringify(arg, null, 2);
402
- const prefixedJson = json.split("\n").map((line, idx) => idx === 0 ? `${Logger.colors.darkGrey}${line}` : `${prefix} ${Logger.colors.grey}${line}`).join("\n") + Logger.colors.initial;
426
+ let colStart = "";
427
+ let colLine = "";
428
+ let colReset = "";
429
+ if (enableColor) {
430
+ colStart = Logger.colors.darkGrey;
431
+ colLine = Logger.colors.grey;
432
+ colReset = Logger.colors.initial;
433
+ }
434
+ const prefixedJson = json.split("\n").map((line, idx) => idx === 0 ? `${colStart}${line}` : `${prefix} ${colLine}${line}`).join("\n") + colReset;
403
435
  return prefixedJson;
404
436
  }
405
437
  __name(formatObject, "formatObject");
406
438
  function formattedArgs(prefix, args, color) {
439
+ let colReset = Logger.colors.initial;
440
+ if (color === void 0) {
441
+ color = "";
442
+ colReset = "";
443
+ }
407
444
  return args.map((arg) => {
408
445
  if (typeof arg === "string") {
409
- return `${color}${arg}${Logger.colors.initial}`;
446
+ return `${color}${arg}${colReset}`;
410
447
  } else if (typeof arg === "object") {
411
- return formatObject(prefix, arg);
448
+ return formatObject(prefix, arg, color === "");
412
449
  }
413
450
  return arg;
414
451
  });
@@ -421,80 +458,163 @@ function getCallee() {
421
458
  }
422
459
  __name(getCallee, "getCallee");
423
460
  function canLog(level) {
424
- return logLevelRank[level] >= logLevelRank[logLevel];
461
+ return logLevels.has(level);
425
462
  }
426
463
  __name(canLog, "canLog");
427
- var logLevel = "debug";
428
- var logLevelRank = {
429
- debug: 0,
430
- comment: 1,
431
- log: 2,
432
- info: 3,
433
- warn: 4,
434
- error: 5
435
- };
464
+ function processLogQueue(filepath) {
465
+ const state = fileStates.get(filepath);
466
+ if (!state || state.isWriting || state.queue.length === 0) {
467
+ return;
468
+ }
469
+ state.isWriting = true;
470
+ const messagesToWrite = state.queue.join("\n") + "\n";
471
+ state.queue = [];
472
+ const dir = path.dirname(filepath);
473
+ fs.mkdir(dir, {
474
+ recursive: true
475
+ }, (err) => {
476
+ if (err) {
477
+ console.error(`[Logger] Failed to create directory ${dir}`, err);
478
+ state.isWriting = false;
479
+ return;
480
+ }
481
+ fs.appendFile(filepath, messagesToWrite, {
482
+ encoding: "utf-8"
483
+ }, (err2) => {
484
+ state.isWriting = false;
485
+ if (err2) {
486
+ console.error(`[Logger] Failed to write log to ${filepath}`, err2);
487
+ }
488
+ if (state.queue.length > 0) {
489
+ processLogQueue(filepath);
490
+ }
491
+ });
492
+ });
493
+ }
494
+ __name(processLogQueue, "processLogQueue");
495
+ function enqueue(filepath, message) {
496
+ if (!fileStates.has(filepath)) {
497
+ fileStates.set(filepath, {
498
+ queue: [],
499
+ isWriting: false
500
+ });
501
+ }
502
+ const state = fileStates.get(filepath);
503
+ state.queue.push(message);
504
+ processLogQueue(filepath);
505
+ }
506
+ __name(enqueue, "enqueue");
507
+ function output(level, args) {
508
+ if (!canLog(level)) {
509
+ return;
510
+ }
511
+ const callee = getCallee();
512
+ {
513
+ const prefix = getLogPrefix(callee, level, logLevelColors[level]);
514
+ const data = formattedArgs(prefix, args, logLevelColors[level]);
515
+ logLevelChannel[level](prefix, ...data);
516
+ }
517
+ {
518
+ const prefix = getLogPrefix(callee, level);
519
+ const data = formattedArgs(prefix, args);
520
+ const filepath = fileSettings.get(level)?.filepath;
521
+ if (filepath) {
522
+ const message = prefix + " " + data.join(" ");
523
+ enqueue(filepath, message);
524
+ }
525
+ }
526
+ }
527
+ __name(output, "output");
436
528
  (function(Logger2) {
437
529
  function setLogLevel(level) {
438
- logLevel = level;
530
+ logLevels.clear();
531
+ if (Array.isArray(level)) {
532
+ for (const lvl of level) {
533
+ logLevels.add(lvl);
534
+ }
535
+ } else {
536
+ const targetRank = logLevelRank[level];
537
+ for (const [lvl, rank] of Object.entries(logLevelRank)) {
538
+ if (rank >= targetRank) {
539
+ logLevels.add(lvl);
540
+ }
541
+ }
542
+ }
439
543
  }
440
544
  __name(setLogLevel, "setLogLevel");
441
545
  Logger2.setLogLevel = setLogLevel;
442
546
  function log(...args) {
443
- if (!canLog("log")) return;
444
- const callee = getCallee();
445
- const prefix = getLogPrefix(callee, "log", Logger2.colors.green);
446
- console.log(prefix, ...formattedArgs(prefix, args, Logger2.colors.green));
547
+ output("log", args);
447
548
  }
448
549
  __name(log, "log");
449
550
  Logger2.log = log;
450
551
  function info(...args) {
451
- if (!canLog("info")) return;
452
- const callee = getCallee();
453
- const prefix = getLogPrefix(callee, "info", Logger2.colors.blue);
454
- console.info(prefix, ...formattedArgs(prefix, args, Logger2.colors.blue));
552
+ output("info", args);
455
553
  }
456
554
  __name(info, "info");
457
555
  Logger2.info = info;
458
556
  function warn(...args) {
459
- if (!canLog("warn")) return;
460
- const callee = getCallee();
461
- const prefix = getLogPrefix(callee, "warn", Logger2.colors.brown);
462
- console.warn(prefix, ...formattedArgs(prefix, args, Logger2.colors.brown));
557
+ output("warn", args);
463
558
  }
464
559
  __name(warn, "warn");
465
560
  Logger2.warn = warn;
466
561
  function error(...args) {
467
- if (!canLog("error")) return;
468
- const callee = getCallee();
469
- const prefix = getLogPrefix(callee, "error", Logger2.colors.red);
470
- console.error(prefix, ...formattedArgs(prefix, args, Logger2.colors.red));
562
+ output("error", args);
471
563
  }
472
564
  __name(error, "error");
473
565
  Logger2.error = error;
474
566
  function errorStack(...args) {
475
- if (!canLog("error")) return;
476
- const callee = getCallee();
477
- const prefix = getLogPrefix(callee, "error", Logger2.colors.grey);
478
- console.error(prefix, ...formattedArgs(prefix, args, Logger2.colors.grey));
567
+ output("error", args);
479
568
  }
480
569
  __name(errorStack, "errorStack");
481
570
  Logger2.errorStack = errorStack;
482
571
  function debug(...args) {
483
- if (!canLog("debug")) return;
484
- const callee = getCallee();
485
- const prefix = getLogPrefix(callee, "debug", Logger2.colors.purple);
486
- console.debug(prefix, ...formattedArgs(prefix, args, Logger2.colors.purple));
572
+ output("debug", args);
487
573
  }
488
574
  __name(debug, "debug");
489
575
  Logger2.debug = debug;
490
576
  function comment(...args) {
491
- if (!canLog("comment")) return;
492
- const callee = getCallee();
493
- const prefix = getLogPrefix(callee, "comment", Logger2.colors.grey);
494
- console.debug(prefix, ...formattedArgs(prefix, args, Logger2.colors.grey));
577
+ output("comment", args);
495
578
  }
496
579
  __name(comment, "comment");
497
580
  Logger2.comment = comment;
581
+ function critical(...args) {
582
+ output("critical", args);
583
+ }
584
+ __name(critical, "critical");
585
+ Logger2.critical = critical;
586
+ function enableFileLogging(filepath, levels = [
587
+ "debug",
588
+ "comment",
589
+ "log",
590
+ "info",
591
+ "warn",
592
+ "error",
593
+ "critical"
594
+ ]) {
595
+ for (const level of levels) {
596
+ fileSettings.set(level, {
597
+ filepath
598
+ });
599
+ }
600
+ }
601
+ __name(enableFileLogging, "enableFileLogging");
602
+ Logger2.enableFileLogging = enableFileLogging;
603
+ function disableFileLogging(levels = [
604
+ "debug",
605
+ "comment",
606
+ "log",
607
+ "info",
608
+ "warn",
609
+ "error",
610
+ "critical"
611
+ ]) {
612
+ for (const level of levels) {
613
+ fileSettings.delete(level);
614
+ }
615
+ }
616
+ __name(disableFileLogging, "disableFileLogging");
617
+ Logger2.disableFileLogging = disableFileLogging;
498
618
  Logger2.colors = {
499
619
  black: "\x1B[0;30m",
500
620
  grey: "\x1B[0;37m",
@@ -514,6 +634,37 @@ var logLevelRank = {
514
634
  initial: "\x1B[0m"
515
635
  };
516
636
  })(Logger || (Logger = {}));
637
+ var fileSettings = /* @__PURE__ */ new Map();
638
+ var fileStates = /* @__PURE__ */ new Map();
639
+ var logLevels = /* @__PURE__ */ new Set();
640
+ var logLevelRank = {
641
+ debug: 0,
642
+ comment: 1,
643
+ log: 2,
644
+ info: 3,
645
+ warn: 4,
646
+ error: 5,
647
+ critical: 6
648
+ };
649
+ var logLevelColors = {
650
+ debug: Logger.colors.purple,
651
+ comment: Logger.colors.grey,
652
+ log: Logger.colors.green,
653
+ info: Logger.colors.blue,
654
+ warn: Logger.colors.brown,
655
+ error: Logger.colors.red,
656
+ critical: Logger.colors.lightRed
657
+ };
658
+ var logLevelChannel = {
659
+ debug: console.debug,
660
+ comment: console.debug,
661
+ log: console.log,
662
+ info: console.info,
663
+ warn: console.warn,
664
+ error: console.error,
665
+ critical: console.error
666
+ };
667
+ Logger.setLogLevel("debug");
517
668
  var Logger;
518
669
 
519
670
  // src/DI/injector-explorer.ts
@@ -562,22 +713,17 @@ function Injectable(lifetime = "scope") {
562
713
  if (typeof target !== "function" || !target.prototype) {
563
714
  throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`);
564
715
  }
565
- Reflect.defineMetadata(INJECTABLE_METADATA_KEY, lifetime, target);
716
+ defineInjectableMetadata(target, lifetime);
566
717
  InjectorExplorer.register(target, lifetime);
567
718
  };
568
719
  }
569
720
  __name(Injectable, "Injectable");
570
- function getInjectableMetadata(target) {
571
- return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
572
- }
573
- __name(getInjectableMetadata, "getInjectableMetadata");
574
- var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY");
575
721
 
576
722
  // src/decorators/controller.decorator.ts
577
- function Controller(path) {
723
+ function Controller(path2) {
578
724
  return (target) => {
579
725
  const data = {
580
- path,
726
+ path: path2,
581
727
  guards: getGuardForController(target.name)
582
728
  };
583
729
  Reflect.defineMetadata(CONTROLLER_METADATA_KEY, data, target);
@@ -625,8 +771,9 @@ var middlewares = /* @__PURE__ */ new Map();
625
771
  // src/request.ts
626
772
  import "reflect-metadata";
627
773
  var _Request = class _Request {
628
- constructor(event, id, method, path, body) {
774
+ constructor(event, senderId, id, method, path2, body) {
629
775
  __publicField(this, "event");
776
+ __publicField(this, "senderId");
630
777
  __publicField(this, "id");
631
778
  __publicField(this, "method");
632
779
  __publicField(this, "path");
@@ -634,11 +781,12 @@ var _Request = class _Request {
634
781
  __publicField(this, "context", RootInjector.createScope());
635
782
  __publicField(this, "params", {});
636
783
  this.event = event;
784
+ this.senderId = senderId;
637
785
  this.id = id;
638
786
  this.method = method;
639
- this.path = path;
787
+ this.path = path2;
640
788
  this.body = body;
641
- this.path = path.replace(/^\/|\/$/g, "");
789
+ this.path = path2.replace(/^\/|\/$/g, "");
642
790
  }
643
791
  };
644
792
  __name(_Request, "Request");
@@ -720,8 +868,8 @@ var _RadixTree = class _RadixTree {
720
868
  * @param path - The path to insert into the tree.
721
869
  * @param value - The value to associate with the path.
722
870
  */
723
- insert(path, value) {
724
- const segments = this.normalize(path);
871
+ insert(path2, value) {
872
+ const segments = this.normalize(path2);
725
873
  this.insertRecursive(this.root, segments, value);
726
874
  }
727
875
  /**
@@ -750,8 +898,8 @@ var _RadixTree = class _RadixTree {
750
898
  * @param path - The path to search for in the Radix Tree.
751
899
  * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined.
752
900
  */
753
- search(path) {
754
- const segments = this.normalize(path);
901
+ search(path2) {
902
+ const segments = this.normalize(path2);
755
903
  return this.searchRecursive(this.root, segments, {});
756
904
  }
757
905
  /**
@@ -807,8 +955,8 @@ var _RadixTree = class _RadixTree {
807
955
  * @param path - The path to normalize.
808
956
  * @returns An array of normalized path segments.
809
957
  */
810
- normalize(path) {
811
- const segments = path.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
958
+ normalize(path2) {
959
+ const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
812
960
  return [
813
961
  "",
814
962
  ...segments
@@ -918,6 +1066,7 @@ var _Router = class _Router {
918
1066
  status: 200,
919
1067
  body: null
920
1068
  };
1069
+ let isCritical = false;
921
1070
  try {
922
1071
  const routeDef = this.findRoute(request);
923
1072
  await this.resolveController(request, response, routeDef);
@@ -931,10 +1080,12 @@ var _Router = class _Router {
931
1080
  response.error = error.message;
932
1081
  response.stack = error.stack;
933
1082
  } else if (error instanceof Error) {
1083
+ isCritical = true;
934
1084
  response.status = 500;
935
1085
  response.error = error.message || "Internal Server Error";
936
1086
  response.stack = error.stack || "No stack trace available";
937
1087
  } else {
1088
+ isCritical = true;
938
1089
  response.status = 500;
939
1090
  response.error = "Unknown error occurred";
940
1091
  response.stack = "No stack trace available";
@@ -942,11 +1093,23 @@ var _Router = class _Router {
942
1093
  } finally {
943
1094
  const t1 = performance.now();
944
1095
  const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`;
945
- if (response.status < 400) Logger.log(message);
946
- else if (response.status < 500) Logger.warn(message);
947
- else Logger.error(message);
1096
+ if (response.status < 400) {
1097
+ Logger.log(message);
1098
+ } else if (response.status < 500) {
1099
+ Logger.warn(message);
1100
+ } else {
1101
+ if (isCritical) {
1102
+ Logger.critical(message);
1103
+ } else {
1104
+ Logger.error(message);
1105
+ }
1106
+ }
948
1107
  if (response.error !== void 0) {
949
- Logger.error(response.error);
1108
+ if (isCritical) {
1109
+ Logger.critical(response.error);
1110
+ } else {
1111
+ Logger.error(response.error);
1112
+ }
950
1113
  if (response.stack !== void 0) {
951
1114
  Logger.errorStack(response.stack);
952
1115
  }
@@ -964,12 +1127,13 @@ var _Router = class _Router {
964
1127
  responses: []
965
1128
  }
966
1129
  };
1130
+ let isCritical = false;
967
1131
  try {
968
1132
  const payload = this.normalizeBatchPayload(request.body);
969
1133
  const batchResponses = [];
970
1134
  for (const [index, item] of payload.requests.entries()) {
971
1135
  const subRequestId = item.requestId ?? `${request.id}:${index}`;
972
- const atomicRequest = new Request(request.event, subRequestId, item.method, item.path, item.body);
1136
+ const atomicRequest = new Request(request.event, request.senderId, subRequestId, item.method, item.path, item.body);
973
1137
  batchResponses.push(await this.handleAtomic(atomicRequest));
974
1138
  }
975
1139
  response.body.responses = batchResponses;
@@ -980,10 +1144,12 @@ var _Router = class _Router {
980
1144
  response.error = error.message;
981
1145
  response.stack = error.stack;
982
1146
  } else if (error instanceof Error) {
1147
+ isCritical = true;
983
1148
  response.status = 500;
984
1149
  response.error = error.message || "Internal Server Error";
985
1150
  response.stack = error.stack || "No stack trace available";
986
1151
  } else {
1152
+ isCritical = true;
987
1153
  response.status = 500;
988
1154
  response.error = "Unknown error occurred";
989
1155
  response.stack = "No stack trace available";
@@ -991,11 +1157,23 @@ var _Router = class _Router {
991
1157
  } finally {
992
1158
  const t1 = performance.now();
993
1159
  const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`;
994
- if (response.status < 400) Logger.log(message);
995
- else if (response.status < 500) Logger.warn(message);
996
- else Logger.error(message);
1160
+ if (response.status < 400) {
1161
+ Logger.log(message);
1162
+ } else if (response.status < 500) {
1163
+ Logger.warn(message);
1164
+ } else {
1165
+ if (isCritical) {
1166
+ Logger.critical(message);
1167
+ } else {
1168
+ Logger.error(message);
1169
+ }
1170
+ }
997
1171
  if (response.error !== void 0) {
998
- Logger.error(response.error);
1172
+ if (isCritical) {
1173
+ Logger.critical(response.error);
1174
+ } else {
1175
+ Logger.error(response.error);
1176
+ }
999
1177
  if (response.stack !== void 0) {
1000
1178
  Logger.errorStack(response.stack);
1001
1179
  }
@@ -1021,11 +1199,11 @@ var _Router = class _Router {
1021
1199
  if (entry === null || typeof entry !== "object") {
1022
1200
  throw new BadRequestException(`Batch request at index ${index} must be an object.`);
1023
1201
  }
1024
- const { requestId, path, method, body } = entry;
1202
+ const { requestId, path: path2, method, body } = entry;
1025
1203
  if (requestId !== void 0 && typeof requestId !== "string") {
1026
1204
  throw new BadRequestException(`Batch request at index ${index} has an invalid requestId.`);
1027
1205
  }
1028
- if (typeof path !== "string" || path.length === 0) {
1206
+ if (typeof path2 !== "string" || path2.length === 0) {
1029
1207
  throw new BadRequestException(`Batch request at index ${index} must define a non-empty path.`);
1030
1208
  }
1031
1209
  if (typeof method !== "string") {
@@ -1037,7 +1215,7 @@ var _Router = class _Router {
1037
1215
  }
1038
1216
  return {
1039
1217
  requestId,
1040
- path,
1218
+ path: path2,
1041
1219
  method: normalizedMethod,
1042
1220
  body
1043
1221
  };
@@ -1189,20 +1367,23 @@ function _ts_decorate2(decorators, target, key, desc) {
1189
1367
  __name(_ts_decorate2, "_ts_decorate");
1190
1368
  var _NoxSocket = class _NoxSocket {
1191
1369
  constructor() {
1192
- __publicField(this, "messagePorts", /* @__PURE__ */ new Map());
1370
+ __publicField(this, "channels", /* @__PURE__ */ new Map());
1193
1371
  }
1194
- register(senderId, channel) {
1195
- this.messagePorts.set(senderId, channel);
1372
+ register(senderId, requestChannel, socketChannel) {
1373
+ this.channels.set(senderId, {
1374
+ request: requestChannel,
1375
+ socket: socketChannel
1376
+ });
1196
1377
  }
1197
1378
  get(senderId) {
1198
- return this.messagePorts.get(senderId);
1379
+ return this.channels.get(senderId);
1199
1380
  }
1200
1381
  unregister(senderId) {
1201
- this.messagePorts.delete(senderId);
1382
+ this.channels.delete(senderId);
1202
1383
  }
1203
1384
  getSenderIds() {
1204
1385
  return [
1205
- ...this.messagePorts.keys()
1386
+ ...this.channels.keys()
1206
1387
  ];
1207
1388
  }
1208
1389
  emit(eventName, payload, targetSenderIds) {
@@ -1213,13 +1394,13 @@ var _NoxSocket = class _NoxSocket {
1213
1394
  const recipients = targetSenderIds ?? this.getSenderIds();
1214
1395
  let delivered = 0;
1215
1396
  for (const senderId of recipients) {
1216
- const channel = this.messagePorts.get(senderId);
1397
+ const channel = this.channels.get(senderId);
1217
1398
  if (!channel) {
1218
1399
  Logger.warn(`No message channel found for sender ID: ${senderId} while emitting "${normalizedEvent}".`);
1219
1400
  continue;
1220
1401
  }
1221
1402
  try {
1222
- channel.port1.postMessage(createRendererEventMessage(normalizedEvent, payload));
1403
+ channel.socket.port1.postMessage(createRendererEventMessage(normalizedEvent, payload));
1223
1404
  delivered++;
1224
1405
  } catch (error) {
1225
1406
  Logger.error(`[Noxus] Failed to emit "${normalizedEvent}" to sender ${senderId}.`, error);
@@ -1256,17 +1437,20 @@ var _NoxApp = class _NoxApp {
1256
1437
  __publicField(this, "router");
1257
1438
  __publicField(this, "socket");
1258
1439
  __publicField(this, "app");
1440
+ /**
1441
+ *
1442
+ */
1259
1443
  __publicField(this, "onRendererMessage", /* @__PURE__ */ __name(async (event) => {
1260
- const { senderId, requestId, path, method, body } = event.data;
1261
- const channel = this.socket.get(senderId);
1262
- if (!channel) {
1444
+ const { senderId, requestId, path: path2, method, body } = event.data;
1445
+ const channels = this.socket.get(senderId);
1446
+ if (!channels) {
1263
1447
  Logger.error(`No message channel found for sender ID: ${senderId}`);
1264
1448
  return;
1265
1449
  }
1266
1450
  try {
1267
- const request = new Request(event, requestId, method, path, body);
1451
+ const request = new Request(event, senderId, requestId, method, path2, body);
1268
1452
  const response = await this.router.handle(request);
1269
- channel.port1.postMessage(response);
1453
+ channels.request.port1.postMessage(response);
1270
1454
  } catch (err) {
1271
1455
  const response = {
1272
1456
  requestId,
@@ -1274,7 +1458,7 @@ var _NoxApp = class _NoxApp {
1274
1458
  body: null,
1275
1459
  error: err.message || "Internal Server Error"
1276
1460
  };
1277
- channel.port1.postMessage(response);
1461
+ channels.request.port1.postMessage(response);
1278
1462
  }
1279
1463
  }, "onRendererMessage"));
1280
1464
  this.router = router;
@@ -1303,14 +1487,17 @@ var _NoxApp = class _NoxApp {
1303
1487
  if (this.socket.get(senderId)) {
1304
1488
  this.shutdownChannel(senderId);
1305
1489
  }
1306
- const channel = new MessageChannelMain();
1307
- channel.port1.on("message", this.onRendererMessage);
1308
- channel.port1.start();
1309
- this.socket.register(senderId, channel);
1490
+ const requestChannel = new MessageChannelMain();
1491
+ const socketChannel = new MessageChannelMain();
1492
+ requestChannel.port1.on("message", this.onRendererMessage);
1493
+ requestChannel.port1.start();
1494
+ socketChannel.port1.start();
1495
+ this.socket.register(senderId, requestChannel, socketChannel);
1310
1496
  event.sender.postMessage("port", {
1311
1497
  senderId
1312
1498
  }, [
1313
- channel.port2
1499
+ requestChannel.port2,
1500
+ socketChannel.port2
1314
1501
  ]);
1315
1502
  }
1316
1503
  /**
@@ -1329,14 +1516,16 @@ var _NoxApp = class _NoxApp {
1329
1516
  * @param remove - Whether to remove the channel from the messagePorts map.
1330
1517
  */
1331
1518
  shutdownChannel(channelSenderId) {
1332
- const channel = this.socket.get(channelSenderId);
1333
- if (!channel) {
1519
+ const channels = this.socket.get(channelSenderId);
1520
+ if (!channels) {
1334
1521
  Logger.warn(`No message channel found for sender ID: ${channelSenderId}`);
1335
1522
  return;
1336
1523
  }
1337
- channel.port1.off("message", this.onRendererMessage);
1338
- channel.port1.close();
1339
- channel.port2.close();
1524
+ channels.request.port1.off("message", this.onRendererMessage);
1525
+ channels.request.port1.close();
1526
+ channels.request.port2.close();
1527
+ channels.socket.port1.close();
1528
+ channels.socket.port2.close();
1340
1529
  this.socket.unregister(channelSenderId);
1341
1530
  }
1342
1531
  /**
@@ -1407,6 +1596,42 @@ async function bootstrapApplication(rootModule) {
1407
1596
  }
1408
1597
  __name(bootstrapApplication, "bootstrapApplication");
1409
1598
 
1599
+ // src/preload-bridge.ts
1600
+ import { contextBridge, ipcRenderer } from "electron/renderer";
1601
+ var DEFAULT_EXPOSE_NAME = "noxus";
1602
+ var DEFAULT_INIT_EVENT = "init-port";
1603
+ var DEFAULT_REQUEST_CHANNEL = "gimme-my-port";
1604
+ var DEFAULT_RESPONSE_CHANNEL = "port";
1605
+ function exposeNoxusBridge(options = {}) {
1606
+ const { exposeAs = DEFAULT_EXPOSE_NAME, initMessageType = DEFAULT_INIT_EVENT, requestChannel = DEFAULT_REQUEST_CHANNEL, responseChannel = DEFAULT_RESPONSE_CHANNEL, targetWindow = window } = options;
1607
+ const api = {
1608
+ requestPort: /* @__PURE__ */ __name(() => {
1609
+ ipcRenderer.send(requestChannel);
1610
+ ipcRenderer.once(responseChannel, (event, message) => {
1611
+ const ports = (event.ports ?? []).filter((port) => port !== void 0);
1612
+ if (ports.length === 0) {
1613
+ console.error("[Noxus] No MessagePort received from main process.");
1614
+ return;
1615
+ }
1616
+ for (const port of ports) {
1617
+ try {
1618
+ port.start();
1619
+ } catch (error) {
1620
+ console.error("[Noxus] Failed to start MessagePort.", error);
1621
+ }
1622
+ }
1623
+ targetWindow.postMessage({
1624
+ type: initMessageType,
1625
+ senderId: message?.senderId
1626
+ }, "*", ports);
1627
+ });
1628
+ }, "requestPort")
1629
+ };
1630
+ contextBridge.exposeInMainWorld(exposeAs, api);
1631
+ return api;
1632
+ }
1633
+ __name(exposeNoxusBridge, "exposeNoxusBridge");
1634
+
1410
1635
  // src/renderer-events.ts
1411
1636
  var _RendererEventRegistry = class _RendererEventRegistry {
1412
1637
  constructor() {
@@ -1486,6 +1711,252 @@ var _RendererEventRegistry = class _RendererEventRegistry {
1486
1711
  };
1487
1712
  __name(_RendererEventRegistry, "RendererEventRegistry");
1488
1713
  var RendererEventRegistry = _RendererEventRegistry;
1714
+
1715
+ // src/renderer-client.ts
1716
+ var DEFAULT_INIT_EVENT2 = "init-port";
1717
+ var DEFAULT_BRIDGE_NAMES = [
1718
+ "noxus",
1719
+ "ipcRenderer"
1720
+ ];
1721
+ function defaultRequestId() {
1722
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1723
+ return crypto.randomUUID();
1724
+ }
1725
+ return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
1726
+ }
1727
+ __name(defaultRequestId, "defaultRequestId");
1728
+ function normalizeBridgeNames(preferred) {
1729
+ const names = [];
1730
+ const add = /* @__PURE__ */ __name((name) => {
1731
+ if (!name) return;
1732
+ if (!names.includes(name)) {
1733
+ names.push(name);
1734
+ }
1735
+ }, "add");
1736
+ if (Array.isArray(preferred)) {
1737
+ for (const name of preferred) {
1738
+ add(name);
1739
+ }
1740
+ } else {
1741
+ add(preferred);
1742
+ }
1743
+ for (const fallback of DEFAULT_BRIDGE_NAMES) {
1744
+ add(fallback);
1745
+ }
1746
+ return names;
1747
+ }
1748
+ __name(normalizeBridgeNames, "normalizeBridgeNames");
1749
+ function resolveBridgeFromWindow(windowRef, preferred) {
1750
+ const names = normalizeBridgeNames(preferred);
1751
+ const globalRef = windowRef;
1752
+ if (!globalRef) {
1753
+ return null;
1754
+ }
1755
+ for (const name of names) {
1756
+ const candidate = globalRef[name];
1757
+ if (candidate && typeof candidate.requestPort === "function") {
1758
+ return candidate;
1759
+ }
1760
+ }
1761
+ return null;
1762
+ }
1763
+ __name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
1764
+ var _NoxRendererClient = class _NoxRendererClient {
1765
+ constructor(options = {}) {
1766
+ __publicField(this, "events", new RendererEventRegistry());
1767
+ __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
1768
+ __publicField(this, "requestPort");
1769
+ __publicField(this, "socketPort");
1770
+ __publicField(this, "senderId");
1771
+ __publicField(this, "bridge");
1772
+ __publicField(this, "initMessageType");
1773
+ __publicField(this, "windowRef");
1774
+ __publicField(this, "generateRequestId");
1775
+ __publicField(this, "isReady", false);
1776
+ __publicField(this, "setupPromise");
1777
+ __publicField(this, "setupResolve");
1778
+ __publicField(this, "setupReject");
1779
+ __publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
1780
+ if (event.data?.type !== this.initMessageType) {
1781
+ return;
1782
+ }
1783
+ if (!Array.isArray(event.ports) || event.ports.length < 2) {
1784
+ const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
1785
+ console.error(error);
1786
+ this.setupReject?.(error);
1787
+ this.resetSetupState();
1788
+ return;
1789
+ }
1790
+ this.windowRef.removeEventListener("message", this.onWindowMessage);
1791
+ this.requestPort = event.ports[0];
1792
+ this.socketPort = event.ports[1];
1793
+ this.senderId = event.data.senderId;
1794
+ if (this.requestPort === void 0 || this.socketPort === void 0) {
1795
+ const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
1796
+ console.error(error);
1797
+ this.setupReject?.(error);
1798
+ this.resetSetupState();
1799
+ return;
1800
+ }
1801
+ this.attachRequestPort(this.requestPort);
1802
+ this.attachSocketPort(this.socketPort);
1803
+ this.isReady = true;
1804
+ this.setupResolve?.();
1805
+ this.resetSetupState(true);
1806
+ }, "onWindowMessage"));
1807
+ __publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
1808
+ if (this.events.tryDispatchFromMessageEvent(event)) {
1809
+ return;
1810
+ }
1811
+ console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
1812
+ }, "onSocketMessage"));
1813
+ __publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
1814
+ if (this.events.tryDispatchFromMessageEvent(event)) {
1815
+ return;
1816
+ }
1817
+ const response = event.data;
1818
+ if (!response || typeof response.requestId !== "string") {
1819
+ console.error("[Noxus] Renderer received an invalid response payload.", response);
1820
+ return;
1821
+ }
1822
+ const pending = this.pendingRequests.get(response.requestId);
1823
+ if (!pending) {
1824
+ console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
1825
+ return;
1826
+ }
1827
+ this.pendingRequests.delete(response.requestId);
1828
+ this.onRequestCompleted(pending, response);
1829
+ if (response.status >= 400) {
1830
+ pending.reject(response);
1831
+ return;
1832
+ }
1833
+ pending.resolve(response.body);
1834
+ }, "onRequestMessage"));
1835
+ this.windowRef = options.windowRef ?? window;
1836
+ const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
1837
+ this.bridge = resolvedBridge ?? null;
1838
+ this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT2;
1839
+ this.generateRequestId = options.generateRequestId ?? defaultRequestId;
1840
+ }
1841
+ async setup() {
1842
+ if (this.isReady) {
1843
+ return Promise.resolve();
1844
+ }
1845
+ if (this.setupPromise) {
1846
+ return this.setupPromise;
1847
+ }
1848
+ if (!this.bridge || typeof this.bridge.requestPort !== "function") {
1849
+ throw new Error("[Noxus] Renderer bridge is missing requestPort().");
1850
+ }
1851
+ this.setupPromise = new Promise((resolve, reject) => {
1852
+ this.setupResolve = resolve;
1853
+ this.setupReject = reject;
1854
+ });
1855
+ this.windowRef.addEventListener("message", this.onWindowMessage);
1856
+ this.bridge.requestPort();
1857
+ return this.setupPromise;
1858
+ }
1859
+ dispose() {
1860
+ this.windowRef.removeEventListener("message", this.onWindowMessage);
1861
+ this.requestPort?.close();
1862
+ this.socketPort?.close();
1863
+ this.requestPort = void 0;
1864
+ this.socketPort = void 0;
1865
+ this.senderId = void 0;
1866
+ this.isReady = false;
1867
+ this.pendingRequests.clear();
1868
+ }
1869
+ async request(request) {
1870
+ const senderId = this.senderId;
1871
+ const requestId = this.generateRequestId();
1872
+ if (senderId === void 0) {
1873
+ return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
1874
+ }
1875
+ const readinessError = this.validateReady(requestId);
1876
+ if (readinessError) {
1877
+ return Promise.reject(readinessError);
1878
+ }
1879
+ const message = {
1880
+ requestId,
1881
+ senderId,
1882
+ ...request
1883
+ };
1884
+ return new Promise((resolve, reject) => {
1885
+ const pending = {
1886
+ resolve,
1887
+ reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
1888
+ request: message,
1889
+ submittedAt: Date.now()
1890
+ };
1891
+ this.pendingRequests.set(message.requestId, pending);
1892
+ this.requestPort.postMessage(message);
1893
+ });
1894
+ }
1895
+ async batch(requests) {
1896
+ return this.request({
1897
+ method: "BATCH",
1898
+ path: "",
1899
+ body: {
1900
+ requests
1901
+ }
1902
+ });
1903
+ }
1904
+ getSenderId() {
1905
+ return this.senderId;
1906
+ }
1907
+ onRequestCompleted(pending, response) {
1908
+ if (typeof console.groupCollapsed === "function") {
1909
+ console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
1910
+ }
1911
+ if (response.error) {
1912
+ console.error("error message:", response.error);
1913
+ }
1914
+ if (response.body !== void 0) {
1915
+ console.info("response:", response.body);
1916
+ }
1917
+ console.info("request:", pending.request);
1918
+ console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
1919
+ if (typeof console.groupCollapsed === "function") {
1920
+ console.groupEnd();
1921
+ }
1922
+ }
1923
+ attachRequestPort(port) {
1924
+ port.onmessage = this.onRequestMessage;
1925
+ port.start();
1926
+ }
1927
+ attachSocketPort(port) {
1928
+ port.onmessage = this.onSocketMessage;
1929
+ port.start();
1930
+ }
1931
+ validateReady(requestId) {
1932
+ if (!this.isElectronEnvironment()) {
1933
+ return this.createErrorResponse(requestId, "Not running in Electron environment");
1934
+ }
1935
+ if (!this.requestPort) {
1936
+ return this.createErrorResponse(requestId, "MessagePort is not available");
1937
+ }
1938
+ return void 0;
1939
+ }
1940
+ createErrorResponse(requestId, message) {
1941
+ return {
1942
+ status: 500,
1943
+ requestId,
1944
+ error: message
1945
+ };
1946
+ }
1947
+ resetSetupState(success = false) {
1948
+ if (!success) {
1949
+ this.setupPromise = void 0;
1950
+ }
1951
+ this.setupResolve = void 0;
1952
+ this.setupReject = void 0;
1953
+ }
1954
+ isElectronEnvironment() {
1955
+ return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
1956
+ }
1957
+ };
1958
+ __name(_NoxRendererClient, "NoxRendererClient");
1959
+ var NoxRendererClient = _NoxRendererClient;
1489
1960
  export {
1490
1961
  AppInjector,
1491
1962
  Authorize,
@@ -1515,6 +1986,7 @@ export {
1515
1986
  NotFoundException,
1516
1987
  NotImplementedException,
1517
1988
  NoxApp,
1989
+ NoxRendererClient,
1518
1990
  NoxSocket,
1519
1991
  Patch,
1520
1992
  PaymentRequiredException,
@@ -1536,6 +2008,7 @@ export {
1536
2008
  VariantAlsoNegotiatesException,
1537
2009
  bootstrapApplication,
1538
2010
  createRendererEventMessage,
2011
+ exposeNoxusBridge,
1539
2012
  getControllerMetadata,
1540
2013
  getGuardForController,
1541
2014
  getGuardForControllerAction,
@@ -1544,6 +2017,7 @@ export {
1544
2017
  getMiddlewaresForControllerAction,
1545
2018
  getModuleMetadata,
1546
2019
  getRouteMetadata,
2020
+ hasInjectableMetadata,
1547
2021
  inject,
1548
2022
  isRendererEventMessage
1549
2023
  };