befly 3.24.8 → 3.24.10
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/apis/dashboard/environmentInfo.js +1 -0
- package/apis/sysConfig/get.js +1 -1
- package/apis/tongJi/errorList.js +14 -1
- package/apis/tongJi/errorReport.js +1 -0
- package/apis/tongJi/infoReport.js +1 -1
- package/hooks/permission.js +1 -1
- package/hooks/validator.js +1 -1
- package/index.js +9 -10
- package/lib/cacheHelper.js +3 -3
- package/lib/connect.js +1 -0
- package/lib/dbHelper.js +30 -26
- package/lib/dbUtil.js +8 -8
- package/lib/logger.js +1 -1
- package/lib/sqlBuilder.js +1 -1
- package/lib/validator.js +2 -2
- package/package.json +1 -1
- package/plugins/email.js +2 -1
- package/scripts/syncDb/context.js +2 -1
- package/scripts/syncDb/diff.js +1 -0
- package/scripts/syncDb/index.js +2 -1
- package/scripts/syncDb/report.js +1 -0
- package/utils/fieldClear.js +1 -1
- package/utils/regexpUtil.js +1 -1
package/apis/sysConfig/get.js
CHANGED
package/apis/tongJi/errorList.js
CHANGED
|
@@ -43,7 +43,20 @@ export default {
|
|
|
43
43
|
const where = {};
|
|
44
44
|
|
|
45
45
|
if (keyword) {
|
|
46
|
-
where["$or"] = [
|
|
46
|
+
where["$or"] = [
|
|
47
|
+
{ pagePath$like: keyword },
|
|
48
|
+
{ pageName$like: keyword },
|
|
49
|
+
{ message$like: keyword },
|
|
50
|
+
{ errorType$like: keyword },
|
|
51
|
+
{ productName$like: keyword },
|
|
52
|
+
{ productCode$like: keyword },
|
|
53
|
+
{ productVersion$like: keyword },
|
|
54
|
+
{ browserName$like: keyword },
|
|
55
|
+
{ osName$like: keyword },
|
|
56
|
+
{ deviceType$like: keyword },
|
|
57
|
+
{ deviceVendor$like: keyword },
|
|
58
|
+
{ deviceModel$like: keyword }
|
|
59
|
+
];
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
if (errorType) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UAParser } from "ua-parser-js";
|
|
2
2
|
|
|
3
|
-
import { isValidPositiveInt } from "#root/utils/is.js";
|
|
4
3
|
import { getDateYmdNumber } from "#root/utils/datetime.js";
|
|
4
|
+
import { isValidPositiveInt } from "#root/utils/is.js";
|
|
5
5
|
|
|
6
6
|
function getInfoStatsMember(ctx) {
|
|
7
7
|
if (isValidPositiveInt(ctx.userId)) {
|
package/hooks/permission.js
CHANGED
package/hooks/validator.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 相对导入
|
|
2
2
|
import { Validator } from "../lib/validator.js";
|
|
3
|
-
import { ErrorResponse } from "../utils/response.js";
|
|
4
3
|
import { isPlainObject } from "../utils/is.js";
|
|
4
|
+
import { ErrorResponse } from "../utils/response.js";
|
|
5
5
|
import { snakeCase } from "../utils/util.js";
|
|
6
6
|
|
|
7
7
|
/**
|
package/index.js
CHANGED
|
@@ -3,10 +3,6 @@
|
|
|
3
3
|
* 提供简洁的框架接口,核心逻辑已提取到 loader 层
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
// 配置
|
|
7
|
-
import beflyConfig from "#root/configs/beflyConfig.json";
|
|
8
|
-
import beflyMenus from "#root/configs/beflyMenus.json";
|
|
9
|
-
|
|
10
6
|
// 检查
|
|
11
7
|
import { checkApi } from "#root/checks/api.js";
|
|
12
8
|
import { checkConfig } from "#root/checks/config.js";
|
|
@@ -14,6 +10,9 @@ import { checkHook } from "#root/checks/hook.js";
|
|
|
14
10
|
import { checkMenu } from "#root/checks/menu.js";
|
|
15
11
|
import { checkPlugin } from "#root/checks/plugin.js";
|
|
16
12
|
import { checkTable } from "#root/checks/table.js";
|
|
13
|
+
// 配置
|
|
14
|
+
import beflyConfig from "#root/configs/beflyConfig.json";
|
|
15
|
+
import beflyMenus from "#root/configs/beflyMenus.json";
|
|
17
16
|
// ========== 相对导入(项目内部文件) ==========
|
|
18
17
|
// 基础设施
|
|
19
18
|
import { Connect } from "#root/lib/connect.js";
|
|
@@ -28,9 +27,9 @@ import { syncDev } from "#root/sync/dev.js";
|
|
|
28
27
|
import { syncMenu } from "#root/sync/menu.js";
|
|
29
28
|
// 工具
|
|
30
29
|
import { calcPerfTime } from "#root/utils/calcPerfTime.js";
|
|
31
|
-
import { scanSources } from "#root/utils/scanSources.js";
|
|
32
|
-
import { isPrimaryProcess } from "#root/utils/is.js";
|
|
33
30
|
import { deepMerge } from "#root/utils/deepMerge.js";
|
|
31
|
+
import { isPrimaryProcess } from "#root/utils/is.js";
|
|
32
|
+
import { scanSources } from "#root/utils/scanSources.js";
|
|
34
33
|
|
|
35
34
|
export { syncDb } from "#root/scripts/syncDb/index.js";
|
|
36
35
|
export { xmlParse } from "#root/lib/xmlParse.js";
|
|
@@ -169,7 +168,7 @@ export class Befly {
|
|
|
169
168
|
await Connect.connectMysql(this.context.config.mysql);
|
|
170
169
|
|
|
171
170
|
// 加载插件
|
|
172
|
-
for (const item of this.plugins.
|
|
171
|
+
for (const item of this.plugins.toSorted((a, b) => a.order - b.order)) {
|
|
173
172
|
this.context[item.fileName] = await item.handler(this.context);
|
|
174
173
|
}
|
|
175
174
|
await ensureSyncPrerequisites(this.context);
|
|
@@ -183,7 +182,7 @@ export class Befly {
|
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
// 加载钩子
|
|
186
|
-
this.hooks = this.hooks.
|
|
185
|
+
this.hooks = this.hooks.toSorted((a, b) => a.order - b.order);
|
|
187
186
|
|
|
188
187
|
// 加载所有 API
|
|
189
188
|
this.apis = Object.fromEntries(this.apis.map((api) => [api.apiPath, api]));
|
|
@@ -198,11 +197,11 @@ export class Befly {
|
|
|
198
197
|
// 开发模式下启用详细错误信息
|
|
199
198
|
development: this.context.env.RUN_MODE === "development",
|
|
200
199
|
// 空闲连接超时时间(秒),防止恶意连接占用资源
|
|
201
|
-
fetch: async (req,
|
|
200
|
+
fetch: async (req, httpServer) => {
|
|
202
201
|
const url = new URL(req.url);
|
|
203
202
|
|
|
204
203
|
if (url.pathname.startsWith("/api/")) {
|
|
205
|
-
return apiFetch(req,
|
|
204
|
+
return apiFetch(req, httpServer);
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
if (url.pathname.startsWith("/public/")) {
|
package/lib/cacheHelper.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Logger } from "./logger.js";
|
|
7
6
|
import { isNonEmptyString, isNullable, isString } from "../utils/is.js";
|
|
7
|
+
import { Logger } from "./logger.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 缓存助手类
|
|
@@ -110,7 +110,7 @@ export class CacheHelper {
|
|
|
110
110
|
|
|
111
111
|
for (const roleCode of roleCodes) {
|
|
112
112
|
const apiPaths = roleApiPathsMap.get(roleCode) || [];
|
|
113
|
-
const members = Array.from(new Set(apiPaths)).
|
|
113
|
+
const members = Array.from(new Set(apiPaths)).toSorted();
|
|
114
114
|
|
|
115
115
|
if (members.length > 0) {
|
|
116
116
|
items.push({ key: `role:apis:${roleCode}`, members: members });
|
|
@@ -168,7 +168,7 @@ export class CacheHelper {
|
|
|
168
168
|
|
|
169
169
|
for (const roleCode of roleCodes) {
|
|
170
170
|
const menuPaths = roleMenuPathsMap.get(roleCode) || [];
|
|
171
|
-
const members = Array.from(new Set(menuPaths)).
|
|
171
|
+
const members = Array.from(new Set(menuPaths)).toSorted();
|
|
172
172
|
|
|
173
173
|
if (members.length > 0) {
|
|
174
174
|
items.push({ key: `role:menus:${roleCode}`, members: members });
|
package/lib/connect.js
CHANGED
package/lib/dbHelper.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { fieldClear } from "../utils/fieldClear.js";
|
|
2
2
|
import { isNonEmptyString, isNullable, isNumber, isPlainObject, isString } from "../utils/is.js";
|
|
3
3
|
import { camelCase, canConvertToNumber, keysToSnake, snakeCase } from "../utils/util.js";
|
|
4
|
-
import { Logger } from "./logger.js";
|
|
5
4
|
import { DbParse } from "./dbParse.js";
|
|
6
|
-
import { SqlBuilder } from "./sqlBuilder.js";
|
|
7
5
|
import { deserializeArrayFields, parseTableRef, serializeArrayFields } from "./dbUtil.js";
|
|
6
|
+
import { Logger } from "./logger.js";
|
|
7
|
+
import { SqlBuilder } from "./sqlBuilder.js";
|
|
8
8
|
|
|
9
9
|
function quoteIdentMySql(identifier) {
|
|
10
10
|
if (!isString(identifier)) {
|
|
@@ -29,38 +29,38 @@ function normalizeSqlMetaNumber(value) {
|
|
|
29
29
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const convertRecord = (source) => {
|
|
38
|
-
const converted = {};
|
|
32
|
+
function convertBigIntRecord(source) {
|
|
33
|
+
const converted = {};
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
for (const [key, item] of Object.entries(source)) {
|
|
36
|
+
let nextValue = item;
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
38
|
+
if (typeof item === "bigint") {
|
|
39
|
+
const convertedNumber = canConvertToNumber(item);
|
|
40
|
+
if (convertedNumber !== null) {
|
|
41
|
+
nextValue = convertedNumber;
|
|
42
|
+
} else {
|
|
43
|
+
nextValue = String(item);
|
|
50
44
|
}
|
|
51
|
-
|
|
52
|
-
converted[key] = nextValue;
|
|
53
45
|
}
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
}
|
|
47
|
+
converted[key] = nextValue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return converted;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function normalizeBigIntValues(value) {
|
|
54
|
+
if (isNullable(value)) {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
57
|
|
|
58
58
|
if (Array.isArray(value)) {
|
|
59
|
-
return value.map((item) =>
|
|
59
|
+
return value.map((item) => convertBigIntRecord(item));
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (typeof value === "object") {
|
|
63
|
-
return
|
|
63
|
+
return convertBigIntRecord(value);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
return value;
|
|
@@ -710,7 +710,11 @@ class DbHelper {
|
|
|
710
710
|
}
|
|
711
711
|
|
|
712
712
|
if (result.length >= MAX_LIMIT) {
|
|
713
|
-
Logger.warn(`getAll 达到最大限制 ${MAX_LIMIT},实际总数 ${total},只返回前 ${MAX_LIMIT} 条`, {
|
|
713
|
+
Logger.warn(`getAll 达到最大限制 ${MAX_LIMIT},实际总数 ${total},只返回前 ${MAX_LIMIT} 条`, {
|
|
714
|
+
table: options.table,
|
|
715
|
+
limit: MAX_LIMIT,
|
|
716
|
+
total: total
|
|
717
|
+
});
|
|
714
718
|
}
|
|
715
719
|
|
|
716
720
|
const lists = this.normalizeListData(result);
|
|
@@ -862,7 +866,7 @@ class DbHelper {
|
|
|
862
866
|
processedList.push({ id: item.id, data: userData });
|
|
863
867
|
}
|
|
864
868
|
|
|
865
|
-
const fields = Array.from(fieldSet).
|
|
869
|
+
const fields = Array.from(fieldSet).toSorted();
|
|
866
870
|
if (fields.length === 0) {
|
|
867
871
|
return {
|
|
868
872
|
data: 0,
|
package/lib/dbUtil.js
CHANGED
|
@@ -507,6 +507,12 @@ export function processJoinOrderBy(orderBy) {
|
|
|
507
507
|
return normalizeOrderBy(orderBy, processJoinField);
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
+
function replaceJoinOnSegment(segment) {
|
|
511
|
+
return segment.replace(/([a-zA-Z_][a-zA-Z0-9_]*)(\s*\.\s*)([a-zA-Z_][a-zA-Z0-9_]*)/g, (_match, left, dot, right) => {
|
|
512
|
+
return `${snakeCase(left)}${dot}${snakeCase(right)}`;
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
|
|
510
516
|
export function processJoinOn(on) {
|
|
511
517
|
if (!isString(on)) {
|
|
512
518
|
return String(on);
|
|
@@ -517,12 +523,6 @@ export function processJoinOn(on) {
|
|
|
517
523
|
return raw;
|
|
518
524
|
}
|
|
519
525
|
|
|
520
|
-
const replaceSegment = (segment) => {
|
|
521
|
-
return segment.replace(/([a-zA-Z_][a-zA-Z0-9_]*)(\s*\.\s*)([a-zA-Z_][a-zA-Z0-9_]*)/g, (_match, left, dot, right) => {
|
|
522
|
-
return `${snakeCase(left)}${dot}${snakeCase(right)}`;
|
|
523
|
-
});
|
|
524
|
-
};
|
|
525
|
-
|
|
526
526
|
let result = "";
|
|
527
527
|
let buffer = "";
|
|
528
528
|
let quote = null;
|
|
@@ -540,7 +540,7 @@ export function processJoinOn(on) {
|
|
|
540
540
|
|
|
541
541
|
if (ch === "'" || ch === '"' || ch === "`") {
|
|
542
542
|
if (buffer.length > 0) {
|
|
543
|
-
result +=
|
|
543
|
+
result += replaceJoinOnSegment(buffer);
|
|
544
544
|
buffer = "";
|
|
545
545
|
}
|
|
546
546
|
quote = ch;
|
|
@@ -554,7 +554,7 @@ export function processJoinOn(on) {
|
|
|
554
554
|
}
|
|
555
555
|
|
|
556
556
|
if (buffer.length > 0) {
|
|
557
|
-
result +=
|
|
557
|
+
result += replaceJoinOnSegment(buffer);
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
return result;
|
package/lib/logger.js
CHANGED
|
@@ -7,8 +7,8 @@ import { stat } from "node:fs/promises";
|
|
|
7
7
|
import { join as nodePathJoin, resolve as nodePathResolve } from "node:path";
|
|
8
8
|
|
|
9
9
|
import { formatYmdHms } from "../utils/datetime.js";
|
|
10
|
-
import { buildSensitiveKeyMatcher, sanitizeLogObject } from "../utils/loggerUtils.js";
|
|
11
10
|
import { isFiniteNumber, isNumber, isPlainObject, isString } from "../utils/is.js";
|
|
11
|
+
import { buildSensitiveKeyMatcher, sanitizeLogObject } from "../utils/loggerUtils.js";
|
|
12
12
|
import { normalizePositiveInt } from "../utils/util.js";
|
|
13
13
|
|
|
14
14
|
// 注意:Logger 可能在运行时/测试中被 process.chdir() 影响。
|
package/lib/sqlBuilder.js
CHANGED
package/lib/validator.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* 纯静态类设计,简洁易用
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import RegexAliases from "../configs/regexpAlias.json";
|
|
7
6
|
import { FIELD_RULE_DEFAULT_MAX, FIELD_RULE_DEFAULT_MIN, FIELD_RULE_INPUT_TYPES } from "../configs/constConfig.js";
|
|
8
|
-
import
|
|
7
|
+
import RegexAliases from "../configs/regexpAlias.json";
|
|
9
8
|
import { isFiniteNumber, isIntegerNumber, isJsonObject, isJsonPrimitive, isJsonStructure, isNullable, isNumber, isPlainObject, isRegexInput, isString } from "../utils/is.js";
|
|
9
|
+
import { getCompiledRegex } from "../utils/regexpUtil.js";
|
|
10
10
|
|
|
11
11
|
const INPUT_TYPE_SET = new Set(FIELD_RULE_INPUT_TYPES);
|
|
12
12
|
const RULE_ALLOWED_KEYS = new Set(["input", "check", "name", "min", "max", "detail"]);
|
package/package.json
CHANGED
package/plugins/email.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Logger } from "#root/lib/logger.js";
|
|
|
7
7
|
import { importDefault } from "#root/utils/importDefault.js";
|
|
8
8
|
import { isNonEmptyString, isPlainObject } from "#root/utils/is.js";
|
|
9
9
|
import { camelCase } from "#root/utils/util.js";
|
|
10
|
+
|
|
10
11
|
import { buildSyncDbDiff, groupSyncDbColumns } from "./diff.js";
|
|
11
12
|
import { printSyncDbProcessLog } from "./report.js";
|
|
12
13
|
|
|
@@ -65,7 +66,7 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
if (skippedBeflyTables.size > 0) {
|
|
68
|
-
const skippedTables = Array.from(skippedBeflyTables).
|
|
69
|
+
const skippedTables = Array.from(skippedBeflyTables).toSorted((left, right) => left.localeCompare(right));
|
|
69
70
|
Logger.info("已跳过 befly_ 前缀表,不参与对比", {
|
|
70
71
|
skippedTableCount: skippedBeflyTables.size,
|
|
71
72
|
skippedTables: skippedTables
|
package/scripts/syncDb/diff.js
CHANGED
|
@@ -2,6 +2,7 @@ import { join } from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import { isNonEmptyString, isPlainObject } from "#root/utils/is.js";
|
|
4
4
|
import { camelCase, snakeCase } from "#root/utils/util.js";
|
|
5
|
+
|
|
5
6
|
import { printSyncDbProcessLog } from "./report.js";
|
|
6
7
|
import { toSyncDbFieldDef } from "./transform.js";
|
|
7
8
|
|
package/scripts/syncDb/index.js
CHANGED
|
@@ -2,8 +2,9 @@ import { join, resolve } from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import { Connect } from "#root/lib/connect.js";
|
|
4
4
|
import { Logger } from "#root/lib/logger.js";
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import { prepareSyncDbBaseContext } from "./context.js";
|
|
7
|
+
import { applySyncDbDiff } from "./diff.js";
|
|
7
8
|
import { printSyncDbDiffSummary, printSyncDbProcessLog, writeSyncDbReport } from "./report.js";
|
|
8
9
|
|
|
9
10
|
export async function syncDb(mysqlConfig) {
|
package/scripts/syncDb/report.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname } from "node:path";
|
|
|
4
4
|
import { Logger } from "#root/lib/logger.js";
|
|
5
5
|
import { isNonEmptyString } from "#root/utils/is.js";
|
|
6
6
|
import { camelCase } from "#root/utils/util.js";
|
|
7
|
+
|
|
7
8
|
import { toSyncDbFieldDef } from "./transform.js";
|
|
8
9
|
|
|
9
10
|
export function printSyncDbProcessLog(message) {
|
package/utils/fieldClear.js
CHANGED
|
@@ -13,7 +13,7 @@ export function fieldClear(data, options = {}) {
|
|
|
13
13
|
const { pickKeys, omitKeys, keepValues, excludeValues, keepMap } = options;
|
|
14
14
|
|
|
15
15
|
const filterObj = (obj) => {
|
|
16
|
-
|
|
16
|
+
const result = {};
|
|
17
17
|
let keys = Object.keys(obj);
|
|
18
18
|
if (pickKeys && pickKeys.length) {
|
|
19
19
|
keys = keys.filter((k) => pickKeys.includes(k));
|