befly 3.17.0 → 3.17.2

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 (150) hide show
  1. package/README.md +6 -0
  2. package/apis/admin/cacheRefresh.js +122 -0
  3. package/apis/admin/del.js +34 -0
  4. package/apis/admin/detail.js +23 -0
  5. package/apis/admin/ins.js +69 -0
  6. package/apis/admin/list.js +28 -0
  7. package/apis/admin/upd.js +95 -0
  8. package/apis/api/all.js +24 -0
  9. package/apis/api/list.js +31 -0
  10. package/apis/auth/login.js +123 -0
  11. package/apis/auth/sendSmsCode.js +24 -0
  12. package/apis/dashboard/configStatus.js +39 -0
  13. package/apis/dashboard/environmentInfo.js +43 -0
  14. package/apis/dashboard/performanceMetrics.js +20 -0
  15. package/apis/dashboard/permissionStats.js +27 -0
  16. package/apis/dashboard/serviceStatus.js +75 -0
  17. package/apis/dashboard/systemInfo.js +19 -0
  18. package/apis/dashboard/systemOverview.js +30 -0
  19. package/apis/dashboard/systemResources.js +106 -0
  20. package/apis/dict/all.js +23 -0
  21. package/apis/dict/del.js +16 -0
  22. package/apis/dict/detail.js +27 -0
  23. package/apis/dict/ins.js +51 -0
  24. package/apis/dict/items.js +30 -0
  25. package/apis/dict/list.js +36 -0
  26. package/apis/dict/upd.js +74 -0
  27. package/apis/dictType/all.js +16 -0
  28. package/apis/dictType/del.js +38 -0
  29. package/apis/dictType/detail.js +20 -0
  30. package/apis/dictType/ins.js +37 -0
  31. package/apis/dictType/list.js +26 -0
  32. package/apis/dictType/upd.js +51 -0
  33. package/apis/email/config.js +25 -0
  34. package/apis/email/logList.js +23 -0
  35. package/apis/email/send.js +66 -0
  36. package/apis/email/verify.js +21 -0
  37. package/apis/loginLog/list.js +23 -0
  38. package/apis/menu/all.js +41 -0
  39. package/apis/menu/list.js +25 -0
  40. package/apis/operateLog/list.js +23 -0
  41. package/apis/role/all.js +21 -0
  42. package/apis/role/apiSave.js +43 -0
  43. package/apis/role/apis.js +22 -0
  44. package/apis/role/del.js +49 -0
  45. package/apis/role/detail.js +32 -0
  46. package/apis/role/ins.js +46 -0
  47. package/apis/role/list.js +27 -0
  48. package/apis/role/menuSave.js +42 -0
  49. package/apis/role/menus.js +22 -0
  50. package/apis/role/save.js +40 -0
  51. package/apis/role/upd.js +50 -0
  52. package/apis/sysConfig/all.js +16 -0
  53. package/apis/sysConfig/del.js +36 -0
  54. package/apis/sysConfig/get.js +49 -0
  55. package/apis/sysConfig/ins.js +50 -0
  56. package/apis/sysConfig/list.js +24 -0
  57. package/apis/sysConfig/upd.js +62 -0
  58. package/checks/api.js +55 -0
  59. package/checks/config.js +107 -0
  60. package/checks/hook.js +38 -0
  61. package/checks/menu.js +58 -0
  62. package/checks/plugin.js +38 -0
  63. package/checks/table.js +78 -0
  64. package/configs/beflyConfig.json +61 -0
  65. package/configs/beflyMenus.json +85 -0
  66. package/configs/constConfig.js +34 -0
  67. package/configs/regexpAlias.json +55 -0
  68. package/hooks/auth.js +34 -0
  69. package/hooks/cors.js +39 -0
  70. package/hooks/parser.js +90 -0
  71. package/hooks/permission.js +71 -0
  72. package/hooks/validator.js +43 -0
  73. package/index.js +326 -0
  74. package/lib/cacheHelper.js +483 -0
  75. package/lib/cacheKeys.js +42 -0
  76. package/lib/connect.js +120 -0
  77. package/lib/dbHelper/builders.js +698 -0
  78. package/lib/dbHelper/context.js +131 -0
  79. package/lib/dbHelper/dataOps.js +505 -0
  80. package/lib/dbHelper/execute.js +65 -0
  81. package/lib/dbHelper/index.js +27 -0
  82. package/lib/dbHelper/transaction.js +43 -0
  83. package/lib/dbHelper/util.js +58 -0
  84. package/lib/dbHelper/validate.js +549 -0
  85. package/lib/emailHelper.js +110 -0
  86. package/lib/logger.js +604 -0
  87. package/lib/redisHelper.js +684 -0
  88. package/lib/sqlBuilder/batch.js +113 -0
  89. package/lib/sqlBuilder/check.js +150 -0
  90. package/lib/sqlBuilder/compiler.js +347 -0
  91. package/lib/sqlBuilder/errors.js +60 -0
  92. package/lib/sqlBuilder/index.js +218 -0
  93. package/lib/sqlBuilder/parser.js +296 -0
  94. package/lib/sqlBuilder/util.js +260 -0
  95. package/lib/validator.js +303 -0
  96. package/package.json +19 -12
  97. package/paths.js +112 -0
  98. package/plugins/cache.js +16 -0
  99. package/plugins/config.js +11 -0
  100. package/plugins/email.js +27 -0
  101. package/plugins/logger.js +20 -0
  102. package/plugins/mysql.js +36 -0
  103. package/plugins/redis.js +34 -0
  104. package/plugins/tool.js +155 -0
  105. package/router/api.js +140 -0
  106. package/router/static.js +71 -0
  107. package/sql/admin.sql +18 -0
  108. package/sql/api.sql +12 -0
  109. package/sql/dict.sql +13 -0
  110. package/sql/dictType.sql +12 -0
  111. package/sql/emailLog.sql +20 -0
  112. package/sql/loginLog.sql +25 -0
  113. package/sql/menu.sql +12 -0
  114. package/sql/operateLog.sql +22 -0
  115. package/sql/role.sql +14 -0
  116. package/sql/sysConfig.sql +16 -0
  117. package/sync/api.js +93 -0
  118. package/sync/cache.js +13 -0
  119. package/sync/dev.js +171 -0
  120. package/sync/menu.js +99 -0
  121. package/tables/admin.json +56 -0
  122. package/tables/api.json +26 -0
  123. package/tables/dict.json +30 -0
  124. package/tables/dictType.json +24 -0
  125. package/tables/emailLog.json +61 -0
  126. package/tables/loginLog.json +86 -0
  127. package/tables/menu.json +24 -0
  128. package/tables/operateLog.json +68 -0
  129. package/tables/role.json +32 -0
  130. package/tables/sysConfig.json +43 -0
  131. package/utils/calcPerfTime.js +13 -0
  132. package/utils/cors.js +17 -0
  133. package/utils/deepMerge.js +78 -0
  134. package/utils/fieldClear.js +65 -0
  135. package/utils/formatYmdHms.js +23 -0
  136. package/utils/formatZodIssues.js +109 -0
  137. package/utils/getClientIp.js +47 -0
  138. package/utils/importDefault.js +51 -0
  139. package/utils/is.js +462 -0
  140. package/utils/loggerUtils.js +185 -0
  141. package/utils/processInfo.js +39 -0
  142. package/utils/regexpUtil.js +52 -0
  143. package/utils/response.js +114 -0
  144. package/utils/scanFiles.js +124 -0
  145. package/utils/scanSources.js +68 -0
  146. package/utils/sortModules.js +75 -0
  147. package/utils/toSessionTtlSeconds.js +14 -0
  148. package/utils/util.js +374 -0
  149. package/befly.js +0 -16413
  150. package/befly.min.js +0 -72
@@ -0,0 +1,218 @@
1
+ /**
2
+ * SQL 构造器 - JavaScript 版本
3
+ * 提供链式 API 构建 SQL 查询
4
+ */
5
+
6
+ import { resolveQuoteIdent, normalizeLimitValue, normalizeOffsetValue } from "./util.js";
7
+ import { appendGroupByItems, appendHavingItems, appendJoinItem, appendOrderByItems, appendSelectItems, appendSelectRaw, appendWhereInput, appendWhereRaw, createWhereRoot, setFromValue } from "./parser.js";
8
+ import { compileCount, compileDelete, compileInsert, compileSelect, compileUpdate, compileWhere } from "./compiler.js";
9
+ import { toDeleteInSql, toUpdateCaseByIdSql } from "./batch.js";
10
+
11
+ function createModel() {
12
+ return {
13
+ select: [],
14
+ from: null,
15
+ where: createWhereRoot(),
16
+ joins: [],
17
+ orderBy: [],
18
+ groupBy: [],
19
+ having: [],
20
+ limit: null,
21
+ offset: null
22
+ };
23
+ }
24
+
25
+ /**
26
+ * SQL 构建器类
27
+ */
28
+ export class SqlBuilder {
29
+ _model;
30
+ _quoteIdent;
31
+
32
+ constructor(options) {
33
+ this._quoteIdent = resolveQuoteIdent(options);
34
+ this._model = createModel();
35
+ }
36
+
37
+ /**
38
+ * 重置构建器状态
39
+ */
40
+ reset() {
41
+ this._model = createModel();
42
+ return this;
43
+ }
44
+
45
+ /**
46
+ * 获取 WHERE 条件(供 DbHelper 使用)
47
+ */
48
+ getWhereConditions() {
49
+ const result = compileWhere(this._model.where, this._quoteIdent);
50
+ return { sql: result.sql, params: result.params };
51
+ }
52
+
53
+ /**
54
+ * SELECT 字段
55
+ */
56
+ select(fields = "*") {
57
+ appendSelectItems(this._model.select, fields);
58
+ return this;
59
+ }
60
+
61
+ /**
62
+ * SELECT 原始表达式(不做转义)
63
+ */
64
+ selectRaw(expr) {
65
+ appendSelectRaw(this._model.select, expr);
66
+ return this;
67
+ }
68
+
69
+ /**
70
+ * FROM 表名
71
+ */
72
+ from(table) {
73
+ setFromValue(this._model, table, false);
74
+ return this;
75
+ }
76
+
77
+ /**
78
+ * FROM 原始表达式(不做转义)
79
+ */
80
+ fromRaw(tableExpr) {
81
+ setFromValue(this._model, tableExpr, true);
82
+ return this;
83
+ }
84
+
85
+ /**
86
+ * WHERE 条件
87
+ */
88
+ where(conditionOrField, value) {
89
+ appendWhereInput(this._model.where, conditionOrField, value);
90
+ return this;
91
+ }
92
+
93
+ /**
94
+ * WHERE 原始片段(不做转义),可附带参数。
95
+ */
96
+ whereRaw(sql, params) {
97
+ appendWhereRaw(this._model.where, sql, params);
98
+ return this;
99
+ }
100
+
101
+ /**
102
+ * LEFT JOIN
103
+ */
104
+ leftJoin(table, on) {
105
+ appendJoinItem(this._model.joins, "left", table, on);
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * RIGHT JOIN
111
+ */
112
+ rightJoin(table, on) {
113
+ appendJoinItem(this._model.joins, "right", table, on);
114
+ return this;
115
+ }
116
+
117
+ /**
118
+ * INNER JOIN
119
+ */
120
+ innerJoin(table, on) {
121
+ appendJoinItem(this._model.joins, "inner", table, on);
122
+ return this;
123
+ }
124
+
125
+ /**
126
+ * ORDER BY
127
+ * @param fields - 格式为 ["field#ASC", "field2#DESC"]
128
+ */
129
+ orderBy(fields) {
130
+ appendOrderByItems(this._model.orderBy, fields);
131
+ return this;
132
+ }
133
+
134
+ /**
135
+ * GROUP BY
136
+ */
137
+ groupBy(field) {
138
+ appendGroupByItems(this._model.groupBy, field);
139
+ return this;
140
+ }
141
+
142
+ /**
143
+ * HAVING
144
+ */
145
+ having(condition) {
146
+ appendHavingItems(this._model.having, condition);
147
+ return this;
148
+ }
149
+
150
+ /**
151
+ * LIMIT
152
+ */
153
+ limit(count, offset) {
154
+ const result = normalizeLimitValue(count, offset);
155
+ this._model.limit = result.limitValue;
156
+ this._model.offset = result.offsetValue;
157
+ return this;
158
+ }
159
+
160
+ /**
161
+ * OFFSET
162
+ */
163
+ offset(count) {
164
+ const offsetValue = normalizeOffsetValue(count);
165
+ this._model.offset = offsetValue;
166
+ return this;
167
+ }
168
+
169
+ /**
170
+ * 构建 SELECT 查询
171
+ */
172
+ toSelectSql() {
173
+ return compileSelect(this._model, this._quoteIdent);
174
+ }
175
+
176
+ /**
177
+ * 构建 INSERT 查询
178
+ */
179
+ toInsertSql(table, data) {
180
+ return compileInsert(table, data, this._quoteIdent);
181
+ }
182
+
183
+ /**
184
+ * 构建 UPDATE 查询
185
+ */
186
+ toUpdateSql(table, data) {
187
+ return compileUpdate(this._model, table, data, this._quoteIdent);
188
+ }
189
+
190
+ /**
191
+ * 构建 DELETE 查询
192
+ */
193
+ toDeleteSql(table) {
194
+ return compileDelete(this._model, table, this._quoteIdent);
195
+ }
196
+
197
+ /**
198
+ * 构建 COUNT 查询
199
+ */
200
+ toCountSql() {
201
+ return compileCount(this._model, this._quoteIdent);
202
+ }
203
+
204
+ static toDeleteInSql(options) {
205
+ return toDeleteInSql(options);
206
+ }
207
+
208
+ static toUpdateCaseByIdSql(options) {
209
+ return toUpdateCaseByIdSql(options);
210
+ }
211
+ }
212
+
213
+ /**
214
+ * 创建新的 SQL 构建器实例
215
+ */
216
+ export function createQueryBuilder() {
217
+ return new SqlBuilder();
218
+ }
@@ -0,0 +1,296 @@
1
+ import { SqlErrors } from "./errors.js";
2
+ import { validateParam } from "./util.js";
3
+ import { isNonEmptyString, isString } from "../../utils/is.js";
4
+
5
+ export function createWhereRoot() {
6
+ return { type: "group", join: "AND", items: [] };
7
+ }
8
+
9
+ export function appendSelectItems(list, fields) {
10
+ if (Array.isArray(fields)) {
11
+ for (const field of fields) {
12
+ list.push({ type: "field", value: field });
13
+ }
14
+ return;
15
+ }
16
+
17
+ if (isString(fields)) {
18
+ list.push({ type: "field", value: fields });
19
+ return;
20
+ }
21
+
22
+ throw new Error(SqlErrors.SELECT_FIELDS_INVALID, {
23
+ cause: null,
24
+ code: "validation"
25
+ });
26
+ }
27
+
28
+ export function appendSelectRaw(list, expr) {
29
+ if (!isNonEmptyString(expr)) {
30
+ throw new Error(SqlErrors.SELECT_RAW_NEED_NON_EMPTY(expr), {
31
+ cause: null,
32
+ code: "validation"
33
+ });
34
+ }
35
+ list.push({ type: "raw", value: expr });
36
+ }
37
+
38
+ export function setFromValue(state, table, isRaw) {
39
+ if (!isNonEmptyString(table)) {
40
+ const err = isRaw ? SqlErrors.FROM_RAW_NEED_NON_EMPTY(table) : SqlErrors.FROM_NEED_NON_EMPTY(table);
41
+ throw new Error(err, {
42
+ cause: null,
43
+ code: "validation"
44
+ });
45
+ }
46
+
47
+ state.from = { type: isRaw ? "raw" : "table", value: table.trim() };
48
+ }
49
+
50
+ export function appendJoinItem(list, joinType, table, on) {
51
+ if (!isString(table) || !isString(on)) {
52
+ throw new Error(SqlErrors.JOIN_NEED_STRING(table, on), {
53
+ cause: null,
54
+ code: "validation"
55
+ });
56
+ }
57
+
58
+ list.push({ type: joinType, table: table, on: on });
59
+ }
60
+
61
+ export function appendOrderByItems(list, fields) {
62
+ if (!Array.isArray(fields)) {
63
+ throw new Error(SqlErrors.ORDER_BY_NEED_ARRAY, {
64
+ cause: null,
65
+ code: "validation"
66
+ });
67
+ }
68
+
69
+ for (const item of fields) {
70
+ if (!isString(item) || !item.includes("#")) {
71
+ throw new Error(SqlErrors.ORDER_BY_ITEM_NEED_HASH(item), {
72
+ cause: null,
73
+ code: "validation"
74
+ });
75
+ }
76
+
77
+ const parts = item.split("#");
78
+ if (parts.length !== 2) {
79
+ throw new Error(SqlErrors.ORDER_BY_ITEM_NEED_HASH(item), {
80
+ cause: null,
81
+ code: "validation"
82
+ });
83
+ }
84
+
85
+ const fieldName = parts[0];
86
+ const direction = parts[1];
87
+ const cleanField = fieldName.trim();
88
+ const cleanDir = direction.trim().toUpperCase();
89
+
90
+ if (!cleanField) {
91
+ throw new Error(SqlErrors.ORDER_BY_FIELD_EMPTY(item), {
92
+ cause: null,
93
+ code: "validation"
94
+ });
95
+ }
96
+
97
+ if (!["ASC", "DESC"].includes(cleanDir)) {
98
+ throw new Error(SqlErrors.ORDER_BY_DIR_INVALID(cleanDir), {
99
+ cause: null,
100
+ code: "validation"
101
+ });
102
+ }
103
+
104
+ list.push({ field: cleanField, dir: cleanDir });
105
+ }
106
+ }
107
+
108
+ export function appendGroupByItems(list, field) {
109
+ if (Array.isArray(field)) {
110
+ for (const item of field) {
111
+ if (isString(item)) {
112
+ list.push(item);
113
+ }
114
+ }
115
+ return;
116
+ }
117
+
118
+ if (isString(field)) {
119
+ list.push(field);
120
+ }
121
+ }
122
+
123
+ export function appendHavingItems(list, condition) {
124
+ if (isString(condition)) {
125
+ list.push(condition);
126
+ }
127
+ }
128
+
129
+ export function appendWhereInput(root, conditionOrField, value) {
130
+ if (conditionOrField && typeof conditionOrField === "object" && !Array.isArray(conditionOrField)) {
131
+ const node = parseWhereObject(conditionOrField);
132
+ if (node && node.items.length > 0) {
133
+ root.items.push(node);
134
+ }
135
+ return;
136
+ }
137
+
138
+ if (isString(conditionOrField)) {
139
+ if (value === undefined) {
140
+ throw new Error(SqlErrors.WHERE_VALUE_REQUIRED, {
141
+ cause: null,
142
+ code: "validation"
143
+ });
144
+ }
145
+ const node = buildOperatorNode(conditionOrField, "=", value);
146
+ if (node) {
147
+ root.items.push(node);
148
+ }
149
+ }
150
+ }
151
+
152
+ export function appendWhereRaw(root, sql, params) {
153
+ if (!isNonEmptyString(sql)) {
154
+ throw new Error(SqlErrors.WHERE_RAW_NEED_NON_EMPTY(sql), {
155
+ cause: null,
156
+ code: "validation"
157
+ });
158
+ }
159
+
160
+ const paramList = Array.isArray(params) ? params : [];
161
+ for (const param of paramList) {
162
+ validateParam(param);
163
+ }
164
+
165
+ root.items.push({ type: "raw", sql: sql, params: paramList });
166
+ }
167
+
168
+ function parseWhereObject(whereObj) {
169
+ if (!whereObj || typeof whereObj !== "object") {
170
+ return { type: "group", join: "AND", items: [] };
171
+ }
172
+
173
+ const group = { type: "group", join: "AND", items: [] };
174
+
175
+ for (const [key, value] of Object.entries(whereObj)) {
176
+ if (value === undefined) {
177
+ continue;
178
+ }
179
+
180
+ if (key === "$and") {
181
+ if (Array.isArray(value)) {
182
+ for (const condition of value) {
183
+ if (condition && typeof condition === "object" && !Array.isArray(condition)) {
184
+ const sub = parseWhereObject(condition);
185
+ if (sub.items.length > 0) {
186
+ if (sub.join === "AND") {
187
+ for (const item of sub.items) {
188
+ group.items.push(item);
189
+ }
190
+ } else {
191
+ group.items.push(sub);
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ continue;
198
+ }
199
+
200
+ if (key === "$or") {
201
+ if (Array.isArray(value)) {
202
+ const orGroup = { type: "group", join: "OR", items: [] };
203
+ for (const condition of value) {
204
+ if (!condition || typeof condition !== "object" || Array.isArray(condition)) {
205
+ continue;
206
+ }
207
+ const sub = parseWhereObject(condition);
208
+ if (sub.items.length > 0) {
209
+ orGroup.items.push(sub);
210
+ }
211
+ }
212
+ if (orGroup.items.length > 0) {
213
+ group.items.push(orGroup);
214
+ }
215
+ }
216
+ continue;
217
+ }
218
+
219
+ if (key.includes("$")) {
220
+ const lastDollarIndex = key.lastIndexOf("$");
221
+ const fieldName = key.substring(0, lastDollarIndex);
222
+ const operator = "$" + key.substring(lastDollarIndex + 1);
223
+ const node = buildOperatorNode(fieldName, operator, value);
224
+ if (node) {
225
+ group.items.push(node);
226
+ }
227
+ continue;
228
+ }
229
+
230
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
231
+ for (const [op, val] of Object.entries(value)) {
232
+ const node = buildOperatorNode(key, op, val);
233
+ if (node) {
234
+ group.items.push(node);
235
+ }
236
+ }
237
+ continue;
238
+ }
239
+
240
+ const node = buildOperatorNode(key, "=", value);
241
+ if (node) {
242
+ group.items.push(node);
243
+ }
244
+ }
245
+
246
+ return group;
247
+ }
248
+
249
+ function buildOperatorNode(fieldName, operator, value) {
250
+ switch (operator) {
251
+ case "$in":
252
+ if (!Array.isArray(value)) {
253
+ throw new Error(SqlErrors.IN_NEED_ARRAY(operator), {
254
+ cause: null,
255
+ code: "validation"
256
+ });
257
+ }
258
+ if (value.length === 0) {
259
+ throw new Error(SqlErrors.IN_NEED_NON_EMPTY, {
260
+ cause: null,
261
+ code: "validation"
262
+ });
263
+ }
264
+ return { type: "op", field: fieldName, operator: operator, value: value };
265
+ case "$nin":
266
+ case "$notIn":
267
+ if (!Array.isArray(value)) {
268
+ throw new Error(SqlErrors.NIN_NEED_ARRAY(operator), {
269
+ cause: null,
270
+ code: "validation"
271
+ });
272
+ }
273
+ if (value.length === 0) {
274
+ throw new Error(SqlErrors.NIN_NEED_NON_EMPTY, {
275
+ cause: null,
276
+ code: "validation"
277
+ });
278
+ }
279
+ return { type: "op", field: fieldName, operator: operator, value: value };
280
+ case "$between":
281
+ case "$notBetween":
282
+ if (Array.isArray(value) && value.length === 2) {
283
+ return { type: "op", field: fieldName, operator: operator, value: value };
284
+ }
285
+ return null;
286
+ case "$null":
287
+ case "$notNull":
288
+ if (value === true) {
289
+ return { type: "op", field: fieldName, operator: operator, value: value };
290
+ }
291
+ return null;
292
+ default:
293
+ validateParam(value);
294
+ return { type: "op", field: fieldName, operator: operator, value: value };
295
+ }
296
+ }