opticore-webapp 1.0.86 → 1.0.88

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
@@ -462,6 +462,60 @@ var getEnvFileLoadingService = (filePath, localLanguage) => {
462
462
  }
463
463
  };
464
464
 
465
+ // src/application/service/hmrSupervisor.service.ts
466
+ var import_child_process = require("child_process");
467
+ var import_ansi_colors2 = __toESM(require("ansi-colors"), 1);
468
+ function startHmrSupervisor(options) {
469
+ let crashRestarts = 0;
470
+ let child = null;
471
+ let shuttingDown = false;
472
+ const spawnChild = () => {
473
+ child = (0, import_child_process.spawn)(
474
+ process.execPath,
475
+ [...process.execArgv, ...process.argv.slice(1)],
476
+ {
477
+ stdio: "inherit",
478
+ env: { ...process.env, OPTICORE_HMR_CHILD: "1" }
479
+ }
480
+ );
481
+ child.on("exit", (code, signal) => {
482
+ if (shuttingDown) return;
483
+ if (signal) {
484
+ return;
485
+ }
486
+ if (code === 0) {
487
+ spawnChild();
488
+ return;
489
+ }
490
+ if (!options.restartOnCrash || crashRestarts >= options.maxCrashRestarts) {
491
+ console.log(
492
+ `[${import_ansi_colors2.default.red("OptiCore HOT Reload")}] child crashed (exit code ${code}) \u2014 giving up after ${crashRestarts} restart(s).`
493
+ );
494
+ process.exit(code ?? 1);
495
+ return;
496
+ }
497
+ crashRestarts += 1;
498
+ console.log(
499
+ `[${import_ansi_colors2.default.red("OptiCore HOT Reload")}] child crashed (exit code ${code}) \u2014 restarting (${crashRestarts}/${options.maxCrashRestarts}).`
500
+ );
501
+ spawnChild();
502
+ });
503
+ };
504
+ const shutdown = (signal) => {
505
+ shuttingDown = true;
506
+ if (child && !child.killed) {
507
+ child.once("exit", () => process.exit(0));
508
+ child.kill(signal);
509
+ setTimeout(() => process.exit(0), 3e3).unref();
510
+ } else {
511
+ process.exit(0);
512
+ }
513
+ };
514
+ process.once("SIGINT", () => shutdown("SIGINT"));
515
+ process.once("SIGTERM", () => shutdown("SIGTERM"));
516
+ spawnChild();
517
+ }
518
+
465
519
  // src/core/webServer.core.ts
466
520
  var WebServerCore = class {
467
521
  serverUtility;
@@ -524,6 +578,16 @@ var WebServerCore = class {
524
578
  * @param dependenciesProvider
525
579
  */
526
580
  onStartServer(routers, databaseCallback, dependenciesProvider) {
581
+ if (!import_node_process4.default.env.OPTICORE_HMR_CHILD) {
582
+ const resolvedHmr = this.resolveHotReloadConfig();
583
+ if (resolvedHmr !== null) {
584
+ startHmrSupervisor({
585
+ restartOnCrash: this.hotReloadCfg?.restartOnCrash ?? this.getEnvironmentValue.hmrAutoRestarts ?? true,
586
+ maxCrashRestarts: this.hotReloadCfg?.maxCrashRestarts ?? (this.getEnvironmentValue.hmrMaxRestarts > 0 ? this.getEnvironmentValue.hmrMaxRestarts : 5)
587
+ });
588
+ return;
589
+ }
590
+ }
527
591
  this.loadTranslationFiles();
528
592
  getEnvFileLoadingService(".env", this.localLanguage);
529
593
  if (this.getEnvironmentValue.appPort === "" && Number(this.getEnvironmentValue.appPort) === 0) {
package/dist/index.d.cts CHANGED
@@ -17,10 +17,14 @@ interface WebServerConstructorInterface {
17
17
  * Enable hot reload in development mode.
18
18
  * - true → use all defaults
19
19
  * - HotReloadConfig → custom configuration
20
- * The watcher starts automatically when onStartServer() is called.
21
- * On code changes the HTTP server is closed gracefully and the process
22
- * exits (code 0) so your external runner restarts it:
23
- * tsx --watch src/index.ts | nodemon | node --watch dist/index.js
20
+ *
21
+ * `onStartServer()` runs the app under a built-in supervisor process
22
+ * when this is enabled: on code changes the HTTP server is closed
23
+ * gracefully, the process exits (code 0), and the supervisor
24
+ * immediately re-executes the same command — no external runner
25
+ * (nodemon, `tsx --watch`, `node --watch`, ...) is required. Running
26
+ * under one of those anyway still works; it just adds a redundant
27
+ * outer restart layer.
24
28
  */
25
29
  hotReload?: boolean | HotReloadConfig;
26
30
  }
package/dist/index.d.ts CHANGED
@@ -17,10 +17,14 @@ interface WebServerConstructorInterface {
17
17
  * Enable hot reload in development mode.
18
18
  * - true → use all defaults
19
19
  * - HotReloadConfig → custom configuration
20
- * The watcher starts automatically when onStartServer() is called.
21
- * On code changes the HTTP server is closed gracefully and the process
22
- * exits (code 0) so your external runner restarts it:
23
- * tsx --watch src/index.ts | nodemon | node --watch dist/index.js
20
+ *
21
+ * `onStartServer()` runs the app under a built-in supervisor process
22
+ * when this is enabled: on code changes the HTTP server is closed
23
+ * gracefully, the process exits (code 0), and the supervisor
24
+ * immediately re-executes the same command — no external runner
25
+ * (nodemon, `tsx --watch`, `node --watch`, ...) is required. Running
26
+ * under one of those anyway still works; it just adds a redundant
27
+ * outer restart layer.
24
28
  */
25
29
  hotReload?: boolean | HotReloadConfig;
26
30
  }
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/core/webServer.core.ts
2
2
  import * as path3 from "path";
3
- import process5 from "process";
3
+ import process6 from "process";
4
4
  import corsOrigin from "cors";
5
5
  import { CEventNameError as eventName2, ServerListenEventError as ServerListenEventError2 } from "opticore-catch-exception-error";
6
6
  import { express as express2 } from "opticore-express";
@@ -11,7 +11,7 @@ import { requestCallsEvent } from "opticore-request-call-event";
11
11
  import { HotReloadWatcher } from "opticore-watcher";
12
12
 
13
13
  // src/core/handlers/eventProcess.handler.ts
14
- import process from "process";
14
+ import process2 from "process";
15
15
  import EventEmitter from "events";
16
16
  import { express } from "opticore-express";
17
17
  import { ServerListenEventError, CEventNameError as eventName, CEvent as event } from "opticore-catch-exception-error";
@@ -22,42 +22,42 @@ function eventProcessHandler(localeLanguage) {
22
22
  errorEmitter.on(eventName.error, (error) => {
23
23
  serverListenEvent.listenerError(error);
24
24
  });
25
- process.on(event.beforeExit, (code) => {
25
+ process2.on(event.beforeExit, (code) => {
26
26
  setTimeout(() => {
27
27
  serverListenEvent.processBeforeExit(code);
28
28
  }, 100);
29
29
  });
30
- process.on(event.disconnect, () => {
30
+ process2.on(event.disconnect, () => {
31
31
  serverListenEvent.processDisconnected();
32
32
  });
33
- process.on(event.exit, (code) => {
33
+ process2.on(event.exit, (code) => {
34
34
  serverListenEvent.exited(code);
35
35
  });
36
- process.on(event.rejectionHandled, (promise) => {
36
+ process2.on(event.rejectionHandled, (promise) => {
37
37
  serverListenEvent.promiseRejectionHandled(promise);
38
38
  });
39
- process.on(event.uncaughtException, (error) => {
39
+ process2.on(event.uncaughtException, (error) => {
40
40
  serverListenEvent.uncaughtException(error);
41
41
  });
42
- process.on(event.uncaughtExceptionMonitor, (error) => {
42
+ process2.on(event.uncaughtExceptionMonitor, (error) => {
43
43
  serverListenEvent.uncaughtExceptionMonitor(error);
44
44
  });
45
- process.on(event.unhandledRejection, (reason, promise) => {
45
+ process2.on(event.unhandledRejection, (reason, promise) => {
46
46
  serverListenEvent.unhandledRejection(reason, promise);
47
47
  });
48
- process.on(event.warning, (warning) => {
48
+ process2.on(event.warning, (warning) => {
49
49
  serverListenEvent.warning(warning);
50
50
  });
51
- process.on(event.message, (message) => {
51
+ process2.on(event.message, (message) => {
52
52
  serverListenEvent.message(message);
53
53
  });
54
- process.on(event.multipleResolves, (type, promise, reason) => {
54
+ process2.on(event.multipleResolves, (type, promise, reason) => {
55
55
  serverListenEvent.multipleResolves(type, promise, reason);
56
56
  });
57
- process.on(event.sigint, () => {
57
+ process2.on(event.sigint, () => {
58
58
  serverListenEvent.processInterrupted();
59
59
  });
60
- process.on(event.sigterm, (signal) => {
60
+ process2.on(event.sigterm, (signal) => {
61
61
  serverListenEvent.sigtermSignalReceived(signal);
62
62
  });
63
63
  app.use((err, req, res, next) => {
@@ -66,7 +66,7 @@ function eventProcessHandler(localeLanguage) {
66
66
  }
67
67
 
68
68
  // src/application/service/core.service.ts
69
- import process3 from "process";
69
+ import process4 from "process";
70
70
  import chalk from "chalk";
71
71
  import * as path from "path";
72
72
  import * as fs from "fs";
@@ -76,8 +76,8 @@ import { TranslationLoader } from "opticore-translator";
76
76
  import { getEnvironmentValue } from "opticore-env-access";
77
77
 
78
78
  // src/utils/envPath.utils.ts
79
- import process2 from "process";
80
- var envPath = process2.cwd() + "/config/env/.env";
79
+ import process3 from "process";
80
+ var envPath = process3.cwd() + "/config/env/.env";
81
81
 
82
82
  // src/application/service/loaderTranslationFile.service.ts
83
83
  import { translationLoaderConfig } from "opticore-loader-translation";
@@ -169,7 +169,7 @@ var CoreService = class {
169
169
  getEnvFileLoading(filePath) {
170
170
  this.loadTranslationFiles();
171
171
  try {
172
- const fullPath = path.resolve(process3.cwd(), filePath);
172
+ const fullPath = path.resolve(process4.cwd(), filePath);
173
173
  if (fs.existsSync(fullPath)) {
174
174
  const env = fs.readFileSync(fullPath, "utf-8");
175
175
  const lines = env.split("\n");
@@ -177,7 +177,7 @@ var CoreService = class {
177
177
  const match = line.match(/^([^#=]+)=([^#]+)$/);
178
178
  if (match) {
179
179
  const key = match[1].trim();
180
- process3.env[key] = match[2].trim();
180
+ process4.env[key] = match[2].trim();
181
181
  }
182
182
  });
183
183
  }
@@ -195,7 +195,7 @@ var CoreService = class {
195
195
  * Returns an Object containing a node version, openssl, and v0
196
196
  */
197
197
  getVersions() {
198
- const { node, openssl, v8 } = process3.versions;
198
+ const { node, openssl, v8 } = process4.versions;
199
199
  const data = {
200
200
  "node version": node,
201
201
  "openssl": openssl,
@@ -216,14 +216,14 @@ var CoreService = class {
216
216
  */
217
217
  getUsageMemory() {
218
218
  this.loadTranslationFiles();
219
- const memoryData = process3.memoryUsage();
219
+ const memoryData = process4.memoryUsage();
220
220
  const data = {
221
221
  [TranslationLoader.t("totalMemoryAllocated", this.localLanguage)]: this.formatMemoryUsage(memoryData.rss),
222
222
  [TranslationLoader.t("sizeAllocatedHeap", this.localLanguage)]: this.formatMemoryUsage(memoryData.heapTotal),
223
223
  [TranslationLoader.t("memoryUsedExecution", this.localLanguage)]: this.formatMemoryUsage(memoryData.heapUsed),
224
224
  [TranslationLoader.t("externalMemory", this.localLanguage)]: this.formatMemoryUsage(memoryData.external),
225
- [TranslationLoader.t("memoryUsageUser", this.localLanguage)]: this.formatMemoryUsage(process3.cpuUsage().user),
226
- [TranslationLoader.t("memoryUsageSystem", this.localLanguage)]: this.formatMemoryUsage(process3.cpuUsage().system)
225
+ [TranslationLoader.t("memoryUsageUser", this.localLanguage)]: this.formatMemoryUsage(process4.cpuUsage().user),
226
+ [TranslationLoader.t("memoryUsageSystem", this.localLanguage)]: this.formatMemoryUsage(process4.cpuUsage().system)
227
227
  };
228
228
  return {
229
229
  "rss": data[TranslationLoader.t("totalMemoryAllocated", this.localLanguage)],
@@ -232,18 +232,18 @@ var CoreService = class {
232
232
  "external": data[TranslationLoader.t("externalMemory", this.localLanguage)],
233
233
  "user": data[TranslationLoader.t("memoryUsageUser", this.localLanguage)],
234
234
  "system": data[TranslationLoader.t("memoryUsageSystem", this.localLanguage)],
235
- "pid": process3.pid
235
+ "pid": process4.pid
236
236
  };
237
237
  }
238
238
  /**
239
239
  * Return an Object containing a project path and running server time
240
240
  */
241
241
  getProjectInfo() {
242
- const startTime = process3.hrtime();
243
- const endTime = process3.hrtime(startTime);
242
+ const startTime = process4.hrtime();
243
+ const endTime = process4.hrtime(startTime);
244
244
  const executionTime = (endTime[0] * 1e9 + endTime[1]) / 1e6;
245
245
  return {
246
- "projectPath": path.join(process3.cwd()),
246
+ "projectPath": path.join(process4.cwd()),
247
247
  "startingTime": `${executionTime.toFixed(5)} ms`
248
248
  };
249
249
  }
@@ -292,7 +292,7 @@ var CoreService = class {
292
292
  const maxLength = Math.max(...messages.map((m) => {
293
293
  return m.replace(/\u001b\[[0-9]{1,2}m/g, "").length;
294
294
  })) + 4;
295
- console.log(chalk.blackBright(`${TranslationLoader.t("tailingServerLog", this.localLanguage)} (${path.join(path.basename(process3.cwd()), "logs", "app.log")})`));
295
+ console.log(chalk.blackBright(`${TranslationLoader.t("tailingServerLog", this.localLanguage)} (${path.join(path.basename(process4.cwd()), "logs", "app.log")})`));
296
296
  const border = chalk.bgGreen.white(" ".repeat(maxLength));
297
297
  console.log(border);
298
298
  messages.forEach((msg) => {
@@ -397,7 +397,7 @@ import { SContainer as SContainer2 } from "opticore-dependency-inject";
397
397
 
398
398
  // src/application/service/getEnvFileLoading.service.ts
399
399
  import path2 from "path";
400
- import process4 from "process";
400
+ import process5 from "process";
401
401
  import fs2 from "fs";
402
402
  import { TranslationLoader as TranslationLoader2 } from "opticore-translator";
403
403
  import { HttpStatusCode as status2 } from "opticore-http-response";
@@ -405,7 +405,7 @@ var getEnvFileLoadingService = (filePath, localLanguage) => {
405
405
  loaderTranslationFile(localLanguage);
406
406
  const logger = dependenciesContainerProvider(localLanguage).resolve("LoggerCore");
407
407
  try {
408
- const fullPath = path2.resolve(process4.cwd(), filePath);
408
+ const fullPath = path2.resolve(process5.cwd(), filePath);
409
409
  if (fs2.existsSync(fullPath)) {
410
410
  const env = fs2.readFileSync(fullPath, "utf-8");
411
411
  const lines = env.split("\n");
@@ -413,7 +413,7 @@ var getEnvFileLoadingService = (filePath, localLanguage) => {
413
413
  const match = line.match(/^([^#=]+)=([^#]+)$/);
414
414
  if (match) {
415
415
  const key = match[1].trim();
416
- process4.env[key] = match[2].trim();
416
+ process5.env[key] = match[2].trim();
417
417
  }
418
418
  });
419
419
  }
@@ -428,6 +428,60 @@ var getEnvFileLoadingService = (filePath, localLanguage) => {
428
428
  }
429
429
  };
430
430
 
431
+ // src/application/service/hmrSupervisor.service.ts
432
+ import { spawn } from "child_process";
433
+ import colors2 from "ansi-colors";
434
+ function startHmrSupervisor(options) {
435
+ let crashRestarts = 0;
436
+ let child = null;
437
+ let shuttingDown = false;
438
+ const spawnChild = () => {
439
+ child = spawn(
440
+ process.execPath,
441
+ [...process.execArgv, ...process.argv.slice(1)],
442
+ {
443
+ stdio: "inherit",
444
+ env: { ...process.env, OPTICORE_HMR_CHILD: "1" }
445
+ }
446
+ );
447
+ child.on("exit", (code, signal) => {
448
+ if (shuttingDown) return;
449
+ if (signal) {
450
+ return;
451
+ }
452
+ if (code === 0) {
453
+ spawnChild();
454
+ return;
455
+ }
456
+ if (!options.restartOnCrash || crashRestarts >= options.maxCrashRestarts) {
457
+ console.log(
458
+ `[${colors2.red("OptiCore HOT Reload")}] child crashed (exit code ${code}) \u2014 giving up after ${crashRestarts} restart(s).`
459
+ );
460
+ process.exit(code ?? 1);
461
+ return;
462
+ }
463
+ crashRestarts += 1;
464
+ console.log(
465
+ `[${colors2.red("OptiCore HOT Reload")}] child crashed (exit code ${code}) \u2014 restarting (${crashRestarts}/${options.maxCrashRestarts}).`
466
+ );
467
+ spawnChild();
468
+ });
469
+ };
470
+ const shutdown = (signal) => {
471
+ shuttingDown = true;
472
+ if (child && !child.killed) {
473
+ child.once("exit", () => process.exit(0));
474
+ child.kill(signal);
475
+ setTimeout(() => process.exit(0), 3e3).unref();
476
+ } else {
477
+ process.exit(0);
478
+ }
479
+ };
480
+ process.once("SIGINT", () => shutdown("SIGINT"));
481
+ process.once("SIGTERM", () => shutdown("SIGTERM"));
482
+ spawnChild();
483
+ }
484
+
431
485
  // src/core/webServer.core.ts
432
486
  var WebServerCore = class {
433
487
  serverUtility;
@@ -490,6 +544,16 @@ var WebServerCore = class {
490
544
  * @param dependenciesProvider
491
545
  */
492
546
  onStartServer(routers, databaseCallback, dependenciesProvider) {
547
+ if (!process6.env.OPTICORE_HMR_CHILD) {
548
+ const resolvedHmr = this.resolveHotReloadConfig();
549
+ if (resolvedHmr !== null) {
550
+ startHmrSupervisor({
551
+ restartOnCrash: this.hotReloadCfg?.restartOnCrash ?? this.getEnvironmentValue.hmrAutoRestarts ?? true,
552
+ maxCrashRestarts: this.hotReloadCfg?.maxCrashRestarts ?? (this.getEnvironmentValue.hmrMaxRestarts > 0 ? this.getEnvironmentValue.hmrMaxRestarts : 5)
553
+ });
554
+ return;
555
+ }
556
+ }
493
557
  this.loadTranslationFiles();
494
558
  getEnvFileLoadingService(".env", this.localLanguage);
495
559
  if (this.getEnvironmentValue.appPort === "" && Number(this.getEnvironmentValue.appPort) === 0) {
@@ -517,7 +581,7 @@ var WebServerCore = class {
517
581
  this.registerDependencies(dependenciesProvider);
518
582
  }
519
583
  this.container.loadServices();
520
- this.expressApp.use(express2.static(path3.join(process5.cwd(), "public/template")));
584
+ this.expressApp.use(express2.static(path3.join(process6.cwd(), "public/template")));
521
585
  this.registerRoutes(routers);
522
586
  const resolvedHmr = this.resolveHotReloadConfig();
523
587
  if (resolvedHmr !== null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opticore-webapp",
3
- "version": "1.0.86",
3
+ "version": "1.0.88",
4
4
  "description": "wep server",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -32,18 +32,18 @@
32
32
  "chalk": "^5.6.2",
33
33
  "cors": "^2.8.6",
34
34
  "gradient-string": "^3.0.0",
35
- "opticore-catch-exception-error": "^1.0.29",
36
- "opticore-dependency-inject": "^1.0.10",
37
- "opticore-env-access": "^1.0.23",
35
+ "opticore-catch-exception-error": "^1.0.30",
36
+ "opticore-dependency-inject": "^1.0.11",
37
+ "opticore-env-access": "^1.0.25",
38
38
  "opticore-express": "^1.0.9",
39
39
  "opticore-http-response": "^1.0.11",
40
- "opticore-loader-translation": "^1.0.9",
41
- "opticore-logger": "^1.0.32",
42
- "opticore-request-call-event": "^1.0.17",
40
+ "opticore-loader-translation": "^1.0.10",
41
+ "opticore-logger": "^1.0.33",
42
+ "opticore-request-call-event": "^1.0.18",
43
43
  "opticore-router": "^1.0.22",
44
- "opticore-server-logger": "^1.0.14",
45
- "opticore-translator": "^1.0.16",
46
- "opticore-watcher": "^1.0.31"
44
+ "opticore-server-logger": "^1.0.15",
45
+ "opticore-translator": "^1.0.17",
46
+ "opticore-watcher": "^1.0.32"
47
47
  },
48
48
  "overrides": {
49
49
  "js-yaml": "^4.2.0",