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