befly 3.74.2 → 3.75.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.
Files changed (65) hide show
  1. package/apis/dashboard/systemResources.js +3 -1
  2. package/apis/dict/_dict.js +1 -1
  3. package/apis/role/_role.js +2 -2
  4. package/apis/tongJi/dailyStats.js +2 -2
  5. package/apis/tongJi/dailyStatsDistribution.js +3 -3
  6. package/apis/tongJi/errorList.js +2 -2
  7. package/apis/tongJi/errorStats.js +6 -6
  8. package/checks/api.js +11 -6
  9. package/checks/items.js +56 -0
  10. package/checks/menu.js +1 -1
  11. package/checks/table.js +4 -5
  12. package/configs/beflyConfig.json +5 -10
  13. package/configs/constConfig.js +44 -3
  14. package/hooks/auth.js +3 -2
  15. package/hooks/parser.js +15 -4
  16. package/hooks/permission.js +3 -2
  17. package/hooks/rateLimit.js +16 -3
  18. package/hooks/validator.js +2 -1
  19. package/index.js +53 -24
  20. package/lib/cacheHelper.js +83 -229
  21. package/lib/connect.js +3 -13
  22. package/lib/dbHelper.js +57 -142
  23. package/lib/dbParse.js +65 -248
  24. package/lib/dbUtil.js +19 -63
  25. package/lib/logger.js +45 -22
  26. package/lib/redisHelper.js +186 -420
  27. package/lib/smtpText.js +7 -18
  28. package/lib/sqlBuilder.js +22 -51
  29. package/lib/xmlParse.js +15 -59
  30. package/package.json +1 -1
  31. package/plugins/cache.js +2 -3
  32. package/plugins/config.js +3 -1
  33. package/plugins/cron.js +2 -2
  34. package/plugins/email.js +3 -1
  35. package/plugins/logger.js +2 -2
  36. package/plugins/mysql.js +5 -10
  37. package/plugins/redis.js +4 -11
  38. package/plugins/tool.js +3 -3
  39. package/plugins/xmlParse.js +3 -1
  40. package/router/api.js +2 -6
  41. package/router/static.js +9 -10
  42. package/schemas/config.js +4 -4
  43. package/scripts/syncDb/context.js +4 -7
  44. package/scripts/syncDb/diff.js +2 -1
  45. package/scripts/syncDb/index.js +2 -6
  46. package/sync/api.js +7 -8
  47. package/sync/cache.js +3 -1
  48. package/sync/dev.js +28 -65
  49. package/sync/menu.js +5 -6
  50. package/sync/syncUtil.js +25 -0
  51. package/utils/calcPerfTime.js +2 -3
  52. package/utils/crypto.js +0 -40
  53. package/utils/deepMerge.js +2 -6
  54. package/utils/error.js +64 -0
  55. package/utils/fieldClear.js +13 -56
  56. package/utils/importDefault.js +11 -12
  57. package/utils/is.js +5 -182
  58. package/utils/loggerUtils.js +3 -1
  59. package/utils/response.js +12 -8
  60. package/utils/scanFiles.js +2 -53
  61. package/utils/scanSources.js +9 -0
  62. package/utils/util.js +25 -222
  63. package/checks/hook.js +0 -39
  64. package/checks/plugin.js +0 -39
  65. package/utils/processInfo.js +0 -39
package/lib/smtpText.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Buffer } from "node:buffer";
2
2
 
3
+ import { createError } from "../utils/error.js";
4
+
3
5
  function encodeBase64(value) {
4
6
  return Buffer.from(String(value || ""), "utf8").toString("base64");
5
7
  }
@@ -98,7 +100,7 @@ function createResponseReader() {
98
100
 
99
101
  const responseLines = [];
100
102
  let consumedCount = 0;
101
- let code = 0;
103
+ let code;
102
104
  for (const line of completeLines) {
103
105
  consumedCount = consumedCount + 1;
104
106
  responseLines.push(line);
@@ -143,8 +145,7 @@ function createResponseReader() {
143
145
  close: function (error) {
144
146
  closedError =
145
147
  error ||
146
- new Error("SMTP 连接已关闭", {
147
- cause: null,
148
+ createError("SMTP 连接已关闭", {
148
149
  code: "runtime",
149
150
  subsystem: "smtp",
150
151
  operation: "readResponse"
@@ -171,8 +172,7 @@ async function readResponseWithTimeout(reader, timeout) {
171
172
  new Promise(function (_resolve, reject) {
172
173
  timer = setTimeout(function () {
173
174
  reject(
174
- new Error("SMTP 响应超时", {
175
- cause: null,
175
+ createError("SMTP 响应超时", {
176
176
  code: "runtime",
177
177
  subsystem: "smtp",
178
178
  operation: "readResponse"
@@ -189,13 +189,7 @@ async function readResponseWithTimeout(reader, timeout) {
189
189
  async function expectResponse(reader, expectedCodes, commandName, timeout) {
190
190
  const response = await readResponseWithTimeout(reader, timeout);
191
191
  if (!expectedCodes.includes(response.code)) {
192
- throw new Error(`SMTP ${commandName} 响应异常: ${response.text}`, {
193
- cause: null,
194
- code: "runtime",
195
- subsystem: "smtp",
196
- operation: commandName,
197
- response: response.text
198
- });
192
+ throw createError(`SMTP ${commandName} 响应异常: ${response.text}`, { code: "runtime", subsystem: "smtp", operation: commandName, response: response.text });
199
193
  }
200
194
  return response;
201
195
  }
@@ -207,12 +201,7 @@ function writeCommand(socket, command) {
207
201
  export async function sendSmtpTextMail(config, options) {
208
202
  const mail = createSmtpTextMessage(config, options);
209
203
  if (mail.recipients.length === 0) {
210
- throw new Error("邮件收件人不能为空", {
211
- cause: null,
212
- code: "validation",
213
- subsystem: "smtp",
214
- operation: "sendSmtpTextMail"
215
- });
204
+ throw createError("邮件收件人不能为空", { code: "validation", subsystem: "smtp", operation: "sendSmtpTextMail" });
216
205
  }
217
206
 
218
207
  const reader = createResponseReader();
package/lib/sqlBuilder.js CHANGED
@@ -1,6 +1,27 @@
1
1
  /**
2
- * SQL 构造器 - JavaScript 版本
3
2
  * 提供链式 API 构建 SQL 查询
3
+ *
4
+ * ==================== where 节点树协议 ====================
5
+ *
6
+ * 本类消费由 lib/dbParse.js 产出的 where 节点树(唯一协议来源),
7
+ * 新增节点类型/操作符时必须同步修改 dbParse 的产出端与这里的编译端。
8
+ *
9
+ * 节点结构(三态):
10
+ * 1. 条件组:{ type: "group", join: "AND" | "OR", items: Node[] }
11
+ * - items 为空数组时编译为空串(不生成 WHERE 片段)
12
+ * - join 为 OR 时,组内每个子条件单独加括号
13
+ * 2. 操作节点:{ type: "op", field: string, operator: string, value: any }
14
+ * - operator 支持(缺省按等值处理):$not $in $notIn $like $leftLike $rightLike $notLike
15
+ * $gt $gte $lt $lte $between $notBetween $null $notNull
16
+ * - $between/$notBetween 的 value 为 [min, max]
17
+ * - 缺省操作符:value === null 编译为 IS NULL,否则 =
18
+ * - field 已由 dbParse 完成合法性校验,这里仅做标识符转义
19
+ * 3. 原始片段:{ type: "raw", sql: string, params?: any[] }
20
+ * - 由 whereRaw() 手动追加,或 dbParse 在特殊场景产出
21
+ *
22
+ * 边界约定:
23
+ * - 空字符串 like/leftLike/rightLike 由 dbParse 过滤,不进入节点树
24
+ * - 本类不校验节点合法性(信任上层),仅负责编译
4
25
  */
5
26
 
6
27
  import { isNonEmptyString } from "../utils/is.js";
@@ -26,22 +47,6 @@ export class SqlBuilder {
26
47
  };
27
48
  }
28
49
 
29
- /**
30
- * 重置构建器状态
31
- */
32
- reset() {
33
- this.queryModel = {
34
- select: [],
35
- from: null,
36
- where: { type: "group", join: "AND", items: [] },
37
- joins: [],
38
- orderBy: [],
39
- limit: null,
40
- offset: null
41
- };
42
- return this;
43
- }
44
-
45
50
  compileOperatorNode(node) {
46
51
  const escapedField = escapeField(node.field, this.quoteIdentifier);
47
52
 
@@ -177,14 +182,6 @@ export class SqlBuilder {
177
182
  return this;
178
183
  }
179
184
 
180
- /**
181
- * FROM 原始表达式(不做转义)
182
- */
183
- fromRaw(tableExpr) {
184
- this.queryModel.from = { type: "raw", value: tableExpr.trim() };
185
- return this;
186
- }
187
-
188
185
  /**
189
186
  * WHERE 条件
190
187
  */
@@ -381,32 +378,6 @@ export class SqlBuilder {
381
378
  };
382
379
  }
383
380
 
384
- /**
385
- * 构建 COUNT 查询
386
- */
387
- toCountSql() {
388
- const params = [];
389
- let fromSql = this.queryModel.from.value;
390
- if (this.queryModel.from.type !== "raw") {
391
- fromSql = escapeTable(this.queryModel.from.value, this.quoteIdentifier);
392
- }
393
- let sql = `SELECT COUNT(*) as total FROM ${fromSql}`;
394
-
395
- if (this.queryModel.joins.length > 0) {
396
- sql += ` ${this.queryModel.joins.map((join) => `${join.type.toUpperCase()} JOIN ${escapeTable(join.table, this.quoteIdentifier)} ON ${join.on}`).join(" ")}`;
397
- }
398
-
399
- const whereResult = this.compileWhereNode(this.queryModel.where);
400
- if (whereResult.sql) {
401
- sql += ` WHERE ${whereResult.sql}`;
402
- for (const param of whereResult.params) {
403
- params.push(param);
404
- }
405
- }
406
-
407
- return { sql: sql, params: params };
408
- }
409
-
410
381
  static toDeleteInSql(options) {
411
382
  if (options.ids.length === 0) {
412
383
  return { sql: "", params: [] };
package/lib/xmlParse.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createError } from "#befly/utils/error.js";
1
2
  import { isString } from "#befly/utils/is.js";
2
3
 
3
4
  function decodeXmlText(value) {
@@ -44,13 +45,8 @@ function skipIgnoredMarkup(rawXml, startIndex) {
44
45
 
45
46
  if (rawXml.startsWith("<?", index)) {
46
47
  const declarationEnd = rawXml.indexOf("?>", index);
47
- if (declarationEnd < 0) {
48
- throw new Error("XML 声明未闭合", {
49
- cause: null,
50
- code: "validation",
51
- subsystem: "xml",
52
- operation: "skipIgnoredMarkup"
53
- });
48
+ if (declarationEnd === -1) {
49
+ throw createError("XML 声明未闭合", { code: "validation", subsystem: "xml", operation: "skipIgnoredMarkup" });
54
50
  }
55
51
  index = declarationEnd + 2;
56
52
  continue;
@@ -58,13 +54,8 @@ function skipIgnoredMarkup(rawXml, startIndex) {
58
54
 
59
55
  if (rawXml.startsWith("<!--", index)) {
60
56
  const commentEnd = rawXml.indexOf("-->", index);
61
- if (commentEnd < 0) {
62
- throw new Error("XML 注释未闭合", {
63
- cause: null,
64
- code: "validation",
65
- subsystem: "xml",
66
- operation: "skipIgnoredMarkup"
67
- });
57
+ if (commentEnd === -1) {
58
+ throw createError("XML 注释未闭合", { code: "validation", subsystem: "xml", operation: "skipIgnoredMarkup" });
68
59
  }
69
60
  index = commentEnd + 3;
70
61
  continue;
@@ -78,25 +69,15 @@ function skipIgnoredMarkup(rawXml, startIndex) {
78
69
 
79
70
  function parseNode(rawXml, startIndex) {
80
71
  const openEnd = rawXml.indexOf(">", startIndex);
81
- if (openEnd < 0) {
82
- throw new Error("XML 开始标签不完整", {
83
- cause: null,
84
- code: "validation",
85
- subsystem: "xml",
86
- operation: "parseNode"
87
- });
72
+ if (openEnd === -1) {
73
+ throw createError("XML 开始标签不完整", { code: "validation", subsystem: "xml", operation: "parseNode" });
88
74
  }
89
75
 
90
76
  const openContent = rawXml.slice(startIndex + 1, openEnd).trim();
91
77
  const isSelfClosing = openContent.endsWith("/");
92
78
  const tagName = (isSelfClosing ? openContent.slice(0, -1).trim() : openContent).split(/\s+/)[0];
93
79
  if (!tagName || tagName.startsWith("/")) {
94
- throw new Error("XML 标签格式不正确", {
95
- cause: null,
96
- code: "validation",
97
- subsystem: "xml",
98
- operation: "parseNode"
99
- });
80
+ throw createError("XML 标签格式不正确", { code: "validation", subsystem: "xml", operation: "parseNode" });
100
81
  }
101
82
  if (isSelfClosing) {
102
83
  return {
@@ -116,13 +97,8 @@ function parseNode(rawXml, startIndex) {
116
97
 
117
98
  if (rawXml.startsWith("<![CDATA[", index)) {
118
99
  const cdataEnd = rawXml.indexOf("]]>", index);
119
- if (cdataEnd < 0) {
120
- throw new Error("XML CDATA 未闭合", {
121
- cause: null,
122
- code: "validation",
123
- subsystem: "xml",
124
- operation: "parseNode"
125
- });
100
+ if (cdataEnd === -1) {
101
+ throw createError("XML CDATA 未闭合", { code: "validation", subsystem: "xml", operation: "parseNode" });
126
102
  }
127
103
  text += rawXml.slice(index + 9, cdataEnd);
128
104
  index = cdataEnd + 3;
@@ -147,45 +123,25 @@ function parseNode(rawXml, startIndex) {
147
123
  }
148
124
 
149
125
  const nextTagIndex = rawXml.indexOf("<", index);
150
- if (nextTagIndex < 0) {
151
- throw new Error("XML 结束标签缺失", {
152
- cause: null,
153
- code: "validation",
154
- subsystem: "xml",
155
- operation: "parseNode"
156
- });
126
+ if (nextTagIndex === -1) {
127
+ throw createError("XML 结束标签缺失", { code: "validation", subsystem: "xml", operation: "parseNode" });
157
128
  }
158
129
  text += rawXml.slice(index, nextTagIndex);
159
130
  index = nextTagIndex;
160
131
  }
161
132
 
162
- throw new Error("XML 标签未闭合", {
163
- cause: null,
164
- code: "validation",
165
- subsystem: "xml",
166
- operation: "parseNode"
167
- });
133
+ throw createError("XML 标签未闭合", { code: "validation", subsystem: "xml", operation: "parseNode" });
168
134
  }
169
135
 
170
136
  export function xmlParse(value) {
171
137
  if (!isString(value) || value.length < 1) {
172
- throw new Error("xmlParse 输入必须是非空字符串", {
173
- cause: null,
174
- code: "validation",
175
- subsystem: "xml",
176
- operation: "xmlParse"
177
- });
138
+ throw createError("xmlParse 输入必须是非空字符串", { code: "validation", subsystem: "xml", operation: "xmlParse" });
178
139
  }
179
140
 
180
141
  const normalized = value.trim();
181
142
  const startIndex = skipIgnoredMarkup(normalized, 0);
182
143
  if (normalized[startIndex] !== "<") {
183
- throw new Error("XML 根节点缺失", {
184
- cause: null,
185
- code: "validation",
186
- subsystem: "xml",
187
- operation: "xmlParse"
188
- });
144
+ throw createError("XML 根节点缺失", { code: "validation", subsystem: "xml", operation: "xmlParse" });
189
145
  }
190
146
 
191
147
  const node = parseNode(normalized, startIndex);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.74.2",
3
+ "version": "3.75.0",
4
4
  "gitHead": "49c39d36695036e85fc64083cc43c1652fff96cb",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
package/plugins/cache.js CHANGED
@@ -1,15 +1,14 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
- * 缓存插件 - JavaScript 版本
3
3
  * 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
4
4
  */
5
-
6
5
  import { CacheHelper } from "../lib/cacheHelper.js";
7
6
 
8
7
  /**
9
8
  * 缓存插件
10
9
  */
11
10
  export default {
12
- order: 6,
11
+ order: PLUGIN_ORDER.CACHE,
13
12
  handler: async function (befly) {
14
13
  return new CacheHelper({ mysql: befly.mysql, redis: befly.redis });
15
14
  }
package/plugins/config.js CHANGED
@@ -1,10 +1,12 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
2
+
1
3
  /**
2
4
  * 配置插件
3
5
  * 提供访问项目配置的能力
4
6
  */
5
7
 
6
8
  export default {
7
- order: 1,
9
+ order: PLUGIN_ORDER.CONFIG,
8
10
  handler: (befly) => {
9
11
  return befly.config;
10
12
  }
package/plugins/cron.js CHANGED
@@ -1,8 +1,8 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
3
  * 定时任务插件
3
4
  * 基于 Bun.cron 提供进程内定时任务能力。
4
5
  */
5
-
6
6
  import { Logger } from "../lib/logger.js";
7
7
  import { isPrimaryProcess } from "../utils/is.js";
8
8
 
@@ -84,7 +84,7 @@ export function stopAll() {
84
84
  }
85
85
 
86
86
  export default {
87
- order: 8,
87
+ order: PLUGIN_ORDER.CRON,
88
88
  handler: async function (befly) {
89
89
  return {
90
90
  register: (name, schedule, task) => register(befly, name, schedule, task),
package/plugins/email.js CHANGED
@@ -2,8 +2,10 @@ import { Logger } from "#befly/lib/logger.js";
2
2
  import { sendSmtpTextMail } from "#befly/lib/smtpText.js";
3
3
  import { hasEmailConfig } from "#befly/utils/email.js";
4
4
 
5
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
6
+
5
7
  export default {
6
- order: 7,
8
+ order: PLUGIN_ORDER.EMAIL,
7
9
  handler: async function (befly) {
8
10
  const config = befly?.config?.email || {};
9
11
  const enabled = hasEmailConfig(config);
package/plugins/logger.js CHANGED
@@ -1,15 +1,15 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
3
  * 日志插件
3
4
  * 提供全局日志功能
4
5
  */
5
-
6
6
  import { Logger } from "../lib/logger.js";
7
7
 
8
8
  /**
9
9
  * 日志插件
10
10
  */
11
11
  export default {
12
- order: 2,
12
+ order: PLUGIN_ORDER.LOGGER,
13
13
  handler: async function () {
14
14
  // 日志已在 createBefly 中按 runMode 初始化,这里只注入 Logger 实例
15
15
  return Logger;
package/plugins/mysql.js CHANGED
@@ -1,17 +1,17 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
3
  * 数据库插件
3
4
  * 初始化数据库连接和 SQL 管理器
4
5
  */
5
-
6
6
  import { Connect } from "../lib/connect.js";
7
7
  import { DbHelper } from "../lib/dbHelper.js";
8
- import { Logger } from "../lib/logger.js";
8
+ import { createError } from "../utils/error.js";
9
9
 
10
10
  /**
11
11
  * 数据库插件
12
12
  */
13
13
  export default {
14
- order: 5,
14
+ order: PLUGIN_ORDER.MYSQL,
15
15
  handler: async function (befly) {
16
16
  try {
17
17
  // 创建数据库管理器实例
@@ -20,18 +20,13 @@ export default {
20
20
  dbName: befly.config?.mysql?.database,
21
21
  sql: Connect.getMysql(),
22
22
  beflyMode: befly.config?.mysql?.beflyMode,
23
+ queryTimeout: befly.config?.mysql?.queryTimeout,
23
24
  tables: befly.tables
24
25
  });
25
26
 
26
27
  return dbManager;
27
28
  } catch (error) {
28
- Logger.error("数据库初始化失败", error, { runMode: befly.config?.runMode });
29
- throw new Error("数据库初始化失败", {
30
- cause: error,
31
- code: "runtime",
32
- subsystem: "db",
33
- operation: "init"
34
- });
29
+ throw createError("数据库初始化失败", { cause: error, code: "runtime", subsystem: "db", operation: "init" });
35
30
  }
36
31
  }
37
32
  };
package/plugins/redis.js CHANGED
@@ -1,19 +1,18 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
3
  * Redis 插件
3
4
  * 初始化 Redis 连接和助手工具
4
5
  */
5
-
6
6
  import { Connect } from "../lib/connect.js";
7
- import { Logger } from "../lib/logger.js";
8
7
  import { RedisHelper } from "../lib/redisHelper.js";
8
+ import { createError } from "../utils/error.js";
9
9
 
10
10
  /**
11
11
  * Redis 插件
12
12
  */
13
13
  export default {
14
- order: 4,
14
+ order: PLUGIN_ORDER.REDIS,
15
15
  handler: async function (befly) {
16
- const env = befly.config?.runMode;
17
16
  const redisPrefix = befly.config?.redis?.prefix;
18
17
  try {
19
18
  // 启动期已建立 Redis 连接;这里仅校验连接存在
@@ -22,13 +21,7 @@ export default {
22
21
  // 返回 RedisHelper 实例
23
22
  return new RedisHelper(redisPrefix);
24
23
  } catch (error) {
25
- Logger.error("Redis 初始化失败", error, { env: env });
26
- throw new Error("Redis 初始化失败", {
27
- cause: error,
28
- code: "runtime",
29
- subsystem: "redis",
30
- operation: "init"
31
- });
24
+ throw createError("Redis 初始化失败", { cause: error, code: "runtime", subsystem: "redis", operation: "init" });
32
25
  }
33
26
  }
34
27
  };
package/plugins/tool.js CHANGED
@@ -1,8 +1,8 @@
1
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
1
2
  /**
2
3
  * 工具插件
3
4
  * 提供常用的工具函数
4
5
  */
5
-
6
6
  import { isNumber, isString } from "../utils/is.js";
7
7
 
8
8
  /**
@@ -94,7 +94,7 @@ export function Raw(ctx, data, options = {}) {
94
94
  } else {
95
95
  // JSON 序列化(对象/数组/原始值均可)
96
96
  body = JSON.stringify(data);
97
- finalContentType = finalContentType || "application/json";
97
+ finalContentType ||= "application/json";
98
98
  }
99
99
 
100
100
  // 合并响应头
@@ -119,7 +119,7 @@ export function Raw(ctx, data, options = {}) {
119
119
  }
120
120
 
121
121
  export default {
122
- order: 3,
122
+ order: PLUGIN_ORDER.TOOL,
123
123
  handler: () => {
124
124
  return {
125
125
  Yes: Yes,
@@ -1,7 +1,9 @@
1
1
  import { xmlParse } from "#befly/lib/xmlParse.js";
2
2
 
3
+ import { PLUGIN_ORDER } from "../configs/constConfig.js";
4
+
3
5
  export default {
4
- order: 4,
6
+ order: PLUGIN_ORDER.XML_PARSE,
5
7
  handler: () => {
6
8
  return xmlParse;
7
9
  }
package/router/api.js CHANGED
@@ -8,6 +8,7 @@ import picomatch from "picomatch";
8
8
  import { Logger } from "../lib/logger.js";
9
9
  // 相对导入
10
10
  import { setCorsOptions } from "../utils/cors.js";
11
+ import { createError } from "../utils/error.js";
11
12
  import { getClientIp } from "../utils/getClientIp.js";
12
13
  import { ErrorResponse, FinalResponse } from "../utils/response.js";
13
14
  import { genShortId } from "../utils/util.js";
@@ -17,12 +18,7 @@ function createExcludeApisLogMatchers(excludeApisLog) {
17
18
  try {
18
19
  return picomatch(pattern);
19
20
  } catch (error) {
20
- throw new Error(`excludeApisLog glob 无效: ${pattern}`, {
21
- cause: error,
22
- code: "validation",
23
- subsystem: "config",
24
- operation: "excludeApisLog"
25
- });
21
+ throw createError(`excludeApisLog glob 无效: ${pattern}`, { cause: error, code: "validation", subsystem: "config", operation: "excludeApisLog" });
26
22
  }
27
23
  });
28
24
  }
package/router/static.js CHANGED
@@ -76,17 +76,16 @@ export function staticHandler(corsConfig, uploadConfig) {
76
76
  return new Response(file, {
77
77
  headers: headers
78
78
  });
79
- } else {
80
- return Response.json(
81
- {
82
- code: 1,
83
- msg: "文件未找到"
84
- },
85
- {
86
- headers: corsHeaders
87
- }
88
- );
89
79
  }
80
+ return Response.json(
81
+ {
82
+ code: 1,
83
+ msg: "文件未找到"
84
+ },
85
+ {
86
+ headers: corsHeaders
87
+ }
88
+ );
90
89
  } catch (error) {
91
90
  Logger.error("静态文件处理失败", error);
92
91
 
package/schemas/config.js CHANGED
@@ -1,12 +1,9 @@
1
- import { RUN_MODE_VALUES } from "../configs/constConfig.js";
2
-
3
1
  const noTrimString = { type: "string", noTrim: true };
4
2
  const boolInt = { type: "boolInt" };
5
3
  const port = { type: "number", integer: true, min: 1, max: 65535 };
6
4
 
7
5
  export const configSchema = {
8
6
  root: {
9
- runMode: { type: "values", values: RUN_MODE_VALUES },
10
7
  appName: noTrimString,
11
8
  appPort: port,
12
9
  appHost: noTrimString,
@@ -37,7 +34,8 @@ export const configSchema = {
37
34
  beflyMode: { type: "values", values: ["manual", "auto"], optional: true },
38
35
  idleTimeout: { type: "number", min: 1, optional: true },
39
36
  maxLifetime: { type: "number", min: 0, optional: true },
40
- connectionTimeout: { type: "number", min: 1, optional: true }
37
+ connectionTimeout: { type: "number", min: 1, optional: true },
38
+ queryTimeout: { type: "number", min: 1, optional: true }
41
39
  },
42
40
  redis: {
43
41
  hostname: noTrimString,
@@ -58,6 +56,8 @@ export const configSchema = {
58
56
  },
59
57
  rateLimit: {
60
58
  enable: boolInt,
59
+ // 限流服务不可用时是否放行(1 放行 / 0 拒绝),默认 1
60
+ failOpen: boolInt,
61
61
  defaultLimit: { type: "number", integer: true, min: 1 },
62
62
  defaultWindow: { type: "number", integer: true, min: 1 },
63
63
  key: noTrimString,
@@ -1,9 +1,11 @@
1
1
  import { mkdir } from "node:fs/promises";
2
2
  import { basename, resolve, join } from "node:path";
3
3
 
4
+ import { BEFLY_TABLE_PREFIX } from "#befly/configs/constConfig.js";
4
5
  import { Connect } from "#befly/lib/connect.js";
5
6
  import { DbHelper } from "#befly/lib/dbHelper.js";
6
7
  import { Logger } from "#befly/lib/logger.js";
8
+ import { createError } from "#befly/utils/error.js";
7
9
  import { importDefault } from "#befly/utils/importDefault.js";
8
10
  import { isNonEmptyString, isPlainObject } from "#befly/utils/is.js";
9
11
  import { camelCase } from "#befly/utils/util.js";
@@ -35,12 +37,7 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
35
37
  printSyncDbProcessLog(`表定义目录=${tablesDir}`);
36
38
 
37
39
  if (!isPlainObject(mysqlConfig)) {
38
- throw new Error("syncDb 缺少 mysql 配置", {
39
- cause: null,
40
- code: "validation",
41
- subsystem: "scripts",
42
- operation: "syncDb"
43
- });
40
+ throw createError("syncDb 缺少 mysql 配置", { code: "validation", subsystem: "scripts", operation: "syncDb" });
44
41
  }
45
42
 
46
43
  printSyncDbProcessLog(`同步模式=${mysqlConfig.beflyMode === "manual" ? "手动" : "自动"}`);
@@ -61,7 +58,7 @@ export async function prepareSyncDbBaseContext(mysqlConfig) {
61
58
  const skippedBeflyTables = new Set();
62
59
  for (const row of dbColumns) {
63
60
  const tableName = String(row?.tableName || "");
64
- if (isNonEmptyString(tableName) && tableName.toLowerCase().startsWith("befly_")) {
61
+ if (isNonEmptyString(tableName) && tableName.toLowerCase().startsWith(BEFLY_TABLE_PREFIX)) {
65
62
  skippedBeflyTables.add(tableName);
66
63
  }
67
64
  }
@@ -1,5 +1,6 @@
1
1
  import { join } from "node:path";
2
2
 
3
+ import { BEFLY_TABLE_PREFIX } from "#befly/configs/constConfig.js";
3
4
  import { isNonEmptyString, isPlainObject } from "#befly/utils/is.js";
4
5
  import { camelCase, snakeCase } from "#befly/utils/util.js";
5
6
 
@@ -67,7 +68,7 @@ export function groupSyncDbColumns(rows) {
67
68
  if (!isNonEmptyString(tableName)) {
68
69
  continue;
69
70
  }
70
- if (tableName.toLowerCase().startsWith("befly_")) {
71
+ if (tableName.toLowerCase().startsWith(BEFLY_TABLE_PREFIX)) {
71
72
  continue;
72
73
  }
73
74
 
@@ -2,6 +2,7 @@ import { join, resolve } from "node:path";
2
2
 
3
3
  import { Connect } from "#befly/lib/connect.js";
4
4
  import { Logger } from "#befly/lib/logger.js";
5
+ import { createError } from "#befly/utils/error.js";
5
6
 
6
7
  import { prepareSyncDbBaseContext } from "./context.js";
7
8
  import { applySyncDbDiff } from "./diff.js";
@@ -34,12 +35,7 @@ export async function syncDb(mysqlConfig) {
34
35
  reportPath: writtenReportPath
35
36
  };
36
37
  } catch (error) {
37
- throw new Error("执行表定义同步失败", {
38
- cause: error,
39
- code: "runtime",
40
- subsystem: "scripts",
41
- operation: "syncDb"
42
- });
38
+ throw createError("执行表定义同步失败", { cause: error, code: "runtime", subsystem: "scripts", operation: "syncDb" });
43
39
  } finally {
44
40
  await Connect.disconnect();
45
41
  await Logger.flush();