befly 3.16.10 → 3.16.11
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 +0 -129
- package/befly.js +12769 -0
- package/befly.min.js +47 -0
- package/package.json +18 -29
- package/dist/befly.config.d.ts +0 -7
- package/dist/befly.config.js +0 -128
- package/dist/befly.js +0 -17348
- package/dist/befly.min.js +0 -23
- package/dist/checks/checkApi.d.ts +0 -1
- package/dist/checks/checkApi.js +0 -139
- package/dist/checks/checkConfig.d.ts +0 -9
- package/dist/checks/checkConfig.js +0 -255
- package/dist/checks/checkHook.d.ts +0 -1
- package/dist/checks/checkHook.js +0 -132
- package/dist/checks/checkMenu.d.ts +0 -3
- package/dist/checks/checkMenu.js +0 -106
- package/dist/checks/checkPlugin.d.ts +0 -1
- package/dist/checks/checkPlugin.js +0 -132
- package/dist/checks/checkTable.d.ts +0 -7
- package/dist/checks/checkTable.js +0 -431
- package/dist/configs/presetRegexp.d.ts +0 -145
- package/dist/configs/presetRegexp.js +0 -218
- package/dist/hooks/auth.d.ts +0 -3
- package/dist/hooks/auth.js +0 -24
- package/dist/hooks/cors.d.ts +0 -7
- package/dist/hooks/cors.js +0 -36
- package/dist/hooks/parser.d.ts +0 -10
- package/dist/hooks/parser.js +0 -76
- package/dist/hooks/permission.d.ts +0 -11
- package/dist/hooks/permission.js +0 -78
- package/dist/hooks/validator.d.ts +0 -7
- package/dist/hooks/validator.js +0 -52
- package/dist/index.d.ts +0 -28
- package/dist/index.js +0 -316
- package/dist/lib/asyncContext.d.ts +0 -21
- package/dist/lib/asyncContext.js +0 -27
- package/dist/lib/cacheHelper.d.ts +0 -128
- package/dist/lib/cacheHelper.js +0 -477
- package/dist/lib/cacheKeys.d.ts +0 -27
- package/dist/lib/cacheKeys.js +0 -37
- package/dist/lib/cipher.d.ts +0 -153
- package/dist/lib/cipher.js +0 -237
- package/dist/lib/connect.d.ts +0 -95
- package/dist/lib/connect.js +0 -313
- package/dist/lib/dbHelper.d.ts +0 -229
- package/dist/lib/dbHelper.js +0 -1099
- package/dist/lib/dbUtils.d.ts +0 -91
- package/dist/lib/dbUtils.js +0 -544
- package/dist/lib/jwt.d.ts +0 -13
- package/dist/lib/jwt.js +0 -77
- package/dist/lib/logger.d.ts +0 -46
- package/dist/lib/logger.js +0 -731
- package/dist/lib/redisHelper.d.ts +0 -193
- package/dist/lib/redisHelper.js +0 -598
- package/dist/lib/sqlBuilder.d.ts +0 -160
- package/dist/lib/sqlBuilder.js +0 -837
- package/dist/lib/sqlCheck.d.ts +0 -23
- package/dist/lib/sqlCheck.js +0 -119
- package/dist/lib/validator.d.ts +0 -45
- package/dist/lib/validator.js +0 -424
- package/dist/loader/loadApis.d.ts +0 -12
- package/dist/loader/loadApis.js +0 -71
- package/dist/loader/loadHooks.d.ts +0 -7
- package/dist/loader/loadHooks.js +0 -50
- package/dist/loader/loadPlugins.d.ts +0 -8
- package/dist/loader/loadPlugins.js +0 -69
- package/dist/paths.d.ts +0 -93
- package/dist/paths.js +0 -100
- package/dist/plugins/cache.d.ts +0 -10
- package/dist/plugins/cache.js +0 -24
- package/dist/plugins/cipher.d.ts +0 -7
- package/dist/plugins/cipher.js +0 -14
- package/dist/plugins/config.d.ts +0 -3
- package/dist/plugins/config.js +0 -9
- package/dist/plugins/db.d.ts +0 -10
- package/dist/plugins/db.js +0 -48
- package/dist/plugins/jwt.d.ts +0 -6
- package/dist/plugins/jwt.js +0 -13
- package/dist/plugins/logger.d.ts +0 -10
- package/dist/plugins/logger.js +0 -21
- package/dist/plugins/redis.d.ts +0 -10
- package/dist/plugins/redis.js +0 -40
- package/dist/plugins/tool.d.ts +0 -75
- package/dist/plugins/tool.js +0 -105
- package/dist/router/api.d.ts +0 -14
- package/dist/router/api.js +0 -109
- package/dist/router/static.d.ts +0 -9
- package/dist/router/static.js +0 -56
- package/dist/scripts/ensureDist.d.ts +0 -1
- package/dist/scripts/ensureDist.js +0 -296
- package/dist/sync/syncApi.d.ts +0 -3
- package/dist/sync/syncApi.js +0 -163
- package/dist/sync/syncCache.d.ts +0 -2
- package/dist/sync/syncCache.js +0 -14
- package/dist/sync/syncDev.d.ts +0 -6
- package/dist/sync/syncDev.js +0 -166
- package/dist/sync/syncMenu.d.ts +0 -14
- package/dist/sync/syncMenu.js +0 -308
- package/dist/sync/syncTable.d.ts +0 -126
- package/dist/sync/syncTable.js +0 -1129
- package/dist/types/api.d.ts +0 -177
- package/dist/types/api.js +0 -4
- package/dist/types/befly.d.ts +0 -231
- package/dist/types/befly.js +0 -4
- package/dist/types/cache.d.ts +0 -96
- package/dist/types/cache.js +0 -4
- package/dist/types/cipher.d.ts +0 -27
- package/dist/types/cipher.js +0 -7
- package/dist/types/common.d.ts +0 -127
- package/dist/types/common.js +0 -5
- package/dist/types/context.d.ts +0 -39
- package/dist/types/context.js +0 -4
- package/dist/types/coreError.d.ts +0 -31
- package/dist/types/coreError.js +0 -38
- package/dist/types/crypto.d.ts +0 -20
- package/dist/types/crypto.js +0 -4
- package/dist/types/database.d.ts +0 -182
- package/dist/types/database.js +0 -4
- package/dist/types/hook.d.ts +0 -30
- package/dist/types/hook.js +0 -19
- package/dist/types/jwt.d.ts +0 -76
- package/dist/types/jwt.js +0 -4
- package/dist/types/logger.d.ts +0 -95
- package/dist/types/logger.js +0 -6
- package/dist/types/plugin.d.ts +0 -27
- package/dist/types/plugin.js +0 -17
- package/dist/types/redis.d.ts +0 -80
- package/dist/types/redis.js +0 -4
- package/dist/types/roleApisCache.d.ts +0 -21
- package/dist/types/roleApisCache.js +0 -8
- package/dist/types/sync.d.ts +0 -93
- package/dist/types/sync.js +0 -4
- package/dist/types/table.d.ts +0 -34
- package/dist/types/table.js +0 -4
- package/dist/types/validate.d.ts +0 -113
- package/dist/types/validate.js +0 -4
- package/dist/utils/calcPerfTime.d.ts +0 -4
- package/dist/utils/calcPerfTime.js +0 -13
- package/dist/utils/cors.d.ts +0 -8
- package/dist/utils/cors.js +0 -17
- package/dist/utils/dbFieldRules.d.ts +0 -31
- package/dist/utils/dbFieldRules.js +0 -94
- package/dist/utils/fieldClear.d.ts +0 -11
- package/dist/utils/fieldClear.js +0 -57
- package/dist/utils/formatYmdHms.d.ts +0 -1
- package/dist/utils/formatYmdHms.js +0 -20
- package/dist/utils/getClientIp.d.ts +0 -6
- package/dist/utils/getClientIp.js +0 -39
- package/dist/utils/importDefault.d.ts +0 -1
- package/dist/utils/importDefault.js +0 -53
- package/dist/utils/isDirentDirectory.d.ts +0 -3
- package/dist/utils/isDirentDirectory.js +0 -18
- package/dist/utils/loadMenuConfigs.d.ts +0 -11
- package/dist/utils/loadMenuConfigs.js +0 -130
- package/dist/utils/loggerUtils.d.ts +0 -18
- package/dist/utils/loggerUtils.js +0 -171
- package/dist/utils/mergeAndConcat.d.ts +0 -7
- package/dist/utils/mergeAndConcat.js +0 -77
- package/dist/utils/normalizeFieldDefinition.d.ts +0 -18
- package/dist/utils/normalizeFieldDefinition.js +0 -27
- package/dist/utils/processInfo.d.ts +0 -26
- package/dist/utils/processInfo.js +0 -41
- package/dist/utils/response.d.ts +0 -20
- package/dist/utils/response.js +0 -96
- package/dist/utils/scanAddons.d.ts +0 -15
- package/dist/utils/scanAddons.js +0 -35
- package/dist/utils/scanCoreBuiltins.d.ts +0 -3
- package/dist/utils/scanCoreBuiltins.js +0 -72
- package/dist/utils/scanFiles.d.ts +0 -32
- package/dist/utils/scanFiles.js +0 -124
- package/dist/utils/scanSources.d.ts +0 -10
- package/dist/utils/scanSources.js +0 -46
- package/dist/utils/sortModules.d.ts +0 -28
- package/dist/utils/sortModules.js +0 -105
- package/dist/utils/sqlUtil.d.ts +0 -33
- package/dist/utils/sqlUtil.js +0 -146
- package/dist/utils/util.d.ts +0 -172
- package/dist/utils/util.js +0 -517
package/dist/sync/syncApi.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../lib/logger";
|
|
2
|
-
import { CoreError } from "../types/coreError";
|
|
3
|
-
import { keyBy } from "../utils/util";
|
|
4
|
-
const getApiParentPath = (apiPath) => {
|
|
5
|
-
const segments = apiPath
|
|
6
|
-
.split("/")
|
|
7
|
-
.map((s) => s.trim())
|
|
8
|
-
.filter((s) => s.length > 0);
|
|
9
|
-
// segments 示例:
|
|
10
|
-
// - /api/addon/admin/sysConfig/list -> ["api","addon","admin","sysConfig","list"]
|
|
11
|
-
// - /api/app/test/hi -> ["api","app","test","hi"]
|
|
12
|
-
const seg2 = segments[1] || "";
|
|
13
|
-
const take = seg2 === "addon" ? 4 : 3;
|
|
14
|
-
const parentSegments = segments.slice(0, Math.min(take, segments.length));
|
|
15
|
-
if (parentSegments.length === 0)
|
|
16
|
-
return "";
|
|
17
|
-
return `/${parentSegments.join("/")}`;
|
|
18
|
-
};
|
|
19
|
-
const normalizeAuthForDb = (value) => {
|
|
20
|
-
if (value === false || value === 0 || value === "0" || value === "否") {
|
|
21
|
-
return "否";
|
|
22
|
-
}
|
|
23
|
-
if (Array.isArray(value)) {
|
|
24
|
-
const list = value
|
|
25
|
-
.filter((item) => typeof item === "string")
|
|
26
|
-
.map((item) => item.trim())
|
|
27
|
-
.filter((item) => item !== "");
|
|
28
|
-
if (list.length > 0) {
|
|
29
|
-
return list.join(",");
|
|
30
|
-
}
|
|
31
|
-
return "是";
|
|
32
|
-
}
|
|
33
|
-
if (typeof value === "string") {
|
|
34
|
-
const trimmed = value.trim();
|
|
35
|
-
if (trimmed !== "") {
|
|
36
|
-
return trimmed;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return "是";
|
|
40
|
-
};
|
|
41
|
-
export async function syncApi(ctx, apis) {
|
|
42
|
-
const tableName = "addon_admin_api";
|
|
43
|
-
if (!ctx.db) {
|
|
44
|
-
throw new CoreError({ message: "同步接口:ctx.db 未初始化", kind: "validation" });
|
|
45
|
-
}
|
|
46
|
-
if (!ctx.cache) {
|
|
47
|
-
throw new CoreError({ message: "同步接口:ctx.cache 未初始化", kind: "validation" });
|
|
48
|
-
}
|
|
49
|
-
if (!(await ctx.db.tableExists(tableName)).data) {
|
|
50
|
-
Logger.debug(`${tableName} 表不存在`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const allDbApis = await ctx.db.getAll({
|
|
54
|
-
table: tableName,
|
|
55
|
-
fields: ["id", "path", "parentPath", "name", "addonName", "auth", "state"],
|
|
56
|
-
where: { state$gte: 0 }
|
|
57
|
-
});
|
|
58
|
-
const dbLists = allDbApis.data.lists || [];
|
|
59
|
-
const allDbApiMap = keyBy(dbLists, (item) => item.path);
|
|
60
|
-
const insData = [];
|
|
61
|
-
const updData = [];
|
|
62
|
-
const delData = [];
|
|
63
|
-
// 1) 先构建当前扫描到的 path 集合(用于删除差集)
|
|
64
|
-
const apiRouteKeys = new Set();
|
|
65
|
-
// 2) 插入 / 更新(存在不一定更新:仅当 name/path/addonName/auth 任一不匹配时更新)
|
|
66
|
-
for (const api of apis) {
|
|
67
|
-
// 仅当 type **显式存在** 且不为 "api" 时才跳过,避免误把真实 API 条目过滤掉。
|
|
68
|
-
if (api.type !== "api") {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
const record = api;
|
|
72
|
-
const path = record["path"];
|
|
73
|
-
const name = record["name"];
|
|
74
|
-
const addonNameRaw = record["addonName"];
|
|
75
|
-
if (typeof path !== "string" || path.trim() === "") {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (typeof name !== "string" || name.trim() === "") {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const addonName = typeof addonNameRaw === "string" ? addonNameRaw : "";
|
|
82
|
-
// auth:运行时支持 boolean/string[];DB 字段使用字符串(否/是/角色列表)。
|
|
83
|
-
// 统一在 syncApi 写库前做归一化,避免类型不一致导致每次启动都触发更新。
|
|
84
|
-
const authRaw = record["auth"];
|
|
85
|
-
const auth = normalizeAuthForDb(authRaw);
|
|
86
|
-
const parentPath = getApiParentPath(path);
|
|
87
|
-
apiRouteKeys.add(path);
|
|
88
|
-
const item = allDbApiMap[path];
|
|
89
|
-
if (item) {
|
|
90
|
-
const existingAuth = normalizeAuthForDb(item.auth);
|
|
91
|
-
const shouldUpdate = name !== item.name || path !== item.path || addonName !== item.addonName || parentPath !== item.parentPath || auth !== existingAuth;
|
|
92
|
-
if (shouldUpdate) {
|
|
93
|
-
updData.push({
|
|
94
|
-
id: item.id,
|
|
95
|
-
name: name,
|
|
96
|
-
path: path,
|
|
97
|
-
parentPath: parentPath,
|
|
98
|
-
addonName: addonName,
|
|
99
|
-
auth: auth
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
insData.push({
|
|
105
|
-
name: name,
|
|
106
|
-
path: path,
|
|
107
|
-
parentPath: parentPath,
|
|
108
|
-
addonName: addonName,
|
|
109
|
-
auth: auth
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// 3) 删除:用差集(DB - 当前扫描)得到要删除的 id
|
|
114
|
-
for (const record of dbLists) {
|
|
115
|
-
if (!apiRouteKeys.has(record.path)) {
|
|
116
|
-
delData.push(record.id);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (updData.length > 0) {
|
|
120
|
-
try {
|
|
121
|
-
await ctx.db.updBatch(tableName, updData.map((api) => {
|
|
122
|
-
return {
|
|
123
|
-
id: api.id,
|
|
124
|
-
data: {
|
|
125
|
-
name: api.name,
|
|
126
|
-
path: api.path,
|
|
127
|
-
parentPath: api.parentPath,
|
|
128
|
-
addonName: api.addonName,
|
|
129
|
-
auth: api.auth
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
}));
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
Logger.error({ err: error, msg: "同步接口批量更新失败" });
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (insData.length > 0) {
|
|
139
|
-
try {
|
|
140
|
-
await ctx.db.insBatch(tableName, insData.map((api) => {
|
|
141
|
-
return {
|
|
142
|
-
name: api.name,
|
|
143
|
-
path: api.path,
|
|
144
|
-
parentPath: api.parentPath,
|
|
145
|
-
addonName: api.addonName,
|
|
146
|
-
auth: api.auth
|
|
147
|
-
};
|
|
148
|
-
}));
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
Logger.error({ err: error, msg: "同步接口批量新增失败" });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (delData.length > 0) {
|
|
155
|
-
try {
|
|
156
|
-
await ctx.db.delForceBatch(tableName, delData);
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
Logger.error({ err: error, msg: "同步接口批量删除失败" });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// 缓存同步职责已收敛到 syncCache(启动流程单点调用),此处只负责 DB 同步。
|
|
163
|
-
}
|
package/dist/sync/syncCache.d.ts
DELETED
package/dist/sync/syncCache.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { CoreError } from "../types/coreError";
|
|
2
|
-
export async function syncCache(ctx) {
|
|
3
|
-
if (!ctx.cache) {
|
|
4
|
-
throw new CoreError({ message: "同步缓存:ctx.cache 未初始化", kind: "validation" });
|
|
5
|
-
}
|
|
6
|
-
// 1) 缓存接口列表
|
|
7
|
-
await ctx.cache.cacheApis();
|
|
8
|
-
// 2) 缓存菜单列表
|
|
9
|
-
await ctx.cache.cacheMenus();
|
|
10
|
-
// 3) 重建角色权限缓存(严格模式下要求 role.apis 必须为 pathname 字符串数组)
|
|
11
|
-
await ctx.cache.rebuildRoleApiPermissions();
|
|
12
|
-
// 4) 重建角色菜单权限缓存(role.menus 为 menu.path 字符串数组)
|
|
13
|
-
await ctx.cache.rebuildRoleMenuPermissions();
|
|
14
|
-
}
|
package/dist/sync/syncDev.d.ts
DELETED
package/dist/sync/syncDev.js
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { Cipher } from "../lib/cipher";
|
|
2
|
-
import { Logger } from "../lib/logger";
|
|
3
|
-
import { CoreError } from "../types/coreError";
|
|
4
|
-
export async function syncDev(ctx, config = {}) {
|
|
5
|
-
if (!config.devPassword) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
if (!ctx.db) {
|
|
9
|
-
throw new CoreError({
|
|
10
|
-
message: "同步开发:ctx.db 未初始化",
|
|
11
|
-
kind: "validation",
|
|
12
|
-
noLog: true,
|
|
13
|
-
meta: { subsystem: "syncDev", operation: "precheck" }
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
if (!ctx.cache) {
|
|
17
|
-
throw new CoreError({
|
|
18
|
-
message: "同步开发:ctx.cache 未初始化",
|
|
19
|
-
kind: "validation",
|
|
20
|
-
noLog: true,
|
|
21
|
-
meta: { subsystem: "syncDev", operation: "precheck" }
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
if (!(await ctx.db.tableExists("addon_admin_admin")).data) {
|
|
25
|
-
Logger.debug(`addon_admin_admin 表不存在`);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (!(await ctx.db.tableExists("addon_admin_role")).data) {
|
|
29
|
-
Logger.debug(`addon_admin_role 表不存在`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
if (!(await ctx.db.tableExists("addon_admin_menu")).data) {
|
|
33
|
-
Logger.debug(`addon_admin_menu 表不存在`);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (!(await ctx.db.tableExists("addon_admin_api")).data) {
|
|
37
|
-
Logger.debug(`addon_admin_api 表不存在`);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const allMenus = await ctx.db.getAll({
|
|
41
|
-
table: "addon_admin_menu",
|
|
42
|
-
fields: ["path"],
|
|
43
|
-
where: { state$gte: 0 },
|
|
44
|
-
orderBy: ["id#ASC"]
|
|
45
|
-
});
|
|
46
|
-
const allApis = await ctx.db.getAll({
|
|
47
|
-
table: "addon_admin_api",
|
|
48
|
-
fields: ["path"],
|
|
49
|
-
where: { state$gte: 0 },
|
|
50
|
-
orderBy: ["id#ASC"]
|
|
51
|
-
});
|
|
52
|
-
const devRole = await ctx.db.getOne({
|
|
53
|
-
table: "addon_admin_role",
|
|
54
|
-
where: { code: "dev" }
|
|
55
|
-
});
|
|
56
|
-
const devRoleData = {
|
|
57
|
-
code: "dev",
|
|
58
|
-
name: "开发者角色",
|
|
59
|
-
description: "拥有所有菜单和接口权限的开发者角色",
|
|
60
|
-
menus: allMenus.data.lists.map((item) => item.path).filter((v) => typeof v === "string" && v.length > 0),
|
|
61
|
-
apis: allApis.data.lists.map((item) => item.path).filter((v) => typeof v === "string" && v.length > 0),
|
|
62
|
-
sort: 0
|
|
63
|
-
};
|
|
64
|
-
if (typeof devRole.data.id === "number") {
|
|
65
|
-
await ctx.db.updData({
|
|
66
|
-
table: "addon_admin_role",
|
|
67
|
-
where: { code: "dev" },
|
|
68
|
-
data: {
|
|
69
|
-
name: devRoleData.name,
|
|
70
|
-
description: devRoleData.description,
|
|
71
|
-
menus: devRoleData.menus,
|
|
72
|
-
apis: devRoleData.apis,
|
|
73
|
-
sort: devRoleData.sort
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
await ctx.db.insData({
|
|
79
|
-
table: "addon_admin_role",
|
|
80
|
-
data: devRoleData
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
const devAdminData = {
|
|
84
|
-
nickname: "开发者",
|
|
85
|
-
email: config.devEmail || "dev@qq.com",
|
|
86
|
-
username: "dev",
|
|
87
|
-
password: await Cipher.hashPassword(Cipher.sha256(config.devPassword + "befly")),
|
|
88
|
-
roleCode: "dev",
|
|
89
|
-
roleType: "admin"
|
|
90
|
-
};
|
|
91
|
-
const devAdmin = await ctx.db.getOne({
|
|
92
|
-
table: "addon_admin_admin",
|
|
93
|
-
where: { username: "dev" }
|
|
94
|
-
});
|
|
95
|
-
if (typeof devAdmin.data.id === "number") {
|
|
96
|
-
await ctx.db.updData({
|
|
97
|
-
table: "addon_admin_admin",
|
|
98
|
-
where: { username: "dev" },
|
|
99
|
-
data: {
|
|
100
|
-
nickname: devAdminData.nickname,
|
|
101
|
-
email: devAdminData.email,
|
|
102
|
-
username: devAdminData.username,
|
|
103
|
-
password: devAdminData.password,
|
|
104
|
-
roleCode: devAdminData.roleCode,
|
|
105
|
-
roleType: devAdminData.roleType
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
await ctx.db.insData({
|
|
111
|
-
table: "addon_admin_admin",
|
|
112
|
-
data: devAdminData
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const roles = [
|
|
116
|
-
{
|
|
117
|
-
code: "user",
|
|
118
|
-
name: "用户角色",
|
|
119
|
-
description: "普通用户角色",
|
|
120
|
-
sort: 1
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
code: "admin",
|
|
124
|
-
name: "管理员角色",
|
|
125
|
-
description: "管理员角色",
|
|
126
|
-
sort: 2
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
code: "guest",
|
|
130
|
-
name: "访客角色",
|
|
131
|
-
description: "访客角色",
|
|
132
|
-
sort: 3
|
|
133
|
-
}
|
|
134
|
-
];
|
|
135
|
-
for (const roleConfig of roles) {
|
|
136
|
-
const existingRole = await ctx.db.getOne({
|
|
137
|
-
table: "addon_admin_role",
|
|
138
|
-
where: { code: roleConfig.code }
|
|
139
|
-
});
|
|
140
|
-
if (existingRole.data?.id) {
|
|
141
|
-
// 角色存在则强制更新(不做差异判断)
|
|
142
|
-
await ctx.db.updData({
|
|
143
|
-
table: "addon_admin_role",
|
|
144
|
-
where: { code: roleConfig.code },
|
|
145
|
-
data: {
|
|
146
|
-
name: roleConfig.name,
|
|
147
|
-
description: roleConfig.description,
|
|
148
|
-
sort: roleConfig.sort
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
await ctx.db.insData({
|
|
154
|
-
table: "addon_admin_role",
|
|
155
|
-
data: {
|
|
156
|
-
code: roleConfig.code,
|
|
157
|
-
name: roleConfig.name,
|
|
158
|
-
description: roleConfig.description,
|
|
159
|
-
menus: [],
|
|
160
|
-
apis: [],
|
|
161
|
-
sort: roleConfig.sort
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
package/dist/sync/syncMenu.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { BeflyContext } from "../types/befly";
|
|
2
|
-
import type { MenuConfig } from "../types/sync";
|
|
3
|
-
type MenuDef = {
|
|
4
|
-
path: string;
|
|
5
|
-
name: string;
|
|
6
|
-
sort: number;
|
|
7
|
-
parentPath: string;
|
|
8
|
-
};
|
|
9
|
-
export declare function syncMenu(ctx: BeflyContext, mergedMenus: MenuConfig[]): Promise<void>;
|
|
10
|
-
export declare const __test__: {
|
|
11
|
-
scanViewsDir: (viewsDir: string, prefix: string, parentPath?: string) => Promise<MenuConfig[]>;
|
|
12
|
-
flattenMenusToDefMap: (mergedMenus: MenuConfig[]) => Map<string, MenuDef>;
|
|
13
|
-
};
|
|
14
|
-
export {};
|
package/dist/sync/syncMenu.js
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../lib/logger";
|
|
2
|
-
import { CoreError } from "../types/coreError";
|
|
3
|
-
import { getParentPath } from "../utils/loadMenuConfigs";
|
|
4
|
-
function createDisableMenuMatcher(ctx) {
|
|
5
|
-
const rawRules = ctx.config?.disableMenus;
|
|
6
|
-
const rules = Array.isArray(rawRules) ? rawRules : [];
|
|
7
|
-
const patterns = [];
|
|
8
|
-
for (const rule of rules) {
|
|
9
|
-
if (typeof rule !== "string") {
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
12
|
-
const trimmed = rule.trim();
|
|
13
|
-
if (!trimmed) {
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
patterns.push(trimmed);
|
|
17
|
-
}
|
|
18
|
-
if (patterns.length === 0) {
|
|
19
|
-
return () => false;
|
|
20
|
-
}
|
|
21
|
-
const globs = patterns.map((p) => new Bun.Glob(p));
|
|
22
|
-
return (path) => {
|
|
23
|
-
if (typeof path !== "string") {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
const trimmed = path.trim();
|
|
27
|
-
if (!trimmed) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
// Bun.Glob 在不同场景下可能以 "/a/b" 或 "a/b" 参与匹配;这里双候选兜底。
|
|
31
|
-
const candidates = [];
|
|
32
|
-
candidates.push(trimmed);
|
|
33
|
-
if (trimmed.startsWith("/")) {
|
|
34
|
-
candidates.push(trimmed.slice(1));
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
candidates.push(`/${trimmed}`);
|
|
38
|
-
}
|
|
39
|
-
for (const glob of globs) {
|
|
40
|
-
const match = typeof glob === "object" && glob !== null && "match" in glob ? glob.match : undefined;
|
|
41
|
-
if (typeof match !== "function") {
|
|
42
|
-
throw new Error("同步菜单:当前 Bun 版本不支持 Bun.Glob.match,无法按 disableMenus 做 glob 匹配");
|
|
43
|
-
}
|
|
44
|
-
const matchFn = match;
|
|
45
|
-
for (const candidate of candidates) {
|
|
46
|
-
if (matchFn.call(glob, candidate)) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return false;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function filterMenusByDisableMenus(menus, isDisabledPath) {
|
|
55
|
-
const out = [];
|
|
56
|
-
for (const menu of menus) {
|
|
57
|
-
if (menu === null || typeof menu !== "object") {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
const path = typeof menu.path === "string" ? String(menu.path).trim() : "";
|
|
61
|
-
if (path && isDisabledPath(path)) {
|
|
62
|
-
// 节点被禁用:整棵子树直接忽略
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const children = menu.children;
|
|
66
|
-
const nextChildren = Array.isArray(children) && children.length > 0 ? filterMenusByDisableMenus(children, isDisabledPath) : [];
|
|
67
|
-
// 只保留 syncMenu 需要的最小字段,避免引入扩展运算符/不必要的字段复制
|
|
68
|
-
const next = {};
|
|
69
|
-
if (typeof menu.name === "string") {
|
|
70
|
-
next.name = menu.name;
|
|
71
|
-
}
|
|
72
|
-
if (typeof menu.path === "string") {
|
|
73
|
-
next.path = menu.path;
|
|
74
|
-
}
|
|
75
|
-
if (typeof menu.sort === "number") {
|
|
76
|
-
next.sort = menu.sort;
|
|
77
|
-
}
|
|
78
|
-
if (typeof menu.parentPath === "string") {
|
|
79
|
-
next.parentPath = menu.parentPath;
|
|
80
|
-
}
|
|
81
|
-
if (nextChildren.length > 0) {
|
|
82
|
-
next.children = nextChildren;
|
|
83
|
-
}
|
|
84
|
-
out.push(next);
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
88
|
-
function flattenMenusToDefMap(mergedMenus) {
|
|
89
|
-
// 读取配置菜单:扁平化为 path => { name, sort, parentPath }
|
|
90
|
-
// - 以 path 为唯一键:后出现的覆盖先出现的(与旧逻辑“同 path 多次同步同一条记录”一致)
|
|
91
|
-
// parentPath 规则:
|
|
92
|
-
// 1) 若 menu 显式携带 parentPath(包括空字符串),以其为准
|
|
93
|
-
// 2) 否则使用“树结构”推导的父级(由 children 嵌套关系决定;根级为 "")
|
|
94
|
-
// 3) 保底:若无法推导(极端情况),回退到 getParentPath(path)
|
|
95
|
-
const menuDefMap = new Map();
|
|
96
|
-
const stack = [];
|
|
97
|
-
for (const m of mergedMenus) {
|
|
98
|
-
stack.push({ menu: m, parentPathFromTree: "" });
|
|
99
|
-
}
|
|
100
|
-
while (stack.length > 0) {
|
|
101
|
-
const item = stack.pop();
|
|
102
|
-
const menu = item ? item.menu : null;
|
|
103
|
-
if (!menu) {
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const path = typeof menu.path === "string" ? menu.path : "";
|
|
107
|
-
const rawChildren = menu.children;
|
|
108
|
-
if (rawChildren && Array.isArray(rawChildren) && rawChildren.length > 0) {
|
|
109
|
-
const nextParentPathFromTree = typeof path === "string" ? path : "";
|
|
110
|
-
for (const child of rawChildren) {
|
|
111
|
-
stack.push({ menu: child, parentPathFromTree: nextParentPathFromTree });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (!path) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
const name = typeof menu.name === "string" ? menu.name : "";
|
|
118
|
-
if (!name) {
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
const sort = typeof menu.sort === "number" ? menu.sort : 999999;
|
|
122
|
-
const hasExplicitParentPath = typeof menu.parentPath === "string";
|
|
123
|
-
const parentPath = hasExplicitParentPath ? menu.parentPath : typeof item?.parentPathFromTree === "string" ? item.parentPathFromTree : getParentPath(path);
|
|
124
|
-
menuDefMap.set(path, {
|
|
125
|
-
path: path,
|
|
126
|
-
name: name,
|
|
127
|
-
sort: sort,
|
|
128
|
-
parentPath: parentPath
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return menuDefMap;
|
|
132
|
-
}
|
|
133
|
-
export async function syncMenu(ctx, mergedMenus) {
|
|
134
|
-
if (!ctx.db) {
|
|
135
|
-
throw new CoreError({ message: "同步菜单:ctx.db 未初始化", kind: "validation" });
|
|
136
|
-
}
|
|
137
|
-
if (!ctx.cache) {
|
|
138
|
-
throw new CoreError({ message: "同步菜单:ctx.cache 未初始化", kind: "validation" });
|
|
139
|
-
}
|
|
140
|
-
if (!ctx.config) {
|
|
141
|
-
throw new CoreError({ message: "同步菜单:ctx.config 未初始化", kind: "validation" });
|
|
142
|
-
}
|
|
143
|
-
if (!(await ctx.db.tableExists("addon_admin_menu")).data) {
|
|
144
|
-
Logger.debug(`addon_admin_menu 表不存在`);
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const isDisabledPath = createDisableMenuMatcher(ctx);
|
|
148
|
-
const filteredMenus = filterMenusByDisableMenus(mergedMenus, isDisabledPath);
|
|
149
|
-
const menuDefMap = flattenMenusToDefMap(filteredMenus);
|
|
150
|
-
const configPaths = new Set();
|
|
151
|
-
for (const p of menuDefMap.keys()) {
|
|
152
|
-
configPaths.add(p);
|
|
153
|
-
}
|
|
154
|
-
const tableName = "addon_admin_menu";
|
|
155
|
-
// 2) 批量同步(事务内):按 path diff 执行批量 insert/update/delete
|
|
156
|
-
await ctx.db.trans(async (trans) => {
|
|
157
|
-
// 读取全部菜单(用于清理 disableMenus 命中菜单:不分 state)
|
|
158
|
-
const allExistingMenusAllState = await trans.getAll({
|
|
159
|
-
table: tableName,
|
|
160
|
-
fields: ["id", "name", "path", "parentPath", "sort", "state"]
|
|
161
|
-
});
|
|
162
|
-
const existingListAllState = allExistingMenusAllState.data.lists || [];
|
|
163
|
-
const existingList = existingListAllState.filter((m) => typeof m?.state === "number" && m.state >= 0);
|
|
164
|
-
const existingMenuMap = new Map();
|
|
165
|
-
const duplicateIdSet = new Set();
|
|
166
|
-
const duplicatePathInfoMap = new Map();
|
|
167
|
-
for (const record of existingList) {
|
|
168
|
-
if (typeof record?.path !== "string" || !record.path) {
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
if (typeof record?.id !== "number") {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
// disableMenus 命中的记录会在后续强制删除;这里跳过可减少无意义告警
|
|
175
|
-
if (isDisabledPath(record.path)) {
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
const existing = existingMenuMap.get(record.path);
|
|
179
|
-
if (!existing) {
|
|
180
|
-
existingMenuMap.set(record.path, record);
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
const existingId = typeof existing?.id === "number" ? existing.id : 0;
|
|
184
|
-
const recordId = record.id;
|
|
185
|
-
// 保留 id 最大的一条(genTimeID 越大通常越新),其余标记为重复并清理
|
|
186
|
-
if (recordId > existingId) {
|
|
187
|
-
existingMenuMap.set(record.path, record);
|
|
188
|
-
if (existingId > 0) {
|
|
189
|
-
duplicateIdSet.add(existingId);
|
|
190
|
-
}
|
|
191
|
-
const info = duplicatePathInfoMap.get(record.path) || { keptId: recordId, removedIds: [] };
|
|
192
|
-
info.keptId = recordId;
|
|
193
|
-
if (existingId > 0) {
|
|
194
|
-
info.removedIds.push(existingId);
|
|
195
|
-
}
|
|
196
|
-
duplicatePathInfoMap.set(record.path, info);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
if (recordId > 0) {
|
|
200
|
-
duplicateIdSet.add(recordId);
|
|
201
|
-
}
|
|
202
|
-
const info = duplicatePathInfoMap.get(record.path) || { keptId: existingId, removedIds: [] };
|
|
203
|
-
info.keptId = existingId;
|
|
204
|
-
if (recordId > 0) {
|
|
205
|
-
info.removedIds.push(recordId);
|
|
206
|
-
}
|
|
207
|
-
duplicatePathInfoMap.set(record.path, info);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (duplicatePathInfoMap.size > 0) {
|
|
211
|
-
const examples = [];
|
|
212
|
-
for (const entry of duplicatePathInfoMap.entries()) {
|
|
213
|
-
const path = entry[0];
|
|
214
|
-
const info = entry[1];
|
|
215
|
-
examples.push({ path: path, keptId: info.keptId, removedIds: info.removedIds });
|
|
216
|
-
if (examples.length >= 10) {
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
Logger.warn({
|
|
221
|
-
table: tableName,
|
|
222
|
-
duplicatePaths: duplicatePathInfoMap.size,
|
|
223
|
-
duplicateIds: duplicateIdSet.size,
|
|
224
|
-
examples: examples,
|
|
225
|
-
msg: "addon_admin_menu 检测到重复 path 记录:已保留 id 最大的一条并删除其余记录"
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
// 2) 一次性算出 insert/update(仅依赖 path diff,不使用 pid,不预生成 id)
|
|
229
|
-
const updList = [];
|
|
230
|
-
const insList = [];
|
|
231
|
-
for (const def of menuDefMap.values()) {
|
|
232
|
-
const existing = existingMenuMap.get(def.path);
|
|
233
|
-
if (existing) {
|
|
234
|
-
const existingParentPath = typeof existing.parentPath === "string" ? existing.parentPath : "";
|
|
235
|
-
const needUpdate = existing.name !== def.name || existing.sort !== def.sort || existingParentPath !== def.parentPath;
|
|
236
|
-
if (needUpdate) {
|
|
237
|
-
updList.push({
|
|
238
|
-
id: existing.id,
|
|
239
|
-
data: {
|
|
240
|
-
name: def.name,
|
|
241
|
-
path: def.path,
|
|
242
|
-
parentPath: def.parentPath,
|
|
243
|
-
sort: def.sort
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
insList.push({
|
|
250
|
-
name: def.name,
|
|
251
|
-
path: def.path,
|
|
252
|
-
parentPath: def.parentPath,
|
|
253
|
-
sort: def.sort
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (updList.length > 0) {
|
|
258
|
-
await trans.updBatch(tableName, updList);
|
|
259
|
-
}
|
|
260
|
-
if (insList.length > 0) {
|
|
261
|
-
await trans.insBatch(tableName, insList);
|
|
262
|
-
}
|
|
263
|
-
// 3) 删除差集(DB - 配置,仅 state>=0) + 删除重复 path 的多余记录 + 删除 disableMenus 命中菜单(不分 state)
|
|
264
|
-
const delIdSet = new Set();
|
|
265
|
-
for (const record of existingList) {
|
|
266
|
-
if (typeof record?.path !== "string" || !record.path) {
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
if (!configPaths.has(record.path)) {
|
|
270
|
-
if (typeof record?.id === "number") {
|
|
271
|
-
delIdSet.add(record.id);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
for (const id of duplicateIdSet) {
|
|
276
|
-
if (typeof id === "number" && id > 0) {
|
|
277
|
-
delIdSet.add(id);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
// 删除 disableMenus 命中的菜单:不分 state(包括 state=-1 的历史/禁用数据也一并清理)
|
|
281
|
-
for (const record of existingListAllState) {
|
|
282
|
-
if (typeof record?.path !== "string" || !record.path) {
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
if (!isDisabledPath(record.path)) {
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
if (typeof record?.id === "number" && record.id > 0) {
|
|
289
|
-
delIdSet.add(record.id);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const delIds = Array.from(delIdSet);
|
|
293
|
-
if (delIds.length > 0) {
|
|
294
|
-
await trans.delForceBatch(tableName, delIds);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
// 缓存同步职责已收敛到 syncCache(启动流程单点调用),此处只负责 DB 同步。
|
|
298
|
-
}
|
|
299
|
-
// 仅测试用(避免将内部扫描逻辑变成稳定 API)
|
|
300
|
-
export const __test__ = {
|
|
301
|
-
scanViewsDir: async (viewsDir, prefix, parentPath = "") => {
|
|
302
|
-
const mod = await import("../utils/loadMenuConfigs");
|
|
303
|
-
return await mod.scanViewsDirToMenuConfigs(viewsDir, prefix, parentPath);
|
|
304
|
-
},
|
|
305
|
-
flattenMenusToDefMap: (mergedMenus) => {
|
|
306
|
-
return flattenMenusToDefMap(mergedMenus);
|
|
307
|
-
}
|
|
308
|
-
};
|