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.
- package/README.md +6 -0
- package/apis/admin/cacheRefresh.js +122 -0
- package/apis/admin/del.js +34 -0
- package/apis/admin/detail.js +23 -0
- package/apis/admin/ins.js +69 -0
- package/apis/admin/list.js +28 -0
- package/apis/admin/upd.js +95 -0
- package/apis/api/all.js +24 -0
- package/apis/api/list.js +31 -0
- package/apis/auth/login.js +123 -0
- package/apis/auth/sendSmsCode.js +24 -0
- package/apis/dashboard/configStatus.js +39 -0
- package/apis/dashboard/environmentInfo.js +43 -0
- package/apis/dashboard/performanceMetrics.js +20 -0
- package/apis/dashboard/permissionStats.js +27 -0
- package/apis/dashboard/serviceStatus.js +75 -0
- package/apis/dashboard/systemInfo.js +19 -0
- package/apis/dashboard/systemOverview.js +30 -0
- package/apis/dashboard/systemResources.js +106 -0
- package/apis/dict/all.js +23 -0
- package/apis/dict/del.js +16 -0
- package/apis/dict/detail.js +27 -0
- package/apis/dict/ins.js +51 -0
- package/apis/dict/items.js +30 -0
- package/apis/dict/list.js +36 -0
- package/apis/dict/upd.js +74 -0
- package/apis/dictType/all.js +16 -0
- package/apis/dictType/del.js +38 -0
- package/apis/dictType/detail.js +20 -0
- package/apis/dictType/ins.js +37 -0
- package/apis/dictType/list.js +26 -0
- package/apis/dictType/upd.js +51 -0
- package/apis/email/config.js +25 -0
- package/apis/email/logList.js +23 -0
- package/apis/email/send.js +66 -0
- package/apis/email/verify.js +21 -0
- package/apis/loginLog/list.js +23 -0
- package/apis/menu/all.js +41 -0
- package/apis/menu/list.js +25 -0
- package/apis/operateLog/list.js +23 -0
- package/apis/role/all.js +21 -0
- package/apis/role/apiSave.js +43 -0
- package/apis/role/apis.js +22 -0
- package/apis/role/del.js +49 -0
- package/apis/role/detail.js +32 -0
- package/apis/role/ins.js +46 -0
- package/apis/role/list.js +27 -0
- package/apis/role/menuSave.js +42 -0
- package/apis/role/menus.js +22 -0
- package/apis/role/save.js +40 -0
- package/apis/role/upd.js +50 -0
- package/apis/sysConfig/all.js +16 -0
- package/apis/sysConfig/del.js +36 -0
- package/apis/sysConfig/get.js +49 -0
- package/apis/sysConfig/ins.js +50 -0
- package/apis/sysConfig/list.js +24 -0
- package/apis/sysConfig/upd.js +62 -0
- package/checks/api.js +55 -0
- package/checks/config.js +107 -0
- package/checks/hook.js +38 -0
- package/checks/menu.js +58 -0
- package/checks/plugin.js +38 -0
- package/checks/table.js +78 -0
- package/configs/beflyConfig.json +61 -0
- package/configs/beflyMenus.json +85 -0
- package/configs/constConfig.js +34 -0
- package/configs/regexpAlias.json +55 -0
- package/hooks/auth.js +34 -0
- package/hooks/cors.js +39 -0
- package/hooks/parser.js +90 -0
- package/hooks/permission.js +71 -0
- package/hooks/validator.js +43 -0
- package/index.js +326 -0
- package/lib/cacheHelper.js +483 -0
- package/lib/cacheKeys.js +42 -0
- package/lib/connect.js +120 -0
- package/lib/dbHelper/builders.js +698 -0
- package/lib/dbHelper/context.js +131 -0
- package/lib/dbHelper/dataOps.js +505 -0
- package/lib/dbHelper/execute.js +65 -0
- package/lib/dbHelper/index.js +27 -0
- package/lib/dbHelper/transaction.js +43 -0
- package/lib/dbHelper/util.js +58 -0
- package/lib/dbHelper/validate.js +549 -0
- package/lib/emailHelper.js +110 -0
- package/lib/logger.js +604 -0
- package/lib/redisHelper.js +684 -0
- package/lib/sqlBuilder/batch.js +113 -0
- package/lib/sqlBuilder/check.js +150 -0
- package/lib/sqlBuilder/compiler.js +347 -0
- package/lib/sqlBuilder/errors.js +60 -0
- package/lib/sqlBuilder/index.js +218 -0
- package/lib/sqlBuilder/parser.js +296 -0
- package/lib/sqlBuilder/util.js +260 -0
- package/lib/validator.js +303 -0
- package/package.json +19 -12
- package/paths.js +112 -0
- package/plugins/cache.js +16 -0
- package/plugins/config.js +11 -0
- package/plugins/email.js +27 -0
- package/plugins/logger.js +20 -0
- package/plugins/mysql.js +36 -0
- package/plugins/redis.js +34 -0
- package/plugins/tool.js +155 -0
- package/router/api.js +140 -0
- package/router/static.js +71 -0
- package/sql/admin.sql +18 -0
- package/sql/api.sql +12 -0
- package/sql/dict.sql +13 -0
- package/sql/dictType.sql +12 -0
- package/sql/emailLog.sql +20 -0
- package/sql/loginLog.sql +25 -0
- package/sql/menu.sql +12 -0
- package/sql/operateLog.sql +22 -0
- package/sql/role.sql +14 -0
- package/sql/sysConfig.sql +16 -0
- package/sync/api.js +93 -0
- package/sync/cache.js +13 -0
- package/sync/dev.js +171 -0
- package/sync/menu.js +99 -0
- package/tables/admin.json +56 -0
- package/tables/api.json +26 -0
- package/tables/dict.json +30 -0
- package/tables/dictType.json +24 -0
- package/tables/emailLog.json +61 -0
- package/tables/loginLog.json +86 -0
- package/tables/menu.json +24 -0
- package/tables/operateLog.json +68 -0
- package/tables/role.json +32 -0
- package/tables/sysConfig.json +43 -0
- package/utils/calcPerfTime.js +13 -0
- package/utils/cors.js +17 -0
- package/utils/deepMerge.js +78 -0
- package/utils/fieldClear.js +65 -0
- package/utils/formatYmdHms.js +23 -0
- package/utils/formatZodIssues.js +109 -0
- package/utils/getClientIp.js +47 -0
- package/utils/importDefault.js +51 -0
- package/utils/is.js +462 -0
- package/utils/loggerUtils.js +185 -0
- package/utils/processInfo.js +39 -0
- package/utils/regexpUtil.js +52 -0
- package/utils/response.js +114 -0
- package/utils/scanFiles.js +124 -0
- package/utils/scanSources.js +68 -0
- package/utils/sortModules.js +75 -0
- package/utils/toSessionTtlSeconds.js +14 -0
- package/utils/util.js +374 -0
- package/befly.js +0 -16413
- package/befly.min.js +0 -72
package/utils/util.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 注意:本文件用于集中维护 core 内部通用 utils。
|
|
3
|
+
* - 按项目规范:避免零散小文件噪音;实现集中在本文件,而不是做 re-export 聚合。
|
|
4
|
+
* - 仅在 packages/core 内部使用;core 对外不承诺这些路径导出。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { isBoolean, isNullable, isNumber, isPlainObject } from "./is.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 判断 bigint 是否可安全转换为 number。
|
|
11
|
+
* - 超出安全整数范围则不可转换
|
|
12
|
+
* - 转换后若是科学计数法表示则不可转换
|
|
13
|
+
*/
|
|
14
|
+
export function canConvertToNumber(value) {
|
|
15
|
+
const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
|
|
16
|
+
const minSafe = BigInt(Number.MIN_SAFE_INTEGER);
|
|
17
|
+
|
|
18
|
+
if (value > maxSafe || value < minSafe) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const asNumber = Number(value);
|
|
23
|
+
if (!Number.isSafeInteger(asNumber)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const text = String(asNumber);
|
|
28
|
+
if (text.includes("e") || text.includes("E")) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return asNumber;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 安全格式化值用于日志预览(截断长文本,避免抛错)。
|
|
37
|
+
*/
|
|
38
|
+
export function formatValuePreview(value) {
|
|
39
|
+
if (value === null) {
|
|
40
|
+
return "null";
|
|
41
|
+
}
|
|
42
|
+
if (value === undefined) {
|
|
43
|
+
return "undefined";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
const s = value.length > 80 ? `${value.slice(0, 80)}...` : value;
|
|
48
|
+
return JSON.stringify(s);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (isNumber(value) || isBoolean(value) || typeof value === "bigint") {
|
|
52
|
+
return String(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof value === "function") {
|
|
56
|
+
return "[Function]";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const s = JSON.stringify(value);
|
|
61
|
+
if (typeof s === "string") {
|
|
62
|
+
return s.length > 120 ? `${s.slice(0, 120)}...` : s;
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
// ignore
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const s = String(value);
|
|
69
|
+
return s.length > 120 ? `${s.slice(0, 120)}...` : s;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 获取值的类型标识(数组/对象等做细分)。
|
|
74
|
+
*/
|
|
75
|
+
export function getTypeTag(value) {
|
|
76
|
+
if (value === null) return "null";
|
|
77
|
+
if (value === undefined) return "undefined";
|
|
78
|
+
if (Array.isArray(value)) return "array";
|
|
79
|
+
|
|
80
|
+
const t = typeof value;
|
|
81
|
+
if (t === "string") return "string";
|
|
82
|
+
if (t === "number") return "number";
|
|
83
|
+
if (t === "boolean") return "boolean";
|
|
84
|
+
if (t === "bigint") return "bigint";
|
|
85
|
+
if (t === "symbol") return "symbol";
|
|
86
|
+
if (t === "function") return "function";
|
|
87
|
+
|
|
88
|
+
return "object";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 正则字符转义列表
|
|
92
|
+
const REGEXP_SPECIAL = /[\^$.*+?()[\]{}|]/g;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 转义字符串中的正则特殊字符。
|
|
96
|
+
*/
|
|
97
|
+
export function escapeRegExp(input) {
|
|
98
|
+
return String(input).replace(REGEXP_SPECIAL, "\\$&");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 归一化正整数:非法值回退,超出范围裁剪。
|
|
103
|
+
*/
|
|
104
|
+
export function normalizePositiveInt(value, fallback, min, max) {
|
|
105
|
+
if (!Number.isFinite(value)) return fallback;
|
|
106
|
+
const v = Math.floor(value);
|
|
107
|
+
if (v < min) return fallback;
|
|
108
|
+
if (v > max) return max;
|
|
109
|
+
return v;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 遍历 plain object 的自有字段。
|
|
114
|
+
*/
|
|
115
|
+
export function forOwn(obj, iteratee) {
|
|
116
|
+
if (typeof iteratee !== "function") {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!isPlainObject(obj)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const record = obj;
|
|
125
|
+
for (const key of Object.keys(record)) {
|
|
126
|
+
iteratee(record[key], key);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 将字符串拆分为词段(用于 camelCase/snakeCase)
|
|
131
|
+
function toWordParts(input) {
|
|
132
|
+
const normalized = String(input)
|
|
133
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
134
|
+
.replace(/[^a-zA-Z0-9]+/g, " ")
|
|
135
|
+
.trim();
|
|
136
|
+
|
|
137
|
+
if (normalized.length === 0) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return normalized.split(/\s+/).filter((p) => p.length > 0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 首字母大写
|
|
145
|
+
function upperFirst(s) {
|
|
146
|
+
if (s.length === 0) {
|
|
147
|
+
return s;
|
|
148
|
+
}
|
|
149
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 把字符串转为小驼峰。
|
|
154
|
+
* - 主要用于文件名/目录名(例如 my_plugin / my-plugin / my plugin)。
|
|
155
|
+
*/
|
|
156
|
+
export function camelCase(input) {
|
|
157
|
+
const parts = toWordParts(input);
|
|
158
|
+
if (parts.length === 0) {
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const firstPart = parts[0];
|
|
163
|
+
if (!firstPart) {
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const first = firstPart.toLowerCase();
|
|
168
|
+
const rest = parts.slice(1).map((p) => upperFirst(p.toLowerCase()));
|
|
169
|
+
return [first].concat(rest).join("");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 归一化字符串为词序列
|
|
173
|
+
function normalizeToWords(input) {
|
|
174
|
+
return String(input)
|
|
175
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
176
|
+
.replace(/[^a-zA-Z0-9]+/g, " ")
|
|
177
|
+
.trim();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 把字符串转为 snake_case。
|
|
182
|
+
* - 主要用于表名/字段名(例如 userId -> user_id)。
|
|
183
|
+
*/
|
|
184
|
+
export function snakeCase(input) {
|
|
185
|
+
const normalized = normalizeToWords(input);
|
|
186
|
+
if (normalized.length === 0) {
|
|
187
|
+
return "";
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return normalized
|
|
191
|
+
.split(/\s+/)
|
|
192
|
+
.filter((p) => p.length > 0)
|
|
193
|
+
.map((p) => p.toLowerCase())
|
|
194
|
+
.join("_");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 对象字段名转小驼峰
|
|
199
|
+
* @param obj - 源对象
|
|
200
|
+
* @returns 字段名转为小驼峰格式的新对象
|
|
201
|
+
*/
|
|
202
|
+
export const keysToCamel = (obj) => {
|
|
203
|
+
if (!obj || !isPlainObject(obj)) return obj;
|
|
204
|
+
|
|
205
|
+
const result = {};
|
|
206
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
207
|
+
const camelKey = camelCase(key);
|
|
208
|
+
result[camelKey] = value;
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 对象字段名转下划线
|
|
215
|
+
* @param obj - 源对象
|
|
216
|
+
* @returns 字段名转为下划线格式的新对象
|
|
217
|
+
*/
|
|
218
|
+
export const keysToSnake = (obj) => {
|
|
219
|
+
if (!obj || !isPlainObject(obj)) return obj;
|
|
220
|
+
|
|
221
|
+
const result = {};
|
|
222
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
223
|
+
const snakeKey = snakeCase(key);
|
|
224
|
+
result[snakeKey] = value;
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 数组对象字段名批量转小驼峰
|
|
231
|
+
* @param arr - 源数组
|
|
232
|
+
* @returns 字段名转为小驼峰格式的新数组
|
|
233
|
+
*/
|
|
234
|
+
export const arrayKeysToCamel = (arr) => {
|
|
235
|
+
if (!arr || !Array.isArray(arr)) return arr;
|
|
236
|
+
return arr.map((item) => keysToCamel(item));
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 根据点路径读取对象字段(不存在则返回 undefined)。
|
|
241
|
+
*/
|
|
242
|
+
export function getByPath(obj, path) {
|
|
243
|
+
if (!path) {
|
|
244
|
+
return obj;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const parts = path.split(".");
|
|
248
|
+
let cur = obj;
|
|
249
|
+
|
|
250
|
+
for (const part of parts) {
|
|
251
|
+
if (isNullable(cur)) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
if (typeof cur !== "object") {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
const record = cur;
|
|
258
|
+
cur = record[part];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return cur;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 根据点路径写入对象字段(中间层自动补空对象)。
|
|
266
|
+
*/
|
|
267
|
+
export function setByPath(target, path, value) {
|
|
268
|
+
const parts = path.split(".");
|
|
269
|
+
// 避免无效 path(如 a..b)导致部分写入
|
|
270
|
+
for (const part of parts) {
|
|
271
|
+
if (!part) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
let cur = target;
|
|
276
|
+
|
|
277
|
+
for (let i = 0; i < parts.length; i++) {
|
|
278
|
+
const key = parts[i];
|
|
279
|
+
if (!key) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const isLast = i === parts.length - 1;
|
|
284
|
+
if (isLast) {
|
|
285
|
+
cur[key] = value;
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const nextVal = cur[key];
|
|
290
|
+
if (!isPlainObject(nextVal)) {
|
|
291
|
+
cur[key] = {};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
cur = cur[key];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* 生成移除指定字段后的浅拷贝。
|
|
300
|
+
*/
|
|
301
|
+
export function omit(obj, keys) {
|
|
302
|
+
if (!isPlainObject(obj)) {
|
|
303
|
+
return {};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const keySet = new Set(Array.isArray(keys) ? keys : []);
|
|
307
|
+
const out = {};
|
|
308
|
+
|
|
309
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
310
|
+
if (keySet.has(k)) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
out[k] = v;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return out;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 从对象中挑选指定字段。
|
|
321
|
+
*/
|
|
322
|
+
export const pickFields = (obj, keys) => {
|
|
323
|
+
if (!obj || (!isPlainObject(obj) && !Array.isArray(obj))) {
|
|
324
|
+
return {};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const record = obj;
|
|
328
|
+
const result = {};
|
|
329
|
+
|
|
330
|
+
for (const key of keys) {
|
|
331
|
+
if (key in record) {
|
|
332
|
+
result[key] = record[key];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return result;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* 根据 key 生成对象映射。
|
|
341
|
+
*/
|
|
342
|
+
export function keyBy(items, getKey) {
|
|
343
|
+
const out = {};
|
|
344
|
+
|
|
345
|
+
if (!Array.isArray(items) || typeof getKey !== "function") {
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
for (const item of items) {
|
|
350
|
+
const key = getKey(item);
|
|
351
|
+
if (typeof key !== "string" || key === "") {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
out[key] = item;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* 生成短 ID
|
|
362
|
+
* 由时间戳(base36)+ 随机字符组成,约 13 位
|
|
363
|
+
* - 前 8 位:时间戳(可排序)
|
|
364
|
+
* - 后 5 位:随机字符(防冲突)
|
|
365
|
+
* @returns 短 ID 字符串
|
|
366
|
+
*/
|
|
367
|
+
export function genShortId() {
|
|
368
|
+
const timePart = Date.now().toString(36);
|
|
369
|
+
let rand = "";
|
|
370
|
+
while (rand.length < 10) {
|
|
371
|
+
rand = rand + Math.random().toString(36).slice(2);
|
|
372
|
+
}
|
|
373
|
+
return timePart + rand.slice(0, 10);
|
|
374
|
+
}
|