befly 3.7.0 → 3.7.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/check.ts +79 -87
- package/lib/database.ts +3 -3
- package/lib/dbHelper.ts +2 -2
- package/lib/middleware.ts +2 -2
- package/lifecycle/lifecycle.ts +0 -1
- package/lifecycle/loader.ts +0 -4
- package/main.ts +4 -7
- package/menu.json +31 -43
- package/package.json +2 -2
- package/router/api.ts +1 -1
package/check.ts
CHANGED
|
@@ -81,16 +81,12 @@ export const checkDefault = async function (): Promise<void> {
|
|
|
81
81
|
for (const addonName of addons) {
|
|
82
82
|
const addonTablesDir = Addon.getDir(addonName, 'tables');
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
})
|
|
90
|
-
allTableFiles.push({ file: file, type: 'addon', addonName: addonName });
|
|
91
|
-
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
// addon 的 tables 目录可能不存在,跳过
|
|
84
|
+
for await (const file of tablesGlob.scan({
|
|
85
|
+
cwd: addonTablesDir,
|
|
86
|
+
absolute: true,
|
|
87
|
+
onlyFiles: true
|
|
88
|
+
})) {
|
|
89
|
+
allTableFiles.push({ file: file, type: 'addon', addonName: addonName });
|
|
94
90
|
}
|
|
95
91
|
}
|
|
96
92
|
|
|
@@ -124,98 +120,94 @@ export const checkDefault = async function (): Promise<void> {
|
|
|
124
120
|
}
|
|
125
121
|
|
|
126
122
|
// 验证规则格式
|
|
123
|
+
fileRules++;
|
|
124
|
+
totalRules++;
|
|
125
|
+
|
|
126
|
+
// 检查是否使用了保留字段
|
|
127
|
+
if (RESERVED_FIELDS.includes(colKey as any)) {
|
|
128
|
+
Logger.warn(`${fileType}表 ${fileName} 文件包含保留字段 ${colKey},` + `不能在表定义中使用以下字段: ${RESERVED_FIELDS.join(', ')}`);
|
|
129
|
+
fileValid = false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 使用 parseRule 解析字段规则
|
|
133
|
+
let parsed;
|
|
127
134
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
parsed = parseRule(rule);
|
|
136
|
+
} catch (error: any) {
|
|
137
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 字段规则解析失败:${error.message}`);
|
|
138
|
+
fileValid = false;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
130
141
|
|
|
131
|
-
|
|
132
|
-
if (RESERVED_FIELDS.includes(colKey as any)) {
|
|
133
|
-
Logger.warn(`${fileType}表 ${fileName} 文件包含保留字段 ${colKey},` + `不能在表定义中使用以下字段: ${RESERVED_FIELDS.join(', ')}`);
|
|
134
|
-
fileValid = false;
|
|
135
|
-
}
|
|
142
|
+
const { name: fieldName, type: fieldType, min: fieldMin, max: fieldMax, default: fieldDefault, index: fieldIndex, regex: fieldRegx } = parsed;
|
|
136
143
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
144
|
+
// 第1个值:名称必须为中文、数字、字母、下划线、短横线、空格
|
|
145
|
+
if (!FIELD_NAME_REGEX.test(fieldName)) {
|
|
146
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 字段名称 "${fieldName}" 格式错误,` + `必须为中文、数字、字母、下划线、短横线、空格`);
|
|
147
|
+
fileValid = false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 第2个值:字段类型必须为string,number,text,array_string,array_text之一
|
|
151
|
+
if (!FIELD_TYPES.includes(fieldType as any)) {
|
|
152
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 字段类型 "${fieldType}" 格式错误,` + `必须为${FIELD_TYPES.join('、')}之一`);
|
|
153
|
+
fileValid = false;
|
|
154
|
+
}
|
|
146
155
|
|
|
147
|
-
|
|
156
|
+
// 第3/4个值:需要是 null 或 数字
|
|
157
|
+
if (!(fieldMin === null || typeof fieldMin === 'number')) {
|
|
158
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 格式错误,必须为null或数字`);
|
|
159
|
+
fileValid = false;
|
|
160
|
+
}
|
|
161
|
+
if (!(fieldMax === null || typeof fieldMax === 'number')) {
|
|
162
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最大值 "${fieldMax}" 格式错误,必须为null或数字`);
|
|
163
|
+
fileValid = false;
|
|
164
|
+
}
|
|
148
165
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
166
|
+
// 约束:当最小值与最大值均为数字时,要求最小值 <= 最大值
|
|
167
|
+
if (fieldMin !== null && fieldMax !== null) {
|
|
168
|
+
if (fieldMin > fieldMax) {
|
|
169
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 不能大于最大值 "${fieldMax}"`);
|
|
152
170
|
fileValid = false;
|
|
153
171
|
}
|
|
172
|
+
}
|
|
154
173
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
174
|
+
// 第6个值:是否创建索引必须为0或1
|
|
175
|
+
if (fieldIndex !== 0 && fieldIndex !== 1) {
|
|
176
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 索引标识 "${fieldIndex}" 格式错误,必须为0或1`);
|
|
177
|
+
fileValid = false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 第7个值:必须为null或正则表达式(parseRule已经验证过了)
|
|
181
|
+
// parseRule 已经将正则字符串转换为 RegExp 或 null,这里不需要再验证
|
|
160
182
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
183
|
+
// 第4个值与类型联动校验 + 默认值规则
|
|
184
|
+
if (fieldType === 'text') {
|
|
185
|
+
// text:min/max 必须为 null,默认值必须为 'null'
|
|
186
|
+
if (fieldMin !== null) {
|
|
187
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最小值必须为 null,当前为 "${fieldMin}"`);
|
|
164
188
|
fileValid = false;
|
|
165
189
|
}
|
|
166
|
-
if (
|
|
167
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey}
|
|
190
|
+
if (fieldMax !== null) {
|
|
191
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最大长度必须为 null,当前为 "${fieldMax}"`);
|
|
168
192
|
fileValid = false;
|
|
169
193
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (fieldMin > fieldMax) {
|
|
174
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 不能大于最大值 "${fieldMax}"`);
|
|
175
|
-
fileValid = false;
|
|
176
|
-
}
|
|
194
|
+
if (fieldDefault !== 'null') {
|
|
195
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 text 类型,默认值必须为 null,当前为 "${fieldDefault}"`);
|
|
196
|
+
fileValid = false;
|
|
177
197
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
198
|
+
} else if (fieldType === 'string' || fieldType === 'array') {
|
|
199
|
+
if (fieldMax === null || typeof fieldMax !== 'number') {
|
|
200
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,` + `最大长度必须为数字,当前为 "${fieldMax}"`);
|
|
201
|
+
fileValid = false;
|
|
202
|
+
} else if (fieldMax > MAX_VARCHAR_LENGTH) {
|
|
203
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最大长度 ${fieldMax} 越界,` + `${fieldType} 类型长度必须在 1..${MAX_VARCHAR_LENGTH} 范围内`);
|
|
182
204
|
fileValid = false;
|
|
183
205
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// 第4个值与类型联动校验 + 默认值规则
|
|
189
|
-
if (fieldType === 'text') {
|
|
190
|
-
// text:min/max 必须为 null,默认值必须为 'null'
|
|
191
|
-
if (fieldMin !== null) {
|
|
192
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最小值必须为 null,当前为 "${fieldMin}"`);
|
|
193
|
-
fileValid = false;
|
|
194
|
-
}
|
|
195
|
-
if (fieldMax !== null) {
|
|
196
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最大长度必须为 null,当前为 "${fieldMax}"`);
|
|
197
|
-
fileValid = false;
|
|
198
|
-
}
|
|
199
|
-
if (fieldDefault !== 'null') {
|
|
200
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 text 类型,默认值必须为 null,当前为 "${fieldDefault}"`);
|
|
201
|
-
fileValid = false;
|
|
202
|
-
}
|
|
203
|
-
} else if (fieldType === 'string' || fieldType === 'array') {
|
|
204
|
-
if (fieldMax === null || typeof fieldMax !== 'number') {
|
|
205
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,` + `最大长度必须为数字,当前为 "${fieldMax}"`);
|
|
206
|
-
fileValid = false;
|
|
207
|
-
} else if (fieldMax > MAX_VARCHAR_LENGTH) {
|
|
208
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最大长度 ${fieldMax} 越界,` + `${fieldType} 类型长度必须在 1..${MAX_VARCHAR_LENGTH} 范围内`);
|
|
209
|
-
fileValid = false;
|
|
210
|
-
}
|
|
211
|
-
} else if (fieldType === 'number') {
|
|
212
|
-
if (fieldDefault !== 'null' && typeof fieldDefault !== 'number') {
|
|
213
|
-
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 number 类型,` + `默认值必须为数字或null,当前为 "${fieldDefault}"`);
|
|
214
|
-
fileValid = false;
|
|
215
|
-
}
|
|
206
|
+
} else if (fieldType === 'number') {
|
|
207
|
+
if (fieldDefault !== 'null' && typeof fieldDefault !== 'number') {
|
|
208
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 number 类型,` + `默认值必须为数字或null,当前为 "${fieldDefault}"`);
|
|
209
|
+
fileValid = false;
|
|
216
210
|
}
|
|
217
|
-
} catch (error: any) {
|
|
218
|
-
// 单个字段规则解析失败已在上面处理
|
|
219
211
|
}
|
|
220
212
|
}
|
|
221
213
|
|
|
@@ -226,7 +218,7 @@ export const checkDefault = async function (): Promise<void> {
|
|
|
226
218
|
invalidFiles++;
|
|
227
219
|
}
|
|
228
220
|
} catch (error: any) {
|
|
229
|
-
Logger.error(`${fileType}表 ${fileName}
|
|
221
|
+
Logger.error(`${fileType}表 ${fileName} 解析失败`, error);
|
|
230
222
|
invalidFiles++;
|
|
231
223
|
}
|
|
232
224
|
}
|
|
@@ -241,7 +233,7 @@ export const checkDefault = async function (): Promise<void> {
|
|
|
241
233
|
throw new Error('表定义检查失败,请修复上述错误后重试');
|
|
242
234
|
}
|
|
243
235
|
} catch (error: any) {
|
|
244
|
-
Logger.error('
|
|
236
|
+
Logger.error('数据表定义检查过程中出错', error);
|
|
245
237
|
throw error;
|
|
246
238
|
}
|
|
247
239
|
};
|
package/lib/database.ts
CHANGED
|
@@ -94,7 +94,7 @@ export class Database {
|
|
|
94
94
|
Logger.error('数据库连接测试失败', error);
|
|
95
95
|
|
|
96
96
|
try {
|
|
97
|
-
await sql
|
|
97
|
+
await sql?.close();
|
|
98
98
|
} catch (cleanupError) {}
|
|
99
99
|
|
|
100
100
|
throw error;
|
|
@@ -109,7 +109,7 @@ export class Database {
|
|
|
109
109
|
try {
|
|
110
110
|
await this.sqlClient.close();
|
|
111
111
|
} catch (error: any) {
|
|
112
|
-
Logger.
|
|
112
|
+
Logger.error('关闭 SQL 连接时出错', error);
|
|
113
113
|
}
|
|
114
114
|
this.sqlClient = null;
|
|
115
115
|
}
|
|
@@ -200,7 +200,7 @@ export class Database {
|
|
|
200
200
|
try {
|
|
201
201
|
this.redisClient.close();
|
|
202
202
|
} catch (error: any) {
|
|
203
|
-
Logger.
|
|
203
|
+
Logger.error('关闭 Redis 连接时出错', error);
|
|
204
204
|
}
|
|
205
205
|
this.redisClient = null;
|
|
206
206
|
}
|
package/lib/dbHelper.ts
CHANGED
|
@@ -410,7 +410,7 @@ export class DbHelper {
|
|
|
410
410
|
try {
|
|
411
411
|
processed.id = await this.befly.redis.genTimeID();
|
|
412
412
|
} catch (error: any) {
|
|
413
|
-
throw new Error(`生成 ID 失败,Redis 可能不可用 (table: ${table})
|
|
413
|
+
throw new Error(`生成 ID 失败,Redis 可能不可用 (table: ${table})`, error);
|
|
414
414
|
}
|
|
415
415
|
|
|
416
416
|
// 强制生成时间戳(不可被用户覆盖)
|
|
@@ -634,7 +634,7 @@ export class DbHelper {
|
|
|
634
634
|
await conn.query('ROLLBACK');
|
|
635
635
|
Logger.warn('事务已回滚');
|
|
636
636
|
} catch (rollbackError: any) {
|
|
637
|
-
Logger.error('
|
|
637
|
+
Logger.error('事务回滚失败', rollbackError);
|
|
638
638
|
}
|
|
639
639
|
}
|
|
640
640
|
throw error;
|
package/lib/middleware.ts
CHANGED
|
@@ -132,8 +132,8 @@ export async function parsePostParams(api: ApiRoute, ctx: RequestContext): Promi
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
return true;
|
|
135
|
-
} catch (
|
|
136
|
-
Logger.error('处理请求参数时发生错误',
|
|
135
|
+
} catch (error: any) {
|
|
136
|
+
Logger.error('处理请求参数时发生错误', error);
|
|
137
137
|
return false;
|
|
138
138
|
}
|
|
139
139
|
}
|
package/lifecycle/lifecycle.ts
CHANGED
package/lifecycle/loader.ts
CHANGED
|
@@ -212,7 +212,6 @@ export class Loader {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
const addonPluginsInitTime = calcPerfTime(addonPluginsInitStart);
|
|
215
|
-
Logger.info(`✓ 组件插件加载完成: ${addonPlugins.length} 个,耗时: ${addonPluginsScanTime}`);
|
|
216
215
|
}
|
|
217
216
|
}
|
|
218
217
|
|
|
@@ -275,12 +274,10 @@ export class Loader {
|
|
|
275
274
|
}
|
|
276
275
|
}
|
|
277
276
|
const userPluginsInitTime = calcPerfTime(userPluginsInitStart);
|
|
278
|
-
Logger.info(`✓ 用户插件加载完成: ${sortedUserPlugins.length} 个,耗时: ${userPluginsInitTime}`);
|
|
279
277
|
}
|
|
280
278
|
|
|
281
279
|
const totalLoadTime = calcPerfTime(loadStartTime);
|
|
282
280
|
const totalPluginCount = sortedCorePlugins.length + addonPlugins.length + sortedUserPlugins.length;
|
|
283
|
-
Logger.info(`✓ 所有插件加载完成: ${totalPluginCount} 个,总耗时: ${totalLoadTime}`);
|
|
284
281
|
|
|
285
282
|
// 核心插件失败 → 关键错误,必须退出
|
|
286
283
|
if (hadCorePluginError) {
|
|
@@ -412,7 +409,6 @@ export class Loader {
|
|
|
412
409
|
}
|
|
413
410
|
|
|
414
411
|
const totalLoadTime = calcPerfTime(loadStartTime);
|
|
415
|
-
Logger.info(`✓ ${dirDisplayName}接口加载完成: ${loadedApis}/${totalApis},耗时: ${totalLoadTime}`);
|
|
416
412
|
|
|
417
413
|
// 检查是否有加载失败的 API(理论上不会到达这里,因为上面已经 critical 退出)
|
|
418
414
|
if (failedApis > 0) {
|
package/main.ts
CHANGED
|
@@ -41,23 +41,20 @@ export class Befly {
|
|
|
41
41
|
async listen(callback?: (server: Server) => void): Promise<Server> {
|
|
42
42
|
const server = await this.lifecycle.start(this.appContext, callback);
|
|
43
43
|
|
|
44
|
-
// 注册优雅关闭信号处理器
|
|
45
44
|
const gracefulShutdown = async (signal: string) => {
|
|
46
|
-
Logger.info(`\n收到 ${signal} 信号,开始优雅关闭...`);
|
|
47
|
-
|
|
48
45
|
// 1. 停止接收新请求
|
|
49
46
|
server.stop(true);
|
|
50
|
-
Logger.info('
|
|
47
|
+
Logger.info('HTTP 服务器已停止');
|
|
51
48
|
|
|
52
49
|
// 2. 关闭数据库连接
|
|
53
50
|
try {
|
|
54
51
|
await Database.disconnect();
|
|
55
|
-
Logger.info('
|
|
52
|
+
Logger.info('数据库连接已关闭');
|
|
56
53
|
} catch (error: any) {
|
|
57
|
-
Logger.
|
|
54
|
+
Logger.err('关闭数据库连接时出错:', error);
|
|
58
55
|
}
|
|
59
56
|
|
|
60
|
-
Logger.info('
|
|
57
|
+
Logger.info('服务器已优雅关闭');
|
|
61
58
|
process.exit(0);
|
|
62
59
|
};
|
|
63
60
|
|
package/menu.json
CHANGED
|
@@ -7,61 +7,49 @@
|
|
|
7
7
|
"type": 1
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
|
-
"name": "
|
|
11
|
-
"path": "/
|
|
12
|
-
"icon": "
|
|
10
|
+
"name": "人员管理",
|
|
11
|
+
"path": "/people",
|
|
12
|
+
"icon": "UserCircle",
|
|
13
13
|
"sort": 2,
|
|
14
|
-
"type": 1
|
|
14
|
+
"type": 1,
|
|
15
|
+
"children": [
|
|
16
|
+
{
|
|
17
|
+
"name": "管理员管理",
|
|
18
|
+
"path": "/admin",
|
|
19
|
+
"icon": "Users",
|
|
20
|
+
"sort": 2,
|
|
21
|
+
"type": 1
|
|
22
|
+
}
|
|
23
|
+
]
|
|
15
24
|
},
|
|
16
25
|
{
|
|
17
|
-
"name": "
|
|
18
|
-
"path": "/
|
|
19
|
-
"icon": "
|
|
26
|
+
"name": "权限设置",
|
|
27
|
+
"path": "/settings",
|
|
28
|
+
"icon": "Settings",
|
|
20
29
|
"sort": 3,
|
|
21
|
-
"type": 1
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"name": "菜单管理",
|
|
25
|
-
"path": "/menu",
|
|
26
|
-
"icon": "Menu",
|
|
27
|
-
"sort": 4,
|
|
28
|
-
"type": 1
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"name": "角色管理",
|
|
32
|
-
"path": "/role",
|
|
33
|
-
"icon": "Users",
|
|
34
|
-
"sort": 5,
|
|
35
|
-
"type": 1
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"name": "字典管理",
|
|
39
|
-
"path": "/dict",
|
|
40
|
-
"icon": "BookOpen",
|
|
41
|
-
"sort": 6,
|
|
42
|
-
"type": 1
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"name": "用户管理",
|
|
46
|
-
"path": "/user",
|
|
47
|
-
"icon": "UserCog",
|
|
48
|
-
"sort": 7,
|
|
49
30
|
"type": 1,
|
|
50
31
|
"children": [
|
|
51
32
|
{
|
|
52
|
-
"name": "
|
|
53
|
-
"path": "/
|
|
54
|
-
"icon": "
|
|
55
|
-
"sort":
|
|
33
|
+
"name": "菜单管理",
|
|
34
|
+
"path": "/menu",
|
|
35
|
+
"icon": "Menu",
|
|
36
|
+
"sort": 4,
|
|
56
37
|
"type": 1
|
|
57
38
|
},
|
|
58
39
|
{
|
|
59
|
-
"name": "
|
|
60
|
-
"path": "/
|
|
61
|
-
"icon": "
|
|
62
|
-
"sort":
|
|
40
|
+
"name": "角色管理",
|
|
41
|
+
"path": "/role",
|
|
42
|
+
"icon": "Users",
|
|
43
|
+
"sort": 5,
|
|
63
44
|
"type": 1
|
|
64
45
|
}
|
|
65
46
|
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "字典管理",
|
|
50
|
+
"path": "/dict",
|
|
51
|
+
"icon": "BookOpen",
|
|
52
|
+
"sort": 6,
|
|
53
|
+
"type": 1
|
|
66
54
|
}
|
|
67
55
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.2",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"es-toolkit": "^1.41.0",
|
|
70
70
|
"pathe": "^2.0.3"
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "4e67637bf6481e2455901b0dba798bfa52236898"
|
|
73
73
|
}
|
package/router/api.ts
CHANGED
|
@@ -115,7 +115,7 @@ export function apiHandler(apiRoutes: Map<string, ApiRoute>, pluginLists: Plugin
|
|
|
115
115
|
}
|
|
116
116
|
} catch (error: any) {
|
|
117
117
|
// 记录详细的错误日志
|
|
118
|
-
Logger.
|
|
118
|
+
Logger.error(api ? `接口 [${api.name}] 执行失败` : '处理接口请求时发生错误', error);
|
|
119
119
|
|
|
120
120
|
return Response.json(No('内部服务器错误'), {
|
|
121
121
|
headers: corsOptions.headers
|