nodebbs 0.0.9 → 0.1.0
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/README.md +19 -17
- package/dist/commands/db/import.d.ts +10 -0
- package/dist/commands/db/import.js +87 -0
- package/dist/commands/pack/index.js +3 -4
- package/dist/commands/rebuild/index.js +3 -3
- package/dist/commands/start/index.d.ts +1 -1
- package/dist/commands/start/index.js +70 -61
- package/dist/templates/docker-compose.lowmem.yml +3 -49
- package/dist/templates/docker-compose.yml +91 -34
- package/dist/templates/env +26 -11
- package/dist/utils/docker.d.ts +1 -1
- package/dist/utils/docker.js +2 -5
- package/dist/utils/env.d.ts +1 -1
- package/dist/utils/selection.d.ts +1 -1
- package/dist/utils/selection.js +5 -6
- package/oclif.manifest.json +93 -59
- package/package.json +1 -1
- package/dist/templates/docker-compose.prod.yml +0 -120
- package/dist/templates/init-db.sql +0 -14
|
@@ -3,22 +3,37 @@ services:
|
|
|
3
3
|
postgres:
|
|
4
4
|
image: postgres:16-alpine
|
|
5
5
|
container_name: nodebbs-postgres
|
|
6
|
-
restart:
|
|
6
|
+
restart: always
|
|
7
7
|
environment:
|
|
8
8
|
POSTGRES_USER: postgres
|
|
9
|
-
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD
|
|
9
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
10
10
|
POSTGRES_DB: ${POSTGRES_DB:-nodebbs}
|
|
11
|
-
TZ: Asia/Shanghai
|
|
11
|
+
TZ: ${TZ:-Asia/Shanghai}
|
|
12
12
|
volumes:
|
|
13
13
|
- postgres_data:/var/lib/postgresql/data
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
# 生产环境默认不暴露数据库端口到主机,只在 Docker 网络内部访问
|
|
15
|
+
# 如果需要外部访问 (如开发调试),可以将下面两行取消注释
|
|
16
|
+
# ports:
|
|
17
|
+
# - "${POSTGRES_PORT:-5432}:5432"
|
|
17
18
|
healthcheck:
|
|
18
19
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
19
|
-
interval:
|
|
20
|
-
timeout:
|
|
20
|
+
interval: 30s
|
|
21
|
+
timeout: 10s
|
|
21
22
|
retries: 5
|
|
23
|
+
start_period: 40s
|
|
24
|
+
deploy:
|
|
25
|
+
resources:
|
|
26
|
+
limits:
|
|
27
|
+
cpus: '1'
|
|
28
|
+
memory: 512M
|
|
29
|
+
reservations:
|
|
30
|
+
cpus: '0.25'
|
|
31
|
+
memory: 256M
|
|
32
|
+
logging:
|
|
33
|
+
driver: "json-file"
|
|
34
|
+
options:
|
|
35
|
+
max-size: "10m"
|
|
36
|
+
max-file: "3"
|
|
22
37
|
networks:
|
|
23
38
|
- nodebbs-network
|
|
24
39
|
|
|
@@ -26,45 +41,62 @@ services:
|
|
|
26
41
|
redis:
|
|
27
42
|
image: redis:7-alpine
|
|
28
43
|
container_name: nodebbs-redis
|
|
29
|
-
restart:
|
|
30
|
-
command:
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
restart: always
|
|
45
|
+
command: >
|
|
46
|
+
redis-server
|
|
47
|
+
--requirepass ${REDIS_PASSWORD}
|
|
48
|
+
--appendonly yes
|
|
49
|
+
--appendfsync everysec
|
|
50
|
+
--maxmemory 256mb
|
|
51
|
+
--maxmemory-policy allkeys-lru
|
|
33
52
|
volumes:
|
|
34
53
|
- redis_data:/data
|
|
35
|
-
|
|
36
|
-
|
|
54
|
+
# 生产环境默认不暴露 Redis 端口到主机
|
|
55
|
+
# ports:
|
|
56
|
+
# - "${REDIS_PORT:-6379}:6379"
|
|
37
57
|
healthcheck:
|
|
38
58
|
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
|
39
|
-
interval:
|
|
40
|
-
timeout:
|
|
59
|
+
interval: 30s
|
|
60
|
+
timeout: 10s
|
|
41
61
|
retries: 5
|
|
62
|
+
start_period: 20s
|
|
63
|
+
deploy:
|
|
64
|
+
resources:
|
|
65
|
+
limits:
|
|
66
|
+
cpus: '0.5'
|
|
67
|
+
memory: 256M
|
|
68
|
+
reservations:
|
|
69
|
+
cpus: '0.1'
|
|
70
|
+
memory: 128M
|
|
71
|
+
logging:
|
|
72
|
+
driver: "json-file"
|
|
73
|
+
options:
|
|
74
|
+
max-size: "10m"
|
|
75
|
+
max-file: "3"
|
|
42
76
|
networks:
|
|
43
77
|
- nodebbs-network
|
|
44
78
|
|
|
45
79
|
# API 服务
|
|
46
80
|
api:
|
|
47
|
-
|
|
48
|
-
context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
|
|
49
|
-
dockerfile: apps/api/Dockerfile
|
|
81
|
+
image: ${API_IMAGE:-ghcr.io/aiprojecthub/nodebbs-api:latest}
|
|
50
82
|
container_name: nodebbs-api
|
|
51
|
-
restart:
|
|
83
|
+
restart: always
|
|
52
84
|
environment:
|
|
53
85
|
NODE_ENV: production
|
|
54
86
|
APP_NAME: ${APP_NAME:-nodebbs}
|
|
55
87
|
HOST: 0.0.0.0
|
|
56
88
|
PORT: 7100
|
|
57
|
-
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD
|
|
58
|
-
REDIS_URL: redis://default:${REDIS_PASSWORD
|
|
59
|
-
USER_CACHE_TTL: ${USER_CACHE_TTL:-
|
|
60
|
-
JWT_SECRET: ${JWT_SECRET
|
|
89
|
+
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-nodebbs}
|
|
90
|
+
REDIS_URL: redis://default:${REDIS_PASSWORD}@redis:6379/0
|
|
91
|
+
USER_CACHE_TTL: ${USER_CACHE_TTL:-300}
|
|
92
|
+
JWT_SECRET: ${JWT_SECRET}
|
|
61
93
|
JWT_ACCESS_TOKEN_EXPIRES_IN: ${JWT_ACCESS_TOKEN_EXPIRES_IN:-1y}
|
|
62
94
|
CORS_ORIGIN: ${CORS_ORIGIN:-*}
|
|
63
95
|
APP_URL: ${APP_URL:-http://localhost:3100}
|
|
64
|
-
TZ: Asia/Shanghai
|
|
96
|
+
TZ: ${TZ:-Asia/Shanghai}
|
|
97
|
+
NODE_OPTIONS: "--max-old-space-size=512"
|
|
65
98
|
volumes:
|
|
66
99
|
- api_uploads:/app/apps/api/uploads
|
|
67
|
-
- ./apps/api/src:/app/apps/api/src:ro
|
|
68
100
|
ports:
|
|
69
101
|
- "${API_PORT:-7100}:7100"
|
|
70
102
|
depends_on:
|
|
@@ -78,26 +110,35 @@ services:
|
|
|
78
110
|
timeout: 10s
|
|
79
111
|
retries: 3
|
|
80
112
|
start_period: 40s
|
|
113
|
+
deploy:
|
|
114
|
+
resources:
|
|
115
|
+
limits:
|
|
116
|
+
cpus: '1'
|
|
117
|
+
memory: 768M
|
|
118
|
+
reservations:
|
|
119
|
+
cpus: '0.3'
|
|
120
|
+
memory: 384M
|
|
121
|
+
logging:
|
|
122
|
+
driver: "json-file"
|
|
123
|
+
options:
|
|
124
|
+
max-size: "20m"
|
|
125
|
+
max-file: "5"
|
|
81
126
|
networks:
|
|
82
127
|
- nodebbs-network
|
|
83
128
|
|
|
84
129
|
# Web 前端服务
|
|
85
130
|
web:
|
|
86
|
-
|
|
87
|
-
context: . # 从 monorepo 根目录构建(turbo prune 需要完整的 workspace)
|
|
88
|
-
dockerfile: apps/web/Dockerfile
|
|
89
|
-
args:
|
|
90
|
-
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
|
|
91
|
-
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
|
|
131
|
+
image: ${WEB_IMAGE:-ghcr.io/aiprojecthub/nodebbs-web:latest}
|
|
92
132
|
container_name: nodebbs-web
|
|
93
|
-
restart:
|
|
133
|
+
restart: always
|
|
94
134
|
environment:
|
|
95
135
|
NODE_ENV: production
|
|
96
136
|
APP_NAME: ${APP_NAME:-nodebbs}
|
|
97
137
|
PORT: 3100
|
|
98
138
|
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:7100}
|
|
99
139
|
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3100}
|
|
100
|
-
TZ: Asia/Shanghai
|
|
140
|
+
TZ: ${TZ:-Asia/Shanghai}
|
|
141
|
+
NODE_OPTIONS: "--max-old-space-size=512"
|
|
101
142
|
ports:
|
|
102
143
|
- "${WEB_PORT:-3100}:3100"
|
|
103
144
|
depends_on:
|
|
@@ -109,6 +150,19 @@ services:
|
|
|
109
150
|
timeout: 10s
|
|
110
151
|
retries: 3
|
|
111
152
|
start_period: 40s
|
|
153
|
+
deploy:
|
|
154
|
+
resources:
|
|
155
|
+
limits:
|
|
156
|
+
cpus: '1'
|
|
157
|
+
memory: 768M
|
|
158
|
+
reservations:
|
|
159
|
+
cpus: '0.3'
|
|
160
|
+
memory: 384M
|
|
161
|
+
logging:
|
|
162
|
+
driver: "json-file"
|
|
163
|
+
options:
|
|
164
|
+
max-size: "20m"
|
|
165
|
+
max-file: "5"
|
|
112
166
|
networks:
|
|
113
167
|
- nodebbs-network
|
|
114
168
|
|
|
@@ -125,3 +179,6 @@ volumes:
|
|
|
125
179
|
networks:
|
|
126
180
|
nodebbs-network:
|
|
127
181
|
driver: bridge
|
|
182
|
+
ipam:
|
|
183
|
+
config:
|
|
184
|
+
- subnet: 172.28.0.0/16
|
package/dist/templates/env
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
# ========================================
|
|
2
|
-
# NodeBBS
|
|
2
|
+
# NodeBBS 部署环境变量配置示例
|
|
3
3
|
# ========================================
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# ========================================
|
|
6
|
+
# 基础配置
|
|
7
|
+
# ========================================
|
|
8
|
+
# 应用名称(用于 Docker 容器前缀)
|
|
6
9
|
APP_NAME=nodebbs
|
|
7
10
|
|
|
11
|
+
# 部署环境 (prod, dev)
|
|
12
|
+
NODE_ENV=production
|
|
13
|
+
|
|
14
|
+
# 镜像配置
|
|
15
|
+
# 默认为 GitHub Container Registry
|
|
16
|
+
# 注意:使用 `nodebbs start` 时,可以选择版本 tag 覆盖此处的默认 latest tag
|
|
17
|
+
# 如果需要固定特定版本 (如 v1.0),请修改以下配置或在部署时输入对应的 tag
|
|
18
|
+
API_IMAGE=ghcr.io/aiprojecthub/nodebbs-api:latest
|
|
19
|
+
WEB_IMAGE=ghcr.io/aiprojecthub/nodebbs-web:latest
|
|
20
|
+
|
|
8
21
|
# ========================================
|
|
9
22
|
# 数据库配置
|
|
10
23
|
# ========================================
|
|
24
|
+
# 务必修改为强密码!
|
|
11
25
|
POSTGRES_PASSWORD=your_secure_postgres_password_here
|
|
12
26
|
POSTGRES_DB=nodebbs
|
|
13
27
|
POSTGRES_PORT=5432
|
|
@@ -15,6 +29,7 @@ POSTGRES_PORT=5432
|
|
|
15
29
|
# ========================================
|
|
16
30
|
# Redis 配置
|
|
17
31
|
# ========================================
|
|
32
|
+
# 务必修改为强密码!
|
|
18
33
|
REDIS_PASSWORD=your_secure_redis_password_here
|
|
19
34
|
REDIS_PORT=6379
|
|
20
35
|
|
|
@@ -24,8 +39,8 @@ REDIS_PORT=6379
|
|
|
24
39
|
API_PORT=7100
|
|
25
40
|
|
|
26
41
|
# 用户缓存 TTL(秒)
|
|
27
|
-
#
|
|
28
|
-
USER_CACHE_TTL=
|
|
42
|
+
# 生产环境建议: 120-300
|
|
43
|
+
USER_CACHE_TTL=300
|
|
29
44
|
|
|
30
45
|
# JWT 配置
|
|
31
46
|
# 使用 `openssl rand -base64 32` 生成安全的密钥
|
|
@@ -37,6 +52,7 @@ JWT_ACCESS_TOKEN_EXPIRES_IN=1y
|
|
|
37
52
|
CORS_ORIGIN=*
|
|
38
53
|
|
|
39
54
|
# 应用 URL(OAuth 回调使用)
|
|
55
|
+
# 生产环境请修改为公网域名
|
|
40
56
|
APP_URL=http://localhost:3100
|
|
41
57
|
|
|
42
58
|
# ========================================
|
|
@@ -45,17 +61,16 @@ APP_URL=http://localhost:3100
|
|
|
45
61
|
WEB_PORT=3100
|
|
46
62
|
|
|
47
63
|
# API 地址(公网访问地址)
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
NEXT_PUBLIC_API_URL=http://192.168.0.100:7100
|
|
64
|
+
# 生产环境请修改为公网域名,例如: https://api.yourdomain.com
|
|
65
|
+
# 或者是 Nginx 反向代理后的地址,例如: https://yourdomain.com/api
|
|
66
|
+
NEXT_PUBLIC_API_URL=http://localhost:7100
|
|
52
67
|
|
|
53
68
|
# 应用 URL(公网访问地址)
|
|
54
|
-
#
|
|
55
|
-
# 生产环境: https://yourdomain.com
|
|
69
|
+
# 生产环境请修改为公网域名,例如: https://yourdomain.com
|
|
56
70
|
NEXT_PUBLIC_APP_URL=http://localhost:3100
|
|
57
71
|
|
|
58
72
|
# ========================================
|
|
59
|
-
#
|
|
73
|
+
# 其他配置
|
|
60
74
|
# ========================================
|
|
75
|
+
# 时区
|
|
61
76
|
TZ=Asia/Shanghai
|
package/dist/utils/docker.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - 如果存在,则优先使用项目根目录的配置。
|
|
6
6
|
* - 如果不存在,则使用 CLI 内置的模板文件。
|
|
7
7
|
*
|
|
8
|
-
* @param env - 运行环境 ('production' | 'lowmem'
|
|
8
|
+
* @param env - 运行环境 ('production' | 'lowmem')
|
|
9
9
|
* @returns 对象包含文件路径数组和是否使用内置模板的标志
|
|
10
10
|
*/
|
|
11
11
|
export declare function getComposeFiles(env: string): Promise<{
|
package/dist/utils/docker.js
CHANGED
|
@@ -12,7 +12,7 @@ const fileExists = promisify(exists);
|
|
|
12
12
|
* - 如果存在,则优先使用项目根目录的配置。
|
|
13
13
|
* - 如果不存在,则使用 CLI 内置的模板文件。
|
|
14
14
|
*
|
|
15
|
-
* @param env - 运行环境 ('production' | 'lowmem'
|
|
15
|
+
* @param env - 运行环境 ('production' | 'lowmem')
|
|
16
16
|
* @returns 对象包含文件路径数组和是否使用内置模板的标志
|
|
17
17
|
*/
|
|
18
18
|
export async function getComposeFiles(env) {
|
|
@@ -29,7 +29,7 @@ export async function getComposeFiles(env) {
|
|
|
29
29
|
}
|
|
30
30
|
const files = [baseFile];
|
|
31
31
|
if (env === 'production') {
|
|
32
|
-
|
|
32
|
+
// Production now uses the default file (merged config)
|
|
33
33
|
}
|
|
34
34
|
else if (env === 'lowmem') {
|
|
35
35
|
files.push(path.join(templateDir, 'docker-compose.lowmem.yml'));
|
|
@@ -68,9 +68,6 @@ export async function runCompose(files, args, isBuiltIn = false) {
|
|
|
68
68
|
const composeArgs = files.flatMap(f => ['-f', f]);
|
|
69
69
|
if (isBuiltIn) {
|
|
70
70
|
composeArgs.push('--project-directory', process.cwd());
|
|
71
|
-
// 将 INIT_DB_PATH 设置为内置 sql 文件
|
|
72
|
-
const templateDir = path.dirname(files[0]);
|
|
73
|
-
process.env.INIT_DB_PATH = path.join(templateDir, 'init-db.sql');
|
|
74
71
|
}
|
|
75
72
|
composeArgs.push(...args);
|
|
76
73
|
// 使用 stdio: 'inherit' 实时显示输出
|
package/dist/utils/env.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function initEnv(): Promise<void>;
|
|
2
|
-
export declare function checkEnv(envType: 'production' | 'lowmem'
|
|
2
|
+
export declare function checkEnv(envType: 'production' | 'lowmem'): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type EnvType = 'production' | 'lowmem'
|
|
1
|
+
export type EnvType = 'production' | 'lowmem';
|
|
2
2
|
export declare const EnvFlag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
3
3
|
export declare function setStoredEnv(env: EnvType): Promise<void>;
|
|
4
4
|
export declare function clearStoredEnv(): Promise<void>;
|
package/dist/utils/selection.js
CHANGED
|
@@ -6,14 +6,14 @@ import path from 'node:path';
|
|
|
6
6
|
const ENV_MARKER_FILE = '.env.lock';
|
|
7
7
|
export const EnvFlag = Flags.string({
|
|
8
8
|
char: 'e',
|
|
9
|
-
description: '部署环境 (production, lowmem
|
|
10
|
-
options: ['production', 'lowmem'
|
|
9
|
+
description: '部署环境 (production, lowmem)',
|
|
10
|
+
options: ['production', 'lowmem'],
|
|
11
11
|
});
|
|
12
12
|
async function getStoredEnv() {
|
|
13
13
|
try {
|
|
14
14
|
const content = await fs.readFile(path.resolve(process.cwd(), ENV_MARKER_FILE), 'utf-8');
|
|
15
15
|
const env = content.trim();
|
|
16
|
-
if (['production', 'lowmem'
|
|
16
|
+
if (['production', 'lowmem'].includes(env)) {
|
|
17
17
|
return env;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -51,9 +51,8 @@ export async function selectEnvironment(env, options = {}) {
|
|
|
51
51
|
const selected = await select({
|
|
52
52
|
message: options.prompt || '请选择运行环境:',
|
|
53
53
|
choices: [
|
|
54
|
-
{ name: '
|
|
55
|
-
{ name: '低配环境 (1C1G
|
|
56
|
-
{ name: '基础环境 (仅用于测试)', value: 'basic' },
|
|
54
|
+
{ name: '标准环境 (推荐)', value: 'production' },
|
|
55
|
+
{ name: '低配环境 (1C1G)', value: 'lowmem' },
|
|
57
56
|
{ name: '❌ 取消', value: '__CANCEL__' },
|
|
58
57
|
],
|
|
59
58
|
loop: true,
|