@fecommunity/reactpress-server 1.0.0-beta.4 → 1.0.0-beta.41

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.
@@ -1,246 +1,203 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { program } = require('commander');
4
- const { execSync } = require('child_process');
3
+ /**
4
+ * ReactPress Server CLI Entry Point
5
+ * This script allows starting the ReactPress server via npx
6
+ * Supports both regular and PM2 startup modes
7
+ */
8
+
5
9
  const path = require('path');
6
10
  const fs = require('fs');
7
- const chalk = require('chalk');
8
- const inquirer = require('inquirer');
9
-
10
- program
11
- .name('@fecommunity/reactpress-server')
12
- .description('ReactPress Server CLI')
13
- .version('1.0.0');
14
-
15
- // Init command - 初始化服务器配置
16
- program
17
- .command('init')
18
- .description('Initialize ReactPress server configuration')
19
- .option('-d, --database <type>', 'Database type (mysql|postgres)', 'mysql')
20
- .option('-p, --port <port>', 'Server port', '3002')
21
- .option('--skip-db-setup', 'Skip database setup')
22
- .action(async (options) => {
23
- console.log(chalk.blue('🚀 Initializing ReactPress Server...\n'));
24
-
25
- const cwd = process.cwd();
26
- const envPath = path.join(cwd, '.env');
27
-
28
- // 检查.env文件是否已存在
29
- if (fs.existsSync(envPath)) {
30
- const { overwrite } = await inquirer.prompt([
31
- {
32
- type: 'confirm',
33
- name: 'overwrite',
34
- message: 'Configuration file (.env) already exists. Overwrite?',
35
- default: false
36
- }
37
- ]);
38
-
39
- if (!overwrite) {
40
- console.log(chalk.yellow('⚠️ Initialization cancelled.'));
41
- process.exit(0);
42
- }
43
- }
44
-
45
- // 使用基础配置模板,基于根目录的.env文件
46
- console.log(chalk.cyan('📋 Creating configuration file based on default template...\n'));
47
-
48
- // 生成JWT密钥
49
- const jwtSecret = require('crypto').randomBytes(32).toString('hex');
50
- console.log(chalk.green('🔐 Generated JWT secret'));
51
-
52
- // 创建.env文件 - 基于根目录模板
53
- const envContent = `# Database Config
54
- DB_HOST=127.0.0.1
55
- DB_PORT=3306
56
- DB_USER=reactpress
57
- DB_PASSWD=reactpress
58
- DB_DATABASE=reactpress
59
-
60
- # JWT Secret
61
- JWT_SECRET=${jwtSecret}
62
-
63
- # Client Config
64
- CLIENT_SITE_URL=http://localhost:3001
65
-
66
- # Server Config
67
- SERVER_SITE_URL=http://localhost:${options.port}
68
- SERVER_PORT=${options.port}
69
- SERVER_API_PREFIX=/api
70
-
71
- # Admin Config
72
- ADMIN_USER=admin
73
- ADMIN_PASSWD=admin
74
-
75
- # Environment
76
- NODE_ENV=development
77
- `;
78
-
79
- fs.writeFileSync(envPath, envContent);
80
- console.log(chalk.green('✅ Configuration saved to .env file'));
81
-
82
- if (!options.skipDbSetup) {
83
- console.log(chalk.yellow('\n🗄️ Database setup:'));
84
- console.log(chalk.gray(`Please ensure your ${options.database} server is running and create the database:`));
85
- console.log(chalk.cyan(`CREATE DATABASE reactpress;`));
86
- console.log(chalk.gray(`CREATE USER 'reactpress'@'localhost' IDENTIFIED BY 'reactpress';`));
87
- console.log(chalk.gray(`GRANT ALL PRIVILEGES ON reactpress.* TO 'reactpress'@'localhost';`));
88
- console.log(chalk.gray(`FLUSH PRIVILEGES;`));
89
- }
90
-
91
- console.log(chalk.green('\n🎉 ReactPress Server initialized successfully!'));
92
- console.log(chalk.cyan('\nNext steps:'));
93
- console.log(chalk.gray('1. Start the server: npx @fecommunity/reactpress-server start'));
94
- console.log(chalk.gray('2. Visit API: http://localhost:' + options.port + '/api'));
95
- console.log(chalk.gray('3. API docs: http://localhost:' + options.port + '/api (Swagger UI)'));
96
- });
11
+ const { spawn, spawnSync } = require('child_process');
97
12
 
98
- // Start command - 启动服务器
99
- program
100
- .command('start')
101
- .description('Start ReactPress server')
102
- .option('-p, --port <port>', 'Server port')
103
- .option('-d, --dev', 'Start in development mode')
104
- .option('--watch', 'Watch for file changes (dev mode)')
105
- .action(async (options) => {
106
- console.log(chalk.blue('🚀 Starting ReactPress Server...\n'));
107
-
108
- const cwd = process.cwd();
109
- const envPath = path.join(cwd, '.env');
110
-
111
- // 检查.env文件是否存在
112
- if (!fs.existsSync(envPath)) {
113
- console.log(chalk.red('❌ Configuration file (.env) not found!'));
114
- console.log(chalk.yellow('Please run: npx @fecommunity/reactpress-server init'));
115
- process.exit(1);
116
- }
117
-
118
- // 检查是否在项目根目录(有server目录)
119
- const serverPath = path.join(cwd, 'server');
120
- const hasServerDir = fs.existsSync(serverPath);
121
-
122
- let serverMainPath;
123
- if (hasServerDir) {
124
- // 在项目根目录,使用相对路径
125
- serverMainPath = path.join(serverPath, 'dist', 'main.js');
126
- const packageDir = serverPath;
127
-
128
- // 检查构建文件是否存在
129
- if (!fs.existsSync(serverMainPath)) {
130
- console.log(chalk.yellow('⚠️ Built server not found, building...'));
131
- try {
132
- execSync('pnpm run build:server', { cwd: cwd, stdio: 'inherit' });
133
- } catch (error) {
134
- console.log(chalk.red('❌ Build failed'));
135
- process.exit(1);
136
- }
137
- }
138
- } else {
139
- // 可能在独立安装的@reactpress/server包中
140
- try {
141
- const serverPackagePath = require.resolve('@fecommunity/reactpress-server/package.json');
142
- const serverPackageDir = path.dirname(serverPackagePath);
143
- serverMainPath = path.join(serverPackageDir, 'dist', 'main.js');
144
- } catch (error) {
145
- console.log(chalk.red('❌ ReactPress server package not found!'));
146
- console.log(chalk.yellow('Please install: npm install @fecommunity/reactpress-server'));
147
- process.exit(1);
148
- }
149
- }
150
-
151
- // 设置环境变量
152
- const env = {
153
- ...process.env,
154
- NODE_ENV: options.dev ? 'development' : 'production'
155
- };
156
-
157
- if (options.port) {
158
- env.SERVER_PORT = options.port;
159
- }
160
-
13
+ // Capture the original working directory where npx was executed
14
+ // BUT prioritize the REACTPRESS_ORIGINAL_CWD environment variable if it exists
15
+ // This ensures consistency when running via pnpm dev from root directory
16
+ const originalCwd = process.env.REACTPRESS_ORIGINAL_CWD || process.cwd();
17
+
18
+ // Get command line arguments
19
+ const args = process.argv.slice(2);
20
+ const usePM2 = args.includes('--pm2');
21
+ const showHelp = args.includes('--help') || args.includes('-h');
22
+
23
+ // Show help if requested
24
+ if (showHelp) {
25
+ console.log(`
26
+ ReactPress Server - NestJS-based backend API for ReactPress CMS
27
+
28
+ Usage:
29
+ npx @fecommunity/reactpress-server [options]
30
+
31
+ Options:
32
+ --pm2 Start server with PM2 process manager
33
+ --help, -h Show this help message
34
+
35
+ Examples:
36
+ npx @fecommunity/reactpress-server # Start server normally
37
+ npx @fecommunity/reactpress-server --pm2 # Start server with PM2
38
+ npx @fecommunity/reactpress-server --help # Show this help message
39
+ `);
40
+ process.exit(0);
41
+ }
42
+
43
+ // Get the directory where this script is located
44
+ const binDir = __dirname;
45
+ const serverDir = path.join(binDir, '..');
46
+ const distPath = path.join(serverDir, 'dist', 'main.js');
47
+ const ecosystemPath = path.join(serverDir, 'ecosystem.config.js');
48
+
49
+ // Function to check if PM2 is installed
50
+ function isPM2Installed() {
51
+ try {
52
+ require.resolve('pm2');
53
+ return true;
54
+ } catch (e) {
55
+ // Check if PM2 is installed globally
161
56
  try {
162
- if (options.dev || options.watch) {
163
- console.log(chalk.yellow('🔄 Starting in development mode...'));
164
- if (hasServerDir) {
165
- execSync('pnpm run dev:server', {
166
- cwd: cwd,
167
- stdio: 'inherit',
168
- env
169
- });
170
- } else {
171
- console.log(chalk.yellow('⚠️ Development mode using built server (source code not available)'));
172
- console.log(chalk.cyan('Starting server with NODE_ENV=development...'));
173
- execSync(`node ${serverMainPath}`, {
174
- cwd: process.cwd(),
175
- stdio: 'inherit',
176
- env
177
- });
178
- }
179
- } else {
180
- console.log(chalk.green('🌟 Starting in production mode...'));
181
- execSync(`node ${serverMainPath}`, {
182
- cwd: process.cwd(),
183
- stdio: 'inherit',
184
- env
185
- });
186
- }
187
- } catch (error) {
188
- console.log(chalk.red('❌ Failed to start server'));
189
- process.exit(1);
57
+ spawnSync('pm2', ['--version'], { stdio: 'ignore' });
58
+ return true;
59
+ } catch (e) {
60
+ return false;
190
61
  }
62
+ }
63
+ }
64
+
65
+ // Function to install PM2
66
+ function installPM2() {
67
+ console.log('[ReactPress Server] Installing PM2...');
68
+ const installResult = spawnSync('npm', ['install', 'pm2', '--no-save'], {
69
+ stdio: 'inherit',
70
+ cwd: serverDir
191
71
  });
72
+
73
+ if (installResult.status !== 0) {
74
+ console.error('[ReactPress Server] Failed to install PM2');
75
+ return false;
76
+ }
77
+
78
+ return true;
79
+ }
192
80
 
193
- // Build command - 构建服务器
194
- program
195
- .command('build')
196
- .description('Build ReactPress server')
197
- .action(() => {
198
- console.log(chalk.blue('🔨 Building ReactPress Server...\n'));
199
-
200
- const cwd = process.cwd();
201
- const serverPath = path.join(cwd, 'server');
202
-
203
- if (!fs.existsSync(serverPath)) {
204
- console.log(chalk.red('❌ Server directory not found!'));
205
- console.log(chalk.yellow('This command should be run from the project root directory.'));
81
+ // Function to start with PM2
82
+ function startWithPM2() {
83
+ // Check if PM2 is installed
84
+ if (!isPM2Installed()) {
85
+ // Try to install PM2
86
+ if (!installPM2()) {
87
+ console.error('[ReactPress Server] Cannot start with PM2');
206
88
  process.exit(1);
207
89
  }
90
+ }
91
+
92
+ // Check if the server is built
93
+ if (!fs.existsSync(distPath)) {
94
+ console.log('[ReactPress Server] Server not built yet. Building...');
95
+
96
+ // Try to build the server
97
+ const buildResult = spawnSync('npm', ['run', 'build'], {
98
+ stdio: 'inherit',
99
+ cwd: serverDir
100
+ });
208
101
 
209
- try {
210
- execSync('pnpm run build:server', {
211
- cwd: cwd,
212
- stdio: 'inherit'
213
- });
214
- console.log(chalk.green('✅ Build completed successfully!'));
215
- } catch (error) {
216
- console.log(chalk.red('❌ Build failed'));
102
+ if (buildResult.status !== 0) {
103
+ console.error('[ReactPress Server] Failed to build server');
217
104
  process.exit(1);
218
105
  }
219
- });
220
-
221
- // Dev command - 开发模式启动
222
- program
223
- .command('dev')
224
- .description('Start server in development mode')
225
- .option('-p, --port <port>', 'Server port')
226
- .action((options) => {
227
- console.log(chalk.blue('🔄 Starting ReactPress Server in development mode...\n'));
228
-
229
- // 调用start命令的dev模式
230
- const args = ['start', '--dev'];
231
- if (options.port) {
232
- args.push('--port', options.port);
106
+ }
107
+
108
+ console.log('[ReactPress Server] Starting with PM2...');
109
+
110
+ // Use ecosystem.config.js if it exists, otherwise use direct command
111
+ let pm2Command = 'pm2';
112
+ try {
113
+ // Try to resolve PM2 path
114
+ pm2Command = path.join(serverDir, 'node_modules', '.bin', 'pm2');
115
+ if (!fs.existsSync(pm2Command)) {
116
+ pm2Command = 'pm2';
233
117
  }
118
+ } catch (e) {
119
+ pm2Command = 'pm2';
120
+ }
121
+
122
+ // Check if ecosystem.config.js exists
123
+ if (fs.existsSync(ecosystemPath)) {
124
+ const pm2 = spawn(pm2Command, ['start', ecosystemPath], {
125
+ stdio: 'inherit',
126
+ cwd: serverDir
127
+ });
234
128
 
235
- // 重新调用当前脚本
236
- const child = require('child_process').spawn('node', [__filename, ...args], {
129
+ pm2.on('close', (code) => {
130
+ console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
131
+ process.exit(code);
132
+ });
133
+
134
+ pm2.on('error', (error) => {
135
+ console.error('[ReactPress Server] Failed to start with PM2:', error);
136
+ process.exit(1);
137
+ });
138
+ } else {
139
+ // Fallback to direct start
140
+ const pm2 = spawn(pm2Command, ['start', distPath, '--name', 'reactpress-server'], {
237
141
  stdio: 'inherit',
238
- env: process.env
142
+ cwd: serverDir
239
143
  });
240
144
 
241
- child.on('exit', (code) => {
145
+ pm2.on('close', (code) => {
146
+ console.log(`[ReactPress Server] PM2 process exited with code ${code}`);
242
147
  process.exit(code);
243
148
  });
244
- });
149
+
150
+ pm2.on('error', (error) => {
151
+ console.error('[ReactPress Server] Failed to start with PM2:', error);
152
+ process.exit(1);
153
+ });
154
+ }
155
+ }
156
+
157
+ // Function to start with regular Node.js
158
+ function startWithNode() {
159
+ // Check if the server is built
160
+ if (!fs.existsSync(distPath)) {
161
+ console.log('[ReactPress Server] Server not built yet. Building...');
162
+
163
+ // Try to build the server
164
+ const buildResult = spawnSync('npm', ['run', 'build'], {
165
+ stdio: 'inherit',
166
+ cwd: serverDir
167
+ });
168
+
169
+ if (buildResult.status !== 0) {
170
+ console.error('[ReactPress Server] Failed to build server');
171
+ process.exit(1);
172
+ }
173
+ }
174
+
175
+ // ONLY set the environment variable if it's not already set
176
+ // This preserves the value set by set-env.js when running pnpm dev from root
177
+ if (!process.env.REACTPRESS_ORIGINAL_CWD) {
178
+ process.env.REACTPRESS_ORIGINAL_CWD = originalCwd;
179
+ } else {
180
+ console.log(`[ReactPress Server] Using existing REACTPRESS_ORIGINAL_CWD: ${process.env.REACTPRESS_ORIGINAL_CWD}`);
181
+ }
182
+
183
+ // Change to the server directory
184
+ process.chdir(serverDir);
185
+
186
+ // Set environment variables
187
+ process.env.NODE_ENV = process.env.NODE_ENV || 'production';
188
+
189
+ // Import and run the server
190
+ try {
191
+ require(distPath);
192
+ } catch (error) {
193
+ console.error('[ReactPress Server] Failed to start server:', error);
194
+ process.exit(1);
195
+ }
196
+ }
245
197
 
246
- program.parse();
198
+ // Main execution
199
+ if (usePM2) {
200
+ startWithPM2();
201
+ } else {
202
+ startWithNode();
203
+ }
package/dist/main.d.ts CHANGED
@@ -1 +1,6 @@
1
+ declare global {
2
+ var installationServer: any;
3
+ var installationPort: number;
4
+ var isInstalling: boolean;
5
+ }
1
6
  export {};