befly 3.8.29 → 3.8.31

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 (70) hide show
  1. package/README.md +91 -6
  2. package/checks/checkApi.ts +2 -1
  3. package/checks/checkApp.ts +31 -1
  4. package/checks/checkTable.ts +3 -2
  5. package/hooks/cors.ts +3 -3
  6. package/hooks/parser.ts +8 -6
  7. package/hooks/permission.ts +12 -5
  8. package/hooks/validator.ts +1 -1
  9. package/lib/cacheHelper.ts +73 -65
  10. package/lib/cipher.ts +2 -1
  11. package/lib/connect.ts +23 -52
  12. package/lib/dbHelper.ts +14 -11
  13. package/lib/jwt.ts +58 -437
  14. package/lib/logger.ts +76 -197
  15. package/lib/redisHelper.ts +163 -1
  16. package/lib/sqlBuilder.ts +2 -1
  17. package/lib/validator.ts +150 -384
  18. package/loader/loadApis.ts +4 -7
  19. package/loader/loadHooks.ts +6 -5
  20. package/loader/loadPlugins.ts +11 -13
  21. package/main.ts +26 -53
  22. package/package.json +10 -8
  23. package/paths.ts +0 -6
  24. package/plugins/cipher.ts +1 -1
  25. package/plugins/config.ts +3 -4
  26. package/plugins/db.ts +6 -7
  27. package/plugins/jwt.ts +7 -6
  28. package/plugins/logger.ts +6 -6
  29. package/plugins/redis.ts +9 -13
  30. package/router/api.ts +2 -2
  31. package/router/static.ts +4 -8
  32. package/sync/syncAll.ts +8 -13
  33. package/sync/syncApi.ts +14 -10
  34. package/sync/syncDb/apply.ts +1 -2
  35. package/sync/syncDb.ts +12 -15
  36. package/sync/syncDev.ts +19 -56
  37. package/sync/syncMenu.ts +182 -137
  38. package/tests/cacheHelper.test.ts +327 -0
  39. package/tests/dbHelper-columns.test.ts +5 -20
  40. package/tests/dbHelper-execute.test.ts +14 -68
  41. package/tests/fields-redis-cache.test.ts +5 -3
  42. package/tests/integration.test.ts +17 -32
  43. package/tests/jwt.test.ts +36 -94
  44. package/tests/logger.test.ts +32 -34
  45. package/tests/redisHelper.test.ts +271 -2
  46. package/tests/redisKeys.test.ts +76 -0
  47. package/tests/sync-connection.test.ts +0 -6
  48. package/tests/syncDb-constants.test.ts +12 -12
  49. package/tests/util.test.ts +5 -1
  50. package/tests/validator.test.ts +611 -85
  51. package/types/befly.d.ts +9 -15
  52. package/types/cache.d.ts +73 -0
  53. package/types/common.d.ts +10 -128
  54. package/types/database.d.ts +221 -5
  55. package/types/index.ts +6 -5
  56. package/types/plugin.d.ts +1 -4
  57. package/types/redis.d.ts +37 -2
  58. package/types/table.d.ts +175 -0
  59. package/config.ts +0 -70
  60. package/hooks/_rateLimit.ts +0 -64
  61. package/lib/regexAliases.ts +0 -59
  62. package/lib/xml.ts +0 -383
  63. package/tests/validator-advanced.test.ts +0 -653
  64. package/tests/xml.test.ts +0 -101
  65. package/types/addon.d.ts +0 -50
  66. package/types/crypto.d.ts +0 -23
  67. package/types/jwt.d.ts +0 -99
  68. package/types/logger.d.ts +0 -43
  69. package/types/tool.d.ts +0 -67
  70. package/types/validator.d.ts +0 -43
package/README.md CHANGED
@@ -37,12 +37,14 @@ bunx befly init
37
37
 
38
38
  ```typescript
39
39
  // main.ts
40
- import { Server } from 'befly';
40
+ import { Befly } from 'befly';
41
41
 
42
- await Server({
43
- name: 'My API',
44
- port: 3000
42
+ const app = new Befly({
43
+ appName: 'My API',
44
+ appPort: 3000
45
45
  });
46
+
47
+ await app.start();
46
48
  ```
47
49
 
48
50
  运行项目:
@@ -55,7 +57,7 @@ bun run main.ts
55
57
 
56
58
  ```typescript
57
59
  // apis/user/hello.ts
58
- import type { ApiRoute } from 'befly';
60
+ import type { ApiRoute } from 'befly/types/index';
59
61
 
60
62
  export default {
61
63
  name: '问候接口',
@@ -79,7 +81,7 @@ export default {
79
81
  ### TypeScript 全面支持
80
82
 
81
83
  ```typescript
82
- import type { ApiRoute, BeflyContext } from 'befly';
84
+ import type { ApiRoute, BeflyContext } from 'befly/types/index';
83
85
  import type { User } from './types/models';
84
86
 
85
87
  export default {
@@ -194,6 +196,89 @@ DB_NAME=/path/to/database.sqlite
194
196
  DB_NAME=:memory:
195
197
  ```
196
198
 
199
+ ## ⚙️ 项目配置文件
200
+
201
+ Befly 使用 `befly.config.ts` 作为统一配置文件:
202
+
203
+ ```typescript
204
+ // befly.config.ts
205
+ export const beflyConfig = {
206
+ appName: '我的应用',
207
+ appPort: 3000,
208
+ appHost: '0.0.0.0',
209
+
210
+ // 数据库配置(优先使用环境变量)
211
+ db: {
212
+ type: 'mysql',
213
+ host: '127.0.0.1',
214
+ port: 3306,
215
+ username: 'root',
216
+ password: 'password',
217
+ database: 'my_database'
218
+ },
219
+
220
+ // Redis 配置
221
+ redis: {
222
+ host: '127.0.0.1',
223
+ port: 6379,
224
+ prefix: 'befly:'
225
+ },
226
+
227
+ // CORS 跨域配置
228
+ cors: {
229
+ origin: ['http://localhost:5173'],
230
+ methods: ['GET', 'POST', 'PUT', 'DELETE']
231
+ },
232
+
233
+ // Addon 插件配置
234
+ addons: {
235
+ admin: {
236
+ email: { host: 'smtp.qq.com' }
237
+ }
238
+ }
239
+ };
240
+ ```
241
+
242
+ ### 数据库连接
243
+
244
+ 框架会自动从 `beflyConfig` 获取配置并建立连接,无需手动传参:
245
+
246
+ ```typescript
247
+ import { Connect } from 'befly/lib/connect';
248
+
249
+ // 连接 SQL 数据库(配置自动从 beflyConfig.db 获取)
250
+ await Connect.connectSql();
251
+
252
+ // 连接 Redis(配置自动从 beflyConfig.redis 获取)
253
+ await Connect.connectRedis();
254
+
255
+ // 同时连接 SQL 和 Redis
256
+ await Connect.connect();
257
+
258
+ // 获取连接状态
259
+ const status = Connect.getStatus();
260
+ console.log(status.sql.connected); // true/false
261
+ console.log(status.redis.connected); // true/false
262
+
263
+ // 断开连接
264
+ await Connect.disconnect();
265
+ ```
266
+
267
+ ### 配置文件迁移指南
268
+
269
+ 如果你的项目之前使用 `app.config.ts`,请按以下步骤迁移:
270
+
271
+ 1. **重命名文件**:`app.config.ts` → `befly.config.ts`
272
+ 2. **更新导出名**:`config` → `beflyConfig`
273
+
274
+ ```typescript
275
+ // 旧写法
276
+ export const config = { ... };
277
+
278
+ // 新写法
279
+ export const beflyConfig = { ... };
280
+ ```
281
+
197
282
  ## 📖 文档
198
283
 
199
284
  完整文档请访问 [`/docs` 目录](./docs/):
@@ -3,7 +3,8 @@ import { existsSync } from 'node:fs';
3
3
 
4
4
  // 外部依赖
5
5
  import { isPlainObject } from 'es-toolkit/compat';
6
- import { scanAddons, getAddonDir, addonDirExists, scanFiles } from 'befly-util';
6
+ import { scanFiles } from 'befly-shared/scanFiles';
7
+ import { scanAddons, getAddonDir, addonDirExists } from 'befly-shared/addonHelper';
7
8
 
8
9
  // 相对导入
9
10
  import { Logger } from '../lib/logger.js';
@@ -1,6 +1,6 @@
1
1
  // 内部依赖
2
2
  import { join } from 'node:path';
3
- import { existsSync, mkdirSync } from 'node:fs';
3
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
4
4
 
5
5
  // 相对导入
6
6
  import { Logger } from '../lib/logger.js';
@@ -24,6 +24,36 @@ export async function checkApp(): Promise<void> {
24
24
  if (!existsSync(logsDir)) {
25
25
  mkdirSync(logsDir, { recursive: true });
26
26
  }
27
+
28
+ // 检查并创建 configs 目录和配置文件
29
+ const configsDir = join(projectDir, 'configs');
30
+ if (!existsSync(configsDir)) {
31
+ mkdirSync(configsDir, { recursive: true });
32
+ }
33
+
34
+ // 检查并创建 befly.common.json
35
+ const beflyJsonPath = join(configsDir, 'befly.common.json');
36
+ if (!existsSync(beflyJsonPath)) {
37
+ writeFileSync(beflyJsonPath, '{}', 'utf-8');
38
+ }
39
+
40
+ // 检查并创建 befly.dev.json
41
+ const beflyDevJsonPath = join(configsDir, 'befly.dev.json');
42
+ if (!existsSync(beflyDevJsonPath)) {
43
+ writeFileSync(beflyDevJsonPath, '{}', 'utf-8');
44
+ }
45
+
46
+ // 检查并创建 befly.prod.json
47
+ const beflyProdJsonPath = join(configsDir, 'befly.prod.json');
48
+ if (!existsSync(beflyProdJsonPath)) {
49
+ writeFileSync(beflyProdJsonPath, '{}', 'utf-8');
50
+ }
51
+
52
+ // 检查并创建 befly.local.json
53
+ const beflyLocalJsonPath = join(configsDir, 'befly.local.json');
54
+ if (!existsSync(beflyLocalJsonPath)) {
55
+ writeFileSync(beflyLocalJsonPath, '{}', 'utf-8');
56
+ }
27
57
  } catch (error: any) {
28
58
  Logger.error('项目结构检查过程中出错', error);
29
59
  throw error;
@@ -3,14 +3,15 @@ import { existsSync } from 'node:fs';
3
3
 
4
4
  // 外部依赖
5
5
  import { basename } from 'pathe';
6
- import { scanAddons, getAddonDir, scanFiles } from 'befly-util';
6
+ import { scanFiles } from 'befly-shared/scanFiles';
7
+ import { scanAddons, getAddonDir } from 'befly-shared/addonHelper';
7
8
 
8
9
  // 相对导入
9
10
  import { Logger } from '../lib/logger.js';
10
11
  import { projectTableDir } from '../paths.js';
11
12
 
12
13
  // 类型导入
13
- import type { FieldDefinition } from '../types/common.js';
14
+ import type { FieldDefinition } from 'befly-shared/types';
14
15
 
15
16
  /**
16
17
  * 表文件信息接口
package/hooks/cors.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  // 相对导入
2
2
  import { setCorsOptions } from '../util.js';
3
+ import { beflyConfig } from '../befly.config.js';
3
4
 
4
5
  // 类型导入
5
6
  import type { Hook } from '../types/hook.js';
@@ -24,11 +25,10 @@ const hook: Hook = {
24
25
  credentials: 'true'
25
26
  };
26
27
 
27
- const userConfig = (hook as any).config || {};
28
- const config = { ...defaultConfig, ...userConfig };
28
+ const corsConfig = { ...defaultConfig, ...(beflyConfig.cors || {}) };
29
29
 
30
30
  // 设置 CORS 响应头
31
- const headers = setCorsOptions(req, config);
31
+ const headers = setCorsOptions(req, corsConfig);
32
32
 
33
33
  ctx.corsHeaders = headers;
34
34
 
package/hooks/parser.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  // 外部依赖
2
2
  import { isPlainObject, isEmpty } from 'es-toolkit/compat';
3
- import { pickFields } from 'befly-util';
3
+ import { pickFields } from 'befly-shared/pickFields';
4
+ import { XMLParser } from 'fast-xml-parser';
4
5
 
5
6
  // 相对导入
6
- import { Xml } from '../lib/xml.js';
7
7
  import { ErrorResponse } from '../util.js';
8
8
 
9
9
  // 类型导入
10
10
  import type { Hook } from '../types/hook.js';
11
11
 
12
+ const xmlParser = new XMLParser();
13
+
12
14
  /**
13
15
  * 请求参数解析钩子
14
16
  * - GET 请求:解析 URL 查询参数
@@ -43,7 +45,7 @@ const hook: Hook = {
43
45
  } else if (contentType.includes('application/xml') || contentType.includes('text/xml')) {
44
46
  // XML 格式
45
47
  const text = await ctx.req.text();
46
- const body = await Xml.parse(text);
48
+ const body = xmlParser.parse(text);
47
49
  if (isPlainObject(ctx.api.fields) && !isEmpty(ctx.api.fields)) {
48
50
  ctx.body = pickFields(body, Object.keys(ctx.api.fields));
49
51
  } else {
@@ -51,12 +53,12 @@ const hook: Hook = {
51
53
  }
52
54
  } else {
53
55
  // 不支持的 Content-Type
54
- ctx.response = ErrorResponse(ctx, '无效的请求参数格式');
56
+ ctx.response = ErrorResponse(ctx, '无效的请求参数格式', 1, null, { location: 'content-type', value: contentType });
55
57
  return;
56
58
  }
57
- } catch (e) {
59
+ } catch (e: any) {
58
60
  // 解析失败
59
- ctx.response = ErrorResponse(ctx, '无效的请求参数格式');
61
+ ctx.response = ErrorResponse(ctx, '无效的请求参数格式', 1, null, { location: 'body', error: e.message });
60
62
  return;
61
63
  }
62
64
  }
@@ -1,5 +1,6 @@
1
1
  // 相对导入
2
2
  import { ErrorResponse } from '../util.js';
3
+ import { RedisKeys } from 'befly-shared/redisKeys';
3
4
 
4
5
  // 类型导入
5
6
  import type { Hook } from '../types/hook.js';
@@ -35,11 +36,17 @@ const hook: Hook = {
35
36
  // 4. 角色权限检查
36
37
  let hasPermission = false;
37
38
  if (ctx.user.roleCode && befly.redis) {
38
- // 验证角色权限
39
- const apiPath = `${ctx.req.method}${new URL(ctx.req.url).pathname}`;
40
- const roleApisKey = `role:apis:${ctx.user.roleCode}`;
41
- const isMember = await befly.redis.sismember(roleApisKey, apiPath);
42
- hasPermission = isMember === 1;
39
+ try {
40
+ // 验证角色权限
41
+ const apiPath = `${ctx.req.method}${new URL(ctx.req.url).pathname}`;
42
+ const roleApisKey = RedisKeys.roleApis(ctx.user.roleCode);
43
+ const isMember = await befly.redis.sismember(roleApisKey, apiPath);
44
+ hasPermission = isMember === 1;
45
+ } catch (error) {
46
+ // Redis 异常时降级为拒绝访问
47
+ befly.logger.warn({ err: error, route: ctx.route }, 'Redis 权限检查失败');
48
+ hasPermission = false;
49
+ }
43
50
  }
44
51
 
45
52
  if (!hasPermission) {
@@ -23,7 +23,7 @@ const hook: Hook = {
23
23
  const result = Validator.validate(ctx.body, ctx.api.fields, ctx.api.required || []);
24
24
 
25
25
  if (result.code !== 0) {
26
- ctx.response = ErrorResponse(ctx, '无效的请求参数格式', 1, result.fields);
26
+ ctx.response = ErrorResponse(ctx, result.firstError || '参数验证失败', 1, null, result.fieldErrors);
27
27
  return;
28
28
  }
29
29
  }
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import { Logger } from './logger.js';
7
+ import { RedisKeys } from 'befly-shared/redisKeys';
8
+
7
9
  import type { BeflyContext } from '../types/befly.js';
8
10
 
9
11
  /**
@@ -26,29 +28,27 @@ export class CacheHelper {
26
28
  async cacheApis(): Promise<void> {
27
29
  try {
28
30
  // 检查表是否存在
29
- const tableExists = await this.befly.db.tableExists('core_api');
31
+ const tableExists = await this.befly.db.tableExists('addon_admin_api');
30
32
  if (!tableExists) {
31
33
  Logger.warn('⚠️ 接口表不存在,跳过接口缓存');
32
34
  return;
33
35
  }
34
36
 
35
- // 从数据库查询所有接口(与 apiAll.ts 保持一致)
37
+ // 从数据库查询所有接口
36
38
  const apiList = await this.befly.db.getAll({
37
- table: 'core_api',
39
+ table: 'addon_admin_api',
38
40
  fields: ['id', 'name', 'path', 'method', 'description', 'addonName', 'addonTitle'],
39
41
  orderBy: ['addonName#ASC', 'path#ASC']
40
42
  });
41
43
 
42
44
  // 缓存到 Redis
43
- const result = await this.befly.redis.setObject('apis:all', apiList);
45
+ const result = await this.befly.redis.setObject(RedisKeys.apisAll(), apiList);
44
46
 
45
47
  if (result === null) {
46
48
  Logger.warn('⚠️ 接口缓存失败');
47
- } else {
48
- Logger.info(`✅ 已缓存 ${apiList.length} 个接口到 Redis (Key: apis:all)`);
49
49
  }
50
50
  } catch (error: any) {
51
- Logger.error('⚠️ 接口缓存异常:', error);
51
+ Logger.error({ err: error }, '⚠️ 接口缓存异常');
52
52
  }
53
53
  }
54
54
 
@@ -58,7 +58,7 @@ export class CacheHelper {
58
58
  async cacheMenus(): Promise<void> {
59
59
  try {
60
60
  // 检查表是否存在
61
- const tableExists = await this.befly.db.tableExists('core_menu');
61
+ const tableExists = await this.befly.db.tableExists('addon_admin_menu');
62
62
  if (!tableExists) {
63
63
  Logger.warn('⚠️ 菜单表不存在,跳过菜单缓存');
64
64
  return;
@@ -66,86 +66,97 @@ export class CacheHelper {
66
66
 
67
67
  // 从数据库查询所有菜单
68
68
  const menus = await this.befly.db.getAll({
69
- table: 'core_menu',
69
+ table: 'addon_admin_menu',
70
70
  fields: ['id', 'pid', 'name', 'path', 'icon', 'type', 'sort'],
71
71
  orderBy: ['sort#ASC', 'id#ASC']
72
72
  });
73
73
 
74
74
  // 缓存到 Redis
75
- const result = await this.befly.redis.setObject('menus:all', menus);
75
+ const result = await this.befly.redis.setObject(RedisKeys.menusAll(), menus);
76
76
 
77
77
  if (result === null) {
78
78
  Logger.warn('⚠️ 菜单缓存失败');
79
- } else {
80
- Logger.info(`✅ 已缓存 ${menus.length} 个菜单到 Redis (Key: menus:all)`);
81
79
  }
82
80
  } catch (error: any) {
83
- const errorMessage = error?.message || error?.toString?.() || String(error);
84
- Logger.warn('⚠️ 菜单缓存异常:', errorMessage);
81
+ Logger.warn({ err: error }, '⚠️ 菜单缓存异常');
85
82
  }
86
83
  }
87
84
 
88
85
  /**
89
86
  * 缓存所有角色的接口权限到 Redis
87
+ * 优化:使用 Promise.all 利用 Bun Redis 自动 pipeline 特性
90
88
  */
91
89
  async cacheRolePermissions(): Promise<void> {
92
90
  try {
93
91
  // 检查表是否存在
94
- const apiTableExists = await this.befly.db.tableExists('core_api');
95
- const roleTableExists = await this.befly.db.tableExists('core_role');
92
+ const apiTableExists = await this.befly.db.tableExists('addon_admin_api');
93
+ const roleTableExists = await this.befly.db.tableExists('addon_admin_role');
96
94
 
97
95
  if (!apiTableExists || !roleTableExists) {
98
96
  Logger.warn('⚠️ 接口或角色表不存在,跳过角色权限缓存');
99
97
  return;
100
98
  }
101
99
 
102
- // 查询所有角色
103
- const roles = await this.befly.db.getAll({
104
- table: 'core_role',
105
- fields: ['id', 'code', 'apis']
106
- });
100
+ // 并行查询角色和接口(利用自动 pipeline)
101
+ const [roles, allApis] = await Promise.all([
102
+ this.befly.db.getAll({
103
+ table: 'addon_admin_role',
104
+ fields: ['id', 'code', 'apis']
105
+ }),
106
+ this.befly.db.getAll({
107
+ table: 'addon_admin_api',
108
+ fields: ['id', 'path', 'method']
109
+ })
110
+ ]);
111
+
112
+ // 构建接口 ID -> 路径的映射(避免重复过滤)
113
+ const apiMap = new Map<number, string>();
114
+ for (const api of allApis) {
115
+ apiMap.set(api.id, `${api.method}${api.path}`);
116
+ }
107
117
 
108
- // 查询所有接口(用于权限映射)
109
- const allApis = await this.befly.db.getAll({
110
- table: 'core_api',
111
- fields: ['id', 'name', 'path', 'method', 'description', 'addonName']
112
- });
118
+ // 收集需要缓存的角色权限
119
+ const cacheOperations: Array<{ roleCode: string; apiPaths: string[] }> = [];
113
120
 
114
- // 为每个角色缓存接口权限
115
- let cachedRoles = 0;
116
121
  for (const role of roles) {
117
122
  if (!role.apis) continue;
118
123
 
119
- // 解析角色的接口 ID 列表
120
- const apiIds = role.apis
121
- .split(',')
122
- .map((id: string) => parseInt(id.trim()))
123
- .filter((id: number) => !isNaN(id));
124
-
125
- // 根据 ID 过滤出接口路径
126
- const roleApiPaths = allApis.filter((api: any) => apiIds.includes(api.id)).map((api: any) => `${api.method}${api.path}`);
127
-
128
- if (roleApiPaths.length === 0) continue;
124
+ // 解析角色的接口 ID 列表并映射到路径
125
+ const apiPaths: string[] = [];
126
+ const apiIds = role.apis.split(',');
127
+
128
+ for (const idStr of apiIds) {
129
+ const id = parseInt(idStr.trim());
130
+ if (!isNaN(id)) {
131
+ const path = apiMap.get(id);
132
+ if (path) {
133
+ apiPaths.push(path);
134
+ }
135
+ }
136
+ }
129
137
 
130
- // 使用 Redis Set 缓存角色权限(性能优化:SADD + SISMEMBER)
131
- const redisKey = `role:apis:${role.code}`;
138
+ if (apiPaths.length > 0) {
139
+ cacheOperations.push({ roleCode: role.code, apiPaths: apiPaths });
140
+ }
141
+ }
132
142
 
133
- // 先删除旧数据
134
- await this.befly.redis.del(redisKey);
143
+ if (cacheOperations.length === 0) {
144
+ Logger.info('✅ 没有需要缓存的角色权限');
145
+ return;
146
+ }
135
147
 
136
- // 批量添加到 Set
137
- const result = await this.befly.redis.sadd(redisKey, roleApiPaths);
148
+ // 批量删除旧缓存(利用自动 pipeline)
149
+ const deletePromises = cacheOperations.map((op) => this.befly.redis.del(RedisKeys.roleApis(op.roleCode)));
150
+ await Promise.all(deletePromises);
138
151
 
139
- if (result > 0) {
140
- cachedRoles++;
141
- Logger.debug(` └ 角色 ${role.code}: ${result} 个接口`);
142
- }
143
- }
152
+ // 批量添加新缓存(利用自动 pipeline)
153
+ const addPromises = cacheOperations.map((op) => this.befly.redis.sadd(RedisKeys.roleApis(op.roleCode), op.apiPaths));
154
+ const results = await Promise.all(addPromises);
144
155
 
145
- Logger.info(`✅ 已缓存 ${cachedRoles} 个角色的接口权限`);
156
+ // 统计成功缓存的角色数
157
+ const cachedRoles = results.filter((r) => r > 0).length;
146
158
  } catch (error: any) {
147
- const errorMessage = error?.message || error?.toString?.() || String(error);
148
- Logger.warn('⚠️ 角色权限缓存异常:', errorMessage);
159
+ Logger.warn({ err: error }, '⚠️ 角色权限缓存异常');
149
160
  }
150
161
  }
151
162
 
@@ -169,10 +180,10 @@ export class CacheHelper {
169
180
  */
170
181
  async getApis(): Promise<any[]> {
171
182
  try {
172
- const apis = await this.befly.redis.getObject<any[]>('apis:all');
183
+ const apis = await this.befly.redis.getObject<any[]>(RedisKeys.apisAll());
173
184
  return apis || [];
174
185
  } catch (error: any) {
175
- Logger.error('获取接口缓存失败:', error);
186
+ Logger.error({ err: error }, '获取接口缓存失败');
176
187
  return [];
177
188
  }
178
189
  }
@@ -183,10 +194,10 @@ export class CacheHelper {
183
194
  */
184
195
  async getMenus(): Promise<any[]> {
185
196
  try {
186
- const menus = await this.befly.redis.getObject<any[]>('menus:all');
197
+ const menus = await this.befly.redis.getObject<any[]>(RedisKeys.menusAll());
187
198
  return menus || [];
188
199
  } catch (error: any) {
189
- Logger.error('获取菜单缓存失败:', error);
200
+ Logger.error({ err: error }, '获取菜单缓存失败');
190
201
  return [];
191
202
  }
192
203
  }
@@ -198,11 +209,10 @@ export class CacheHelper {
198
209
  */
199
210
  async getRolePermissions(roleCode: string): Promise<string[]> {
200
211
  try {
201
- const redisKey = `role:apis:${roleCode}`;
202
- const permissions = await this.befly.redis.smembers(redisKey);
212
+ const permissions = await this.befly.redis.smembers(RedisKeys.roleApis(roleCode));
203
213
  return permissions || [];
204
214
  } catch (error: any) {
205
- Logger.error(`获取角色 ${roleCode} 权限缓存失败:`, error);
215
+ Logger.error({ err: error, roleCode: roleCode }, '获取角色权限缓存失败');
206
216
  return [];
207
217
  }
208
218
  }
@@ -215,11 +225,10 @@ export class CacheHelper {
215
225
  */
216
226
  async checkRolePermission(roleCode: string, apiPath: string): Promise<boolean> {
217
227
  try {
218
- const redisKey = `role:apis:${roleCode}`;
219
- const result = await this.befly.redis.sismember(redisKey, apiPath);
228
+ const result = await this.befly.redis.sismember(RedisKeys.roleApis(roleCode), apiPath);
220
229
  return result === 1;
221
230
  } catch (error: any) {
222
- Logger.error(`检查角色 ${roleCode} 权限失败:`, error);
231
+ Logger.error({ err: error, roleCode: roleCode }, '检查角色权限失败');
223
232
  return false;
224
233
  }
225
234
  }
@@ -231,15 +240,14 @@ export class CacheHelper {
231
240
  */
232
241
  async deleteRolePermissions(roleCode: string): Promise<boolean> {
233
242
  try {
234
- const redisKey = `role:apis:${roleCode}`;
235
- const result = await this.befly.redis.del(redisKey);
243
+ const result = await this.befly.redis.del(RedisKeys.roleApis(roleCode));
236
244
  if (result > 0) {
237
245
  Logger.info(`✅ 已删除角色 ${roleCode} 的权限缓存`);
238
246
  return true;
239
247
  }
240
248
  return false;
241
249
  } catch (error: any) {
242
- Logger.error(`删除角色 ${roleCode} 权限缓存失败:`, error);
250
+ Logger.error({ err: error, roleCode: roleCode }, '删除角色权限缓存失败');
243
251
  return false;
244
252
  }
245
253
  }
package/lib/cipher.ts CHANGED
@@ -4,7 +4,8 @@
4
4
  */
5
5
 
6
6
  import { createSign } from 'node:crypto';
7
- import type { EncodingType, HashAlgorithm, PasswordHashOptions } from '../types/crypto';
7
+
8
+ import type { EncodingType, HashAlgorithm, PasswordHashOptions } from 'befly-shared/types';
8
9
 
9
10
  /**
10
11
  * 加密工具类