opticore-webapp 1.0.69 → 1.0.71

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 CHANGED
@@ -30,116 +30,35 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ HotReloadWatcher: () => HotReloadWatcher,
33
34
  WebServer: () => WebServerCore,
34
35
  envPath: () => envPath
35
36
  });
36
37
  module.exports = __toCommonJS(index_exports);
37
38
 
38
39
  // src/core/webServer.core.ts
39
- var path2 = __toESM(require("path"), 1);
40
- var import_node_process3 = __toESM(require("process"), 1);
40
+ var path3 = __toESM(require("path"), 1);
41
+ var import_node_process4 = __toESM(require("process"), 1);
41
42
  var import_cors = __toESM(require("cors"), 1);
42
- var import_express = __toESM(require("express"), 1);
43
- var import_chokidar = __toESM(require("chokidar"), 1);
44
43
  var import_opticore_catch_exception_error3 = require("opticore-catch-exception-error");
44
+ var import_opticore_express2 = require("opticore-express");
45
45
  var import_opticore_env_access2 = require("opticore-env-access");
46
+ var import_opticore_http_response4 = require("opticore-http-response");
47
+ var import_opticore_translator3 = require("opticore-translator");
46
48
  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");
50
49
 
51
50
  // src/core/handlers/eventProcess.handler.ts
52
51
  var import_node_process = __toESM(require("process"), 1);
53
52
  var import_node_events = __toESM(require("events"), 1);
53
+ var import_opticore_express = require("opticore-express");
54
54
  var import_opticore_catch_exception_error = require("opticore-catch-exception-error");
55
-
56
- // src/utils/isTransformError.utils.ts
57
- var isTransformErrorUtils = (error) => {
58
- return error?.name === "TransformError" || error?.message?.includes("Transform failed") || error?.message?.includes("esbuild");
59
- };
60
-
61
- // src/core/handlers/eventProcess.handler.ts
62
- function eventProcessHandler(localeLanguage, expressApp) {
55
+ function eventProcessHandler(localeLanguage) {
63
56
  const errorEmitter = new import_node_events.default();
57
+ const app = (0, import_opticore_express.express)();
64
58
  const serverListenEvent = new import_opticore_catch_exception_error.ServerListenEventError(localeLanguage);
65
- console.log("[Server] Setting up error event handlers...");
66
59
  errorEmitter.on(import_opticore_catch_exception_error.CEventNameError.error, (error) => {
67
- console.error("[Server] EventEmitter error caught:", error.message);
68
- if (isTransformErrorUtils(error)) {
69
- handleTransformError(error);
70
- }
71
60
  serverListenEvent.listenerError(error);
72
61
  });
73
- function handleTransformError(error) {
74
- console.error("[Server] ============================================");
75
- console.error("[Server] TRANSFORM ERROR DETECTED");
76
- console.error("[Server] ============================================");
77
- console.error("[Server] Message:", error.message);
78
- console.error("[Server] Stack:", error.stack);
79
- if (error.errors && Array.isArray(error.errors)) {
80
- error.errors.forEach((err, index) => {
81
- console.error(`[Server] Error ${index + 1}:`, err.text);
82
- if (err.location) {
83
- console.error(`[Server] File: ${err.location.file}`);
84
- console.error(`[Server] Line: ${err.location.line}, Column: ${err.location.column}`);
85
- }
86
- });
87
- }
88
- const fileMatch = error.message.match(/([^:]+\.ts):(\d+):(\d+):/);
89
- if (fileMatch) {
90
- console.error("[Server] Problem file:", fileMatch[1]);
91
- console.error("[Server] Line:", fileMatch[2], "Column:", fileMatch[3]);
92
- }
93
- const errorDetailMatch = error.message.match(/ERROR: (.+)$/m);
94
- if (errorDetailMatch) {
95
- console.error("[Server] Error detail:", errorDetailMatch[1]);
96
- }
97
- console.error("[Server] ============================================");
98
- if (import_node_process.default.send) {
99
- import_node_process.default.send({
100
- type: "TRANSFORM_ERROR",
101
- error: error.message,
102
- stack: error.stack,
103
- errorName: error.name,
104
- details: error.errors,
105
- timestamp: Date.now()
106
- });
107
- }
108
- }
109
- import_node_process.default.on(import_opticore_catch_exception_error.CEvent.uncaughtException, (error) => {
110
- console.error("[Server] UNCAUGHT EXCEPTION:", error.message);
111
- console.error("[Server] Stack:", error.stack);
112
- if (isTransformErrorUtils(error)) {
113
- errorEmitter.emit("transformError", error);
114
- }
115
- serverListenEvent.uncaughtException(error);
116
- if (import_node_process.default.send) {
117
- const messageType = isTransformErrorUtils(error) ? "TRANSFORM_ERROR" : "HOT_RELOAD_ERROR";
118
- import_node_process.default.send({
119
- type: messageType,
120
- error: error.message,
121
- stack: error.stack,
122
- errorName: error.name,
123
- timestamp: Date.now()
124
- });
125
- }
126
- });
127
- import_node_process.default.on(import_opticore_catch_exception_error.CEvent.unhandledRejection, (reason, promise) => {
128
- console.error("[Server] UNHANDLED REJECTION:", reason);
129
- if (isTransformErrorUtils(reason)) {
130
- errorEmitter.emit("transformError", reason);
131
- }
132
- serverListenEvent.unhandledRejection(reason, promise);
133
- if (import_node_process.default.send) {
134
- const messageType = isTransformErrorUtils(reason) ? "TRANSFORM_ERROR" : "HOT_RELOAD_ERROR";
135
- import_node_process.default.send({
136
- type: messageType,
137
- error: reason?.message || String(reason),
138
- errorName: reason?.name,
139
- timestamp: Date.now()
140
- });
141
- }
142
- });
143
62
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.beforeExit, (code) => {
144
63
  setTimeout(() => {
145
64
  serverListenEvent.processBeforeExit(code);
@@ -154,20 +73,20 @@ function eventProcessHandler(localeLanguage, expressApp) {
154
73
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.rejectionHandled, (promise) => {
155
74
  serverListenEvent.promiseRejectionHandled(promise);
156
75
  });
76
+ import_node_process.default.on(import_opticore_catch_exception_error.CEvent.uncaughtException, (error) => {
77
+ serverListenEvent.uncaughtException(error);
78
+ });
157
79
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.uncaughtExceptionMonitor, (error) => {
158
- console.error("[Server] UNCAUGHT EXCEPTION MONITOR:", error.message);
159
- if (isTransformErrorUtils(error)) {
160
- errorEmitter.emit("transformError", error);
161
- }
162
80
  serverListenEvent.uncaughtExceptionMonitor(error);
163
81
  });
82
+ import_node_process.default.on(import_opticore_catch_exception_error.CEvent.unhandledRejection, (reason, promise) => {
83
+ serverListenEvent.unhandledRejection(reason, promise);
84
+ });
164
85
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.warning, (warning) => {
165
86
  serverListenEvent.warning(warning);
166
87
  });
167
88
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.message, (message) => {
168
- if (message.type !== "HOT_RELOAD_REQUEST" && message.type !== "SERVER_READY") {
169
- serverListenEvent.message(message);
170
- }
89
+ serverListenEvent.message(message);
171
90
  });
172
91
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.multipleResolves, (type, promise, reason) => {
173
92
  serverListenEvent.multipleResolves(type, promise, reason);
@@ -178,15 +97,9 @@ function eventProcessHandler(localeLanguage, expressApp) {
178
97
  import_node_process.default.on(import_opticore_catch_exception_error.CEvent.sigterm, (signal) => {
179
98
  serverListenEvent.sigtermSignalReceived(signal);
180
99
  });
181
- expressApp.use((err, req, res, next) => {
182
- console.error("[Server] Express error middleware triggered:", err.message);
183
- console.error("[Server] Request URL:", req.url);
184
- console.error("[Server] Request method:", req.method);
185
- errorEmitter.emit(import_opticore_catch_exception_error.CEventNameError.error, err);
100
+ app.use((err, req, res, next) => {
186
101
  serverListenEvent.expressErrorHandlingMiddleware(errorEmitter, err, req, res, next);
187
102
  });
188
- console.log("[Server] Error event handlers configured successfully");
189
- return errorEmitter;
190
103
  }
191
104
 
192
105
  // src/application/service/core.service.ts
@@ -238,18 +151,20 @@ var dependenciesContainerProvider = (localLang) => {
238
151
  };
239
152
 
240
153
  // src/application/service/core.service.ts
241
- var import_opticore_logger2 = require("opticore-logger");
154
+ var import_opticore_dependency_inject2 = require("opticore-dependency-inject");
242
155
 
243
- // src/application/service/logger.service.ts
244
- var SLogger = (localLang) => {
245
- return {
246
- get serverLog() {
247
- return dependenciesContainerProvider(localLang).resolve("OpticoreLogger");
248
- },
249
- get logger() {
250
- return dependenciesContainerProvider(localLang).resolve("LoggerCore");
251
- }
252
- };
156
+ // src/utils/parsingDateTime.utils.ts
157
+ var parsingDateTimeUtils = (localFormatTime) => {
158
+ const now = /* @__PURE__ */ new Date();
159
+ const formatter = new Intl.DateTimeFormat(localFormatTime, {
160
+ day: "2-digit",
161
+ month: "2-digit",
162
+ year: "numeric",
163
+ hour: "2-digit",
164
+ minute: "2-digit",
165
+ hour12: false
166
+ });
167
+ return formatter.format(now);
253
168
  };
254
169
 
255
170
  // src/application/service/core.service.ts
@@ -258,10 +173,12 @@ var CoreService = class {
258
173
  environmentPath;
259
174
  serverLog;
260
175
  logger;
176
+ container;
261
177
  constructor(localLang, environmentPath) {
178
+ this.loadTranslationFiles();
262
179
  this.environmentPath = environmentPath;
263
180
  this.localLanguage = localLang;
264
- loaderTranslationFile(this.localLanguage);
181
+ this.container = new import_opticore_dependency_inject2.SContainer(localLang);
265
182
  this.serverLog = dependenciesContainerProvider(localLang).resolve("OpticoreLogger");
266
183
  this.logger = dependenciesContainerProvider(localLang).resolve("LoggerCore");
267
184
  }
@@ -275,6 +192,41 @@ var CoreService = class {
275
192
  formatMemoryUsage(data) {
276
193
  return `${Math.round(data / 1024 / 1024 * 100) / 100} MB`;
277
194
  }
195
+ loadTranslationFiles() {
196
+ loaderTranslationFile(this.localLanguage);
197
+ }
198
+ /**
199
+ *
200
+ * @param filePath
201
+ * @private
202
+ *
203
+ * Return void
204
+ */
205
+ getEnvFileLoading(filePath) {
206
+ this.loadTranslationFiles();
207
+ try {
208
+ const fullPath = path.resolve(import_node_process2.default.cwd(), filePath);
209
+ if (fs.existsSync(fullPath)) {
210
+ const env = fs.readFileSync(fullPath, "utf-8");
211
+ const lines = env.split("\n");
212
+ lines.forEach((line) => {
213
+ const match = line.match(/^([^#=]+)=([^#]+)$/);
214
+ if (match) {
215
+ const key = match[1].trim();
216
+ import_node_process2.default.env[key] = match[2].trim();
217
+ }
218
+ });
219
+ }
220
+ } catch (err) {
221
+ this.logger.error({
222
+ message: err.message,
223
+ title: import_opticore_translator.TranslationLoader.t("EnvFileLoading", this.localLanguage),
224
+ errorType: err.code,
225
+ stackTrace: err.stack,
226
+ httpCodeValue: import_opticore_http_response.HttpStatusCode.INTERNAL_SERVER_ERROR
227
+ });
228
+ }
229
+ }
278
230
  /**
279
231
  * Returns an Object containing a node version, openssl, and v0
280
232
  */
@@ -299,7 +251,7 @@ var CoreService = class {
299
251
  * and Memory usage system
300
252
  */
301
253
  getUsageMemory() {
302
- loaderTranslationFile(this.localLanguage);
254
+ this.loadTranslationFiles();
303
255
  const memoryData = import_node_process2.default.memoryUsage();
304
256
  const data = {
305
257
  [import_opticore_translator.TranslationLoader.t("totalMemoryAllocated", this.localLanguage)]: this.formatMemoryUsage(memoryData.rss),
@@ -331,37 +283,6 @@ var CoreService = class {
331
283
  "startingTime": `${executionTime.toFixed(5)} ms`
332
284
  };
333
285
  }
334
- /**
335
- *
336
- * @param filePath
337
- * @private
338
- *
339
- * Return void
340
- */
341
- getEnvFileLoading(filePath) {
342
- try {
343
- const fullPath = path.resolve(import_node_process2.default.cwd(), filePath);
344
- if (fs.existsSync(fullPath)) {
345
- const env = fs.readFileSync(fullPath, "utf-8");
346
- const lines = env.split("\n");
347
- lines.forEach((line) => {
348
- const match = line.match(/^([^#=]+)=([^#]+)$/);
349
- if (match) {
350
- const key = match[1].trim();
351
- import_node_process2.default.env[key] = match[2].trim();
352
- }
353
- });
354
- }
355
- } catch (err) {
356
- this.logger.error({
357
- message: err.message,
358
- title: import_opticore_translator.TranslationLoader.t("EnvFileLoading", this.localLanguage),
359
- errorType: err.code,
360
- stackTrace: err.stack,
361
- httpCodeValue: import_opticore_http_response.HttpStatusCode.INTERNAL_SERVER_ERROR
362
- });
363
- }
364
- }
365
286
  /**
366
287
  *
367
288
  * @param development
@@ -370,14 +291,15 @@ var CoreService = class {
370
291
  * Return string
371
292
  */
372
293
  getServerRunningMode(development, production) {
294
+ this.loadTranslationFiles();
373
295
  try {
374
- loaderTranslationFile(this.localLanguage);
375
296
  this.getEnvFileLoading(".env");
376
- const env = (0, import_opticore_env_access.getEnvironnementValue)(path.join(envPath));
377
- const isDevelopment = env.devEnv === development && env.prodEnv === "";
297
+ const env = (0, import_opticore_env_access.getEnvironmentValue)(path.join(envPath));
298
+ const isDevelopment = env.devEnv === development;
299
+ const isProd = env.prodEnv === production;
378
300
  if (isDevelopment) {
379
301
  return `${import_opticore_translator.TranslationLoader.t("serverRunning", this.localLanguage)} ${import_ansi_colors.default.bgBlue(`${import_ansi_colors.default.bold(`${development}`)}`)} mode`;
380
- } else if (!isDevelopment) {
302
+ } else if (isProd) {
381
303
  return `${import_opticore_translator.TranslationLoader.t("serverRunning", this.localLanguage)} ${import_ansi_colors.default.bgBlue(`${import_ansi_colors.default.bold(`${production}`)}`)} mode`;
382
304
  } else {
383
305
  return `${import_opticore_translator.TranslationLoader.t("serverRunning", this.localLanguage)} ${import_ansi_colors.default.bgBlue(`${import_ansi_colors.default.bold(`${development}`)}`)} mode`;
@@ -393,10 +315,10 @@ var CoreService = class {
393
315
  }
394
316
  }
395
317
  infoServer(host, port) {
318
+ this.loadTranslationFiles();
396
319
  try {
397
- loaderTranslationFile(this.localLanguage);
398
- const getEnvironment = (0, import_opticore_env_access.getEnvironnementValue)(this.environmentPath);
399
- const msg5 = getEnvironment.protocolTransfert === "" ? import_ansi_colors.default.underline(`http://${host}:${port}`) : import_ansi_colors.default.underline(`${getEnvironment.protocolTransfert}://${host}:${port}`);
320
+ const getEnvironment = (0, import_opticore_env_access.getEnvironmentValue)(this.environmentPath);
321
+ const msg5 = getEnvironment.protocolTransfer === "" ? import_ansi_colors.default.underline(`http://${host}:${port}`) : import_ansi_colors.default.underline(`${getEnvironment.protocolTransfer}://${host}:${port}`);
400
322
  const messages = [
401
323
  import_opticore_translator.TranslationLoader.t("webServerListening", this.localLanguage),
402
324
  import_opticore_translator.TranslationLoader.t("webServerUsingNodeVersion", this.localLanguage, { nodeVersion: this.getVersions().nodeVersion }),
@@ -416,20 +338,33 @@ var CoreService = class {
416
338
  });
417
339
  console.log(border);
418
340
  console.log("\n");
419
- const logCore = new import_opticore_logger2.LoggerCore();
420
- logCore.success({
421
- title: import_opticore_translator.TranslationLoader.t("serverRunningTitle", this.localLanguage),
422
- message: import_opticore_translator.TranslationLoader.t("serverRunningAt", this.localLanguage, { server: msg5 })
423
- });
424
- SLogger(this.localLanguage).serverLog.serverLog({
425
- timestamp: (/* @__PURE__ */ new Date()).toString(),
341
+ this.serverLog.serverLog({
342
+ timestamp: parsingDateTimeUtils(getEnvironment.localFormatTime),
426
343
  level: "SERVER",
427
344
  title: import_opticore_translator.TranslationLoader.t("serverRunningTitle", this.localLanguage),
428
345
  typeName: import_opticore_translator.TranslationLoader.t("opticoreServerTypeName", this.localLanguage),
429
346
  message: import_opticore_translator.TranslationLoader.t("serverRunningAt", this.localLanguage, { server: msg5 })
430
347
  });
348
+ const dependenciesList = this.container.listDependencies();
349
+ if (dependenciesList.length > 0) {
350
+ this.serverLog.opticoreLog({
351
+ level: "OPTICORE",
352
+ message: import_opticore_translator.TranslationLoader.t("DEPENDENCIES_STORED", this.localLanguage, { dependenciesList: dependenciesList.join(", ") }),
353
+ timestamp: parsingDateTimeUtils(getEnvironment.localFormatTime),
354
+ title: import_opticore_translator.TranslationLoader.t("DEPENDENCIES_CONTAINER", this.localLanguage),
355
+ typeName: "DEPENDENCIES_CONTAINER"
356
+ });
357
+ } else {
358
+ this.serverLog.opticoreLog({
359
+ level: "OPTICORE",
360
+ message: import_opticore_translator.TranslationLoader.t("NO_DEPENDENCIES_STORED", this.localLanguage),
361
+ timestamp: parsingDateTimeUtils(getEnvironment.localFormatTime),
362
+ title: import_opticore_translator.TranslationLoader.t("DEPENDENCIES_CONTAINER", this.localLanguage),
363
+ typeName: "DEPENDENCIES_CONTAINER"
364
+ });
365
+ }
431
366
  } catch (err) {
432
- SLogger(this.localLanguage).logger.error({
367
+ this.logger.error({
433
368
  message: err.message,
434
369
  title: import_opticore_translator.TranslationLoader.t("server", this.localLanguage),
435
370
  errorType: err.code,
@@ -445,6 +380,20 @@ var dateTimeFormattedUtils = `${(/* @__PURE__ */ new Date()).getMonth()}-${(/* @
445
380
 
446
381
  // src/application/service/serverStartError.service.ts
447
382
  var import_opticore_catch_exception_error2 = require("opticore-catch-exception-error");
383
+
384
+ // src/application/service/logger.service.ts
385
+ var SLogger = (localLang) => {
386
+ return {
387
+ get serverLog() {
388
+ return dependenciesContainerProvider(localLang).resolve("OpticoreLogger");
389
+ },
390
+ get logger() {
391
+ return dependenciesContainerProvider(localLang).resolve("LoggerCore");
392
+ }
393
+ };
394
+ };
395
+
396
+ // src/application/service/serverStartError.service.ts
448
397
  var import_opticore_http_response2 = require("opticore-http-response");
449
398
  var SServerStartError = (err, environmentPath) => {
450
399
  if (err.name) {
@@ -476,391 +425,165 @@ var SServerStartError = (err, environmentPath) => {
476
425
  }
477
426
  };
478
427
 
428
+ // src/core/webServer.core.ts
429
+ var import_opticore_dependency_inject3 = require("opticore-dependency-inject");
430
+
431
+ // src/application/service/getEnvFileLoading.service.ts
432
+ var import_path = __toESM(require("path"), 1);
433
+ var import_node_process3 = __toESM(require("process"), 1);
434
+ var import_fs = __toESM(require("fs"), 1);
435
+ var import_opticore_translator2 = require("opticore-translator");
436
+ var import_opticore_http_response3 = require("opticore-http-response");
437
+ var getEnvFileLoadingService = (filePath, localLanguage) => {
438
+ loaderTranslationFile(localLanguage);
439
+ const logger = dependenciesContainerProvider(localLanguage).resolve("LoggerCore");
440
+ try {
441
+ const fullPath = import_path.default.resolve(import_node_process3.default.cwd(), filePath);
442
+ if (import_fs.default.existsSync(fullPath)) {
443
+ const env = import_fs.default.readFileSync(fullPath, "utf-8");
444
+ const lines = env.split("\n");
445
+ lines.forEach((line) => {
446
+ const match = line.match(/^([^#=]+)=([^#]+)$/);
447
+ if (match) {
448
+ const key = match[1].trim();
449
+ import_node_process3.default.env[key] = match[2].trim();
450
+ }
451
+ });
452
+ }
453
+ } catch (err) {
454
+ logger.error({
455
+ message: err.message,
456
+ title: import_opticore_translator2.TranslationLoader.t("EnvFileLoading", localLanguage),
457
+ errorType: err.code,
458
+ stackTrace: err.stack,
459
+ httpCodeValue: import_opticore_http_response3.HttpStatusCode.INTERNAL_SERVER_ERROR
460
+ });
461
+ }
462
+ };
463
+
479
464
  // src/core/webServer.core.ts
480
465
  var WebServerCore = class {
481
466
  serverUtility;
482
- expressApp;
467
+ expressApp = (0, import_opticore_express2.express)();
468
+ container;
483
469
  localLanguage;
484
470
  loggerConfig;
485
- getEnvironment;
471
+ routerExpressApp;
472
+ getEnvironmentValue;
486
473
  environmentPath;
487
474
  serverListenEvent;
488
- // Existing properties
489
- currentRoutes = [];
490
- currentDependencies = [];
491
- server = void 0;
492
- errorEmitter;
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
- */
475
+ dependenciesRegistered = false;
528
476
  constructor(paramsConstructor) {
529
- this.getEnvironment = (0, import_opticore_env_access2.getEnvironmentValue)(paramsConstructor.environmentPath);
477
+ this.loadTranslationFiles();
478
+ this.stackTraceErrorHandling();
479
+ this.getEnvironmentValue = (0, import_opticore_env_access2.getEnvironmentValue)(paramsConstructor.environmentPath);
480
+ this.routerExpressApp = paramsConstructor.app;
530
481
  this.loggerConfig = paramsConstructor.loggerConfig;
531
482
  this.localLanguage = paramsConstructor.localLanguage;
532
483
  this.environmentPath = paramsConstructor.environmentPath;
533
- this.expressApp = (0, import_express.default)();
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 }));
484
+ this.container = new import_opticore_dependency_inject3.SContainer(paramsConstructor.localLanguage);
485
+ this.expressApp.use(import_opticore_express2.express.json());
486
+ this.expressApp.use(import_opticore_express2.express.raw());
487
+ this.expressApp.use(import_opticore_express2.express.text());
488
+ this.expressApp.use(import_opticore_express2.express.urlencoded({ extended: true }));
539
489
  this.expressApp.use((0, import_cors.default)(paramsConstructor.corsOriginOptions));
490
+ this.serverListenEvent = new import_opticore_catch_exception_error3.ServerListenEventError(paramsConstructor.localLanguage);
540
491
  this.serverUtility = new CoreService(paramsConstructor.localLanguage, paramsConstructor.environmentPath);
541
- this.serverStatus = "STARTING";
542
- this.serverStartTime = /* @__PURE__ */ new Date();
543
- this.setupProcessEventListeners();
544
492
  }
545
493
  /**
546
- * Starts the HTTP server and initializes all components including HMR if enabled.
547
- *
548
- * @method onStartServer
549
- * @public
550
494
  *
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
- * ```
495
+ * @param dependencies
576
496
  */
577
- onStartServer(routers, databaseCallback, dependenciesProvider) {
497
+ registerDependencies(dependencies2) {
498
+ this.loadTranslationFiles();
578
499
  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();
500
+ getEnvFileLoadingService(".env", this.localLanguage);
501
+ if (dependencies2 && dependencies2.length > 0) {
502
+ dependencies2.forEach((dependency) => {
503
+ this.container.register(dependency.key, dependency.factory, dependency.scope);
504
+ });
590
505
  }
591
- return server;
592
- } catch (error) {
593
- this.handleStartupError(error);
506
+ } catch (err) {
507
+ SLogger(this.environmentPath).logger.error({
508
+ message: err.message,
509
+ title: "Register Dependencies",
510
+ errorType: err.code,
511
+ stackTrace: err.stack,
512
+ httpCodeValue: import_opticore_http_response4.HttpStatusCode.INTERNAL_SERVER_ERROR
513
+ });
594
514
  }
595
515
  }
596
516
  /**
597
- * Validates server configuration parameters.
598
517
  *
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)
518
+ * @param routers
519
+ * @param databaseCallback
520
+ * @param dependenciesProvider
610
521
  */
611
- validateServerParameters() {
612
- loaderTranslationFile(this.localLanguage);
613
- const port = Number(this.getEnvironment.appPort);
614
- if (isNaN(port) || port <= 0) {
522
+ onStartServer(routers, databaseCallback, dependenciesProvider) {
523
+ this.loadTranslationFiles();
524
+ getEnvFileLoadingService(".env", this.localLanguage);
525
+ if (this.getEnvironmentValue.appPort === "" && Number(this.getEnvironmentValue.appPort) === 0) {
526
+ this.serverListenEvent.hostPortUndefined(Number(this.getEnvironmentValue.appPort));
527
+ } else if (this.getEnvironmentValue.appHost === "") {
528
+ this.serverListenEvent.hostUndefined(this.getEnvironmentValue.appHost);
529
+ } else if (Number(this.getEnvironmentValue.appPort) === 0) {
615
530
  this.serverListenEvent.portUndefined();
616
- return false;
617
- }
618
- if (!this.getEnvironment.appHost || this.getEnvironment.appHost.trim() === "") {
619
- this.serverListenEvent.hostUndefined(this.getEnvironment.appHost);
620
- return false;
621
- }
622
- if (!this.localLanguage || this.localLanguage.trim() === "") {
623
- SLogger(this.localLanguage).logger.error({
624
- message: import_opticore_translator2.TranslationLoader.t("noDefaultLocalLang", this.localLanguage),
625
- title: import_opticore_translator2.TranslationLoader.t("noLocalLang", this.localLanguage),
626
- errorType: import_opticore_translator2.TranslationLoader.t("localLangMissing", this.localLanguage),
531
+ } else if (this.localLanguage === "") {
532
+ SLogger(this.environmentPath).logger.error({
533
+ message: import_opticore_translator3.TranslationLoader.t("noDefaultLocalLang", this.localLanguage),
534
+ title: import_opticore_translator3.TranslationLoader.t("noLocalLang", this.localLanguage),
535
+ errorType: import_opticore_translator3.TranslationLoader.t("localLangMissing", this.localLanguage),
627
536
  stackTrace: void 0,
628
- httpCodeValue: import_opticore_http_response3.HttpStatusCode.NOT_FOUND
537
+ httpCodeValue: import_opticore_http_response4.HttpStatusCode.NOT_FOUND
629
538
  });
630
- return false;
631
- }
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, () => {
660
- try {
661
- this.configureServerComponents(databaseCallback);
662
- this.serverStatus = "READY";
663
- SLogger(this.localLanguage).logger.info({
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
- })
669
- });
670
- } catch (err) {
671
- this.handleServerConfigurationError(err);
539
+ } else {
540
+ return this.expressApp.listen(
541
+ Number(this.getEnvironmentValue.appPort),
542
+ () => {
543
+ this.loadTranslationFiles();
544
+ try {
545
+ databaseCallback(this.getEnvironmentValue);
546
+ if (dependenciesProvider) {
547
+ this.registerDependencies(dependenciesProvider);
548
+ }
549
+ this.container.loadServices();
550
+ this.expressApp.use(import_opticore_express2.express.static(path3.join(import_node_process4.default.cwd(), "public/template")));
551
+ this.registerRoutes(routers);
552
+ } catch (err) {
553
+ SServerStartError(err, this.environmentPath);
554
+ }
672
555
  }
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
556
  );
684
557
  }
685
558
  }
686
559
  /**
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
560
  *
696
- * @throws {Error} If component configuration fails
561
+ * @param serverWeb
697
562
  */
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
- );
708
- }
709
- }
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();
563
+ onListeningOnServerEvent(serverWeb) {
564
+ this.loadTranslationFiles();
565
+ serverWeb.on(import_opticore_catch_exception_error3.CEventNameError.error, (err) => {
566
+ this.serverListenEvent.onEventError(err);
567
+ }).on(import_opticore_catch_exception_error3.CEventNameError.close, () => {
568
+ this.serverListenEvent.serverClosing();
569
+ }).on(import_opticore_catch_exception_error3.CEventNameError.drop, () => {
570
+ this.serverListenEvent.dropNewConnection();
571
+ }).on(import_opticore_catch_exception_error3.CEventNameError.listening, () => {
720
572
  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
- }
727
- }
728
- /**
729
- * Handles server configuration errors.
730
- *
731
- * @method handleServerConfigurationError
732
- * @private
733
- *
734
- * @param {any} err - The error that occurred
735
- *
736
- * @returns {void}
737
- */
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);
746
- }
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);
822
573
  });
823
574
  }
824
575
  /**
825
- * Sets up HTTP server event listeners.
826
- *
827
- * @method setupServerEventListeners
828
- * @private
829
576
  *
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
577
+ * @param serverWeb
843
578
  */
844
- setupServerEventListeners() {
845
- loaderTranslationFile(this.localLanguage);
846
- if (!this.server) {
847
- return;
848
- }
849
- this.server.on(import_opticore_catch_exception_error3.CEventNameError.error, (err) => {
850
- this.serverListenEvent.onEventError(err);
851
- });
852
- this.server.on(import_opticore_catch_exception_error3.CEventNameError.close, () => {
853
- this.serverListenEvent.serverClosing();
854
- });
855
- this.server.on(import_opticore_catch_exception_error3.CEventNameError.drop, () => {
856
- this.serverListenEvent.dropNewConnection();
857
- });
858
- this.server.on(import_opticore_catch_exception_error3.CEventNameError.request, (req, res) => {
579
+ onRequestOnServerEvent(serverWeb) {
580
+ this.loadTranslationFiles();
581
+ serverWeb.on(import_opticore_catch_exception_error3.CEventNameError.request, (req, res) => {
859
582
  (0, import_opticore_request_call_event.requestCallsEvent)(
860
583
  req,
861
584
  res,
862
- this.getEnvironment.appHost,
863
- Number(this.getEnvironment.appPort),
585
+ this.getEnvironmentValue.appHost,
586
+ Number(this.getEnvironmentValue.appPort),
864
587
  dateTimeFormattedUtils,
865
588
  this.environmentPath,
866
589
  this.localLanguage
@@ -868,627 +591,437 @@ var WebServerCore = class {
868
591
  });
869
592
  }
870
593
  /**
871
- * Sets up error handling middleware and event emitters.
872
594
  *
873
- * @method setupErrorHandling
874
595
  * @private
875
- *
876
- * @returns {void}
877
596
  */
878
- setupErrorHandling() {
597
+ loadTranslationFiles() {
879
598
  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
599
  }
913
600
  /**
914
- * Registers routes with the Express application.
915
601
  *
916
- * @method registerRoutes
602
+ * @param allFeatureRoutes
917
603
  * @private
918
- *
919
- * @param {any[]} allFeatureRoutes - Array of feature routes to register
920
- *
921
- * @returns {void}
922
604
  */
923
605
  registerRoutes(allFeatureRoutes) {
924
- allFeatureRoutes.forEach((router) => {
925
- if (router.routes) {
926
- router.routes.forEach((route) => {
927
- this.expressApp.use(route.path, route.handler);
928
- });
929
- }
606
+ allFeatureRoutes.map((router) => {
607
+ router.routes.map((route) => {
608
+ this.expressApp.use(route.path, route.handler);
609
+ });
930
610
  });
931
611
  }
932
612
  /**
933
- * Displays server information.
934
613
  *
935
- * @method infoWebApp
936
614
  * @private
937
- *
938
- * @returns {void}
939
615
  */
940
- infoWebApp() {
941
- loaderTranslationFile(this.localLanguage);
942
- this.serverUtility.infoServer(
943
- this.getEnvironment.appHost,
944
- Number(this.getEnvironment.appPort)
945
- );
616
+ stackTraceErrorHandling() {
617
+ return eventProcessHandler(this.localLanguage);
946
618
  }
947
619
  /**
948
- * Starts the Hot Module Replacement (HMR) file watching system.
949
620
  *
950
- * @method startHMR
951
621
  * @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
622
  */
963
- startHMR() {
623
+ infoWebApp() {
624
+ this.loadTranslationFiles();
625
+ this.serverUtility.infoServer(
626
+ this.getEnvironmentValue.appHost,
627
+ Number(this.getEnvironmentValue.appPort)
628
+ );
629
+ }
630
+ };
631
+
632
+ // src/hotReload/hotReload.watcher.ts
633
+ var import_child_process = require("child_process");
634
+ var import_fs2 = require("fs");
635
+ var import_promises = require("fs/promises");
636
+ var import_path2 = require("path");
637
+ var import_dotenv = require("dotenv");
638
+ var import_chalk2 = __toESM(require("chalk"), 1);
639
+ var import_ansi_colors2 = __toESM(require("ansi-colors"), 1);
640
+ var import_gradient_string = __toESM(require("gradient-string"), 1);
641
+ var DEFAULT_WATCH_EXTENSIONS = [".ts", ".js", ".mjs", ".cjs", ".json"];
642
+ var DEFAULT_HOT_RELOAD_EXTENSIONS = [".json"];
643
+ var DEFAULT_IGNORE = [
644
+ "node_modules",
645
+ "dist",
646
+ ".git",
647
+ "package.json",
648
+ "package-lock.json",
649
+ ".idea",
650
+ ".vscode",
651
+ "coverage",
652
+ "logs"
653
+ ];
654
+ var DEFAULT_DEBOUNCE_MS = 300;
655
+ var DEFAULT_MAX_CRASH_RESTARTS = 5;
656
+ var HotReloadWatcher = class {
657
+ cfg;
658
+ child = null;
659
+ watchers = [];
660
+ debounceTimer = null;
661
+ isRestarting = false;
662
+ crashRestartCount = 0;
663
+ started = false;
664
+ restartStart = 0;
665
+ constructor(config) {
666
+ this.cfg = {
667
+ entry: (0, import_path2.resolve)(config.entry),
668
+ runtime: config.runtime ?? "node",
669
+ runtimeArgs: config.runtimeArgs ?? [],
670
+ rootDir: (0, import_path2.resolve)(config.rootDir ?? process.cwd()),
671
+ watchDirs: config.watchDirs ?? [],
672
+ watchExtensions: config.watchExtensions ?? DEFAULT_WATCH_EXTENSIONS,
673
+ ignore: [...DEFAULT_IGNORE, ...config.ignore ?? []],
674
+ envFile: config.envFile ?? ".env",
675
+ hotReloadExtensions: config.hotReloadExtensions ?? DEFAULT_HOT_RELOAD_EXTENSIONS,
676
+ debounceMs: config.debounceMs ?? DEFAULT_DEBOUNCE_MS,
677
+ restartOnCrash: config.restartOnCrash ?? true,
678
+ maxCrashRestarts: config.maxCrashRestarts ?? DEFAULT_MAX_CRASH_RESTARTS
679
+ };
680
+ }
681
+ // ─── Public API ──────────────────────────────────────────────────────────
682
+ async start() {
683
+ if (this.started) return;
684
+ this.started = true;
685
+ this.printBanner();
686
+ this.spawnChild();
687
+ await this.setupWatchers();
688
+ this.setupProcessSignals();
689
+ }
690
+ async stop() {
691
+ this.watchers.forEach((w) => {
692
+ w.close();
693
+ });
694
+ this.watchers = [];
695
+ await this.killChild(true);
696
+ this.printStopped();
697
+ }
698
+ // ─── Child process management ────────────────────────────────────────────
699
+ spawnChild() {
700
+ const { entry, runtime, runtimeArgs } = this.cfg;
964
701
  try {
965
- loaderTranslationFile(this.localLanguage);
966
- const hmrConfig = this.getEnvironment;
967
- if (!hmrConfig.hmrEnabled) {
968
- SLogger(this.localLanguage).logger.info({
969
- title: import_opticore_translator2.TranslationLoader.t("HMR_DISABLED", this.localLanguage),
970
- message: "HMR is disabled in configuration"
971
- });
972
- return;
973
- }
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
702
+ this.child = runtime === "node" ? (0, import_child_process.fork)(entry, [], {
703
+ stdio: ["inherit", "inherit", "inherit", "ipc"],
704
+ env: process.env
705
+ }) : (0, import_child_process.spawn)(runtime, [...runtimeArgs, entry], {
706
+ stdio: "inherit",
707
+ env: process.env,
708
+ shell: false
1005
709
  });
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();
1009
- SLogger(this.localLanguage).logger.info({
1010
- title: import_opticore_translator2.TranslationLoader.t("HMR_STARTED", this.localLanguage),
1011
- message: import_opticore_translator2.TranslationLoader.t("HMR_MONITORING_STARTED", this.localLanguage)
710
+ this.child.on("exit", (code) => {
711
+ if (this.isRestarting) return;
712
+ if (code !== 0 && code !== null) {
713
+ this.printCrash(code);
714
+ if (this.cfg.restartOnCrash && this.crashRestartCount < this.cfg.maxCrashRestarts) {
715
+ this.crashRestartCount++;
716
+ this.printCrashRetry(this.crashRestartCount, this.cfg.maxCrashRestarts);
717
+ setTimeout(() => {
718
+ this.spawnChild();
719
+ }, 1e3);
720
+ } else if (this.crashRestartCount >= this.cfg.maxCrashRestarts) {
721
+ this.printCrashLimit(this.cfg.maxCrashRestarts);
722
+ process.exit(1);
723
+ }
724
+ }
1012
725
  });
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
726
+ this.child.on("error", (err) => {
727
+ this.printError(`Failed to start child process: ${err.message}`);
1019
728
  });
729
+ } catch (err) {
730
+ this.printError(`Cannot spawn '${runtime} ${entry}': ${err.message}`);
731
+ process.exit(1);
1020
732
  }
1021
733
  }
1022
- /**
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.
1036
- */
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);
1045
- SLogger(this.localLanguage).logger.info({
1046
- title: import_opticore_translator2.TranslationLoader.t("FILE_CHANGE_DETECTED", this.localLanguage),
1047
- message: `File ${action}: ${filePath}`
734
+ async killChild(silent = false) {
735
+ if (!this.child) return;
736
+ const child = this.child;
737
+ this.child = null;
738
+ await new Promise((done) => {
739
+ const forceKill = setTimeout(() => {
740
+ child.kill("SIGKILL");
741
+ done();
742
+ }, 3e3);
743
+ child.once("exit", () => {
744
+ clearTimeout(forceKill);
745
+ done();
746
+ });
747
+ child.kill("SIGTERM");
1048
748
  });
1049
749
  }
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;
750
+ // ─── File watching ────────────────────────────────────────────────────────
751
+ async setupWatchers() {
752
+ const dirs = [
753
+ this.cfg.rootDir,
754
+ ...this.cfg.watchDirs.map((d) => (0, import_path2.resolve)(d))
755
+ ];
756
+ for (const dir of dirs) {
757
+ await this.watchDirectoryRecursive(dir);
1070
758
  }
1071
- if (!this.canProceedWithHMRRestart()) {
759
+ }
760
+ async watchDirectoryRecursive(dir) {
761
+ if (this.shouldIgnoreDir(dir)) return;
762
+ try {
763
+ await (0, import_promises.access)(dir);
764
+ } catch {
1072
765
  return;
1073
766
  }
1074
- this.hmrRestartPending = true;
1075
- this.hmrRestartCount++;
1076
- this.lastHmrRestartTime = Date.now();
1077
767
  try {
1078
- loaderTranslationFile(this.localLanguage);
1079
- SLogger(this.localLanguage).logger.info({
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
- })
1085
- });
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
- })
768
+ const watcher = (0, import_fs2.watch)(dir, (event2, filename) => {
769
+ if (!filename) return;
770
+ this.onFileChange((0, import_path2.join)(dir, filename));
1102
771
  });
1103
- } catch (error) {
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
772
+ watcher.on("error", () => {
1110
773
  });
1111
- } finally {
1112
- this.hmrRestartPending = false;
774
+ this.watchers.push(watcher);
775
+ const entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
776
+ for (const entry of entries) {
777
+ if (entry.isDirectory()) {
778
+ await this.watchDirectoryRecursive((0, import_path2.join)(dir, entry.name));
779
+ }
780
+ }
781
+ } catch {
1113
782
  }
1114
783
  }
1115
- /**
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
1130
- */
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();
784
+ // ─── Change handling ─────────────────────────────────────────────────────
785
+ onFileChange(filePath) {
786
+ if (this.shouldIgnoreFile(filePath)) return;
787
+ if (!this.isWatchedFile(filePath)) return;
788
+ const rel = (0, import_path2.relative)(this.cfg.rootDir, filePath);
789
+ if (this.isHotReloadable(filePath)) {
790
+ this.doHotReload(filePath, rel);
791
+ } else {
792
+ this.scheduleRestart(rel);
1140
793
  }
1141
794
  }
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() {
1157
- try {
1158
- SLogger(this.localLanguage).logger.info({
1159
- title: import_opticore_translator2.TranslationLoader.t("ROUTES_RELOADED", this.localLanguage),
1160
- message: "Routes dynamically reloaded"
1161
- });
1162
- } catch (error) {
1163
- throw new Error(`Route reload failed: ${error.message}`);
795
+ doHotReload(filePath, relativePath) {
796
+ if (this.isEnvFile(filePath)) {
797
+ (0, import_dotenv.config)({ path: filePath, override: true });
798
+ this.printHot(relativePath, "env variables reloaded");
799
+ this.sendIpc({ type: "hot-reload", file: relativePath, kind: "env" });
800
+ } else {
801
+ this.printHot(relativePath, "json config reloaded");
802
+ this.sendIpc({ type: "hot-reload", file: relativePath, kind: "json" });
1164
803
  }
1165
804
  }
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() {
1177
- try {
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
- });
805
+ scheduleRestart(relativePath) {
806
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
807
+ this.debounceTimer = setTimeout(async () => {
808
+ this.printReloading(relativePath);
809
+ this.restartStart = Date.now();
810
+ this.isRestarting = true;
811
+ this.crashRestartCount = 0;
812
+ await this.killChild(true);
813
+ this.isRestarting = false;
814
+ this.spawnChild();
815
+ this.printReady(Date.now() - this.restartStart);
816
+ }, this.cfg.debounceMs);
817
+ }
818
+ // ─── IPC ─────────────────────────────────────────────────────────────────
819
+ sendIpc(message) {
820
+ if (this.child && typeof this.child.send === "function") {
821
+ try {
822
+ this.child.send(message);
823
+ } catch {
1184
824
  }
1185
- } catch (error) {
1186
- throw new Error(`Dependency reload failed: ${error.message}`);
1187
825
  }
1188
826
  }
1189
- /**
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
1201
- */
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"
1208
- });
1209
- return false;
1210
- }
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
- })
1225
- });
1226
- return false;
1227
- }
1228
- return true;
827
+ // ─── Ignore / watch filters ───────────────────────────────────────────────
828
+ shouldIgnoreDir(dirPath) {
829
+ return this.cfg.ignore.some((p) => dirPath.includes(`/${p}`) || dirPath.endsWith(p));
1229
830
  }
1230
- /**
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}
1240
- */
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
- });
831
+ shouldIgnoreFile(filePath) {
832
+ const name = (0, import_path2.basename)(filePath);
833
+ const rel = (0, import_path2.relative)(this.cfg.rootDir, filePath);
834
+ return this.cfg.ignore.some((p) => name === p || rel.includes(p) || filePath.includes(`/${p}/`));
1249
835
  }
1250
- /**
1251
- * Handles HMR watcher errors.
1252
- *
1253
- * @method onHMRWatcherError
1254
- * @private
1255
- *
1256
- * @param {Error} error - The watcher error
1257
- *
1258
- * @returns {void}
1259
- */
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
1266
- });
836
+ isWatchedFile(filePath) {
837
+ if (this.isEnvFile(filePath)) return true;
838
+ return this.cfg.watchExtensions.includes((0, import_path2.extname)(filePath));
839
+ }
840
+ isHotReloadable(filePath) {
841
+ if (this.isEnvFile(filePath)) return true;
842
+ return this.cfg.hotReloadExtensions.includes((0, import_path2.extname)(filePath));
843
+ }
844
+ isEnvFile(filePath) {
845
+ const name = (0, import_path2.basename)(filePath);
846
+ return name === this.cfg.envFile || name.startsWith(".env");
847
+ }
848
+ // ─── ANSI strip helper (for width calculation) ────────────────────────────
849
+ strip(str) {
850
+ return str.replace(/\[[0-9;]*m/g, "").replace(/\][^]*/g, "");
1267
851
  }
852
+ // ─── Timestamp ────────────────────────────────────────────────────────────
853
+ ts() {
854
+ const n = /* @__PURE__ */ new Date();
855
+ const h = String(n.getHours()).padStart(2, "0");
856
+ const m = String(n.getMinutes()).padStart(2, "0");
857
+ const s = String(n.getSeconds()).padStart(2, "0");
858
+ return `${h}:${m}:${s}`;
859
+ }
860
+ // ─── Console output ───────────────────────────────────────────────────────
1268
861
  /**
1269
- * Stops the HMR system.
1270
- *
1271
- * @method stopHMR
1272
- * @private
1273
- *
1274
- * @returns {void}
862
+ * Startup banner — mirrors the infoServer() box style from CoreService.
863
+ *
864
+ * ╔══════════════════════════════════════════╗
865
+ * gradient title
866
+ * ╔══ bgGreen box ════════════════════════╗
867
+ * entry dist/index.js
868
+ * runtime node (IPC enabled)
869
+ * root ./src
870
+ * watching .ts .js .json .env
871
+ * debounce 300ms
872
+ * ╚══════════════════════════════════════════╝
1275
873
  */
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)
874
+ printBanner() {
875
+ const entryRel = (0, import_path2.relative)(process.cwd(), this.cfg.entry) || this.cfg.entry;
876
+ const rootRel = (0, import_path2.relative)(process.cwd(), this.cfg.rootDir) || ".";
877
+ const runtimeStr = this.cfg.runtime === "node" ? `node ${import_chalk2.default.blackBright("(IPC enabled)")}` : this.cfg.runtime;
878
+ const extStr = [...this.cfg.watchExtensions, ".env"].join(" ");
879
+ const ignoreStr = this.cfg.ignore.slice(0, 4).join(" ") + (this.cfg.ignore.length > 4 ? ` ${import_chalk2.default.blackBright(`+${this.cfg.ignore.length - 4} more`)}` : "");
880
+ const TITLE = "OPTICORE HOT RELOAD";
881
+ const rows = [
882
+ ` entry ${import_chalk2.default.white.bold(entryRel)}`,
883
+ ` runtime ${runtimeStr}`,
884
+ ` root ${import_chalk2.default.white(rootRel)}`,
885
+ ` watching ${import_chalk2.default.cyan(extStr)}`,
886
+ ` ignoring ${import_chalk2.default.blackBright(ignoreStr)}`,
887
+ ` debounce ${import_chalk2.default.white(`${this.cfg.debounceMs}ms`)}`
888
+ ];
889
+ const maxLen = Math.max(
890
+ TITLE.length + 4,
891
+ ...rows.map((r) => this.strip(r).length)
892
+ ) + 4;
893
+ const border = import_chalk2.default.bgGreen.white(" ".repeat(maxLen));
894
+ const titlePad = " ".repeat(Math.max(0, Math.floor((maxLen - TITLE.length) / 2)));
895
+ console.log("\n" + titlePad + (0, import_gradient_string.default)(["#43e97b", "#38f9d7", "#00c6fb"])(TITLE));
896
+ console.log(border);
897
+ rows.forEach((row) => {
898
+ const cleanLen = this.strip(row).length;
899
+ const padding = Math.max(0, maxLen - cleanLen - 2);
900
+ console.log(import_chalk2.default.bgGreen.white(` ${row}${" ".repeat(padding)} `));
1288
901
  });
902
+ console.log(border);
903
+ console.log(import_chalk2.default.blackBright(` watching for changes...
904
+ `));
1289
905
  }
1290
906
  /**
1291
- * Stops the server and HMR system cleanly.
1292
- *
1293
- * @method onStopServer
1294
- * @public
907
+ * HOT event in-process reload, no server restart.
1295
908
  *
1296
- * @returns {void}
909
+ * ✔ [ HOT ] 14:23:45 | .env → env variables reloaded
1297
910
  */
1298
- onStopServer() {
1299
- this.stopHMR();
1300
- if (this.server) {
1301
- this.server.close(() => {
1302
- SLogger(this.localLanguage).logger.info({
1303
- title: import_opticore_translator2.TranslationLoader.t("SERVER_STOPPED", this.localLanguage),
1304
- message: "Server stopped cleanly"
1305
- });
1306
- });
1307
- this.serverStatus = "STOPPED";
1308
- }
911
+ printHot(file, action) {
912
+ const badge = import_ansi_colors2.default.bgCyan(import_ansi_colors2.default.white.bold(" HOT "));
913
+ const ts = import_chalk2.default.blackBright(this.ts());
914
+ const sep = import_chalk2.default.blackBright("|");
915
+ const filePart = import_chalk2.default.cyan.bold(file.padEnd(32));
916
+ const arrow = import_chalk2.default.green("\u2192");
917
+ const msg = import_chalk2.default.green(action);
918
+ console.log(` ${import_chalk2.default.green("\u2714")} ${badge} ${ts} ${sep} ${filePart} ${arrow} ${msg}`);
1309
919
  }
1310
920
  /**
1311
- * Gets the current server state information.
921
+ * RELOAD event server restart triggered.
1312
922
  *
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
923
+ * ⚡ [ RELOAD ] 14:24:03 | src/routes/user.ts → restarting server...
1324
924
  */
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
- };
925
+ printReloading(file) {
926
+ const badge = import_ansi_colors2.default.bgYellow(import_ansi_colors2.default.white.bold(" RELOAD "));
927
+ const ts = import_chalk2.default.blackBright(this.ts());
928
+ const sep = import_chalk2.default.blackBright("|");
929
+ const filePart = import_chalk2.default.yellow.bold(file.padEnd(32));
930
+ const arrow = import_chalk2.default.yellow("\u2192");
931
+ const msg = import_chalk2.default.yellow("restarting server...");
932
+ console.log(`
933
+ ${import_chalk2.default.yellow("\u26A1")} ${badge} ${ts} ${sep} ${filePart} ${arrow} ${msg}`);
1349
934
  }
1350
935
  /**
1351
- * Gets the current server status.
1352
- *
1353
- * @method getServerStatus
1354
- * @public
936
+ * READY event server successfully restarted.
937
+ * Uses the same full-width bgGreen border as infoServer().
1355
938
  *
1356
- * @returns {TServerStatus} Current server status
939
+ * ════════════════════════════════════════════
940
+ * READY server restarted in 245ms
941
+ * ════════════════════════════════════════════
1357
942
  */
1358
- getServerStatus() {
1359
- return this.serverStatus;
943
+ printReady(elapsedMs) {
944
+ const msg = ` server restarted in ${import_chalk2.default.white.bold(`${elapsedMs}ms`)}`;
945
+ const cleanLen = this.strip(msg).length;
946
+ const width = Math.max(52, cleanLen + 6);
947
+ const border = import_chalk2.default.bgGreen.white(" ".repeat(width));
948
+ const padding = Math.max(0, width - cleanLen - 2);
949
+ const line = import_chalk2.default.bgGreen.white(` ${import_chalk2.default.bgGreen.white.bold(" READY ")} ${msg}${" ".repeat(padding)} `);
950
+ console.log(` ${border}`);
951
+ console.log(` ${line}`);
952
+ console.log(` ${border}
953
+ `);
1360
954
  }
1361
955
  /**
1362
- * Gets detailed server statistics.
1363
- *
1364
- * @method getServerStats
1365
- * @public
1366
- *
1367
- * @returns {IServerStats} Server statistics object
956
+ * CRASH event unexpected child process exit.
1368
957
  *
1369
- * @remarks
1370
- * Includes:
1371
- * - Performance metrics (CPU, memory)
1372
- * - Uptime information
1373
- * - HMR statistics
958
+ * ✘ [ CRASH ] 14:24:10 | server exited with code 1
1374
959
  */
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
- };
960
+ printCrash(code) {
961
+ const badge = import_ansi_colors2.default.bgRed(import_ansi_colors2.default.white.bold(" CRASH "));
962
+ const ts = import_chalk2.default.blackBright(this.ts());
963
+ const sep = import_chalk2.default.blackBright("|");
964
+ const msg = import_chalk2.default.red(`server exited with code ${import_chalk2.default.bold(String(code))}`);
965
+ console.log(`
966
+ ${import_chalk2.default.red("\u2718")} ${badge} ${ts} ${sep} ${msg}`);
1398
967
  }
1399
968
  /**
1400
- * Formats milliseconds into a human-readable uptime string.
969
+ * RETRY event auto-restart after crash.
1401
970
  *
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"
971
+ * ↺ [ RETRY ] 14:24:11 | attempt 1 / 5
1411
972
  */
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`;
1423
- } else {
1424
- return `${seconds}s`;
1425
- }
973
+ printCrashRetry(attempt, max) {
974
+ const badge = import_ansi_colors2.default.bgMagenta(import_ansi_colors2.default.white.bold(" RETRY "));
975
+ const ts = import_chalk2.default.blackBright(this.ts());
976
+ const sep = import_chalk2.default.blackBright("|");
977
+ const msg = import_chalk2.default.magenta(`auto-restart attempt ${import_chalk2.default.bold(`${attempt} / ${max}`)}`);
978
+ console.log(` ${import_chalk2.default.magenta("\u21BA")} ${badge} ${ts} ${sep} ${msg}`);
1426
979
  }
1427
980
  /**
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"
981
+ * LIMIT reached give up restarting.
1439
982
  */
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++;
1447
- }
1448
- return `${value.toFixed(2)} ${units[unitIndex]}`;
983
+ printCrashLimit(max) {
984
+ const badge = import_ansi_colors2.default.bgRed(import_ansi_colors2.default.white.bold(" ERROR "));
985
+ const ts = import_chalk2.default.blackBright(this.ts());
986
+ const sep = import_chalk2.default.blackBright("|");
987
+ const msg = import_chalk2.default.red(`max crash restarts reached (${import_chalk2.default.bold(String(max))}), giving up`);
988
+ console.log(`
989
+ ${import_chalk2.default.red("\u2718")} ${badge} ${ts} ${sep} ${msg}
990
+ `);
1449
991
  }
1450
992
  /**
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
993
+ * Error miscellaneous internal error.
1457
994
  */
1458
- isHMRActive() {
1459
- return this.getEnvironment.hmrEnabled && this.fileWatcher !== null;
995
+ printError(message) {
996
+ const badge = import_ansi_colors2.default.bgRed(import_ansi_colors2.default.white.bold(" ERROR "));
997
+ const ts = import_chalk2.default.blackBright(this.ts());
998
+ const sep = import_chalk2.default.blackBright("|");
999
+ console.error(` ${import_chalk2.default.red("\u2718")} ${badge} ${ts} ${sep} ${import_chalk2.default.red(message)}`);
1460
1000
  }
1461
1001
  /**
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
1002
+ * Stopped watcher shut down.
1474
1003
  */
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
1004
+ printStopped() {
1005
+ const badge = import_ansi_colors2.default.bgBlackBright(import_ansi_colors2.default.white.bold(" STOPPED"));
1006
+ const ts = import_chalk2.default.blackBright(this.ts());
1007
+ const sep = import_chalk2.default.blackBright("|");
1008
+ console.log(` ${import_chalk2.default.gray("\u25A0")} ${badge} ${ts} ${sep} ${import_chalk2.default.gray("watcher stopped")}
1009
+ `);
1010
+ }
1011
+ // ─── Graceful shutdown ────────────────────────────────────────────────────
1012
+ setupProcessSignals() {
1013
+ const shutdown = async () => {
1014
+ console.log("");
1015
+ await this.stop();
1016
+ process.exit(0);
1487
1017
  };
1018
+ process.once("SIGINT", shutdown);
1019
+ process.once("SIGTERM", shutdown);
1488
1020
  }
1489
1021
  };
1490
1022
  // Annotate the CommonJS export names for ESM import in node:
1491
1023
  0 && (module.exports = {
1024
+ HotReloadWatcher,
1492
1025
  WebServer,
1493
1026
  envPath
1494
1027
  });