befly 3.73.0 → 3.74.0

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/index.js CHANGED
@@ -55,7 +55,7 @@ function prefixMenuPaths(menus, prefix) {
55
55
  });
56
56
  }
57
57
 
58
- async function ensureSyncPrerequisites(ctx) {
58
+ async function syncReady(ctx) {
59
59
  const missingCtxKeys = ["ctx.redis", "ctx.mysql", "ctx.cache"].filter((key) => !ctx[key.slice(4)]);
60
60
  if (missingCtxKeys.length > 0) {
61
61
  throw new Error(`启动失败:${missingCtxKeys.join("、")} 未初始化`, {
@@ -88,6 +88,7 @@ async function ensureSyncPrerequisites(ctx) {
88
88
  }
89
89
 
90
90
  export async function createBefly(config = {}, menus = []) {
91
+ const mergeStartTime = Bun.nanoseconds();
91
92
  const mergedConfig = deepMerge(beflyConfig, config);
92
93
  const mergedMenus = deepMerge(prefixMenuPaths(beflyMenus, "core"), menus);
93
94
 
@@ -95,15 +96,35 @@ export async function createBefly(config = {}, menus = []) {
95
96
  runtimeEnv: mergedConfig.runMode,
96
97
  ...mergedConfig.logger
97
98
  });
99
+ Logger.info(`启动 合并配置 耗时 ${calcPerfTime(mergeStartTime)}`);
98
100
 
101
+ let stageStartTime = Bun.nanoseconds();
99
102
  const configHasError = await checkConfig(mergedConfig);
103
+ Logger.info(`启动 检查配置 耗时 ${calcPerfTime(stageStartTime)}`);
104
+
105
+ stageStartTime = Bun.nanoseconds();
100
106
  const { apis, tables, plugins, hooks } = await scanSources();
107
+ Logger.info(`启动 扫描源码 耗时 ${calcPerfTime(stageStartTime)}`);
101
108
 
109
+ stageStartTime = Bun.nanoseconds();
102
110
  const apiHasError = await checkApi(apis);
111
+ Logger.info(`启动 检查接口 耗时 ${calcPerfTime(stageStartTime)}`);
112
+
113
+ stageStartTime = Bun.nanoseconds();
103
114
  const tableHasError = await checkTable(tables);
115
+ Logger.info(`启动 检查表 耗时 ${calcPerfTime(stageStartTime)}`);
116
+
117
+ stageStartTime = Bun.nanoseconds();
104
118
  const pluginHasError = await checkPlugin(plugins);
119
+ Logger.info(`启动 检查插件 耗时 ${calcPerfTime(stageStartTime)}`);
120
+
121
+ stageStartTime = Bun.nanoseconds();
105
122
  const hookHasError = await checkHook(hooks);
123
+ Logger.info(`启动 检查钩子 耗时 ${calcPerfTime(stageStartTime)}`);
124
+
125
+ stageStartTime = Bun.nanoseconds();
106
126
  const menuHasError = await checkMenu(mergedMenus);
127
+ Logger.info(`启动 检查菜单 耗时 ${calcPerfTime(stageStartTime)}`);
107
128
 
108
129
  if (configHasError || apiHasError || tableHasError || pluginHasError || hookHasError || menuHasError) {
109
130
  throw new Error("检查失败:存在配置/结构问题", {
@@ -167,24 +188,46 @@ export class Befly {
167
188
 
168
189
  // 启动期建立基础连接(SQL + Redis)
169
190
  // 说明:连接职责收敛到启动期单点;插件只消费已连接实例(Connect.getSql/getRedis)。
191
+ let stageStartTime = Bun.nanoseconds();
170
192
  await Connect.connectRedis(this.context.config.redis);
193
+ Logger.info(`启动 连接 Redis 耗时 ${calcPerfTime(stageStartTime)}`);
194
+
195
+ stageStartTime = Bun.nanoseconds();
171
196
  await Connect.connectMysql(this.context.config.mysql);
197
+ Logger.info(`启动 连接 Mysql 耗时 ${calcPerfTime(stageStartTime)}`);
172
198
 
173
199
  // 加载插件
174
200
  for (const item of this.plugins.toSorted((a, b) => a.order - b.order)) {
201
+ const pluginStartTime = Bun.nanoseconds();
175
202
  this.context[item.fileName] = await item.handler(this.context);
203
+ Logger.info(`启动 插件 ${item.fileName} 耗时 ${calcPerfTime(pluginStartTime)}`);
176
204
  }
177
- await ensureSyncPrerequisites(this.context);
205
+
206
+ stageStartTime = Bun.nanoseconds();
207
+ await syncReady(this.context);
208
+ Logger.info(`启动 同步就绪 耗时 ${calcPerfTime(stageStartTime)}`);
178
209
 
179
210
  // 自动同步(PM2 cluster:主进程执行,其它进程等待同步完成)
180
211
  if (isPrimaryProcess()) {
212
+ stageStartTime = Bun.nanoseconds();
181
213
  await syncApi(this.context, this.apis);
214
+ Logger.info(`启动 同步接口 耗时 ${calcPerfTime(stageStartTime)}`);
215
+
216
+ stageStartTime = Bun.nanoseconds();
182
217
  await syncMenu(this.context, this.menus);
218
+ Logger.info(`启动 同步菜单 耗时 ${calcPerfTime(stageStartTime)}`);
219
+
220
+ stageStartTime = Bun.nanoseconds();
183
221
  await syncDev(this.context);
222
+ Logger.info(`启动 同步开发账号 耗时 ${calcPerfTime(stageStartTime)}`);
223
+
224
+ stageStartTime = Bun.nanoseconds();
184
225
  await syncCache(this.context);
226
+ Logger.info(`启动 同步缓存 耗时 ${calcPerfTime(stageStartTime)}`);
185
227
  }
186
228
 
187
229
  // 加载钩子
230
+ stageStartTime = Bun.nanoseconds();
188
231
  this.hooks = this.hooks.toSorted((a, b) => a.order - b.order);
189
232
 
190
233
  // 加载所有 API
@@ -193,7 +236,9 @@ export class Befly {
193
236
  // 启动 HTTP服务器
194
237
  const apiFetch = apiHandler(this.apis, this.hooks, this.context);
195
238
  const staticFetch = staticHandler(this.context.config.cors, this.context.config.upload);
239
+ Logger.info(`启动 装配接口 耗时 ${calcPerfTime(stageStartTime)}`);
196
240
 
241
+ stageStartTime = Bun.nanoseconds();
197
242
  const server = Bun.serve({
198
243
  port: this.context.config.appPort || 3000,
199
244
  hostname: this.context.config.appHost || "0.0.0.0",
@@ -230,6 +275,7 @@ export class Befly {
230
275
  return Response.json({ code: 1, msg: "内部服务器错误" }, { status: 200 });
231
276
  }
232
277
  });
278
+ Logger.info(`启动 监听服务 耗时 ${calcPerfTime(stageStartTime)}`);
233
279
 
234
280
  const finalStartupTime = calcPerfTime(serverStartTime);
235
281
 
package/lib/connect.js CHANGED
@@ -88,7 +88,6 @@ export class Connect {
88
88
  });
89
89
 
90
90
  await this.mysqlClient`SELECT 1`;
91
- Logger.info(`Mysql 连接成功 (${config.hostname})`);
92
91
  } catch (error) {
93
92
  await this.handleConnectError("mysqlClient", "Mysql", "mysql", config.hostname, error);
94
93
  }
@@ -101,11 +100,6 @@ export class Connect {
101
100
  static async connectRedis(config) {
102
101
  try {
103
102
  this.redisClient = new RedisClient(buildRedisUrl(config));
104
- // Called when successfully connected to Redis server
105
- this.redisClient.onconnect = () => {
106
- Logger.info(`Redis 连接成功 (${config.hostname})`);
107
- };
108
-
109
103
  // Called when disconnected from Redis server
110
104
  this.redisClient.onclose = (error) => {
111
105
  if (error) {
package/lib/dbHelper.js CHANGED
@@ -1052,20 +1052,11 @@ class DbHelper {
1052
1052
  }
1053
1053
 
1054
1054
  async trans(callback) {
1055
- const abortMark = "__beflyTransAbort";
1056
-
1057
1055
  if (this.isTransaction) {
1058
- const result = await callback(this);
1059
- if (result?.code !== undefined && result.code !== 0) {
1060
- const abortError = new Error("TRANSACTION_ABORT", {
1061
- cause: null,
1062
- code: "runtime"
1063
- });
1064
- abortError[abortMark] = true;
1065
- abortError.payload = result;
1066
- throw abortError;
1067
- }
1068
- return result;
1056
+ throw new Error("不支持嵌套事务", {
1057
+ cause: null,
1058
+ code: "policy"
1059
+ });
1069
1060
  }
1070
1061
 
1071
1062
  if (typeof this.sql?.begin !== "function") {
@@ -1075,34 +1066,17 @@ class DbHelper {
1075
1066
  });
1076
1067
  }
1077
1068
 
1078
- try {
1079
- return await this.sql.begin(async (tx) => {
1080
- const trans = new this.constructor({
1081
- redis: this.redis,
1082
- dbName: this.dbName,
1083
- sql: tx,
1084
- isTransaction: true,
1085
- beflyMode: this.beflyMode,
1086
- tables: this.tables
1087
- });
1088
- const result = await callback(trans);
1089
- if (result?.code !== undefined && result.code !== 0) {
1090
- const abortError = new Error("TRANSACTION_ABORT", {
1091
- cause: null,
1092
- code: "runtime"
1093
- });
1094
- abortError[abortMark] = true;
1095
- abortError.payload = result;
1096
- throw abortError;
1097
- }
1098
- return result;
1069
+ return await this.sql.begin(async (tx) => {
1070
+ const trans = new this.constructor({
1071
+ redis: this.redis,
1072
+ dbName: this.dbName,
1073
+ sql: tx,
1074
+ isTransaction: true,
1075
+ beflyMode: this.beflyMode,
1076
+ tables: this.tables
1099
1077
  });
1100
- } catch (error) {
1101
- if (error && error[abortMark] === true) {
1102
- return error.payload;
1103
- }
1104
- throw error;
1105
- }
1078
+ return await callback(trans);
1079
+ });
1106
1080
  }
1107
1081
  }
1108
1082
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.73.0",
3
+ "version": "3.74.0",
4
4
  "gitHead": "49c39d36695036e85fc64083cc43c1652fff96cb",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
package/plugins/tool.js CHANGED
@@ -47,6 +47,21 @@ export function No(msg, data = null, other = {}) {
47
47
  return out;
48
48
  }
49
49
 
50
+ /**
51
+ * 业务失败并抛出错误
52
+ *
53
+ * 仅用于事务内需要回滚的业务失败;抛出后由路由统一转换为 { code: 1 } 响应。
54
+ * @param msg - 消息
55
+ * @param data - 数据(可选)
56
+ * @param other - 其他字段(可选)
57
+ */
58
+ export function Fail(msg, data = null, other = {}) {
59
+ const error = new Error(msg);
60
+ error.isBeflyResponse = true;
61
+ error.payload = No(msg, data, other);
62
+ throw error;
63
+ }
64
+
50
65
  /**
51
66
  * 统一响应函数
52
67
  *
@@ -109,6 +124,7 @@ export default {
109
124
  return {
110
125
  Yes: Yes,
111
126
  No: No,
127
+ Fail: Fail,
112
128
  Raw: Raw
113
129
  };
114
130
  }
package/router/api.js CHANGED
@@ -158,6 +158,10 @@ export function apiHandler(apis, hooks, context) {
158
158
  // 7. 返回响应(自动处理 response/result/日志)
159
159
  return FinalResponse(ctx);
160
160
  } catch (err) {
161
+ if (err && err.isBeflyResponse === true) {
162
+ ctx.result = err.payload;
163
+ return FinalResponse(ctx);
164
+ }
161
165
  // 全局错误处理
162
166
  Logger.error("请求错误", err, {
163
167
  path: ctx.apiPath,