neex 0.6.47 → 0.6.51

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.
@@ -6,55 +6,239 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.addStartCommands = void 0;
7
7
  const start_manager_js_1 = require("../start-manager.js");
8
8
  const logger_manager_js_1 = require("../logger-manager.js");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const figures_1 = __importDefault(require("figures"));
9
11
  const path_1 = __importDefault(require("path"));
10
12
  const fs_1 = __importDefault(require("fs"));
11
13
  function addStartCommands(program) {
12
- let manager = null;
13
- const startCommand = program
14
- .command('start [entry]')
15
- .description('Start a production-ready application')
16
- .option('-n, --name <name>', 'Application name')
17
- .option('-w, --watch', 'Watch for file changes and restart the application', false)
18
- .option('--quiet', 'Suppress all output', false)
19
- .option('--color', 'Force color output', true)
20
- .option('--verbose', 'Enable verbose logging', false)
21
- .option('--node-args <args>', 'Arguments to pass to the node process', (value) => value.split(' '), [])
22
- .action(async (entry, options) => {
23
- let entryPoint = entry;
24
- if (!entryPoint) {
25
- const defaultPath = path_1.default.join(process.cwd(), 'dist', 'index.js');
26
- if (fs_1.default.existsSync(defaultPath)) {
27
- entryPoint = defaultPath;
14
+ let startManager = null;
15
+ // Start command for production execution
16
+ program
17
+ .command('start [file]')
18
+ .description('Start production application (default: dist/index.js)')
19
+ .option('-d, --dir <directory>', 'Working directory', process.cwd())
20
+ .option('-e, --env <file>', 'Environment file to load', '.env')
21
+ .option('-p, --port <port>', 'Port number (if applicable)', parseInt)
22
+ .option('-w, --workers <count>', 'Number of worker processes', parseInt, 1)
23
+ .option('-c, --cluster', 'Enable cluster mode')
24
+ .option('-m, --memory <limit>', 'Memory limit (e.g., 512M, 1G)')
25
+ .option('-l, --log-level <level>', 'Log level (error, warn, info, debug)', 'info')
26
+ .option('-f, --log-file <file>', 'Log file path')
27
+ .option('--no-color', 'Disable colored output')
28
+ .option('-q, --quiet', 'Quiet mode')
29
+ .option('-v, --verbose', 'Verbose output')
30
+ .option('--watch', 'Watch for changes and restart')
31
+ .option('--max-memory <limit>', 'Maximum memory before restart (e.g., 1G)')
32
+ .option('--max-crashes <count>', 'Maximum crashes before giving up', parseInt, 5)
33
+ .option('--restart-delay <ms>', 'Delay between restarts (ms)', parseInt, 1000)
34
+ .option('--health-check', 'Enable health check monitoring')
35
+ .option('--health-port <port>', 'Health check port', parseInt, 3001)
36
+ .option('--graceful-timeout <ms>', 'Graceful shutdown timeout (ms)', parseInt, 30000)
37
+ .option('--inspect', 'Enable Node.js inspector')
38
+ .option('--inspect-brk', 'Enable Node.js inspector with break')
39
+ .option('--node-args <args>', 'Additional Node.js arguments')
40
+ .action(async (file, options) => {
41
+ try {
42
+ const targetFile = file || 'dist/index.js';
43
+ const resolvedFile = path_1.default.resolve(options.dir, targetFile);
44
+ // Check if file exists
45
+ if (!fs_1.default.existsSync(resolvedFile)) {
46
+ // Try to find main file from package.json
47
+ const packageJsonPath = path_1.default.join(options.dir, 'package.json');
48
+ if (fs_1.default.existsSync(packageJsonPath)) {
49
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
50
+ const mainFile = packageJson.main || 'index.js';
51
+ const alternativeFile = path_1.default.resolve(options.dir, mainFile);
52
+ if (fs_1.default.existsSync(alternativeFile)) {
53
+ if (options.verbose) {
54
+ logger_manager_js_1.loggerManager.printLine(`Using main file from package.json: ${mainFile}`, 'info');
55
+ }
56
+ }
57
+ else {
58
+ throw new Error(`Neither ${targetFile} nor ${mainFile} found. Please build your project first.`);
59
+ }
60
+ }
61
+ else {
62
+ throw new Error(`File not found: ${resolvedFile}. Please build your project first.`);
63
+ }
64
+ }
65
+ if (!options.quiet) {
66
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting production server: ${chalk_1.default.cyan(targetFile)}`, 'info');
67
+ }
68
+ startManager = new start_manager_js_1.StartManager({
69
+ file: resolvedFile,
70
+ workingDir: options.dir,
71
+ envFile: options.env,
72
+ port: options.port,
73
+ workers: options.workers,
74
+ cluster: options.cluster,
75
+ memoryLimit: options.memory,
76
+ logLevel: options.logLevel,
77
+ logFile: options.logFile,
78
+ color: options.color,
79
+ quiet: options.quiet,
80
+ verbose: options.verbose,
81
+ watch: options.watch,
82
+ maxMemory: options.maxMemory,
83
+ maxCrashes: options.maxCrashes,
84
+ restartDelay: options.restartDelay,
85
+ healthCheck: options.healthCheck,
86
+ healthPort: options.healthPort,
87
+ gracefulTimeout: options.gracefulTimeout,
88
+ inspect: options.inspect,
89
+ inspectBrk: options.inspectBrk,
90
+ nodeArgs: options.nodeArgs
91
+ });
92
+ await startManager.start();
93
+ }
94
+ catch (error) {
95
+ if (error instanceof Error) {
96
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Start failed: ${error.message}`, 'error');
28
97
  }
29
98
  else {
30
- logger_manager_js_1.loggerManager.printLine('Entry file not found. Please specify an entry file or build the project first.', 'error');
31
- process.exit(1);
99
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown start error occurred`, 'error');
32
100
  }
101
+ process.exit(1);
33
102
  }
34
- const startOptions = {
35
- entry: entryPoint,
36
- name: options.name,
37
- watch: options.watch,
38
- quiet: options.quiet,
39
- color: options.color,
40
- verbose: options.verbose,
41
- nodeArgs: options.nodeArgs,
42
- };
43
- manager = new start_manager_js_1.StartManager(startOptions);
103
+ });
104
+ // Quick start command
105
+ program
106
+ .command('run [file]')
107
+ .description('Quick start without options (alias for start)')
108
+ .action(async (file) => {
44
109
  try {
45
- await manager.start();
110
+ const targetFile = file || 'dist/index.js';
111
+ if (!fs_1.default.existsSync(targetFile)) {
112
+ throw new Error(`File not found: ${targetFile}. Please build your project first.`);
113
+ }
114
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Running: ${chalk_1.default.cyan(targetFile)}`, 'info');
115
+ startManager = new start_manager_js_1.StartManager({
116
+ file: path_1.default.resolve(targetFile),
117
+ workingDir: process.cwd(),
118
+ envFile: '.env',
119
+ port: undefined,
120
+ workers: 1,
121
+ cluster: false,
122
+ memoryLimit: undefined,
123
+ logLevel: 'info',
124
+ logFile: undefined,
125
+ color: true,
126
+ quiet: false,
127
+ verbose: false,
128
+ watch: false,
129
+ maxMemory: undefined,
130
+ maxCrashes: 5,
131
+ restartDelay: 1000,
132
+ healthCheck: false,
133
+ healthPort: 3001,
134
+ gracefulTimeout: 30000,
135
+ inspect: false,
136
+ inspectBrk: false,
137
+ nodeArgs: undefined
138
+ });
139
+ await startManager.start();
46
140
  }
47
141
  catch (error) {
48
- logger_manager_js_1.loggerManager.printLine(error.message, 'error');
142
+ if (error instanceof Error) {
143
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Run failed: ${error.message}`, 'error');
144
+ }
145
+ else {
146
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown run error occurred`, 'error');
147
+ }
49
148
  process.exit(1);
50
149
  }
51
150
  });
52
- return {
53
- cleanupStart: async () => {
54
- if (manager) {
55
- await manager.stop();
151
+ // Production command with clustering
152
+ program
153
+ .command('prod [file]')
154
+ .description('Start in production mode with clustering')
155
+ .option('-w, --workers <count>', 'Number of workers (default: CPU cores)', parseInt)
156
+ .option('-p, --port <port>', 'Port number', parseInt)
157
+ .option('-e, --env <file>', 'Environment file', '.env.production')
158
+ .option('-l, --log-file <file>', 'Log file path')
159
+ .option('-q, --quiet', 'Quiet mode')
160
+ .action(async (file, options) => {
161
+ try {
162
+ const targetFile = file || 'dist/index.js';
163
+ const resolvedFile = path_1.default.resolve(targetFile);
164
+ if (!fs_1.default.existsSync(resolvedFile)) {
165
+ throw new Error(`File not found: ${resolvedFile}. Please build your project first.`);
166
+ }
167
+ const workers = options.workers || require('os').cpus().length;
168
+ if (!options.quiet) {
169
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting production server with ${workers} workers`, 'info');
56
170
  }
57
- },
171
+ startManager = new start_manager_js_1.StartManager({
172
+ file: resolvedFile,
173
+ workingDir: process.cwd(),
174
+ envFile: options.env,
175
+ port: options.port,
176
+ workers,
177
+ cluster: true,
178
+ memoryLimit: undefined,
179
+ logLevel: 'info',
180
+ logFile: options.logFile,
181
+ color: false,
182
+ quiet: options.quiet,
183
+ verbose: false,
184
+ watch: false,
185
+ maxMemory: '1G',
186
+ maxCrashes: 3,
187
+ restartDelay: 2000,
188
+ healthCheck: true,
189
+ healthPort: 3001,
190
+ gracefulTimeout: 30000,
191
+ inspect: false,
192
+ inspectBrk: false,
193
+ nodeArgs: undefined
194
+ });
195
+ await startManager.start();
196
+ }
197
+ catch (error) {
198
+ if (error instanceof Error) {
199
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Production start failed: ${error.message}`, 'error');
200
+ }
201
+ else {
202
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown production start error occurred`, 'error');
203
+ }
204
+ process.exit(1);
205
+ }
206
+ });
207
+ // Cleanup function
208
+ const cleanupStart = async () => {
209
+ if (startManager) {
210
+ try {
211
+ await startManager.stop();
212
+ startManager = null;
213
+ }
214
+ catch (error) {
215
+ // Ignore cleanup errors
216
+ }
217
+ }
58
218
  };
219
+ // Handle process termination
220
+ const handleExit = (signal) => {
221
+ if (startManager) {
222
+ logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received ${signal}, stopping server...`, 'info');
223
+ cleanupStart().then(() => {
224
+ process.exit(0);
225
+ }).catch(() => {
226
+ process.exit(1);
227
+ });
228
+ }
229
+ else {
230
+ process.exit(0);
231
+ }
232
+ };
233
+ // Register signal handlers
234
+ process.on('SIGINT', () => handleExit('SIGINT'));
235
+ process.on('SIGTERM', () => handleExit('SIGTERM'));
236
+ process.on('SIGUSR2', () => handleExit('SIGUSR2')); // PM2 restart
237
+ process.on('exit', () => {
238
+ if (startManager) {
239
+ cleanupStart();
240
+ }
241
+ });
242
+ return { cleanupStart };
59
243
  }
60
244
  exports.addStartCommands = addStartCommands;
@@ -46,97 +46,20 @@ class DevManager {
46
46
  }
47
47
  }
48
48
  }
49
- detectRuntime() {
50
- // Check if we're running in Bun
51
- if (typeof globalThis.Bun !== 'undefined' || process.versions.bun) {
52
- return 'bun';
53
- }
54
- // Check if we're running in Deno
55
- if (typeof globalThis.Deno !== 'undefined') {
56
- return 'deno';
57
- }
58
- return 'node';
59
- }
60
49
  getExecuteCommand() {
61
50
  if (this.options.execCommand) {
62
51
  const parts = this.options.execCommand.split(' ');
63
52
  return { command: parts[0], args: [...parts.slice(1), this.options.file] };
64
53
  }
65
- const runtime = this.detectRuntime();
66
- const isTypeScript = this.options.file.endsWith('.ts') || this.options.useTypeScript;
67
- let command;
68
- let args = [];
69
- switch (runtime) {
70
- case 'bun':
71
- command = 'bun';
72
- args = ['run', this.options.file];
73
- break;
74
- case 'deno':
75
- command = 'deno';
76
- args = ['run', '--allow-all', this.options.file];
77
- break;
78
- case 'node':
79
- default:
80
- command = 'node';
81
- if (isTypeScript) {
82
- // Try different TypeScript execution methods
83
- if (this.commandExists('tsx')) {
84
- command = 'tsx';
85
- args = [this.options.file];
86
- }
87
- else if (this.commandExists('ts-node')) {
88
- command = 'ts-node';
89
- args = [this.options.file];
90
- }
91
- else {
92
- // Fallback: try to use node with --loader
93
- const tsNodePath = this.findTsNodePath();
94
- if (tsNodePath) {
95
- args = ['--loader', tsNodePath, this.options.file];
96
- }
97
- else {
98
- throw new Error('TypeScript execution not available. Please install tsx or ts-node');
99
- }
100
- }
101
- }
102
- else {
103
- // Regular JavaScript file
104
- args = [this.options.file];
105
- }
106
- break;
107
- }
108
- // Add inspect flags for Node.js
109
- if (runtime === 'node' && command === 'node') {
110
- if (this.options.inspect) {
111
- args.unshift('--inspect');
112
- }
113
- if (this.options.inspectBrk) {
114
- args.unshift('--inspect-brk');
115
- }
116
- }
117
- return { command, args };
118
- }
119
- commandExists(command) {
120
- try {
121
- const { execSync } = require('child_process');
122
- execSync(`which ${command}`, { stdio: 'ignore' });
123
- return true;
124
- }
125
- catch (_a) {
126
- return false;
54
+ // Default to tsx for TypeScript files
55
+ const args = [this.options.file];
56
+ if (this.options.inspect) {
57
+ args.unshift('--inspect');
127
58
  }
128
- }
129
- findTsNodePath() {
130
- const paths = [
131
- path_1.default.join(process.cwd(), 'node_modules', 'ts-node', 'esm.mjs'),
132
- path_1.default.join(process.cwd(), 'node_modules', 'ts-node', 'register.js'),
133
- ];
134
- for (const tsPath of paths) {
135
- if (fs_1.default.existsSync(tsPath)) {
136
- return tsPath;
137
- }
59
+ if (this.options.inspectBrk) {
60
+ args.unshift('--inspect-brk');
138
61
  }
139
- return null;
62
+ return { command: 'tsx', args };
140
63
  }
141
64
  clearConsole() {
142
65
  if (this.options.clearConsole && process.stdout.isTTY) {
@@ -149,66 +72,50 @@ class DevManager {
149
72
  return;
150
73
  }
151
74
  this.loadEnvFile();
152
- try {
153
- const { command, args } = this.getExecuteCommand();
154
- if (this.options.verbose) {
155
- logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
75
+ const { command, args } = this.getExecuteCommand();
76
+ if (this.options.verbose) {
77
+ logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
78
+ }
79
+ this.process = (0, child_process_1.spawn)(command, args, {
80
+ stdio: ['ignore', 'pipe', 'pipe'],
81
+ shell: false,
82
+ env: {
83
+ ...process.env,
84
+ NODE_ENV: process.env.NODE_ENV || 'development',
85
+ FORCE_COLOR: this.options.color ? '1' : '0'
86
+ },
87
+ detached: true
88
+ });
89
+ this.startTime = new Date();
90
+ this.restartCount++;
91
+ if (!this.options.quiet) {
92
+ const timestamp = new Date().toLocaleTimeString();
93
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(this.options.file)} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
94
+ }
95
+ (_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
96
+ if (!this.options.quiet) {
97
+ process.stdout.write(data);
156
98
  }
157
- this.process = (0, child_process_1.spawn)(command, args, {
158
- stdio: ['ignore', 'pipe', 'pipe'],
159
- shell: false,
160
- env: {
161
- ...process.env,
162
- NODE_ENV: process.env.NODE_ENV || 'development',
163
- FORCE_COLOR: this.options.color ? '1' : '0',
164
- // Add common TypeScript environment variables
165
- TS_NODE_COMPILER_OPTIONS: '{"module":"commonjs","target":"es2020"}',
166
- TS_NODE_TRANSPILE_ONLY: 'true'
167
- },
168
- detached: true
169
- });
170
- this.startTime = new Date();
171
- this.restartCount++;
99
+ });
100
+ (_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
172
101
  if (!this.options.quiet) {
173
- const timestamp = new Date().toLocaleTimeString();
174
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(this.options.file)} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
102
+ process.stderr.write(data);
175
103
  }
176
- (_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
177
- if (!this.options.quiet) {
178
- process.stdout.write(data);
179
- }
180
- });
181
- (_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
182
- if (!this.options.quiet) {
183
- process.stderr.write(data);
184
- }
185
- });
186
- this.process.on('error', (error) => {
187
- logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
188
- // Provide helpful error messages
189
- if (error.message.includes('ENOENT')) {
190
- logger_manager_js_1.loggerManager.printLine(`Command not found. Make sure the required runtime is installed.`, 'error');
191
- }
192
- else if (error.message.includes('EACCES')) {
193
- logger_manager_js_1.loggerManager.printLine(`Permission denied. The command might not be executable.`, 'error');
194
- }
195
- });
196
- this.process.on('exit', (code, signal) => {
197
- if (this.process) {
198
- this.process = null;
199
- if (!this.isRestarting) {
200
- if (code !== 0) {
201
- const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
202
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
203
- }
104
+ });
105
+ this.process.on('error', (error) => {
106
+ logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
107
+ });
108
+ this.process.on('exit', (code, signal) => {
109
+ if (this.process) {
110
+ this.process = null;
111
+ if (!this.isRestarting) {
112
+ if (code !== 0) {
113
+ const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
114
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
204
115
  }
205
116
  }
206
- });
207
- }
208
- catch (error) {
209
- logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
210
- throw error;
211
- }
117
+ }
118
+ });
212
119
  }
213
120
  async stopProcess() {
214
121
  if (!this.process) {
@@ -275,12 +182,6 @@ class DevManager {
275
182
  '**/dist/**',
276
183
  '**/build/**',
277
184
  '**/*.log',
278
- '**/.next/**',
279
- '**/.nuxt/**',
280
- '**/.vscode/**',
281
- '**/.idea/**',
282
- '**/coverage/**',
283
- '**/*.map',
284
185
  ...this.options.ignore.map(pattern => `**/${pattern}/**`)
285
186
  ];
286
187
  this.watcher = (0, chokidar_1.watch)(watchPatterns, {
@@ -288,11 +189,7 @@ class DevManager {
288
189
  ignoreInitial: true,
289
190
  followSymlinks: false,
290
191
  usePolling: false,
291
- atomic: 300,
292
- awaitWriteFinish: {
293
- stabilityThreshold: 100,
294
- pollInterval: 50
295
- }
192
+ atomic: 300
296
193
  });
297
194
  this.watcher.on('change', (filePath) => {
298
195
  if (this.options.verbose) {
@@ -331,7 +228,6 @@ class DevManager {
331
228
  logger_manager_js_1.loggerManager.printLine(`Target file: ${this.options.file}`, 'info');
332
229
  logger_manager_js_1.loggerManager.printLine(`Watch patterns: ${this.options.watch.join(', ')}`, 'info');
333
230
  logger_manager_js_1.loggerManager.printLine(`Restart delay: ${this.options.delay}ms`, 'info');
334
- logger_manager_js_1.loggerManager.printLine(`Runtime: ${this.detectRuntime()}`, 'info');
335
231
  }
336
232
  this.setupWatcher();
337
233
  await this.startProcess();