befly 3.9.40 → 3.10.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.
- package/README.md +47 -19
- package/befly.config.ts +19 -2
- package/checks/checkApi.ts +79 -77
- package/checks/checkHook.ts +48 -0
- package/checks/checkMenu.ts +168 -0
- package/checks/checkPlugin.ts +48 -0
- package/checks/checkTable.ts +137 -183
- package/docs/README.md +17 -11
- package/docs/api/api.md +16 -2
- package/docs/guide/quickstart.md +31 -10
- package/docs/hooks/hook.md +2 -2
- package/docs/hooks/rateLimit.md +1 -1
- package/docs/infra/redis.md +26 -14
- package/docs/plugins/plugin.md +23 -21
- package/docs/quickstart.md +5 -328
- package/docs/reference/addon.md +0 -4
- package/docs/reference/config.md +14 -31
- package/docs/reference/logger.md +3 -3
- package/docs/reference/sync.md +132 -237
- package/docs/reference/table.md +28 -30
- package/hooks/auth.ts +3 -4
- package/hooks/cors.ts +4 -6
- package/hooks/parser.ts +3 -4
- package/hooks/permission.ts +3 -4
- package/hooks/validator.ts +3 -4
- package/lib/cacheHelper.ts +89 -153
- package/lib/cacheKeys.ts +1 -1
- package/lib/connect.ts +9 -13
- package/lib/dbDialect.ts +285 -0
- package/lib/dbHelper.ts +179 -507
- package/lib/dbUtils.ts +450 -0
- package/lib/logger.ts +41 -5
- package/lib/redisHelper.ts +1 -0
- package/lib/sqlBuilder.ts +358 -58
- package/lib/sqlCheck.ts +136 -0
- package/lib/validator.ts +1 -1
- package/loader/loadApis.ts +23 -126
- package/loader/loadHooks.ts +31 -46
- package/loader/loadPlugins.ts +37 -52
- package/main.ts +58 -19
- package/package.json +24 -25
- package/paths.ts +14 -14
- package/plugins/cache.ts +12 -6
- package/plugins/cipher.ts +2 -2
- package/plugins/config.ts +6 -8
- package/plugins/db.ts +14 -19
- package/plugins/jwt.ts +6 -7
- package/plugins/logger.ts +7 -9
- package/plugins/redis.ts +8 -10
- package/plugins/tool.ts +3 -4
- package/router/api.ts +3 -2
- package/router/static.ts +7 -5
- package/sync/syncApi.ts +80 -235
- package/sync/syncCache.ts +16 -0
- package/sync/syncDev.ts +167 -202
- package/sync/syncMenu.ts +230 -444
- package/sync/syncTable.ts +1247 -0
- package/tests/_mocks/mockSqliteDb.ts +204 -0
- package/tests/addonHelper-cache.test.ts +32 -0
- package/tests/apiHandler-routePath-only.test.ts +32 -0
- package/tests/cacheHelper.test.ts +16 -51
- package/tests/checkApi-routePath-strict.test.ts +166 -0
- package/tests/checkMenu.test.ts +346 -0
- package/tests/checkTable-smoke.test.ts +157 -0
- package/tests/dbDialect-cache.test.ts +23 -0
- package/tests/dbDialect.test.ts +46 -0
- package/tests/dbHelper-advanced.test.ts +1 -1
- package/tests/dbHelper-all-array-types.test.ts +15 -15
- package/tests/dbHelper-batch-write.test.ts +90 -0
- package/tests/dbHelper-columns.test.ts +36 -54
- package/tests/dbHelper-execute.test.ts +26 -26
- package/tests/dbHelper-joins.test.ts +85 -176
- package/tests/fixtures/scanFilesAddon/node_modules/@befly-addon/demo/apis/sub/b.ts +3 -0
- package/tests/fixtures/scanFilesApis/a.ts +3 -0
- package/tests/fixtures/scanFilesApis/sub/b.ts +3 -0
- package/tests/loadPlugins-order-smoke.test.ts +75 -0
- package/tests/logger.test.ts +6 -6
- package/tests/redisHelper.test.ts +6 -1
- package/tests/scanFiles-routePath.test.ts +46 -0
- package/tests/smoke-sql.test.ts +24 -0
- package/tests/sqlBuilder-advanced.test.ts +18 -5
- package/tests/sqlBuilder.test.ts +24 -0
- package/tests/sync-init-guard.test.ts +105 -0
- package/tests/syncApi-insBatch-fields-consistent.test.ts +61 -0
- package/tests/syncApi-obsolete-records.test.ts +69 -0
- package/tests/syncApi-type-compat.test.ts +72 -0
- package/tests/syncDev-permissions.test.ts +81 -0
- package/tests/syncMenu-disableMenus-hard-delete.test.ts +88 -0
- package/tests/syncMenu-duplicate-path.test.ts +122 -0
- package/tests/syncMenu-obsolete-records.test.ts +161 -0
- package/tests/syncMenu-parentPath-from-tree.test.ts +75 -0
- package/tests/syncMenu-paths.test.ts +0 -9
- package/tests/{syncDb-apply.test.ts → syncTable-apply.test.ts} +14 -24
- package/tests/{syncDb-array-number.test.ts → syncTable-array-number.test.ts} +31 -31
- package/tests/syncTable-constants.test.ts +101 -0
- package/tests/syncTable-db-integration.test.ts +237 -0
- package/tests/{syncDb-ddl.test.ts → syncTable-ddl.test.ts} +67 -53
- package/tests/{syncDb-helpers.test.ts → syncTable-helpers.test.ts} +12 -26
- package/tests/syncTable-schema.test.ts +99 -0
- package/tests/syncTable-testkit.test.ts +25 -0
- package/tests/syncTable-types.test.ts +122 -0
- package/tests/tableRef-and-deserialize.test.ts +67 -0
- package/tsconfig.json +1 -1
- package/types/api.d.ts +1 -1
- package/types/befly.d.ts +13 -12
- package/types/cache.d.ts +2 -2
- package/types/context.d.ts +1 -1
- package/types/database.d.ts +0 -5
- package/types/hook.d.ts +1 -10
- package/types/plugin.d.ts +2 -96
- package/types/sync.d.ts +19 -25
- package/utils/convertBigIntFields.ts +38 -0
- package/utils/disableMenusGlob.ts +85 -0
- package/utils/importDefault.ts +21 -0
- package/utils/isDirentDirectory.ts +23 -0
- package/utils/loadMenuConfigs.ts +145 -0
- package/utils/processFields.ts +25 -0
- package/utils/scanAddons.ts +72 -0
- package/utils/scanFiles.ts +129 -21
- package/utils/scanSources.ts +64 -0
- package/utils/sortModules.ts +137 -0
- package/checks/checkApp.ts +0 -55
- package/docs/cipher.md +0 -582
- package/docs/database.md +0 -1176
- package/hooks/rateLimit.ts +0 -276
- package/sync/syncAll.ts +0 -35
- package/sync/syncDb/apply.ts +0 -192
- package/sync/syncDb/constants.ts +0 -119
- package/sync/syncDb/ddl.ts +0 -251
- package/sync/syncDb/helpers.ts +0 -84
- package/sync/syncDb/schema.ts +0 -202
- package/sync/syncDb/sqlite.ts +0 -48
- package/sync/syncDb/table.ts +0 -207
- package/sync/syncDb/tableCreate.ts +0 -163
- package/sync/syncDb/types.ts +0 -132
- package/sync/syncDb/version.ts +0 -69
- package/sync/syncDb.ts +0 -168
- package/tests/rateLimit-hook.test.ts +0 -477
- package/tests/syncDb-constants.test.ts +0 -130
- package/tests/syncDb-schema.test.ts +0 -179
- package/tests/syncDb-types.test.ts +0 -139
- package/utils/addonHelper.ts +0 -90
- package/utils/modules.ts +0 -98
- package/utils/route.ts +0 -23
package/sync/syncDev.ts
CHANGED
|
@@ -1,230 +1,195 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* - 邮箱: 通过 DEV_EMAIL 环境变量配置(默认 dev@qq.com)
|
|
4
|
-
* - 姓名: 开发者
|
|
5
|
-
* - 密码: 使用 bcrypt 加密,通过 DEV_PASSWORD 环境变量配置
|
|
6
|
-
* - 角色: 同步 dev, user, admin, guest 四个角色
|
|
7
|
-
* - dev: 拥有所有菜单和接口权限
|
|
8
|
-
* - user, admin, guest: 菜单和接口权限为空
|
|
9
|
-
* - 同步完成后:重建角色接口权限缓存到 Redis(极简方案:覆盖更新)
|
|
10
|
-
* - 表名: addon_admin_admin
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import type { SyncDevOptions } from "../types/sync.js";
|
|
14
|
-
|
|
15
|
-
import { beflyConfig } from "../befly.config.js";
|
|
16
|
-
import { CacheHelper } from "../lib/cacheHelper.js";
|
|
1
|
+
import type { BeflyContext } from "../types/befly.js";
|
|
2
|
+
|
|
17
3
|
import { Cipher } from "../lib/cipher.js";
|
|
18
|
-
import { Connect } from "../lib/connect.js";
|
|
19
|
-
import { DbHelper } from "../lib/dbHelper.js";
|
|
20
4
|
import { Logger } from "../lib/logger.js";
|
|
21
|
-
import { RedisHelper } from "../lib/redisHelper.js";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* SyncDev 命令主函数
|
|
25
|
-
*/
|
|
26
|
-
export async function syncDevCommand(options: SyncDevOptions = {}): Promise<void> {
|
|
27
|
-
try {
|
|
28
|
-
if (options.plan) {
|
|
29
|
-
Logger.debug("[计划] 同步完成后将初始化/更新开发管理员账号(plan 模式不执行)");
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
5
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
6
|
+
export type SyncDevConfig = {
|
|
7
|
+
devEmail?: string;
|
|
8
|
+
devPassword?: string;
|
|
9
|
+
};
|
|
37
10
|
|
|
38
|
-
|
|
39
|
-
|
|
11
|
+
export async function syncDev(ctx: BeflyContext, config: SyncDevConfig = {}): Promise<void> {
|
|
12
|
+
if (!config.devPassword) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
40
15
|
|
|
41
|
-
|
|
42
|
-
const helper = new DbHelper({ redis: redisHelper } as any, Connect.getSql());
|
|
16
|
+
const devEmail = typeof config.devEmail === "string" && config.devEmail.length > 0 ? config.devEmail : "dev@qq.com";
|
|
43
17
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Logger.debug("[SyncDev] 表 addon_admin_admin 不存在,跳过开发者账号同步");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
18
|
+
if (!ctx.db) {
|
|
19
|
+
throw new Error("syncDev: ctx.db 未初始化(Db 插件未加载或注入失败)");
|
|
20
|
+
}
|
|
50
21
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Logger.debug("[SyncDev] 表 addon_admin_role 不存在,跳过开发者账号同步");
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
22
|
+
if (!ctx.cache) {
|
|
23
|
+
throw new Error("syncDev: ctx.cache 未初始化(cache 插件未加载或注入失败)");
|
|
24
|
+
}
|
|
57
25
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
if (!(await ctx.db.tableExists("addon_admin_admin"))) {
|
|
27
|
+
Logger.debug(`addon_admin_admin 表不存在`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!(await ctx.db.tableExists("addon_admin_role"))) {
|
|
31
|
+
Logger.debug(`addon_admin_role 表不存在`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!(await ctx.db.tableExists("addon_admin_menu"))) {
|
|
35
|
+
Logger.debug(`addon_admin_menu 表不存在`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
64
38
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
39
|
+
const allMenus = await ctx.db.getAll({
|
|
40
|
+
table: "addon_admin_menu",
|
|
41
|
+
fields: ["path"],
|
|
42
|
+
where: { state$gte: 0 },
|
|
43
|
+
orderBy: ["id#ASC"]
|
|
44
|
+
} as any);
|
|
45
|
+
|
|
46
|
+
const menuPaths = Array.from(new Set((allMenus.lists || []).map((m: any) => (typeof m?.path === "string" ? m.path.trim() : "")).filter((p: string) => p.length > 0)));
|
|
47
|
+
|
|
48
|
+
const existApi = await ctx.db.tableExists("addon_admin_api");
|
|
49
|
+
let apiPaths: string[] = [];
|
|
50
|
+
if (existApi) {
|
|
51
|
+
const allApis = await ctx.db.getAll({
|
|
52
|
+
table: "addon_admin_api",
|
|
53
|
+
fields: ["routePath"],
|
|
54
|
+
where: { state$gte: 0 },
|
|
69
55
|
orderBy: ["id#ASC"]
|
|
70
|
-
});
|
|
56
|
+
} as any);
|
|
57
|
+
|
|
58
|
+
apiPaths = Array.from(
|
|
59
|
+
new Set(
|
|
60
|
+
(allApis.lists || []).map((a: any) => {
|
|
61
|
+
if (typeof a?.routePath !== "string") {
|
|
62
|
+
throw new Error("syncDev: addon_admin_api.routePath 必须是字符串");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const routePath = a.routePath.trim();
|
|
66
|
+
if (routePath.length === 0) {
|
|
67
|
+
throw new Error("syncDev: addon_admin_api.routePath 不允许为空字符串");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!routePath.startsWith("/")) {
|
|
71
|
+
throw new Error(`syncDev: addon_admin_api.routePath 必须是 pathname(以 / 开头),当前值=${routePath}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return routePath;
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
const roles = [
|
|
81
|
+
{
|
|
82
|
+
code: "dev",
|
|
83
|
+
name: "开发者角色",
|
|
84
|
+
description: "拥有所有菜单和接口权限的开发者角色",
|
|
85
|
+
menus: menuPaths,
|
|
86
|
+
apis: apiPaths,
|
|
87
|
+
sort: 0
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
code: "user",
|
|
91
|
+
name: "用户角色",
|
|
92
|
+
description: "普通用户角色",
|
|
93
|
+
menus: [],
|
|
94
|
+
apis: [],
|
|
95
|
+
sort: 1
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
code: "admin",
|
|
99
|
+
name: "管理员角色",
|
|
100
|
+
description: "管理员角色",
|
|
101
|
+
menus: [],
|
|
102
|
+
apis: [],
|
|
103
|
+
sort: 2
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
code: "guest",
|
|
107
|
+
name: "访客角色",
|
|
108
|
+
description: "访客角色",
|
|
109
|
+
menus: [],
|
|
110
|
+
apis: [],
|
|
111
|
+
sort: 3
|
|
75
112
|
}
|
|
113
|
+
];
|
|
76
114
|
|
|
77
|
-
|
|
115
|
+
let devRole = null;
|
|
116
|
+
for (const roleConfig of roles) {
|
|
117
|
+
const existingRole = await ctx.db.getOne({
|
|
118
|
+
table: "addon_admin_role",
|
|
119
|
+
where: { code: roleConfig.code }
|
|
120
|
+
});
|
|
78
121
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (existApi) {
|
|
83
|
-
const allApis = await helper.getAll({
|
|
84
|
-
table: "addon_admin_api",
|
|
85
|
-
fields: ["id"],
|
|
86
|
-
orderBy: ["id#ASC"]
|
|
87
|
-
});
|
|
122
|
+
if (existingRole) {
|
|
123
|
+
const nextMenus = roleConfig.menus;
|
|
124
|
+
const nextApis = roleConfig.apis;
|
|
88
125
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
}
|
|
126
|
+
const existingMenus = Array.isArray(existingRole.menus) ? existingRole.menus : [];
|
|
127
|
+
const existingApis = Array.isArray(existingRole.apis) ? existingRole.apis : [];
|
|
93
128
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
{
|
|
97
|
-
code: "dev",
|
|
98
|
-
name: "开发者角色",
|
|
99
|
-
description: "拥有所有菜单和接口权限的开发者角色",
|
|
100
|
-
menus: menuIds,
|
|
101
|
-
apis: apiIds,
|
|
102
|
-
sort: 0
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
code: "user",
|
|
106
|
-
name: "用户角色",
|
|
107
|
-
description: "普通用户角色",
|
|
108
|
-
menus: [],
|
|
109
|
-
apis: [],
|
|
110
|
-
sort: 1
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
code: "admin",
|
|
114
|
-
name: "管理员角色",
|
|
115
|
-
description: "管理员角色",
|
|
116
|
-
menus: [],
|
|
117
|
-
apis: [],
|
|
118
|
-
sort: 2
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
code: "guest",
|
|
122
|
-
name: "访客角色",
|
|
123
|
-
description: "访客角色",
|
|
124
|
-
menus: [],
|
|
125
|
-
apis: [],
|
|
126
|
-
sort: 3
|
|
127
|
-
}
|
|
128
|
-
];
|
|
129
|
+
const menusChanged = existingMenus.length !== nextMenus.length || existingMenus.some((v: any, i: number) => v !== nextMenus[i]);
|
|
130
|
+
const apisChanged = existingApis.length !== nextApis.length || existingApis.some((v: any, i: number) => v !== nextApis[i]);
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
let devRole = null;
|
|
132
|
-
for (const roleConfig of roles) {
|
|
133
|
-
const existingRole = await helper.getOne({
|
|
134
|
-
table: "addon_admin_role",
|
|
135
|
-
where: { code: roleConfig.code }
|
|
136
|
-
});
|
|
132
|
+
const hasChanges = existingRole.name !== roleConfig.name || existingRole.description !== roleConfig.description || menusChanged || apisChanged || existingRole.sort !== roleConfig.sort;
|
|
137
133
|
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
const existingMenusJson = JSON.stringify(existingRole.menus || []);
|
|
141
|
-
const existingApisJson = JSON.stringify(existingRole.apis || []);
|
|
142
|
-
const nextMenusJson = JSON.stringify(roleConfig.menus);
|
|
143
|
-
const nextApisJson = JSON.stringify(roleConfig.apis);
|
|
144
|
-
|
|
145
|
-
const hasChanges = existingRole.name !== roleConfig.name || existingRole.description !== roleConfig.description || existingMenusJson !== nextMenusJson || existingApisJson !== nextApisJson || existingRole.sort !== roleConfig.sort;
|
|
146
|
-
|
|
147
|
-
if (hasChanges) {
|
|
148
|
-
// 更新现有角色
|
|
149
|
-
await helper.updData({
|
|
150
|
-
table: "addon_admin_role",
|
|
151
|
-
where: { code: roleConfig.code },
|
|
152
|
-
data: {
|
|
153
|
-
name: roleConfig.name,
|
|
154
|
-
description: roleConfig.description,
|
|
155
|
-
menus: roleConfig.menus,
|
|
156
|
-
apis: roleConfig.apis,
|
|
157
|
-
sort: roleConfig.sort
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
if (roleConfig.code === "dev") {
|
|
162
|
-
devRole = existingRole;
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
// 创建新角色
|
|
166
|
-
const roleId = await helper.insData({
|
|
134
|
+
if (hasChanges) {
|
|
135
|
+
await ctx.db.updData({
|
|
167
136
|
table: "addon_admin_role",
|
|
168
|
-
|
|
137
|
+
where: { code: roleConfig.code },
|
|
138
|
+
data: {
|
|
139
|
+
name: roleConfig.name,
|
|
140
|
+
description: roleConfig.description,
|
|
141
|
+
menus: roleConfig.menus,
|
|
142
|
+
apis: roleConfig.apis,
|
|
143
|
+
sort: roleConfig.sort
|
|
144
|
+
}
|
|
169
145
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
146
|
+
}
|
|
147
|
+
if (roleConfig.code === "dev") {
|
|
148
|
+
devRole = existingRole;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
const roleId = await ctx.db.insData({
|
|
152
|
+
table: "addon_admin_role",
|
|
153
|
+
data: roleConfig
|
|
154
|
+
});
|
|
155
|
+
if (roleConfig.code === "dev") {
|
|
156
|
+
devRole = { id: roleId };
|
|
173
157
|
}
|
|
174
158
|
}
|
|
159
|
+
}
|
|
175
160
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
161
|
+
if (!devRole) {
|
|
162
|
+
Logger.error("dev 角色不存在,无法创建开发者账号");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
180
165
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
166
|
+
const sha256Hashed = Cipher.sha256(config.devPassword + "befly");
|
|
167
|
+
const hashed = await Cipher.hashPassword(sha256Hashed);
|
|
168
|
+
|
|
169
|
+
const devData = {
|
|
170
|
+
nickname: "开发者",
|
|
171
|
+
email: devEmail,
|
|
172
|
+
username: "dev",
|
|
173
|
+
password: hashed,
|
|
174
|
+
roleCode: "dev",
|
|
175
|
+
roleType: "admin"
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const existing = await ctx.db.getOne({
|
|
179
|
+
table: "addon_admin_admin",
|
|
180
|
+
where: { email: devEmail }
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (existing) {
|
|
184
|
+
await ctx.db.updData({
|
|
197
185
|
table: "addon_admin_admin",
|
|
198
|
-
where: { email:
|
|
186
|
+
where: { email: devEmail },
|
|
187
|
+
data: devData
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
await ctx.db.insData({
|
|
191
|
+
table: "addon_admin_admin",
|
|
192
|
+
data: devData
|
|
199
193
|
});
|
|
200
|
-
|
|
201
|
-
if (existing) {
|
|
202
|
-
// 更新现有账号
|
|
203
|
-
await helper.updData({
|
|
204
|
-
table: "addon_admin_admin",
|
|
205
|
-
where: { email: beflyConfig.devEmail },
|
|
206
|
-
data: devData
|
|
207
|
-
});
|
|
208
|
-
} else {
|
|
209
|
-
// 插入新账号
|
|
210
|
-
await helper.insData({
|
|
211
|
-
table: "addon_admin_admin",
|
|
212
|
-
data: devData
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// 重建角色接口权限缓存到 Redis(极简方案:覆盖更新)
|
|
217
|
-
// 说明:syncDev 会修改角色 apis,需同步刷新对应角色权限缓存
|
|
218
|
-
try {
|
|
219
|
-
const cacheHelper = new CacheHelper({ db: helper, redis: redisHelper } as any);
|
|
220
|
-
await cacheHelper.rebuildRoleApiPermissions();
|
|
221
|
-
} catch (error: any) {
|
|
222
|
-
Logger.warn({ err: error }, "[SyncDev] 重建角色接口权限缓存失败");
|
|
223
|
-
}
|
|
224
|
-
} catch (error: any) {
|
|
225
|
-
Logger.error({ err: error }, "同步开发者管理员失败");
|
|
226
|
-
throw error;
|
|
227
|
-
} finally {
|
|
228
|
-
await Connect.disconnect();
|
|
229
194
|
}
|
|
230
195
|
}
|