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.
@@ -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('健康检查', false, {}, [], async (befly, ctx) => {
6
- try {
7
- const info = {
8
- status: 'ok',
9
- timestamp: new Date().toISOString(),
10
- uptime: process.uptime(),
11
- memory: process.memoryUsage(),
12
- runtime: 'Bun',
13
- version: Bun.version,
14
- platform: process.platform,
15
- arch: process.arch
16
- };
17
- // 检查 Redis 连接状态
18
- if (Env.REDIS_ENABLE === 1) {
19
- if (befly.redis) {
20
- try {
21
- await befly.redis.ping();
22
- info.redis = '已连接';
23
- } catch (error) {
24
- info.redis = '未连接';
25
- info.redisError = error.message;
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
- } else {
31
- info.redis = '禁用';
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
+ );
@@ -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('令牌检测', false, {}, [], async (befly, ctx) => {
7
- try {
8
- const token = ctx.headers?.authorization?.split(' ')[1] || '';
9
- if (!token) {
10
- return RNo('令牌不能为空');
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.1",
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": "568a64555d16f9a8175808ff6802572d2a9c78ca"
54
+ "gitHead": "1b484a191c11bb664c35214135ae2bb461f2d851"
55
55
  }
package/plugins/db.js CHANGED
@@ -56,13 +56,47 @@ export default {
56
56
  }
57
57
  }
58
58
 
59
- // 数据库操作方法
60
- const dbMethods = {
59
+ // 数据库管理类
60
+ class DatabaseManager {
61
+ // 私有属性
62
+ #pool;
63
+
64
+ constructor(pool) {
65
+ this.#pool = pool;
66
+ }
67
+
61
68
  // 原始连接池访问
62
- pool: pool,
69
+ get pool() {
70
+ return this.#pool;
71
+ }
63
72
 
64
73
  // 创建查询构造器
65
- query: () => createQueryBuilder(),
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 { where = {}, fields = '*', leftJoins = [] } = typeof options === 'object' && !Array.isArray(options) ? options : { where: options };
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, data);
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, data);
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, dataArray);
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 dbMethods.close();
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 dbMethods;
501
+ return dbManager;
449
502
  } else {
450
503
  Logger.warn(`MySQL 未启用,跳过初始化`);
451
504
  return {};