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,68 @@
1
+ import type { WhereConditions } from "../types/common";
2
+ export declare class DbUtils {
3
+ static parseTableRef(tableRef: string): {
4
+ schema: string | null;
5
+ table: string;
6
+ alias: string | null;
7
+ };
8
+ /**
9
+ * 规范化表引用:只 snakeCase schema/table,本身 alias 保持原样。
10
+ * - 支持:table / table alias / schema.table / schema.table alias
11
+ */
12
+ static normalizeTableRef(tableRef: string): string;
13
+ /**
14
+ * JOIN 场景下主表的限定符:优先使用 alias;没有 alias 时使用 snakeCase(table)。
15
+ * 用于构造类似 "o.state$gt" 的 where key,避免出现 "order o.state$gt" 这种带空格的非法 key。
16
+ */
17
+ static getJoinMainQualifier(tableRef: string): string;
18
+ /**
19
+ * 字段数组转下划线格式
20
+ * 支持排除字段语法:['!password', '!token']
21
+ *
22
+ * 说明:exclude 模式需要表的所有字段名,因此通过 getTableColumns 回调获取
23
+ */
24
+ static fieldsToSnake(table: string, fields: string[], getTableColumns: (table: string) => Promise<string[]>): Promise<string[]>;
25
+ static validateAndClassifyFields(fields?: string[]): {
26
+ type: "all" | "include" | "exclude";
27
+ fields: string[];
28
+ };
29
+ static orderByToSnake(orderBy: string[]): string[];
30
+ static processJoinField(field: string): string;
31
+ static processJoinWhereKey(key: string): string;
32
+ static processJoinWhere(where: any): any;
33
+ static processJoinOrderBy(orderBy: string[]): string[];
34
+ static addDefaultStateFilter(where?: WhereConditions, table?: string, hasJoins?: boolean): WhereConditions;
35
+ /**
36
+ * Where 条件键名转下划线格式(递归处理嵌套)
37
+ * 支持操作符字段(如 userId$gt)和逻辑操作符($or, $and)
38
+ */
39
+ static whereKeysToSnake(where: any): any;
40
+ /**
41
+ * 序列化数组字段(写入数据库前)
42
+ * 将数组类型的字段转换为 JSON 字符串
43
+ */
44
+ static serializeArrayFields(data: Record<string, any>): Record<string, any>;
45
+ /**
46
+ * 反序列化数组字段(从数据库读取后)
47
+ * 将 JSON 字符串转换回数组
48
+ */
49
+ static deserializeArrayFields<T = any>(data: Record<string, any> | null): T | null;
50
+ static cleanAndSnakeAndSerializeWriteData(data: Record<string, any>, excludeValues?: any[]): Record<string, any>;
51
+ static stripSystemFieldsForWrite(data: Record<string, any>, options: {
52
+ allowState: boolean;
53
+ }): Record<string, any>;
54
+ static buildInsertRow(options: {
55
+ data: Record<string, any>;
56
+ id: number;
57
+ now: number;
58
+ }): Record<string, any>;
59
+ static buildUpdateRow(options: {
60
+ data: Record<string, any>;
61
+ now: number;
62
+ allowState: boolean;
63
+ }): Record<string, any>;
64
+ static buildPartialUpdateData(options: {
65
+ data: Record<string, any>;
66
+ allowState: boolean;
67
+ }): Record<string, any>;
68
+ }
@@ -1,88 +1,68 @@
1
- import type { WhereConditions } from "../types/common.ts";
2
-
3
- import { snakeCase } from "es-toolkit/string";
4
-
5
- import { fieldClear } from "../utils/fieldClear.ts";
6
- import { keysToSnake } from "../utils/keysToSnake.ts";
7
-
1
+ import { fieldClear } from "../utils/fieldClear";
2
+ import { keysToSnake, snakeCase } from "../utils/util";
8
3
  export class DbUtils {
9
- static parseTableRef(tableRef: string): { schema: string | null; table: string; alias: string | null } {
4
+ static parseTableRef(tableRef) {
10
5
  if (typeof tableRef !== "string") {
11
6
  throw new Error(`tableRef 必须是字符串 (tableRef: ${String(tableRef)})`);
12
7
  }
13
-
14
8
  const trimmed = tableRef.trim();
15
9
  if (!trimmed) {
16
10
  throw new Error("tableRef 不能为空");
17
11
  }
18
-
19
12
  const parts = trimmed.split(/\s+/).filter((p) => p.length > 0);
20
13
  if (parts.length > 2) {
21
14
  throw new Error(`不支持的表引用格式(包含过多片段)。请使用最简形式:table 或 table alias 或 schema.table 或 schema.table alias (tableRef: ${trimmed})`);
22
15
  }
23
-
24
16
  const namePart = parts[0];
25
17
  const aliasPart = parts.length === 2 ? parts[1] : null;
26
-
27
18
  const nameSegments = namePart.split(".");
28
19
  if (nameSegments.length > 2) {
29
20
  throw new Error(`不支持的表引用格式(schema 层级过深) (tableRef: ${trimmed})`);
30
21
  }
31
-
32
22
  const schema = nameSegments.length === 2 ? nameSegments[0] : null;
33
23
  const table = nameSegments.length === 2 ? nameSegments[1] : nameSegments[0];
34
-
35
24
  return { schema: schema, table: table, alias: aliasPart };
36
25
  }
37
-
38
26
  /**
39
27
  * 规范化表引用:只 snakeCase schema/table,本身 alias 保持原样。
40
28
  * - 支持:table / table alias / schema.table / schema.table alias
41
29
  */
42
- static normalizeTableRef(tableRef: string): string {
30
+ static normalizeTableRef(tableRef) {
43
31
  const parsed = DbUtils.parseTableRef(tableRef);
44
-
45
32
  const schemaPart = parsed.schema ? snakeCase(parsed.schema) : null;
46
33
  const tablePart = snakeCase(parsed.table);
47
-
48
34
  let result = schemaPart ? `${schemaPart}.${tablePart}` : tablePart;
49
35
  if (parsed.alias) {
50
36
  result = `${result} ${parsed.alias}`;
51
37
  }
52
-
53
38
  return result;
54
39
  }
55
-
56
40
  /**
57
41
  * JOIN 场景下主表的限定符:优先使用 alias;没有 alias 时使用 snakeCase(table)。
58
42
  * 用于构造类似 "o.state$gt" 的 where key,避免出现 "order o.state$gt" 这种带空格的非法 key。
59
43
  */
60
- static getJoinMainQualifier(tableRef: string): string {
44
+ static getJoinMainQualifier(tableRef) {
61
45
  const parsed = DbUtils.parseTableRef(tableRef);
62
46
  if (parsed.alias) {
63
47
  return parsed.alias;
64
48
  }
65
49
  return snakeCase(parsed.table);
66
50
  }
67
-
68
51
  /**
69
52
  * 字段数组转下划线格式
70
53
  * 支持排除字段语法:['!password', '!token']
71
54
  *
72
55
  * 说明:exclude 模式需要表的所有字段名,因此通过 getTableColumns 回调获取
73
56
  */
74
- static async fieldsToSnake(table: string, fields: string[], getTableColumns: (table: string) => Promise<string[]>): Promise<string[]> {
57
+ static async fieldsToSnake(table, fields, getTableColumns) {
75
58
  if (!fields || !Array.isArray(fields)) {
76
59
  return ["*"];
77
60
  }
78
-
79
61
  const classified = DbUtils.validateAndClassifyFields(fields);
80
-
81
62
  // 情况1:查询所有字段
82
63
  if (classified.type === "all") {
83
64
  return ["*"];
84
65
  }
85
-
86
66
  // 情况2:指定包含字段
87
67
  if (classified.type === "include") {
88
68
  return classified.fields.map((field) => {
@@ -93,83 +73,64 @@ export class DbUtils {
93
73
  return snakeCase(field);
94
74
  });
95
75
  }
96
-
97
76
  // 情况3:排除字段
98
77
  if (classified.type === "exclude") {
99
78
  const allColumns = await getTableColumns(table);
100
79
  const excludeSnakeFields = classified.fields.map((f) => snakeCase(f));
101
-
102
80
  const resultFields = allColumns.filter((col) => !excludeSnakeFields.includes(col));
103
81
  if (resultFields.length === 0) {
104
82
  throw new Error(`排除字段后没有剩余字段可查询。表: ${table}, 排除: ${excludeSnakeFields.join(", ")}`);
105
83
  }
106
-
107
84
  return resultFields;
108
85
  }
109
-
110
86
  return ["*"];
111
87
  }
112
-
113
- static validateAndClassifyFields(fields?: string[]): {
114
- type: "all" | "include" | "exclude";
115
- fields: string[];
116
- } {
88
+ static validateAndClassifyFields(fields) {
117
89
  // 情况1:空数组或 undefined,表示查询所有
118
90
  if (!fields || fields.length === 0) {
119
91
  return { type: "all", fields: [] };
120
92
  }
121
-
122
93
  // 检测是否有星号(禁止)
123
94
  if (fields.some((f) => f === "*")) {
124
95
  throw new Error("fields 不支持 * 星号,请使用空数组 [] 或不传参数表示查询所有字段");
125
96
  }
126
-
127
97
  // 检测是否有空字符串或无效值
128
98
  if (fields.some((f) => !f || typeof f !== "string" || f.trim() === "")) {
129
99
  throw new Error("fields 不能包含空字符串或无效值");
130
100
  }
131
-
132
101
  // 统计包含字段和排除字段
133
102
  const includeFields = fields.filter((f) => !f.startsWith("!"));
134
103
  const excludeFields = fields.filter((f) => f.startsWith("!"));
135
-
136
104
  // 情况2:全部是包含字段
137
105
  if (includeFields.length > 0 && excludeFields.length === 0) {
138
106
  return { type: "include", fields: includeFields };
139
107
  }
140
-
141
108
  // 情况3:全部是排除字段
142
109
  if (excludeFields.length > 0 && includeFields.length === 0) {
143
110
  // 去掉感叹号前缀
144
111
  const cleanExcludeFields = excludeFields.map((f) => f.substring(1));
145
112
  return { type: "exclude", fields: cleanExcludeFields };
146
113
  }
147
-
148
114
  // 混用情况:报错
149
115
  throw new Error('fields 不能同时包含普通字段和排除字段(! 开头)。只能使用以下3种方式之一:\n1. 空数组 [] 或不传(查询所有)\n2. 全部指定字段 ["id", "name"]\n3. 全部排除字段 ["!password", "!token"]');
150
116
  }
151
-
152
- static orderByToSnake(orderBy: string[]): string[] {
117
+ static orderByToSnake(orderBy) {
153
118
  if (!orderBy || !Array.isArray(orderBy)) {
154
119
  return orderBy;
155
120
  }
156
-
157
121
  return orderBy.map((item) => {
158
122
  if (typeof item !== "string" || !item.includes("#")) {
159
123
  return item;
160
124
  }
161
-
162
125
  const [field, direction] = item.split("#");
163
126
  return `${snakeCase(field.trim())}#${direction.trim()}`;
164
127
  });
165
128
  }
166
-
167
- static processJoinField(field: string): string {
129
+ static processJoinField(field) {
168
130
  // 跳过函数、星号、已处理的字段
169
131
  if (field.includes("(") || field === "*" || field.startsWith("`")) {
170
132
  return field;
171
133
  }
172
-
173
134
  // 处理别名 AS
174
135
  if (field.toUpperCase().includes(" AS ")) {
175
136
  const parts = field.split(/\s+AS\s+/i);
@@ -177,7 +138,6 @@ export class DbUtils {
177
138
  const aliasPart = parts[1].trim();
178
139
  return `${DbUtils.processJoinField(fieldPart)} AS ${aliasPart}`;
179
140
  }
180
-
181
141
  // 处理表别名.字段名(JOIN 模式下,点号前面通常是别名,不应被 snakeCase 改写)
182
142
  if (field.includes(".")) {
183
143
  const parts = field.split(".");
@@ -185,33 +145,27 @@ export class DbUtils {
185
145
  const fieldName = parts[1];
186
146
  return `${tableName.trim()}.${snakeCase(fieldName)}`;
187
147
  }
188
-
189
148
  // 普通字段
190
149
  return snakeCase(field);
191
150
  }
192
-
193
- static processJoinWhereKey(key: string): string {
151
+ static processJoinWhereKey(key) {
194
152
  // 保留逻辑操作符
195
153
  if (key === "$or" || key === "$and") {
196
154
  return key;
197
155
  }
198
-
199
156
  // 处理带操作符的字段名(如 user.userId$gt)
200
157
  if (key.includes("$")) {
201
158
  const lastDollarIndex = key.lastIndexOf("$");
202
159
  const fieldPart = key.substring(0, lastDollarIndex);
203
160
  const operator = key.substring(lastDollarIndex);
204
-
205
161
  if (fieldPart.includes(".")) {
206
162
  const parts = fieldPart.split(".");
207
163
  const tableName = parts[0];
208
164
  const fieldName = parts[1];
209
165
  return `${tableName.trim()}.${snakeCase(fieldName)}${operator}`;
210
166
  }
211
-
212
167
  return `${snakeCase(fieldPart)}${operator}`;
213
168
  }
214
-
215
169
  // 处理表名.字段名
216
170
  if (key.includes(".")) {
217
171
  const parts = key.split(".");
@@ -219,101 +173,86 @@ export class DbUtils {
219
173
  const fieldName = parts[1];
220
174
  return `${tableName.trim()}.${snakeCase(fieldName)}`;
221
175
  }
222
-
223
176
  // 普通字段
224
177
  return snakeCase(key);
225
178
  }
226
-
227
- static processJoinWhere(where: any): any {
179
+ static processJoinWhere(where) {
228
180
  if (!where || typeof where !== "object") {
229
181
  return where;
230
182
  }
231
-
232
183
  if (Array.isArray(where)) {
233
184
  return where.map((item) => DbUtils.processJoinWhere(item));
234
185
  }
235
-
236
- const result: any = {};
186
+ const result = {};
237
187
  for (const [key, value] of Object.entries(where)) {
238
188
  const newKey = DbUtils.processJoinWhereKey(key);
239
-
240
189
  if (key === "$or" || key === "$and") {
241
- result[newKey] = (value as any[]).map((item) => DbUtils.processJoinWhere(item));
242
- } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
190
+ result[newKey] = value.map((item) => DbUtils.processJoinWhere(item));
191
+ }
192
+ else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
243
193
  result[newKey] = DbUtils.processJoinWhere(value);
244
- } else {
194
+ }
195
+ else {
245
196
  result[newKey] = value;
246
197
  }
247
198
  }
248
-
249
199
  return result;
250
200
  }
251
-
252
- static processJoinOrderBy(orderBy: string[]): string[] {
201
+ static processJoinOrderBy(orderBy) {
253
202
  if (!orderBy || !Array.isArray(orderBy)) {
254
203
  return orderBy;
255
204
  }
256
-
257
205
  return orderBy.map((item) => {
258
206
  if (typeof item !== "string" || !item.includes("#")) {
259
207
  return item;
260
208
  }
261
-
262
209
  const [field, direction] = item.split("#");
263
210
  return `${DbUtils.processJoinField(field.trim())}#${direction.trim()}`;
264
211
  });
265
212
  }
266
-
267
- static addDefaultStateFilter(where: WhereConditions = {}, table?: string, hasJoins: boolean = false): WhereConditions {
213
+ static addDefaultStateFilter(where = {}, table, hasJoins = false) {
268
214
  // 如果用户已经指定了 state 条件,优先使用用户的条件
269
215
  const hasStateCondition = Object.keys(where).some((key) => key.startsWith("state") || key.includes(".state"));
270
-
271
216
  if (hasStateCondition) {
272
217
  return where;
273
218
  }
274
-
275
219
  // JOIN 查询时需要指定主表名前缀避免歧义
276
220
  if (hasJoins && table) {
277
221
  // table 可能带别名("order o"),这里只需要别名/主表引用本身,不做 snakeCase 改写
278
- const result: any = {};
222
+ const result = {};
279
223
  for (const [key, value] of Object.entries(where)) {
280
224
  result[key] = value;
281
225
  }
282
226
  result[`${table}.state$gt`] = 0;
283
227
  return result;
284
228
  }
285
-
286
229
  // 默认查询 state > 0 的数据
287
- const result: any = {};
230
+ const result = {};
288
231
  for (const [key, value] of Object.entries(where)) {
289
232
  result[key] = value;
290
233
  }
291
234
  result.state$gt = 0;
292
235
  return result;
293
236
  }
294
-
295
237
  /**
296
238
  * Where 条件键名转下划线格式(递归处理嵌套)
297
239
  * 支持操作符字段(如 userId$gt)和逻辑操作符($or, $and)
298
240
  */
299
- static whereKeysToSnake(where: any): any {
241
+ static whereKeysToSnake(where) {
300
242
  if (!where || typeof where !== "object") {
301
243
  return where;
302
244
  }
303
-
304
245
  // 处理数组($or, $and 等)
305
246
  if (Array.isArray(where)) {
306
247
  return where.map((item) => DbUtils.whereKeysToSnake(item));
307
248
  }
308
-
309
- const result: any = {};
249
+ const result = {};
310
250
  for (const [key, value] of Object.entries(where)) {
311
251
  // 保留 $or, $and 等逻辑操作符
312
252
  if (key === "$or" || key === "$and") {
313
- result[key] = (value as any[]).map((item) => DbUtils.whereKeysToSnake(item));
253
+ result[key] = value.map((item) => DbUtils.whereKeysToSnake(item));
314
254
  continue;
315
255
  }
316
-
317
256
  // 处理带操作符的字段名(如 userId$gt)
318
257
  if (key.includes("$")) {
319
258
  const lastDollarIndex = key.lastIndexOf("$");
@@ -323,127 +262,113 @@ export class DbUtils {
323
262
  result[snakeKey] = value;
324
263
  continue;
325
264
  }
326
-
327
265
  // 普通字段:转换键名,递归处理值(支持嵌套对象)
328
266
  const snakeKey = snakeCase(key);
329
267
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
330
268
  result[snakeKey] = DbUtils.whereKeysToSnake(value);
331
- } else {
269
+ }
270
+ else {
332
271
  result[snakeKey] = value;
333
272
  }
334
273
  }
335
-
336
274
  return result;
337
275
  }
338
-
339
276
  /**
340
277
  * 序列化数组字段(写入数据库前)
341
278
  * 将数组类型的字段转换为 JSON 字符串
342
279
  */
343
- static serializeArrayFields(data: Record<string, any>): Record<string, any> {
344
- const serialized: Record<string, any> = {};
345
-
280
+ static serializeArrayFields(data) {
281
+ const serialized = {};
346
282
  for (const [key, value] of Object.entries(data)) {
347
283
  if (value === null || value === undefined) {
348
284
  serialized[key] = value;
349
285
  continue;
350
286
  }
351
-
352
287
  if (Array.isArray(value)) {
353
288
  serialized[key] = JSON.stringify(value);
354
289
  continue;
355
290
  }
356
-
357
291
  serialized[key] = value;
358
292
  }
359
-
360
293
  return serialized;
361
294
  }
362
-
363
295
  /**
364
296
  * 反序列化数组字段(从数据库读取后)
365
297
  * 将 JSON 字符串转换回数组
366
298
  */
367
- static deserializeArrayFields<T = any>(data: Record<string, any> | null): T | null {
299
+ static deserializeArrayFields(data) {
368
300
  if (!data) {
369
301
  return null;
370
302
  }
371
-
372
- const deserialized: Record<string, any> = {};
303
+ const deserialized = {};
373
304
  for (const [key, value] of Object.entries(data)) {
374
305
  deserialized[key] = value;
375
306
  }
376
-
377
307
  for (const [key, value] of Object.entries(deserialized)) {
378
308
  if (typeof value !== "string") {
379
309
  continue;
380
310
  }
381
-
382
311
  if (value.startsWith("[") && value.endsWith("]")) {
383
312
  try {
384
313
  const parsed = JSON.parse(value);
385
314
  if (Array.isArray(parsed)) {
386
315
  deserialized[key] = parsed;
387
316
  }
388
- } catch {
317
+ }
318
+ catch {
389
319
  // 解析失败则保持原值
390
320
  }
391
321
  }
392
322
  }
393
-
394
- return deserialized as T;
323
+ return deserialized;
395
324
  }
396
-
397
- static cleanAndSnakeAndSerializeWriteData(data: Record<string, any>, excludeValues: any[] = [null, undefined]): Record<string, any> {
325
+ static cleanAndSnakeAndSerializeWriteData(data, excludeValues = [null, undefined]) {
398
326
  const cleanData = fieldClear(data, { excludeValues: excludeValues });
399
327
  const snakeData = keysToSnake(cleanData);
400
328
  return DbUtils.serializeArrayFields(snakeData);
401
329
  }
402
-
403
- static stripSystemFieldsForWrite(data: Record<string, any>, options: { allowState: boolean }): Record<string, any> {
404
- const result: Record<string, any> = {};
330
+ static stripSystemFieldsForWrite(data, options) {
331
+ const result = {};
405
332
  for (const [key, value] of Object.entries(data)) {
406
333
  // 系统字段不可由用户覆盖
407
- if (key === "id") continue;
408
- if (key === "created_at") continue;
409
- if (key === "updated_at") continue;
410
- if (key === "deleted_at") continue;
411
- if (!options.allowState && key === "state") continue;
334
+ if (key === "id")
335
+ continue;
336
+ if (key === "created_at")
337
+ continue;
338
+ if (key === "updated_at")
339
+ continue;
340
+ if (key === "deleted_at")
341
+ continue;
342
+ if (!options.allowState && key === "state")
343
+ continue;
412
344
  result[key] = value;
413
345
  }
414
-
415
346
  return result;
416
347
  }
417
-
418
- static buildInsertRow(options: { data: Record<string, any>; id: number; now: number }): Record<string, any> {
348
+ static buildInsertRow(options) {
419
349
  const serializedData = DbUtils.cleanAndSnakeAndSerializeWriteData(options.data);
420
350
  const userData = DbUtils.stripSystemFieldsForWrite(serializedData, { allowState: false });
421
-
422
- const result: Record<string, any> = {};
351
+ const result = {};
423
352
  for (const [key, value] of Object.entries(userData)) {
424
353
  result[key] = value;
425
354
  }
426
-
427
355
  result.id = options.id;
428
356
  result.created_at = options.now;
429
357
  result.updated_at = options.now;
430
358
  result.state = 1;
431
359
  return result;
432
360
  }
433
-
434
- static buildUpdateRow(options: { data: Record<string, any>; now: number; allowState: boolean }): Record<string, any> {
361
+ static buildUpdateRow(options) {
435
362
  const serializedData = DbUtils.cleanAndSnakeAndSerializeWriteData(options.data);
436
363
  const userData = DbUtils.stripSystemFieldsForWrite(serializedData, { allowState: options.allowState });
437
-
438
- const result: Record<string, any> = {};
364
+ const result = {};
439
365
  for (const [key, value] of Object.entries(userData)) {
440
366
  result[key] = value;
441
367
  }
442
368
  result.updated_at = options.now;
443
369
  return result;
444
370
  }
445
-
446
- static buildPartialUpdateData(options: { data: Record<string, any>; allowState: boolean }): Record<string, any> {
371
+ static buildPartialUpdateData(options) {
447
372
  const serializedData = DbUtils.cleanAndSnakeAndSerializeWriteData(options.data);
448
373
  return DbUtils.stripSystemFieldsForWrite(serializedData, { allowState: options.allowState });
449
374
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * JWT 工具类 - 基于 fast-jwt 实现
3
+ */
4
+ import type { AuthConfig } from "../types/befly";
5
+ import type { JwtPayload, JwtSignOptions, JwtVerifyOptions, JwtDecoded } from "../types/jwt";
6
+ export declare class Jwt {
7
+ private config;
8
+ constructor(config?: AuthConfig);
9
+ sign(payload: JwtPayload, options?: JwtSignOptions): string;
10
+ verify<T = JwtPayload>(token: string, options?: JwtVerifyOptions): T;
11
+ decode(token: string, complete?: false): JwtPayload;
12
+ decode(token: string, complete: true): JwtDecoded;
13
+ }
@@ -1,35 +1,19 @@
1
1
  /**
2
2
  * JWT 工具类 - 基于 fast-jwt 实现
3
3
  */
4
-
5
- import type { AuthConfig } from "../types/befly.ts";
6
- import type { JwtPayload, JwtSignOptions, JwtVerifyOptions, JwtDecoded, JwtHeader } from "../types/jwt.ts";
7
- import type { Algorithm as FastJwtAlgorithm } from "fast-jwt";
8
-
9
4
  import { createSigner, createVerifier, createDecoder } from "fast-jwt";
10
-
11
- interface FastJwtComplete {
12
- header: JwtHeader;
13
- payload: JwtPayload;
14
- signature: string;
15
- input: string;
16
- }
17
-
18
5
  export class Jwt {
19
- private config: AuthConfig;
20
-
21
- constructor(config: AuthConfig = {}) {
6
+ config;
7
+ constructor(config = {}) {
22
8
  this.config = {
23
9
  secret: config.secret || "befly-secret",
24
10
  expiresIn: config.expiresIn || "7d",
25
11
  algorithm: config.algorithm || "HS256"
26
12
  };
27
13
  }
28
-
29
- sign(payload: JwtPayload, options: JwtSignOptions = {}): string {
14
+ sign(payload, options = {}) {
30
15
  const key = options.secret || this.config.secret || "befly-secret";
31
- const algorithm = (options.algorithm || this.config.algorithm || "HS256") as FastJwtAlgorithm;
32
-
16
+ const algorithm = (options.algorithm || this.config.algorithm || "HS256");
33
17
  const signer = createSigner({
34
18
  key: key,
35
19
  algorithm: algorithm,
@@ -42,15 +26,13 @@ export class Jwt {
42
26
  });
43
27
  return signer(payload);
44
28
  }
45
-
46
- verify<T = JwtPayload>(token: string, options: JwtVerifyOptions = {}): T {
29
+ verify(token, options = {}) {
47
30
  if (!token || typeof token !== "string") {
48
31
  throw new Error("Token必须是非空字符串");
49
32
  }
50
33
  const key = options.secret || this.config.secret || "befly-secret";
51
- const algorithm = (this.config.algorithm || "HS256") as FastJwtAlgorithm;
52
- const algorithms: FastJwtAlgorithm[] = options.algorithms ? (options.algorithms as FastJwtAlgorithm[]) : [algorithm];
53
-
34
+ const algorithm = (this.config.algorithm || "HS256");
35
+ const algorithms = options.algorithms ? options.algorithms : [algorithm];
54
36
  const verifier = createVerifier({
55
37
  key: key,
56
38
  algorithms: algorithms,
@@ -62,18 +44,15 @@ export class Jwt {
62
44
  cache: true,
63
45
  cacheTTL: 600000
64
46
  });
65
- return verifier(token) as T;
47
+ return verifier(token);
66
48
  }
67
-
68
- decode(token: string, complete?: false): JwtPayload;
69
- decode(token: string, complete: true): JwtDecoded;
70
- decode(token: string, complete: boolean = false): JwtPayload | JwtDecoded {
49
+ decode(token, complete = false) {
71
50
  if (!token || typeof token !== "string") {
72
51
  throw new Error("Token必须是非空字符串");
73
52
  }
74
53
  if (complete) {
75
54
  const decoder = createDecoder({ complete: true });
76
- const result = decoder(token) as FastJwtComplete;
55
+ const result = decoder(token);
77
56
  return {
78
57
  header: result.header,
79
58
  payload: result.payload,
@@ -81,6 +60,6 @@ export class Jwt {
81
60
  };
82
61
  }
83
62
  const decoder = createDecoder();
84
- return decoder(token) as JwtPayload;
63
+ return decoder(token);
85
64
  }
86
65
  }