befly 3.10.18 → 3.11.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.
Files changed (223) hide show
  1. package/README.md +83 -307
  2. package/dist/befly.config.d.ts +7 -0
  3. package/{befly.config.ts → dist/befly.config.js} +11 -36
  4. package/dist/befly.js +15621 -0
  5. package/dist/befly.min.js +21 -0
  6. package/dist/checks/checkApi.d.ts +1 -0
  7. package/{checks/checkApi.ts → dist/checks/checkApi.js} +12 -30
  8. package/dist/checks/checkHook.d.ts +1 -0
  9. package/dist/checks/checkHook.js +86 -0
  10. package/dist/checks/checkMenu.d.ts +7 -0
  11. package/{checks/checkMenu.ts → dist/checks/checkMenu.js} +18 -53
  12. package/dist/checks/checkPlugin.d.ts +1 -0
  13. package/dist/checks/checkPlugin.js +86 -0
  14. package/dist/checks/checkTable.d.ts +6 -0
  15. package/{checks/checkTable.ts → dist/checks/checkTable.js} +17 -41
  16. package/dist/configs/presetFields.d.ts +4 -0
  17. package/{configs/presetFields.ts → dist/configs/presetFields.js} +1 -1
  18. package/dist/configs/presetRegexp.d.ts +145 -0
  19. package/{utils/regex.ts → dist/configs/presetRegexp.js} +8 -31
  20. package/dist/hooks/auth.d.ts +7 -0
  21. package/{hooks/auth.ts → dist/hooks/auth.js} +8 -10
  22. package/dist/hooks/cors.d.ts +11 -0
  23. package/{hooks/cors.ts → dist/hooks/cors.js} +5 -13
  24. package/dist/hooks/parser.d.ts +14 -0
  25. package/{hooks/parser.ts → dist/hooks/parser.js} +31 -45
  26. package/dist/hooks/permission.d.ts +14 -0
  27. package/{hooks/permission.ts → dist/hooks/permission.js} +16 -25
  28. package/dist/hooks/validator.d.ts +11 -0
  29. package/{hooks/validator.ts → dist/hooks/validator.js} +9 -14
  30. package/dist/index.d.ts +26 -0
  31. package/{main.ts → dist/index.js} +61 -100
  32. package/dist/lib/asyncContext.d.ts +21 -0
  33. package/dist/lib/asyncContext.js +27 -0
  34. package/dist/lib/cacheHelper.d.ts +95 -0
  35. package/{lib/cacheHelper.ts → dist/lib/cacheHelper.js} +45 -105
  36. package/dist/lib/cacheKeys.d.ts +23 -0
  37. package/{lib/cacheKeys.ts → dist/lib/cacheKeys.js} +5 -10
  38. package/dist/lib/cipher.d.ts +153 -0
  39. package/{lib/cipher.ts → dist/lib/cipher.js} +23 -44
  40. package/dist/lib/connect.d.ts +91 -0
  41. package/{lib/connect.ts → dist/lib/connect.js} +47 -88
  42. package/dist/lib/dbDialect.d.ts +87 -0
  43. package/{lib/dbDialect.ts → dist/lib/dbDialect.js} +32 -112
  44. package/dist/lib/dbHelper.d.ts +204 -0
  45. package/{lib/dbHelper.ts → dist/lib/dbHelper.js} +82 -241
  46. package/dist/lib/dbUtils.d.ts +68 -0
  47. package/{lib/dbUtils.ts → dist/lib/dbUtils.js} +51 -126
  48. package/dist/lib/jwt.d.ts +13 -0
  49. package/{lib/jwt.ts → dist/lib/jwt.js} +11 -32
  50. package/dist/lib/logger.d.ts +42 -0
  51. package/dist/lib/logger.js +1144 -0
  52. package/dist/lib/redisHelper.d.ts +185 -0
  53. package/{lib/redisHelper.ts → dist/lib/redisHelper.js} +97 -141
  54. package/dist/lib/sqlBuilder.d.ts +160 -0
  55. package/{lib/sqlBuilder.ts → dist/lib/sqlBuilder.js} +132 -278
  56. package/dist/lib/sqlCheck.d.ts +23 -0
  57. package/{lib/sqlCheck.ts → dist/lib/sqlCheck.js} +24 -41
  58. package/dist/lib/validator.d.ts +45 -0
  59. package/{lib/validator.ts → dist/lib/validator.js} +44 -61
  60. package/dist/loader/loadApis.d.ts +12 -0
  61. package/{loader/loadApis.ts → dist/loader/loadApis.js} +10 -20
  62. package/dist/loader/loadHooks.d.ts +7 -0
  63. package/dist/loader/loadHooks.js +35 -0
  64. package/dist/loader/loadPlugins.d.ts +8 -0
  65. package/{loader/loadPlugins.ts → dist/loader/loadPlugins.js} +14 -26
  66. package/dist/paths.d.ts +93 -0
  67. package/{paths.ts → dist/paths.js} +6 -19
  68. package/dist/plugins/cache.d.ts +16 -0
  69. package/{plugins/cache.ts → dist/plugins/cache.js} +7 -12
  70. package/dist/plugins/cipher.d.ts +12 -0
  71. package/{plugins/cipher.ts → dist/plugins/cipher.js} +4 -6
  72. package/dist/plugins/config.d.ts +12 -0
  73. package/dist/plugins/config.js +8 -0
  74. package/dist/plugins/db.d.ts +16 -0
  75. package/{plugins/db.ts → dist/plugins/db.js} +11 -17
  76. package/dist/plugins/jwt.d.ts +12 -0
  77. package/dist/plugins/jwt.js +12 -0
  78. package/dist/plugins/logger.d.ts +32 -0
  79. package/{plugins/logger.ts → dist/plugins/logger.js} +5 -8
  80. package/dist/plugins/redis.d.ts +16 -0
  81. package/{plugins/redis.ts → dist/plugins/redis.js} +9 -12
  82. package/dist/plugins/tool.d.ts +81 -0
  83. package/{plugins/tool.ts → dist/plugins/tool.js} +9 -30
  84. package/dist/router/api.d.ts +14 -0
  85. package/dist/router/api.js +107 -0
  86. package/dist/router/static.d.ts +9 -0
  87. package/{router/static.ts → dist/router/static.js} +20 -34
  88. package/dist/scripts/ensureDist.d.ts +1 -0
  89. package/dist/scripts/ensureDist.js +296 -0
  90. package/dist/sync/syncApi.d.ts +3 -0
  91. package/{sync/syncApi.ts → dist/sync/syncApi.js} +35 -55
  92. package/dist/sync/syncCache.d.ts +2 -0
  93. package/{sync/syncCache.ts → dist/sync/syncCache.js} +1 -6
  94. package/dist/sync/syncDev.d.ts +6 -0
  95. package/{sync/syncDev.ts → dist/sync/syncDev.js} +29 -62
  96. package/dist/sync/syncMenu.d.ts +14 -0
  97. package/{sync/syncMenu.ts → dist/sync/syncMenu.js} +65 -125
  98. package/dist/sync/syncTable.d.ts +151 -0
  99. package/{sync/syncTable.ts → dist/sync/syncTable.js} +172 -379
  100. package/{types → dist/types}/api.d.ts +12 -51
  101. package/dist/types/api.js +4 -0
  102. package/{types → dist/types}/befly.d.ts +32 -227
  103. package/dist/types/befly.js +4 -0
  104. package/{types → dist/types}/cache.d.ts +7 -15
  105. package/dist/types/cache.js +4 -0
  106. package/dist/types/cipher.d.ts +27 -0
  107. package/dist/types/cipher.js +7 -0
  108. package/{types → dist/types}/common.d.ts +8 -33
  109. package/dist/types/common.js +5 -0
  110. package/{types → dist/types}/context.d.ts +3 -5
  111. package/dist/types/context.js +4 -0
  112. package/{types → dist/types}/crypto.d.ts +0 -3
  113. package/dist/types/crypto.js +4 -0
  114. package/dist/types/database.d.ts +138 -0
  115. package/dist/types/database.js +4 -0
  116. package/dist/types/hook.d.ts +17 -0
  117. package/dist/types/hook.js +6 -0
  118. package/dist/types/jwt.d.ts +75 -0
  119. package/dist/types/jwt.js +4 -0
  120. package/dist/types/logger.d.ts +59 -0
  121. package/dist/types/logger.js +6 -0
  122. package/dist/types/plugin.d.ts +16 -0
  123. package/dist/types/plugin.js +6 -0
  124. package/dist/types/redis.d.ts +71 -0
  125. package/dist/types/redis.js +4 -0
  126. package/{types/roleApisCache.ts → dist/types/roleApisCache.d.ts} +0 -2
  127. package/dist/types/roleApisCache.js +8 -0
  128. package/dist/types/sync.d.ts +92 -0
  129. package/dist/types/sync.js +4 -0
  130. package/dist/types/table.d.ts +34 -0
  131. package/dist/types/table.js +4 -0
  132. package/dist/types/validate.d.ts +67 -0
  133. package/dist/types/validate.js +4 -0
  134. package/dist/utils/calcPerfTime.d.ts +4 -0
  135. package/{utils/calcPerfTime.ts → dist/utils/calcPerfTime.js} +3 -3
  136. package/dist/utils/convertBigIntFields.d.ts +11 -0
  137. package/{utils/convertBigIntFields.ts → dist/utils/convertBigIntFields.js} +5 -9
  138. package/dist/utils/cors.d.ts +8 -0
  139. package/{utils/cors.ts → dist/utils/cors.js} +1 -3
  140. package/dist/utils/disableMenusGlob.d.ts +13 -0
  141. package/{utils/disableMenusGlob.ts → dist/utils/disableMenusGlob.js} +9 -29
  142. package/dist/utils/fieldClear.d.ts +11 -0
  143. package/{utils/fieldClear.ts → dist/utils/fieldClear.js} +15 -33
  144. package/dist/utils/getClientIp.d.ts +6 -0
  145. package/{utils/getClientIp.ts → dist/utils/getClientIp.js} +1 -7
  146. package/dist/utils/importDefault.d.ts +1 -0
  147. package/dist/utils/importDefault.js +29 -0
  148. package/dist/utils/isDirentDirectory.d.ts +2 -0
  149. package/{utils/isDirentDirectory.ts → dist/utils/isDirentDirectory.js} +3 -8
  150. package/dist/utils/loadMenuConfigs.d.ts +29 -0
  151. package/{utils/loadMenuConfigs.ts → dist/utils/loadMenuConfigs.js} +66 -52
  152. package/dist/utils/mergeAndConcat.d.ts +7 -0
  153. package/dist/utils/mergeAndConcat.js +72 -0
  154. package/dist/utils/processAtSymbol.d.ts +4 -0
  155. package/{utils/processFields.ts → dist/utils/processAtSymbol.js} +5 -9
  156. package/dist/utils/processInfo.d.ts +24 -0
  157. package/{utils/process.ts → dist/utils/processInfo.js} +2 -18
  158. package/dist/utils/response.d.ts +20 -0
  159. package/{utils/response.ts → dist/utils/response.js} +28 -49
  160. package/dist/utils/scanAddons.d.ts +17 -0
  161. package/{utils/scanAddons.ts → dist/utils/scanAddons.js} +7 -41
  162. package/dist/utils/scanConfig.d.ts +26 -0
  163. package/{utils/scanConfig.ts → dist/utils/scanConfig.js} +28 -66
  164. package/dist/utils/scanCoreBuiltins.d.ts +3 -0
  165. package/dist/utils/scanCoreBuiltins.js +65 -0
  166. package/dist/utils/scanFiles.d.ts +30 -0
  167. package/{utils/scanFiles.ts → dist/utils/scanFiles.js} +44 -71
  168. package/dist/utils/scanSources.d.ts +10 -0
  169. package/dist/utils/scanSources.js +46 -0
  170. package/dist/utils/sortModules.d.ts +28 -0
  171. package/{utils/sortModules.ts → dist/utils/sortModules.js} +26 -66
  172. package/dist/utils/util.d.ts +84 -0
  173. package/dist/utils/util.js +262 -0
  174. package/package.json +26 -34
  175. package/.gitignore +0 -0
  176. package/bunfig.toml +0 -3
  177. package/checks/checkHook.ts +0 -48
  178. package/checks/checkPlugin.ts +0 -48
  179. package/configs/presetRegexp.ts +0 -225
  180. package/docs/README.md +0 -98
  181. package/docs/api/api.md +0 -1921
  182. package/docs/guide/examples.md +0 -926
  183. package/docs/guide/quickstart.md +0 -354
  184. package/docs/hooks/auth.md +0 -38
  185. package/docs/hooks/cors.md +0 -28
  186. package/docs/hooks/hook.md +0 -838
  187. package/docs/hooks/parser.md +0 -19
  188. package/docs/hooks/rateLimit.md +0 -47
  189. package/docs/infra/redis.md +0 -628
  190. package/docs/plugins/cipher.md +0 -61
  191. package/docs/plugins/database.md +0 -189
  192. package/docs/plugins/plugin.md +0 -986
  193. package/docs/reference/addon.md +0 -510
  194. package/docs/reference/config.md +0 -573
  195. package/docs/reference/logger.md +0 -495
  196. package/docs/reference/sync.md +0 -478
  197. package/docs/reference/table.md +0 -763
  198. package/docs/reference/validator.md +0 -620
  199. package/lib/asyncContext.ts +0 -43
  200. package/lib/logger.ts +0 -811
  201. package/loader/loadHooks.ts +0 -51
  202. package/plugins/config.ts +0 -13
  203. package/plugins/jwt.ts +0 -15
  204. package/router/api.ts +0 -130
  205. package/tsconfig.json +0 -8
  206. package/types/database.d.ts +0 -541
  207. package/types/hook.d.ts +0 -25
  208. package/types/jwt.d.ts +0 -118
  209. package/types/logger.d.ts +0 -65
  210. package/types/plugin.d.ts +0 -19
  211. package/types/redis.d.ts +0 -83
  212. package/types/sync.d.ts +0 -398
  213. package/types/table.d.ts +0 -216
  214. package/types/validate.d.ts +0 -69
  215. package/utils/arrayKeysToCamel.ts +0 -18
  216. package/utils/configTypes.ts +0 -3
  217. package/utils/genShortId.ts +0 -12
  218. package/utils/importDefault.ts +0 -21
  219. package/utils/keysToCamel.ts +0 -22
  220. package/utils/keysToSnake.ts +0 -22
  221. package/utils/pickFields.ts +0 -19
  222. package/utils/scanSources.ts +0 -64
  223. package/utils/sqlLog.ts +0 -37
@@ -0,0 +1,95 @@
1
+ /**
2
+ * 缓存助手 - TypeScript 版本
3
+ * 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
4
+ */
5
+ type CacheHelperDb = {
6
+ tableExists(table: string): Promise<{
7
+ data: boolean;
8
+ }>;
9
+ getAll(options: any): Promise<{
10
+ data: {
11
+ lists: any[];
12
+ };
13
+ }>;
14
+ };
15
+ type CacheHelperRedis = {
16
+ setObject<T = any>(key: string, obj: T, ttl?: number | null): Promise<string | null>;
17
+ getObject<T = any>(key: string): Promise<T | null>;
18
+ del(key: string): Promise<number>;
19
+ delBatch(keys: string[]): Promise<number>;
20
+ sadd(key: string, members: string[]): Promise<number>;
21
+ saddBatch(items: Array<{
22
+ key: string;
23
+ members: string[];
24
+ }>): Promise<number>;
25
+ smembers(key: string): Promise<string[]>;
26
+ sismember(key: string, member: string): Promise<boolean>;
27
+ };
28
+ type CacheHelperDeps = {
29
+ db: CacheHelperDb;
30
+ redis: CacheHelperRedis;
31
+ };
32
+ /**
33
+ * 缓存助手类
34
+ */
35
+ export declare class CacheHelper {
36
+ private db;
37
+ private redis;
38
+ constructor(deps: CacheHelperDeps);
39
+ private assertApiPathname;
40
+ private assertApiPathList;
41
+ /**
42
+ * 缓存所有接口到 Redis
43
+ */
44
+ cacheApis(): Promise<void>;
45
+ /**
46
+ * 缓存所有菜单到 Redis(从数据库读取)
47
+ */
48
+ cacheMenus(): Promise<void>;
49
+ /**
50
+ * 缓存所有角色的接口权限到 Redis
51
+ * 全量重建:清理所有角色权限缓存并重建
52
+ * - 极简方案:每个角色一个 Set,直接覆盖更新(DEL + SADD)
53
+ */
54
+ rebuildRoleApiPermissions(): Promise<void>;
55
+ /**
56
+ * 增量刷新单个角色的接口权限缓存
57
+ * - apiIds 为空数组:仅清理缓存(防止残留)
58
+ * - apiIds 非空:使用 $in 最小查询,DEL 后 SADD
59
+ */
60
+ refreshRoleApiPermissions(roleCode: string, apiPaths: string[]): Promise<void>;
61
+ /**
62
+ * 缓存所有数据
63
+ */
64
+ cacheAll(): Promise<void>;
65
+ /**
66
+ * 获取缓存的所有接口
67
+ * @returns 接口列表
68
+ */
69
+ getApis(): Promise<any[]>;
70
+ /**
71
+ * 获取缓存的所有菜单
72
+ * @returns 菜单列表
73
+ */
74
+ getMenus(): Promise<any[]>;
75
+ /**
76
+ * 获取角色的接口权限
77
+ * @param roleCode - 角色代码
78
+ * @returns 接口路径列表
79
+ */
80
+ getRolePermissions(roleCode: string): Promise<string[]>;
81
+ /**
82
+ * 检查角色是否有指定接口权限
83
+ * @param roleCode - 角色代码
84
+ * @param apiPath - 接口路径(url.pathname,例如 /api/user/login;与 method 无关)
85
+ * @returns 是否有权限
86
+ */
87
+ checkRolePermission(roleCode: string, apiPath: string): Promise<boolean>;
88
+ /**
89
+ * 删除角色的接口权限缓存
90
+ * @param roleCode - 角色代码
91
+ * @returns 是否删除成功
92
+ */
93
+ deleteRolePermissions(roleCode: string): Promise<boolean>;
94
+ }
95
+ export {};
@@ -2,108 +2,71 @@
2
2
  * 缓存助手 - TypeScript 版本
3
3
  * 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
4
4
  */
5
-
6
- import { CacheKeys } from "./cacheKeys.ts";
7
- import { Logger } from "./logger.ts";
8
-
9
- type CacheHelperDb = {
10
- tableExists(table: string): Promise<{ data: boolean }>;
11
- getAll(options: any): Promise<{ data: { lists: any[] } }>;
12
- };
13
-
14
- type CacheHelperRedis = {
15
- setObject<T = any>(key: string, obj: T, ttl?: number | null): Promise<string | null>;
16
- getObject<T = any>(key: string): Promise<T | null>;
17
- del(key: string): Promise<number>;
18
- delBatch(keys: string[]): Promise<number>;
19
- sadd(key: string, members: string[]): Promise<number>;
20
- saddBatch(items: Array<{ key: string; members: string[] }>): Promise<number>;
21
- smembers(key: string): Promise<string[]>;
22
- sismember(key: string, member: string): Promise<boolean>;
23
- };
24
-
25
- type CacheHelperDeps = {
26
- db: CacheHelperDb;
27
- redis: CacheHelperRedis;
28
- };
29
-
5
+ import { CacheKeys } from "./cacheKeys";
6
+ import { Logger } from "./logger";
30
7
  /**
31
8
  * 缓存助手类
32
9
  */
33
10
  export class CacheHelper {
34
- private db: CacheHelperDb;
35
- private redis: CacheHelperRedis;
36
-
37
- constructor(deps: CacheHelperDeps) {
11
+ db;
12
+ redis;
13
+ constructor(deps) {
38
14
  this.db = deps.db;
39
15
  this.redis = deps.redis;
40
16
  }
41
-
42
- private assertApiPathname(value: unknown, errorPrefix: string): string {
17
+ assertApiPathname(value, errorPrefix) {
43
18
  if (typeof value !== "string") {
44
19
  throw new Error(`${errorPrefix} 必须是字符串`);
45
20
  }
46
-
47
21
  const trimmed = value.trim();
48
22
  if (!trimmed) {
49
23
  throw new Error(`${errorPrefix} 不允许为空字符串`);
50
24
  }
51
-
52
25
  if (/^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/i.test(trimmed)) {
53
26
  throw new Error(`${errorPrefix} 不允许包含 method 前缀,应为 url.pathname(例如 /api/app/xxx)`);
54
27
  }
55
-
56
28
  if (!trimmed.startsWith("/")) {
57
29
  throw new Error(`${errorPrefix} 必须是 pathname(以 / 开头)`);
58
30
  }
59
-
60
31
  if (trimmed.includes(" ")) {
61
32
  throw new Error(`${errorPrefix} 不允许包含空格`);
62
33
  }
63
-
64
34
  return trimmed;
65
35
  }
66
-
67
- private assertApiPathList(value: unknown, roleCode: string): string[] {
68
- if (value === null || value === undefined) return [];
69
-
70
- let list: unknown = value;
71
-
36
+ assertApiPathList(value, roleCode) {
37
+ if (value === null || value === undefined)
38
+ return [];
39
+ let list = value;
72
40
  // 兼容历史/手工数据:apis 可能被存成 JSON 字符串或 "null"
73
41
  if (typeof list === "string") {
74
42
  const trimmed = list.trim();
75
-
76
43
  // TEXT 字段常见历史值:"null"(表示空)
77
44
  if (trimmed === "" || trimmed === "null") {
78
45
  return [];
79
46
  }
80
-
81
47
  if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
82
48
  try {
83
49
  list = JSON.parse(trimmed);
84
- } catch {
50
+ }
51
+ catch {
85
52
  throw new Error(`角色权限数据不合法:addon_admin_role.apis JSON 解析失败,roleCode=${roleCode}`);
86
53
  }
87
54
  }
88
55
  }
89
-
90
56
  if (!Array.isArray(list)) {
91
57
  const typeLabel = typeof list;
92
58
  throw new Error(`角色权限数据不合法:addon_admin_role.apis 必须是字符串数组或 JSON 数组字符串,roleCode=${roleCode},type=${typeLabel}`);
93
59
  }
94
-
95
- const out: string[] = [];
60
+ const out = [];
96
61
  for (const item of list) {
97
62
  out.push(this.assertApiPathname(item, `角色权限数据不合法:addon_admin_role.apis 元素,roleCode=${roleCode}`));
98
63
  }
99
-
100
64
  return out;
101
65
  }
102
-
103
66
  /**
104
67
  * 缓存所有接口到 Redis
105
68
  */
106
- async cacheApis(): Promise<void> {
69
+ async cacheApis() {
107
70
  try {
108
71
  // 检查表是否存在
109
72
  const tableExists = await this.db.tableExists("addon_admin_api");
@@ -111,27 +74,24 @@ export class CacheHelper {
111
74
  Logger.warn("⚠️ 接口表不存在,跳过接口缓存");
112
75
  return;
113
76
  }
114
-
115
77
  // 从数据库查询所有接口
116
78
  const apiList = await this.db.getAll({
117
79
  table: "addon_admin_api"
118
80
  });
119
-
120
81
  // 缓存到 Redis
121
82
  const result = await this.redis.setObject(CacheKeys.apisAll(), apiList.data.lists);
122
-
123
83
  if (result === null) {
124
84
  Logger.warn("⚠️ 接口缓存失败");
125
85
  }
126
- } catch (error: any) {
86
+ }
87
+ catch (error) {
127
88
  Logger.error({ err: error }, "⚠️ 接口缓存异常");
128
89
  }
129
90
  }
130
-
131
91
  /**
132
92
  * 缓存所有菜单到 Redis(从数据库读取)
133
93
  */
134
- async cacheMenus(): Promise<void> {
94
+ async cacheMenus() {
135
95
  try {
136
96
  // 检查表是否存在
137
97
  const tableExists = await this.db.tableExists("addon_admin_menu");
@@ -139,194 +99,173 @@ export class CacheHelper {
139
99
  Logger.warn("⚠️ 菜单表不存在,跳过菜单缓存");
140
100
  return;
141
101
  }
142
-
143
102
  // 从数据库查询所有菜单
144
103
  const menus = await this.db.getAll({
145
104
  table: "addon_admin_menu"
146
105
  });
147
-
148
106
  // 缓存到 Redis
149
107
  const result = await this.redis.setObject(CacheKeys.menusAll(), menus.data.lists);
150
-
151
108
  if (result === null) {
152
109
  Logger.warn("⚠️ 菜单缓存失败");
153
110
  }
154
- } catch (error: any) {
111
+ }
112
+ catch (error) {
155
113
  Logger.warn({ err: error }, "⚠️ 菜单缓存异常");
156
114
  }
157
115
  }
158
-
159
116
  /**
160
117
  * 缓存所有角色的接口权限到 Redis
161
118
  * 全量重建:清理所有角色权限缓存并重建
162
119
  * - 极简方案:每个角色一个 Set,直接覆盖更新(DEL + SADD)
163
120
  */
164
- async rebuildRoleApiPermissions(): Promise<void> {
121
+ async rebuildRoleApiPermissions() {
165
122
  try {
166
123
  // 检查表是否存在
167
124
  const roleTableExists = await this.db.tableExists("addon_admin_role");
168
-
169
125
  if (!roleTableExists.data) {
170
126
  Logger.warn("⚠️ 角色表不存在,跳过角色权限缓存");
171
127
  return;
172
128
  }
173
-
174
129
  // 查询所有角色(仅取必要字段)
175
130
  const roles = await this.db.getAll({
176
131
  table: "addon_admin_role",
177
132
  fields: ["code", "apis"]
178
133
  });
179
-
180
- const roleApiPathsMap = new Map<string, string[]>();
181
-
134
+ const roleApiPathsMap = new Map();
182
135
  for (const role of roles.data.lists) {
183
- if (!role?.code) continue;
136
+ if (!role?.code)
137
+ continue;
184
138
  const apiPaths = this.assertApiPathList(role.apis, role.code);
185
139
  roleApiPathsMap.set(role.code, apiPaths);
186
140
  }
187
-
188
141
  const roleCodes = Array.from(roleApiPathsMap.keys());
189
142
  if (roleCodes.length === 0) {
190
143
  Logger.info("✅ 没有需要缓存的角色权限");
191
144
  return;
192
145
  }
193
-
194
146
  // 清理所有角色的缓存 key(保证幂等)
195
147
  const roleKeys = roleCodes.map((code) => CacheKeys.roleApis(code));
196
148
  await this.redis.delBatch(roleKeys);
197
-
198
149
  // 批量写入新缓存(只写入非空权限)
199
- const items: Array<{ key: string; members: string[] }> = [];
200
-
150
+ const items = [];
201
151
  for (const roleCode of roleCodes) {
202
152
  const apiPaths = roleApiPathsMap.get(roleCode) || [];
203
153
  const members = Array.from(new Set(apiPaths)).sort();
204
-
205
154
  if (members.length > 0) {
206
155
  items.push({ key: CacheKeys.roleApis(roleCode), members: members });
207
156
  }
208
157
  }
209
-
210
158
  if (items.length > 0) {
211
159
  await this.redis.saddBatch(items);
212
160
  }
213
-
214
161
  // 极简方案不做版本/ready/meta:重建完成即生效
215
- } catch (error: any) {
162
+ }
163
+ catch (error) {
216
164
  Logger.error({ err: error }, "⚠️ 角色权限缓存异常(将阻断启动)");
217
165
  throw error;
218
166
  }
219
167
  }
220
-
221
168
  /**
222
169
  * 增量刷新单个角色的接口权限缓存
223
170
  * - apiIds 为空数组:仅清理缓存(防止残留)
224
171
  * - apiIds 非空:使用 $in 最小查询,DEL 后 SADD
225
172
  */
226
- async refreshRoleApiPermissions(roleCode: string, apiPaths: string[]): Promise<void> {
173
+ async refreshRoleApiPermissions(roleCode, apiPaths) {
227
174
  if (!roleCode || typeof roleCode !== "string") {
228
175
  throw new Error("roleCode 必须是非空字符串");
229
176
  }
230
177
  if (!Array.isArray(apiPaths)) {
231
178
  throw new Error("apiPaths 必须是数组");
232
179
  }
233
-
234
180
  const normalizedPaths = apiPaths.map((p) => this.assertApiPathname(p, `refreshRoleApiPermissions: apiPaths 元素,roleCode=${roleCode}`));
235
181
  const roleKey = CacheKeys.roleApis(roleCode);
236
-
237
182
  // 空数组短路:保证清理残留
238
183
  if (normalizedPaths.length === 0) {
239
184
  await this.redis.del(roleKey);
240
185
  return;
241
186
  }
242
-
243
187
  const members = Array.from(new Set(normalizedPaths));
244
-
245
188
  await this.redis.del(roleKey);
246
189
  if (members.length > 0) {
247
190
  await this.redis.sadd(roleKey, members);
248
191
  }
249
192
  }
250
-
251
193
  /**
252
194
  * 缓存所有数据
253
195
  */
254
- async cacheAll(): Promise<void> {
196
+ async cacheAll() {
255
197
  // 1. 缓存接口
256
198
  await this.cacheApis();
257
-
258
199
  // 2. 缓存菜单
259
200
  await this.cacheMenus();
260
-
261
201
  // 3. 缓存角色权限
262
202
  await this.rebuildRoleApiPermissions();
263
203
  }
264
-
265
204
  /**
266
205
  * 获取缓存的所有接口
267
206
  * @returns 接口列表
268
207
  */
269
- async getApis(): Promise<any[]> {
208
+ async getApis() {
270
209
  try {
271
- const apis = await this.redis.getObject<any[]>(CacheKeys.apisAll());
210
+ const apis = await this.redis.getObject(CacheKeys.apisAll());
272
211
  return apis || [];
273
- } catch (error: any) {
212
+ }
213
+ catch (error) {
274
214
  Logger.error({ err: error }, "获取接口缓存失败");
275
215
  return [];
276
216
  }
277
217
  }
278
-
279
218
  /**
280
219
  * 获取缓存的所有菜单
281
220
  * @returns 菜单列表
282
221
  */
283
- async getMenus(): Promise<any[]> {
222
+ async getMenus() {
284
223
  try {
285
- const menus = await this.redis.getObject<any[]>(CacheKeys.menusAll());
224
+ const menus = await this.redis.getObject(CacheKeys.menusAll());
286
225
  return menus || [];
287
- } catch (error: any) {
226
+ }
227
+ catch (error) {
288
228
  Logger.error({ err: error }, "获取菜单缓存失败");
289
229
  return [];
290
230
  }
291
231
  }
292
-
293
232
  /**
294
233
  * 获取角色的接口权限
295
234
  * @param roleCode - 角色代码
296
235
  * @returns 接口路径列表
297
236
  */
298
- async getRolePermissions(roleCode: string): Promise<string[]> {
237
+ async getRolePermissions(roleCode) {
299
238
  try {
300
239
  const permissions = await this.redis.smembers(CacheKeys.roleApis(roleCode));
301
240
  return permissions || [];
302
- } catch (error: any) {
241
+ }
242
+ catch (error) {
303
243
  Logger.error({ err: error, roleCode: roleCode }, "获取角色权限缓存失败");
304
244
  return [];
305
245
  }
306
246
  }
307
-
308
247
  /**
309
248
  * 检查角色是否有指定接口权限
310
249
  * @param roleCode - 角色代码
311
250
  * @param apiPath - 接口路径(url.pathname,例如 /api/user/login;与 method 无关)
312
251
  * @returns 是否有权限
313
252
  */
314
- async checkRolePermission(roleCode: string, apiPath: string): Promise<boolean> {
253
+ async checkRolePermission(roleCode, apiPath) {
315
254
  try {
316
255
  const pathname = this.assertApiPathname(apiPath, "checkRolePermission: apiPath");
317
256
  return await this.redis.sismember(CacheKeys.roleApis(roleCode), pathname);
318
- } catch (error: any) {
257
+ }
258
+ catch (error) {
319
259
  Logger.error({ err: error, roleCode: roleCode }, "检查角色权限失败");
320
260
  return false;
321
261
  }
322
262
  }
323
-
324
263
  /**
325
264
  * 删除角色的接口权限缓存
326
265
  * @param roleCode - 角色代码
327
266
  * @returns 是否删除成功
328
267
  */
329
- async deleteRolePermissions(roleCode: string): Promise<boolean> {
268
+ async deleteRolePermissions(roleCode) {
330
269
  try {
331
270
  const result = await this.redis.del(CacheKeys.roleApis(roleCode));
332
271
  if (result > 0) {
@@ -334,7 +273,8 @@ export class CacheHelper {
334
273
  return true;
335
274
  }
336
275
  return false;
337
- } catch (error: any) {
276
+ }
277
+ catch (error) {
338
278
  Logger.error({ err: error, roleCode: roleCode }, "删除角色权限缓存失败");
339
279
  return false;
340
280
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Cache Key 统一管理
3
+ * 所有缓存键在此统一定义,避免硬编码分散
4
+ */
5
+ /**
6
+ * Cache Key 生成函数集合
7
+ */
8
+ export declare class CacheKeys {
9
+ /** 所有接口缓存 */
10
+ static apisAll(): string;
11
+ /** 所有菜单缓存 */
12
+ static menusAll(): string;
13
+ /** 角色信息缓存(完整角色对象) */
14
+ static roleInfo(roleCode: string): string;
15
+ /**
16
+ * 角色接口权限缓存(Set 集合)
17
+ * - key: role:apis:${roleCode}
18
+ * - member: url.pathname(例如 /api/user/login;与 method 无关)
19
+ */
20
+ static roleApis(roleCode: string): string;
21
+ /** 表结构缓存 */
22
+ static tableColumns(table: string): string;
23
+ }
@@ -2,37 +2,32 @@
2
2
  * Cache Key 统一管理
3
3
  * 所有缓存键在此统一定义,避免硬编码分散
4
4
  */
5
-
6
5
  /**
7
6
  * Cache Key 生成函数集合
8
7
  */
9
8
  export class CacheKeys {
10
9
  /** 所有接口缓存 */
11
- static apisAll(): string {
10
+ static apisAll() {
12
11
  return "apis:all";
13
12
  }
14
-
15
13
  /** 所有菜单缓存 */
16
- static menusAll(): string {
14
+ static menusAll() {
17
15
  return "menus:all";
18
16
  }
19
-
20
17
  /** 角色信息缓存(完整角色对象) */
21
- static roleInfo(roleCode: string): string {
18
+ static roleInfo(roleCode) {
22
19
  return `role:info:${roleCode}`;
23
20
  }
24
-
25
21
  /**
26
22
  * 角色接口权限缓存(Set 集合)
27
23
  * - key: role:apis:${roleCode}
28
24
  * - member: url.pathname(例如 /api/user/login;与 method 无关)
29
25
  */
30
- static roleApis(roleCode: string): string {
26
+ static roleApis(roleCode) {
31
27
  return `role:apis:${roleCode}`;
32
28
  }
33
-
34
29
  /** 表结构缓存 */
35
- static tableColumns(table: string): string {
30
+ static tableColumns(table) {
36
31
  return `table:columns:${table}`;
37
32
  }
38
33
  }