coding-tool-x 3.6.6 → 3.6.8
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/CHANGELOG.md +7 -0
- package/dist/web/assets/{Analytics-CcGKjDkP.js → Analytics-C57ZRDq5.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-DPOa1w5D.js → ConfigTemplates-B3qqqL05.js} +1 -1
- package/dist/web/assets/Home-CG5XrTNc.js +1 -0
- package/dist/web/assets/Home-CIua-b-o.css +1 -0
- package/dist/web/assets/{PluginManager-BVbHUdey.js → PluginManager-BhX0LUzr.js} +1 -1
- package/dist/web/assets/{ProjectList-BQrz2FKo.js → ProjectList-BQ01OZn9.js} +1 -1
- package/dist/web/assets/{SessionList-CRGer64T.js → SessionList-DPv2IOXG.js} +1 -1
- package/dist/web/assets/{SkillManager-BhJKtWYM.js → SkillManager-D5CfQm2O.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-pc6tpF3m.js → WorkspaceManager-Ce8ggteK.js} +1 -1
- package/dist/web/assets/index-CpnFNWqC.js +2 -0
- package/dist/web/assets/index-DJ9VFidd.css +1 -0
- package/dist/web/assets/{naive-ui-DM897mIP.js → naive-ui-kcWDeJwl.js} +1 -1
- package/dist/web/index.html +3 -3
- package/package.json +1 -1
- package/src/commands/stats.js +1 -1
- package/src/config/channel-preset-websites.js +2 -1
- package/src/config/paths.js +8 -0
- package/src/server/api/agents.js +16 -54
- package/src/server/api/claude-hooks.js +1 -1
- package/src/server/api/claude-statistics.js +57 -0
- package/src/server/api/commands.js +16 -54
- package/src/server/api/dashboard.js +2 -2
- package/src/server/api/gemini-channels.js +2 -0
- package/src/server/api/hooks.js +4 -1
- package/src/server/api/plugins.js +40 -65
- package/src/server/api/skills.js +21 -77
- package/src/server/api/validation-errors.js +34 -0
- package/src/server/gemini-proxy-server.js +205 -21
- package/src/server/index.js +1 -0
- package/src/server/services/agents-service.js +166 -75
- package/src/server/services/base/base-channel-service.js +15 -0
- package/src/server/services/base/proxy-utils.js +6 -3
- package/src/server/services/base/response-usage-parser.js +44 -0
- package/src/server/services/channel-balance.js +86 -1
- package/src/server/services/claude-statistics-service.js +139 -0
- package/src/server/services/commands-service.js +203 -121
- package/src/server/services/config-artifact-paths.js +116 -0
- package/src/server/services/config-export-service.js +7 -6
- package/src/server/services/config-registry-service.js +2 -2
- package/src/server/services/config-sync-manager.js +45 -11
- package/src/server/services/config-templates-service.js +21 -19
- package/src/server/services/format-converter.js +42 -4
- package/src/server/services/gemini-channels.js +30 -1
- package/src/server/services/gemini-sessions.js +347 -61
- package/src/server/services/mcp-client.js +236 -49
- package/src/server/services/mcp-service.js +51 -64
- package/src/server/services/notification-hooks.js +659 -88
- package/src/server/services/opencode-channels.js +15 -0
- package/src/server/services/plugins-service.js +771 -63
- package/src/server/services/repo-scanner-base.js +6 -29
- package/src/server/services/skill-service.js +187 -63
- package/dist/web/assets/Home-BP1LxGtp.js +0 -1
- package/dist/web/assets/Home-BeGkC4bb.css +0 -1
- package/dist/web/assets/index-0isNzXNY.css +0 -1
- package/dist/web/assets/index-BsdIJwLf.js +0 -2
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
const express = require('express');
|
|
8
8
|
const { PluginsService } = require('../services/plugins-service');
|
|
9
9
|
const { maskToken } = require('../services/oauth-utils');
|
|
10
|
+
const { sendApiError } = require('./validation-errors');
|
|
10
11
|
|
|
11
12
|
const router = express.Router();
|
|
12
|
-
const SUPPORTED_PLATFORMS = ['claude', 'opencode'];
|
|
13
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
13
14
|
const pluginServices = new Map();
|
|
14
15
|
|
|
15
16
|
function resolvePlatform(rawPlatform) {
|
|
@@ -63,6 +64,28 @@ function sanitizeRepos(service, repos = []) {
|
|
|
63
64
|
return (Array.isArray(repos) ? repos : []).map(sanitizeRepo);
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
/**
|
|
68
|
+
* 获取平台插件能力
|
|
69
|
+
* GET /api/plugins/capabilities
|
|
70
|
+
*/
|
|
71
|
+
router.get('/capabilities', (req, res) => {
|
|
72
|
+
try {
|
|
73
|
+
const { platform, service } = getPluginsService(req);
|
|
74
|
+
const capabilities = typeof service.getCapabilities === 'function'
|
|
75
|
+
? service.getCapabilities()
|
|
76
|
+
: { platform, supportsPlugins: true };
|
|
77
|
+
|
|
78
|
+
res.json({
|
|
79
|
+
success: true,
|
|
80
|
+
platform,
|
|
81
|
+
capabilities
|
|
82
|
+
});
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error('[Plugins API] Get capabilities error:', err);
|
|
85
|
+
sendApiError(res, err);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
66
89
|
/**
|
|
67
90
|
* 获取插件列表
|
|
68
91
|
* GET /api/plugins
|
|
@@ -79,10 +102,7 @@ router.get('/', (req, res) => {
|
|
|
79
102
|
});
|
|
80
103
|
} catch (err) {
|
|
81
104
|
console.error('[Plugins API] List plugins error:', err);
|
|
82
|
-
res
|
|
83
|
-
success: false,
|
|
84
|
-
message: err.message
|
|
85
|
-
});
|
|
105
|
+
sendApiError(res, err);
|
|
86
106
|
}
|
|
87
107
|
});
|
|
88
108
|
|
|
@@ -107,10 +127,7 @@ router.get('/market', async (req, res) => {
|
|
|
107
127
|
});
|
|
108
128
|
} catch (err) {
|
|
109
129
|
console.error('[Plugins API] Get market plugins error:', err);
|
|
110
|
-
res
|
|
111
|
-
success: false,
|
|
112
|
-
message: err.message
|
|
113
|
-
});
|
|
130
|
+
sendApiError(res, err);
|
|
114
131
|
}
|
|
115
132
|
});
|
|
116
133
|
|
|
@@ -164,10 +181,7 @@ router.post('/install', async (req, res) => {
|
|
|
164
181
|
});
|
|
165
182
|
} catch (err) {
|
|
166
183
|
console.error('[Plugins API] Install plugin error:', err);
|
|
167
|
-
res
|
|
168
|
-
success: false,
|
|
169
|
-
message: err.message
|
|
170
|
-
});
|
|
184
|
+
sendApiError(res, err);
|
|
171
185
|
}
|
|
172
186
|
});
|
|
173
187
|
|
|
@@ -188,10 +202,7 @@ router.get('/repos', (req, res) => {
|
|
|
188
202
|
});
|
|
189
203
|
} catch (err) {
|
|
190
204
|
console.error('[Plugins API] Get repos error:', err);
|
|
191
|
-
res
|
|
192
|
-
success: false,
|
|
193
|
-
message: err.message
|
|
194
|
-
});
|
|
205
|
+
sendApiError(res, err);
|
|
195
206
|
}
|
|
196
207
|
});
|
|
197
208
|
|
|
@@ -223,10 +234,7 @@ router.post('/repos', (req, res) => {
|
|
|
223
234
|
});
|
|
224
235
|
} catch (err) {
|
|
225
236
|
console.error('[Plugins API] Add repo error:', err);
|
|
226
|
-
res
|
|
227
|
-
success: false,
|
|
228
|
-
message: err.message
|
|
229
|
-
});
|
|
237
|
+
sendApiError(res, err);
|
|
230
238
|
}
|
|
231
239
|
});
|
|
232
240
|
|
|
@@ -243,10 +251,7 @@ router.delete('/repos', (req, res) => {
|
|
|
243
251
|
});
|
|
244
252
|
} catch (err) {
|
|
245
253
|
console.error('[Plugins API] Remove repo error:', err);
|
|
246
|
-
res
|
|
247
|
-
success: false,
|
|
248
|
-
message: err.message
|
|
249
|
-
});
|
|
254
|
+
sendApiError(res, err);
|
|
250
255
|
}
|
|
251
256
|
});
|
|
252
257
|
|
|
@@ -271,10 +276,7 @@ router.put('/repos/toggle', (req, res) => {
|
|
|
271
276
|
});
|
|
272
277
|
} catch (err) {
|
|
273
278
|
console.error('[Plugins API] Toggle repo error:', err);
|
|
274
|
-
res
|
|
275
|
-
success: false,
|
|
276
|
-
message: err.message
|
|
277
|
-
});
|
|
279
|
+
sendApiError(res, err);
|
|
278
280
|
}
|
|
279
281
|
});
|
|
280
282
|
|
|
@@ -298,10 +300,7 @@ router.delete('/repos/:owner/:name', (req, res) => {
|
|
|
298
300
|
});
|
|
299
301
|
} catch (err) {
|
|
300
302
|
console.error('[Plugins API] Remove repo error:', err);
|
|
301
|
-
res
|
|
302
|
-
success: false,
|
|
303
|
-
message: err.message
|
|
304
|
-
});
|
|
303
|
+
sendApiError(res, err);
|
|
305
304
|
}
|
|
306
305
|
});
|
|
307
306
|
|
|
@@ -333,10 +332,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
333
332
|
});
|
|
334
333
|
} catch (err) {
|
|
335
334
|
console.error('[Plugins API] Toggle repo error:', err);
|
|
336
|
-
res
|
|
337
|
-
success: false,
|
|
338
|
-
message: err.message
|
|
339
|
-
});
|
|
335
|
+
sendApiError(res, err);
|
|
340
336
|
}
|
|
341
337
|
});
|
|
342
338
|
|
|
@@ -367,10 +363,7 @@ router.put('/repos/auth', (req, res) => {
|
|
|
367
363
|
});
|
|
368
364
|
} catch (err) {
|
|
369
365
|
console.error('[Plugins API] Update repo auth error:', err);
|
|
370
|
-
res
|
|
371
|
-
success: false,
|
|
372
|
-
message: err.message
|
|
373
|
-
});
|
|
366
|
+
sendApiError(res, err);
|
|
374
367
|
}
|
|
375
368
|
});
|
|
376
369
|
|
|
@@ -391,10 +384,7 @@ router.post('/repos/sync', async (req, res) => {
|
|
|
391
384
|
});
|
|
392
385
|
} catch (err) {
|
|
393
386
|
console.error('[Plugins API] Sync repos error:', err);
|
|
394
|
-
res
|
|
395
|
-
success: false,
|
|
396
|
-
message: err.message
|
|
397
|
-
});
|
|
387
|
+
sendApiError(res, err);
|
|
398
388
|
}
|
|
399
389
|
});
|
|
400
390
|
|
|
@@ -415,10 +405,7 @@ router.post('/sync', async (req, res) => {
|
|
|
415
405
|
});
|
|
416
406
|
} catch (err) {
|
|
417
407
|
console.error('[Plugins API] Sync plugins error:', err);
|
|
418
|
-
res
|
|
419
|
-
success: false,
|
|
420
|
-
message: err.message
|
|
421
|
-
});
|
|
408
|
+
sendApiError(res, err);
|
|
422
409
|
}
|
|
423
410
|
});
|
|
424
411
|
|
|
@@ -504,10 +491,7 @@ router.get('/:name', (req, res) => {
|
|
|
504
491
|
});
|
|
505
492
|
} catch (err) {
|
|
506
493
|
console.error('[Plugins API] Get plugin error:', err);
|
|
507
|
-
res
|
|
508
|
-
success: false,
|
|
509
|
-
message: err.message
|
|
510
|
-
});
|
|
494
|
+
sendApiError(res, err);
|
|
511
495
|
}
|
|
512
496
|
});
|
|
513
497
|
|
|
@@ -536,10 +520,7 @@ router.delete('/:name', (req, res) => {
|
|
|
536
520
|
});
|
|
537
521
|
} catch (err) {
|
|
538
522
|
console.error('[Plugins API] Uninstall plugin error:', err);
|
|
539
|
-
res
|
|
540
|
-
success: false,
|
|
541
|
-
message: err.message
|
|
542
|
-
});
|
|
523
|
+
sendApiError(res, err);
|
|
543
524
|
}
|
|
544
525
|
});
|
|
545
526
|
|
|
@@ -571,10 +552,7 @@ router.put('/:name/toggle', (req, res) => {
|
|
|
571
552
|
});
|
|
572
553
|
} catch (err) {
|
|
573
554
|
console.error('[Plugins API] Toggle plugin error:', err);
|
|
574
|
-
res
|
|
575
|
-
success: false,
|
|
576
|
-
message: err.message
|
|
577
|
-
});
|
|
555
|
+
sendApiError(res, err);
|
|
578
556
|
}
|
|
579
557
|
});
|
|
580
558
|
|
|
@@ -605,10 +583,7 @@ router.put('/:name/config', (req, res) => {
|
|
|
605
583
|
});
|
|
606
584
|
} catch (err) {
|
|
607
585
|
console.error('[Plugins API] Update plugin config error:', err);
|
|
608
|
-
res
|
|
609
|
-
success: false,
|
|
610
|
-
message: err.message
|
|
611
|
-
});
|
|
586
|
+
sendApiError(res, err);
|
|
612
587
|
}
|
|
613
588
|
});
|
|
614
589
|
|
package/src/server/api/skills.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const express = require('express');
|
|
6
6
|
const { SkillService } = require('../services/skill-service');
|
|
7
7
|
const { maskToken } = require('../services/oauth-utils');
|
|
8
|
+
const { sendApiError } = require('./validation-errors');
|
|
8
9
|
|
|
9
10
|
const router = express.Router();
|
|
10
11
|
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
@@ -84,10 +85,7 @@ router.get('/', async (req, res) => {
|
|
|
84
85
|
});
|
|
85
86
|
} catch (err) {
|
|
86
87
|
console.error('[Skills API] List skills error:', err);
|
|
87
|
-
res
|
|
88
|
-
success: false,
|
|
89
|
-
message: err.message
|
|
90
|
-
});
|
|
88
|
+
sendApiError(res, err);
|
|
91
89
|
}
|
|
92
90
|
});
|
|
93
91
|
|
|
@@ -116,10 +114,7 @@ router.get('/detail/*', async (req, res) => {
|
|
|
116
114
|
});
|
|
117
115
|
} catch (err) {
|
|
118
116
|
console.error('[Skills API] Get skill detail error:', err);
|
|
119
|
-
res
|
|
120
|
-
success: false,
|
|
121
|
-
message: err.message
|
|
122
|
-
});
|
|
117
|
+
sendApiError(res, err);
|
|
123
118
|
}
|
|
124
119
|
});
|
|
125
120
|
|
|
@@ -138,10 +133,7 @@ router.get('/installed', (req, res) => {
|
|
|
138
133
|
});
|
|
139
134
|
} catch (err) {
|
|
140
135
|
console.error('[Skills API] Get installed skills error:', err);
|
|
141
|
-
res
|
|
142
|
-
success: false,
|
|
143
|
-
message: err.message
|
|
144
|
-
});
|
|
136
|
+
sendApiError(res, err);
|
|
145
137
|
}
|
|
146
138
|
});
|
|
147
139
|
|
|
@@ -184,10 +176,7 @@ router.post('/install', async (req, res) => {
|
|
|
184
176
|
});
|
|
185
177
|
} catch (err) {
|
|
186
178
|
console.error('[Skills API] Install skill error:', err);
|
|
187
|
-
res
|
|
188
|
-
success: false,
|
|
189
|
-
message: err.message
|
|
190
|
-
});
|
|
179
|
+
sendApiError(res, err);
|
|
191
180
|
}
|
|
192
181
|
});
|
|
193
182
|
|
|
@@ -209,7 +198,7 @@ router.post('/install-local', (req, res) => {
|
|
|
209
198
|
res.json({ success: true, platform, ...result });
|
|
210
199
|
} catch (err) {
|
|
211
200
|
console.error('[Skills API] Install local skill error:', err);
|
|
212
|
-
res
|
|
201
|
+
sendApiError(res, err);
|
|
213
202
|
}
|
|
214
203
|
});
|
|
215
204
|
|
|
@@ -259,10 +248,7 @@ router.post('/create', (req, res) => {
|
|
|
259
248
|
});
|
|
260
249
|
} catch (err) {
|
|
261
250
|
console.error('[Skills API] Create skill error:', err);
|
|
262
|
-
res
|
|
263
|
-
success: false,
|
|
264
|
-
message: err.message
|
|
265
|
-
});
|
|
251
|
+
sendApiError(res, err);
|
|
266
252
|
}
|
|
267
253
|
});
|
|
268
254
|
|
|
@@ -292,10 +278,7 @@ router.post('/uninstall', (req, res) => {
|
|
|
292
278
|
});
|
|
293
279
|
} catch (err) {
|
|
294
280
|
console.error('[Skills API] Uninstall skill error:', err);
|
|
295
|
-
res
|
|
296
|
-
success: false,
|
|
297
|
-
message: err.message
|
|
298
|
-
});
|
|
281
|
+
sendApiError(res, err);
|
|
299
282
|
}
|
|
300
283
|
});
|
|
301
284
|
|
|
@@ -314,10 +297,7 @@ router.get('/repos', (req, res) => {
|
|
|
314
297
|
});
|
|
315
298
|
} catch (err) {
|
|
316
299
|
console.error('[Skills API] Get repos error:', err);
|
|
317
|
-
res
|
|
318
|
-
success: false,
|
|
319
|
-
message: err.message
|
|
320
|
-
});
|
|
300
|
+
sendApiError(res, err);
|
|
321
301
|
}
|
|
322
302
|
});
|
|
323
303
|
|
|
@@ -349,10 +329,7 @@ router.post('/repos', (req, res) => {
|
|
|
349
329
|
});
|
|
350
330
|
} catch (err) {
|
|
351
331
|
console.error('[Skills API] Add repo error:', err);
|
|
352
|
-
res
|
|
353
|
-
success: false,
|
|
354
|
-
message: err.message
|
|
355
|
-
});
|
|
332
|
+
sendApiError(res, err);
|
|
356
333
|
}
|
|
357
334
|
});
|
|
358
335
|
|
|
@@ -369,10 +346,7 @@ router.delete('/repos', (req, res) => {
|
|
|
369
346
|
});
|
|
370
347
|
} catch (err) {
|
|
371
348
|
console.error('[Skills API] Remove repo error:', err);
|
|
372
|
-
res
|
|
373
|
-
success: false,
|
|
374
|
-
message: err.message
|
|
375
|
-
});
|
|
349
|
+
sendApiError(res, err);
|
|
376
350
|
}
|
|
377
351
|
});
|
|
378
352
|
|
|
@@ -390,10 +364,7 @@ router.put('/repos/toggle', (req, res) => {
|
|
|
390
364
|
});
|
|
391
365
|
} catch (err) {
|
|
392
366
|
console.error('[Skills API] Toggle repo error:', err);
|
|
393
|
-
res
|
|
394
|
-
success: false,
|
|
395
|
-
message: err.message
|
|
396
|
-
});
|
|
367
|
+
sendApiError(res, err);
|
|
397
368
|
}
|
|
398
369
|
});
|
|
399
370
|
|
|
@@ -425,10 +396,7 @@ router.put('/repos/auth', (req, res) => {
|
|
|
425
396
|
});
|
|
426
397
|
} catch (err) {
|
|
427
398
|
console.error('[Skills API] Update repo auth error:', err);
|
|
428
|
-
res
|
|
429
|
-
success: false,
|
|
430
|
-
message: err.message
|
|
431
|
-
});
|
|
399
|
+
sendApiError(res, err);
|
|
432
400
|
}
|
|
433
401
|
});
|
|
434
402
|
|
|
@@ -451,10 +419,7 @@ router.delete('/repos/:owner/:name', (req, res) => {
|
|
|
451
419
|
});
|
|
452
420
|
} catch (err) {
|
|
453
421
|
console.error('[Skills API] Remove repo error:', err);
|
|
454
|
-
res
|
|
455
|
-
success: false,
|
|
456
|
-
message: err.message
|
|
457
|
-
});
|
|
422
|
+
sendApiError(res, err);
|
|
458
423
|
}
|
|
459
424
|
});
|
|
460
425
|
|
|
@@ -479,10 +444,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
479
444
|
});
|
|
480
445
|
} catch (err) {
|
|
481
446
|
console.error('[Skills API] Toggle repo error:', err);
|
|
482
|
-
res
|
|
483
|
-
success: false,
|
|
484
|
-
message: err.message
|
|
485
|
-
});
|
|
447
|
+
sendApiError(res, err);
|
|
486
448
|
}
|
|
487
449
|
});
|
|
488
450
|
|
|
@@ -529,10 +491,7 @@ router.post('/create-with-files', (req, res) => {
|
|
|
529
491
|
});
|
|
530
492
|
} catch (err) {
|
|
531
493
|
console.error('[Skills API] Create skill with files error:', err);
|
|
532
|
-
res
|
|
533
|
-
success: false,
|
|
534
|
-
message: err.message
|
|
535
|
-
});
|
|
494
|
+
sendApiError(res, err);
|
|
536
495
|
}
|
|
537
496
|
});
|
|
538
497
|
|
|
@@ -554,10 +513,7 @@ router.get('/:directory/files', (req, res) => {
|
|
|
554
513
|
});
|
|
555
514
|
} catch (err) {
|
|
556
515
|
console.error('[Skills API] Get skill files error:', err);
|
|
557
|
-
res
|
|
558
|
-
success: false,
|
|
559
|
-
message: err.message
|
|
560
|
-
});
|
|
516
|
+
sendApiError(res, err);
|
|
561
517
|
}
|
|
562
518
|
});
|
|
563
519
|
|
|
@@ -588,10 +544,7 @@ router.get('/:directory/file/*', (req, res) => {
|
|
|
588
544
|
});
|
|
589
545
|
} catch (err) {
|
|
590
546
|
console.error('[Skills API] Get skill file content error:', err);
|
|
591
|
-
res
|
|
592
|
-
success: false,
|
|
593
|
-
message: err.message
|
|
594
|
-
});
|
|
547
|
+
sendApiError(res, err);
|
|
595
548
|
}
|
|
596
549
|
});
|
|
597
550
|
|
|
@@ -622,10 +575,7 @@ router.post('/:directory/files', (req, res) => {
|
|
|
622
575
|
});
|
|
623
576
|
} catch (err) {
|
|
624
577
|
console.error('[Skills API] Add skill files error:', err);
|
|
625
|
-
res
|
|
626
|
-
success: false,
|
|
627
|
-
message: err.message
|
|
628
|
-
});
|
|
578
|
+
sendApiError(res, err);
|
|
629
579
|
}
|
|
630
580
|
});
|
|
631
581
|
|
|
@@ -655,10 +605,7 @@ router.delete('/:directory/file/*', (req, res) => {
|
|
|
655
605
|
});
|
|
656
606
|
} catch (err) {
|
|
657
607
|
console.error('[Skills API] Delete skill file error:', err);
|
|
658
|
-
res
|
|
659
|
-
success: false,
|
|
660
|
-
message: err.message
|
|
661
|
-
});
|
|
608
|
+
sendApiError(res, err);
|
|
662
609
|
}
|
|
663
610
|
});
|
|
664
611
|
|
|
@@ -697,10 +644,7 @@ router.put('/:directory/file/*', (req, res) => {
|
|
|
697
644
|
});
|
|
698
645
|
} catch (err) {
|
|
699
646
|
console.error('[Skills API] Update skill file error:', err);
|
|
700
|
-
res
|
|
701
|
-
success: false,
|
|
702
|
-
message: err.message
|
|
703
|
-
});
|
|
647
|
+
sendApiError(res, err);
|
|
704
648
|
}
|
|
705
649
|
});
|
|
706
650
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const VALIDATION_ERROR_PATTERNS = [
|
|
2
|
+
/^Invalid\b/i,
|
|
3
|
+
/不能为空/,
|
|
4
|
+
/不合法/,
|
|
5
|
+
/只能包含/,
|
|
6
|
+
/不能包含/,
|
|
7
|
+
/必须/,
|
|
8
|
+
/不能/,
|
|
9
|
+
/Missing\b/i,
|
|
10
|
+
/requires?/i,
|
|
11
|
+
/required/i,
|
|
12
|
+
/escapes/i,
|
|
13
|
+
/not support/i,
|
|
14
|
+
/不支持/
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function isValidationError(error) {
|
|
18
|
+
const message = String(error?.message || error || '');
|
|
19
|
+
return VALIDATION_ERROR_PATTERNS.some(pattern => pattern.test(message));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function sendApiError(res, error, fallbackStatus = 500, extra = {}) {
|
|
23
|
+
const status = isValidationError(error) ? 400 : fallbackStatus;
|
|
24
|
+
return res.status(status).json({
|
|
25
|
+
success: false,
|
|
26
|
+
message: error?.message || String(error),
|
|
27
|
+
...extra
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
isValidationError,
|
|
33
|
+
sendApiError
|
|
34
|
+
};
|