befly 3.10.17 → 3.10.19

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 (218) 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} +8 -31
  4. package/dist/checks/checkApi.d.ts +1 -0
  5. package/{checks/checkApi.ts → dist/checks/checkApi.js} +10 -27
  6. package/dist/checks/checkHook.d.ts +1 -0
  7. package/{checks/checkHook.ts → dist/checks/checkHook.js} +10 -19
  8. package/dist/checks/checkMenu.d.ts +7 -0
  9. package/{checks/checkMenu.ts → dist/checks/checkMenu.js} +15 -50
  10. package/dist/checks/checkPlugin.d.ts +1 -0
  11. package/{checks/checkPlugin.ts → dist/checks/checkPlugin.js} +10 -19
  12. package/dist/checks/checkTable.d.ts +6 -0
  13. package/{checks/checkTable.ts → dist/checks/checkTable.js} +16 -40
  14. package/dist/configs/presetFields.d.ts +4 -0
  15. package/{configs/presetFields.ts → dist/configs/presetFields.js} +1 -1
  16. package/dist/configs/presetRegexp.d.ts +145 -0
  17. package/{utils/regex.ts → dist/configs/presetRegexp.js} +8 -31
  18. package/dist/hooks/auth.d.ts +5 -0
  19. package/{hooks/auth.ts → dist/hooks/auth.js} +5 -9
  20. package/dist/hooks/cors.d.ts +9 -0
  21. package/{hooks/cors.ts → dist/hooks/cors.js} +2 -12
  22. package/dist/hooks/parser.d.ts +12 -0
  23. package/{hooks/parser.ts → dist/hooks/parser.js} +27 -42
  24. package/dist/hooks/permission.d.ts +12 -0
  25. package/{hooks/permission.ts → dist/hooks/permission.js} +11 -22
  26. package/dist/hooks/validator.d.ts +9 -0
  27. package/{hooks/validator.ts → dist/hooks/validator.js} +5 -12
  28. package/dist/lib/asyncContext.d.ts +21 -0
  29. package/dist/lib/asyncContext.js +27 -0
  30. package/dist/lib/cacheHelper.d.ts +95 -0
  31. package/{lib/cacheHelper.ts → dist/lib/cacheHelper.js} +43 -103
  32. package/dist/lib/cacheKeys.d.ts +23 -0
  33. package/{lib/cacheKeys.ts → dist/lib/cacheKeys.js} +5 -10
  34. package/dist/lib/cipher.d.ts +153 -0
  35. package/{lib/cipher.ts → dist/lib/cipher.js} +23 -44
  36. package/dist/lib/connect.d.ts +91 -0
  37. package/{lib/connect.ts → dist/lib/connect.js} +46 -87
  38. package/dist/lib/dbDialect.d.ts +87 -0
  39. package/{lib/dbDialect.ts → dist/lib/dbDialect.js} +32 -112
  40. package/dist/lib/dbHelper.d.ts +204 -0
  41. package/{lib/dbHelper.ts → dist/lib/dbHelper.js} +73 -230
  42. package/dist/lib/dbUtils.d.ts +68 -0
  43. package/{lib/dbUtils.ts → dist/lib/dbUtils.js} +49 -123
  44. package/dist/lib/jwt.d.ts +13 -0
  45. package/{lib/jwt.ts → dist/lib/jwt.js} +11 -32
  46. package/dist/lib/logger.d.ts +32 -0
  47. package/{lib/logger.ts → dist/lib/logger.js} +201 -278
  48. package/dist/lib/redisHelper.d.ts +185 -0
  49. package/{lib/redisHelper.ts → dist/lib/redisHelper.js} +95 -139
  50. package/dist/lib/sqlBuilder.d.ts +160 -0
  51. package/{lib/sqlBuilder.ts → dist/lib/sqlBuilder.js} +131 -277
  52. package/dist/lib/sqlCheck.d.ts +23 -0
  53. package/{lib/sqlCheck.ts → dist/lib/sqlCheck.js} +24 -41
  54. package/dist/lib/validator.d.ts +45 -0
  55. package/{lib/validator.ts → dist/lib/validator.js} +43 -60
  56. package/dist/loader/loadApis.d.ts +12 -0
  57. package/{loader/loadApis.ts → dist/loader/loadApis.js} +7 -17
  58. package/dist/loader/loadHooks.d.ts +8 -0
  59. package/{loader/loadHooks.ts → dist/loader/loadHooks.js} +5 -19
  60. package/dist/loader/loadPlugins.d.ts +8 -0
  61. package/{loader/loadPlugins.ts → dist/loader/loadPlugins.js} +8 -20
  62. package/dist/main.d.ts +26 -0
  63. package/{main.ts → dist/main.js} +39 -78
  64. package/dist/paths.d.ts +93 -0
  65. package/{paths.ts → dist/paths.js} +6 -19
  66. package/dist/plugins/cache.d.ts +14 -0
  67. package/{plugins/cache.ts → dist/plugins/cache.js} +4 -11
  68. package/dist/plugins/cipher.d.ts +10 -0
  69. package/{plugins/cipher.ts → dist/plugins/cipher.js} +1 -5
  70. package/dist/plugins/config.d.ts +10 -0
  71. package/dist/plugins/config.js +6 -0
  72. package/dist/plugins/db.d.ts +14 -0
  73. package/{plugins/db.ts → dist/plugins/db.js} +5 -13
  74. package/dist/plugins/jwt.d.ts +10 -0
  75. package/{plugins/jwt.ts → dist/plugins/jwt.js} +2 -7
  76. package/dist/plugins/logger.d.ts +28 -0
  77. package/{plugins/logger.ts → dist/plugins/logger.js} +2 -7
  78. package/dist/plugins/redis.d.ts +14 -0
  79. package/{plugins/redis.ts → dist/plugins/redis.js} +4 -9
  80. package/dist/plugins/tool.d.ts +79 -0
  81. package/{plugins/tool.ts → dist/plugins/tool.js} +7 -30
  82. package/dist/router/api.d.ts +14 -0
  83. package/dist/router/api.js +107 -0
  84. package/dist/router/static.d.ts +9 -0
  85. package/{router/static.ts → dist/router/static.js} +17 -31
  86. package/dist/scripts/ensureDist.d.ts +1 -0
  87. package/dist/scripts/ensureDist.js +80 -0
  88. package/dist/sync/syncApi.d.ts +3 -0
  89. package/{sync/syncApi.ts → dist/sync/syncApi.js} +33 -53
  90. package/dist/sync/syncCache.d.ts +2 -0
  91. package/{sync/syncCache.ts → dist/sync/syncCache.js} +1 -6
  92. package/dist/sync/syncDev.d.ts +6 -0
  93. package/{sync/syncDev.ts → dist/sync/syncDev.js} +27 -60
  94. package/dist/sync/syncMenu.d.ts +14 -0
  95. package/{sync/syncMenu.ts → dist/sync/syncMenu.js} +61 -121
  96. package/dist/sync/syncTable.d.ts +151 -0
  97. package/{sync/syncTable.ts → dist/sync/syncTable.js} +168 -375
  98. package/{types → dist/types}/api.d.ts +12 -51
  99. package/dist/types/api.js +4 -0
  100. package/{types → dist/types}/befly.d.ts +32 -223
  101. package/dist/types/befly.js +4 -0
  102. package/{types → dist/types}/cache.d.ts +7 -15
  103. package/dist/types/cache.js +4 -0
  104. package/dist/types/cipher.d.ts +27 -0
  105. package/dist/types/cipher.js +7 -0
  106. package/{types → dist/types}/common.d.ts +8 -33
  107. package/dist/types/common.js +5 -0
  108. package/{types → dist/types}/context.d.ts +3 -5
  109. package/dist/types/context.js +4 -0
  110. package/{types → dist/types}/crypto.d.ts +0 -3
  111. package/dist/types/crypto.js +4 -0
  112. package/dist/types/database.d.ts +138 -0
  113. package/dist/types/database.js +4 -0
  114. package/dist/types/hook.d.ts +15 -0
  115. package/dist/types/hook.js +6 -0
  116. package/dist/types/jwt.d.ts +75 -0
  117. package/dist/types/jwt.js +4 -0
  118. package/dist/types/logger.d.ts +47 -0
  119. package/dist/types/logger.js +6 -0
  120. package/dist/types/plugin.d.ts +14 -0
  121. package/dist/types/plugin.js +6 -0
  122. package/dist/types/redis.d.ts +71 -0
  123. package/dist/types/redis.js +4 -0
  124. package/{types/roleApisCache.ts → dist/types/roleApisCache.d.ts} +0 -2
  125. package/dist/types/roleApisCache.js +8 -0
  126. package/dist/types/sync.d.ts +92 -0
  127. package/dist/types/sync.js +4 -0
  128. package/dist/types/table.d.ts +34 -0
  129. package/dist/types/table.js +4 -0
  130. package/dist/types/validate.d.ts +67 -0
  131. package/dist/types/validate.js +4 -0
  132. package/dist/utils/arrayKeysToCamel.d.ts +13 -0
  133. package/{utils/arrayKeysToCamel.ts → dist/utils/arrayKeysToCamel.js} +4 -4
  134. package/dist/utils/calcPerfTime.d.ts +4 -0
  135. package/{utils/calcPerfTime.ts → dist/utils/calcPerfTime.js} +3 -3
  136. package/dist/utils/configTypes.d.ts +1 -0
  137. package/dist/utils/configTypes.js +1 -0
  138. package/dist/utils/convertBigIntFields.d.ts +11 -0
  139. package/{utils/convertBigIntFields.ts → dist/utils/convertBigIntFields.js} +5 -9
  140. package/dist/utils/cors.d.ts +8 -0
  141. package/{utils/cors.ts → dist/utils/cors.js} +1 -3
  142. package/dist/utils/disableMenusGlob.d.ts +13 -0
  143. package/{utils/disableMenusGlob.ts → dist/utils/disableMenusGlob.js} +9 -29
  144. package/dist/utils/fieldClear.d.ts +11 -0
  145. package/{utils/fieldClear.ts → dist/utils/fieldClear.js} +15 -33
  146. package/dist/utils/genShortId.d.ts +10 -0
  147. package/{utils/genShortId.ts → dist/utils/genShortId.js} +1 -1
  148. package/dist/utils/getClientIp.d.ts +6 -0
  149. package/{utils/getClientIp.ts → dist/utils/getClientIp.js} +1 -7
  150. package/dist/utils/importDefault.d.ts +1 -0
  151. package/dist/utils/importDefault.js +29 -0
  152. package/dist/utils/isDirentDirectory.d.ts +2 -0
  153. package/{utils/isDirentDirectory.ts → dist/utils/isDirentDirectory.js} +3 -8
  154. package/dist/utils/keysToCamel.d.ts +10 -0
  155. package/{utils/keysToCamel.ts → dist/utils/keysToCamel.js} +4 -5
  156. package/dist/utils/keysToSnake.d.ts +10 -0
  157. package/{utils/keysToSnake.ts → dist/utils/keysToSnake.js} +4 -5
  158. package/dist/utils/loadMenuConfigs.d.ts +5 -0
  159. package/{utils/loadMenuConfigs.ts → dist/utils/loadMenuConfigs.js} +22 -49
  160. package/dist/utils/pickFields.d.ts +4 -0
  161. package/{utils/pickFields.ts → dist/utils/pickFields.js} +2 -5
  162. package/dist/utils/process.d.ts +24 -0
  163. package/{utils/process.ts → dist/utils/process.js} +2 -18
  164. package/dist/utils/processFields.d.ts +4 -0
  165. package/{utils/processFields.ts → dist/utils/processFields.js} +4 -8
  166. package/dist/utils/regex.d.ts +145 -0
  167. package/{configs/presetRegexp.ts → dist/utils/regex.js} +8 -31
  168. package/dist/utils/response.d.ts +20 -0
  169. package/{utils/response.ts → dist/utils/response.js} +27 -48
  170. package/dist/utils/scanAddons.d.ts +17 -0
  171. package/{utils/scanAddons.ts → dist/utils/scanAddons.js} +4 -38
  172. package/dist/utils/scanConfig.d.ts +26 -0
  173. package/{utils/scanConfig.ts → dist/utils/scanConfig.js} +22 -59
  174. package/dist/utils/scanFiles.d.ts +30 -0
  175. package/{utils/scanFiles.ts → dist/utils/scanFiles.js} +25 -65
  176. package/dist/utils/scanSources.d.ts +10 -0
  177. package/{utils/scanSources.ts → dist/utils/scanSources.js} +16 -39
  178. package/dist/utils/sortModules.d.ts +28 -0
  179. package/{utils/sortModules.ts → dist/utils/sortModules.js} +24 -64
  180. package/dist/utils/sqlLog.d.ts +14 -0
  181. package/{utils/sqlLog.ts → dist/utils/sqlLog.js} +2 -14
  182. package/package.json +15 -32
  183. package/.gitignore +0 -0
  184. package/bunfig.toml +0 -3
  185. package/docs/README.md +0 -98
  186. package/docs/api/api.md +0 -1921
  187. package/docs/guide/examples.md +0 -926
  188. package/docs/guide/quickstart.md +0 -354
  189. package/docs/hooks/auth.md +0 -38
  190. package/docs/hooks/cors.md +0 -28
  191. package/docs/hooks/hook.md +0 -838
  192. package/docs/hooks/parser.md +0 -19
  193. package/docs/hooks/rateLimit.md +0 -47
  194. package/docs/infra/redis.md +0 -628
  195. package/docs/plugins/cipher.md +0 -61
  196. package/docs/plugins/database.md +0 -189
  197. package/docs/plugins/plugin.md +0 -986
  198. package/docs/reference/addon.md +0 -510
  199. package/docs/reference/config.md +0 -573
  200. package/docs/reference/logger.md +0 -495
  201. package/docs/reference/sync.md +0 -478
  202. package/docs/reference/table.md +0 -763
  203. package/docs/reference/validator.md +0 -620
  204. package/lib/asyncContext.ts +0 -43
  205. package/plugins/config.ts +0 -13
  206. package/router/api.ts +0 -130
  207. package/tsconfig.json +0 -54
  208. package/types/database.d.ts +0 -541
  209. package/types/hook.d.ts +0 -25
  210. package/types/jwt.d.ts +0 -118
  211. package/types/logger.d.ts +0 -65
  212. package/types/plugin.d.ts +0 -19
  213. package/types/redis.d.ts +0 -83
  214. package/types/sync.d.ts +0 -398
  215. package/types/table.d.ts +0 -216
  216. package/types/validate.d.ts +0 -69
  217. package/utils/configTypes.ts +0 -3
  218. package/utils/importDefault.ts +0 -21
@@ -1,11 +1,8 @@
1
1
  import { isPlainObject } from "es-toolkit/compat";
2
2
  import { omit } from "es-toolkit/object";
3
-
4
3
  import { Logger } from "../lib/logger.js";
5
-
6
- export async function checkHook(hooks: any[]): Promise<void> {
4
+ export async function checkHook(hooks) {
7
5
  let hasError = false;
8
-
9
6
  for (const hook of hooks) {
10
7
  try {
11
8
  if (!isPlainObject(hook)) {
@@ -13,35 +10,29 @@ export async function checkHook(hooks: any[]): Promise<void> {
13
10
  hasError = true;
14
11
  continue;
15
12
  }
16
-
17
- if (!Array.isArray((hook as any).deps)) {
13
+ if (!Array.isArray(hook.deps)) {
18
14
  Logger.warn(omit(hook, ["handler"]), "钩子的 deps 属性必须是字符串数组");
19
15
  hasError = true;
20
16
  continue;
21
17
  }
22
-
23
- if ((hook as any).deps.some((depItem: any) => typeof depItem !== "string")) {
18
+ if (hook.deps.some((depItem) => typeof depItem !== "string")) {
24
19
  Logger.warn(omit(hook, ["handler"]), "钩子的 deps 属性必须是字符串数组");
25
20
  hasError = true;
26
21
  }
27
-
28
- if (typeof (hook as any).handler !== "function") {
22
+ if (typeof hook.handler !== "function") {
29
23
  Logger.warn(omit(hook, ["handler"]), "钩子的 handler 属性必须是函数");
30
24
  hasError = true;
31
25
  continue;
32
26
  }
33
- } catch (error: any) {
34
- Logger.error(
35
- {
36
- err: error,
37
- item: hook
38
- },
39
- "钩子解析失败"
40
- );
27
+ }
28
+ catch (error) {
29
+ Logger.error({
30
+ err: error,
31
+ item: hook
32
+ }, "钩子解析失败");
41
33
  hasError = true;
42
34
  }
43
35
  }
44
-
45
36
  if (hasError) {
46
37
  throw new Error("钩子结构检查失败");
47
38
  }
@@ -0,0 +1,7 @@
1
+ import type { MenuConfig } from "../types/sync.ts";
2
+ import type { AddonInfo } from "../utils/scanAddons.ts";
3
+ type CheckMenuOptions = {
4
+ disableMenus?: string[];
5
+ };
6
+ export declare const checkMenu: (addons: AddonInfo[], options?: CheckMenuOptions) => Promise<MenuConfig[]>;
7
+ export {};
@@ -1,11 +1,7 @@
1
- import type { MenuConfig } from "../types/sync.js";
2
- import type { AddonInfo } from "../utils/scanAddons.js";
3
-
4
1
  import { Logger } from "../lib/logger.js";
5
2
  import { compileDisableMenuGlobRules, isMenuPathDisabledByGlobRules } from "../utils/disableMenusGlob.js";
6
3
  import { loadMenuConfigs } from "../utils/loadMenuConfigs.js";
7
-
8
- function isValidMenuPath(path: string): { ok: boolean; reason: string } {
4
+ function isValidMenuPath(path) {
9
5
  if (!path) {
10
6
  return { ok: false, reason: "path 不能为空" };
11
7
  }
@@ -23,96 +19,74 @@ function isValidMenuPath(path: string): { ok: boolean; reason: string } {
23
19
  }
24
20
  return { ok: true, reason: "" };
25
21
  }
26
-
27
- type CheckMenuOptions = {
28
- disableMenus?: string[];
29
- };
30
-
31
- type DisableMenuRule = ReturnType<typeof compileDisableMenuGlobRules>[number];
32
-
33
- function filterMenusByDisableRules(mergedMenus: MenuConfig[], rules: DisableMenuRule[]): MenuConfig[] {
22
+ function filterMenusByDisableRules(mergedMenus, rules) {
34
23
  if (rules.length === 0) {
35
24
  return mergedMenus;
36
25
  }
37
-
38
- const filtered: MenuConfig[] = [];
39
-
26
+ const filtered = [];
40
27
  for (const menu of mergedMenus) {
41
- const menuPath = typeof (menu as any)?.path === "string" ? String((menu as any).path).trim() : "";
28
+ const menuPath = typeof menu?.path === "string" ? String(menu.path).trim() : "";
42
29
  if (menuPath && isMenuPathDisabledByGlobRules(menuPath, rules)) {
43
30
  continue;
44
31
  }
45
-
46
- const children = Array.isArray((menu as any)?.children) ? ((menu as any).children as MenuConfig[]) : null;
32
+ const children = Array.isArray(menu?.children) ? menu.children : null;
47
33
  if (children && children.length > 0) {
48
34
  const nextChildren = filterMenusByDisableRules(children, rules);
49
35
  if (nextChildren.length > 0) {
50
- (menu as any).children = nextChildren;
51
- } else {
52
- delete (menu as any).children;
36
+ menu.children = nextChildren;
37
+ }
38
+ else {
39
+ delete menu.children;
53
40
  }
54
41
  }
55
-
56
42
  filtered.push(menu);
57
43
  }
58
-
59
44
  return filtered;
60
45
  }
61
-
62
- export const checkMenu = async (addons: AddonInfo[], options: CheckMenuOptions = {}): Promise<MenuConfig[]> => {
46
+ export const checkMenu = async (addons, options = {}) => {
63
47
  let hasError = false;
64
-
65
48
  const mergedMenus = await loadMenuConfigs(addons);
66
-
67
49
  const disableRules = compileDisableMenuGlobRules(options.disableMenus);
68
50
  const filteredMenus = filterMenusByDisableRules(mergedMenus, disableRules);
69
-
70
- const stack: Array<{ menu: any; depth: number }> = [];
51
+ const stack = [];
71
52
  for (const m of filteredMenus) {
72
53
  stack.push({ menu: m, depth: 1 });
73
54
  }
74
-
75
- const pathSet = new Set<string>();
76
-
55
+ const pathSet = new Set();
77
56
  while (stack.length > 0) {
78
- const current = stack.pop() as { menu: any; depth: number };
57
+ const current = stack.pop();
79
58
  const menu = current?.menu;
80
59
  const depth = typeof current?.depth === "number" ? current.depth : 0;
81
-
82
60
  if (menu === null || typeof menu !== "object") {
83
61
  hasError = true;
84
62
  Logger.warn({ menu: menu }, "菜单节点必须是对象");
85
63
  continue;
86
64
  }
87
-
88
65
  if (depth > 3) {
89
66
  hasError = true;
90
67
  Logger.warn({ path: menu?.path, depth: depth }, "菜单层级超过 3 级(最多三级)");
91
68
  continue;
92
69
  }
93
-
94
70
  const children = menu.children;
95
71
  if (typeof children !== "undefined" && !Array.isArray(children)) {
96
72
  hasError = true;
97
73
  Logger.warn({ path: menu?.path, childrenType: typeof children }, "菜单 children 必须是数组");
98
74
  continue;
99
75
  }
100
-
101
76
  if (Array.isArray(children) && children.length > 0) {
102
77
  if (depth >= 3) {
103
78
  hasError = true;
104
79
  Logger.warn({ path: menu?.path, depth: depth }, "菜单层级超过 3 级(最多三级)");
105
- } else {
80
+ }
81
+ else {
106
82
  for (const child of children) {
107
83
  stack.push({ menu: child, depth: depth + 1 });
108
84
  }
109
85
  }
110
86
  }
111
-
112
87
  const path = typeof menu.path === "string" ? menu.path.trim() : "";
113
88
  const name = typeof menu.name === "string" ? menu.name.trim() : "";
114
89
  const sort = typeof menu.sort === "number" ? menu.sort : 999999;
115
-
116
90
  // 标准化输出(用于后续 syncMenu 直接使用)
117
91
  if (typeof menu.path === "string") {
118
92
  menu.path = path;
@@ -123,46 +97,37 @@ export const checkMenu = async (addons: AddonInfo[], options: CheckMenuOptions =
123
97
  if (typeof menu.sort === "undefined") {
124
98
  menu.sort = sort;
125
99
  }
126
-
127
100
  if (!path) {
128
101
  hasError = true;
129
102
  Logger.warn({ menu: menu }, "菜单缺少 path(必须是非空字符串)");
130
103
  continue;
131
104
  }
132
-
133
105
  const pathCheck = isValidMenuPath(path);
134
106
  if (!pathCheck.ok) {
135
107
  hasError = true;
136
108
  Logger.warn({ path: path, reason: pathCheck.reason }, "菜单 path 不合法");
137
109
  }
138
-
139
110
  if (!name) {
140
111
  hasError = true;
141
112
  Logger.warn({ path: path, menu: menu }, "菜单缺少 name(必须是非空字符串)");
142
113
  }
143
-
144
114
  if (typeof menu.sort !== "undefined" && typeof menu.sort !== "number") {
145
115
  hasError = true;
146
116
  Logger.warn({ path: path, sort: menu.sort }, "菜单 sort 必须是 number");
147
117
  }
148
-
149
118
  if (typeof menu.sort === "number" && (!Number.isFinite(menu.sort) || menu.sort < 1)) {
150
119
  hasError = true;
151
120
  Logger.warn({ path: path, sort: menu.sort }, "菜单 sort 最小值为 1");
152
121
  }
153
-
154
122
  if (pathSet.has(path)) {
155
123
  hasError = true;
156
124
  Logger.warn({ path: path }, "菜单 path 重复(严格模式禁止重复 path)");
157
125
  continue;
158
126
  }
159
-
160
127
  pathSet.add(path);
161
128
  }
162
-
163
129
  if (hasError) {
164
130
  throw new Error("菜单结构检查失败");
165
131
  }
166
-
167
132
  return filteredMenus;
168
133
  };
@@ -0,0 +1 @@
1
+ export declare function checkPlugin(plugins: any[]): Promise<void>;
@@ -1,11 +1,8 @@
1
1
  import { isPlainObject } from "es-toolkit/compat";
2
2
  import { omit } from "es-toolkit/object";
3
-
4
3
  import { Logger } from "../lib/logger.js";
5
-
6
- export async function checkPlugin(plugins: any[]): Promise<void> {
4
+ export async function checkPlugin(plugins) {
7
5
  let hasError = false;
8
-
9
6
  for (const plugin of plugins) {
10
7
  try {
11
8
  if (!isPlainObject(plugin)) {
@@ -13,35 +10,29 @@ export async function checkPlugin(plugins: any[]): Promise<void> {
13
10
  hasError = true;
14
11
  continue;
15
12
  }
16
-
17
- if (!Array.isArray((plugin as any).deps)) {
13
+ if (!Array.isArray(plugin.deps)) {
18
14
  Logger.warn(omit(plugin, ["handler"]), "插件的 deps 属性必须是字符串数组");
19
15
  hasError = true;
20
16
  continue;
21
17
  }
22
-
23
- if ((plugin as any).deps.some((depItem: any) => typeof depItem !== "string")) {
18
+ if (plugin.deps.some((depItem) => typeof depItem !== "string")) {
24
19
  Logger.warn(omit(plugin, ["handler"]), "插件的 deps 属性必须是字符串数组");
25
20
  hasError = true;
26
21
  }
27
-
28
- if (typeof (plugin as any).handler !== "function") {
22
+ if (typeof plugin.handler !== "function") {
29
23
  Logger.warn(omit(plugin, ["handler"]), "插件的 handler 属性必须是函数");
30
24
  hasError = true;
31
25
  continue;
32
26
  }
33
- } catch (error: any) {
34
- Logger.error(
35
- {
36
- err: error,
37
- item: plugin
38
- },
39
- "插件解析失败"
40
- );
27
+ }
28
+ catch (error) {
29
+ Logger.error({
30
+ err: error,
31
+ item: plugin
32
+ }, "插件解析失败");
41
33
  hasError = true;
42
34
  }
43
35
  }
44
-
45
36
  if (hasError) {
46
37
  throw new Error("插件结构检查失败");
47
38
  }
@@ -0,0 +1,6 @@
1
+ import type { ScanFileResult } from "../utils/scanFiles.ts";
2
+ /**
3
+ * 检查表定义文件
4
+ * @throws 当检查失败时抛出异常
5
+ */
6
+ export declare function checkTable(tables: ScanFileResult[]): Promise<void>;
@@ -1,23 +1,16 @@
1
- import type { FieldDefinition } from "../types/validate.js";
2
- import type { ScanFileResult } from "../utils/scanFiles.js";
3
-
4
1
  import { Logger } from "../lib/logger.js";
5
-
6
2
  /**
7
3
  * 保留字段列表
8
4
  */
9
- const RESERVED_FIELDS = ["id", "created_at", "updated_at", "deleted_at", "state"] as const;
10
-
5
+ const RESERVED_FIELDS = ["id", "created_at", "updated_at", "deleted_at", "state"];
11
6
  /**
12
7
  * 允许的字段类型
13
8
  */
14
- const FIELD_TYPES = ["string", "number", "text", "array_string", "array_text", "array_number_string", "array_number_text"] as const;
15
-
9
+ const FIELD_TYPES = ["string", "number", "text", "array_string", "array_text", "array_number_string", "array_number_text"];
16
10
  /**
17
11
  * 允许的字段属性列表
18
12
  */
19
- const ALLOWED_FIELD_PROPERTIES = ["name", "type", "min", "max", "default", "detail", "index", "unique", "nullable", "unsigned", "regexp"] as const;
20
-
13
+ const ALLOWED_FIELD_PROPERTIES = ["name", "type", "min", "max", "default", "detail", "index", "unique", "nullable", "unsigned", "regexp"];
21
14
  /**
22
15
  * 小驼峰命名正则
23
16
  * 可选:以下划线开头(用于特殊文件,如通用字段定义)
@@ -25,34 +18,28 @@ const ALLOWED_FIELD_PROPERTIES = ["name", "type", "min", "max", "default", "deta
25
18
  * 示例:userTable、testCustomers、common
26
19
  */
27
20
  const LOWER_CAMEL_CASE_REGEX = /^_?[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
28
-
29
21
  /**
30
22
  * 字段名称正则
31
23
  * 必须为中文、数字、字母、下划线、短横线、空格
32
24
  */
33
25
  const FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
34
-
35
26
  /**
36
27
  * VARCHAR 最大长度限制
37
28
  */
38
29
  const MAX_VARCHAR_LENGTH = 65535;
39
-
40
30
  /**
41
31
  * 检查表定义文件
42
32
  * @throws 当检查失败时抛出异常
43
33
  */
44
- export async function checkTable(tables: ScanFileResult[]): Promise<void> {
34
+ export async function checkTable(tables) {
45
35
  // 收集所有表文件
46
36
  let hasError = false;
47
-
48
37
  // 合并进行验证逻辑
49
38
  for (const item of tables) {
50
39
  if (item.type !== "table") {
51
40
  continue;
52
41
  }
53
-
54
42
  const sourceName = typeof item.sourceName === "string" ? item.sourceName : "";
55
-
56
43
  try {
57
44
  const fileName = item.fileName;
58
45
  const table = item.content || {};
@@ -62,7 +49,6 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
62
49
  hasError = true;
63
50
  continue;
64
51
  }
65
-
66
52
  // 检查 table 中的每个验证规则
67
53
  for (const [colKey, fieldDef] of Object.entries(table)) {
68
54
  if (typeof fieldDef !== "object" || fieldDef === null || Array.isArray(fieldDef)) {
@@ -70,24 +56,20 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
70
56
  hasError = true;
71
57
  continue;
72
58
  }
73
-
74
59
  // 检查是否使用了保留字段
75
- if (RESERVED_FIELDS.includes(colKey as any)) {
60
+ if (RESERVED_FIELDS.includes(colKey)) {
76
61
  Logger.warn(`${sourceName}表 ${fileName} 文件包含保留字段 ${colKey},` + `不能在表定义中使用以下字段: ${RESERVED_FIELDS.join(", ")}`);
77
62
  hasError = true;
78
63
  }
79
-
80
64
  // 直接使用字段对象
81
- const field = fieldDef as FieldDefinition;
82
-
65
+ const field = fieldDef;
83
66
  // 检查是否存在非法属性
84
67
  const fieldKeys = Object.keys(field);
85
- const illegalProps = fieldKeys.filter((key) => !ALLOWED_FIELD_PROPERTIES.includes(key as any));
68
+ const illegalProps = fieldKeys.filter((key) => !ALLOWED_FIELD_PROPERTIES.includes(key));
86
69
  if (illegalProps.length > 0) {
87
70
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 包含非法属性: ${illegalProps.join(", ")},` + `允许的属性为: ${ALLOWED_FIELD_PROPERTIES.join(", ")}`);
88
71
  hasError = true;
89
72
  }
90
-
91
73
  // 检查必填字段:name, type
92
74
  if (!field.name || typeof field.name !== "string") {
93
75
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 缺少必填字段 name 或类型错误`);
@@ -99,7 +81,6 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
99
81
  hasError = true;
100
82
  continue;
101
83
  }
102
-
103
84
  // 检查可选字段的类型
104
85
  if (field.min !== undefined && !(field.min === null || typeof field.min === "number")) {
105
86
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 字段 min 类型错误,必须为 null 或数字`);
@@ -133,33 +114,27 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
133
114
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 字段 regexp 类型错误,必须为 null 或字符串`);
134
115
  hasError = true;
135
116
  }
136
-
137
117
  const { name: fieldName, type: fieldType, min: fieldMin, max: fieldMax, default: fieldDefault } = field;
138
-
139
118
  // 字段名称必须为中文、数字、字母、下划线、短横线、空格
140
119
  if (!FIELD_NAME_REGEX.test(fieldName)) {
141
120
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 字段名称 "${fieldName}" 格式错误,` + `必须为中文、数字、字母、下划线、短横线、空格`);
142
121
  hasError = true;
143
122
  }
144
-
145
123
  // 字段类型必须为string,number,text,array_string,array_text之一
146
- if (!FIELD_TYPES.includes(fieldType as any)) {
124
+ if (!FIELD_TYPES.includes(fieldType)) {
147
125
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 字段类型 "${fieldType}" 格式错误,` + `必须为${FIELD_TYPES.join("、")}之一`);
148
126
  hasError = true;
149
127
  }
150
-
151
128
  // unsigned 仅对 number 类型有效(且仅 MySQL 语义上生效)
152
129
  if (fieldType !== "number" && field.unsigned !== undefined) {
153
130
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 字段类型为 ${fieldType},不允许设置 unsigned(仅 number 类型有效)`);
154
131
  hasError = true;
155
132
  }
156
-
157
133
  // 约束:unique 与 index 不能同时为 true(否则会重复索引),必须阻断启动。
158
134
  if (field.unique === true && field.index === true) {
159
135
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 同时设置了 unique=true 和 index=true,` + `unique 和 index 不能同时设置,请删除其一(否则会创建重复索引)`);
160
136
  hasError = true;
161
137
  }
162
-
163
138
  // 约束:当最小值与最大值均为数字时,要求最小值 <= 最大值
164
139
  if (fieldMin !== undefined && fieldMax !== undefined && fieldMin !== null && fieldMax !== null) {
165
140
  if (fieldMin > fieldMax) {
@@ -167,7 +142,6 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
167
142
  hasError = true;
168
143
  }
169
144
  }
170
-
171
145
  // 类型联动校验 + 默认值规则
172
146
  if (fieldType === "text" || fieldType === "array_text" || fieldType === "array_number_text") {
173
147
  // text / array_text / array_number_text:min/max 必须为 null,默认值必须为 null,且不支持索引/唯一约束
@@ -183,7 +157,6 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
183
157
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,默认值必须为 null,当前为 "${fieldDefault}"`);
184
158
  hasError = true;
185
159
  }
186
-
187
160
  if (field.index === true) {
188
161
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,不支持创建索引(index=true 无效)`);
189
162
  hasError = true;
@@ -192,15 +165,18 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
192
165
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,不支持唯一约束(unique=true 无效)`);
193
166
  hasError = true;
194
167
  }
195
- } else if (fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string") {
168
+ }
169
+ else if (fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string") {
196
170
  if (fieldMax !== undefined && (fieldMax === null || typeof fieldMax !== "number")) {
197
171
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 为 ${fieldType} 类型,` + `最大长度必须为数字,当前为 "${fieldMax}"`);
198
172
  hasError = true;
199
- } else if (fieldMax !== undefined && fieldMax > MAX_VARCHAR_LENGTH) {
173
+ }
174
+ else if (fieldMax !== undefined && fieldMax > MAX_VARCHAR_LENGTH) {
200
175
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 最大长度 ${fieldMax} 越界,` + `${fieldType} 类型长度必须在 1..${MAX_VARCHAR_LENGTH} 范围内`);
201
176
  hasError = true;
202
177
  }
203
- } else if (fieldType === "number") {
178
+ }
179
+ else if (fieldType === "number") {
204
180
  // number 类型:default 如果存在,必须为 null 或 number
205
181
  if (fieldDefault !== undefined && fieldDefault !== null && typeof fieldDefault !== "number") {
206
182
  Logger.warn(`${sourceName}表 ${fileName} 文件 ${colKey} 为 number 类型,` + `默认值必须为数字或 null,当前为 "${fieldDefault}"`);
@@ -208,12 +184,12 @@ export async function checkTable(tables: ScanFileResult[]): Promise<void> {
208
184
  }
209
185
  }
210
186
  }
211
- } catch (error: any) {
187
+ }
188
+ catch (error) {
212
189
  Logger.error(`${sourceName}表 ${item.fileName} 解析失败`, error);
213
190
  hasError = true;
214
191
  }
215
192
  }
216
-
217
193
  if (hasError) {
218
194
  throw new Error("表结构检查失败");
219
195
  }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 预定义的默认字段(API fields 的 @ 引用)
3
+ */
4
+ export declare const presetFields: Record<string, any>;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 预定义的默认字段(API fields 的 @ 引用)
3
3
  */
4
- export const presetFields: Record<string, any> = {
4
+ export const presetFields = {
5
5
  "@id": { name: "ID", type: "number", min: 1, max: null },
6
6
  "@page": { name: "页码", type: "number", min: 1, max: 9999, default: 1 },
7
7
  "@limit": { name: "每页数量", type: "number", min: 1, max: 100, default: 30 },
@@ -0,0 +1,145 @@
1
+ /**
2
+ * 内置正则表达式别名
3
+ * 用于表单验证和数据校验
4
+ * 命名规范:小驼峰格式
5
+ */
6
+ export declare const RegexAliases: {
7
+ /** 正整数(不含0) */
8
+ readonly number: "^\\d+$";
9
+ /** 整数(含负数) */
10
+ readonly integer: "^-?\\d+$";
11
+ /** 浮点数 */
12
+ readonly float: "^-?\\d+(\\.\\d+)?$";
13
+ /** 正整数(不含0) */
14
+ readonly positive: "^[1-9]\\d*$";
15
+ /** 负整数 */
16
+ readonly negative: "^-\\d+$";
17
+ /** 零 */
18
+ readonly zero: "^0$";
19
+ /** 纯字母 */
20
+ readonly word: "^[a-zA-Z]+$";
21
+ /** 字母和数字 */
22
+ readonly alphanumeric: "^[a-zA-Z0-9]+$";
23
+ /** 字母、数字和下划线 */
24
+ readonly alphanumeric_: "^[a-zA-Z0-9_]+$";
25
+ /** 字母、数字、下划线和短横线 */
26
+ readonly alphanumericDash_: "^[a-zA-Z0-9_-]+$";
27
+ /** 小写字母 */
28
+ readonly lowercase: "^[a-z]+$";
29
+ /** 大写字母 */
30
+ readonly uppercase: "^[A-Z]+$";
31
+ /** 纯中文 */
32
+ readonly chinese: "^[\\u4e00-\\u9fa5]+$";
33
+ /** 中文和字母 */
34
+ readonly chineseWord: "^[\\u4e00-\\u9fa5a-zA-Z]+$";
35
+ /** 邮箱地址 */
36
+ readonly email: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
37
+ /** 中国大陆手机号 */
38
+ readonly phone: "^1[3-9]\\d{9}$";
39
+ /** 固定电话(区号-号码) */
40
+ readonly telephone: "^0\\d{2,3}-?\\d{7,8}$";
41
+ /** URL 地址 */
42
+ readonly url: "^https?://";
43
+ /** IPv4 地址 */
44
+ readonly ip: "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
45
+ /** IPv6 地址 */
46
+ readonly ipv6: "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$";
47
+ /** 域名 */
48
+ readonly domain: "^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$";
49
+ /** UUID */
50
+ readonly uuid: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
51
+ /** 十六进制字符串 */
52
+ readonly hex: "^[0-9a-fA-F]+$";
53
+ /** Base64 编码 */
54
+ readonly base64: "^[A-Za-z0-9+/=]+$";
55
+ /** MD5 哈希 */
56
+ readonly md5: "^[a-f0-9]{32}$";
57
+ /** SHA1 哈希 */
58
+ readonly sha1: "^[a-f0-9]{40}$";
59
+ /** SHA256 哈希 */
60
+ readonly sha256: "^[a-f0-9]{64}$";
61
+ /** 日期 YYYY-MM-DD */
62
+ readonly date: "^\\d{4}-\\d{2}-\\d{2}$";
63
+ /** 时间 HH:MM:SS */
64
+ readonly time: "^\\d{2}:\\d{2}:\\d{2}$";
65
+ /** ISO 日期时间 */
66
+ readonly datetime: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}";
67
+ /** 年份 */
68
+ readonly year: "^\\d{4}$";
69
+ /** 月份 01-12 */
70
+ readonly month: "^(0[1-9]|1[0-2])$";
71
+ /** 日期 01-31 */
72
+ readonly day: "^(0[1-9]|[12]\\d|3[01])$";
73
+ /** 变量名 */
74
+ readonly variable: "^[a-zA-Z_][a-zA-Z0-9_]*$";
75
+ /** 常量名(全大写) */
76
+ readonly constant: "^[A-Z][A-Z0-9_]*$";
77
+ /** 包名(小写+连字符) */
78
+ readonly package: "^[a-z][a-z0-9-]*$";
79
+ /** 中国身份证号(18位) */
80
+ readonly idCard: "^\\d{17}[\\dXx]$";
81
+ /** 护照号 */
82
+ readonly passport: "^[a-zA-Z0-9]{5,17}$";
83
+ /** 银行卡号(16-19位数字) */
84
+ readonly bankCard: "^\\d{16,19}$";
85
+ /** 微信号(6-20位,字母开头,可包含字母、数字、下划线、减号) */
86
+ readonly wechat: "^[a-zA-Z][a-zA-Z0-9_-]{5,19}$";
87
+ /** QQ号(5-11位数字,首位非0) */
88
+ readonly qq: "^[1-9]\\d{4,10}$";
89
+ /** 支付宝账号(手机号或邮箱) */
90
+ readonly alipay: "^(1[3-9]\\d{9}|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$";
91
+ /** 用户名(4-20位,字母开头,可包含字母、数字、下划线) */
92
+ readonly username: "^[a-zA-Z][a-zA-Z0-9_]{3,19}$";
93
+ /** 昵称(2-20位,支持中文、字母、数字) */
94
+ readonly nickname: "^[\\u4e00-\\u9fa5a-zA-Z0-9]{2,20}$";
95
+ /** 弱密码(至少6位) */
96
+ readonly passwordWeak: "^.{6,}$";
97
+ /** 中等密码(至少8位,包含字母和数字) */
98
+ readonly passwordMedium: "^(?=.*[a-zA-Z])(?=.*\\d).{8,}$";
99
+ /** 强密码(至少8位,包含大小写字母、数字和特殊字符) */
100
+ readonly passwordStrong: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*]).{8,}$";
101
+ /** 车牌号(新能源+普通) */
102
+ readonly licensePlate: "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$";
103
+ /** 邮政编码 */
104
+ readonly postalCode: "^\\d{6}$";
105
+ /** 版本号(语义化版本) */
106
+ readonly semver: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$";
107
+ /** 颜色值(十六进制) */
108
+ readonly colorHex: "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$";
109
+ /** 空字符串 */
110
+ readonly empty: "^$";
111
+ /** 非空 */
112
+ readonly notempty: ".+";
113
+ };
114
+ /**
115
+ * 正则别名类型
116
+ */
117
+ export type RegexAliasName = keyof typeof RegexAliases;
118
+ /**
119
+ * 获取正则表达式字符串
120
+ * @param name 正则别名(以 @ 开头)或自定义正则字符串
121
+ * @returns 正则表达式字符串
122
+ */
123
+ export declare function getRegex(name: string): string;
124
+ /**
125
+ * 获取编译后的正则表达式对象(带缓存)
126
+ * @param pattern 正则别名或正则字符串
127
+ * @param flags 正则标志(如 'i', 'g')
128
+ * @returns 编译后的 RegExp 对象
129
+ */
130
+ export declare function getCompiledRegex(pattern: string, flags?: string): RegExp;
131
+ /**
132
+ * 验证值是否匹配正则(使用缓存)
133
+ * @param value 要验证的值
134
+ * @param pattern 正则别名或正则字符串
135
+ * @returns 是否匹配
136
+ */
137
+ export declare function matchRegex(value: string, pattern: string): boolean;
138
+ /**
139
+ * 清除正则缓存
140
+ */
141
+ export declare function clearRegexCache(): void;
142
+ /**
143
+ * 获取缓存大小
144
+ */
145
+ export declare function getRegexCacheSize(): number;