neex 0.6.44 → 0.6.46
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/bun.lock +626 -0
- package/dist/src/build-manager.js +310 -287
- package/dist/src/commands/build-commands.js +43 -162
- package/dist/src/commands/dev-commands.js +40 -179
- package/dist/src/commands/start-commands.js +39 -235
- package/dist/src/dev-manager.js +248 -0
- package/dist/src/dev-runner.js +8 -8
- package/dist/src/logger-manager.js +17 -0
- package/dist/src/logger-process.js +11 -42
- package/dist/src/start-manager.js +91 -369
- package/dist/src/watcher.js +12 -22
- package/package.json +4 -1
|
@@ -3,46 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
// src/.logger-process.ts
|
|
6
|
+
exports.logger = void 0;
|
|
8
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
chalk_1.default.blue,
|
|
20
|
-
chalk_1.default.yellow,
|
|
21
|
-
chalk_1.default.green,
|
|
22
|
-
chalk_1.default.red
|
|
23
|
-
];
|
|
24
|
-
let hash = 0;
|
|
25
|
-
for (let i = 0; i < command.length; i++) {
|
|
26
|
-
hash = (hash << 5) - hash + command.charCodeAt(i);
|
|
27
|
-
hash |= 0;
|
|
28
|
-
}
|
|
29
|
-
return colors[Math.abs(hash) % colors.length];
|
|
30
|
-
}
|
|
31
|
-
log(data) {
|
|
32
|
-
this.print(data.toString(), process.stdout);
|
|
33
|
-
}
|
|
34
|
-
error(data) {
|
|
35
|
-
this.print(data.toString(), process.stderr, chalk_1.default.red);
|
|
36
|
-
}
|
|
37
|
-
print(data, stream, colorizer) {
|
|
38
|
-
const lines = data.split('\n').filter(line => line.trim().length > 0);
|
|
39
|
-
for (const line of lines) {
|
|
40
|
-
const coloredLine = colorizer ? colorizer(line) : line;
|
|
41
|
-
stream.write(`${this.prefix}${coloredLine}\n`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
info(message) {
|
|
45
|
-
console.log(`${this.prefix}${chalk_1.default.blue(message)}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
exports.LoggerProcess = LoggerProcess;
|
|
8
|
+
exports.logger = {
|
|
9
|
+
printLine: (message, level = "info") => {
|
|
10
|
+
const prefix = {
|
|
11
|
+
info: chalk_1.default.blue("i"),
|
|
12
|
+
warn: chalk_1.default.yellow("!"),
|
|
13
|
+
error: chalk_1.default.red("x"),
|
|
14
|
+
}[level];
|
|
15
|
+
console.log(`${prefix} ${message}`);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -1,399 +1,121 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
6
|
exports.StartManager = void 0;
|
|
30
|
-
// src/start-manager.ts - Production application
|
|
31
|
-
const
|
|
32
|
-
const
|
|
7
|
+
// src/start-manager.ts - Production application runner
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const logger_manager_js_1 = require("./logger-manager.js");
|
|
33
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
34
11
|
const figures_1 = __importDefault(require("figures"));
|
|
35
|
-
const
|
|
36
|
-
const
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
37
14
|
class StartManager {
|
|
38
15
|
constructor(options) {
|
|
39
|
-
this.
|
|
40
|
-
this.
|
|
41
|
-
this.
|
|
42
|
-
this.startTime = new Date();
|
|
43
|
-
this.processStats = {
|
|
44
|
-
memoryUsage: 0,
|
|
45
|
-
cpuUsage: 0,
|
|
46
|
-
uptime: 0
|
|
47
|
-
};
|
|
48
|
-
const defaultOptions = {
|
|
49
|
-
parallel: false,
|
|
50
|
-
printOutput: true,
|
|
51
|
-
color: true,
|
|
52
|
-
showTiming: true,
|
|
53
|
-
prefix: true,
|
|
54
|
-
stopOnError: false,
|
|
55
|
-
minimalOutput: false,
|
|
56
|
-
groupOutput: false,
|
|
57
|
-
isServerMode: true,
|
|
58
|
-
watch: false,
|
|
59
|
-
watchPaths: [],
|
|
60
|
-
ignore: [
|
|
61
|
-
'node_modules/**',
|
|
62
|
-
'.git/**',
|
|
63
|
-
'*.log',
|
|
64
|
-
'src/**',
|
|
65
|
-
'test/**',
|
|
66
|
-
'tests/**',
|
|
67
|
-
'coverage/**',
|
|
68
|
-
'.nyc_output/**',
|
|
69
|
-
'*.tmp',
|
|
70
|
-
'*.temp'
|
|
71
|
-
],
|
|
72
|
-
ext: ['js', 'mjs', 'json'],
|
|
73
|
-
delay: 1000,
|
|
74
|
-
verbose: false,
|
|
75
|
-
showInfo: false,
|
|
76
|
-
runnerName: 'neex start',
|
|
77
|
-
environment: 'production',
|
|
78
|
-
maxRestarts: 10,
|
|
79
|
-
restartDelay: 3000,
|
|
80
|
-
signal: 'SIGTERM',
|
|
81
|
-
cluster: false,
|
|
82
|
-
clusterInstances: os.cpus().length
|
|
83
|
-
};
|
|
84
|
-
this.options = {
|
|
85
|
-
...defaultOptions,
|
|
86
|
-
...options
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
setupFileWatcher() {
|
|
90
|
-
var _a;
|
|
91
|
-
if (!this.options.watch || !((_a = this.options.watchPaths) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const watchOptions = {
|
|
95
|
-
watch: this.options.watchPaths,
|
|
96
|
-
ignore: this.options.ignore,
|
|
97
|
-
ext: this.options.ext,
|
|
98
|
-
delay: this.options.delay,
|
|
99
|
-
verbose: this.options.verbose && this.options.showInfo
|
|
100
|
-
};
|
|
101
|
-
this.fileWatcher = new watcher_1.FileWatcher(watchOptions);
|
|
102
|
-
this.fileWatcher.on('change', (event) => {
|
|
103
|
-
if (this.options.watch && this.isRunning) {
|
|
104
|
-
this.handleFileChange(event);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
async handleFileChange(event) {
|
|
109
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
110
|
-
if (this.options.showInfo) {
|
|
111
|
-
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
112
|
-
}
|
|
113
|
-
await this.gracefulRestart();
|
|
114
|
-
}
|
|
115
|
-
generateClusterCommand() {
|
|
116
|
-
if (!this.options.cluster) {
|
|
117
|
-
return this.options.command;
|
|
118
|
-
}
|
|
119
|
-
const instances = this.options.clusterInstances || os.cpus().length;
|
|
120
|
-
const baseCommand = this.options.command;
|
|
121
|
-
// For cluster mode, we'll use a simple approach with PM2-like clustering
|
|
122
|
-
// This is a simplified implementation - in real production, you'd use PM2 or similar
|
|
123
|
-
return `${baseCommand} --cluster=${instances}`;
|
|
124
|
-
}
|
|
125
|
-
async startApplication() {
|
|
126
|
-
const command = this.generateClusterCommand();
|
|
127
|
-
// Set environment variables
|
|
128
|
-
const env = {
|
|
129
|
-
...process.env,
|
|
130
|
-
NODE_ENV: this.options.environment,
|
|
131
|
-
NEEX_START_MODE: 'production',
|
|
132
|
-
NEEX_PROCESS_NAME: this.options.processName
|
|
133
|
-
};
|
|
134
|
-
// Create a modified options object for the runner
|
|
135
|
-
const runnerOptions = {
|
|
136
|
-
...this.options,
|
|
137
|
-
env,
|
|
138
|
-
customPrefix: () => this.options.processName,
|
|
139
|
-
// Override some options for production
|
|
140
|
-
stopOnError: false,
|
|
141
|
-
restartOnFailure: true,
|
|
142
|
-
maxRestarts: this.options.maxRestarts,
|
|
143
|
-
restartDelay: this.options.restartDelay,
|
|
144
|
-
keepAlive: true,
|
|
145
|
-
onProcessExit: (code, signal) => {
|
|
146
|
-
if (code === 0) {
|
|
147
|
-
this.isRunning = false;
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// Only restart if it's not a graceful shutdown
|
|
151
|
-
if (signal !== this.options.signal) {
|
|
152
|
-
this.crashCount++;
|
|
153
|
-
if (this.shouldRestart()) {
|
|
154
|
-
this.handleCrash().catch(console.error);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
this.runner = new runner_1.Runner(runnerOptions);
|
|
160
|
-
try {
|
|
161
|
-
const results = await this.runner.run([command]);
|
|
162
|
-
this.isRunning = true;
|
|
163
|
-
return results;
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
this.crashCount++;
|
|
167
|
-
if (this.options.showInfo) {
|
|
168
|
-
logger_1.default.printLine(`Application crashed: ${error.message}`, 'error');
|
|
169
|
-
}
|
|
170
|
-
// Check if we should restart
|
|
171
|
-
if (this.shouldRestart()) {
|
|
172
|
-
await this.handleCrash();
|
|
173
|
-
}
|
|
174
|
-
return [];
|
|
175
|
-
}
|
|
16
|
+
this.process = null;
|
|
17
|
+
this.isStopping = false;
|
|
18
|
+
this.options = options;
|
|
176
19
|
}
|
|
177
|
-
|
|
178
|
-
if (!this.options.maxRestarts) {
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
return this.restartCount < this.options.maxRestarts;
|
|
182
|
-
}
|
|
183
|
-
async handleCrash() {
|
|
184
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
185
|
-
if (this.options.showInfo) {
|
|
186
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Application crashed`)}`, 'error');
|
|
187
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Attempting restart in ${this.options.restartDelay}ms...`)}`, 'info');
|
|
188
|
-
}
|
|
189
|
-
// Wait before restarting
|
|
190
|
-
await new Promise(resolve => setTimeout(resolve, this.options.restartDelay));
|
|
191
|
-
await this.gracefulRestart();
|
|
192
|
-
}
|
|
193
|
-
collectProcessStats() {
|
|
194
|
-
if (!this.options.showInfo) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
const memUsage = process.memoryUsage();
|
|
198
|
-
this.processStats.memoryUsage = Math.round(memUsage.heapUsed / 1024 / 1024);
|
|
199
|
-
this.processStats.uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
200
|
-
// Simple CPU usage approximation
|
|
201
|
-
const cpuUsage = process.cpuUsage();
|
|
202
|
-
this.processStats.cpuUsage = Math.round(((cpuUsage.user + cpuUsage.system) / 1000000) * 100) / 100;
|
|
203
|
-
}
|
|
204
|
-
printStartBanner() {
|
|
20
|
+
async startProcess() {
|
|
205
21
|
var _a, _b;
|
|
206
|
-
if (
|
|
22
|
+
if (this.process) {
|
|
207
23
|
return;
|
|
208
24
|
}
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
console.log(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Crashes: ${this.crashCount}`)}`);
|
|
228
|
-
}
|
|
229
|
-
// Show process stats
|
|
230
|
-
this.collectProcessStats();
|
|
231
|
-
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory: ${this.processStats.memoryUsage}MB`)}`);
|
|
232
|
-
if (this.options.memoryLimit) {
|
|
233
|
-
const memoryPercent = Math.round((this.processStats.memoryUsage / this.options.memoryLimit) * 100);
|
|
234
|
-
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Memory usage: ${memoryPercent}%`)}`);
|
|
235
|
-
}
|
|
236
|
-
console.log('');
|
|
237
|
-
}
|
|
238
|
-
formatUptime(seconds) {
|
|
239
|
-
if (seconds < 60) {
|
|
240
|
-
return `${seconds}s`;
|
|
241
|
-
}
|
|
242
|
-
else if (seconds < 3600) {
|
|
243
|
-
const minutes = Math.floor(seconds / 60);
|
|
244
|
-
const remainingSeconds = seconds % 60;
|
|
245
|
-
return `${minutes}m ${remainingSeconds}s`;
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
const hours = Math.floor(seconds / 3600);
|
|
249
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
250
|
-
return `${hours}h ${minutes}m`;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
monitorResources() {
|
|
254
|
-
if (!this.options.showInfo) {
|
|
255
|
-
return;
|
|
25
|
+
const nodeArgs = this.options.nodeArgs || [];
|
|
26
|
+
const args = [...nodeArgs, this.options.entry];
|
|
27
|
+
if (this.options.verbose) {
|
|
28
|
+
logger_manager_js_1.loggerManager.printLine(`Executing: node ${args.join(' ')}`, 'info');
|
|
29
|
+
}
|
|
30
|
+
this.process = (0, child_process_1.spawn)('node', args, {
|
|
31
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
32
|
+
shell: false,
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
NODE_ENV: 'production',
|
|
36
|
+
FORCE_COLOR: this.options.color ? '1' : '0'
|
|
37
|
+
},
|
|
38
|
+
detached: true
|
|
39
|
+
});
|
|
40
|
+
const appName = this.options.name || path_1.default.basename(this.options.entry);
|
|
41
|
+
if (!this.options.quiet) {
|
|
42
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Starting ${chalk_1.default.cyan(appName)} in production mode...`, 'info');
|
|
256
43
|
}
|
|
257
|
-
|
|
258
|
-
if (!this.
|
|
259
|
-
|
|
260
|
-
return;
|
|
44
|
+
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
45
|
+
if (!this.options.quiet) {
|
|
46
|
+
process.stdout.write(data);
|
|
261
47
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (this.options.
|
|
265
|
-
|
|
266
|
-
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');
|
|
48
|
+
});
|
|
49
|
+
(_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
50
|
+
if (!this.options.quiet) {
|
|
51
|
+
process.stderr.write(data);
|
|
267
52
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
53
|
+
});
|
|
54
|
+
this.process.on('error', (error) => {
|
|
55
|
+
logger_manager_js_1.loggerManager.printLine(`Application error: ${error.message}`, 'error');
|
|
56
|
+
});
|
|
57
|
+
this.process.on('exit', (code) => {
|
|
58
|
+
this.process = null;
|
|
59
|
+
if (!this.isStopping) {
|
|
60
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Application ${appName} exited with code ${code}`, 'error');
|
|
61
|
+
if (this.options.watch) {
|
|
62
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting application...`, 'info');
|
|
63
|
+
this.startProcess();
|
|
64
|
+
}
|
|
272
65
|
}
|
|
273
|
-
}
|
|
66
|
+
});
|
|
274
67
|
}
|
|
275
68
|
async start() {
|
|
276
|
-
this.
|
|
277
|
-
|
|
278
|
-
// Setup file watcher if enabled
|
|
279
|
-
if (this.options.watch) {
|
|
280
|
-
this.setupFileWatcher();
|
|
281
|
-
}
|
|
282
|
-
// Print start banner
|
|
283
|
-
this.printStartBanner();
|
|
284
|
-
// Start file watcher if enabled
|
|
285
|
-
if (this.fileWatcher) {
|
|
286
|
-
await this.fileWatcher.start();
|
|
287
|
-
}
|
|
288
|
-
// Start resource monitoring
|
|
289
|
-
this.monitorResources();
|
|
290
|
-
// Start application
|
|
291
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
292
|
-
if (this.options.showInfo) {
|
|
293
|
-
logger_1.default.printLine(`${prefix} Starting ${this.options.processName}...`, 'info');
|
|
294
|
-
}
|
|
295
|
-
await this.startApplication();
|
|
296
|
-
// Set up graceful shutdown
|
|
297
|
-
this.setupGracefulShutdown();
|
|
298
|
-
if (this.options.showInfo) {
|
|
299
|
-
logger_1.default.printLine(`${prefix} ${this.options.processName} is running in ${this.options.environment} mode`, 'info');
|
|
300
|
-
if (this.options.watch) {
|
|
301
|
-
logger_1.default.printLine(`${prefix} Watching for changes...`, 'info');
|
|
302
|
-
}
|
|
303
|
-
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
async gracefulRestart() {
|
|
307
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
308
|
-
if (!this.isRunning) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
if (!this.shouldRestart()) {
|
|
312
|
-
if (this.options.showInfo) {
|
|
313
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.red(`${figures_1.default.cross} Max restarts reached (${this.options.maxRestarts}). Stopping application.`)}`, 'error');
|
|
314
|
-
}
|
|
315
|
-
await this.stop();
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
if (this.options.showInfo) {
|
|
319
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.yellow(`${figures_1.default.warning} Gracefully restarting ${this.options.processName}...`)}`, 'info');
|
|
320
|
-
}
|
|
321
|
-
this.restartCount++;
|
|
322
|
-
this.lastRestartTime = new Date();
|
|
323
|
-
// Stop current processes gracefully
|
|
324
|
-
if (this.runner) {
|
|
325
|
-
this.runner.cleanup(this.options.signal);
|
|
69
|
+
if (!fs_1.default.existsSync(this.options.entry)) {
|
|
70
|
+
throw new Error(`Entry file not found: ${this.options.entry}`);
|
|
326
71
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
this.printStartBanner();
|
|
331
|
-
// Start application again
|
|
332
|
-
await this.startApplication();
|
|
333
|
-
if (this.options.showInfo) {
|
|
334
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} restarted successfully`)}`, 'info');
|
|
72
|
+
await this.startProcess();
|
|
73
|
+
if (!this.options.quiet) {
|
|
74
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Application is running.`, 'info');
|
|
335
75
|
}
|
|
336
76
|
}
|
|
337
77
|
async stop() {
|
|
338
|
-
|
|
339
|
-
|
|
78
|
+
this.isStopping = true;
|
|
79
|
+
const proc = this.process;
|
|
80
|
+
if (!proc) {
|
|
340
81
|
return;
|
|
341
82
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
// Stop application gracefully
|
|
351
|
-
if (this.runner) {
|
|
352
|
-
this.runner.cleanup(this.options.signal);
|
|
353
|
-
}
|
|
354
|
-
// Calculate final stats
|
|
355
|
-
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
356
|
-
const uptimeStr = this.formatUptime(uptime);
|
|
357
|
-
if (this.options.showInfo) {
|
|
358
|
-
logger_1.default.printLine(`${prefix} ${chalk_1.default.green(`${figures_1.default.tick} ${this.options.processName} stopped successfully`)}`, 'info');
|
|
359
|
-
logger_1.default.printLine(`${prefix} Final stats: ${uptimeStr} uptime, ${this.restartCount} restarts, ${this.crashCount} crashes`, 'info');
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
setupGracefulShutdown() {
|
|
363
|
-
const handleSignal = (signal) => {
|
|
364
|
-
if (this.options.showInfo) {
|
|
365
|
-
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Gracefully shutting down ${this.options.processName}...`)}`);
|
|
366
|
-
}
|
|
367
|
-
this.stop().then(() => {
|
|
368
|
-
process.exit(0);
|
|
83
|
+
this.process = null;
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
const appName = this.options.name || path_1.default.basename(this.options.entry);
|
|
86
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping application ${appName}...`, 'info');
|
|
87
|
+
proc.on('exit', () => {
|
|
88
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Application stopped.`, 'info');
|
|
89
|
+
resolve();
|
|
369
90
|
});
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
91
|
+
proc.on('error', () => {
|
|
92
|
+
// Handle errors during shutdown, e.g., if the process is already gone
|
|
93
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Application stopped.`, 'info');
|
|
94
|
+
resolve();
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
if (proc.pid) {
|
|
98
|
+
const pid = proc.pid;
|
|
99
|
+
// Kill the entire process group
|
|
100
|
+
process.kill(-pid, 'SIGTERM');
|
|
101
|
+
// Set a timeout to force kill if it doesn't terminate gracefully
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
if (!proc.killed) {
|
|
104
|
+
try {
|
|
105
|
+
process.kill(-pid, 'SIGKILL');
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
// Ignore errors if the process is already gone
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, 5000).unref(); // .unref() allows the main process to exit if this is the only thing running
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
// This can happen if the process is already dead
|
|
116
|
+
resolve();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
397
119
|
}
|
|
398
120
|
}
|
|
399
121
|
exports.StartManager = StartManager;
|
package/dist/src/watcher.js
CHANGED
|
@@ -32,17 +32,7 @@ const fs = __importStar(require("fs"));
|
|
|
32
32
|
const path = __importStar(require("path"));
|
|
33
33
|
const events_1 = require("events");
|
|
34
34
|
const chalk_1 = __importDefault(require("chalk"));
|
|
35
|
-
|
|
36
|
-
const logger = {
|
|
37
|
-
printLine: (message, level = 'info') => {
|
|
38
|
-
const prefix = {
|
|
39
|
-
info: chalk_1.default.blue('i'),
|
|
40
|
-
warn: chalk_1.default.yellow('!'),
|
|
41
|
-
error: chalk_1.default.red('x'),
|
|
42
|
-
}[level];
|
|
43
|
-
console.log(`${prefix} ${message}`);
|
|
44
|
-
},
|
|
45
|
-
};
|
|
35
|
+
const logger_process_1 = require("./logger-process");
|
|
46
36
|
class FileWatcher extends events_1.EventEmitter {
|
|
47
37
|
constructor(options) {
|
|
48
38
|
super();
|
|
@@ -131,7 +121,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
131
121
|
try {
|
|
132
122
|
const absolutePath = path.resolve(dirPath);
|
|
133
123
|
if (this.options.verbose) {
|
|
134
|
-
logger.printLine(`Watching directory: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
124
|
+
logger_process_1.logger.printLine(`Watching directory: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
135
125
|
}
|
|
136
126
|
const watcher = fs.watch(absolutePath, { recursive: true }, async (eventType, filename) => {
|
|
137
127
|
if (!filename)
|
|
@@ -149,7 +139,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
149
139
|
}
|
|
150
140
|
catch (error) {
|
|
151
141
|
if (this.options.verbose) {
|
|
152
|
-
logger.printLine(`Failed to watch directory ${dirPath}: ${error.message}`, 'warn');
|
|
142
|
+
logger_process_1.logger.printLine(`Failed to watch directory ${dirPath}: ${error.message}`, 'warn');
|
|
153
143
|
}
|
|
154
144
|
}
|
|
155
145
|
}
|
|
@@ -163,7 +153,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
163
153
|
return;
|
|
164
154
|
}
|
|
165
155
|
if (this.options.verbose) {
|
|
166
|
-
logger.printLine(`Watching file: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
156
|
+
logger_process_1.logger.printLine(`Watching file: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
167
157
|
}
|
|
168
158
|
const watcher = fs.watch(absolutePath, (eventType) => {
|
|
169
159
|
this.handleFileChange(absolutePath, eventType);
|
|
@@ -173,13 +163,13 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
173
163
|
}
|
|
174
164
|
catch (error) {
|
|
175
165
|
if (this.options.verbose) {
|
|
176
|
-
logger.printLine(`Failed to watch file ${filePath}: ${error.message}`, 'warn');
|
|
166
|
+
logger_process_1.logger.printLine(`Failed to watch file ${filePath}: ${error.message}`, 'warn');
|
|
177
167
|
}
|
|
178
168
|
}
|
|
179
169
|
}
|
|
180
170
|
handleFileChange(filePath, eventType) {
|
|
181
171
|
if (this.options.verbose) {
|
|
182
|
-
logger.printLine(`File ${eventType}: ${chalk_1.default.yellow(path.relative(process.cwd(), filePath))}`, 'info');
|
|
172
|
+
logger_process_1.logger.printLine(`File ${eventType}: ${chalk_1.default.yellow(path.relative(process.cwd(), filePath))}`, 'info');
|
|
183
173
|
}
|
|
184
174
|
// Debounce file changes
|
|
185
175
|
if (this.debounceTimer) {
|
|
@@ -198,7 +188,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
198
188
|
return;
|
|
199
189
|
}
|
|
200
190
|
this.isWatching = true;
|
|
201
|
-
logger.printLine('Starting file watcher...', 'info');
|
|
191
|
+
logger_process_1.logger.printLine('Starting file watcher...', 'info');
|
|
202
192
|
for (const watchPath of this.options.watch) {
|
|
203
193
|
const absolutePath = path.resolve(watchPath);
|
|
204
194
|
try {
|
|
@@ -211,20 +201,20 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
211
201
|
}
|
|
212
202
|
}
|
|
213
203
|
catch (error) {
|
|
214
|
-
logger.printLine(`Cannot watch ${watchPath}: ${error.message}`, 'warn');
|
|
204
|
+
logger_process_1.logger.printLine(`Cannot watch ${watchPath}: ${error.message}`, 'warn');
|
|
215
205
|
}
|
|
216
206
|
}
|
|
217
207
|
const watchedCount = this.watchers.length;
|
|
218
|
-
logger.printLine(`File watcher started. Monitoring ${chalk_1.default.green(watchedCount)} locations`, 'info');
|
|
208
|
+
logger_process_1.logger.printLine(`File watcher started. Monitoring ${chalk_1.default.green(watchedCount)} locations`, 'info');
|
|
219
209
|
if (this.options.ext && this.options.ext.length > 0) {
|
|
220
|
-
logger.printLine(`Watching extensions: ${chalk_1.default.cyan(this.options.ext.join(', '))}`, 'info');
|
|
210
|
+
logger_process_1.logger.printLine(`Watching extensions: ${chalk_1.default.cyan(this.options.ext.join(', '))}`, 'info');
|
|
221
211
|
}
|
|
222
212
|
}
|
|
223
213
|
stop() {
|
|
224
214
|
if (!this.isWatching) {
|
|
225
215
|
return;
|
|
226
216
|
}
|
|
227
|
-
logger.printLine('Stopping file watcher...', 'info');
|
|
217
|
+
logger_process_1.logger.printLine('Stopping file watcher...', 'info');
|
|
228
218
|
this.watchers.forEach(watcher => {
|
|
229
219
|
try {
|
|
230
220
|
watcher.close();
|
|
@@ -240,7 +230,7 @@ class FileWatcher extends events_1.EventEmitter {
|
|
|
240
230
|
clearTimeout(this.debounceTimer);
|
|
241
231
|
this.debounceTimer = null;
|
|
242
232
|
}
|
|
243
|
-
logger.printLine('File watcher stopped', 'info');
|
|
233
|
+
logger_process_1.logger.printLine('File watcher stopped', 'info');
|
|
244
234
|
}
|
|
245
235
|
isActive() {
|
|
246
236
|
return this.isWatching;
|