befly 3.74.3 → 3.75.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/apis/dashboard/systemResources.js +3 -1
- package/apis/dict/_dict.js +1 -1
- package/apis/role/_role.js +2 -2
- package/apis/tongJi/dailyStats.js +2 -2
- package/apis/tongJi/dailyStatsDistribution.js +3 -3
- package/apis/tongJi/errorList.js +2 -2
- package/apis/tongJi/errorStats.js +6 -6
- package/checks/api.js +14 -8
- package/checks/config.js +4 -3
- package/checks/items.js +65 -0
- package/checks/menu.js +4 -3
- package/checks/table.js +7 -7
- package/configs/beflyConfig.json +5 -10
- package/configs/constConfig.js +44 -3
- package/hooks/auth.js +3 -2
- package/hooks/parser.js +15 -4
- package/hooks/permission.js +3 -2
- package/hooks/rateLimit.js +16 -3
- package/hooks/validator.js +2 -1
- package/index.js +72 -28
- package/lib/cacheHelper.js +83 -229
- package/lib/connect.js +3 -13
- package/lib/dbHelper.js +57 -142
- package/lib/dbParse.js +65 -248
- package/lib/dbUtil.js +19 -63
- package/lib/logger.js +45 -22
- package/lib/redisHelper.js +186 -420
- package/lib/smtpText.js +7 -18
- package/lib/sqlBuilder.js +22 -51
- package/lib/xmlParse.js +15 -59
- package/package.json +1 -1
- package/plugins/cache.js +2 -3
- package/plugins/config.js +3 -1
- package/plugins/cron.js +2 -2
- package/plugins/email.js +3 -1
- package/plugins/logger.js +2 -2
- package/plugins/mysql.js +5 -10
- package/plugins/redis.js +4 -11
- package/plugins/tool.js +3 -3
- package/plugins/xmlParse.js +3 -1
- package/router/api.js +2 -6
- package/router/static.js +9 -10
- package/schemas/config.js +4 -4
- package/scripts/syncDb/context.js +4 -7
- package/scripts/syncDb/diff.js +2 -1
- package/scripts/syncDb/index.js +2 -6
- package/sync/api.js +7 -8
- package/sync/cache.js +3 -1
- package/sync/dev.js +28 -65
- package/sync/menu.js +5 -6
- package/sync/syncUtil.js +25 -0
- package/utils/calcPerfTime.js +2 -3
- package/utils/crypto.js +0 -40
- package/utils/deepMerge.js +2 -6
- package/utils/error.js +64 -0
- package/utils/fieldClear.js +13 -56
- package/utils/importDefault.js +11 -12
- package/utils/is.js +3 -180
- package/utils/loggerUtils.js +3 -1
- package/utils/response.js +12 -8
- package/utils/scanFiles.js +2 -53
- package/utils/scanSources.js +9 -0
- package/utils/util.js +25 -222
- package/checks/hook.js +0 -39
- package/checks/plugin.js +0 -39
- package/utils/processInfo.js +0 -39
package/index.js
CHANGED
|
@@ -6,16 +6,17 @@
|
|
|
6
6
|
// 检查
|
|
7
7
|
import { checkApi } from "#befly/checks/api.js";
|
|
8
8
|
import { checkConfig } from "#befly/checks/config.js";
|
|
9
|
-
import { checkHook } from "#befly/checks/
|
|
9
|
+
import { checkHook, checkPlugin } from "#befly/checks/items.js";
|
|
10
10
|
import { checkMenu } from "#befly/checks/menu.js";
|
|
11
|
-
import { checkPlugin } from "#befly/checks/plugin.js";
|
|
12
11
|
import { checkTable } from "#befly/checks/table.js";
|
|
13
12
|
// 配置
|
|
14
13
|
import beflyConfig from "#befly/configs/beflyConfig.json";
|
|
15
14
|
import beflyMenus from "#befly/configs/beflyMenus.json";
|
|
15
|
+
import { BEFLY_ADMIN_TABLE, BEFLY_API_TABLE, BEFLY_MENU_TABLE, BEFLY_ROLE_TABLE } from "#befly/configs/constConfig.js";
|
|
16
16
|
// ========== 相对导入(项目内部文件) ==========
|
|
17
17
|
// 基础设施
|
|
18
18
|
import { Connect } from "#befly/lib/connect.js";
|
|
19
|
+
// oxlint-disable-next-line unicorn/prefer-export-from -- Logger 同时被本文件大量使用,不能合并为 re-export
|
|
19
20
|
import { Logger } from "#befly/lib/logger.js";
|
|
20
21
|
// 路由处理
|
|
21
22
|
import { apiHandler } from "#befly/router/api.js";
|
|
@@ -27,14 +28,20 @@ import { syncDev } from "#befly/sync/dev.js";
|
|
|
27
28
|
import { syncMenu } from "#befly/sync/menu.js";
|
|
28
29
|
// 工具
|
|
29
30
|
import { calcPerfTime } from "#befly/utils/calcPerfTime.js";
|
|
31
|
+
import { formatYmdHms } from "#befly/utils/datetime.js";
|
|
30
32
|
import { deepMerge } from "#befly/utils/deepMerge.js";
|
|
33
|
+
import { createError } from "#befly/utils/error.js";
|
|
31
34
|
import { isPrimaryProcess } from "#befly/utils/is.js";
|
|
32
35
|
import { scanSources } from "#befly/utils/scanSources.js";
|
|
36
|
+
import { getRunMode, waitFor } from "#befly/utils/util.js";
|
|
33
37
|
|
|
34
38
|
export { syncDb } from "#befly/scripts/syncDb/index.js";
|
|
35
39
|
export { xmlParse } from "#befly/lib/xmlParse.js";
|
|
36
40
|
export { Logger };
|
|
37
41
|
|
|
42
|
+
// 主进程同步完成的 Redis 就绪标记(非主进程等待此标记后再对外服务)
|
|
43
|
+
const SYNC_READY_KEY = "befly:syncReady";
|
|
44
|
+
|
|
38
45
|
function prefixMenuPaths(menus, prefix) {
|
|
39
46
|
return menus.map((menu) => {
|
|
40
47
|
const nextMenu = {
|
|
@@ -58,8 +65,7 @@ function prefixMenuPaths(menus, prefix) {
|
|
|
58
65
|
async function syncReady(ctx) {
|
|
59
66
|
const missingCtxKeys = ["ctx.redis", "ctx.mysql", "ctx.cache"].filter((key) => !ctx[key.slice(4)]);
|
|
60
67
|
if (missingCtxKeys.length > 0) {
|
|
61
|
-
throw
|
|
62
|
-
cause: null,
|
|
68
|
+
throw createError(`启动失败:${missingCtxKeys.join("、")} 未初始化`, {
|
|
63
69
|
code: "runtime",
|
|
64
70
|
subsystem: "sync",
|
|
65
71
|
operation: "ctxCheck",
|
|
@@ -67,7 +73,7 @@ async function syncReady(ctx) {
|
|
|
67
73
|
});
|
|
68
74
|
}
|
|
69
75
|
|
|
70
|
-
const requiredTables = [
|
|
76
|
+
const requiredTables = [BEFLY_API_TABLE, BEFLY_MENU_TABLE, BEFLY_ADMIN_TABLE, BEFLY_ROLE_TABLE];
|
|
71
77
|
const missingTables = [];
|
|
72
78
|
|
|
73
79
|
for (const table of requiredTables) {
|
|
@@ -77,8 +83,7 @@ async function syncReady(ctx) {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
if (missingTables.length > 0) {
|
|
80
|
-
throw
|
|
81
|
-
cause: null,
|
|
86
|
+
throw createError(`同步依赖表缺失: ${missingTables.join("、")}`, {
|
|
82
87
|
code: "runtime",
|
|
83
88
|
subsystem: "sync",
|
|
84
89
|
operation: "tableExists",
|
|
@@ -93,13 +98,13 @@ export async function createBefly(config = {}, menus = []) {
|
|
|
93
98
|
const mergedMenus = deepMerge(prefixMenuPaths(beflyMenus, "core"), menus);
|
|
94
99
|
|
|
95
100
|
Logger.configure({
|
|
96
|
-
runtimeEnv:
|
|
101
|
+
runtimeEnv: getRunMode(),
|
|
97
102
|
...mergedConfig.logger
|
|
98
103
|
});
|
|
99
104
|
Logger.info(`启动 合并配置 耗时 ${calcPerfTime(mergeStartTime)}`);
|
|
100
105
|
|
|
101
106
|
let stageStartTime = Bun.nanoseconds();
|
|
102
|
-
const
|
|
107
|
+
const configErrors = await checkConfig(mergedConfig);
|
|
103
108
|
Logger.info(`启动 检查配置 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
104
109
|
|
|
105
110
|
stageStartTime = Bun.nanoseconds();
|
|
@@ -107,34 +112,48 @@ export async function createBefly(config = {}, menus = []) {
|
|
|
107
112
|
Logger.info(`启动 扫描源码 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
108
113
|
|
|
109
114
|
stageStartTime = Bun.nanoseconds();
|
|
110
|
-
const
|
|
115
|
+
const apiErrors = await checkApi(apis);
|
|
111
116
|
Logger.info(`启动 检查接口 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
112
117
|
|
|
113
118
|
stageStartTime = Bun.nanoseconds();
|
|
114
|
-
const
|
|
119
|
+
const tableErrors = await checkTable(tables);
|
|
115
120
|
Logger.info(`启动 检查表 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
116
121
|
|
|
117
122
|
stageStartTime = Bun.nanoseconds();
|
|
118
|
-
const
|
|
123
|
+
const pluginErrors = await checkPlugin(plugins);
|
|
119
124
|
Logger.info(`启动 检查插件 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
120
125
|
|
|
121
126
|
stageStartTime = Bun.nanoseconds();
|
|
122
|
-
const
|
|
127
|
+
const hookErrors = await checkHook(hooks);
|
|
123
128
|
Logger.info(`启动 检查钩子 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
124
129
|
|
|
125
130
|
stageStartTime = Bun.nanoseconds();
|
|
126
|
-
const
|
|
131
|
+
const menuErrors = await checkMenu(mergedMenus);
|
|
127
132
|
Logger.info(`启动 检查菜单 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
128
133
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
// 汇总各检查明细,报错可直接定位到具体文件/路径/配置/字段
|
|
135
|
+
const failedChecks = [
|
|
136
|
+
{ check: "配置", errors: configErrors },
|
|
137
|
+
{ check: "接口", errors: apiErrors },
|
|
138
|
+
{ check: "表结构", errors: tableErrors },
|
|
139
|
+
{ check: "插件", errors: pluginErrors },
|
|
140
|
+
{ check: "钩子", errors: hookErrors },
|
|
141
|
+
{ check: "菜单", errors: menuErrors }
|
|
142
|
+
].filter((entry) => entry.errors.length > 0);
|
|
143
|
+
|
|
144
|
+
if (failedChecks.length > 0) {
|
|
145
|
+
throw createError("检查失败:存在配置/结构问题", {
|
|
132
146
|
code: "policy",
|
|
133
147
|
subsystem: "checks",
|
|
134
|
-
operation: "checkAll"
|
|
148
|
+
operation: "checkAll",
|
|
149
|
+
errors: failedChecks
|
|
135
150
|
});
|
|
136
151
|
}
|
|
137
152
|
|
|
153
|
+
// 运行模式以环境为准(NODE_ENV,线上部署注入 production;本地开发默认 development),
|
|
154
|
+
// 覆盖配置值,保证 befly.config.runMode 与运行时判断一致
|
|
155
|
+
mergedConfig.runMode = getRunMode();
|
|
156
|
+
|
|
138
157
|
return new Befly({
|
|
139
158
|
config: mergedConfig,
|
|
140
159
|
tables: tables,
|
|
@@ -168,12 +187,7 @@ export class Befly {
|
|
|
168
187
|
return;
|
|
169
188
|
}
|
|
170
189
|
|
|
171
|
-
throw
|
|
172
|
-
cause: null,
|
|
173
|
-
code: "policy",
|
|
174
|
-
subsystem: "start",
|
|
175
|
-
operation: "factoryGuard"
|
|
176
|
-
});
|
|
190
|
+
throw createError("请使用 createBefly(...) 创建实例后再调用 start", { code: "policy", subsystem: "start", operation: "factoryGuard" });
|
|
177
191
|
}
|
|
178
192
|
|
|
179
193
|
/**
|
|
@@ -207,7 +221,7 @@ export class Befly {
|
|
|
207
221
|
await syncReady(this.context);
|
|
208
222
|
Logger.info(`启动 同步就绪 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
209
223
|
|
|
210
|
-
// 自动同步(
|
|
224
|
+
// 自动同步(bm2 多实例:主进程执行同步并写就绪标记,其它进程等待同步完成后再对外服务)
|
|
211
225
|
if (isPrimaryProcess()) {
|
|
212
226
|
stageStartTime = Bun.nanoseconds();
|
|
213
227
|
await syncApi(this.context, this.apis);
|
|
@@ -224,6 +238,20 @@ export class Befly {
|
|
|
224
238
|
stageStartTime = Bun.nanoseconds();
|
|
225
239
|
await syncCache(this.context);
|
|
226
240
|
Logger.info(`启动 同步缓存 耗时 ${calcPerfTime(stageStartTime)}`);
|
|
241
|
+
|
|
242
|
+
// 同步完成:写入就绪标记(TTL 防崩溃残留),非主进程据此放行
|
|
243
|
+
await this.context.redis.setString(SYNC_READY_KEY, String(Date.now()), 300);
|
|
244
|
+
} else {
|
|
245
|
+
// 非主进程:在监听端口前等待主进程本次同步完成(时间戳判断,同机时钟一致)
|
|
246
|
+
const startAt = Date.now();
|
|
247
|
+
await waitFor({
|
|
248
|
+
label: "主进程同步完成",
|
|
249
|
+
check: async () => {
|
|
250
|
+
const ready = await this.context.redis.getString(SYNC_READY_KEY);
|
|
251
|
+
return ready !== null && Number(ready) > startAt;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
Logger.info("启动 等待主进程同步完成 完成");
|
|
227
255
|
}
|
|
228
256
|
|
|
229
257
|
// 加载钩子
|
|
@@ -241,7 +269,7 @@ export class Befly {
|
|
|
241
269
|
stageStartTime = Bun.nanoseconds();
|
|
242
270
|
const server = Bun.serve({
|
|
243
271
|
port: this.context.config.appPort || 3000,
|
|
244
|
-
hostname: this.context.config.appHost || "
|
|
272
|
+
hostname: this.context.config.appHost || "127.0.0.1",
|
|
245
273
|
// 开发模式下启用详细错误信息
|
|
246
274
|
development: this.context.config.runMode === "development",
|
|
247
275
|
// 空闲连接超时时间(秒),防止恶意连接占用资源
|
|
@@ -256,6 +284,22 @@ export class Befly {
|
|
|
256
284
|
return staticFetch(req);
|
|
257
285
|
}
|
|
258
286
|
|
|
287
|
+
// 根路径返回服务基本信息
|
|
288
|
+
if (url.pathname === "/") {
|
|
289
|
+
return Response.json(
|
|
290
|
+
{
|
|
291
|
+
code: 0,
|
|
292
|
+
msg: "success",
|
|
293
|
+
data: {
|
|
294
|
+
name: this.context.config.appName,
|
|
295
|
+
mode: this.context.config.runMode,
|
|
296
|
+
time: formatYmdHms(Date.now())
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{ status: 200 }
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
259
303
|
return Response.json({ code: 1, msg: "路径不存在" }, { status: 200 });
|
|
260
304
|
},
|
|
261
305
|
error: (error) => {
|
|
@@ -302,7 +346,7 @@ export class Befly {
|
|
|
302
346
|
// - 作为库代码,也不应该强行终止宿主进程
|
|
303
347
|
|
|
304
348
|
// 注意:测试要求 start() 失败时必须 Logger.error 一次,所以这里始终调用 error。
|
|
305
|
-
Logger.error("项目启动失败", error
|
|
349
|
+
Logger.error("项目启动失败", error);
|
|
306
350
|
|
|
307
351
|
// 尽力把错误日志落盘/输出后再把异常抛给上层。
|
|
308
352
|
try {
|
|
@@ -312,7 +356,7 @@ export class Befly {
|
|
|
312
356
|
// ignore
|
|
313
357
|
}
|
|
314
358
|
|
|
315
|
-
throw
|
|
359
|
+
throw createError("运行时错误", {
|
|
316
360
|
cause: error,
|
|
317
361
|
code: error?.code || "runtime",
|
|
318
362
|
subsystem: "start",
|