befly 3.6.0 → 3.7.1
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 +239 -0
- package/lib/database.ts +3 -3
- package/lib/dbHelper.ts +2 -2
- package/lib/middleware.ts +2 -2
- package/lifecycle/checker.ts +5 -2
- package/lifecycle/lifecycle.ts +0 -1
- package/lifecycle/loader.ts +0 -5
- package/main.ts +8 -9
- package/package.json +3 -7
- package/plugins/cache.ts +0 -1
- package/plugins/db.ts +0 -1
- package/plugins/logger.ts +0 -1
- package/plugins/redis.ts +0 -6
- package/router/api.ts +1 -1
- package/entry.ts +0 -9
package/check.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表规则检查器 - TypeScript 版本
|
|
3
|
+
* 验证表定义文件的格式和规则
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { basename } from 'pathe';
|
|
7
|
+
import { Logger } from './lib/logger.js';
|
|
8
|
+
import { parseRule } from './util.js';
|
|
9
|
+
import { projectTableDir } from './paths.js';
|
|
10
|
+
import { Addon } from './lib/addon.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 表文件信息接口
|
|
14
|
+
*/
|
|
15
|
+
interface TableFileInfo {
|
|
16
|
+
/** 表文件路径 */
|
|
17
|
+
file: string;
|
|
18
|
+
/** 文件类型:project(项目)或 addon(组件) */
|
|
19
|
+
type: 'project' | 'addon';
|
|
20
|
+
/** 如果是 addon 类型,记录 addon 名称 */
|
|
21
|
+
addonName?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 保留字段列表
|
|
26
|
+
*/
|
|
27
|
+
const RESERVED_FIELDS = ['id', 'created_at', 'updated_at', 'deleted_at', 'state'] as const;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 允许的字段类型
|
|
31
|
+
*/
|
|
32
|
+
const FIELD_TYPES = ['string', 'number', 'text', 'array_string', 'array_text'] as const;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 小驼峰命名正则
|
|
36
|
+
* 可选:以下划线开头(用于特殊文件,如通用字段定义)
|
|
37
|
+
* 必须以小写字母开头,后续可包含小写/数字,或多个 [大写+小写/数字] 片段
|
|
38
|
+
* 示例:userTable、testCustomers、common
|
|
39
|
+
*/
|
|
40
|
+
const LOWER_CAMEL_CASE_REGEX = /^_?[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 字段名称正则
|
|
44
|
+
* 必须为中文、数字、字母、下划线、短横线、空格
|
|
45
|
+
*/
|
|
46
|
+
const FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* VARCHAR 最大长度限制
|
|
50
|
+
*/
|
|
51
|
+
const MAX_VARCHAR_LENGTH = 65535;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 检查表定义文件
|
|
55
|
+
* @throws 当检查失败时抛出异常
|
|
56
|
+
*/
|
|
57
|
+
export const checkDefault = async function (): Promise<void> {
|
|
58
|
+
try {
|
|
59
|
+
const tablesGlob = new Bun.Glob('*.json');
|
|
60
|
+
|
|
61
|
+
// 统计信息
|
|
62
|
+
let totalFiles = 0;
|
|
63
|
+
let totalRules = 0;
|
|
64
|
+
let validFiles = 0;
|
|
65
|
+
let invalidFiles = 0;
|
|
66
|
+
|
|
67
|
+
// 收集所有表文件
|
|
68
|
+
const allTableFiles: TableFileInfo[] = [];
|
|
69
|
+
|
|
70
|
+
// 收集项目表字段定义文件
|
|
71
|
+
for await (const file of tablesGlob.scan({
|
|
72
|
+
cwd: projectTableDir,
|
|
73
|
+
absolute: true,
|
|
74
|
+
onlyFiles: true
|
|
75
|
+
})) {
|
|
76
|
+
allTableFiles.push({ file: file, type: 'project' });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 收集 addon 表字段定义文件
|
|
80
|
+
const addons = Addon.scan();
|
|
81
|
+
for (const addonName of addons) {
|
|
82
|
+
const addonTablesDir = Addon.getDir(addonName, 'tables');
|
|
83
|
+
|
|
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 });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 合并进行验证逻辑
|
|
94
|
+
for (const { file, type, addonName } of allTableFiles) {
|
|
95
|
+
totalFiles++;
|
|
96
|
+
const fileName = basename(file);
|
|
97
|
+
const fileBaseName = basename(file, '.json');
|
|
98
|
+
const fileType = type === 'project' ? '项目' : `组件${addonName}`;
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
// 1) 文件名小驼峰校验
|
|
102
|
+
if (!LOWER_CAMEL_CASE_REGEX.test(fileBaseName)) {
|
|
103
|
+
Logger.warn(`${fileType}表 ${fileName} 文件名必须使用小驼峰命名(例如 testCustomers.json)`);
|
|
104
|
+
// 命名不合规,记录错误并计为无效文件,继续下一个文件
|
|
105
|
+
invalidFiles++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 读取并解析 JSON 文件
|
|
110
|
+
const table = await Bun.file(file).json();
|
|
111
|
+
let fileValid = true;
|
|
112
|
+
let fileRules = 0;
|
|
113
|
+
|
|
114
|
+
// 检查 table 中的每个验证规则
|
|
115
|
+
for (const [colKey, rule] of Object.entries(table)) {
|
|
116
|
+
if (typeof rule !== 'string') {
|
|
117
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 规则必须为字符串`);
|
|
118
|
+
fileValid = false;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
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;
|
|
134
|
+
try {
|
|
135
|
+
parsed = parseRule(rule);
|
|
136
|
+
} catch (error: any) {
|
|
137
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 字段规则解析失败:${error.message}`);
|
|
138
|
+
fileValid = false;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const { name: fieldName, type: fieldType, min: fieldMin, max: fieldMax, default: fieldDefault, index: fieldIndex, regex: fieldRegx } = parsed;
|
|
143
|
+
|
|
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
|
+
}
|
|
155
|
+
|
|
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
|
+
}
|
|
165
|
+
|
|
166
|
+
// 约束:当最小值与最大值均为数字时,要求最小值 <= 最大值
|
|
167
|
+
if (fieldMin !== null && fieldMax !== null) {
|
|
168
|
+
if (fieldMin > fieldMax) {
|
|
169
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 最小值 "${fieldMin}" 不能大于最大值 "${fieldMax}"`);
|
|
170
|
+
fileValid = false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
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,这里不需要再验证
|
|
182
|
+
|
|
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}"`);
|
|
188
|
+
fileValid = false;
|
|
189
|
+
}
|
|
190
|
+
if (fieldMax !== null) {
|
|
191
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 的 text 类型最大长度必须为 null,当前为 "${fieldMax}"`);
|
|
192
|
+
fileValid = false;
|
|
193
|
+
}
|
|
194
|
+
if (fieldDefault !== 'null') {
|
|
195
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 text 类型,默认值必须为 null,当前为 "${fieldDefault}"`);
|
|
196
|
+
fileValid = false;
|
|
197
|
+
}
|
|
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} 范围内`);
|
|
204
|
+
fileValid = false;
|
|
205
|
+
}
|
|
206
|
+
} else if (fieldType === 'number') {
|
|
207
|
+
if (fieldDefault !== 'null' && typeof fieldDefault !== 'number') {
|
|
208
|
+
Logger.warn(`${fileType}表 ${fileName} 文件 ${colKey} 为 number 类型,` + `默认值必须为数字或null,当前为 "${fieldDefault}"`);
|
|
209
|
+
fileValid = false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (fileValid) {
|
|
215
|
+
validFiles++;
|
|
216
|
+
// Logger.info(`${fileType}表 ${fileName} 验证通过(${fileRules} 个字段)`);
|
|
217
|
+
} else {
|
|
218
|
+
invalidFiles++;
|
|
219
|
+
}
|
|
220
|
+
} catch (error: any) {
|
|
221
|
+
Logger.error(`${fileType}表 ${fileName} 解析失败`, error);
|
|
222
|
+
invalidFiles++;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 输出统计信息
|
|
227
|
+
// Logger.info(` 总文件数: ${totalFiles}`);
|
|
228
|
+
// Logger.info(` 总规则数: ${totalRules}`);
|
|
229
|
+
// Logger.info(` 通过文件: ${validFiles}`);
|
|
230
|
+
// Logger.info(` 失败文件: ${invalidFiles}`);
|
|
231
|
+
|
|
232
|
+
if (invalidFiles > 0) {
|
|
233
|
+
throw new Error('表定义检查失败,请修复上述错误后重试');
|
|
234
|
+
}
|
|
235
|
+
} catch (error: any) {
|
|
236
|
+
Logger.error('数据表定义检查过程中出错', error);
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
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/checker.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { join, basename } from 'pathe';
|
|
7
|
+
import { existsSync, statSync } from 'node:fs';
|
|
7
8
|
import { Logger } from '../lib/logger.js';
|
|
8
9
|
import { calcPerfTime } from '../util.js';
|
|
9
10
|
import { projectCheckDir } from '../paths.js';
|
|
@@ -36,8 +37,10 @@ export class Checker {
|
|
|
36
37
|
// 检查目录列表:先项目,后 addons
|
|
37
38
|
const checkDirs: Array<{ path: string; type: 'app' | 'addon'; addonName?: string }> = [];
|
|
38
39
|
|
|
39
|
-
// 添加项目 checks
|
|
40
|
-
|
|
40
|
+
// 添加项目 checks 目录(如果存在)
|
|
41
|
+
if (existsSync(projectCheckDir) && statSync(projectCheckDir).isDirectory()) {
|
|
42
|
+
checkDirs.push({ path: projectCheckDir, type: 'app' });
|
|
43
|
+
}
|
|
41
44
|
|
|
42
45
|
// 添加所有 addon 的 checks 目录
|
|
43
46
|
const addons = Addon.scan();
|
package/lifecycle/lifecycle.ts
CHANGED
package/lifecycle/loader.ts
CHANGED
|
@@ -145,7 +145,6 @@ export class Loader {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
const corePluginsInitTime = calcPerfTime(corePluginsInitStart);
|
|
148
|
-
Logger.info(`✓ 核心插件加载完成: ${corePlugins.length} 个,耗时: ${corePluginsScanTime}`);
|
|
149
148
|
|
|
150
149
|
// 扫描 addon 插件目录
|
|
151
150
|
const addons = Addon.scan();
|
|
@@ -213,7 +212,6 @@ export class Loader {
|
|
|
213
212
|
}
|
|
214
213
|
}
|
|
215
214
|
const addonPluginsInitTime = calcPerfTime(addonPluginsInitStart);
|
|
216
|
-
Logger.info(`✓ 组件插件加载完成: ${addonPlugins.length} 个,耗时: ${addonPluginsScanTime}`);
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
|
|
@@ -276,12 +274,10 @@ export class Loader {
|
|
|
276
274
|
}
|
|
277
275
|
}
|
|
278
276
|
const userPluginsInitTime = calcPerfTime(userPluginsInitStart);
|
|
279
|
-
Logger.info(`✓ 用户插件加载完成: ${sortedUserPlugins.length} 个,耗时: ${userPluginsInitTime}`);
|
|
280
277
|
}
|
|
281
278
|
|
|
282
279
|
const totalLoadTime = calcPerfTime(loadStartTime);
|
|
283
280
|
const totalPluginCount = sortedCorePlugins.length + addonPlugins.length + sortedUserPlugins.length;
|
|
284
|
-
Logger.info(`✓ 所有插件加载完成: ${totalPluginCount} 个,总耗时: ${totalLoadTime}`);
|
|
285
281
|
|
|
286
282
|
// 核心插件失败 → 关键错误,必须退出
|
|
287
283
|
if (hadCorePluginError) {
|
|
@@ -413,7 +409,6 @@ export class Loader {
|
|
|
413
409
|
}
|
|
414
410
|
|
|
415
411
|
const totalLoadTime = calcPerfTime(loadStartTime);
|
|
416
|
-
Logger.info(`✓ ${dirDisplayName}接口加载完成: ${loadedApis}/${totalApis},耗时: ${totalLoadTime}`);
|
|
417
412
|
|
|
418
413
|
// 检查是否有加载失败的 API(理论上不会到达这里,因为上面已经 critical 退出)
|
|
419
414
|
if (failedApis > 0) {
|
package/main.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { coreDir } from './paths.js';
|
|
|
14
14
|
import { DbHelper } from './lib/dbHelper.js';
|
|
15
15
|
import { RedisHelper } from './lib/redisHelper.js';
|
|
16
16
|
import { Addon } from './lib/addon.js';
|
|
17
|
+
import { checkDefault } from './check.js';
|
|
17
18
|
|
|
18
19
|
import type { Server } from 'bun';
|
|
19
20
|
import type { BeflyContext, BeflyOptions } from './types/befly.js';
|
|
@@ -40,23 +41,20 @@ export class Befly {
|
|
|
40
41
|
async listen(callback?: (server: Server) => void): Promise<Server> {
|
|
41
42
|
const server = await this.lifecycle.start(this.appContext, callback);
|
|
42
43
|
|
|
43
|
-
// 注册优雅关闭信号处理器
|
|
44
44
|
const gracefulShutdown = async (signal: string) => {
|
|
45
|
-
Logger.info(`\n收到 ${signal} 信号,开始优雅关闭...`);
|
|
46
|
-
|
|
47
45
|
// 1. 停止接收新请求
|
|
48
46
|
server.stop(true);
|
|
49
|
-
Logger.info('
|
|
47
|
+
Logger.info('HTTP 服务器已停止');
|
|
50
48
|
|
|
51
49
|
// 2. 关闭数据库连接
|
|
52
50
|
try {
|
|
53
51
|
await Database.disconnect();
|
|
54
|
-
Logger.info('
|
|
52
|
+
Logger.info('数据库连接已关闭');
|
|
55
53
|
} catch (error: any) {
|
|
56
|
-
Logger.
|
|
54
|
+
Logger.err('关闭数据库连接时出错:', error);
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
Logger.info('
|
|
57
|
+
Logger.info('服务器已优雅关闭');
|
|
60
58
|
process.exit(0);
|
|
61
59
|
};
|
|
62
60
|
|
|
@@ -76,9 +74,10 @@ export {
|
|
|
76
74
|
Jwt,
|
|
77
75
|
Yes,
|
|
78
76
|
No,
|
|
79
|
-
coreDir,
|
|
80
77
|
Database,
|
|
81
78
|
DbHelper,
|
|
82
79
|
RedisHelper,
|
|
83
|
-
Addon
|
|
80
|
+
Addon,
|
|
81
|
+
coreDir,
|
|
82
|
+
checkDefault
|
|
84
83
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"description": "Befly - 为 Bun 专属打造的 TypeScript API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -38,14 +38,10 @@
|
|
|
38
38
|
"homepage": "https://chensuiyi.me",
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
40
|
"files": [
|
|
41
|
-
"apis/",
|
|
42
|
-
"checks/",
|
|
43
|
-
"config/",
|
|
44
41
|
"lib/",
|
|
45
42
|
"lifecycle/",
|
|
46
43
|
"plugins/",
|
|
47
44
|
"router/",
|
|
48
|
-
"tables/",
|
|
49
45
|
"types/",
|
|
50
46
|
".gitignore",
|
|
51
47
|
".npmignore",
|
|
@@ -58,8 +54,8 @@
|
|
|
58
54
|
"tsconfig.json",
|
|
59
55
|
"LICENSE",
|
|
60
56
|
"main.ts",
|
|
57
|
+
"check.ts",
|
|
61
58
|
"env.ts",
|
|
62
|
-
"entry.ts",
|
|
63
59
|
"menu.json",
|
|
64
60
|
"paths.ts",
|
|
65
61
|
"util.ts",
|
|
@@ -73,5 +69,5 @@
|
|
|
73
69
|
"es-toolkit": "^1.41.0",
|
|
74
70
|
"pathe": "^2.0.3"
|
|
75
71
|
},
|
|
76
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "131c2482f3668346adbbd153e14d5b74cd19e725"
|
|
77
73
|
}
|
package/plugins/cache.ts
CHANGED
package/plugins/db.ts
CHANGED
package/plugins/logger.ts
CHANGED
package/plugins/redis.ts
CHANGED
|
@@ -23,12 +23,6 @@ const redisPlugin: Plugin = {
|
|
|
23
23
|
// 初始化 Redis 客户端(统一使用 database.ts 的连接管理)
|
|
24
24
|
await Database.connectRedis();
|
|
25
25
|
|
|
26
|
-
Logger.info('Redis 插件初始化成功', {
|
|
27
|
-
host: Env.REDIS_HOST,
|
|
28
|
-
port: Env.REDIS_PORT,
|
|
29
|
-
db: Env.REDIS_DB
|
|
30
|
-
});
|
|
31
|
-
|
|
32
26
|
// 返回工具对象,向下游以相同 API 暴露
|
|
33
27
|
return RedisHelper;
|
|
34
28
|
} else {
|
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
|