nuwax-file-server 1.2.4 → 1.2.6
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 +131 -151
- package/dist/appConfig/index.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/config/swagger.js +1 -1
- package/dist/env.development +3 -0
- package/dist/env.production +3 -0
- package/dist/routes/buildRoutes.js +1 -1
- package/dist/routes/codeRoutes.js +1 -1
- package/dist/routes/computerRoutes.js +1 -1
- package/dist/routes/projectRoutes.js +1 -1
- package/dist/scheduler/pnpmPruneScheduler.js +2 -2
- package/dist/server.js +1 -1
- package/dist/service/codeService.js +2 -2
- package/dist/service/projectService.js +1 -1
- package/dist/utils/build/buildProjectUtils.js +4 -4
- package/dist/utils/build/keepAliveDevUtils.js +1 -1
- package/dist/utils/build/processManager.js +9 -9
- package/dist/utils/build/restartDevUtils.js +1 -1
- package/dist/utils/build/startDevUtils.js +1 -1
- package/dist/utils/build/stopDevUtils.js +2 -2
- package/dist/utils/build/syntaxCheckUtils.js +7 -7
- package/dist/utils/buildArg/extraArgsUtils.js +1 -1
- package/dist/utils/buildArg/portPool.js +1 -1
- package/dist/utils/buildArg/portUtils.js +7 -7
- package/dist/utils/buildDependency/dependencyManager.js +17 -17
- package/dist/utils/buildJudge/aliveJudgeUtils.js +1 -1
- package/dist/utils/buildJudge/restartJudgeUtils.js +1 -1
- package/dist/utils/buildPermission/permissionManager.js +3 -3
- package/dist/utils/common/npmrcUtils.js +3 -3
- package/dist/utils/common/zipUtils.js +1 -1
- package/dist/utils/computer/computerFileUtils.js +1 -1
- package/dist/utils/computer/computerUtils.js +1 -1
- package/dist/utils/envUtils.js +3 -3
- package/dist/utils/error/buildErrorParser.js +18 -18
- package/dist/utils/error/errorHandler.js +1 -1
- package/dist/utils/log/getDevLogUtils.js +2 -2
- package/dist/utils/log/logCacheManager.js +2 -2
- package/dist/utils/log/logUtils.js +2 -2
- package/dist/utils/project/backupUtils.js +1 -1
- package/dist/utils/project/copyProjectUtils.js +1 -1
- package/dist/utils/project/frameworkDetectorUtils.js +1 -1
- package/dist/utils/project/getContentUtils.js +1 -1
- package/dist/utils/project/initProjectCleanupUtils.js +1 -1
- package/dist/utils/project/uploadAttachmentFileUtils.js +1 -1
- package/dist/utils/serviceManager.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,159 +1,151 @@
|
|
|
1
1
|
# nuwax-file-server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cross-platform file service deployment tooling for Windows, Linux, and macOS.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
- **CLI
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- **PID
|
|
7
|
+
- **CLI**: `start`, `stop`, `restart`, `status`
|
|
8
|
+
- **Cross-platform**: Windows, Linux, and macOS
|
|
9
|
+
- **Configuration**: Environment variables and CLI flags
|
|
10
|
+
- **Health endpoint**: `GET /health` for liveness checks
|
|
11
|
+
- **PID file**: Tracks and manages the server process
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Installation
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### Local development
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
# 克隆项目
|
|
19
18
|
git clone <repository-url>
|
|
20
19
|
cd nuwax-file-server
|
|
21
20
|
|
|
22
|
-
# 安装依赖
|
|
23
21
|
npm install
|
|
24
22
|
|
|
25
|
-
#
|
|
23
|
+
# Development mode
|
|
26
24
|
npm run dev
|
|
27
25
|
|
|
28
|
-
#
|
|
26
|
+
# Production mode (local)
|
|
29
27
|
npm run prod
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
###
|
|
30
|
+
### Global CLI install
|
|
33
31
|
|
|
34
32
|
```bash
|
|
35
|
-
#
|
|
33
|
+
# From the project root
|
|
36
34
|
npm install -g .
|
|
37
35
|
|
|
38
|
-
#
|
|
36
|
+
# Then run from anywhere
|
|
39
37
|
nuwax-file-server --help
|
|
40
38
|
```
|
|
41
39
|
|
|
42
|
-
###
|
|
40
|
+
### Requirements
|
|
43
41
|
|
|
44
|
-
- Node.js >= 22.0.0
|
|
45
|
-
- zip/unzip
|
|
46
|
-
- pnpm
|
|
42
|
+
- Node.js >= 22.0.0 (native ES modules)
|
|
43
|
+
- zip/unzip (for project archives)
|
|
44
|
+
- pnpm (recommended) or npm/yarn
|
|
47
45
|
|
|
48
|
-
## CLI
|
|
46
|
+
## CLI
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
Available commands:
|
|
51
49
|
|
|
52
|
-
###
|
|
50
|
+
### Basics
|
|
53
51
|
|
|
54
52
|
```bash
|
|
55
|
-
#
|
|
53
|
+
# Start (defaults to env.production)
|
|
56
54
|
nuwax-file-server start
|
|
57
55
|
|
|
58
|
-
#
|
|
56
|
+
# Start with a specific env
|
|
59
57
|
nuwax-file-server start --env development
|
|
60
58
|
nuwax-file-server start --env production
|
|
61
59
|
nuwax-file-server start --env test
|
|
62
60
|
|
|
63
|
-
#
|
|
61
|
+
# Stop
|
|
64
62
|
nuwax-file-server stop
|
|
65
63
|
|
|
66
|
-
#
|
|
64
|
+
# Force stop
|
|
67
65
|
nuwax-file-server stop --force
|
|
68
66
|
|
|
69
|
-
#
|
|
67
|
+
# Restart
|
|
70
68
|
nuwax-file-server restart
|
|
71
69
|
|
|
72
|
-
#
|
|
70
|
+
# Status
|
|
73
71
|
nuwax-file-server status
|
|
74
72
|
```
|
|
75
73
|
|
|
76
|
-
###
|
|
74
|
+
### Advanced
|
|
77
75
|
|
|
78
76
|
```bash
|
|
79
|
-
#
|
|
77
|
+
# Custom port
|
|
80
78
|
nuwax-file-server start --port 8080
|
|
81
79
|
|
|
82
|
-
#
|
|
80
|
+
# Custom config file
|
|
83
81
|
nuwax-file-server start --config /path/to/config.json
|
|
84
82
|
|
|
85
|
-
#
|
|
83
|
+
# Combined
|
|
86
84
|
nuwax-file-server start --env development --port 3000
|
|
87
85
|
```
|
|
88
86
|
|
|
89
|
-
###
|
|
87
|
+
### npm scripts
|
|
90
88
|
|
|
91
89
|
```bash
|
|
92
|
-
# 启动服务
|
|
93
90
|
npm run cli:start
|
|
94
|
-
npm run cli:start:dev #
|
|
95
|
-
npm run cli:start:prod #
|
|
96
|
-
npm run cli:start:test #
|
|
91
|
+
npm run cli:start:dev # development
|
|
92
|
+
npm run cli:start:prod # production
|
|
93
|
+
npm run cli:start:test # test
|
|
97
94
|
|
|
98
|
-
# 停止服务
|
|
99
95
|
npm run cli:stop
|
|
100
|
-
|
|
101
|
-
# 重启服务
|
|
102
96
|
npm run cli:restart
|
|
103
|
-
|
|
104
|
-
# 查看状态
|
|
105
97
|
npm run cli:status
|
|
106
98
|
```
|
|
107
99
|
|
|
108
|
-
##
|
|
100
|
+
## Environment variables
|
|
109
101
|
|
|
110
|
-
|
|
102
|
+
Full reference: [Environment variables](./docs/ENV.md)
|
|
111
103
|
|
|
112
|
-
###
|
|
104
|
+
### Quick example
|
|
113
105
|
|
|
114
106
|
```bash
|
|
115
|
-
#
|
|
107
|
+
# Defaults from env.production (typical)
|
|
116
108
|
nuwax-file-server start --env production --port 60000
|
|
117
109
|
|
|
118
|
-
#
|
|
110
|
+
# Override paths (trim to what you need)
|
|
119
111
|
nuwax-file-server start --env production --port 60000 \
|
|
120
112
|
PROJECT_SOURCE_DIR=/data/projects \
|
|
121
113
|
DIST_TARGET_DIR=/var/www/html \
|
|
122
114
|
UPLOAD_PROJECT_DIR=/data/uploads
|
|
123
115
|
```
|
|
124
116
|
|
|
125
|
-
###
|
|
117
|
+
### Core path variables
|
|
126
118
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
| `INIT_PROJECT_DIR`
|
|
130
|
-
| `UPLOAD_PROJECT_DIR`
|
|
131
|
-
| `PROJECT_SOURCE_DIR`
|
|
132
|
-
| `DIST_TARGET_DIR`
|
|
133
|
-
| `LOG_BASE_DIR`
|
|
134
|
-
| `COMPUTER_WORKSPACE_DIR` |
|
|
135
|
-
| `COMPUTER_LOG_DIR`
|
|
119
|
+
| Variable | Purpose |
|
|
120
|
+
| -------- | ------- |
|
|
121
|
+
| `INIT_PROJECT_DIR` | Scaffold / init project directory |
|
|
122
|
+
| `UPLOAD_PROJECT_DIR` | Uploaded project archives |
|
|
123
|
+
| `PROJECT_SOURCE_DIR` | Project source tree |
|
|
124
|
+
| `DIST_TARGET_DIR` | Build output (e.g. nginx root) |
|
|
125
|
+
| `LOG_BASE_DIR` | Log directory root |
|
|
126
|
+
| `COMPUTER_WORKSPACE_DIR` | “Computer” workspace |
|
|
127
|
+
| `COMPUTER_LOG_DIR` | “Computer” logs |
|
|
136
128
|
|
|
137
|
-
|
|
129
|
+
More options and scenarios: [Environment variables](./docs/ENV.md)
|
|
138
130
|
|
|
139
|
-
###
|
|
131
|
+
### CLI precedence
|
|
140
132
|
|
|
141
133
|
```bash
|
|
142
|
-
#
|
|
134
|
+
# Port: CLI > env > default
|
|
143
135
|
nuwax-file-server start --env production --port 8080
|
|
144
136
|
```
|
|
145
137
|
|
|
146
|
-
##
|
|
138
|
+
## Health check
|
|
147
139
|
|
|
148
|
-
|
|
140
|
+
The server exposes `GET /health` for monitoring and probes.
|
|
149
141
|
|
|
150
|
-
###
|
|
142
|
+
### Request
|
|
151
143
|
|
|
152
144
|
```bash
|
|
153
145
|
curl http://localhost:60000/health
|
|
154
146
|
```
|
|
155
147
|
|
|
156
|
-
###
|
|
148
|
+
### Example response
|
|
157
149
|
|
|
158
150
|
```json
|
|
159
151
|
{
|
|
@@ -174,167 +166,155 @@ curl http://localhost:60000/health
|
|
|
174
166
|
}
|
|
175
167
|
```
|
|
176
168
|
|
|
177
|
-
###
|
|
169
|
+
### Response fields
|
|
178
170
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
| status
|
|
182
|
-
| timestamp
|
|
183
|
-
| uptime
|
|
184
|
-
| version
|
|
185
|
-
| platform
|
|
186
|
-
| nodeVersion | string | Node.js
|
|
187
|
-
| pid
|
|
188
|
-
| memory
|
|
189
|
-
| env
|
|
171
|
+
| Field | Type | Description |
|
|
172
|
+
| ----- | ---- | ----------- |
|
|
173
|
+
| status | string | `"ok"` when healthy |
|
|
174
|
+
| timestamp | number | Unix time (ms) |
|
|
175
|
+
| uptime | number | Uptime in seconds |
|
|
176
|
+
| version | string | Server version |
|
|
177
|
+
| platform | string | `darwin` / `linux` / `win32` |
|
|
178
|
+
| nodeVersion | string | Node.js version |
|
|
179
|
+
| pid | number | Process ID |
|
|
180
|
+
| memory | object | Memory usage (MB) |
|
|
181
|
+
| env | string | Active environment name |
|
|
190
182
|
|
|
191
|
-
##
|
|
183
|
+
## Cross-platform notes
|
|
192
184
|
|
|
193
185
|
### Windows
|
|
194
186
|
|
|
195
|
-
- PID
|
|
196
|
-
-
|
|
197
|
-
-
|
|
187
|
+
- PID file under `%TEMP%\nuwax-file-server\`
|
|
188
|
+
- Stop uses `taskkill /F /PID`
|
|
189
|
+
- Paths use backslashes `\`
|
|
198
190
|
|
|
199
|
-
### Linux/macOS
|
|
191
|
+
### Linux / macOS
|
|
200
192
|
|
|
201
|
-
- PID
|
|
202
|
-
-
|
|
203
|
-
-
|
|
193
|
+
- PID file under `/tmp/nuwax-file-server/`
|
|
194
|
+
- Stop uses signals (SIGTERM / SIGKILL)
|
|
195
|
+
- Paths use `/`
|
|
204
196
|
|
|
205
|
-
###
|
|
197
|
+
### General
|
|
206
198
|
|
|
207
|
-
-
|
|
208
|
-
-
|
|
209
|
-
-
|
|
210
|
-
-
|
|
199
|
+
- Paths built with `path.join()`
|
|
200
|
+
- Temp dir from `os.tmpdir()`
|
|
201
|
+
- Shell commands via `cross-spawn`
|
|
202
|
+
- Process trees via `tree-kill`
|
|
211
203
|
|
|
212
|
-
## pnpm
|
|
204
|
+
## pnpm disk usage
|
|
213
205
|
|
|
214
|
-
|
|
206
|
+
Created, uploaded, or copied projects get an optimized `.npmrc` to reduce pnpm disk footprint.
|
|
215
207
|
|
|
216
|
-
###
|
|
208
|
+
### Automatic injection
|
|
217
209
|
|
|
218
|
-
|
|
210
|
+
`.npmrc` is applied when:
|
|
219
211
|
|
|
220
|
-
-
|
|
221
|
-
-
|
|
222
|
-
-
|
|
212
|
+
- **Create project** (`/create-project`)
|
|
213
|
+
- **Upload project** (`/upload-project`)
|
|
214
|
+
- **Copy project** (`/copy-project`)
|
|
223
215
|
|
|
224
|
-
###
|
|
216
|
+
### Inspect disk usage
|
|
225
217
|
|
|
226
218
|
```bash
|
|
227
|
-
# 自动检测当前环境配置
|
|
228
219
|
npm run pnpm:check
|
|
229
220
|
|
|
230
|
-
#
|
|
231
|
-
npm run pnpm:check:
|
|
232
|
-
npm run pnpm:check:
|
|
233
|
-
npm run pnpm:check:test # 测试环境
|
|
221
|
+
npm run pnpm:check:dev # development
|
|
222
|
+
npm run pnpm:check:prod # production
|
|
223
|
+
npm run pnpm:check:test # test
|
|
234
224
|
|
|
235
|
-
# 或手动指定目录
|
|
236
225
|
bash scripts/pnpm-check.sh /path/to/projects
|
|
237
226
|
```
|
|
238
227
|
|
|
239
|
-
###
|
|
228
|
+
### Prune unused packages
|
|
240
229
|
|
|
241
230
|
```bash
|
|
242
|
-
# 立即清理
|
|
243
231
|
npm run pnpm:prune
|
|
244
232
|
|
|
245
|
-
# 查看日志的清理(推荐)
|
|
246
233
|
npm run pnpm:prune:log
|
|
247
234
|
```
|
|
248
235
|
|
|
249
|
-
###
|
|
236
|
+
### Scheduled prune (built-in)
|
|
250
237
|
|
|
251
|
-
|
|
238
|
+
The app can run a cron-style prune job. Configure with env vars, for example:
|
|
252
239
|
|
|
253
240
|
```yaml
|
|
254
|
-
# docker-compose.yml
|
|
241
|
+
# docker-compose.yml or .env
|
|
255
242
|
environment:
|
|
256
|
-
PNPM_PRUNE_ENABLED: "true"
|
|
257
|
-
PNPM_PRUNE_SCHEDULE: "0 2 * * 0"
|
|
258
|
-
PNPM_PRUNE_TIMEZONE: "Asia/Shanghai"
|
|
259
|
-
PNPM_PRUNE_RUN_ON_START: "false"
|
|
243
|
+
PNPM_PRUNE_ENABLED: "true"
|
|
244
|
+
PNPM_PRUNE_SCHEDULE: "0 2 * * 0"
|
|
245
|
+
PNPM_PRUNE_TIMEZONE: "Asia/Shanghai"
|
|
246
|
+
PNPM_PRUNE_RUN_ON_START: "false"
|
|
260
247
|
```
|
|
261
248
|
|
|
262
|
-
|
|
249
|
+
**Example schedules:**
|
|
263
250
|
|
|
264
251
|
```bash
|
|
265
|
-
"0 2 * * 0" #
|
|
266
|
-
"0 3 * * *" #
|
|
267
|
-
"0 2 1 * *" #
|
|
268
|
-
"0 */6 * * *" #
|
|
252
|
+
"0 2 * * 0" # Sunday 02:00
|
|
253
|
+
"0 3 * * *" # Daily 03:00
|
|
254
|
+
"0 2 1 * *" # 1st of month 02:00
|
|
255
|
+
"0 */6 * * *" # Every 6 hours
|
|
269
256
|
```
|
|
270
257
|
|
|
271
|
-
###
|
|
258
|
+
### Expected benefits
|
|
272
259
|
|
|
273
|
-
-
|
|
274
|
-
-
|
|
275
|
-
-
|
|
276
|
-
- 定期清理,保持 store 整洁
|
|
260
|
+
- Lower disk use when many projects share dependencies (often a large share of savings vs naive installs)
|
|
261
|
+
- Faster installs when using a nearby registry mirror
|
|
262
|
+
- Automated `.npmrc`; periodic store maintenance when enabled
|
|
277
263
|
|
|
278
|
-
##
|
|
264
|
+
## Troubleshooting
|
|
279
265
|
|
|
280
|
-
###
|
|
266
|
+
### Server will not start
|
|
281
267
|
|
|
282
|
-
1.
|
|
283
|
-
2.
|
|
284
|
-
3.
|
|
268
|
+
1. Check the port is free
|
|
269
|
+
2. Check log directory permissions
|
|
270
|
+
3. Confirm env files exist
|
|
285
271
|
|
|
286
272
|
```bash
|
|
287
|
-
# 查看详细日志
|
|
288
273
|
nuwax-file-server start --env development
|
|
289
274
|
```
|
|
290
275
|
|
|
291
|
-
###
|
|
276
|
+
### Server will not stop
|
|
292
277
|
|
|
293
278
|
```bash
|
|
294
|
-
# 使用强制停止
|
|
295
279
|
nuwax-file-server stop --force
|
|
296
280
|
|
|
297
|
-
# 手动查找并停止进程
|
|
298
281
|
ps aux | grep nuwax-file-server
|
|
299
282
|
kill -9 <pid>
|
|
300
283
|
```
|
|
301
284
|
|
|
302
|
-
###
|
|
285
|
+
### Health check fails
|
|
303
286
|
|
|
304
|
-
1.
|
|
305
|
-
2.
|
|
306
|
-
3.
|
|
287
|
+
1. Confirm the process is running
|
|
288
|
+
2. Confirm host/port
|
|
289
|
+
3. Check firewall rules
|
|
307
290
|
|
|
308
291
|
```bash
|
|
309
|
-
# 查看服务状态
|
|
310
292
|
nuwax-file-server status
|
|
311
|
-
|
|
312
|
-
# 测试健康检查
|
|
313
293
|
curl http://localhost:60000/health
|
|
314
294
|
```
|
|
315
295
|
|
|
316
|
-
##
|
|
296
|
+
## Development
|
|
317
297
|
|
|
318
|
-
###
|
|
298
|
+
### Adding a command
|
|
319
299
|
|
|
320
|
-
|
|
300
|
+
In `src/cli.js`, use Commander:
|
|
321
301
|
|
|
322
302
|
```javascript
|
|
323
303
|
program
|
|
324
304
|
.command("newcommand")
|
|
325
|
-
.description("
|
|
326
|
-
.option("--option", "
|
|
305
|
+
.description("Description of the new command")
|
|
306
|
+
.option("--option", "Option description")
|
|
327
307
|
.action((options) => {
|
|
328
|
-
//
|
|
308
|
+
// handler
|
|
329
309
|
});
|
|
330
310
|
```
|
|
331
311
|
|
|
332
|
-
###
|
|
312
|
+
### Adding a setting
|
|
333
313
|
|
|
334
|
-
1.
|
|
335
|
-
2.
|
|
336
|
-
3.
|
|
314
|
+
1. Add variables to `src/env.development` / `src/env.production` / `src/env.test`
|
|
315
|
+
2. Wire them through `src/appConfig/index.js` as needed
|
|
316
|
+
3. Document the change
|
|
337
317
|
|
|
338
|
-
##
|
|
318
|
+
## License
|
|
339
319
|
|
|
340
320
|
ISC
|
package/dist/appConfig/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"path";import n from"fs";import o from"os";import{fileURLToPath as L}from"url";import r from"dotenv";const T=e.dirname(L(import.meta.url));r.config();function O(){const E=process.env.LOG_BASE_DIR,_=e.join(o.tmpdir(),"nuwax-file-server","project_logs");if(!E)return _;try{return n.mkdirSync(E,{recursive:!0}),E}catch{try{n.mkdirSync(_,{recursive:!0})}catch{}return _}}const I=process.env.NODE_ENV||"development";function p(E){const _=e.join(T,"..",`env.${E}`);if(n.existsSync(_))r.config({path:_}),console.log(`Environment configuration file env.${E} loaded`);else{const s=`Environment configuration file env.${E} does not exist, please create the corresponding environment configuration file and try again`;throw console.error(s),new Error(s)}}p(I);const R={NODE_ENV:I,PORT:parseInt(process.env.PORT),INIT_PROJECT_NAME:process.env.INIT_PROJECT_NAME,INIT_PROJECT_DIR:process.env.INIT_PROJECT_DIR,PROJECT_SOURCE_DIR:process.env.PROJECT_SOURCE_DIR,DIST_TARGET_DIR:process.env.DIST_TARGET_DIR,UPLOAD_PROJECT_DIR:process.env.UPLOAD_PROJECT_DIR,MAX_BUILD_CONCURRENCY:process.env.MAX_BUILD_CONCURRENCY?parseInt(process.env.MAX_BUILD_CONCURRENCY,10):void 0,MAX_INLINE_FILE_SIZE_BYTES:process.env.MAX_INLINE_FILE_SIZE_BYTES?parseInt(process.env.MAX_INLINE_FILE_SIZE_BYTES,10):void 0,UPLOAD_MAX_FILE_SIZE_BYTES:process.env.UPLOAD_MAX_FILE_SIZE_BYTES?parseInt(process.env.UPLOAD_MAX_FILE_SIZE_BYTES,10):void 0,UPLOAD_ALLOWED_EXTENSIONS:process.env.UPLOAD_ALLOWED_EXTENSIONS?process.env.UPLOAD_ALLOWED_EXTENSIONS.split(",").map(E=>E.trim().toLowerCase()).filter(Boolean):[],UPLOAD_SINGLE_FILE_SIZE_BYTES:process.env.UPLOAD_SINGLE_FILE_SIZE_BYTES?parseInt(process.env.UPLOAD_SINGLE_FILE_SIZE_BYTES,10):void 0,DOWNLOAD_MAX_FILE_SIZE_BYTES:process.env.DOWNLOAD_MAX_FILE_SIZE_BYTES?parseInt(process.env.DOWNLOAD_MAX_FILE_SIZE_BYTES,10):void 0,REQUEST_BODY_LIMIT:process.env.REQUEST_BODY_LIMIT,TRAVERSE_EXCLUDE_DIRS:process.env.TRAVERSE_EXCLUDE_DIRS?process.env.TRAVERSE_EXCLUDE_DIRS.split(",").map(E=>E.trim()).filter(Boolean):[],BACKUP_TRAVERSE_EXCLUDE_FILES:process.env.BACKUP_TRAVERSE_EXCLUDE_FILES?process.env.BACKUP_TRAVERSE_EXCLUDE_FILES.split(",").map(E=>E.trim()).filter(Boolean):[],CONTENT_TRAVERSE_EXCLUDE_FILES:process.env.CONTENT_TRAVERSE_EXCLUDE_FILES?process.env.CONTENT_TRAVERSE_EXCLUDE_FILES.split(",").map(E=>E.trim()).filter(Boolean):[],INLINE_IMAGE_EXTENSIONS:process.env.INLINE_IMAGE_EXTENSIONS?process.env.INLINE_IMAGE_EXTENSIONS.split(",").map(E=>E.trim().toLowerCase()).filter(Boolean):[],TOP_LEVEL_NOISE_PATTERNS:process.env.TOP_LEVEL_NOISE_PATTERNS?process.env.TOP_LEVEL_NOISE_PATTERNS.split(",").map(E=>E.trim()).filter(Boolean):[],LOG_BASE_DIR:O(),LOG_LEVEL:process.env.LOG_LEVEL?process.env.LOG_LEVEL.toLowerCase():void 0,LOG_PREFIX_API:process.env.LOG_PREFIX_API,LOG_PREFIX_BUILD:process.env.LOG_PREFIX_BUILD,LOG_CONSOLE_ENABLED:typeof process.env.LOG_CONSOLE_ENABLED=="string"?process.env.LOG_CONSOLE_ENABLED.toLowerCase()==="true":void 0,LOG_CACHE_ENABLED:typeof process.env.LOG_CACHE_ENABLED=="string"?process.env.LOG_CACHE_ENABLED.toLowerCase()==="true":void 0,LOG_CACHE_DURATION:process.env.LOG_CACHE_DURATION?parseInt(process.env.LOG_CACHE_DURATION,10):void 0,LOG_CACHE_MAX_ENTRIES:process.env.LOG_CACHE_MAX_ENTRIES?parseInt(process.env.LOG_CACHE_MAX_ENTRIES,10):void 0,LOG_CACHE_MAX_FILE_SIZE:process.env.LOG_CACHE_MAX_FILE_SIZE?parseInt(process.env.LOG_CACHE_MAX_FILE_SIZE,10):void 0,DEV_SERVER_PORT_TIMEOUT:process.env.DEV_SERVER_PORT_TIMEOUT?parseInt(process.env.DEV_SERVER_PORT_TIMEOUT,10):void 0,DEV_SERVER_STOP_TIMEOUT:process.env.DEV_SERVER_STOP_TIMEOUT?parseInt(process.env.DEV_SERVER_STOP_TIMEOUT,10):void 0,DEV_SERVER_STOP_CHECK_INTERVAL:process.env.DEV_SERVER_STOP_CHECK_INTERVAL?parseInt(process.env.DEV_SERVER_STOP_CHECK_INTERVAL,10):void 0,DEV_SERVER_STOP_MAX_ATTEMPTS:process.env.DEV_SERVER_STOP_MAX_ATTEMPTS?parseInt(process.env.DEV_SERVER_STOP_MAX_ATTEMPTS,10):void 0,COMPUTER_WORKSPACE_DIR:process.env.COMPUTER_WORKSPACE_DIR,COMPUTER_LOG_DIR:process.env.COMPUTER_LOG_DIR,CLI_SERVICE_NAME:"nuwax-file-server",CLI_PID_DIR:process.env.CLI_PID_DIR||(process.platform==="win32"?e.join(process.env.TEMP||"","nuwax-file-server"):e.join("/tmp","nuwax-file-server")),CLI_PID_FILE:"server.pid",CLI_STOP_TIMEOUT:process.env.CLI_STOP_TIMEOUT?parseInt(process.env.CLI_STOP_TIMEOUT,10):3e4,CLI_CHECK_INTERVAL:process.env.CLI_CHECK_INTERVAL?parseInt(process.env.CLI_CHECK_INTERVAL,10):500,CLI_LOG_DIR:process.env.CLI_LOG_DIR||(process.platform==="win32"?e.join(process.env.TEMP||"","nuwax-file-server","logs"):e.join("/tmp","nuwax-file-server","logs")),CLI_IS_WINDOWS:process.platform==="win32"};export default R;
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
2
|
+
import{Command as C}from"commander";import S from"path";import x from"os";import m from"fs-extra";import{spawn as D}from"cross-spawn";import{fileURLToPath as T}from"url";import{createRequire as N}from"module";var U=S.dirname(T(import.meta.url)),K=N(import.meta.url),R="1.2.6",a=new C,v={name:"nuwax-file-server",pidDir:S.join(x.tmpdir(),"nuwax-file-server"),logDir:S.join(x.tmpdir(),"nuwax-file-server","logs"),pidFile:S.join(x.tmpdir(),"nuwax-file-server","server.pid")},f={reset:"\x1B[0m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",cyan:"\x1B[36m"};function l(e,o="reset"){console.log(`${f[o]}${e}${f.reset}`)}function d(e){console.error(`${f.red}ERROR: ${e}${f.reset}`)}function r(e){console.log(`${f.green}${e}${f.reset}`)}function n(e){console.log(`${f.blue}${e}${f.reset}`)}function $(){return v.pidFile}function E(){try{let e=$();if(m.existsSync(e)){let o=m.readFileSync(e,"utf8");return JSON.parse(o)}}catch{}return null}function L(e){let o=S.dirname($());m.ensureDirSync(o),m.writeFileSync($(),JSON.stringify(e,null,2))}function I(){let e=$();m.existsSync(e)&&m.removeSync(e)}function h(e){try{return process.kill(e,0),!0}catch(o){return o.code==="ESRCH"||o.code==="EPERM",!1}}async function _(e,o=!1){return new Promise(t=>{if(process.platform==="win32"){let i=o?["/F","/PID",String(e)]:["/PID",String(e)],s=D("taskkill",i,{stdio:"pipe"});s.on("error",c=>{d(`Stop process failed: ${c.message}`),t(!1)}),s.on("close",c=>{c===0?(r(`Process ${e} stopped`),t(!0)):o?D("taskkill",["/F","/PID",String(e)],{stdio:"pipe"}).on("close",u=>{t(u===0)}):t(!1)})}else try{process.kill(-e,o?"SIGKILL":"SIGTERM"),r(`Process group ${e} stopped`),t(!0)}catch(i){if(i.code==="ESRCH")r(`Process ${e} does not exist, already stopped`),t(!0);else try{process.kill(e,o?"SIGKILL":"SIGTERM"),r(`Process ${e} stopped`),t(!0)}catch(s){s.code==="ESRCH"?(r(`Process ${e} does not exist, already stopped`),t(!0)):(d(`Stop process failed: ${s.message}`),t(!1))}}})}async function F(e){let{env:o,port:t,config:g}=e,i=new Set(["env","port","config","force","help","version"]);process.argv.slice(2).forEach(p=>{if(p.startsWith("--")&&p.includes("=")){let b=p.indexOf("="),P=p.slice(2,b);if(!i.has(P)){let O=p.slice(b+1);process.env[P]=O,n(`CLI parameter overrides environment variable: ${P}=${O}`)}}}),n(`Start ${v.name} service...`);let s=E();s&&h(s.pid)&&(d(`Service is already running (PID: ${s.pid})`),n("Please use 'nuwax-file-server stop' to stop the existing service before trying again"),process.exit(1));let c=o||"production";process.env.NODE_ENV=c,n(`Use environment: ${c}`),t&&(process.env.PORT=t,n(`Use port: ${t}`)),g&&(process.env.CONFIG_FILE=g,n(`Use configuration file: ${g}`)),m.ensureDirSync(v.logDir);let w=S.join(U,"server.js"),u=D("node",[w],{env:{...process.env,NODE_ENV:c},stdio:"inherit",detached:!0,cwd:process.cwd(),windowsHide:!0});u.on("error",p=>{d(`Start service failed: ${p.message}`),process.exit(1)}),await new Promise(p=>setTimeout(p,2e3)),h(u.pid)||(d("Start service failed"),process.exit(1));let y={pid:u.pid,startedAt:new Date().toISOString(),env:o||"production",port:t||process.env.PORT||"60000",version:R,platform:process.platform};L(y),u.unref(),r(`Service started (PID: ${u.pid})`),l(`Service running on: http://localhost:${y.port}`,"cyan"),l(`Environment: ${y.env}`,"cyan"),l(`Platform: ${y.platform}`,"cyan"),l(`PID file: ${$()}`,"cyan")}async function k(e){let{force:o}=e;n(`Stop ${v.name} service...`);let t=E();t||(d("Service not found"),n("Service may not be running or PID file has been lost"),process.exit(0)),h(t.pid)||(n("Service process has stopped, clean PID file..."),I(),r("Service has stopped"),process.exit(0)),await _(t.pid,o)&&(await new Promise(s=>setTimeout(s,1e3)),h(t.pid)||(I(),r("Service has stopped"),process.exit(0))),o&&(d("Force stop failed, please stop the process manually"),process.exit(1)),n("Try to force stop..."),await _(t.pid,!0)&&(await new Promise(s=>setTimeout(s,1e3)),h(t.pid)||(I(),r("Service has been forced stopped"),process.exit(0))),d("Stop service failed"),process.exit(1)}async function V(e){l(`Restart ${v.name} service...`,"yellow"),n("Stop existing service...");try{await k({force:!1})}catch{n("Service not running or has stopped")}await new Promise(o=>setTimeout(o,2e3)),n("Start service..."),await F(e),r("Service has been restarted")}function j(){n(`${v.name} service status:`);let e=E();e||(l("Service not running","yellow"),process.exit(0));let o=h(e.pid);if(console.log(""),console.log(` Service name: ${v.name}`),console.log(` Running status: ${o?"Running":"Stopped"}`),console.log(` Process ID: ${e.pid}`),console.log(` Environment: ${e.env||"production"}`),console.log(` Port: ${e.port||"60000"}`),console.log(` Version: ${e.version||R}`),console.log(` Platform: ${e.platform||process.platform}`),console.log(` Started at: ${e.startedAt||"Unknown"}`),e.startedAt){let t=new Date(e.startedAt),i=Math.floor((new Date-t)/1e3),s=Math.floor(i/3600),c=Math.floor(i%3600/60),w=i%60;console.log(` Uptime: ${s} hours ${c} minutes ${w} seconds`)}console.log(` PID file: ${$()}`),console.log(""),o?l("Service running normally","green"):(l("Warning: Service process does not exist, but PID file still exists","yellow"),n("Suggest executing stop command to clean up"))}function A(){a.name("nuwax-file-server").description("Cross-platform file service deployment tool, supporting start/stop/restart/status").version(R,"-v, --version","Display version number").helpOption("-h, --help","Display help information"),a.command("start").allowUnknownOption().description("Start service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").action(F),a.command("stop").description("Stop service").option("--force","Force stop").action(k),a.command("restart").allowUnknownOption().description("Restart service").option("--env <environment>","\u73AF\u5883: development|production|test","production").option("--port <port>","Service port").option("--config <path>","Custom configuration file path").action(V),a.command("status").description("View service status").action(j),a.command("help").description("Display help information").action(()=>{a.outputHelp()}),a.parse(process.argv),process.argv.slice(2).length||(a.outputHelp(),process.exit(0))}A();
|
package/dist/config/swagger.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"swagger-jsdoc";import e from"../appConfig/index.js";const s={definition:{openapi:"3.0.0",info:{title:"Application Builder API",version:"1.0.0",description:"
|
|
1
|
+
import t from"swagger-jsdoc";import e from"../appConfig/index.js";const s={definition:{openapi:"3.0.0",info:{title:"Application Builder API",version:"1.0.0",description:"Application builder API documentation",contact:{name:"API Support"}},servers:[{url:`http://localhost:${e.PORT}`,description:`${e.NODE_ENV} environment`}],tags:[{name:"Build",description:"Build related interfaces"},{name:"Project",description:"Project management interfaces"},{name:"Code",description:"Code submission interfaces"}],components:{schemas:{Error:{type:"object",properties:{success:{type:"boolean",example:!1},error:{type:"object",properties:{type:{type:"string",example:"VALIDATION_ERROR"},message:{type:"string",example:"Project ID cannot be empty"},timestamp:{type:"string",format:"date-time"},requestId:{type:"string"},details:{type:"object"}}}}},Success:{type:"object",properties:{success:{type:"boolean",example:!0},message:{type:"string"}}}}}},apis:["./src/config/swagger/*.js"]},o=t(s);export default o;
|
package/dist/env.development
CHANGED
package/dist/env.production
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import l from"express";import{startDevServer as
|
|
1
|
+
import l from"express";import{startDevServer as m}from"../utils/build/startDevUtils.js";import{restartDevServer as h}from"../utils/build/restartDevUtils.js";import{keepAliveDevServer as u}from"../utils/build/keepAliveDevUtils.js";import{stopDevServer as f}from"../utils/build/stopDevUtils.js";import{buildProject as g}from"../utils/build/buildProjectUtils.js";import{listRunningProcesses as j}from"../utils/build/processManager.js";import y from"../utils/error/buildErrorParser.js";import{getDevLog as w}from"../utils/log/getDevLogUtils.js";import d from"../utils/log/logCacheManager.js";import I from"../utils/buildArg/portPool.js";import{ValidationError as s,asyncHandler as c}from"../utils/error/errorHandler.js";const p=l.Router(),b=[{path:"/start-dev",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});t.setTimeout(6e5),r.setTimeout(6e5);const o=await m(t,String(e));r.json(o)})},{path:"/keep-alive",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId,o=t.query.pid,a=t.query.port,n=t.query.basePath;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});if(!o)throw new s("Process ID cannot be empty",{field:"pid"});if(!a)throw new s("Port cannot be empty",{field:"port"});if(!n)throw new s("basePath cannot be empty",{field:"basePath"});const i=await u(t,String(e),o,a,n);r.json(i)})},{path:"/build",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});t.setTimeout(6e5),r.setTimeout(6e5);const o=await g(t,String(e));r.json(o)})},{path:"/stop-dev",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId,o=t.query.pid;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});if(!o)throw new s("Process ID cannot be empty",{field:"pid"});const a=await f(t,String(e),o,{strict:!0});r.json(a)})},{path:"/restart-dev",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});t.setTimeout(6e5),r.setTimeout(6e5);const o=await h(t,String(e));r.json(o)})},{path:"/list-dev",method:"get",handler:(t,r)=>{const o={success:!0,list:j()};r.json(o)}},{path:"/parse-build-error",method:"post",handler:c(async(t,r)=>{const{projectId:e,errorMessage:o}=t.body;if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});if(!o)throw new s("Error message cannot be empty",{field:"errorMessage"});const n=new y().parseBuildError(o,String(e));r.json({success:!0,message:n})})},{path:"/get-dev-log",method:"get",handler:c(async(t,r)=>{const e=t.query.projectId,o=t.query.startIndex,a=t.query.logType||"temp";if(!e)throw new s("Project ID cannot be empty",{field:"projectId"});const n=o?parseInt(o,10):1;if(isNaN(n)||n<1)throw new s("Start index must be a positive integer (starting from 1)",{field:"startIndex",value:o});const i=await w(String(e),n,a);r.json(i)})},{path:"/get-log-cache-stats",method:"get",handler:(t,r)=>{const e=d.getStats();r.json({success:!0,message:"Get log cache statistics successfully",stats:e})}},{path:"/clear-all-log-cache",method:"get",handler:(t,r)=>{d.clear(),r.json({success:!0,message:"All log caches have been cleared"})}},{path:"/port-pool-status",method:"get",handler:(t,r)=>{const e=I.getStatus();r.json({success:!0,message:"Get port pool status successfully",...e})}}];b.forEach(t=>{p[t.method](t.path,t.handler)});export default p;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import u from"express";import h from"multer";import{asyncHandler as c,ValidationError as a}from"../utils/error/errorHandler.js";import m from"../service/codeService.js";import{log as l}from"../utils/log/logUtils.js";import b from"../appConfig/index.js";const p=u.Router(),g=h({storage:h.memoryStorage(),limits:{fileSize:b.UPLOAD_SINGLE_FILE_SIZE_BYTES}}),w=[{path:"/specified-files-update",method:"post",handler:c(async(t,s)=>{const{projectId:o,codeVersion:n,files:e}=t.body||{};l(o,"INFO","Partial files update",{projectId:o,codeVersion:n,filesCount:e?e.length:0}),e&&Array.isArray(e)&&e.forEach(r=>{if(r&&typeof r.contents=="string"&&r.contents)try{r.contents=decodeURIComponent(r.contents)}catch(f){l(o,"WARN","Decode file content failed",{fileName:r.path,error:f.message})}});const i=await m.specifiedFilesUpdate(String(o),String(n),e,t);s.status(200).json(i)})},{path:"/all-files-update",method:"post",handler:c(async(t,s)=>{const{projectId:o,codeVersion:n,files:e,basePath:i,pid:r}=t.body||{};if(l(o,"INFO","Submit files",{projectId:o,codeVersion:n,basePath:i,pid:r}),!o)throw new a("Project ID cannot be empty",{field:"projectId"});if(n==null)throw new a("codeVersion cannot be empty",{field:"codeVersion"});if(!Array.isArray(e))throw new a("files must be an array",{field:"files"});e&&Array.isArray(e)&&e.forEach(d=>{if(d&&typeof d.contents=="string"&&d.contents)try{d.contents=decodeURIComponent(d.contents)}catch(y){l(o,"WARN","Decode file content failed",{fileName:d.name,error:y.message})}});const f=await m.allFilesUpdate(String(o),String(n),e,t);s.status(200).json(f)})},{path:"/upload-single-file",method:"post",middleware:g.single("file"),handler:c(async(t,s)=>{const{projectId:o,codeVersion:n,filePath:e}=t.body||{},i=t.file;if(l(o,"INFO","\u4E0A\u4F20\u5355\u4E2A\u6587\u4EF6",{projectId:o,codeVersion:n,filePath:e}),!o)throw new a("Project ID cannot be empty",{field:"projectId"});if(n==null)throw new a("codeVersion cannot be empty",{field:"codeVersion"});if(!i)throw new a("File cannot be empty",{field:"file"});if(!e||typeof e!="string")throw new a("File path cannot be empty",{field:"filePath"});l(o,"INFO","Received file information",{originalname:i.originalname,mimetype:i.mimetype,size:i.size,bufferLength:i.buffer?i.buffer.length:0,bufferIsBuffer:Buffer.isBuffer(i.buffer)});const r={buffer:i.buffer,originalname:i.originalname,mimetype:i.mimetype,size:i.size},f=await m.uploadSingleFile(String(o),String(n),r,e,t);s.status(200).json(f)})},{path:"/rollback-version",method:"post",handler:c(async(t,s)=>{const{projectId:o,codeVersion:n,rollbackTo:e}=t.body||{};if(l(o,"INFO","Rollback version",{projectId:o,codeVersion:n,rollbackTo:e}),!o)throw new a("Project ID cannot be empty",{field:"projectId"});if(n==null)throw new a("codeVersion cannot be empty",{field:"codeVersion"});if(e==null)throw new a("rollbackTo cannot be empty",{field:"rollbackTo"});const i=await m.rollbackVersion(String(o),String(n),String(e),t);s.status(200).json(i)})}];w.forEach(t=>{t.middleware?p[t.method](t.path,t.middleware,t.handler):p[t.method](t.path,t.handler)});export default p;
|