befly 3.9.38 → 3.9.40
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 +37 -38
- package/befly.config.ts +62 -40
- package/checks/checkApi.ts +16 -16
- package/checks/checkApp.ts +19 -25
- package/checks/checkTable.ts +42 -42
- package/docs/README.md +42 -35
- package/docs/{api.md → api/api.md} +223 -231
- package/docs/cipher.md +71 -69
- package/docs/database.md +143 -141
- package/docs/{examples.md → guide/examples.md} +181 -181
- package/docs/guide/quickstart.md +331 -0
- package/docs/hooks/auth.md +38 -0
- package/docs/hooks/cors.md +28 -0
- package/docs/{hook.md → hooks/hook.md} +140 -57
- package/docs/hooks/parser.md +19 -0
- package/docs/hooks/rateLimit.md +47 -0
- package/docs/{redis.md → infra/redis.md} +84 -93
- package/docs/plugins/cipher.md +61 -0
- package/docs/plugins/database.md +128 -0
- package/docs/{plugin.md → plugins/plugin.md} +83 -81
- package/docs/quickstart.md +26 -26
- package/docs/{addon.md → reference/addon.md} +46 -46
- package/docs/{config.md → reference/config.md} +32 -80
- package/docs/{logger.md → reference/logger.md} +52 -52
- package/docs/{sync.md → reference/sync.md} +32 -35
- package/docs/{table.md → reference/table.md} +1 -1
- package/docs/{validator.md → reference/validator.md} +57 -57
- package/hooks/auth.ts +8 -4
- package/hooks/cors.ts +13 -13
- package/hooks/parser.ts +37 -17
- package/hooks/permission.ts +26 -14
- package/hooks/rateLimit.ts +276 -0
- package/hooks/validator.ts +8 -8
- package/lib/asyncContext.ts +43 -0
- package/lib/cacheHelper.ts +212 -77
- package/lib/cacheKeys.ts +38 -0
- package/lib/cipher.ts +30 -30
- package/lib/connect.ts +28 -28
- package/lib/dbHelper.ts +183 -102
- package/lib/jwt.ts +16 -16
- package/lib/logger.ts +610 -19
- package/lib/redisHelper.ts +185 -44
- package/lib/sqlBuilder.ts +90 -91
- package/lib/validator.ts +59 -39
- package/loader/loadApis.ts +48 -44
- package/loader/loadHooks.ts +40 -14
- package/loader/loadPlugins.ts +16 -17
- package/main.ts +57 -47
- package/package.json +47 -45
- package/paths.ts +15 -14
- package/plugins/cache.ts +5 -4
- package/plugins/cipher.ts +3 -3
- package/plugins/config.ts +2 -2
- package/plugins/db.ts +9 -9
- package/plugins/jwt.ts +3 -3
- package/plugins/logger.ts +8 -12
- package/plugins/redis.ts +8 -8
- package/plugins/tool.ts +6 -6
- package/router/api.ts +85 -56
- package/router/static.ts +12 -12
- package/sync/syncAll.ts +12 -12
- package/sync/syncApi.ts +55 -52
- package/sync/syncDb/apply.ts +20 -19
- package/sync/syncDb/constants.ts +25 -23
- package/sync/syncDb/ddl.ts +35 -36
- package/sync/syncDb/helpers.ts +6 -9
- package/sync/syncDb/schema.ts +10 -9
- package/sync/syncDb/sqlite.ts +7 -8
- package/sync/syncDb/table.ts +37 -35
- package/sync/syncDb/tableCreate.ts +21 -20
- package/sync/syncDb/types.ts +23 -20
- package/sync/syncDb/version.ts +10 -10
- package/sync/syncDb.ts +43 -36
- package/sync/syncDev.ts +74 -65
- package/sync/syncMenu.ts +190 -55
- package/tests/api-integration-array-number.test.ts +282 -0
- package/tests/befly-config-env.test.ts +78 -0
- package/tests/cacheHelper.test.ts +135 -104
- package/tests/cacheKeys.test.ts +41 -0
- package/tests/cipher.test.ts +90 -89
- package/tests/dbHelper-advanced.test.ts +140 -134
- package/tests/dbHelper-all-array-types.test.ts +316 -0
- package/tests/dbHelper-array-serialization.test.ts +258 -0
- package/tests/dbHelper-columns.test.ts +56 -55
- package/tests/dbHelper-execute.test.ts +45 -44
- package/tests/dbHelper-joins.test.ts +124 -119
- package/tests/fields-redis-cache.test.ts +29 -27
- package/tests/fields-validate.test.ts +38 -38
- package/tests/getClientIp.test.ts +54 -0
- package/tests/integration.test.ts +69 -67
- package/tests/jwt.test.ts +27 -26
- package/tests/logger.test.ts +267 -34
- package/tests/rateLimit-hook.test.ts +477 -0
- package/tests/redisHelper.test.ts +187 -188
- package/tests/redisKeys.test.ts +6 -73
- package/tests/scanConfig.test.ts +144 -0
- package/tests/sqlBuilder-advanced.test.ts +217 -215
- package/tests/sqlBuilder.test.ts +92 -91
- package/tests/sync-connection.test.ts +29 -29
- package/tests/syncDb-apply.test.ts +97 -96
- package/tests/syncDb-array-number.test.ts +160 -0
- package/tests/syncDb-constants.test.ts +48 -47
- package/tests/syncDb-ddl.test.ts +99 -98
- package/tests/syncDb-helpers.test.ts +29 -28
- package/tests/syncDb-schema.test.ts +61 -60
- package/tests/syncDb-types.test.ts +60 -59
- package/tests/syncMenu-paths.test.ts +68 -0
- package/tests/util.test.ts +42 -41
- package/tests/validator-array-number.test.ts +310 -0
- package/tests/validator-default.test.ts +373 -0
- package/tests/validator.test.ts +271 -266
- package/tsconfig.json +4 -5
- package/types/api.d.ts +7 -12
- package/types/befly.d.ts +60 -13
- package/types/cache.d.ts +8 -4
- package/types/common.d.ts +17 -9
- package/types/context.d.ts +2 -2
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +19 -19
- package/types/hook.d.ts +2 -2
- package/types/jwt.d.ts +118 -0
- package/types/logger.d.ts +30 -0
- package/types/plugin.d.ts +4 -4
- package/types/redis.d.ts +7 -3
- package/types/roleApisCache.ts +23 -0
- package/types/sync.d.ts +10 -10
- package/types/table.d.ts +50 -9
- package/types/validate.d.ts +69 -0
- package/utils/addonHelper.ts +90 -0
- package/utils/arrayKeysToCamel.ts +18 -0
- package/utils/calcPerfTime.ts +13 -0
- package/utils/configTypes.ts +3 -0
- package/utils/cors.ts +19 -0
- package/utils/fieldClear.ts +75 -0
- package/utils/genShortId.ts +12 -0
- package/utils/getClientIp.ts +45 -0
- package/utils/keysToCamel.ts +22 -0
- package/utils/keysToSnake.ts +22 -0
- package/utils/modules.ts +98 -0
- package/utils/pickFields.ts +19 -0
- package/utils/process.ts +56 -0
- package/utils/regex.ts +225 -0
- package/utils/response.ts +115 -0
- package/utils/route.ts +23 -0
- package/utils/scanConfig.ts +142 -0
- package/utils/scanFiles.ts +48 -0
- package/.prettierignore +0 -2
- package/.prettierrc +0 -12
- package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
- package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
- package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
- package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
- package/hooks/requestLogger.ts +0 -84
- package/types/index.ts +0 -24
- package/util.ts +0 -283
package/sync/syncDev.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
2
|
* SyncDev 命令 - 同步开发者管理员到数据库
|
|
3
3
|
* - 邮箱: 通过 DEV_EMAIL 环境变量配置(默认 dev@qq.com)
|
|
4
4
|
* - 姓名: 开发者
|
|
@@ -6,18 +6,19 @@
|
|
|
6
6
|
* - 角色: 同步 dev, user, admin, guest 四个角色
|
|
7
7
|
* - dev: 拥有所有菜单和接口权限
|
|
8
8
|
* - user, admin, guest: 菜单和接口权限为空
|
|
9
|
+
* - 同步完成后:重建角色接口权限缓存到 Redis(极简方案:覆盖更新)
|
|
9
10
|
* - 表名: addon_admin_admin
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
import {
|
|
13
|
-
import { Cipher } from '../lib/cipher.js';
|
|
14
|
-
import { Connect } from '../lib/connect.js';
|
|
15
|
-
import { DbHelper } from '../lib/dbHelper.js';
|
|
16
|
-
import { RedisHelper } from '../lib/redisHelper.js';
|
|
17
|
-
import { CacheHelper } from '../lib/cacheHelper.js';
|
|
18
|
-
import { beflyConfig } from '../befly.config.js';
|
|
13
|
+
import type { SyncDevOptions } from "../types/sync.js";
|
|
19
14
|
|
|
20
|
-
import
|
|
15
|
+
import { beflyConfig } from "../befly.config.js";
|
|
16
|
+
import { CacheHelper } from "../lib/cacheHelper.js";
|
|
17
|
+
import { Cipher } from "../lib/cipher.js";
|
|
18
|
+
import { Connect } from "../lib/connect.js";
|
|
19
|
+
import { DbHelper } from "../lib/dbHelper.js";
|
|
20
|
+
import { Logger } from "../lib/logger.js";
|
|
21
|
+
import { RedisHelper } from "../lib/redisHelper.js";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* SyncDev 命令主函数
|
|
@@ -25,7 +26,7 @@ import type { SyncDevOptions } from '../types/index.js';
|
|
|
25
26
|
export async function syncDevCommand(options: SyncDevOptions = {}): Promise<void> {
|
|
26
27
|
try {
|
|
27
28
|
if (options.plan) {
|
|
28
|
-
Logger.debug(
|
|
29
|
+
Logger.debug("[计划] 同步完成后将初始化/更新开发管理员账号(plan 模式不执行)");
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -37,88 +38,91 @@ export async function syncDevCommand(options: SyncDevOptions = {}): Promise<void
|
|
|
37
38
|
// 连接数据库(SQL + Redis)
|
|
38
39
|
await Connect.connect();
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
+
const redisHelper = new RedisHelper();
|
|
42
|
+
const helper = new DbHelper({ redis: redisHelper } as any, Connect.getSql());
|
|
41
43
|
|
|
42
44
|
// 检查 addon_admin_admin 表是否存在
|
|
43
|
-
const existAdmin = await helper.tableExists(
|
|
45
|
+
const existAdmin = await helper.tableExists("addon_admin_admin");
|
|
44
46
|
if (!existAdmin) {
|
|
45
|
-
Logger.debug(
|
|
47
|
+
Logger.debug("[SyncDev] 表 addon_admin_admin 不存在,跳过开发者账号同步");
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
// 检查 addon_admin_role 表是否存在
|
|
50
|
-
const existRole = await helper.tableExists(
|
|
52
|
+
const existRole = await helper.tableExists("addon_admin_role");
|
|
51
53
|
if (!existRole) {
|
|
52
|
-
Logger.debug(
|
|
54
|
+
Logger.debug("[SyncDev] 表 addon_admin_role 不存在,跳过开发者账号同步");
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
// 检查 addon_admin_menu 表是否存在
|
|
57
|
-
const existMenu = await helper.tableExists(
|
|
59
|
+
const existMenu = await helper.tableExists("addon_admin_menu");
|
|
58
60
|
if (!existMenu) {
|
|
59
|
-
Logger.debug(
|
|
61
|
+
Logger.debug("[SyncDev] 表 addon_admin_menu 不存在,跳过开发者账号同步");
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
// 查询所有菜单 ID
|
|
64
66
|
const allMenus = await helper.getAll({
|
|
65
|
-
table:
|
|
66
|
-
fields: [
|
|
67
|
+
table: "addon_admin_menu",
|
|
68
|
+
fields: ["id"],
|
|
69
|
+
orderBy: ["id#ASC"]
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
if (!allMenus || !Array.isArray(allMenus.lists)) {
|
|
70
|
-
Logger.debug(
|
|
73
|
+
Logger.debug("[SyncDev] 菜单数据为空,跳过开发者账号同步");
|
|
71
74
|
return;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
const menuIds = allMenus.lists.length > 0 ? allMenus.lists.map((m: any) => m.id)
|
|
77
|
+
const menuIds = allMenus.lists.length > 0 ? allMenus.lists.map((m: any) => m.id) : [];
|
|
75
78
|
|
|
76
79
|
// 查询所有接口 ID
|
|
77
|
-
const existApi = await helper.tableExists(
|
|
78
|
-
let apiIds =
|
|
80
|
+
const existApi = await helper.tableExists("addon_admin_api");
|
|
81
|
+
let apiIds: number[] = [];
|
|
79
82
|
if (existApi) {
|
|
80
83
|
const allApis = await helper.getAll({
|
|
81
|
-
table:
|
|
82
|
-
fields: [
|
|
84
|
+
table: "addon_admin_api",
|
|
85
|
+
fields: ["id"],
|
|
86
|
+
orderBy: ["id#ASC"]
|
|
83
87
|
});
|
|
84
88
|
|
|
85
89
|
if (allApis && Array.isArray(allApis.lists) && allApis.lists.length > 0) {
|
|
86
|
-
apiIds = allApis.lists.map((a: any) => a.id)
|
|
90
|
+
apiIds = allApis.lists.map((a: any) => a.id);
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
// 定义四个角色的配置
|
|
91
95
|
const roles = [
|
|
92
96
|
{
|
|
93
|
-
code:
|
|
94
|
-
name:
|
|
95
|
-
description:
|
|
97
|
+
code: "dev",
|
|
98
|
+
name: "开发者角色",
|
|
99
|
+
description: "拥有所有菜单和接口权限的开发者角色",
|
|
96
100
|
menus: menuIds,
|
|
97
101
|
apis: apiIds,
|
|
98
102
|
sort: 0
|
|
99
103
|
},
|
|
100
104
|
{
|
|
101
|
-
code:
|
|
102
|
-
name:
|
|
103
|
-
description:
|
|
104
|
-
menus:
|
|
105
|
-
apis:
|
|
105
|
+
code: "user",
|
|
106
|
+
name: "用户角色",
|
|
107
|
+
description: "普通用户角色",
|
|
108
|
+
menus: [],
|
|
109
|
+
apis: [],
|
|
106
110
|
sort: 1
|
|
107
111
|
},
|
|
108
112
|
{
|
|
109
|
-
code:
|
|
110
|
-
name:
|
|
111
|
-
description:
|
|
112
|
-
menus:
|
|
113
|
-
apis:
|
|
113
|
+
code: "admin",
|
|
114
|
+
name: "管理员角色",
|
|
115
|
+
description: "管理员角色",
|
|
116
|
+
menus: [],
|
|
117
|
+
apis: [],
|
|
114
118
|
sort: 2
|
|
115
119
|
},
|
|
116
120
|
{
|
|
117
|
-
code:
|
|
118
|
-
name:
|
|
119
|
-
description:
|
|
120
|
-
menus:
|
|
121
|
-
apis:
|
|
121
|
+
code: "guest",
|
|
122
|
+
name: "访客角色",
|
|
123
|
+
description: "访客角色",
|
|
124
|
+
menus: [],
|
|
125
|
+
apis: [],
|
|
122
126
|
sort: 3
|
|
123
127
|
}
|
|
124
128
|
];
|
|
@@ -127,18 +131,23 @@ export async function syncDevCommand(options: SyncDevOptions = {}): Promise<void
|
|
|
127
131
|
let devRole = null;
|
|
128
132
|
for (const roleConfig of roles) {
|
|
129
133
|
const existingRole = await helper.getOne({
|
|
130
|
-
table:
|
|
134
|
+
table: "addon_admin_role",
|
|
131
135
|
where: { code: roleConfig.code }
|
|
132
136
|
});
|
|
133
137
|
|
|
134
138
|
if (existingRole) {
|
|
135
139
|
// 检查字段是否有变化
|
|
136
|
-
const
|
|
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;
|
|
137
146
|
|
|
138
147
|
if (hasChanges) {
|
|
139
148
|
// 更新现有角色
|
|
140
149
|
await helper.updData({
|
|
141
|
-
table:
|
|
150
|
+
table: "addon_admin_role",
|
|
142
151
|
where: { code: roleConfig.code },
|
|
143
152
|
data: {
|
|
144
153
|
name: roleConfig.name,
|
|
@@ -149,71 +158,71 @@ export async function syncDevCommand(options: SyncDevOptions = {}): Promise<void
|
|
|
149
158
|
}
|
|
150
159
|
});
|
|
151
160
|
}
|
|
152
|
-
if (roleConfig.code ===
|
|
161
|
+
if (roleConfig.code === "dev") {
|
|
153
162
|
devRole = existingRole;
|
|
154
163
|
}
|
|
155
164
|
} else {
|
|
156
165
|
// 创建新角色
|
|
157
166
|
const roleId = await helper.insData({
|
|
158
|
-
table:
|
|
167
|
+
table: "addon_admin_role",
|
|
159
168
|
data: roleConfig
|
|
160
169
|
});
|
|
161
|
-
if (roleConfig.code ===
|
|
170
|
+
if (roleConfig.code === "dev") {
|
|
162
171
|
devRole = { id: roleId };
|
|
163
172
|
}
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
if (!devRole) {
|
|
168
|
-
Logger.error(
|
|
177
|
+
Logger.error("dev 角色不存在,无法创建开发者账号");
|
|
169
178
|
return;
|
|
170
179
|
}
|
|
171
180
|
|
|
172
181
|
// 先对密码进行 SHA-256 + 盐值 哈希(模拟前端加密),再用 bcrypt 存储
|
|
173
|
-
const sha256Hashed = Cipher.sha256(beflyConfig.devPassword +
|
|
182
|
+
const sha256Hashed = Cipher.sha256(beflyConfig.devPassword + "befly");
|
|
174
183
|
const hashed = await Cipher.hashPassword(sha256Hashed);
|
|
175
184
|
|
|
176
185
|
// 准备开发管理员数据
|
|
177
186
|
const devData = {
|
|
178
|
-
nickname:
|
|
187
|
+
nickname: "开发者",
|
|
179
188
|
email: beflyConfig.devEmail,
|
|
180
|
-
username:
|
|
189
|
+
username: "dev",
|
|
181
190
|
password: hashed,
|
|
182
|
-
roleCode:
|
|
183
|
-
roleType:
|
|
191
|
+
roleCode: "dev",
|
|
192
|
+
roleType: "admin"
|
|
184
193
|
};
|
|
185
194
|
|
|
186
195
|
// 查询现有账号
|
|
187
196
|
const existing = await helper.getOne({
|
|
188
|
-
table:
|
|
197
|
+
table: "addon_admin_admin",
|
|
189
198
|
where: { email: beflyConfig.devEmail }
|
|
190
199
|
});
|
|
191
200
|
|
|
192
201
|
if (existing) {
|
|
193
202
|
// 更新现有账号
|
|
194
203
|
await helper.updData({
|
|
195
|
-
table:
|
|
204
|
+
table: "addon_admin_admin",
|
|
196
205
|
where: { email: beflyConfig.devEmail },
|
|
197
206
|
data: devData
|
|
198
207
|
});
|
|
199
208
|
} else {
|
|
200
209
|
// 插入新账号
|
|
201
210
|
await helper.insData({
|
|
202
|
-
table:
|
|
211
|
+
table: "addon_admin_admin",
|
|
203
212
|
data: devData
|
|
204
213
|
});
|
|
205
214
|
}
|
|
206
215
|
|
|
207
|
-
//
|
|
216
|
+
// 重建角色接口权限缓存到 Redis(极简方案:覆盖更新)
|
|
217
|
+
// 说明:syncDev 会修改角色 apis,需同步刷新对应角色权限缓存
|
|
208
218
|
try {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
await cacheHelper.cacheRolePermissions();
|
|
219
|
+
const cacheHelper = new CacheHelper({ db: helper, redis: redisHelper } as any);
|
|
220
|
+
await cacheHelper.rebuildRoleApiPermissions();
|
|
212
221
|
} catch (error: any) {
|
|
213
|
-
|
|
222
|
+
Logger.warn({ err: error }, "[SyncDev] 重建角色接口权限缓存失败");
|
|
214
223
|
}
|
|
215
224
|
} catch (error: any) {
|
|
216
|
-
Logger.error({ err: error },
|
|
225
|
+
Logger.error({ err: error }, "同步开发者管理员失败");
|
|
217
226
|
throw error;
|
|
218
227
|
} finally {
|
|
219
228
|
await Connect.disconnect();
|