opticore-webapp 1.0.68 → 1.0.69
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/index.cjs +778 -560
- package/dist/index.d.cts +462 -148
- package/dist/index.d.ts +462 -148
- package/dist/index.js +780 -558
- package/dist/utils/translations/message.translation.en.json +20 -1
- package/dist/utils/translations/message.translation.fr.json +1 -1
- package/package.json +6 -7
package/dist/index.js
CHANGED
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
import * as path2 from "path";
|
|
3
3
|
import process4 from "process";
|
|
4
4
|
import corsOrigin from "cors";
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
5
|
+
import express from "express";
|
|
6
|
+
import chokidar from "chokidar";
|
|
7
|
+
import {
|
|
8
|
+
CEvent,
|
|
9
|
+
CEventNameError as eventName2,
|
|
10
|
+
ServerListenEventError as ServerListenEventError2
|
|
11
|
+
} from "opticore-catch-exception-error";
|
|
12
|
+
import { getEnvironmentValue } from "opticore-env-access";
|
|
8
13
|
import { requestCallsEvent } from "opticore-request-call-event";
|
|
9
14
|
import { SContainer as SContainer2 } from "opticore-dependency-inject";
|
|
10
15
|
import { HttpStatusCode as HttpStatusCode3 } from "opticore-http-response";
|
|
@@ -446,55 +451,149 @@ var SServerStartError = (err, environmentPath) => {
|
|
|
446
451
|
};
|
|
447
452
|
|
|
448
453
|
// src/core/webServer.core.ts
|
|
449
|
-
import { WebServerWatcherService } from "opticore-watcher";
|
|
450
454
|
var WebServerCore = class {
|
|
451
455
|
serverUtility;
|
|
452
|
-
expressApp
|
|
453
|
-
fileWatcher;
|
|
456
|
+
expressApp;
|
|
454
457
|
localLanguage;
|
|
455
458
|
loggerConfig;
|
|
456
|
-
routerExpressApp;
|
|
457
459
|
getEnvironment;
|
|
458
460
|
environmentPath;
|
|
459
461
|
serverListenEvent;
|
|
462
|
+
// Existing properties
|
|
460
463
|
currentRoutes = [];
|
|
461
464
|
currentDependencies = [];
|
|
462
465
|
server = void 0;
|
|
463
466
|
errorEmitter;
|
|
464
|
-
isWatcherEnabled = true;
|
|
465
467
|
serverStatus = "STARTING";
|
|
466
468
|
serverStartTime = /* @__PURE__ */ new Date();
|
|
469
|
+
// HMR properties
|
|
470
|
+
fileWatcher = null;
|
|
471
|
+
hmrRestartPending = false;
|
|
472
|
+
hmrDebounceTimeout = null;
|
|
473
|
+
hmrRestartCount = 0;
|
|
474
|
+
lastHmrRestartTime = 0;
|
|
475
|
+
/**
|
|
476
|
+
* Creates a new WebServerCore instance.
|
|
477
|
+
*
|
|
478
|
+
* @constructor
|
|
479
|
+
* @param {WebServerConstructorInterface} paramsConstructor - Configuration parameters
|
|
480
|
+
*
|
|
481
|
+
* @param {express.Application} paramsConstructor.app - Express application instance
|
|
482
|
+
* @param {LoggerCore} paramsConstructor.loggerConfig - Logger configuration
|
|
483
|
+
* @param {string} paramsConstructor.environmentPath - Path to environment file
|
|
484
|
+
* @param {string} paramsConstructor.localLanguage - Default language for translations
|
|
485
|
+
* @param {CorsOptions} paramsConstructor.corsOriginOptions - CORS configuration
|
|
486
|
+
*
|
|
487
|
+
* @returns {WebServerCore} New WebServerCore instance
|
|
488
|
+
*
|
|
489
|
+
* @throws {Error} If environment file cannot be loaded
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```typescript
|
|
493
|
+
* const server = new WebServerCore({
|
|
494
|
+
* app: express(),
|
|
495
|
+
* loggerConfig: new LoggerCore(config),
|
|
496
|
+
* environmentPath: ".env",
|
|
497
|
+
* localLanguage: "fr",
|
|
498
|
+
* corsOriginOptions: { origin: "http://localhost:3000" }
|
|
499
|
+
* });
|
|
500
|
+
* ```
|
|
501
|
+
*/
|
|
467
502
|
constructor(paramsConstructor) {
|
|
468
|
-
this.getEnvironment =
|
|
469
|
-
this.routerExpressApp = paramsConstructor.app;
|
|
503
|
+
this.getEnvironment = getEnvironmentValue(paramsConstructor.environmentPath);
|
|
470
504
|
this.loggerConfig = paramsConstructor.loggerConfig;
|
|
471
505
|
this.localLanguage = paramsConstructor.localLanguage;
|
|
472
506
|
this.environmentPath = paramsConstructor.environmentPath;
|
|
507
|
+
this.expressApp = express();
|
|
508
|
+
this.serverListenEvent = new ServerListenEventError2(paramsConstructor.localLanguage);
|
|
473
509
|
this.expressApp.use(express.json());
|
|
474
510
|
this.expressApp.use(express.raw());
|
|
475
511
|
this.expressApp.use(express.text());
|
|
476
512
|
this.expressApp.use(express.urlencoded({ extended: true }));
|
|
477
513
|
this.expressApp.use(corsOrigin(paramsConstructor.corsOriginOptions));
|
|
478
|
-
this.serverListenEvent = new ServerListenEventError2(paramsConstructor.localLanguage);
|
|
479
514
|
this.serverUtility = new CoreService(paramsConstructor.localLanguage, paramsConstructor.environmentPath);
|
|
515
|
+
this.serverStatus = "STARTING";
|
|
516
|
+
this.serverStartTime = /* @__PURE__ */ new Date();
|
|
517
|
+
this.setupProcessEventListeners();
|
|
480
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Starts the HTTP server and initializes all components including HMR if enabled.
|
|
521
|
+
*
|
|
522
|
+
* @method onStartServer
|
|
523
|
+
* @public
|
|
524
|
+
*
|
|
525
|
+
* @param {TFeatureRoutes[]} routers - Array of feature routes to register
|
|
526
|
+
* @param {(env: IEnvVariables) => void} [databaseCallback] - Optional database connection callback
|
|
527
|
+
* @param {TDependency[]} [dependenciesProvider] - Optional dependency injection providers
|
|
528
|
+
*
|
|
529
|
+
* @returns {serverWebApp | undefined} HTTP server instance or undefined if startup fails
|
|
530
|
+
*
|
|
531
|
+
* @throws {ServerListenEventError} If port/host configuration is invalid
|
|
532
|
+
* @throws {Error} If server initialization fails
|
|
533
|
+
*
|
|
534
|
+
* @fires WebServerCore#startHttpServer - When server successfully starts
|
|
535
|
+
* @fires WebServerCore#startHMR - When HMR is started (if enabled)
|
|
536
|
+
* @fires WebServerCore#serverError - When server fails to start
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* ```typescript
|
|
540
|
+
* const server = app.onStartServer(
|
|
541
|
+
* routes,
|
|
542
|
+
* (env) => connectToDatabase(env),
|
|
543
|
+
* dependencies
|
|
544
|
+
* );
|
|
545
|
+
*
|
|
546
|
+
* if (server) {
|
|
547
|
+
* console.log("Server started successfully");
|
|
548
|
+
* }
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
481
551
|
onStartServer(routers, databaseCallback, dependenciesProvider) {
|
|
552
|
+
try {
|
|
553
|
+
loaderTranslationFile(this.localLanguage);
|
|
554
|
+
this.currentRoutes = routers;
|
|
555
|
+
this.currentDependencies = dependenciesProvider || [];
|
|
556
|
+
this.serverStartTime = /* @__PURE__ */ new Date();
|
|
557
|
+
this.serverStatus = "STARTING";
|
|
558
|
+
if (!this.validateServerParameters()) {
|
|
559
|
+
return void 0;
|
|
560
|
+
}
|
|
561
|
+
const server = this.startHttpServer(databaseCallback);
|
|
562
|
+
if (this.getEnvironment.hmrEnabled) {
|
|
563
|
+
this.startHMR();
|
|
564
|
+
}
|
|
565
|
+
return server;
|
|
566
|
+
} catch (error) {
|
|
567
|
+
this.handleStartupError(error);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Validates server configuration parameters.
|
|
572
|
+
*
|
|
573
|
+
* @method validateServerParameters
|
|
574
|
+
* @private
|
|
575
|
+
*
|
|
576
|
+
* @returns {boolean} True if all parameters are valid, false otherwise
|
|
577
|
+
*
|
|
578
|
+
* @remarks
|
|
579
|
+
* Validates:
|
|
580
|
+
* - Port number is valid and positive
|
|
581
|
+
* - Host is not empty
|
|
582
|
+
* - Local language is specified
|
|
583
|
+
* - HMR configuration (if enabled)
|
|
584
|
+
*/
|
|
585
|
+
validateServerParameters() {
|
|
482
586
|
loaderTranslationFile(this.localLanguage);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return void 0;
|
|
587
|
+
const port = Number(this.getEnvironment.appPort);
|
|
588
|
+
if (isNaN(port) || port <= 0) {
|
|
589
|
+
this.serverListenEvent.portUndefined();
|
|
590
|
+
return false;
|
|
488
591
|
}
|
|
489
|
-
if (this.getEnvironment.appHost === "") {
|
|
592
|
+
if (!this.getEnvironment.appHost || this.getEnvironment.appHost.trim() === "") {
|
|
490
593
|
this.serverListenEvent.hostUndefined(this.getEnvironment.appHost);
|
|
491
|
-
return
|
|
492
|
-
}
|
|
493
|
-
if (Number(this.getEnvironment.appPort) === 0) {
|
|
494
|
-
this.serverListenEvent.portUndefined();
|
|
495
|
-
return void 0;
|
|
594
|
+
return false;
|
|
496
595
|
}
|
|
497
|
-
if (this.localLanguage === "") {
|
|
596
|
+
if (!this.localLanguage || this.localLanguage.trim() === "") {
|
|
498
597
|
SLogger(this.localLanguage).logger.error({
|
|
499
598
|
message: TranslationLoader2.t("noDefaultLocalLang", this.localLanguage),
|
|
500
599
|
title: TranslationLoader2.t("noLocalLang", this.localLanguage),
|
|
@@ -502,81 +601,225 @@ var WebServerCore = class {
|
|
|
502
601
|
stackTrace: void 0,
|
|
503
602
|
httpCodeValue: HttpStatusCode3.NOT_FOUND
|
|
504
603
|
});
|
|
505
|
-
return
|
|
604
|
+
return false;
|
|
506
605
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
606
|
+
if (this.getEnvironment.hmrEnabled) {
|
|
607
|
+
if (!this.getEnvironment.hmrWatchPatterns || this.getEnvironment.hmrWatchPatterns.length === 0) {
|
|
608
|
+
SLogger(this.localLanguage).logger.warn({
|
|
609
|
+
title: TranslationLoader2.t("HMR_CONFIG_WARNING", this.localLanguage),
|
|
610
|
+
message: "HMR enabled but no watch patterns defined"
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Starts the HTTP server and sets up event listeners.
|
|
618
|
+
*
|
|
619
|
+
* @method startHttpServer
|
|
620
|
+
* @private
|
|
621
|
+
*
|
|
622
|
+
* @param {(env: IEnvVariables) => void} [databaseCallback] - Database connection callback
|
|
623
|
+
*
|
|
624
|
+
* @returns {serverWebApp | undefined} HTTP server instance or undefined if startup fails
|
|
625
|
+
*
|
|
626
|
+
* @throws {Error} If server fails to start
|
|
627
|
+
*/
|
|
628
|
+
startHttpServer(databaseCallback) {
|
|
629
|
+
try {
|
|
630
|
+
loaderTranslationFile(this.localLanguage);
|
|
631
|
+
const port = Number(this.getEnvironment.appPort);
|
|
632
|
+
const host = this.getEnvironment.appHost;
|
|
633
|
+
this.server = this.expressApp.listen(port, host, () => {
|
|
511
634
|
try {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (this.isWatcherEnabled) {
|
|
521
|
-
this.initializeFileWatcher();
|
|
522
|
-
}
|
|
523
|
-
this.infoWebApp();
|
|
524
|
-
} catch (err) {
|
|
525
|
-
SLogger(this.localLanguage).logger.error({
|
|
526
|
-
title: TranslationLoader2.t("STARTUP_ERROR", this.localLanguage),
|
|
527
|
-
message: err.message,
|
|
528
|
-
errorType: err.code,
|
|
529
|
-
stackTrace: err.stackTrace,
|
|
530
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
635
|
+
this.configureServerComponents(databaseCallback);
|
|
636
|
+
this.serverStatus = "READY";
|
|
637
|
+
SLogger(this.localLanguage).logger.info({
|
|
638
|
+
title: TranslationLoader2.t("SERVER_RUNNING_TITLE", this.localLanguage),
|
|
639
|
+
message: TranslationLoader2.t("SERVER_RUNNING_AT", this.localLanguage, {
|
|
640
|
+
server: `${host}:${port}`,
|
|
641
|
+
hmrEnabled: this.getEnvironment.hmrEnabled ? "with HMR" : "without HMR"
|
|
642
|
+
})
|
|
531
643
|
});
|
|
532
|
-
|
|
644
|
+
} catch (err) {
|
|
645
|
+
this.handleServerConfigurationError(err);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
this.setupServerEventListeners();
|
|
649
|
+
return this.server;
|
|
650
|
+
} catch (error) {
|
|
651
|
+
this.serverListenEvent.onEventError(
|
|
652
|
+
new Error(TranslationLoader2.t(
|
|
653
|
+
"HTTP_SERVER_FAILED",
|
|
654
|
+
this.localLanguage,
|
|
655
|
+
{ errorMessage: error.message }
|
|
656
|
+
))
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Configures server components (database, dependencies, routes, etc.).
|
|
662
|
+
*
|
|
663
|
+
* @method configureServerComponents
|
|
664
|
+
* @private
|
|
665
|
+
*
|
|
666
|
+
* @param {(env: IEnvVariables) => void} [databaseCallback] - Database connection callback
|
|
667
|
+
*
|
|
668
|
+
* @returns {void}
|
|
669
|
+
*
|
|
670
|
+
* @throws {Error} If component configuration fails
|
|
671
|
+
*/
|
|
672
|
+
configureServerComponents(databaseCallback) {
|
|
673
|
+
try {
|
|
674
|
+
loaderTranslationFile(this.localLanguage);
|
|
675
|
+
if (databaseCallback && typeof databaseCallback === "function") {
|
|
676
|
+
try {
|
|
677
|
+
databaseCallback(this.getEnvironment);
|
|
678
|
+
} catch (dbError) {
|
|
679
|
+
this.serverListenEvent.listenerError(
|
|
680
|
+
new Error(TranslationLoader2.t("DB_CON_FAILED", this.localLanguage, { dbErrorMessage: dbError.message }))
|
|
681
|
+
);
|
|
533
682
|
}
|
|
534
683
|
}
|
|
535
|
-
|
|
536
|
-
|
|
684
|
+
try {
|
|
685
|
+
new SContainer2(this.localLanguage, this.currentDependencies);
|
|
686
|
+
} catch (depError) {
|
|
687
|
+
this.serverListenEvent.listenerError(
|
|
688
|
+
new Error(TranslationLoader2.t("DEPENDENCY_INJECTION_FAILED", this.localLanguage, { depErrorMessage: depError.message }))
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
this.expressApp.use(express.static(path2.join(process4.cwd(), "public/template")));
|
|
692
|
+
this.registerRoutes(this.currentRoutes);
|
|
693
|
+
this.setupErrorHandling();
|
|
694
|
+
this.infoWebApp();
|
|
695
|
+
} catch (error) {
|
|
696
|
+
this.serverListenEvent.listenerError(
|
|
697
|
+
new Error(TranslationLoader2.t("SERVER_COMPONENT_CONFIG_FAILED", this.localLanguage, { errorMessage: error.message }))
|
|
698
|
+
);
|
|
699
|
+
throw error;
|
|
700
|
+
}
|
|
537
701
|
}
|
|
538
702
|
/**
|
|
539
|
-
*
|
|
703
|
+
* Handles server configuration errors.
|
|
704
|
+
*
|
|
705
|
+
* @method handleServerConfigurationError
|
|
706
|
+
* @private
|
|
707
|
+
*
|
|
708
|
+
* @param {any} err - The error that occurred
|
|
709
|
+
*
|
|
710
|
+
* @returns {void}
|
|
540
711
|
*/
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
this.
|
|
549
|
-
SLogger(this.localLanguage).logger.error({
|
|
550
|
-
title: TranslationLoader2.t("TRANSFORM_ERROR", this.localLanguage),
|
|
551
|
-
message: error.message,
|
|
552
|
-
errorType: error.name,
|
|
553
|
-
stackTrace: error.stackTrace,
|
|
554
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
this.errorEmitter.on("error", (error) => {
|
|
558
|
-
SLogger(this.localLanguage).logger.info({
|
|
559
|
-
title: TranslationLoader2.t("ERROR_EMITTED", this.localLanguage),
|
|
560
|
-
message: error.message
|
|
561
|
-
});
|
|
562
|
-
});
|
|
563
|
-
this.errorEmitter.on("hotReload", (data) => {
|
|
564
|
-
SLogger(this.localLanguage).logger.info({
|
|
565
|
-
title: TranslationLoader2.t("HOT_RELOAD_EVENT", this.localLanguage),
|
|
566
|
-
message: `Hot reload triggered for ${data.file}`
|
|
567
|
-
});
|
|
568
|
-
});
|
|
712
|
+
handleServerConfigurationError(err) {
|
|
713
|
+
loaderTranslationFile(this.localLanguage);
|
|
714
|
+
this.serverStatus = "ERROR";
|
|
715
|
+
this.serverListenEvent.onEventError(err);
|
|
716
|
+
try {
|
|
717
|
+
SServerStartError(err, this.environmentPath);
|
|
718
|
+
} catch (startError) {
|
|
719
|
+
this.serverListenEvent.listenerError(startError);
|
|
569
720
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Handles general startup errors.
|
|
724
|
+
*
|
|
725
|
+
* @method handleStartupError
|
|
726
|
+
* @private
|
|
727
|
+
*
|
|
728
|
+
* @param {any} error - The startup error
|
|
729
|
+
*
|
|
730
|
+
* @returns {void}
|
|
731
|
+
*/
|
|
732
|
+
handleStartupError(error) {
|
|
733
|
+
loaderTranslationFile(this.localLanguage);
|
|
734
|
+
this.serverStatus = "ERROR";
|
|
735
|
+
this.serverListenEvent.listenerError(error);
|
|
736
|
+
SLogger(this.localLanguage).logger.error({
|
|
737
|
+
title: TranslationLoader2.t("GLOBAL_STARTUP_ERROR", this.localLanguage),
|
|
738
|
+
message: error.message,
|
|
739
|
+
errorType: error.name || "StartupError",
|
|
740
|
+
stackTrace: error.stack,
|
|
741
|
+
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Sets up Node.js process event listeners.
|
|
746
|
+
*
|
|
747
|
+
* @method setupProcessEventListeners
|
|
748
|
+
* @private
|
|
749
|
+
*
|
|
750
|
+
* @returns {void}
|
|
751
|
+
*
|
|
752
|
+
* @remarks
|
|
753
|
+
* Listens for:
|
|
754
|
+
* - Process exit events
|
|
755
|
+
* - Uncaught exceptions
|
|
756
|
+
* - Unhandled rejections
|
|
757
|
+
* - System signals (SIGINT, SIGTERM)
|
|
758
|
+
*/
|
|
759
|
+
setupProcessEventListeners() {
|
|
760
|
+
loaderTranslationFile(this.localLanguage);
|
|
761
|
+
process4.on(CEvent.beforeExit, (code) => {
|
|
762
|
+
this.serverListenEvent.processBeforeExit(code);
|
|
763
|
+
});
|
|
764
|
+
process4.on(CEvent.disconnect, () => {
|
|
765
|
+
this.serverListenEvent.processDisconnected();
|
|
766
|
+
});
|
|
767
|
+
process4.on(CEvent.exit, (code) => {
|
|
768
|
+
this.serverListenEvent.exited(code);
|
|
769
|
+
});
|
|
770
|
+
process4.on(CEvent.message, (message) => {
|
|
771
|
+
this.serverListenEvent.message(message);
|
|
772
|
+
});
|
|
773
|
+
process4.on(CEvent.multipleResolves, (type, promise, reason) => {
|
|
774
|
+
this.serverListenEvent.multipleResolves(type, promise, reason);
|
|
775
|
+
});
|
|
776
|
+
process4.on(CEvent.rejectionHandled, (promise) => {
|
|
777
|
+
this.serverListenEvent.promiseRejectionHandled(promise);
|
|
778
|
+
});
|
|
779
|
+
process4.on(CEvent.uncaughtException, (error) => {
|
|
780
|
+
this.serverListenEvent.uncaughtException(error);
|
|
781
|
+
});
|
|
782
|
+
process4.on(CEvent.uncaughtExceptionMonitor, (error) => {
|
|
783
|
+
this.serverListenEvent.uncaughtExceptionMonitor(error);
|
|
784
|
+
});
|
|
785
|
+
process4.on(CEvent.unhandledRejection, (reason, promise) => {
|
|
786
|
+
this.serverListenEvent.unhandledRejection(reason, promise);
|
|
787
|
+
});
|
|
788
|
+
process4.on(CEvent.warning, (warning) => {
|
|
789
|
+
this.serverListenEvent.warning(warning);
|
|
790
|
+
});
|
|
791
|
+
process4.on(CEvent.sigint, () => {
|
|
792
|
+
this.serverListenEvent.processInterrupted();
|
|
793
|
+
});
|
|
794
|
+
process4.on(CEvent.sigterm, (signal) => {
|
|
795
|
+
this.serverListenEvent.sigtermSignalReceived(signal);
|
|
573
796
|
});
|
|
574
797
|
}
|
|
575
798
|
/**
|
|
576
|
-
*
|
|
799
|
+
* Sets up HTTP server event listeners.
|
|
800
|
+
*
|
|
801
|
+
* @method setupServerEventListeners
|
|
802
|
+
* @private
|
|
803
|
+
*
|
|
804
|
+
* @returns {void}
|
|
805
|
+
*
|
|
806
|
+
* @remarks
|
|
807
|
+
* Configures listeners for:
|
|
808
|
+
* - Server errors
|
|
809
|
+
* - Connection closing
|
|
810
|
+
* - Connection dropping
|
|
811
|
+
* - HTTP requests (for logging)
|
|
812
|
+
*
|
|
813
|
+
* @listens Server#error - Server error events
|
|
814
|
+
* @listens Server#close - Server closing events
|
|
815
|
+
* @listens Server#drop - Connection drop events
|
|
816
|
+
* @listens Server#request - HTTP request events
|
|
577
817
|
*/
|
|
578
|
-
|
|
579
|
-
|
|
818
|
+
setupServerEventListeners() {
|
|
819
|
+
loaderTranslationFile(this.localLanguage);
|
|
820
|
+
if (!this.server) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
580
823
|
this.server.on(eventName2.error, (err) => {
|
|
581
824
|
this.serverListenEvent.onEventError(err);
|
|
582
825
|
});
|
|
@@ -599,544 +842,509 @@ var WebServerCore = class {
|
|
|
599
842
|
});
|
|
600
843
|
}
|
|
601
844
|
/**
|
|
602
|
-
*
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
this.fileWatcher.startWatching();
|
|
609
|
-
this.fileWatcher.setHotReload(true);
|
|
610
|
-
SLogger(this.localLanguage).logger.info({
|
|
611
|
-
title: TranslationLoader2.t("WATCHER_INITIALIZED", this.localLanguage),
|
|
612
|
-
message: "File watcher has been initialized successfully"
|
|
613
|
-
});
|
|
614
|
-
} catch (error) {
|
|
615
|
-
SLogger(this.localLanguage).logger.error({
|
|
616
|
-
title: TranslationLoader2.t("WATCHER_INIT_ERROR", this.localLanguage),
|
|
617
|
-
message: `Failed to initialize file watcher: ${error.message}`,
|
|
618
|
-
errorType: "WatcherInitializationError",
|
|
619
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Setup watcher events
|
|
845
|
+
* Sets up error handling middleware and event emitters.
|
|
846
|
+
*
|
|
847
|
+
* @method setupErrorHandling
|
|
848
|
+
* @private
|
|
849
|
+
*
|
|
850
|
+
* @returns {void}
|
|
625
851
|
*/
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
852
|
+
setupErrorHandling() {
|
|
853
|
+
loaderTranslationFile(this.localLanguage);
|
|
854
|
+
SLogger(this.localLanguage).logger.info({
|
|
855
|
+
title: TranslationLoader2.t("SETTING_UP", this.localLanguage),
|
|
856
|
+
message: TranslationLoader2.t("SETTING_UP_ERROR", this.localLanguage)
|
|
857
|
+
});
|
|
858
|
+
this.errorEmitter = eventProcessHandler(this.localLanguage, this.expressApp);
|
|
859
|
+
if (this.errorEmitter) {
|
|
860
|
+
this.expressApp.use((err, req, res, next) => {
|
|
861
|
+
this.serverListenEvent.expressErrorHandlingMiddleware(
|
|
862
|
+
this.errorEmitter,
|
|
863
|
+
err,
|
|
864
|
+
req,
|
|
865
|
+
res,
|
|
866
|
+
next
|
|
867
|
+
);
|
|
634
868
|
});
|
|
635
|
-
this.
|
|
636
|
-
this.
|
|
869
|
+
this.errorEmitter.on("transformError", (error) => {
|
|
870
|
+
this.serverListenEvent.listenerError(error);
|
|
637
871
|
});
|
|
638
|
-
this.
|
|
639
|
-
|
|
640
|
-
title: TranslationLoader2.t("WATCHER_STARTED", this.localLanguage),
|
|
641
|
-
message: TranslationLoader2.t("FILE_WATCHER_ACTIVE", this.localLanguage)
|
|
642
|
-
});
|
|
872
|
+
this.errorEmitter.on("error", (error) => {
|
|
873
|
+
this.serverListenEvent.listenerError(error);
|
|
643
874
|
});
|
|
644
|
-
this.
|
|
875
|
+
this.errorEmitter.on("hotReload", (data) => {
|
|
645
876
|
SLogger(this.localLanguage).logger.info({
|
|
646
|
-
title: TranslationLoader2.t("
|
|
647
|
-
message:
|
|
877
|
+
title: TranslationLoader2.t("HOT_RELOAD_EVENT", this.localLanguage),
|
|
878
|
+
message: `Hot reload triggered for ${data.file}`
|
|
648
879
|
});
|
|
649
880
|
});
|
|
650
|
-
} catch (error) {
|
|
651
|
-
SLogger(this.localLanguage).logger.error({
|
|
652
|
-
title: TranslationLoader2.t("WATCHER_EVENTS_ERROR", this.localLanguage),
|
|
653
|
-
message: `Failed to setup watcher events: ${error.message}`,
|
|
654
|
-
errorType: "WatcherEventsError",
|
|
655
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
656
|
-
});
|
|
657
881
|
}
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Handle file changes detected by watcher
|
|
661
|
-
*/
|
|
662
|
-
handleFileChange(data) {
|
|
663
|
-
const { event: event2, action, requiresReload } = data;
|
|
664
882
|
SLogger(this.localLanguage).logger.info({
|
|
665
|
-
title: TranslationLoader2.t("
|
|
666
|
-
message: TranslationLoader2.t(
|
|
667
|
-
"PROCESSING_FILE_CHANGE",
|
|
668
|
-
this.localLanguage
|
|
669
|
-
).replace(
|
|
670
|
-
"{file}",
|
|
671
|
-
path2.basename(event2.filePath)
|
|
672
|
-
).replace(
|
|
673
|
-
"{action}",
|
|
674
|
-
action
|
|
675
|
-
)
|
|
676
|
-
});
|
|
677
|
-
if (this.errorEmitter) {
|
|
678
|
-
this.errorEmitter.emit("fileChanged", {
|
|
679
|
-
file: event2.filePath,
|
|
680
|
-
type: event2.extension,
|
|
681
|
-
action,
|
|
682
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
switch (action) {
|
|
686
|
-
case "reloadEnvironment":
|
|
687
|
-
this.reloadEnvironmentConfig();
|
|
688
|
-
break;
|
|
689
|
-
case "reloadConfig":
|
|
690
|
-
this.reloadConfigurationFiles();
|
|
691
|
-
break;
|
|
692
|
-
case "reloadRoutes":
|
|
693
|
-
this.reloadApplicationRoutes(event2.filePath);
|
|
694
|
-
break;
|
|
695
|
-
case "reloadDependencies":
|
|
696
|
-
this.reloadDependencies();
|
|
697
|
-
break;
|
|
698
|
-
case "notifyOnly":
|
|
699
|
-
this.notifyFileChange(event2);
|
|
700
|
-
break;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Handle hot reload requested by watcher
|
|
705
|
-
*/
|
|
706
|
-
handleHotReload(data) {
|
|
707
|
-
const { file, type, action } = data;
|
|
708
|
-
SLogger(this.localLanguage).logger.info({
|
|
709
|
-
title: TranslationLoader2.t("HOT_RELOAD_STARTING", this.localLanguage),
|
|
710
|
-
message: TranslationLoader2.t("HOT_RELOAD_FOR_FILE", this.localLanguage).replace("{file}", path2.basename(file)).replace("{type}", type)
|
|
711
|
-
});
|
|
712
|
-
if (this.errorEmitter) {
|
|
713
|
-
this.errorEmitter.emit("hotReload", {
|
|
714
|
-
file,
|
|
715
|
-
type,
|
|
716
|
-
action,
|
|
717
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
switch (action) {
|
|
721
|
-
case "reloadEnvironment":
|
|
722
|
-
this.executeHotReloadEnvironment(file);
|
|
723
|
-
break;
|
|
724
|
-
case "reloadConfig":
|
|
725
|
-
this.executeHotReloadConfig(file);
|
|
726
|
-
break;
|
|
727
|
-
case "reloadRoutes":
|
|
728
|
-
this.executeHotReloadRoutes(file);
|
|
729
|
-
break;
|
|
730
|
-
case "reloadDependencies":
|
|
731
|
-
this.executeHotReloadDependencies(file);
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
/**
|
|
736
|
-
* Handle watcher errors
|
|
737
|
-
*/
|
|
738
|
-
handleWatcherError(error) {
|
|
739
|
-
SLogger(this.localLanguage).logger.error({
|
|
740
|
-
title: TranslationLoader2.t("WATCHER_SYSTEM_ERROR", this.localLanguage),
|
|
741
|
-
message: error.message || "Unknown watcher system error",
|
|
742
|
-
errorType: "WatcherSystemError",
|
|
743
|
-
stackTrace: error.stack,
|
|
744
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
883
|
+
title: TranslationLoader2.t("ERROR_HANDLING", this.localLanguage),
|
|
884
|
+
message: TranslationLoader2.t("ERROR_HANDLING_CONFIGURED", this.localLanguage)
|
|
745
885
|
});
|
|
746
886
|
}
|
|
747
887
|
/**
|
|
748
|
-
*
|
|
888
|
+
* Registers routes with the Express application.
|
|
889
|
+
*
|
|
890
|
+
* @method registerRoutes
|
|
891
|
+
* @private
|
|
892
|
+
*
|
|
893
|
+
* @param {any[]} allFeatureRoutes - Array of feature routes to register
|
|
894
|
+
*
|
|
895
|
+
* @returns {void}
|
|
749
896
|
*/
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
897
|
+
registerRoutes(allFeatureRoutes) {
|
|
898
|
+
allFeatureRoutes.forEach((router) => {
|
|
899
|
+
if (router.routes) {
|
|
900
|
+
router.routes.forEach((route) => {
|
|
901
|
+
this.expressApp.use(route.path, route.handler);
|
|
902
|
+
});
|
|
903
|
+
}
|
|
754
904
|
});
|
|
755
905
|
}
|
|
756
906
|
/**
|
|
757
|
-
*
|
|
907
|
+
* Displays server information.
|
|
908
|
+
*
|
|
909
|
+
* @method infoWebApp
|
|
910
|
+
* @private
|
|
911
|
+
*
|
|
912
|
+
* @returns {void}
|
|
758
913
|
*/
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
});
|
|
766
|
-
this.notifyEnvironmentReload();
|
|
767
|
-
} catch (error) {
|
|
768
|
-
SLogger(this.localLanguage).logger.error({
|
|
769
|
-
title: TranslationLoader2.t("ENV_RELOAD_FAILED", this.localLanguage),
|
|
770
|
-
message: error.message,
|
|
771
|
-
errorType: "EnvironmentReloadError",
|
|
772
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
773
|
-
});
|
|
774
|
-
}
|
|
914
|
+
infoWebApp() {
|
|
915
|
+
loaderTranslationFile(this.localLanguage);
|
|
916
|
+
this.serverUtility.infoServer(
|
|
917
|
+
this.getEnvironment.appHost,
|
|
918
|
+
Number(this.getEnvironment.appPort)
|
|
919
|
+
);
|
|
775
920
|
}
|
|
776
921
|
/**
|
|
777
|
-
*
|
|
922
|
+
* Starts the Hot Module Replacement (HMR) file watching system.
|
|
923
|
+
*
|
|
924
|
+
* @method startHMR
|
|
925
|
+
* @private
|
|
926
|
+
*
|
|
927
|
+
* @returns {void}
|
|
928
|
+
*
|
|
929
|
+
* @remarks
|
|
930
|
+
* Configures file watcher based on environment variables:
|
|
931
|
+
* - HMR_ENABLED: Enable/disable HMR
|
|
932
|
+
* - HMR_WATCH_PATTERNS: Files to watch
|
|
933
|
+
* - HMR_IGNORE_PATTERNS: Files to ignore
|
|
934
|
+
*
|
|
935
|
+
* @throws {Error} If HMR configuration is invalid
|
|
778
936
|
*/
|
|
779
|
-
|
|
937
|
+
startHMR() {
|
|
780
938
|
try {
|
|
781
|
-
const newEnv = getEnvironnementValue2(this.environmentPath);
|
|
782
|
-
Object.keys(newEnv).forEach((key) => {
|
|
783
|
-
this.getEnvironment[key] = newEnv[key];
|
|
784
|
-
});
|
|
785
939
|
loaderTranslationFile(this.localLanguage);
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
940
|
+
const hmrConfig = this.getEnvironment;
|
|
941
|
+
if (!hmrConfig.hmrEnabled) {
|
|
942
|
+
SLogger(this.localLanguage).logger.info({
|
|
943
|
+
title: TranslationLoader2.t("HMR_DISABLED", this.localLanguage),
|
|
944
|
+
message: "HMR is disabled in configuration"
|
|
945
|
+
});
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (!hmrConfig.hmrWatchPatterns || hmrConfig.hmrWatchPatterns.length === 0) {
|
|
949
|
+
SLogger(this.localLanguage).logger.error({
|
|
950
|
+
title: TranslationLoader2.t("HMR_WATCH_PATTERNS_MISSING", this.localLanguage),
|
|
951
|
+
message: "No watch patterns defined for HMR",
|
|
952
|
+
errorType: "HMR Configuration Error",
|
|
953
|
+
httpCodeValue: HttpStatusCode3.BAD_REQUEST
|
|
954
|
+
});
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const watchPatterns = hmrConfig.hmrWatchPatterns;
|
|
958
|
+
const ignorePatterns = hmrConfig.hmrIgnorePatterns || [
|
|
959
|
+
"node_modules/**",
|
|
960
|
+
"dist/**",
|
|
961
|
+
"build/**",
|
|
962
|
+
"*.log",
|
|
963
|
+
".git/**"
|
|
964
|
+
];
|
|
965
|
+
const allPatterns = [
|
|
966
|
+
...watchPatterns,
|
|
967
|
+
...ignorePatterns.map((pattern) => `!${pattern}`)
|
|
968
|
+
];
|
|
969
|
+
this.fileWatcher = chokidar.watch(allPatterns, {
|
|
970
|
+
ignored: /(^|[/\\])\../,
|
|
971
|
+
persistent: true,
|
|
972
|
+
ignoreInitial: true,
|
|
973
|
+
awaitWriteFinish: {
|
|
974
|
+
stabilityThreshold: 300,
|
|
975
|
+
pollInterval: 100
|
|
976
|
+
},
|
|
977
|
+
cwd: process4.cwd(),
|
|
978
|
+
depth: 10
|
|
796
979
|
});
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
* Reload configuration files
|
|
801
|
-
*/
|
|
802
|
-
reloadConfigurationFiles() {
|
|
803
|
-
try {
|
|
804
|
-
loaderTranslationFile(this.localLanguage);
|
|
980
|
+
this.fileWatcher.on("ready", () => this.onHMRWatcherReady(watchPatterns, ignorePatterns)).on("change", (filePath) => this.handleFileChange(filePath)).on("add", (filePath) => this.handleFileChange(filePath, "added")).on("unlink", (filePath) => this.handleFileChange(filePath, "deleted")).on("error", (error) => this.onHMRWatcherError(error));
|
|
981
|
+
this.hmrRestartCount = 0;
|
|
982
|
+
this.lastHmrRestartTime = Date.now();
|
|
805
983
|
SLogger(this.localLanguage).logger.info({
|
|
806
|
-
title: TranslationLoader2.t("
|
|
807
|
-
message: TranslationLoader2.t("
|
|
984
|
+
title: TranslationLoader2.t("HMR_STARTED", this.localLanguage),
|
|
985
|
+
message: TranslationLoader2.t("HMR_MONITORING_STARTED", this.localLanguage)
|
|
808
986
|
});
|
|
809
987
|
} catch (error) {
|
|
810
988
|
SLogger(this.localLanguage).logger.error({
|
|
811
|
-
title: TranslationLoader2.t("
|
|
989
|
+
title: TranslationLoader2.t("HMR_START_FAILED", this.localLanguage),
|
|
812
990
|
message: error.message,
|
|
813
|
-
errorType: "
|
|
814
|
-
|
|
991
|
+
errorType: "HMR Error",
|
|
992
|
+
stackTrace: error.stack
|
|
815
993
|
});
|
|
816
994
|
}
|
|
817
995
|
}
|
|
818
996
|
/**
|
|
819
|
-
*
|
|
997
|
+
* Handles file change events with debouncing.
|
|
998
|
+
*
|
|
999
|
+
* @method handleFileChange
|
|
1000
|
+
* @private
|
|
1001
|
+
*
|
|
1002
|
+
* @param {string} filePath - Path of the changed file
|
|
1003
|
+
* @param {string} [action="modified"] - Type of file change (modified/added/deleted)
|
|
1004
|
+
*
|
|
1005
|
+
* @returns {void}
|
|
1006
|
+
*
|
|
1007
|
+
* @remarks
|
|
1008
|
+
* Uses debouncing to prevent multiple rapid reloads.
|
|
1009
|
+
* Debounce time configurable via HMR_DEBOUNCE_MS environment variable.
|
|
820
1010
|
*/
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
SLogger(this.localLanguage).logger.info({
|
|
826
|
-
title: TranslationLoader2.t("TRANSLATIONS_RELOADED", this.localLanguage),
|
|
827
|
-
message: TranslationLoader2.t("TRANSLATIONS_HOT_RELOAD_COMPLETE", this.localLanguage).replace("{file}", path2.basename(filePath))
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
} catch (error) {
|
|
831
|
-
SLogger(this.localLanguage).logger.error({
|
|
832
|
-
title: TranslationLoader2.t("HOT_RELOAD_CONFIG_FAILED", this.localLanguage),
|
|
833
|
-
message: error.message,
|
|
834
|
-
errorType: "HotReloadConfigError",
|
|
835
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
836
|
-
});
|
|
1011
|
+
handleFileChange(filePath, action = "modified") {
|
|
1012
|
+
const debounceMs = this.getEnvironment.hmrDebounceMs || 500;
|
|
1013
|
+
if (this.hmrDebounceTimeout) {
|
|
1014
|
+
clearTimeout(this.hmrDebounceTimeout);
|
|
837
1015
|
}
|
|
1016
|
+
this.hmrDebounceTimeout = setTimeout(async () => {
|
|
1017
|
+
await this.triggerHotReload(filePath, action);
|
|
1018
|
+
}, debounceMs);
|
|
1019
|
+
SLogger(this.localLanguage).logger.info({
|
|
1020
|
+
title: TranslationLoader2.t("FILE_CHANGE_DETECTED", this.localLanguage),
|
|
1021
|
+
message: `File ${action}: ${filePath}`
|
|
1022
|
+
});
|
|
838
1023
|
}
|
|
839
1024
|
/**
|
|
840
|
-
*
|
|
1025
|
+
* Triggers a hot reload operation.
|
|
1026
|
+
*
|
|
1027
|
+
* @method triggerHotReload
|
|
1028
|
+
* @private
|
|
1029
|
+
*
|
|
1030
|
+
* @param {string} filePath - Path of the changed file
|
|
1031
|
+
* @param {string} action - Type of file change
|
|
1032
|
+
*
|
|
1033
|
+
* @returns {Promise<void>}
|
|
1034
|
+
*
|
|
1035
|
+
* @remarks
|
|
1036
|
+
* - Checks if reload is already in progress
|
|
1037
|
+
* - Validates restart limits
|
|
1038
|
+
* - Performs appropriate reload actions based on file type
|
|
1039
|
+
* - Emits hotReload event
|
|
841
1040
|
*/
|
|
842
|
-
|
|
1041
|
+
async triggerHotReload(filePath, action) {
|
|
1042
|
+
if (this.hmrRestartPending) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (!this.canProceedWithHMRRestart()) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
this.hmrRestartPending = true;
|
|
1049
|
+
this.hmrRestartCount++;
|
|
1050
|
+
this.lastHmrRestartTime = Date.now();
|
|
843
1051
|
try {
|
|
1052
|
+
loaderTranslationFile(this.localLanguage);
|
|
844
1053
|
SLogger(this.localLanguage).logger.info({
|
|
845
|
-
title: TranslationLoader2.t("
|
|
846
|
-
message: TranslationLoader2.t("
|
|
1054
|
+
title: TranslationLoader2.t("HOT_RELOAD_STARTING", this.localLanguage),
|
|
1055
|
+
message: TranslationLoader2.t("RELOADING_APPLICATION", this.localLanguage, {
|
|
1056
|
+
file: filePath,
|
|
1057
|
+
action
|
|
1058
|
+
})
|
|
847
1059
|
});
|
|
848
|
-
if (filePath.includes("routes") || filePath.includes("controller")) {
|
|
849
|
-
this.reloadSpecificRoute(filePath);
|
|
850
|
-
}
|
|
851
1060
|
if (this.errorEmitter) {
|
|
852
|
-
this.errorEmitter.emit("
|
|
853
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
1061
|
+
this.errorEmitter.emit("hotReload", {
|
|
854
1062
|
file: filePath,
|
|
855
|
-
|
|
1063
|
+
action,
|
|
1064
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1065
|
+
restartCount: this.hmrRestartCount
|
|
856
1066
|
});
|
|
857
1067
|
}
|
|
858
|
-
|
|
859
|
-
SLogger(this.localLanguage).logger.
|
|
860
|
-
title: TranslationLoader2.t("
|
|
861
|
-
message:
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* Execute hot reload for routes
|
|
869
|
-
*/
|
|
870
|
-
executeHotReloadRoutes(filePath) {
|
|
871
|
-
try {
|
|
872
|
-
SLogger(this.localLanguage).logger.info({
|
|
873
|
-
title: TranslationLoader2.t("HOT_RELOAD_ROUTES_START", this.localLanguage),
|
|
874
|
-
message: TranslationLoader2.t("ROUTES_HOT_RELOADING", this.localLanguage).replace("{file}", path2.basename(filePath))
|
|
875
|
-
});
|
|
876
|
-
this.reloadRouterForFile(filePath);
|
|
877
|
-
SLogger(this.localLanguage).logger.info({
|
|
878
|
-
title: TranslationLoader2.t("HOT_RELOAD_ROUTES_SUCCESS", this.localLanguage),
|
|
879
|
-
message: TranslationLoader2.t("ROUTES_HOT_RELOAD_COMPLETE", this.localLanguage)
|
|
1068
|
+
await this.performHotReloadActions(filePath);
|
|
1069
|
+
SLogger(this.localLanguage).logger.success({
|
|
1070
|
+
title: TranslationLoader2.t("HOT_RELOAD_COMPLETE", this.localLanguage),
|
|
1071
|
+
message: TranslationLoader2.t("APPLICATION_RELOADED", this.localLanguage, {
|
|
1072
|
+
file: filePath,
|
|
1073
|
+
restartCount: this.hmrRestartCount,
|
|
1074
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1075
|
+
})
|
|
880
1076
|
});
|
|
881
1077
|
} catch (error) {
|
|
882
1078
|
SLogger(this.localLanguage).logger.error({
|
|
883
|
-
title: TranslationLoader2.t("
|
|
1079
|
+
title: TranslationLoader2.t("HOT_RELOAD_FAILED", this.localLanguage),
|
|
884
1080
|
message: error.message,
|
|
885
|
-
errorType: "
|
|
1081
|
+
errorType: "HotReloadError",
|
|
1082
|
+
stackTrace: error.stack,
|
|
886
1083
|
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
887
1084
|
});
|
|
1085
|
+
} finally {
|
|
1086
|
+
this.hmrRestartPending = false;
|
|
888
1087
|
}
|
|
889
1088
|
}
|
|
890
1089
|
/**
|
|
891
|
-
*
|
|
1090
|
+
* Performs appropriate hot reload actions based on file type.
|
|
1091
|
+
*
|
|
1092
|
+
* @method performHotReloadActions
|
|
1093
|
+
* @private
|
|
1094
|
+
*
|
|
1095
|
+
* @param {string} filePath - Path of the changed file
|
|
1096
|
+
*
|
|
1097
|
+
* @returns {Promise<void>}
|
|
1098
|
+
*
|
|
1099
|
+
* @remarks
|
|
1100
|
+
* Different actions for different file types:
|
|
1101
|
+
* - .json/.env: Reload translations
|
|
1102
|
+
* - routes/controller files: Reload routes
|
|
1103
|
+
* - config/.env files: Reload dependencies
|
|
892
1104
|
*/
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
title: TranslationLoader2.t("HOT_RELOAD_DEPS_START", this.localLanguage),
|
|
897
|
-
message: TranslationLoader2.t(
|
|
898
|
-
"DEPENDENCIES_HOT_RELOADING",
|
|
899
|
-
this.localLanguage
|
|
900
|
-
).replace("{file}", path2.basename(filePath))
|
|
901
|
-
});
|
|
902
|
-
this.reloadDependencies();
|
|
903
|
-
SLogger(this.localLanguage).logger.info({
|
|
904
|
-
title: TranslationLoader2.t("HOT_RELOAD_DEPS_SUCCESS", this.localLanguage),
|
|
905
|
-
message: TranslationLoader2.t("DEPENDENCIES_HOT_RELOAD_COMPLETE", this.localLanguage)
|
|
906
|
-
});
|
|
907
|
-
} catch (error) {
|
|
908
|
-
SLogger(this.localLanguage).logger.error({
|
|
909
|
-
title: TranslationLoader2.t("HOT_RELOAD_DEPS_FAILED", this.localLanguage),
|
|
910
|
-
message: error.message,
|
|
911
|
-
errorType: "HotReloadDependenciesError",
|
|
912
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
913
|
-
});
|
|
1105
|
+
async performHotReloadActions(filePath) {
|
|
1106
|
+
if (filePath.includes(".json") || filePath.endsWith(".env")) {
|
|
1107
|
+
loaderTranslationFile(this.localLanguage);
|
|
914
1108
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
if (this.errorEmitter) {
|
|
921
|
-
this.errorEmitter.emit("environmentReloaded", {
|
|
922
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
923
|
-
environment: this.getEnvironment
|
|
924
|
-
});
|
|
1109
|
+
if (filePath.includes("routes") || filePath.includes("controller")) {
|
|
1110
|
+
await this.reloadRoutes();
|
|
1111
|
+
}
|
|
1112
|
+
if (filePath.includes("config") || filePath.includes(".env")) {
|
|
1113
|
+
await this.reloadDependencies();
|
|
925
1114
|
}
|
|
926
1115
|
}
|
|
927
1116
|
/**
|
|
928
|
-
*
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
*
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
SLogger(this.localLanguage).logger.info({
|
|
941
|
-
title: "Router Reload",
|
|
942
|
-
message: `Reloading router for file: ${filePath}`
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
|
-
/**
|
|
946
|
-
* Reload configurations
|
|
1117
|
+
* Reloads routes dynamically.
|
|
1118
|
+
*
|
|
1119
|
+
* @method reloadRoutes
|
|
1120
|
+
* @private
|
|
1121
|
+
*
|
|
1122
|
+
* @returns {Promise<void>}
|
|
1123
|
+
*
|
|
1124
|
+
* @throws {Error} If route reloading fails
|
|
1125
|
+
*
|
|
1126
|
+
* @remarks
|
|
1127
|
+
* This method should be implemented based on your architecture.
|
|
1128
|
+
* It should reload route modules from the filesystem.
|
|
947
1129
|
*/
|
|
948
|
-
|
|
1130
|
+
async reloadRoutes() {
|
|
949
1131
|
try {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1132
|
+
SLogger(this.localLanguage).logger.info({
|
|
1133
|
+
title: TranslationLoader2.t("ROUTES_RELOADED", this.localLanguage),
|
|
1134
|
+
message: "Routes dynamically reloaded"
|
|
953
1135
|
});
|
|
954
|
-
loaderTranslationFile(this.localLanguage);
|
|
955
1136
|
} catch (error) {
|
|
956
|
-
throw new Error(`
|
|
1137
|
+
throw new Error(`Route reload failed: ${error.message}`);
|
|
957
1138
|
}
|
|
958
1139
|
}
|
|
959
1140
|
/**
|
|
960
|
-
*
|
|
1141
|
+
* Reloads dependencies dynamically.
|
|
1142
|
+
*
|
|
1143
|
+
* @method reloadDependencies
|
|
1144
|
+
* @private
|
|
1145
|
+
*
|
|
1146
|
+
* @returns {Promise<void>}
|
|
1147
|
+
*
|
|
1148
|
+
* @throws {Error} If dependency reloading fails
|
|
961
1149
|
*/
|
|
962
|
-
reloadDependencies() {
|
|
1150
|
+
async reloadDependencies() {
|
|
963
1151
|
try {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1152
|
+
if (this.currentDependencies.length > 0) {
|
|
1153
|
+
new SContainer2(this.localLanguage, this.currentDependencies);
|
|
1154
|
+
SLogger(this.localLanguage).logger.info({
|
|
1155
|
+
title: TranslationLoader2.t("DEPENDENCIES_RELOADED", this.localLanguage),
|
|
1156
|
+
message: "Dependencies reloaded"
|
|
1157
|
+
});
|
|
968
1158
|
}
|
|
969
1159
|
} catch (error) {
|
|
970
1160
|
throw new Error(`Dependency reload failed: ${error.message}`);
|
|
971
1161
|
}
|
|
972
1162
|
}
|
|
973
1163
|
/**
|
|
974
|
-
*
|
|
1164
|
+
* Checks if HMR restart can proceed based on configuration limits.
|
|
1165
|
+
*
|
|
1166
|
+
* @method canProceedWithHMRRestart
|
|
1167
|
+
* @private
|
|
1168
|
+
*
|
|
1169
|
+
* @returns {boolean} True if restart can proceed, false otherwise
|
|
1170
|
+
*
|
|
1171
|
+
* @remarks
|
|
1172
|
+
* Checks:
|
|
1173
|
+
* - Auto-restart enabled/disabled
|
|
1174
|
+
* - Maximum restarts per minute limit
|
|
975
1175
|
*/
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
|
|
1176
|
+
canProceedWithHMRRestart() {
|
|
1177
|
+
const hmrConfig = this.getEnvironment;
|
|
1178
|
+
if (!hmrConfig.hmrAutoRestarts) {
|
|
1179
|
+
SLogger(this.localLanguage).logger.warn({
|
|
1180
|
+
title: TranslationLoader2.t("HMR_AUTO_RESTART_DISABLED", this.localLanguage),
|
|
1181
|
+
message: "HMR auto-restart disabled"
|
|
1182
|
+
});
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
const maxRestarts = hmrConfig.hmrMaxRestarts || 5;
|
|
1186
|
+
const now = Date.now();
|
|
1187
|
+
const oneMinuteAgo = now - 6e4;
|
|
1188
|
+
if (this.lastHmrRestartTime < oneMinuteAgo) {
|
|
1189
|
+
this.hmrRestartCount = 0;
|
|
1190
|
+
}
|
|
1191
|
+
if (this.hmrRestartCount >= maxRestarts) {
|
|
1192
|
+
const nextReset = Math.ceil((this.lastHmrRestartTime + 6e4 - now) / 1e3);
|
|
1193
|
+
SLogger(this.localLanguage).logger.error({
|
|
1194
|
+
title: TranslationLoader2.t("HMR_RESTART_LIMIT_EXCEEDED", this.localLanguage),
|
|
1195
|
+
message: TranslationLoader2.t("HMR_RESTART_LIMIT_MESSAGE", this.localLanguage, {
|
|
1196
|
+
max: maxRestarts,
|
|
1197
|
+
nextReset
|
|
1198
|
+
})
|
|
1199
|
+
});
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1202
|
+
return true;
|
|
984
1203
|
}
|
|
985
1204
|
/**
|
|
986
|
-
*
|
|
1205
|
+
* Called when the HMR watcher is ready.
|
|
1206
|
+
*
|
|
1207
|
+
* @method onHMRWatcherReady
|
|
1208
|
+
* @private
|
|
1209
|
+
*
|
|
1210
|
+
* @param {string[]} watchPatterns - Patterns being watched
|
|
1211
|
+
* @param {string[]} ignorePatterns - Patterns being ignored
|
|
1212
|
+
*
|
|
1213
|
+
* @returns {void}
|
|
987
1214
|
*/
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
const column = fileMatch ? parseInt(fileMatch[3], 10) : null;
|
|
997
|
-
const errorDetailMatch = errorMessage.match(/ERROR:\s*(.+?)(?:\n|$)/);
|
|
998
|
-
const errorDetail = errorDetailMatch ? errorDetailMatch[1].trim() : null;
|
|
999
|
-
return {
|
|
1000
|
-
message: errorMessage,
|
|
1001
|
-
file,
|
|
1002
|
-
line,
|
|
1003
|
-
column,
|
|
1004
|
-
errorDetail,
|
|
1005
|
-
tool
|
|
1006
|
-
};
|
|
1215
|
+
onHMRWatcherReady(watchPatterns, ignorePatterns) {
|
|
1216
|
+
SLogger(this.localLanguage).logger.info({
|
|
1217
|
+
title: TranslationLoader2.t("HMR_WATCHER_READY", this.localLanguage),
|
|
1218
|
+
message: TranslationLoader2.t("HMR_WATCHING_DETAILS", this.localLanguage, {
|
|
1219
|
+
watchCount: watchPatterns,
|
|
1220
|
+
ignoreCount: ignorePatterns
|
|
1221
|
+
})
|
|
1222
|
+
});
|
|
1007
1223
|
}
|
|
1008
1224
|
/**
|
|
1009
|
-
*
|
|
1225
|
+
* Handles HMR watcher errors.
|
|
1226
|
+
*
|
|
1227
|
+
* @method onHMRWatcherError
|
|
1228
|
+
* @private
|
|
1229
|
+
*
|
|
1230
|
+
* @param {Error} error - The watcher error
|
|
1231
|
+
*
|
|
1232
|
+
* @returns {void}
|
|
1010
1233
|
*/
|
|
1011
|
-
|
|
1012
|
-
this.
|
|
1013
|
-
this.
|
|
1014
|
-
|
|
1015
|
-
|
|
1234
|
+
onHMRWatcherError(error) {
|
|
1235
|
+
SLogger(this.localLanguage).logger.error({
|
|
1236
|
+
title: TranslationLoader2.t("HMR_WATCHER_ERROR", this.localLanguage),
|
|
1237
|
+
message: error.message,
|
|
1238
|
+
errorType: "FileWatcherError",
|
|
1239
|
+
stackTrace: error.stack
|
|
1240
|
+
});
|
|
1016
1241
|
}
|
|
1017
1242
|
/**
|
|
1018
|
-
*
|
|
1243
|
+
* Stops the HMR system.
|
|
1244
|
+
*
|
|
1245
|
+
* @method stopHMR
|
|
1246
|
+
* @private
|
|
1247
|
+
*
|
|
1248
|
+
* @returns {void}
|
|
1019
1249
|
*/
|
|
1020
|
-
|
|
1250
|
+
stopHMR() {
|
|
1021
1251
|
if (this.fileWatcher) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
SLogger(this.localLanguage).logger.info({
|
|
1025
|
-
title: TranslationLoader2.t("WATCHER_STOPPED", this.localLanguage),
|
|
1026
|
-
message: TranslationLoader2.t("FILE_WATCHER_STOPPED_GRACEFULLY", this.localLanguage)
|
|
1027
|
-
});
|
|
1028
|
-
} catch (error) {
|
|
1029
|
-
SLogger(this.localLanguage).logger.error({
|
|
1030
|
-
title: TranslationLoader2.t("WATCHER_STOP_ERROR", this.localLanguage),
|
|
1031
|
-
message: `Error stopping watcher: ${error.message}`,
|
|
1032
|
-
errorType: "WatcherStopError",
|
|
1033
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
1034
|
-
});
|
|
1035
|
-
} finally {
|
|
1036
|
-
this.fileWatcher = void 0;
|
|
1037
|
-
}
|
|
1252
|
+
this.fileWatcher.close();
|
|
1253
|
+
this.fileWatcher = null;
|
|
1038
1254
|
}
|
|
1255
|
+
if (this.hmrDebounceTimeout) {
|
|
1256
|
+
clearTimeout(this.hmrDebounceTimeout);
|
|
1257
|
+
this.hmrDebounceTimeout = null;
|
|
1258
|
+
}
|
|
1259
|
+
SLogger(this.localLanguage).logger.info({
|
|
1260
|
+
title: TranslationLoader2.t("HMR_STOPPED", this.localLanguage),
|
|
1261
|
+
message: TranslationLoader2.t("HMR_MONITORING_STOPPED", this.localLanguage)
|
|
1262
|
+
});
|
|
1039
1263
|
}
|
|
1040
1264
|
/**
|
|
1041
|
-
*
|
|
1265
|
+
* Stops the server and HMR system cleanly.
|
|
1266
|
+
*
|
|
1267
|
+
* @method onStopServer
|
|
1268
|
+
* @public
|
|
1269
|
+
*
|
|
1270
|
+
* @returns {void}
|
|
1042
1271
|
*/
|
|
1043
|
-
|
|
1044
|
-
this.
|
|
1272
|
+
onStopServer() {
|
|
1273
|
+
this.stopHMR();
|
|
1045
1274
|
if (this.server) {
|
|
1046
1275
|
this.server.close(() => {
|
|
1047
1276
|
SLogger(this.localLanguage).logger.info({
|
|
1048
|
-
title: TranslationLoader2.t("
|
|
1049
|
-
message:
|
|
1277
|
+
title: TranslationLoader2.t("SERVER_STOPPED", this.localLanguage),
|
|
1278
|
+
message: "Server stopped cleanly"
|
|
1050
1279
|
});
|
|
1051
|
-
process4.exit(0);
|
|
1052
1280
|
});
|
|
1053
|
-
|
|
1054
|
-
SLogger(this.localLanguage).logger.error({
|
|
1055
|
-
title: TranslationLoader2.t("FORCE_SHUTDOWN", this.localLanguage),
|
|
1056
|
-
message: TranslationLoader2.t("SERVER_FORCE_SHUTDOWN", this.localLanguage)
|
|
1057
|
-
});
|
|
1058
|
-
process4.exit(1);
|
|
1059
|
-
}, 5e3);
|
|
1060
|
-
} else {
|
|
1061
|
-
process4.exit(0);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
/**
|
|
1065
|
-
* Enable/disable watcher
|
|
1066
|
-
*/
|
|
1067
|
-
setWatcherEnabled(enabled) {
|
|
1068
|
-
this.isWatcherEnabled = enabled;
|
|
1069
|
-
if (enabled && !this.fileWatcher) {
|
|
1070
|
-
this.initializeFileWatcher();
|
|
1071
|
-
} else if (!enabled && this.fileWatcher) {
|
|
1072
|
-
this.stopFileWatcher();
|
|
1281
|
+
this.serverStatus = "STOPPED";
|
|
1073
1282
|
}
|
|
1074
|
-
SLogger(this.localLanguage).logger.info({
|
|
1075
|
-
title: "Watcher Status",
|
|
1076
|
-
message: `File watcher ${enabled ? "enabled" : "disabled"}`
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Get watcher status
|
|
1081
|
-
*/
|
|
1082
|
-
getWatcherStatus() {
|
|
1083
|
-
return {
|
|
1084
|
-
enabled: this.isWatcherEnabled,
|
|
1085
|
-
active: this.fileWatcher !== void 0
|
|
1086
|
-
};
|
|
1087
1283
|
}
|
|
1088
1284
|
/**
|
|
1089
|
-
*
|
|
1285
|
+
* Gets the current server state information.
|
|
1286
|
+
*
|
|
1287
|
+
* @method getServerState
|
|
1288
|
+
* @public
|
|
1289
|
+
*
|
|
1290
|
+
* @returns {IServerStateInfo} Server state information object
|
|
1291
|
+
*
|
|
1292
|
+
* @remarks
|
|
1293
|
+
* Includes:
|
|
1294
|
+
* - Status, host, port
|
|
1295
|
+
* - Route and dependency counts
|
|
1296
|
+
* - Uptime and memory usage
|
|
1297
|
+
* - HMR configuration and statistics
|
|
1090
1298
|
*/
|
|
1091
1299
|
getServerState() {
|
|
1092
1300
|
const now = /* @__PURE__ */ new Date();
|
|
1093
1301
|
const uptime = this.serverStartTime ? now.getTime() - this.serverStartTime.getTime() : 0;
|
|
1094
|
-
const formatUptime = (ms) => {
|
|
1095
|
-
const seconds = Math.floor(ms / 1e3);
|
|
1096
|
-
const minutes = Math.floor(seconds / 60);
|
|
1097
|
-
const hours = Math.floor(minutes / 60);
|
|
1098
|
-
const days = Math.floor(hours / 24);
|
|
1099
|
-
if (days > 0) return `${days}j ${hours % 24}h ${minutes % 60}m`;
|
|
1100
|
-
if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
1101
|
-
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
|
|
1102
|
-
return `${seconds}s`;
|
|
1103
|
-
};
|
|
1104
|
-
const memory = process4.memoryUsage();
|
|
1105
1302
|
return {
|
|
1106
1303
|
status: this.serverStatus,
|
|
1107
|
-
isRunning: this.server !== void 0,
|
|
1304
|
+
isRunning: this.server !== void 0 && this.serverStatus === "READY",
|
|
1108
1305
|
host: this.getEnvironment.appHost,
|
|
1109
1306
|
port: Number(this.getEnvironment.appPort),
|
|
1110
1307
|
language: this.localLanguage,
|
|
1111
|
-
watcherEnabled: this.isWatcherEnabled,
|
|
1112
|
-
watcherActive: this.fileWatcher !== void 0,
|
|
1113
1308
|
routesCount: this.currentRoutes.length,
|
|
1114
1309
|
dependenciesCount: this.currentDependencies.length,
|
|
1115
1310
|
startTime: this.serverStartTime,
|
|
1116
1311
|
currentTime: now,
|
|
1117
1312
|
uptime,
|
|
1118
|
-
uptimeFormatted: formatUptime(uptime),
|
|
1119
|
-
memoryUsage:
|
|
1120
|
-
rss: memory.rss,
|
|
1121
|
-
heapTotal: memory.heapTotal,
|
|
1122
|
-
heapUsed: memory.heapUsed,
|
|
1123
|
-
external: memory.external,
|
|
1124
|
-
arrayBuffers: memory.arrayBuffers
|
|
1125
|
-
},
|
|
1313
|
+
uptimeFormatted: this.formatUptime(uptime),
|
|
1314
|
+
memoryUsage: process4.memoryUsage(),
|
|
1126
1315
|
pid: process4.pid,
|
|
1127
1316
|
platform: process4.platform,
|
|
1128
1317
|
nodeVersion: process4.version,
|
|
1129
|
-
cwd: process4.cwd()
|
|
1318
|
+
cwd: process4.cwd(),
|
|
1319
|
+
hmrEnabled: this.getEnvironment.hmrEnabled,
|
|
1320
|
+
hmrWatchingFiles: this.getEnvironment.hmrWatchPatterns?.length || 0,
|
|
1321
|
+
hmrRestartCount: this.hmrRestartCount
|
|
1130
1322
|
};
|
|
1131
1323
|
}
|
|
1132
1324
|
/**
|
|
1133
|
-
*
|
|
1325
|
+
* Gets the current server status.
|
|
1326
|
+
*
|
|
1327
|
+
* @method getServerStatus
|
|
1328
|
+
* @public
|
|
1329
|
+
*
|
|
1330
|
+
* @returns {TServerStatus} Current server status
|
|
1134
1331
|
*/
|
|
1135
1332
|
getServerStatus() {
|
|
1136
1333
|
return this.serverStatus;
|
|
1137
1334
|
}
|
|
1138
1335
|
/**
|
|
1139
|
-
*
|
|
1336
|
+
* Gets detailed server statistics.
|
|
1337
|
+
*
|
|
1338
|
+
* @method getServerStats
|
|
1339
|
+
* @public
|
|
1340
|
+
*
|
|
1341
|
+
* @returns {IServerStats} Server statistics object
|
|
1342
|
+
*
|
|
1343
|
+
* @remarks
|
|
1344
|
+
* Includes:
|
|
1345
|
+
* - Performance metrics (CPU, memory)
|
|
1346
|
+
* - Uptime information
|
|
1347
|
+
* - HMR statistics
|
|
1140
1348
|
*/
|
|
1141
1349
|
getServerStats() {
|
|
1142
1350
|
const uptime = this.serverStartTime ? Date.now() - this.serverStartTime.getTime() : 0;
|
|
@@ -1153,24 +1361,27 @@ var WebServerCore = class {
|
|
|
1153
1361
|
performance: {
|
|
1154
1362
|
cpuUsage: process4.cpuUsage(),
|
|
1155
1363
|
resourceUsage: process4.resourceUsage?.()
|
|
1364
|
+
},
|
|
1365
|
+
hmrStats: {
|
|
1366
|
+
enabled: this.getEnvironment.hmrEnabled,
|
|
1367
|
+
restartCount: this.hmrRestartCount,
|
|
1368
|
+
lastRestartTime: this.lastHmrRestartTime,
|
|
1369
|
+
watchingFiles: this.getEnvironment.hmrWatchPatterns?.length || 0
|
|
1156
1370
|
}
|
|
1157
1371
|
};
|
|
1158
1372
|
}
|
|
1159
1373
|
/**
|
|
1160
|
-
*
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Format uptime to human readable string
|
|
1374
|
+
* Formats milliseconds into a human-readable uptime string.
|
|
1375
|
+
*
|
|
1376
|
+
* @method formatUptime
|
|
1377
|
+
* @private
|
|
1378
|
+
*
|
|
1379
|
+
* @param {number} ms - Milliseconds to format
|
|
1380
|
+
*
|
|
1381
|
+
* @returns {string} Formatted uptime string
|
|
1382
|
+
*
|
|
1383
|
+
* @example
|
|
1384
|
+
* formatUptime(3661000) // returns "1h 1m 1s"
|
|
1174
1385
|
*/
|
|
1175
1386
|
formatUptime(ms) {
|
|
1176
1387
|
const seconds = Math.floor(ms / 1e3);
|
|
@@ -1178,7 +1389,7 @@ var WebServerCore = class {
|
|
|
1178
1389
|
const hours = Math.floor(minutes / 60);
|
|
1179
1390
|
const days = Math.floor(hours / 24);
|
|
1180
1391
|
if (days > 0) {
|
|
1181
|
-
return `${days}
|
|
1392
|
+
return `${days}d ${hours % 24}h ${minutes % 60}m`;
|
|
1182
1393
|
} else if (hours > 0) {
|
|
1183
1394
|
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
1184
1395
|
} else if (minutes > 0) {
|
|
@@ -1188,55 +1399,66 @@ var WebServerCore = class {
|
|
|
1188
1399
|
}
|
|
1189
1400
|
}
|
|
1190
1401
|
/**
|
|
1191
|
-
*
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
*
|
|
1402
|
+
* Formats bytes into a human-readable size string.
|
|
1403
|
+
*
|
|
1404
|
+
* @method formatBytes
|
|
1405
|
+
* @private
|
|
1406
|
+
*
|
|
1407
|
+
* @param {number} bytes - Bytes to format
|
|
1408
|
+
*
|
|
1409
|
+
* @returns {string} Formatted size string
|
|
1410
|
+
*
|
|
1411
|
+
* @example
|
|
1412
|
+
* formatBytes(1048576) // returns "1.00 MB"
|
|
1200
1413
|
*/
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1414
|
+
formatBytes(bytes) {
|
|
1415
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
1416
|
+
let value = bytes;
|
|
1417
|
+
let unitIndex = 0;
|
|
1418
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
1419
|
+
value /= 1024;
|
|
1420
|
+
unitIndex++;
|
|
1204
1421
|
}
|
|
1422
|
+
return `${value.toFixed(2)} ${units[unitIndex]}`;
|
|
1205
1423
|
}
|
|
1206
1424
|
/**
|
|
1207
|
-
*
|
|
1425
|
+
* Checks if HMR is currently active.
|
|
1426
|
+
*
|
|
1427
|
+
* @method isHMRActive
|
|
1428
|
+
* @public
|
|
1429
|
+
*
|
|
1430
|
+
* @returns {boolean} True if HMR is enabled and watching files, false otherwise
|
|
1208
1431
|
*/
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
this.reloadConfigurations();
|
|
1212
|
-
this.reloadDependencies();
|
|
1213
|
-
SLogger(this.localLanguage).logger.info({
|
|
1214
|
-
title: "Force Reload",
|
|
1215
|
-
message: "All configurations and dependencies have been reloaded"
|
|
1216
|
-
});
|
|
1217
|
-
} catch (error) {
|
|
1218
|
-
SLogger(this.localLanguage).logger.error({
|
|
1219
|
-
title: "Force Reload Failed",
|
|
1220
|
-
message: error.message,
|
|
1221
|
-
errorType: "ForceReloadError",
|
|
1222
|
-
httpCodeValue: HttpStatusCode3.INTERNAL_SERVER_ERROR
|
|
1223
|
-
});
|
|
1224
|
-
}
|
|
1432
|
+
isHMRActive() {
|
|
1433
|
+
return this.getEnvironment.hmrEnabled && this.fileWatcher !== null;
|
|
1225
1434
|
}
|
|
1226
1435
|
/**
|
|
1227
|
-
*
|
|
1436
|
+
* Gets detailed HMR information and status.
|
|
1437
|
+
*
|
|
1438
|
+
* @method getHMRInfo
|
|
1439
|
+
* @public
|
|
1440
|
+
*
|
|
1441
|
+
* @returns {any} HMR information object
|
|
1442
|
+
*
|
|
1443
|
+
* @remarks
|
|
1444
|
+
* Includes:
|
|
1445
|
+
* - Configuration settings from .env
|
|
1446
|
+
* - Current restart count
|
|
1447
|
+
* - Watcher status
|
|
1228
1448
|
*/
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1449
|
+
getHMRInfo() {
|
|
1450
|
+
return {
|
|
1451
|
+
enabled: this.getEnvironment.hmrEnabled,
|
|
1452
|
+
watchPatterns: this.getEnvironment.hmrWatchPatterns,
|
|
1453
|
+
ignorePatterns: this.getEnvironment.hmrIgnorePatterns,
|
|
1454
|
+
debounceMs: this.getEnvironment.hmrDebounceMs,
|
|
1455
|
+
maxRestarts: this.getEnvironment.hmrMaxRestarts,
|
|
1456
|
+
autoRestart: this.getEnvironment.hmrAutoRestarts,
|
|
1457
|
+
currentRestartCount: this.hmrRestartCount,
|
|
1458
|
+
lastRestartTime: this.lastHmrRestartTime,
|
|
1459
|
+
isWatching: this.fileWatcher !== null,
|
|
1460
|
+
isRestartPending: this.hmrRestartPending
|
|
1461
|
+
};
|
|
1240
1462
|
}
|
|
1241
1463
|
};
|
|
1242
1464
|
export {
|