nodebbs 0.3.0 → 0.3.2
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/templates/docker-compose.yml +2 -3
- package/dist/templates/env +2 -2
- package/dist/utils/docker.d.ts +1 -1
- package/dist/utils/docker.js +83 -3
- package/dist/utils/env.js +0 -11
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -43,7 +43,7 @@ services:
|
|
|
43
43
|
# API 服务
|
|
44
44
|
api:
|
|
45
45
|
build:
|
|
46
|
-
context:
|
|
46
|
+
context: .
|
|
47
47
|
dockerfile: apps/api/Dockerfile
|
|
48
48
|
image: ${API_IMAGE:-nodebbs-api:local}
|
|
49
49
|
container_name: nodebbs-api
|
|
@@ -59,7 +59,6 @@ services:
|
|
|
59
59
|
JWT_SECRET: ${JWT_SECRET:-change-this-to-a-secure-random-string-in-production}
|
|
60
60
|
JWT_ACCESS_TOKEN_EXPIRES_IN: ${JWT_ACCESS_TOKEN_EXPIRES_IN:-1y}
|
|
61
61
|
CORS_ORIGIN: ${CORS_ORIGIN:-*}
|
|
62
|
-
APP_URL: ${APP_URL:-http://localhost:3100}
|
|
63
62
|
TZ: Asia/Shanghai
|
|
64
63
|
volumes:
|
|
65
64
|
- api_uploads:/app/apps/api/uploads
|
|
@@ -83,7 +82,7 @@ services:
|
|
|
83
82
|
# Web 前端服务
|
|
84
83
|
web:
|
|
85
84
|
build:
|
|
86
|
-
context:
|
|
85
|
+
context: .
|
|
87
86
|
dockerfile: apps/web/Dockerfile
|
|
88
87
|
image: ${WEB_IMAGE:-nodebbs-web:local}
|
|
89
88
|
container_name: nodebbs-web
|
package/dist/templates/env
CHANGED
|
@@ -34,10 +34,10 @@ JWT_ACCESS_TOKEN_EXPIRES_IN=1y
|
|
|
34
34
|
|
|
35
35
|
# CORS 配置
|
|
36
36
|
# 生产环境建议设置为具体的域名,例如: https://yourdomain.com
|
|
37
|
+
# 支持通配符 * 格式:https://yourdomain.com,https://*.yourdomain.com
|
|
37
38
|
CORS_ORIGIN=*
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
APP_URL=http://localhost:3100
|
|
40
|
+
|
|
41
41
|
|
|
42
42
|
# ========================================
|
|
43
43
|
# Web 前端配置
|
package/dist/utils/docker.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare function getComposeFiles(env: string): Promise<{
|
|
|
16
16
|
* 检查 Docker 环境是否可用
|
|
17
17
|
*
|
|
18
18
|
* 验证 `docker` 和 `docker compose` 命令是否已安装并能正常响应。
|
|
19
|
-
*
|
|
19
|
+
* 如果检查失败,会询问用户是否自动安装。
|
|
20
20
|
*/
|
|
21
21
|
export declare function checkDocker(): Promise<void>;
|
|
22
22
|
/**
|
package/dist/utils/docker.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
3
|
import { logger } from './logger.js';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { exists } from 'node:fs';
|
|
@@ -83,7 +84,7 @@ export async function getComposeFiles(env) {
|
|
|
83
84
|
* 检查 Docker 环境是否可用
|
|
84
85
|
*
|
|
85
86
|
* 验证 `docker` 和 `docker compose` 命令是否已安装并能正常响应。
|
|
86
|
-
*
|
|
87
|
+
* 如果检查失败,会询问用户是否自动安装。
|
|
87
88
|
*/
|
|
88
89
|
export async function checkDocker() {
|
|
89
90
|
logger.info('正在检查 Docker 环境...');
|
|
@@ -93,8 +94,87 @@ export async function checkDocker() {
|
|
|
93
94
|
logger.success('Docker 环境检查通过');
|
|
94
95
|
}
|
|
95
96
|
catch (error) {
|
|
96
|
-
logger.
|
|
97
|
-
|
|
97
|
+
logger.warning('未检测到 Docker 或 Docker Compose。');
|
|
98
|
+
// 如果是 CI 环境或非交互式环境,直接报错
|
|
99
|
+
if (process.env.CI || !process.stdout.isTTY) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
const shouldInstall = await confirm({
|
|
103
|
+
message: '检测到未安装 Docker,是否尝试自动安装?',
|
|
104
|
+
default: true
|
|
105
|
+
});
|
|
106
|
+
if (shouldInstall) {
|
|
107
|
+
try {
|
|
108
|
+
await installDocker();
|
|
109
|
+
// 安装后再次检查
|
|
110
|
+
logger.info('安装完成,正在验证...');
|
|
111
|
+
await execa('docker', ['--version']);
|
|
112
|
+
await execa('docker', ['compose', 'version']);
|
|
113
|
+
logger.success('Docker 环境安装并验证通过!');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
catch (installError) {
|
|
117
|
+
logger.error(`安装失败: ${installError.message}`);
|
|
118
|
+
logger.info('请访问 https://www.docker.com/get-started 手动安装。');
|
|
119
|
+
throw installError;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 用户拒绝安装
|
|
123
|
+
logger.error('用户选择不安装 Docker,无法继续。');
|
|
124
|
+
throw new Error('用户拒绝安装 Docker');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 根据操作系统自动安装 Docker
|
|
129
|
+
*
|
|
130
|
+
* 目前仅支持 Linux 平台,使用官方安装脚本 (get.docker.com)。
|
|
131
|
+
* 安装完成后会尝试启动 Docker 服务并清理临时文件。
|
|
132
|
+
*/
|
|
133
|
+
async function installDocker() {
|
|
134
|
+
const platform = process.platform;
|
|
135
|
+
if (platform === 'linux') {
|
|
136
|
+
const scriptPath = 'get-docker.sh';
|
|
137
|
+
try {
|
|
138
|
+
// 下载官方安装脚本
|
|
139
|
+
logger.info('正在下载 Docker 官方安装脚本...');
|
|
140
|
+
await execa('curl', ['-fsSL', 'https://get.docker.com', '-o', scriptPath], { stdio: 'inherit' });
|
|
141
|
+
// 执行安装脚本
|
|
142
|
+
logger.info('正在执行安装脚本 (可能需要 sudo 权限)...');
|
|
143
|
+
await execa('sh', [scriptPath], { stdio: 'inherit' });
|
|
144
|
+
// 尝试启动 Docker 服务
|
|
145
|
+
logger.info('正在尝试启动 Docker 服务...');
|
|
146
|
+
try {
|
|
147
|
+
await execa('sudo', ['systemctl', 'start', 'docker']);
|
|
148
|
+
await execa('sudo', ['systemctl', 'enable', 'docker']);
|
|
149
|
+
logger.success('Docker 服务已启动并设置为开机自启');
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
logger.warning('无法自动启动 Docker 服务');
|
|
153
|
+
logger.info('请手动运行: sudo systemctl start docker');
|
|
154
|
+
}
|
|
155
|
+
// 提示用户可能需要添加到 docker 组
|
|
156
|
+
logger.warning('请确保您的用户已添加到 docker 组:');
|
|
157
|
+
logger.info(' sudo usermod -aG docker $USER');
|
|
158
|
+
logger.info('您可能需要注销并重新登录才能生效。');
|
|
159
|
+
await confirm({ message: '是否已完成必要配置并准备继续?', default: true });
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
// 清理临时安装脚本
|
|
163
|
+
try {
|
|
164
|
+
const fs = await import('node:fs/promises');
|
|
165
|
+
await fs.unlink(scriptPath);
|
|
166
|
+
logger.info('已清理临时安装脚本');
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// 静默忽略清理失败
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// 不支持的平台 (macOS, Windows 等)
|
|
175
|
+
logger.warning(`暂不支持在 ${platform} 平台自动安装 Docker。`);
|
|
176
|
+
logger.info('请访问 https://www.docker.com/products/docker-desktop/ 下载安装。');
|
|
177
|
+
throw new Error(`不支持在 ${platform} 平台自动安装`);
|
|
98
178
|
}
|
|
99
179
|
}
|
|
100
180
|
/**
|
package/dist/utils/env.js
CHANGED
|
@@ -95,11 +95,6 @@ export async function initEnv() {
|
|
|
95
95
|
default: '7100'
|
|
96
96
|
});
|
|
97
97
|
const serverApiUrl = `http://api:${apiPort}`;
|
|
98
|
-
const defaultAppUrl = `http://localhost:${webPort}`;
|
|
99
|
-
const appUrl = await input({
|
|
100
|
-
message: '设置 APP_URL (应用访问地址):',
|
|
101
|
-
default: defaultAppUrl
|
|
102
|
-
});
|
|
103
98
|
const corsOrigin = await input({
|
|
104
99
|
message: '设置 CORS_ORIGIN (允许跨域的域名):',
|
|
105
100
|
default: '*'
|
|
@@ -111,7 +106,6 @@ export async function initEnv() {
|
|
|
111
106
|
console.log(`JWT_SECRET: ${jwtSecret.substring(0, 3)}******`);
|
|
112
107
|
console.log(`WEB_PORT: ${webPort}`);
|
|
113
108
|
console.log(`API_PORT: ${apiPort}`);
|
|
114
|
-
console.log(`APP_URL: ${appUrl}`);
|
|
115
109
|
console.log(`SERVER_API_URL: ${serverApiUrl}`);
|
|
116
110
|
console.log(`CORS_ORIGIN: ${corsOrigin}`);
|
|
117
111
|
console.log('==========================================\n');
|
|
@@ -135,7 +129,6 @@ export async function initEnv() {
|
|
|
135
129
|
'WEB_PORT': webPort,
|
|
136
130
|
'API_PORT': apiPort,
|
|
137
131
|
'SERVER_API_URL': serverApiUrl,
|
|
138
|
-
'APP_URL': appUrl,
|
|
139
132
|
'CORS_ORIGIN': corsOrigin,
|
|
140
133
|
};
|
|
141
134
|
// 针对每个 Key 进行替换。
|
|
@@ -250,10 +243,6 @@ export async function checkEnv(envType) {
|
|
|
250
243
|
logger.warning('生产环境建议设置具体的 CORS_ORIGIN');
|
|
251
244
|
warnings++;
|
|
252
245
|
}
|
|
253
|
-
if (!envConfig.APP_URL || envConfig.APP_URL === 'http://localhost:3100') {
|
|
254
|
-
logger.warning('生产环境建议设置实际的 APP_URL');
|
|
255
|
-
warnings++;
|
|
256
|
-
}
|
|
257
246
|
}
|
|
258
247
|
if (errors > 0) {
|
|
259
248
|
logger.error(`发现 ${errors} 个配置错误,无法继续。`);
|
package/oclif.manifest.json
CHANGED