neex 0.6.23 → 0.6.24

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.
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.addStartCommands = void 0;
30
+ const start_manager_js_1 = require("../start-manager.js");
30
31
  const chalk_1 = __importDefault(require("chalk"));
31
32
  const figures_1 = __importDefault(require("figures"));
32
33
  const path = __importStar(require("path"));
@@ -90,12 +91,7 @@ async function getStartCommand(filePath, showInfo) {
90
91
  }
91
92
  function addStartCommands(program) {
92
93
  let startManager = null;
93
- const cleanupStart = () => {
94
- if (startManager) {
95
- startManager.stop();
96
- startManager = null;
97
- }
98
- };
94
+ // Start command - run applications in production mode
99
95
  program
100
96
  .command('start <file>')
101
97
  .alias('s')
@@ -122,10 +118,6 @@ function addStartCommands(program) {
122
118
  .action(async (file, options) => {
123
119
  try {
124
120
  const showInfo = options.info || false;
125
- if (showInfo) {
126
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Starting production application server...`));
127
- console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Target file: ${chalk_1.default.cyan(file)}`));
128
- }
129
121
  // Validate file parameter
130
122
  if (!file || file.trim() === '') {
131
123
  console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Error - No file specified!`));
@@ -133,6 +125,11 @@ function addStartCommands(program) {
133
125
  console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Example: neex start dist/server.js`));
134
126
  process.exit(1);
135
127
  }
128
+ // Show initial info (only if --info flag is set)
129
+ if (showInfo) {
130
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Starting production application server...`));
131
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Target file: ${chalk_1.default.cyan(file)}`));
132
+ }
136
133
  // Get the start command configuration
137
134
  let startConfig;
138
135
  try {
@@ -162,17 +159,101 @@ function addStartCommands(program) {
162
159
  // Log configuration only if --info flag is set
163
160
  if (showInfo) {
164
161
  console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
165
- console;
162
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(file)}`));
163
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Runtime: ${chalk_1.default.cyan(startConfig.runtime)}`));
164
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Process name: ${chalk_1.default.cyan(startConfig.processName)}`));
165
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Environment: ${chalk_1.default.cyan(options.env)}`));
166
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
167
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster mode: ${chalk_1.default.cyan(options.cluster ? 'Yes' : 'No')}`));
168
+ if (options.cluster) {
169
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster instances: ${chalk_1.default.cyan(options.clusterInstances || 'auto')}`));
170
+ }
171
+ if (options.watch) {
172
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch paths: ${chalk_1.default.cyan(watchPaths.join(', '))}`));
173
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Extensions: ${chalk_1.default.cyan(extensions.join(', '))}`));
174
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Restart delay: ${chalk_1.default.cyan(options.delay || 1000)}ms`));
175
+ }
176
+ if (options.maxRestarts) {
177
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Max restarts: ${chalk_1.default.cyan(options.maxRestarts)}`));
178
+ }
179
+ if (options.memoryLimit) {
180
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Memory limit: ${chalk_1.default.cyan(options.memoryLimit)}MB`));
181
+ }
182
+ if (options.cpuLimit) {
183
+ console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} CPU limit: ${chalk_1.default.cyan(options.cpuLimit)}%`));
184
+ }
185
+ if (options.verbose) {
186
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Verbose mode enabled - showing detailed logs`));
187
+ }
188
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting production application server...`));
189
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Launching ${chalk_1.default.cyan(startConfig.processName)} in ${chalk_1.default.cyan(options.env)} mode...`));
190
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Press Ctrl+C to stop the application server`));
191
+ console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
166
192
  }
193
+ else {
194
+ // Minimal output without --info flag (similar to neex dev)
195
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting ${chalk_1.default.cyan(path.basename(file))} in ${chalk_1.default.cyan(options.env)} mode...`));
196
+ }
197
+ // Create StartManager instance
198
+ startManager = new start_manager_js_1.StartManager({
199
+ runnerName: 'neex start',
200
+ targetFile: file,
201
+ command: startConfig.command,
202
+ processName: startConfig.processName,
203
+ runtime: startConfig.runtime,
204
+ environment: options.env,
205
+ parallel: false,
206
+ color: options.color,
207
+ showTiming: options.timing,
208
+ prefix: options.prefix,
209
+ printOutput: options.output,
210
+ minimalOutput: options.minimal,
211
+ watch: options.watch,
212
+ watchPaths: watchPaths,
213
+ ignore: ignorePatterns,
214
+ ext: extensions,
215
+ delay: options.delay || 1000,
216
+ maxRestarts: options.maxRestarts,
217
+ restartDelay: options.restartDelay || 3000,
218
+ verbose: options.verbose,
219
+ showInfo: showInfo,
220
+ signal: options.signal,
221
+ cluster: options.cluster,
222
+ clusterInstances: options.clusterInstances,
223
+ memoryLimit: options.memoryLimit,
224
+ cpuLimit: options.cpuLimit,
225
+ groupOutput: false,
226
+ isServerMode: true,
227
+ stopOnError: false
228
+ });
229
+ // Start the application server
230
+ await startManager.start();
167
231
  }
168
232
  catch (error) {
169
- console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
233
+ console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Fatal error occurred`));
234
+ if (error instanceof Error) {
235
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
236
+ if (options.verbose && error.stack) {
237
+ console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
238
+ }
239
+ }
240
+ else {
241
+ console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
242
+ }
243
+ console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
170
244
  process.exit(1);
171
245
  }
172
246
  });
247
+ // Return cleanup function for start manager
173
248
  return {
174
249
  getStartManager: () => startManager,
175
- cleanupStart
250
+ cleanupStart: () => {
251
+ if (startManager && startManager.isActive()) {
252
+ console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Stopping application server...`));
253
+ startManager.stop();
254
+ console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Application server stopped successfully`));
255
+ }
256
+ }
176
257
  };
177
258
  }
178
259
  exports.addStartCommands = addStartCommands;
@@ -45,9 +45,6 @@ class StartManager {
45
45
  cpuUsage: 0,
46
46
  uptime: 0
47
47
  };
48
- if (!options.targetFile || !options.command || !options.processName || !options.runtime) {
49
- throw new Error('Missing required options: targetFile, command, processName, and runtime are required');
50
- }
51
48
  const defaultOptions = {
52
49
  parallel: false,
53
50
  printOutput: true,
@@ -84,31 +81,10 @@ class StartManager {
84
81
  cluster: false,
85
82
  clusterInstances: os.cpus().length
86
83
  };
87
- // Validate numeric values
88
- const validateNumber = (value, name) => {
89
- const num = parseInt(value);
90
- if (isNaN(num) || num < 0) {
91
- throw new Error(`Invalid ${name}: must be a non-negative number`);
92
- }
93
- return num;
94
- };
95
84
  this.options = {
96
85
  ...defaultOptions,
97
- ...options,
98
- delay: validateNumber(options.delay || defaultOptions.delay, 'delay'),
99
- clusterInstances: validateNumber(options.clusterInstances || defaultOptions.clusterInstances, 'clusterInstances'),
100
- memoryLimit: options.memoryLimit ? validateNumber(options.memoryLimit, 'memoryLimit') : undefined,
101
- cpuLimit: options.cpuLimit ? validateNumber(options.cpuLimit, 'cpuLimit') : undefined,
102
- maxRestarts: options.maxRestarts ? validateNumber(options.maxRestarts, 'maxRestarts') : undefined,
103
- restartDelay: validateNumber(options.restartDelay || defaultOptions.restartDelay, 'restartDelay')
86
+ ...options
104
87
  };
105
- // Validate environment
106
- if (this.options.environment) {
107
- this.options.environment = this.options.environment.toLowerCase();
108
- if (!['production', 'development', 'staging', 'test'].includes(this.options.environment)) {
109
- throw new Error(`Invalid environment: ${this.options.environment}. Must be one of: production, development, staging, test`);
110
- }
111
- }
112
88
  }
113
89
  setupFileWatcher() {
114
90
  var _a;
@@ -195,59 +171,20 @@ class StartManager {
195
171
  logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
196
172
  logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
197
173
  }
198
- // Check if we should restart
199
- if (!this.shouldRestart()) {
200
- if (this.options.showInfo) {
201
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
202
- }
203
- await this.stop();
204
- return;
205
- }
206
174
  // Wait before restarting
207
175
  await new Promise(resolve => setTimeout(resolve, this.options.restartDelay));
208
- try {
209
- await this.gracefulRestart();
210
- }
211
- catch (error) {
212
- logger_1.default.printLine(`Failed to restart application: ${error.message}`, 'error');
213
- if (this.options.stopOnError) {
214
- await this.stop();
215
- }
216
- }
176
+ await this.gracefulRestart();
217
177
  }
218
178
  collectProcessStats() {
219
- var _a;
220
179
  if (!this.options.showInfo) {
221
180
  return;
222
181
  }
223
- try {
224
- const memUsage = process.memoryUsage();
225
- this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
226
- this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
227
- // More accurate CPU usage calculation
228
- const cpuUsage = process.cpuUsage();
229
- const totalCpuTime = cpuUsage.user + cpuUsage.system;
230
- const timeDiff = Date.now() - (((_a = this.lastRestartTime) === null || _a === void 0 ? void 0 : _a.getTime()) || this.startTime.getTime());
231
- this.processStats.cpuUsage = Math.round((totalCpuTime / timeDiff) * 100);
232
- // Check resource limits
233
- if (this.options.memoryLimit && this.processStats.memoryUsage > this.options.memoryLimit) {
234
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
235
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} Memory limit exceeded: ${this.processStats.memoryUsage}MB > ${this.options.memoryLimit}MB`)}`, 'warn');
236
- if (this.options.stopOnError) {
237
- this.stop();
238
- }
239
- }
240
- if (this.options.cpuLimit && this.processStats.cpuUsage > this.options.cpuLimit) {
241
- const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
242
- logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.warning} CPU limit exceeded: ${this.processStats.cpuUsage}% > ${this.options.cpuLimit}%`)}`, 'warn');
243
- if (this.options.stopOnError) {
244
- this.stop();
245
- }
246
- }
247
- }
248
- catch (error) {
249
- logger_1.default.printLine(`Failed to collect process stats: ${error.message}`, 'error');
250
- }
182
+ const memUsage = process.memoryUsage();
183
+ this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
184
+ this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
185
+ // Simple CPU usage approximation
186
+ const cpuUsage = process.cpuUsage();
187
+ this.processStats.cpuUsage = Math.round(((cpuUsage.user + cpuUsage.system) / 1000000) * 100) / 100;
251
188
  }
252
189
  printStartBanner() {
253
190
  var _a, _b;
@@ -382,35 +319,6 @@ class StartManager {
382
319
  logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
383
320
  }
384
321
  }
385
- setupGracefulShutdown() {
386
- const handleSignal = async (signal) => {
387
- if (!this.isRunning) {
388
- return;
389
- }
390
- try {
391
- if (this.options.showInfo) {
392
- console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
393
- }
394
- await this.stop();
395
- process.exit(0);
396
- }
397
- catch (error) {
398
- logger_1.default.printLine(`Failed to handle ${signal}: ${error.message}`, 'error');
399
- process.exit(1);
400
- }
401
- };
402
- process.on('SIGINT', () => handleSignal('SIGINT'));
403
- process.on('SIGTERM', () => handleSignal('SIGTERM'));
404
- process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
405
- process.on('uncaughtException', (error) => {
406
- logger_1.default.printLine(`Uncaught Exception: ${error.message}`, 'error');
407
- handleSignal('SIGTERM');
408
- });
409
- process.on('unhandledRejection', (reason) => {
410
- logger_1.default.printLine(`Unhandled Rejection: ${reason}`, 'error');
411
- handleSignal('SIGTERM');
412
- });
413
- }
414
322
  async stop() {
415
323
  const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
416
324
  if (!this.isRunning) {
@@ -420,30 +328,35 @@ class StartManager {
420
328
  logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Stopping ${this.options.processName}...`)}`, 'info');
421
329
  }
422
330
  this.isRunning = false;
423
- try {
424
- // Stop file watcher
425
- if (this.fileWatcher) {
426
- await this.fileWatcher.stop();
427
- }
428
- // Stop application gracefully
429
- if (this.runner) {
430
- await this.runner.cleanup(this.options.signal);
431
- }
432
- // Calculate final stats
433
- const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
434
- const uptimeStr = this.formatUptime(uptime);
435
- if (this.options.showInfo) {
436
- logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
437
- logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
438
- }
331
+ // Stop file watcher
332
+ if (this.fileWatcher) {
333
+ this.fileWatcher.stop();
439
334
  }
440
- catch (error) {
441
- logger_1.default.printLine(`Failed to stop application: ${error.message}`, 'error');
442
- if (this.options.stopOnError) {
443
- process.exit(1);
444
- }
335
+ // Stop application gracefully
336
+ if (this.runner) {
337
+ this.runner.cleanup(this.options.signal);
338
+ }
339
+ // Calculate final stats
340
+ const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
341
+ const uptimeStr = this.formatUptime(uptime);
342
+ if (this.options.showInfo) {
343
+ logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
344
+ logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
445
345
  }
446
346
  }
347
+ setupGracefulShutdown() {
348
+ const handleSignal = (signal) => {
349
+ if (this.options.showInfo) {
350
+ console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
351
+ }
352
+ this.stop().then(() => {
353
+ process.exit(0);
354
+ });
355
+ };
356
+ process.on('SIGINT', () => handleSignal('SIGINT'));
357
+ process.on('SIGTERM', () => handleSignal('SIGTERM'));
358
+ process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
359
+ }
447
360
  isActive() {
448
361
  return this.isRunning;
449
362
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.23",
3
+ "version": "0.6.24",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",