befly 2.0.1 → 2.0.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/apis/health/info.js +40 -33
- package/apis/tool/tokenCheck.js +22 -15
- package/package.json +2 -2
- package/plugins/db.js +86 -33
package/apis/health/info.js
CHANGED
|
@@ -2,41 +2,48 @@ import { Env } from '../../config/env.js';
|
|
|
2
2
|
import { Api } from '../../utils/api.js';
|
|
3
3
|
import { RYes, RNo } from '../../utils/util.js';
|
|
4
4
|
|
|
5
|
-
export default Api.POST(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
5
|
+
export default Api.POST(
|
|
6
|
+
//
|
|
7
|
+
'健康检查',
|
|
8
|
+
false,
|
|
9
|
+
{},
|
|
10
|
+
[],
|
|
11
|
+
async (befly, ctx) => {
|
|
12
|
+
try {
|
|
13
|
+
const info = {
|
|
14
|
+
status: 'ok',
|
|
15
|
+
timestamp: new Date().toISOString(),
|
|
16
|
+
uptime: process.uptime(),
|
|
17
|
+
memory: process.memoryUsage(),
|
|
18
|
+
runtime: 'Bun',
|
|
19
|
+
version: Bun.version,
|
|
20
|
+
platform: process.platform,
|
|
21
|
+
arch: process.arch
|
|
22
|
+
};
|
|
23
|
+
// 检查 Redis 连接状态
|
|
24
|
+
if (Env.REDIS_ENABLE === 1) {
|
|
25
|
+
if (befly.redis) {
|
|
26
|
+
try {
|
|
27
|
+
await befly.redis.ping();
|
|
28
|
+
info.redis = '已连接';
|
|
29
|
+
} catch (error) {
|
|
30
|
+
info.redis = '未连接';
|
|
31
|
+
info.redisError = error.message;
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
info.redis = '未开启';
|
|
26
35
|
}
|
|
27
36
|
} else {
|
|
28
|
-
info.redis = '
|
|
37
|
+
info.redis = '禁用';
|
|
29
38
|
}
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
return RYes('健康检查成功', info);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
befly.logger.error({
|
|
42
|
+
msg: '健康检查失败',
|
|
43
|
+
error: error.message,
|
|
44
|
+
stack: error.stack
|
|
45
|
+
});
|
|
46
|
+
return RNo('健康检查失败');
|
|
32
47
|
}
|
|
33
|
-
return RYes('健康检查成功', info);
|
|
34
|
-
} catch (error) {
|
|
35
|
-
befly.logger.error({
|
|
36
|
-
msg: '健康检查失败',
|
|
37
|
-
error: error.message,
|
|
38
|
-
stack: error.stack
|
|
39
|
-
});
|
|
40
|
-
return RNo('健康检查失败');
|
|
41
48
|
}
|
|
42
|
-
|
|
49
|
+
);
|
package/apis/tool/tokenCheck.js
CHANGED
|
@@ -3,20 +3,27 @@ import { Api } from '../../utils/api.js';
|
|
|
3
3
|
import { RYes, RNo } from '../../utils/util.js';
|
|
4
4
|
import { Jwt } from '../../utils/jwt.js';
|
|
5
5
|
|
|
6
|
-
export default Api.POST(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
export default Api.POST(
|
|
7
|
+
//
|
|
8
|
+
'令牌检测',
|
|
9
|
+
false,
|
|
10
|
+
{},
|
|
11
|
+
[],
|
|
12
|
+
async (befly, ctx) => {
|
|
13
|
+
try {
|
|
14
|
+
const token = ctx.headers?.authorization?.split(' ')[1] || '';
|
|
15
|
+
if (!token) {
|
|
16
|
+
return RNo('令牌不能为空');
|
|
17
|
+
}
|
|
18
|
+
const jwtData = await Jwt.verify(token);
|
|
19
|
+
return RYes('令牌有效');
|
|
20
|
+
} catch (error) {
|
|
21
|
+
befly.logger.error({
|
|
22
|
+
msg: '令牌检测失败',
|
|
23
|
+
error: error.message,
|
|
24
|
+
stack: error.stack
|
|
25
|
+
});
|
|
26
|
+
return RNo('令牌检测失败');
|
|
11
27
|
}
|
|
12
|
-
const jwtData = await Jwt.verify(token);
|
|
13
|
-
return RYes('令牌有效');
|
|
14
|
-
} catch (error) {
|
|
15
|
-
befly.logger.error({
|
|
16
|
-
msg: '令牌检测失败',
|
|
17
|
-
error: error.message,
|
|
18
|
-
stack: error.stack
|
|
19
|
-
});
|
|
20
|
-
return RNo('令牌检测失败');
|
|
21
28
|
}
|
|
22
|
-
|
|
29
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Buma - 为 Bun 专属打造的 API 接口框架核心引擎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"README.md",
|
|
52
52
|
"vitest.config.js"
|
|
53
53
|
],
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "1b484a191c11bb664c35214135ae2bb461f2d851"
|
|
55
55
|
}
|
package/plugins/db.js
CHANGED
|
@@ -56,13 +56,47 @@ export default {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
//
|
|
60
|
-
|
|
59
|
+
// 数据库管理类
|
|
60
|
+
class DatabaseManager {
|
|
61
|
+
// 私有属性
|
|
62
|
+
#pool;
|
|
63
|
+
|
|
64
|
+
constructor(pool) {
|
|
65
|
+
this.#pool = pool;
|
|
66
|
+
}
|
|
67
|
+
|
|
61
68
|
// 原始连接池访问
|
|
62
|
-
pool
|
|
69
|
+
get pool() {
|
|
70
|
+
return this.#pool;
|
|
71
|
+
}
|
|
63
72
|
|
|
64
73
|
// 创建查询构造器
|
|
65
|
-
query
|
|
74
|
+
query() {
|
|
75
|
+
return createQueryBuilder();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 私有方法:通用数据处理函数 - 自动添加ID和时间戳
|
|
79
|
+
async #processDataForInsert(data) {
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
|
|
82
|
+
if (Array.isArray(data)) {
|
|
83
|
+
return await Promise.all(
|
|
84
|
+
data.map(async (item) => ({
|
|
85
|
+
...item,
|
|
86
|
+
id: await befly.redis.genTimeID(),
|
|
87
|
+
created_at: now,
|
|
88
|
+
updated_at: now
|
|
89
|
+
}))
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
return {
|
|
93
|
+
...data,
|
|
94
|
+
id: await befly.redis.genTimeID(),
|
|
95
|
+
created_at: now,
|
|
96
|
+
updated_at: now
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
66
100
|
|
|
67
101
|
// 执行原始 SQL - 核心方法
|
|
68
102
|
async execute(sql, params = []) {
|
|
@@ -72,7 +106,7 @@ export default {
|
|
|
72
106
|
|
|
73
107
|
let conn;
|
|
74
108
|
try {
|
|
75
|
-
conn = await pool.getConnection();
|
|
109
|
+
conn = await this.#pool.getConnection();
|
|
76
110
|
|
|
77
111
|
if (Env.MYSQL_DEBUG === 1) {
|
|
78
112
|
Logger.debug('执行SQL:', { sql, params });
|
|
@@ -92,7 +126,7 @@ export default {
|
|
|
92
126
|
}
|
|
93
127
|
}
|
|
94
128
|
}
|
|
95
|
-
}
|
|
129
|
+
}
|
|
96
130
|
|
|
97
131
|
// 事务处理
|
|
98
132
|
async transaction(callback) {
|
|
@@ -102,7 +136,7 @@ export default {
|
|
|
102
136
|
|
|
103
137
|
let conn;
|
|
104
138
|
try {
|
|
105
|
-
conn = await pool.getConnection();
|
|
139
|
+
conn = await this.#pool.getConnection();
|
|
106
140
|
await conn.beginTransaction();
|
|
107
141
|
|
|
108
142
|
// 为回调函数提供连接对象
|
|
@@ -138,7 +172,7 @@ export default {
|
|
|
138
172
|
}
|
|
139
173
|
}
|
|
140
174
|
}
|
|
141
|
-
}
|
|
175
|
+
}
|
|
142
176
|
|
|
143
177
|
// 获取单条记录详情
|
|
144
178
|
async getDetail(table, options = {}) {
|
|
@@ -146,7 +180,12 @@ export default {
|
|
|
146
180
|
throw new Error('表名是必需的');
|
|
147
181
|
}
|
|
148
182
|
|
|
149
|
-
const {
|
|
183
|
+
const {
|
|
184
|
+
//
|
|
185
|
+
where = {},
|
|
186
|
+
fields = '*',
|
|
187
|
+
leftJoins = []
|
|
188
|
+
} = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
|
|
150
189
|
|
|
151
190
|
try {
|
|
152
191
|
const builder = createQueryBuilder().select(fields).from(table).where(where).limit(1);
|
|
@@ -170,7 +209,7 @@ export default {
|
|
|
170
209
|
Logger.error('getDetail 执行失败:', error);
|
|
171
210
|
throw error;
|
|
172
211
|
}
|
|
173
|
-
}
|
|
212
|
+
}
|
|
174
213
|
|
|
175
214
|
// 获取列表(支持分页)
|
|
176
215
|
async getList(table, options = {}) {
|
|
@@ -252,7 +291,7 @@ export default {
|
|
|
252
291
|
Logger.error('getList 执行失败:', error);
|
|
253
292
|
throw error;
|
|
254
293
|
}
|
|
255
|
-
}
|
|
294
|
+
}
|
|
256
295
|
|
|
257
296
|
// 获取所有记录
|
|
258
297
|
async getAll(table, options = {}) {
|
|
@@ -288,9 +327,9 @@ export default {
|
|
|
288
327
|
Logger.error('getAll 执行失败:', error);
|
|
289
328
|
throw error;
|
|
290
329
|
}
|
|
291
|
-
}
|
|
330
|
+
}
|
|
292
331
|
|
|
293
|
-
// 插入数据
|
|
332
|
+
// 插入数据 - 增强版,自动添加 ID 和时间戳
|
|
294
333
|
async insData(table, data) {
|
|
295
334
|
if (!table || typeof table !== 'string') {
|
|
296
335
|
throw new Error('表名是必需的');
|
|
@@ -301,16 +340,17 @@ export default {
|
|
|
301
340
|
}
|
|
302
341
|
|
|
303
342
|
try {
|
|
343
|
+
const processedData = await this.#processDataForInsert(data);
|
|
304
344
|
const builder = createQueryBuilder();
|
|
305
|
-
const { sql, params } = builder.toInsertSql(table,
|
|
345
|
+
const { sql, params } = builder.toInsertSql(table, processedData);
|
|
306
346
|
return await this.execute(sql, params);
|
|
307
347
|
} catch (error) {
|
|
308
348
|
Logger.error('insData 执行失败:', error);
|
|
309
349
|
throw error;
|
|
310
350
|
}
|
|
311
|
-
}
|
|
351
|
+
}
|
|
312
352
|
|
|
313
|
-
// 更新数据
|
|
353
|
+
// 更新数据 - 增强版,自动添加 updated_at,过滤敏感字段
|
|
314
354
|
async upData(table, data, where) {
|
|
315
355
|
if (!table || typeof table !== 'string') {
|
|
316
356
|
throw new Error('表名是必需的');
|
|
@@ -325,14 +365,23 @@ export default {
|
|
|
325
365
|
}
|
|
326
366
|
|
|
327
367
|
try {
|
|
368
|
+
// 剔除 undefined 值和敏感字段
|
|
369
|
+
const filteredData = Object.fromEntries(Object.entries(data).filter(([key, value]) => value !== undefined && !['id', 'created_at', 'deleted_at'].includes(key)));
|
|
370
|
+
|
|
371
|
+
// 自动添加 updated_at
|
|
372
|
+
const updateData = {
|
|
373
|
+
...filteredData,
|
|
374
|
+
updated_at: Date.now()
|
|
375
|
+
};
|
|
376
|
+
|
|
328
377
|
const builder = createQueryBuilder().where(where);
|
|
329
|
-
const { sql, params } = builder.toUpdateSql(table,
|
|
378
|
+
const { sql, params } = builder.toUpdateSql(table, updateData);
|
|
330
379
|
return await this.execute(sql, params);
|
|
331
380
|
} catch (error) {
|
|
332
381
|
Logger.error('upData 执行失败:', error);
|
|
333
382
|
throw error;
|
|
334
383
|
}
|
|
335
|
-
}
|
|
384
|
+
}
|
|
336
385
|
|
|
337
386
|
// 删除数据
|
|
338
387
|
async delData(table, where) {
|
|
@@ -352,9 +401,9 @@ export default {
|
|
|
352
401
|
Logger.error('delData 执行失败:', error);
|
|
353
402
|
throw error;
|
|
354
403
|
}
|
|
355
|
-
}
|
|
404
|
+
}
|
|
356
405
|
|
|
357
|
-
// 批量插入
|
|
406
|
+
// 批量插入 - 增强版,自动添加 ID 和时间戳
|
|
358
407
|
async insBatch(table, dataArray) {
|
|
359
408
|
if (!table || typeof table !== 'string') {
|
|
360
409
|
throw new Error('表名是必需的');
|
|
@@ -365,14 +414,15 @@ export default {
|
|
|
365
414
|
}
|
|
366
415
|
|
|
367
416
|
try {
|
|
417
|
+
const processedDataArray = await this.#processDataForInsert(dataArray);
|
|
368
418
|
const builder = createQueryBuilder();
|
|
369
|
-
const { sql, params } = builder.toInsertSql(table,
|
|
419
|
+
const { sql, params } = builder.toInsertSql(table, processedDataArray);
|
|
370
420
|
return await this.execute(sql, params);
|
|
371
421
|
} catch (error) {
|
|
372
422
|
Logger.error('insBatch 执行失败:', error);
|
|
373
423
|
throw error;
|
|
374
424
|
}
|
|
375
|
-
}
|
|
425
|
+
}
|
|
376
426
|
|
|
377
427
|
// 获取记录总数
|
|
378
428
|
async getCount(table, options = {}) {
|
|
@@ -404,23 +454,23 @@ export default {
|
|
|
404
454
|
Logger.error('getCount 执行失败:', error);
|
|
405
455
|
throw error;
|
|
406
456
|
}
|
|
407
|
-
}
|
|
457
|
+
}
|
|
408
458
|
|
|
409
459
|
// 获取连接池状态
|
|
410
460
|
getPoolStatus() {
|
|
411
461
|
return {
|
|
412
|
-
activeConnections: pool.activeConnections(),
|
|
413
|
-
totalConnections: pool.totalConnections(),
|
|
414
|
-
idleConnections: pool.idleConnections(),
|
|
415
|
-
taskQueueSize: pool.taskQueueSize()
|
|
462
|
+
activeConnections: this.#pool.activeConnections(),
|
|
463
|
+
totalConnections: this.#pool.totalConnections(),
|
|
464
|
+
idleConnections: this.#pool.idleConnections(),
|
|
465
|
+
taskQueueSize: this.#pool.taskQueueSize()
|
|
416
466
|
};
|
|
417
|
-
}
|
|
467
|
+
}
|
|
418
468
|
|
|
419
469
|
// 关闭连接池
|
|
420
470
|
async close() {
|
|
421
|
-
if (pool) {
|
|
471
|
+
if (this.#pool) {
|
|
422
472
|
try {
|
|
423
|
-
await pool.end();
|
|
473
|
+
await this.#pool.end();
|
|
424
474
|
Logger.info('数据库连接池已关闭');
|
|
425
475
|
} catch (error) {
|
|
426
476
|
Logger.error('关闭数据库连接池失败:', error);
|
|
@@ -428,13 +478,16 @@ export default {
|
|
|
428
478
|
}
|
|
429
479
|
}
|
|
430
480
|
}
|
|
431
|
-
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// 创建数据库管理器实例
|
|
484
|
+
const dbManager = new DatabaseManager(pool);
|
|
432
485
|
|
|
433
486
|
// 监听进程退出事件,确保连接池正确关闭
|
|
434
487
|
const gracefulShutdown = async (signal) => {
|
|
435
488
|
Logger.info(`收到 ${signal} 信号,正在关闭数据库连接池...`);
|
|
436
489
|
try {
|
|
437
|
-
await
|
|
490
|
+
await dbManager.close();
|
|
438
491
|
} catch (error) {
|
|
439
492
|
Logger.error('优雅关闭数据库失败:', error);
|
|
440
493
|
}
|
|
@@ -445,7 +498,7 @@ export default {
|
|
|
445
498
|
process.on('SIGTERM', gracefulShutdown);
|
|
446
499
|
process.on('SIGUSR2', gracefulShutdown); // nodemon 重启
|
|
447
500
|
|
|
448
|
-
return
|
|
501
|
+
return dbManager;
|
|
449
502
|
} else {
|
|
450
503
|
Logger.warn(`MySQL 未启用,跳过初始化`);
|
|
451
504
|
return {};
|