neex 0.6.23 → 0.6.25
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/src/commands/start-commands.js +86 -10
- package/dist/src/start-manager.js +34 -121
- package/package.json +1 -1
|
@@ -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,14 +91,9 @@ async function getStartCommand(filePath, showInfo) {
|
|
|
90
91
|
}
|
|
91
92
|
function addStartCommands(program) {
|
|
92
93
|
let startManager = null;
|
|
93
|
-
|
|
94
|
-
if (startManager) {
|
|
95
|
-
startManager.stop();
|
|
96
|
-
startManager = null;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
94
|
+
// Start command - run applications in production mode
|
|
99
95
|
program
|
|
100
|
-
.command('start <file>')
|
|
96
|
+
.command('start <file>') // Made file mandatory
|
|
101
97
|
.alias('s')
|
|
102
98
|
.description('Start JavaScript/TypeScript applications in production mode')
|
|
103
99
|
.option('-c, --no-color', 'Disable colored output')
|
|
@@ -162,17 +158,97 @@ function addStartCommands(program) {
|
|
|
162
158
|
// Log configuration only if --info flag is set
|
|
163
159
|
if (showInfo) {
|
|
164
160
|
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Configuration:`));
|
|
165
|
-
console;
|
|
161
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Target: ${chalk_1.default.cyan(file)}`));
|
|
162
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Runtime: ${chalk_1.default.cyan(startConfig.runtime)}`));
|
|
163
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Process name: ${chalk_1.default.cyan(startConfig.processName)}`));
|
|
164
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Environment: ${chalk_1.default.cyan(options.env)}`));
|
|
165
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch mode: ${chalk_1.default.cyan(options.watch ? 'Yes' : 'No')}`));
|
|
166
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster mode: ${chalk_1.default.cyan(options.cluster ? 'Yes' : 'No')}`));
|
|
167
|
+
if (options.cluster) {
|
|
168
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Cluster instances: ${chalk_1.default.cyan(options.clusterInstances || 'auto')}`));
|
|
169
|
+
}
|
|
170
|
+
if (options.watch) {
|
|
171
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Watch paths: ${chalk_1.default.cyan(watchPaths.join(', '))}`));
|
|
172
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Extensions: ${chalk_1.default.cyan(extensions.join(', '))}`));
|
|
173
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Restart delay: ${chalk_1.default.cyan(options.delay || 1000)}ms`));
|
|
174
|
+
}
|
|
175
|
+
if (options.maxRestarts) {
|
|
176
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Max restarts: ${chalk_1.default.cyan(options.maxRestarts)}`));
|
|
177
|
+
}
|
|
178
|
+
if (options.memoryLimit) {
|
|
179
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} Memory limit: ${chalk_1.default.cyan(options.memoryLimit)}MB`));
|
|
180
|
+
}
|
|
181
|
+
if (options.cpuLimit) {
|
|
182
|
+
console.log(chalk_1.default.blue(` ${figures_1.default.arrowRight} CPU limit: ${chalk_1.default.cyan(options.cpuLimit)}%`));
|
|
183
|
+
}
|
|
184
|
+
if (options.verbose) {
|
|
185
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Verbose mode enabled - showing detailed logs`));
|
|
186
|
+
}
|
|
187
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Starting production application server...`));
|
|
188
|
+
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...`));
|
|
189
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Press Ctrl+C to stop the application server`));
|
|
190
|
+
console.log(chalk_1.default.gray(`${'='.repeat(60)}`));
|
|
166
191
|
}
|
|
192
|
+
// Create StartManager instance
|
|
193
|
+
startManager = new start_manager_js_1.StartManager({
|
|
194
|
+
runnerName: 'neex start',
|
|
195
|
+
targetFile: file,
|
|
196
|
+
command: startConfig.command,
|
|
197
|
+
processName: startConfig.processName,
|
|
198
|
+
runtime: startConfig.runtime,
|
|
199
|
+
environment: options.env,
|
|
200
|
+
parallel: false,
|
|
201
|
+
color: options.color,
|
|
202
|
+
showTiming: options.timing,
|
|
203
|
+
prefix: options.prefix,
|
|
204
|
+
printOutput: options.output,
|
|
205
|
+
minimalOutput: options.minimal,
|
|
206
|
+
watch: options.watch,
|
|
207
|
+
watchPaths: watchPaths,
|
|
208
|
+
ignore: ignorePatterns,
|
|
209
|
+
ext: extensions,
|
|
210
|
+
delay: options.delay || 1000,
|
|
211
|
+
maxRestarts: options.maxRestarts,
|
|
212
|
+
restartDelay: options.restartDelay || 3000,
|
|
213
|
+
verbose: options.verbose,
|
|
214
|
+
showInfo: showInfo,
|
|
215
|
+
signal: options.signal,
|
|
216
|
+
cluster: options.cluster,
|
|
217
|
+
clusterInstances: options.clusterInstances,
|
|
218
|
+
memoryLimit: options.memoryLimit,
|
|
219
|
+
cpuLimit: options.cpuLimit,
|
|
220
|
+
groupOutput: false,
|
|
221
|
+
isServerMode: true,
|
|
222
|
+
stopOnError: false
|
|
223
|
+
});
|
|
224
|
+
// Start the application server
|
|
225
|
+
await startManager.start();
|
|
167
226
|
}
|
|
168
227
|
catch (error) {
|
|
169
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} neex start:
|
|
228
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} neex start: Fatal error occurred`));
|
|
229
|
+
if (error instanceof Error) {
|
|
230
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Details: ${error.message}`));
|
|
231
|
+
if (options.verbose && error.stack) {
|
|
232
|
+
console.error(chalk_1.default.gray(`Stack trace:\n${error.stack}`));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} Unknown error occurred`));
|
|
237
|
+
}
|
|
238
|
+
console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Try running with --verbose flag for more details`));
|
|
170
239
|
process.exit(1);
|
|
171
240
|
}
|
|
172
241
|
});
|
|
242
|
+
// Return cleanup function for start manager
|
|
173
243
|
return {
|
|
174
244
|
getStartManager: () => startManager,
|
|
175
|
-
cleanupStart
|
|
245
|
+
cleanupStart: () => {
|
|
246
|
+
if (startManager && startManager.isActive()) {
|
|
247
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} neex start: Stopping application server...`));
|
|
248
|
+
startManager.stop();
|
|
249
|
+
console.log(chalk_1.default.green(`${figures_1.default.tick} neex start: Application server stopped successfully`));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
176
252
|
};
|
|
177
253
|
}
|
|
178
254
|
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
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
}
|