befly 3.8.25 → 3.8.27

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.
Files changed (61) hide show
  1. package/config.ts +8 -9
  2. package/hooks/{rateLimit.ts → _rateLimit.ts} +7 -13
  3. package/hooks/auth.ts +3 -11
  4. package/hooks/cors.ts +1 -4
  5. package/hooks/parser.ts +6 -8
  6. package/hooks/permission.ts +9 -12
  7. package/hooks/validator.ts +6 -9
  8. package/lib/cacheHelper.ts +0 -4
  9. package/lib/{database.ts → connect.ts} +65 -18
  10. package/lib/logger.ts +1 -17
  11. package/lib/redisHelper.ts +6 -5
  12. package/loader/loadApis.ts +3 -3
  13. package/loader/loadHooks.ts +15 -41
  14. package/loader/loadPlugins.ts +10 -16
  15. package/main.ts +25 -28
  16. package/package.json +3 -3
  17. package/plugins/cache.ts +2 -2
  18. package/plugins/cipher.ts +15 -0
  19. package/plugins/config.ts +16 -0
  20. package/plugins/db.ts +7 -17
  21. package/plugins/jwt.ts +15 -0
  22. package/plugins/logger.ts +1 -1
  23. package/plugins/redis.ts +4 -4
  24. package/plugins/tool.ts +50 -0
  25. package/router/api.ts +56 -42
  26. package/router/static.ts +12 -12
  27. package/sync/syncAll.ts +2 -20
  28. package/sync/syncApi.ts +7 -7
  29. package/sync/syncDb/apply.ts +1 -4
  30. package/sync/syncDb/constants.ts +3 -0
  31. package/sync/syncDb/ddl.ts +2 -1
  32. package/sync/syncDb/helpers.ts +5 -117
  33. package/sync/syncDb/sqlite.ts +1 -3
  34. package/sync/syncDb/table.ts +8 -142
  35. package/sync/syncDb/tableCreate.ts +25 -9
  36. package/sync/syncDb/types.ts +125 -0
  37. package/sync/syncDb/version.ts +0 -3
  38. package/sync/syncDb.ts +146 -6
  39. package/sync/syncDev.ts +19 -15
  40. package/sync/syncMenu.ts +87 -75
  41. package/tests/redisHelper.test.ts +15 -16
  42. package/tests/sync-connection.test.ts +189 -0
  43. package/tests/syncDb-apply.test.ts +287 -0
  44. package/tests/syncDb-constants.test.ts +150 -0
  45. package/tests/syncDb-ddl.test.ts +205 -0
  46. package/tests/syncDb-helpers.test.ts +112 -0
  47. package/tests/syncDb-schema.test.ts +178 -0
  48. package/tests/syncDb-types.test.ts +129 -0
  49. package/tsconfig.json +2 -2
  50. package/types/api.d.ts +1 -1
  51. package/types/befly.d.ts +23 -21
  52. package/types/common.d.ts +0 -29
  53. package/types/context.d.ts +8 -6
  54. package/types/hook.d.ts +3 -4
  55. package/types/plugin.d.ts +3 -0
  56. package/hooks/errorHandler.ts +0 -23
  57. package/hooks/requestId.ts +0 -24
  58. package/hooks/requestLogger.ts +0 -25
  59. package/hooks/responseFormatter.ts +0 -64
  60. package/router/root.ts +0 -56
  61. package/sync/syncDb/index.ts +0 -164
package/config.ts CHANGED
@@ -6,14 +6,14 @@ import type { BeflyOptions } from './types/befly.js';
6
6
 
7
7
  export const defaultOptions: Required<Omit<BeflyOptions, 'devPassword'>> = {
8
8
  // ========== 核心参数 ==========
9
- nodeEnv: 'development',
10
- appName: 'Befly App',
9
+ nodeEnv: (process.env.NODE_ENV as any) || 'development',
10
+ appName: '野蜂飞舞',
11
11
  appPort: 3000,
12
12
  appHost: '127.0.0.1',
13
13
  devEmail: 'dev@qq.com',
14
+ devPassword: 'beflydev123456',
14
15
  bodyLimit: 1048576, // 1MB
15
16
  tz: 'Asia/Shanghai',
16
- dbCache: 0,
17
17
 
18
18
  // ========== 日志配置 ==========
19
19
  logger: {
@@ -26,14 +26,13 @@ export const defaultOptions: Required<Omit<BeflyOptions, 'devPassword'>> = {
26
26
 
27
27
  // ========== 数据库配置 ==========
28
28
  db: {
29
- enable: 0,
30
- type: 'sqlite',
29
+ type: 'mysql',
31
30
  host: '127.0.0.1',
32
31
  port: 3306,
33
32
  username: 'root',
34
- password: '',
35
- database: 'befly',
36
- poolMax: 1
33
+ password: 'root',
34
+ database: 'befly_demo',
35
+ poolMax: 10
37
36
  },
38
37
 
39
38
  // ========== Redis 配置 ==========
@@ -43,7 +42,7 @@ export const defaultOptions: Required<Omit<BeflyOptions, 'devPassword'>> = {
43
42
  username: '',
44
43
  password: '',
45
44
  db: 0,
46
- prefix: 'befly:'
45
+ prefix: 'befly_demo:'
47
46
  },
48
47
 
49
48
  // ========== 认证配置 ==========
@@ -1,6 +1,6 @@
1
1
  // 相对导入
2
2
  import { Logger } from '../lib/logger.js';
3
- import { JsonResponse } from '../util.js';
3
+ import { ErrorResponse } from '../util.js';
4
4
 
5
5
  // 类型导入
6
6
  import type { Hook } from '../types/hook.js';
@@ -14,16 +14,13 @@ import type { Hook } from '../types/hook.js';
14
14
  * 3. 针对每个用户(userId)或IP进行限制
15
15
  */
16
16
  const hook: Hook = {
17
- // 必须在 auth 之后(获取 userId),但在业务逻辑之前
18
- after: ['parser'],
19
- order: 25,
20
-
21
- handler: async (befly, ctx, next) => {
17
+ order: 7,
18
+ handler: async (befly, ctx) => {
22
19
  const { api } = ctx;
23
20
 
24
21
  // 1. 检查配置
25
22
  if (!api || !api.rateLimit || !befly.redis) {
26
- return next();
23
+ return;
27
24
  }
28
25
 
29
26
  // 2. 解析配置 "10/60" -> count=10, seconds=60
@@ -33,12 +30,12 @@ const hook: Hook = {
33
30
 
34
31
  if (isNaN(limitCount) || isNaN(limitSeconds)) {
35
32
  Logger.warn(`[RateLimit] Invalid config: ${api.rateLimit}`);
36
- return next();
33
+ return;
37
34
  }
38
35
 
39
36
  // 3. 生成 Key
40
37
  // 优先使用 userId,否则使用 IP
41
- const identifier = ctx.user?.userId || ctx.ip || 'unknown';
38
+ const identifier = ctx.user?.id || ctx.ip || 'unknown';
42
39
  const apiPath = ctx.route || `${ctx.req.method}${new URL(ctx.req.url).pathname}`;
43
40
  const key = `rate_limit:${apiPath}:${identifier}`;
44
41
 
@@ -54,15 +51,12 @@ const hook: Hook = {
54
51
 
55
52
  // 6. 判断是否超限
56
53
  if (current > limitCount) {
57
- ctx.response = JsonResponse(ctx, '请求过于频繁,请稍后再试', 429);
54
+ ctx.response = ErrorResponse(ctx, '请求过于频繁,请稍后再试');
58
55
  return;
59
56
  }
60
-
61
- return next();
62
57
  } catch (err) {
63
58
  Logger.error('[RateLimit] Redis error:', err);
64
59
  // Redis 故障时,默认放行,避免阻塞业务
65
- return next();
66
60
  }
67
61
  }
68
62
  };
package/hooks/auth.ts CHANGED
@@ -1,22 +1,15 @@
1
1
  import type { Hook } from '../types/hook.js';
2
- import { Jwt } from '../lib/jwt.js';
3
2
 
4
3
  const hook: Hook = {
5
- after: ['cors'],
6
- order: 5,
7
- handler: async (befly, ctx, next) => {
8
- // 初始化配置(如果有)
9
- // 注意:Hook 没有 onInit,如果需要初始化,可以在 handler 首次执行时做,或者保留 Plugin 机制专门做初始化
10
- // 这里 auth 插件原本有 onInit 来配置 Jwt,现在需要迁移
11
- // 临时方案:直接在 handler 里判断是否配置过,或者让 Jwt 自身处理配置
12
-
4
+ order: 3,
5
+ handler: async (befly, ctx) => {
13
6
  const authHeader = ctx.req.headers.get('authorization');
14
7
 
15
8
  if (authHeader && authHeader.startsWith('Bearer ')) {
16
9
  const token = authHeader.substring(7);
17
10
 
18
11
  try {
19
- const payload = await Jwt.verify(token);
12
+ const payload = await befly.jwt.verify(token);
20
13
  ctx.user = payload;
21
14
  } catch (error: any) {
22
15
  ctx.user = {};
@@ -24,7 +17,6 @@ const hook: Hook = {
24
17
  } else {
25
18
  ctx.user = {};
26
19
  }
27
- await next();
28
20
  }
29
21
  };
30
22
  export default hook;
package/hooks/cors.ts CHANGED
@@ -10,9 +10,8 @@ import type { CorsConfig } from '../types/befly.js';
10
10
  * 设置跨域响应头并处理 OPTIONS 预检请求
11
11
  */
12
12
  const hook: Hook = {
13
- after: ['errorHandler'],
14
13
  order: 2,
15
- handler: async (befly, ctx, next) => {
14
+ handler: async (befly, ctx) => {
16
15
  const req = ctx.req;
17
16
 
18
17
  // 合并默认配置和用户配置
@@ -41,8 +40,6 @@ const hook: Hook = {
41
40
  });
42
41
  return;
43
42
  }
44
-
45
- await next();
46
43
  }
47
44
  };
48
45
  export default hook;
package/hooks/parser.ts CHANGED
@@ -4,7 +4,7 @@ import { pickFields } from 'befly-util';
4
4
 
5
5
  // 相对导入
6
6
  import { Xml } from '../lib/xml.js';
7
- import { JsonResponse } from '../util.js';
7
+ import { ErrorResponse } from '../util.js';
8
8
 
9
9
  // 类型导入
10
10
  import type { Hook } from '../types/hook.js';
@@ -16,10 +16,9 @@ import type { Hook } from '../types/hook.js';
16
16
  * - 根据 API 定义的 fields 过滤字段
17
17
  */
18
18
  const hook: Hook = {
19
- after: ['auth'],
20
- order: 10,
21
- handler: async (befly, ctx, next) => {
22
- if (!ctx.api) return next();
19
+ order: 4,
20
+ handler: async (befly, ctx) => {
21
+ if (!ctx.api) return;
23
22
 
24
23
  // GET 请求:解析查询参数
25
24
  if (ctx.req.method === 'GET') {
@@ -52,16 +51,15 @@ const hook: Hook = {
52
51
  }
53
52
  } else {
54
53
  // 不支持的 Content-Type
55
- ctx.response = JsonResponse(ctx, '无效的请求参数格式');
54
+ ctx.response = ErrorResponse(ctx, '无效的请求参数格式');
56
55
  return;
57
56
  }
58
57
  } catch (e) {
59
58
  // 解析失败
60
- ctx.response = JsonResponse(ctx, '无效的请求参数格式');
59
+ ctx.response = ErrorResponse(ctx, '无效的请求参数格式');
61
60
  return;
62
61
  }
63
62
  }
64
- await next();
65
63
  }
66
64
  };
67
65
  export default hook;
@@ -1,5 +1,5 @@
1
1
  // 相对导入
2
- import { JsonResponse } from '../util.js';
2
+ import { ErrorResponse } from '../util.js';
3
3
 
4
4
  // 类型导入
5
5
  import type { Hook } from '../types/hook.js';
@@ -12,25 +12,24 @@ import type { Hook } from '../types/hook.js';
12
12
  * - 其他角色:检查 Redis 中的角色权限集合
13
13
  */
14
14
  const hook: Hook = {
15
- after: ['parser'],
16
- order: 20,
17
- handler: async (befly, ctx, next) => {
18
- if (!ctx.api) return next();
15
+ order: 6,
16
+ handler: async (befly, ctx) => {
17
+ if (!ctx.api) return;
19
18
 
20
19
  // 1. 接口无需权限
21
20
  if (ctx.api.auth === false) {
22
- return next();
21
+ return;
23
22
  }
24
23
 
25
24
  // 2. 用户未登录
26
- if (!ctx.user || !ctx.user.userId) {
27
- ctx.response = JsonResponse(ctx, '未登录', 401);
25
+ if (!ctx.user || !ctx.user.id) {
26
+ ctx.response = ErrorResponse(ctx, '未登录');
28
27
  return;
29
28
  }
30
29
 
31
30
  // 3. 开发者权限(最高权限)
32
31
  if (ctx.user.roleCode === 'dev') {
33
- return next();
32
+ return;
34
33
  }
35
34
 
36
35
  // 4. 角色权限检查
@@ -44,11 +43,9 @@ const hook: Hook = {
44
43
  }
45
44
 
46
45
  if (!hasPermission) {
47
- ctx.response = JsonResponse(ctx, '无权访问', 403);
46
+ ctx.response = ErrorResponse(ctx, '无权访问');
48
47
  return;
49
48
  }
50
-
51
- await next();
52
49
  }
53
50
  };
54
51
  export default hook;
@@ -1,6 +1,6 @@
1
1
  // 相对导入
2
2
  import { Validator } from '../lib/validator.js';
3
- import { JsonResponse } from '../util.js';
3
+ import { ErrorResponse } from '../util.js';
4
4
 
5
5
  // 类型导入
6
6
  import type { Hook } from '../types/hook.js';
@@ -10,25 +10,22 @@ import type { Hook } from '../types/hook.js';
10
10
  * 根据 API 定义的 fields 和 required 验证请求参数
11
11
  */
12
12
  const hook: Hook = {
13
- after: ['parser'],
14
- order: 15,
15
- handler: async (befly, ctx, next) => {
16
- if (!ctx.api) return next();
13
+ order: 5,
14
+ handler: async (befly, ctx) => {
15
+ if (!ctx.api) return;
17
16
 
18
17
  // 无需验证
19
18
  if (!ctx.api.fields) {
20
- return next();
19
+ return;
21
20
  }
22
21
 
23
22
  // 验证参数
24
23
  const result = Validator.validate(ctx.body, ctx.api.fields, ctx.api.required || []);
25
24
 
26
25
  if (result.code !== 0) {
27
- ctx.response = JsonResponse(ctx, '无效的请求参数格式', 1, result.fields);
26
+ ctx.response = ErrorResponse(ctx, '无效的请求参数格式', 1, result.fields);
28
27
  return;
29
28
  }
30
-
31
- await next();
32
29
  }
33
30
  };
34
31
  export default hook;
@@ -153,8 +153,6 @@ export class CacheHelper {
153
153
  * 缓存所有数据
154
154
  */
155
155
  async cacheAll(): Promise<void> {
156
- Logger.info('========== 开始缓存数据到 Redis ==========');
157
-
158
156
  // 1. 缓存接口
159
157
  await this.cacheApis();
160
158
 
@@ -163,8 +161,6 @@ export class CacheHelper {
163
161
 
164
162
  // 3. 缓存角色权限
165
163
  await this.cacheRolePermissions();
166
-
167
- Logger.info('========== 数据缓存完成 ==========\n');
168
164
  }
169
165
 
170
166
  /**
@@ -7,18 +7,23 @@ import { SQL, RedisClient } from 'bun';
7
7
  import { Logger } from './logger.js';
8
8
  import { DbHelper } from './dbHelper.js';
9
9
  import { RedisHelper } from './redisHelper.js';
10
- import type { BeflyContext, DatabaseConfig, RedisConfig } from '../types/befly.js';
10
+ import type { BeflyContext, BeflyOptions, DatabaseConfig, RedisConfig } from '../types/befly.js';
11
11
  import type { SqlClientOptions } from '../types/database.js';
12
12
 
13
13
  /**
14
14
  * 数据库连接管理器
15
15
  * 使用静态方法管理全局单例连接
16
16
  */
17
- export class Database {
17
+ export class Connect {
18
18
  private static sqlClient: SQL | null = null;
19
19
  private static redisClient: RedisClient | null = null;
20
20
  private static dbHelper: DbHelper | null = null;
21
21
 
22
+ // 连接统计信息
23
+ private static sqlConnectedAt: number | null = null;
24
+ private static redisConnectedAt: number | null = null;
25
+ private static sqlPoolMax: number = 1;
26
+
22
27
  // ========================================
23
28
  // SQL 连接管理
24
29
  // ========================================
@@ -86,11 +91,11 @@ export class Database {
86
91
  const version = await Promise.race([healthCheckPromise, timeoutPromise]);
87
92
 
88
93
  this.sqlClient = sql;
94
+ this.sqlConnectedAt = Date.now();
95
+ this.sqlPoolMax = config.poolMax ?? 1;
89
96
  return sql;
90
97
  } catch (error: any) {
91
- console.log(finalUrl);
92
- Logger.error('数据库连接测试失败', error);
93
-
98
+ Logger.error('[Connect] SQL 连接失败', error);
94
99
  try {
95
100
  await sql?.close();
96
101
  } catch (cleanupError) {}
@@ -107,9 +112,10 @@ export class Database {
107
112
  try {
108
113
  await this.sqlClient.close();
109
114
  } catch (error: any) {
110
- Logger.error('关闭 SQL 连接时出错', error);
115
+ Logger.error('[Connect] 关闭 SQL 连接时出错', error);
111
116
  }
112
117
  this.sqlClient = null;
118
+ this.sqlConnectedAt = null;
113
119
  }
114
120
 
115
121
  if (this.dbHelper) {
@@ -123,7 +129,7 @@ export class Database {
123
129
  */
124
130
  static getSql(): SQL {
125
131
  if (!this.sqlClient) {
126
- throw new Error('SQL 客户端未连接,请先调用 Database.connectSql()');
132
+ throw new Error('SQL 客户端未连接,请先调用 Connect.connectSql()');
127
133
  }
128
134
  return this.sqlClient;
129
135
  }
@@ -135,7 +141,7 @@ export class Database {
135
141
  static getDbHelper(befly?: BeflyContext): DbHelper {
136
142
  if (!this.dbHelper) {
137
143
  if (!this.sqlClient) {
138
- throw new Error('SQL 客户端未连接,请先调用 Database.connectSql()');
144
+ throw new Error('SQL 客户端未连接,请先调用 Connect.connectSql()');
139
145
  }
140
146
  // 创建临时 befly 上下文(仅用于 DbHelper)
141
147
  const ctx = befly || {
@@ -188,9 +194,10 @@ export class Database {
188
194
  await redis.ping();
189
195
 
190
196
  this.redisClient = redis;
197
+ this.redisConnectedAt = Date.now();
191
198
  return redis;
192
199
  } catch (error: any) {
193
- Logger.error('Redis 连接失败', error);
200
+ Logger.error('[Connect] Redis 连接失败', error);
194
201
  throw new Error(`Redis 连接失败: ${error.message}`);
195
202
  }
196
203
  }
@@ -202,8 +209,9 @@ export class Database {
202
209
  if (this.redisClient) {
203
210
  try {
204
211
  this.redisClient.close();
212
+ this.redisConnectedAt = null;
205
213
  } catch (error: any) {
206
- Logger.error('关闭 Redis 连接时出错', error);
214
+ Logger.error('[Connect] 关闭 Redis 连接时出错', error);
207
215
  }
208
216
  this.redisClient = null;
209
217
  }
@@ -215,7 +223,7 @@ export class Database {
215
223
  */
216
224
  static getRedis(): RedisClient {
217
225
  if (!this.redisClient) {
218
- throw new Error('Redis 客户端未连接,请先调用 Database.connectRedis()');
226
+ throw new Error('Redis 客户端未连接,请先调用 Connect.connectRedis()');
219
227
  }
220
228
  return this.redisClient;
221
229
  }
@@ -226,17 +234,21 @@ export class Database {
226
234
 
227
235
  /**
228
236
  * 连接所有数据库(SQL + Redis)
229
- * @param options - 配置选项
237
+ * @param config - Befly 配置对象(可选)
238
+ * @param options - 连接选项
230
239
  */
231
- static async connect(options?: { sql?: SqlClientOptions; redis?: boolean }): Promise<void> {
240
+ static async connect(config?: BeflyOptions, options?: { sql?: SqlClientOptions; redis?: boolean }): Promise<void> {
232
241
  try {
233
- if (options?.sql !== false) {
234
- await this.connectSql(options?.sql);
242
+ // 如果 sql 参数不是 false,则连接 SQL
243
+ // 优先级:options.sql > config.db > 跳过
244
+ const sqlConfig = options?.db || {};
245
+ if (sqlConfig) {
246
+ await this.connectSql(sqlConfig);
235
247
  }
236
248
 
237
- if (options?.redis !== false) {
238
- await this.connectRedis();
239
- }
249
+ // 如果 redis 参数不是 false,则连接 Redis
250
+ const redisConfig = config?.redis || {};
251
+ await this.connectRedis(redisConfig);
240
252
  } catch (error: any) {
241
253
  Logger.error('数据库初始化失败', error);
242
254
  await this.disconnect();
@@ -262,6 +274,38 @@ export class Database {
262
274
  };
263
275
  }
264
276
 
277
+ /**
278
+ * 获取连接状态详细信息(用于监控和调试)
279
+ */
280
+ static getStatus(): {
281
+ sql: {
282
+ connected: boolean;
283
+ connectedAt: number | null;
284
+ uptime: number | null;
285
+ poolMax: number;
286
+ };
287
+ redis: {
288
+ connected: boolean;
289
+ connectedAt: number | null;
290
+ uptime: number | null;
291
+ };
292
+ } {
293
+ const now = Date.now();
294
+ return {
295
+ sql: {
296
+ connected: this.sqlClient !== null,
297
+ connectedAt: this.sqlConnectedAt,
298
+ uptime: this.sqlConnectedAt ? now - this.sqlConnectedAt : null,
299
+ poolMax: this.sqlPoolMax
300
+ },
301
+ redis: {
302
+ connected: this.redisClient !== null,
303
+ connectedAt: this.redisConnectedAt,
304
+ uptime: this.redisConnectedAt ? now - this.redisConnectedAt : null
305
+ }
306
+ };
307
+ }
308
+
265
309
  // ========================================
266
310
  // 测试辅助方法
267
311
  // ========================================
@@ -287,5 +331,8 @@ export class Database {
287
331
  this.sqlClient = null;
288
332
  this.redisClient = null;
289
333
  this.dbHelper = null;
334
+ this.sqlConnectedAt = null;
335
+ this.redisConnectedAt = null;
336
+ this.sqlPoolMax = 1;
290
337
  }
291
338
  }
package/lib/logger.ts CHANGED
@@ -5,20 +5,9 @@
5
5
 
6
6
  import { join } from 'pathe';
7
7
  import { appendFile, stat } from 'node:fs/promises';
8
- import { AsyncLocalStorage } from 'node:async_hooks';
9
8
  import type { LogLevel } from '../types/common.js';
10
9
  import type { LoggerConfig } from '../types/befly.js';
11
10
 
12
- /**
13
- * 日志上下文存储
14
- */
15
- export interface LogContext {
16
- requestId?: string;
17
- [key: string]: any;
18
- }
19
-
20
- export const logContextStorage = new AsyncLocalStorage<LogContext>();
21
-
22
11
  /**
23
12
  * 日志消息类型
24
13
  */
@@ -84,12 +73,7 @@ export class Logger {
84
73
 
85
74
  // 格式化日志消息
86
75
  const levelStr = level.toUpperCase().padStart(5);
87
-
88
- // 获取上下文中的 requestId
89
- const store = logContextStorage.getStore();
90
- const requestId = store?.requestId ? ` [${store.requestId}]` : '';
91
-
92
- const logMessage = `[${timestamp}]${requestId} ${levelStr} - ${content}`;
76
+ const logMessage = `[${timestamp}] ${levelStr} - ${content}`;
93
77
 
94
78
  // 控制台输出
95
79
  if (this.config.console === 1) {
@@ -3,9 +3,10 @@
3
3
  * 提供 Redis 操作的便捷方法
4
4
  */
5
5
 
6
- import { RedisClient } from 'bun';
7
- import { Logger } from '../lib/logger.js';
8
- import { Database } from './database.js';
6
+ import { SQL, RedisClient } from 'bun';
7
+ import { Logger } from './logger.js';
8
+ import { Connect } from './connect.js';
9
+ import type { KeyValue } from '../types/common.js';
9
10
 
10
11
  /**
11
12
  * Redis 助手类
@@ -19,9 +20,9 @@ export class RedisHelper {
19
20
  * @param prefix - Key 前缀
20
21
  */
21
22
  constructor(prefix: string = '') {
22
- const client = Database.getRedis();
23
+ const client = Connect.getRedis();
23
24
  if (!client) {
24
- throw new Error('Redis 客户端未初始化,请先调用 Database.connectRedis()');
25
+ throw new Error('Redis 客户端未初始化,请先调用 Connect.connectRedis()');
25
26
  }
26
27
  this.client = client;
27
28
  this.prefix = prefix ? `${prefix}:` : '';
@@ -58,9 +58,9 @@ const DEFAULT_API_FIELDS = {
58
58
 
59
59
  /**
60
60
  * 加载所有 API 路由
61
- * @param apiRoutes - API 路由映射表
61
+ * @param apis - API 路由映射表
62
62
  */
63
- export async function loadApis(apiRoutes: Map<string, ApiRoute>): Promise<void> {
63
+ export async function loadApis(apis: Map<string, ApiRoute>): Promise<void> {
64
64
  try {
65
65
  const loadStartTime = Bun.nanoseconds();
66
66
 
@@ -120,7 +120,7 @@ export async function loadApis(apiRoutes: Map<string, ApiRoute>): Promise<void>
120
120
 
121
121
  // 构建路由
122
122
  api.route = `${api.method.toUpperCase()}/api/${apiFile.routePrefix ? apiFile.routePrefix + '/' : ''}${apiFile.relativePath}`;
123
- apiRoutes.set(api.route, api);
123
+ apis.set(api.route, api);
124
124
  } catch (error: any) {
125
125
  Logger.error(`[${apiFile.typeName}] 接口 ${apiFile.relativePath} 加载失败`, error);
126
126
  process.exit(1);
@@ -1,63 +1,37 @@
1
1
  /**
2
2
  * 钩子加载器
3
- * 负责扫描和初始化所有钩子(核心、组件、项目)
3
+ * 只加载核心钩子
4
4
  */
5
5
 
6
- // 外部依赖
7
- import { scanAddons, getAddonDir } from 'befly-util';
8
-
9
6
  // 相对导入
10
7
  import { Logger } from '../lib/logger.js';
11
- import { coreHookDir, projectHookDir } from '../paths.js';
12
- import { sortModules, scanModules } from '../util.js';
8
+ import { coreHookDir } from '../paths.js';
9
+ import { scanModules } from '../util.js';
13
10
 
14
11
  // 类型导入
15
12
  import type { Hook } from '../types/hook.js';
16
13
 
17
- export async function loadHooks(befly: {
18
- //
19
- hookLists: Hook[];
20
- pluginsConfig?: Record<string, any>;
21
- }): Promise<void> {
14
+ export async function loadHooks(pluginsConfig: Record<string, any> | undefined, hooks: Hook[]): Promise<void> {
22
15
  try {
23
- const allHooks: Hook[] = [];
24
-
25
16
  // 1. 扫描核心钩子
26
- const coreHooks = await scanModules<Hook>(coreHookDir, 'core', '钩子', befly.pluginsConfig);
27
-
28
- // 2. 扫描组件钩子
29
- const addonHooks: Hook[] = [];
30
- const addons = scanAddons();
31
- for (const addon of addons) {
32
- const dir = getAddonDir(addon, 'hooks');
33
- const hooks = await scanModules<Hook>(dir, 'addon', '钩子', befly.pluginsConfig, addon);
34
- addonHooks.push(...hooks);
35
- }
17
+ const coreHooks = await scanModules<Hook>(coreHookDir, 'core', '钩子', pluginsConfig);
36
18
 
37
- // 3. 扫描项目钩子
38
- const appHooks = await scanModules<Hook>(projectHookDir, 'app', '钩子', befly.pluginsConfig);
39
-
40
- // 4. 合并所有钩子
41
- allHooks.push(...coreHooks);
42
- allHooks.push(...addonHooks);
43
- allHooks.push(...appHooks);
44
-
45
- // 5. 过滤禁用的钩子
46
- const disableHooks = (befly as any).config?.disableHooks || [];
47
- const enabledHooks = allHooks.filter((hook) => !disableHooks.includes(hook.name));
19
+ // 2. 过滤禁用的钩子
20
+ const disableHooks = (pluginsConfig as any)?.disableHooks || [];
21
+ const enabledHooks = coreHooks.filter((hook) => !disableHooks.includes(hook.name));
48
22
 
49
23
  if (disableHooks.length > 0) {
50
24
  Logger.info(`禁用钩子: ${disableHooks.join(', ')}`);
51
25
  }
52
26
 
53
- // 6. 排序
54
- const sortedHooks = sortModules(enabledHooks);
55
- if (sortedHooks === false) {
56
- Logger.error('钩子依赖关系错误,请检查 after 属性');
57
- process.exit(1);
58
- }
27
+ // 3. 按 order 排序
28
+ const sortedHooks = enabledHooks.sort((a, b) => {
29
+ const orderA = a.order ?? 999;
30
+ const orderB = b.order ?? 999;
31
+ return orderA - orderB;
32
+ });
59
33
 
60
- befly.hookLists.push(...sortedHooks);
34
+ hooks.push(...sortedHooks);
61
35
  } catch (error: any) {
62
36
  Logger.error('加载钩子时发生错误', error);
63
37
  process.exit(1);