befly 3.15.19 → 3.15.21
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/dist/befly.js +393 -39
- package/dist/befly.min.js +14 -13
- package/dist/checks/checkApi.js +10 -1
- package/dist/checks/checkHook.js +10 -1
- package/dist/checks/checkPlugin.js +10 -1
- package/dist/checks/checkTable.js +10 -1
- package/dist/index.js +53 -1
- package/dist/lib/cacheHelper.js +11 -1
- package/dist/lib/connect.js +49 -9
- package/dist/lib/dbHelper.js +15 -1
- package/dist/lib/logger.js +26 -6
- package/dist/lib/redisHelper.js +11 -1
- package/dist/loader/loadApis.js +13 -1
- package/dist/loader/loadHooks.js +4 -1
- package/dist/loader/loadPlugins.js +15 -2
- package/dist/plugins/cache.js +3 -2
- package/dist/plugins/db.js +13 -3
- package/dist/plugins/redis.js +11 -1
- package/dist/sync/syncApi.js +3 -2
- package/dist/sync/syncCache.js +2 -1
- package/dist/sync/syncMenu.js +4 -3
- package/dist/sync/syncTable.d.ts +1 -0
- package/dist/sync/syncTable.js +136 -1
- package/dist/types/coreError.d.ts +27 -0
- package/dist/types/coreError.js +35 -0
- package/package.json +2 -2
package/dist/befly.js
CHANGED
|
@@ -913,11 +913,29 @@ function buildLogLine(level, record) {
|
|
|
913
913
|
hostname: HOSTNAME
|
|
914
914
|
};
|
|
915
915
|
if (record && isPlainObject(record)) {
|
|
916
|
-
const out =
|
|
916
|
+
const out = {};
|
|
917
|
+
out["level"] = base["level"];
|
|
918
|
+
out["time"] = base["time"];
|
|
919
|
+
out["timeFormat"] = base["timeFormat"];
|
|
920
|
+
out["pid"] = base["pid"];
|
|
921
|
+
out["hostname"] = base["hostname"];
|
|
922
|
+
for (const key of Object.keys(record)) {
|
|
923
|
+
if (key === "level")
|
|
924
|
+
continue;
|
|
925
|
+
if (key === "time")
|
|
926
|
+
continue;
|
|
927
|
+
if (key === "timeFormat")
|
|
928
|
+
continue;
|
|
929
|
+
if (key === "pid")
|
|
930
|
+
continue;
|
|
931
|
+
if (key === "hostname")
|
|
932
|
+
continue;
|
|
933
|
+
out[key] = record[key];
|
|
934
|
+
}
|
|
917
935
|
if (record.msg !== undefined) {
|
|
918
|
-
out
|
|
919
|
-
} else if (out
|
|
920
|
-
out
|
|
936
|
+
out["msg"] = record.msg;
|
|
937
|
+
} else if (out["msg"] === undefined) {
|
|
938
|
+
out["msg"] = "";
|
|
921
939
|
}
|
|
922
940
|
return `${safeJsonStringify(out)}
|
|
923
941
|
`;
|
|
@@ -7727,6 +7745,38 @@ async function loadBeflyConfig(nodeEnv) {
|
|
|
7727
7745
|
|
|
7728
7746
|
// checks/checkApi.ts
|
|
7729
7747
|
init_logger();
|
|
7748
|
+
|
|
7749
|
+
// types/coreError.ts
|
|
7750
|
+
class CoreError extends Error {
|
|
7751
|
+
kind;
|
|
7752
|
+
code;
|
|
7753
|
+
meta;
|
|
7754
|
+
noLog;
|
|
7755
|
+
logged;
|
|
7756
|
+
cause;
|
|
7757
|
+
constructor(options) {
|
|
7758
|
+
super(options.message);
|
|
7759
|
+
this.name = "CoreError";
|
|
7760
|
+
this.kind = options.kind;
|
|
7761
|
+
this.code = typeof options.code === "string" && options.code.length > 0 ? options.code : null;
|
|
7762
|
+
this.meta = options.meta ? options.meta : null;
|
|
7763
|
+
this.noLog = options.noLog === true;
|
|
7764
|
+
this.logged = options.logged === true;
|
|
7765
|
+
this.cause = options.cause;
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7768
|
+
function isCoreError(error) {
|
|
7769
|
+
if (typeof error !== "object" || error === null)
|
|
7770
|
+
return false;
|
|
7771
|
+
const anyErr = error;
|
|
7772
|
+
if (anyErr.name !== "CoreError")
|
|
7773
|
+
return false;
|
|
7774
|
+
if (typeof anyErr.kind !== "string")
|
|
7775
|
+
return false;
|
|
7776
|
+
return true;
|
|
7777
|
+
}
|
|
7778
|
+
|
|
7779
|
+
// checks/checkApi.ts
|
|
7730
7780
|
init_util();
|
|
7731
7781
|
async function checkApi(apis) {
|
|
7732
7782
|
let hasError = false;
|
|
@@ -7831,7 +7881,15 @@ async function checkApi(apis) {
|
|
|
7831
7881
|
}
|
|
7832
7882
|
}
|
|
7833
7883
|
if (hasError) {
|
|
7834
|
-
throw new
|
|
7884
|
+
throw new CoreError({
|
|
7885
|
+
kind: "policy",
|
|
7886
|
+
message: "\u63A5\u53E3\u7ED3\u6784\u68C0\u67E5\u5931\u8D25",
|
|
7887
|
+
logged: true,
|
|
7888
|
+
meta: {
|
|
7889
|
+
subsystem: "checks",
|
|
7890
|
+
operation: "checkApi"
|
|
7891
|
+
}
|
|
7892
|
+
});
|
|
7835
7893
|
}
|
|
7836
7894
|
}
|
|
7837
7895
|
|
|
@@ -8067,7 +8125,15 @@ async function checkHook(hooks) {
|
|
|
8067
8125
|
}
|
|
8068
8126
|
}
|
|
8069
8127
|
if (hasError) {
|
|
8070
|
-
throw new
|
|
8128
|
+
throw new CoreError({
|
|
8129
|
+
kind: "policy",
|
|
8130
|
+
message: "\u94A9\u5B50\u7ED3\u6784\u68C0\u67E5\u5931\u8D25",
|
|
8131
|
+
logged: true,
|
|
8132
|
+
meta: {
|
|
8133
|
+
subsystem: "checks",
|
|
8134
|
+
operation: "checkHook"
|
|
8135
|
+
}
|
|
8136
|
+
});
|
|
8071
8137
|
}
|
|
8072
8138
|
}
|
|
8073
8139
|
|
|
@@ -8285,7 +8351,15 @@ async function checkPlugin(plugins) {
|
|
|
8285
8351
|
}
|
|
8286
8352
|
}
|
|
8287
8353
|
if (hasError) {
|
|
8288
|
-
throw new
|
|
8354
|
+
throw new CoreError({
|
|
8355
|
+
kind: "policy",
|
|
8356
|
+
message: "\u63D2\u4EF6\u7ED3\u6784\u68C0\u67E5\u5931\u8D25",
|
|
8357
|
+
logged: true,
|
|
8358
|
+
meta: {
|
|
8359
|
+
subsystem: "checks",
|
|
8360
|
+
operation: "checkPlugin"
|
|
8361
|
+
}
|
|
8362
|
+
});
|
|
8289
8363
|
}
|
|
8290
8364
|
}
|
|
8291
8365
|
|
|
@@ -8614,13 +8688,21 @@ async function checkTable(tables, config2) {
|
|
|
8614
8688
|
}
|
|
8615
8689
|
}
|
|
8616
8690
|
if (hasError) {
|
|
8617
|
-
throw new
|
|
8691
|
+
throw new CoreError({
|
|
8692
|
+
kind: "policy",
|
|
8693
|
+
message: "\u8868\u7ED3\u6784\u68C0\u67E5\u5931\u8D25",
|
|
8694
|
+
logged: true,
|
|
8695
|
+
meta: {
|
|
8696
|
+
subsystem: "checks",
|
|
8697
|
+
operation: "checkTable"
|
|
8698
|
+
}
|
|
8699
|
+
});
|
|
8618
8700
|
}
|
|
8619
8701
|
}
|
|
8620
8702
|
|
|
8621
8703
|
// lib/connect.ts
|
|
8622
|
-
init_logger();
|
|
8623
8704
|
var {SQL, RedisClient } = globalThis.Bun;
|
|
8705
|
+
init_logger();
|
|
8624
8706
|
|
|
8625
8707
|
class Connect {
|
|
8626
8708
|
static sqlClient = null;
|
|
@@ -8638,16 +8720,16 @@ class Connect {
|
|
|
8638
8720
|
const password = config2.password === undefined ? "" : typeof config2.password === "string" ? config2.password : "";
|
|
8639
8721
|
const database = typeof config2.database === "string" ? config2.database.trim() : "";
|
|
8640
8722
|
if (!host) {
|
|
8641
|
-
throw new
|
|
8723
|
+
throw new CoreError({ message: "\u6570\u636E\u5E93\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1Adb.host \u7F3A\u5931", kind: "validation" });
|
|
8642
8724
|
}
|
|
8643
8725
|
if (!Number.isFinite(port) || port < 1 || port > 65535) {
|
|
8644
|
-
throw new
|
|
8726
|
+
throw new CoreError({ message: `\u6570\u636E\u5E93\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1Adb.port \u975E\u6CD5\uFF08\u5F53\u524D\u503C\uFF1A${String(config2.port)}\uFF09`, kind: "validation" });
|
|
8645
8727
|
}
|
|
8646
8728
|
if (!username) {
|
|
8647
|
-
throw new
|
|
8729
|
+
throw new CoreError({ message: "\u6570\u636E\u5E93\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1Adb.username \u7F3A\u5931", kind: "validation" });
|
|
8648
8730
|
}
|
|
8649
8731
|
if (!database) {
|
|
8650
|
-
throw new
|
|
8732
|
+
throw new CoreError({ message: "\u6570\u636E\u5E93\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1Adb.database \u7F3A\u5931", kind: "validation" });
|
|
8651
8733
|
}
|
|
8652
8734
|
const user = encodeURIComponent(username);
|
|
8653
8735
|
const pass = encodeURIComponent(password);
|
|
@@ -8666,10 +8748,10 @@ class Connect {
|
|
|
8666
8748
|
const majorText = versionText.split(".")[0];
|
|
8667
8749
|
const major = Number(majorText);
|
|
8668
8750
|
if (!Number.isFinite(major)) {
|
|
8669
|
-
throw new
|
|
8751
|
+
throw new CoreError({ message: `\u65E0\u6CD5\u89E3\u6790 MySQL \u7248\u672C\u4FE1\u606F: ${versionText}`, kind: "runtime", meta: { subsystem: "sql", operation: "version" } });
|
|
8670
8752
|
}
|
|
8671
8753
|
if (major < 8) {
|
|
8672
|
-
throw new
|
|
8754
|
+
throw new CoreError({ message: `\u4EC5\u652F\u6301 MySQL 8.0+\uFF0C\u5F53\u524D\u7248\u672C\uFF1A${versionText}`, kind: "policy", meta: { subsystem: "sql", operation: "version" } });
|
|
8673
8755
|
}
|
|
8674
8756
|
this.mysqlVersionText = versionText;
|
|
8675
8757
|
this.mysqlVersionMajor = major;
|
|
@@ -8690,7 +8772,21 @@ class Connect {
|
|
|
8690
8772
|
try {
|
|
8691
8773
|
await sql?.close();
|
|
8692
8774
|
} catch {}
|
|
8693
|
-
|
|
8775
|
+
if (isCoreError(error)) {
|
|
8776
|
+
error.logged = true;
|
|
8777
|
+
throw error;
|
|
8778
|
+
}
|
|
8779
|
+
const msg = `SQL \u8FDE\u63A5\u5931\u8D25: ${error && typeof error.message === "string" ? error.message : String(error)}`;
|
|
8780
|
+
throw new CoreError({
|
|
8781
|
+
message: msg,
|
|
8782
|
+
kind: "runtime",
|
|
8783
|
+
logged: true,
|
|
8784
|
+
cause: error,
|
|
8785
|
+
meta: {
|
|
8786
|
+
subsystem: "sql",
|
|
8787
|
+
operation: "connect"
|
|
8788
|
+
}
|
|
8789
|
+
});
|
|
8694
8790
|
}
|
|
8695
8791
|
}
|
|
8696
8792
|
static async disconnectSql() {
|
|
@@ -8741,7 +8837,17 @@ class Connect {
|
|
|
8741
8837
|
return redis;
|
|
8742
8838
|
} catch (error) {
|
|
8743
8839
|
Logger.error({ err: error, msg: "[Connect] Redis \u8FDE\u63A5\u5931\u8D25" });
|
|
8744
|
-
|
|
8840
|
+
const msg = `Redis \u8FDE\u63A5\u5931\u8D25: ${error && typeof error.message === "string" ? error.message : String(error)}`;
|
|
8841
|
+
throw new CoreError({
|
|
8842
|
+
message: msg,
|
|
8843
|
+
kind: "runtime",
|
|
8844
|
+
logged: true,
|
|
8845
|
+
cause: error,
|
|
8846
|
+
meta: {
|
|
8847
|
+
subsystem: "redis",
|
|
8848
|
+
operation: "connect"
|
|
8849
|
+
}
|
|
8850
|
+
});
|
|
8745
8851
|
}
|
|
8746
8852
|
}
|
|
8747
8853
|
static async disconnectRedis() {
|
|
@@ -8769,7 +8875,21 @@ class Connect {
|
|
|
8769
8875
|
const env = typeof process?.env?.NODE_ENV === "string" ? "development" : "";
|
|
8770
8876
|
Logger.error({ env, err: error, msg: "\u6570\u636E\u5E93\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25" });
|
|
8771
8877
|
await this.disconnect();
|
|
8772
|
-
|
|
8878
|
+
if (isCoreError(error)) {
|
|
8879
|
+
error.logged = true;
|
|
8880
|
+
throw error;
|
|
8881
|
+
}
|
|
8882
|
+
const msg = `\u6570\u636E\u5E93\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25: ${error && typeof error.message === "string" ? error.message : String(error)}`;
|
|
8883
|
+
throw new CoreError({
|
|
8884
|
+
message: msg,
|
|
8885
|
+
kind: "runtime",
|
|
8886
|
+
logged: true,
|
|
8887
|
+
cause: error,
|
|
8888
|
+
meta: {
|
|
8889
|
+
subsystem: "connect",
|
|
8890
|
+
operation: "connect"
|
|
8891
|
+
}
|
|
8892
|
+
});
|
|
8773
8893
|
}
|
|
8774
8894
|
}
|
|
8775
8895
|
static async disconnect() {
|
|
@@ -8863,7 +8983,18 @@ async function loadApis(apis) {
|
|
|
8863
8983
|
apisMap.set(path, route);
|
|
8864
8984
|
} catch (error) {
|
|
8865
8985
|
Logger.error({ err: error, api: api.relativePath, file: api.filePath, msg: "\u63A5\u53E3\u52A0\u8F7D\u5931\u8D25" });
|
|
8866
|
-
throw
|
|
8986
|
+
throw new CoreError({
|
|
8987
|
+
kind: "runtime",
|
|
8988
|
+
message: "\u63A5\u53E3\u52A0\u8F7D\u5931\u8D25",
|
|
8989
|
+
logged: true,
|
|
8990
|
+
cause: error,
|
|
8991
|
+
meta: {
|
|
8992
|
+
subsystem: "api",
|
|
8993
|
+
operation: "load",
|
|
8994
|
+
relativePath: api.relativePath,
|
|
8995
|
+
filePath: api.filePath
|
|
8996
|
+
}
|
|
8997
|
+
});
|
|
8867
8998
|
}
|
|
8868
8999
|
}
|
|
8869
9000
|
return apisMap;
|
|
@@ -8979,7 +9110,7 @@ async function loadHooks(hooks) {
|
|
|
8979
9110
|
});
|
|
8980
9111
|
const sortedHooks = sortModules(enabledHooks, { moduleLabel: "\u94A9\u5B50" });
|
|
8981
9112
|
if (sortedHooks === false) {
|
|
8982
|
-
throw new
|
|
9113
|
+
throw new CoreError({ message: "\u94A9\u5B50\u4F9D\u8D56\u5173\u7CFB\u9519\u8BEF", kind: "policy", logged: true });
|
|
8983
9114
|
}
|
|
8984
9115
|
for (const item of sortedHooks) {
|
|
8985
9116
|
const hookName = item.moduleName;
|
|
@@ -9017,7 +9148,7 @@ async function loadPlugins(plugins, context) {
|
|
|
9017
9148
|
});
|
|
9018
9149
|
const sortedPlugins = sortModules(enabledPlugins, { moduleLabel: "\u63D2\u4EF6" });
|
|
9019
9150
|
if (sortedPlugins === false) {
|
|
9020
|
-
throw new
|
|
9151
|
+
throw new CoreError({ message: "\u63D2\u4EF6\u4F9D\u8D56\u5173\u7CFB\u9519\u8BEF", kind: "policy", logged: true });
|
|
9021
9152
|
}
|
|
9022
9153
|
for (const item of sortedPlugins) {
|
|
9023
9154
|
const pluginName = item.moduleName;
|
|
@@ -9039,7 +9170,17 @@ async function loadPlugins(plugins, context) {
|
|
|
9039
9170
|
});
|
|
9040
9171
|
} catch (error) {
|
|
9041
9172
|
Logger.error({ err: error, plugin: pluginName, msg: "\u63D2\u4EF6\u521D\u59CB\u5316\u5931\u8D25" });
|
|
9042
|
-
throw
|
|
9173
|
+
throw new CoreError({
|
|
9174
|
+
kind: "runtime",
|
|
9175
|
+
message: `\u63D2\u4EF6\u521D\u59CB\u5316\u5931\u8D25: ${pluginName}`,
|
|
9176
|
+
logged: true,
|
|
9177
|
+
cause: error,
|
|
9178
|
+
meta: {
|
|
9179
|
+
subsystem: "plugin",
|
|
9180
|
+
operation: "init",
|
|
9181
|
+
plugin: pluginName
|
|
9182
|
+
}
|
|
9183
|
+
});
|
|
9043
9184
|
}
|
|
9044
9185
|
}
|
|
9045
9186
|
return pluginsMap;
|
|
@@ -9327,10 +9468,10 @@ var getApiParentPath = (apiPath) => {
|
|
|
9327
9468
|
async function syncApi(ctx, apis) {
|
|
9328
9469
|
const tableName = "addon_admin_api";
|
|
9329
9470
|
if (!ctx.db) {
|
|
9330
|
-
throw new
|
|
9471
|
+
throw new CoreError({ message: "\u540C\u6B65\u63A5\u53E3\uFF1Actx.db \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9331
9472
|
}
|
|
9332
9473
|
if (!ctx.cache) {
|
|
9333
|
-
throw new
|
|
9474
|
+
throw new CoreError({ message: "\u540C\u6B65\u63A5\u53E3\uFF1Actx.cache \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9334
9475
|
}
|
|
9335
9476
|
if (!(await ctx.db.tableExists(tableName)).data) {
|
|
9336
9477
|
Logger.debug(`${tableName} \u8868\u4E0D\u5B58\u5728`);
|
|
@@ -9439,7 +9580,7 @@ async function syncApi(ctx, apis) {
|
|
|
9439
9580
|
// sync/syncCache.ts
|
|
9440
9581
|
async function syncCache(ctx) {
|
|
9441
9582
|
if (!ctx.cache) {
|
|
9442
|
-
throw new
|
|
9583
|
+
throw new CoreError({ message: "\u540C\u6B65\u7F13\u5B58\uFF1Actx.cache \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9443
9584
|
}
|
|
9444
9585
|
await ctx.cache.cacheApis();
|
|
9445
9586
|
await ctx.cache.cacheMenus();
|
|
@@ -9827,13 +9968,13 @@ function flattenMenusToDefMap(mergedMenus) {
|
|
|
9827
9968
|
}
|
|
9828
9969
|
async function syncMenu(ctx, mergedMenus) {
|
|
9829
9970
|
if (!ctx.db) {
|
|
9830
|
-
throw new
|
|
9971
|
+
throw new CoreError({ message: "\u540C\u6B65\u83DC\u5355\uFF1Actx.db \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9831
9972
|
}
|
|
9832
9973
|
if (!ctx.cache) {
|
|
9833
|
-
throw new
|
|
9974
|
+
throw new CoreError({ message: "\u540C\u6B65\u83DC\u5355\uFF1Actx.cache \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9834
9975
|
}
|
|
9835
9976
|
if (!ctx.config) {
|
|
9836
|
-
throw new
|
|
9977
|
+
throw new CoreError({ message: "\u540C\u6B65\u83DC\u5355\uFF1Actx.config \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
9837
9978
|
}
|
|
9838
9979
|
if (!(await ctx.db.tableExists("addon_admin_menu")).data) {
|
|
9839
9980
|
Logger.debug(`addon_admin_menu \u8868\u4E0D\u5B58\u5728`);
|
|
@@ -10227,6 +10368,8 @@ class SyncTable {
|
|
|
10227
10368
|
throw new Error("\u540C\u6B65\u8868\uFF1A\u8BF7\u4F20\u5165\u591A\u4E2A\u8868\u5B9A\u4E49\u7EC4\u6210\u7684\u6570\u7EC4");
|
|
10228
10369
|
}
|
|
10229
10370
|
await SyncTable.ensureDbVersion(this.db);
|
|
10371
|
+
const tableTasks = [];
|
|
10372
|
+
const incompatibleTypeChanges = [];
|
|
10230
10373
|
for (const item of items) {
|
|
10231
10374
|
if (!item || item.type !== "table") {
|
|
10232
10375
|
continue;
|
|
@@ -10237,9 +10380,100 @@ class SyncTable {
|
|
|
10237
10380
|
SyncTable.normalizeFieldDefinitionInPlace(fieldDef);
|
|
10238
10381
|
}
|
|
10239
10382
|
const existsTable = await SyncTable.tableExists(this.db, this.dbName, tableName);
|
|
10383
|
+
const task = {
|
|
10384
|
+
item,
|
|
10385
|
+
tableName,
|
|
10386
|
+
tableFields,
|
|
10387
|
+
existsTable,
|
|
10388
|
+
existingColumns: null,
|
|
10389
|
+
existingIndexes: null,
|
|
10390
|
+
plan: null,
|
|
10391
|
+
planSummary: null,
|
|
10392
|
+
planDetails: null
|
|
10393
|
+
};
|
|
10394
|
+
if (existsTable) {
|
|
10395
|
+
const existingColumns = await SyncTable.getTableColumns(this.db, this.dbName, tableName);
|
|
10396
|
+
const existingIndexes = await SyncTable.getTableIndexes(this.db, this.dbName, tableName);
|
|
10397
|
+
const changes = SyncTable.collectIncompatibleTypeChanges(tableName, existingColumns, tableFields);
|
|
10398
|
+
for (const change of changes) {
|
|
10399
|
+
incompatibleTypeChanges.push(change);
|
|
10400
|
+
}
|
|
10401
|
+
task.existingColumns = existingColumns;
|
|
10402
|
+
task.existingIndexes = existingIndexes;
|
|
10403
|
+
}
|
|
10404
|
+
tableTasks.push(task);
|
|
10405
|
+
}
|
|
10406
|
+
if (incompatibleTypeChanges.length > 0) {
|
|
10407
|
+
const lines = [];
|
|
10408
|
+
for (const change of incompatibleTypeChanges) {
|
|
10409
|
+
lines.push(`- ${change.tableName}.${change.dbFieldName}: ${change.currentType} -> ${change.expectedType}`);
|
|
10410
|
+
}
|
|
10411
|
+
const msgLines = [];
|
|
10412
|
+
msgLines.push("\u7981\u6B62\u5B57\u6BB5\u7C7B\u578B\u53D8\u66F4\uFF08\u68C0\u6D4B\u5230\u4E0D\u517C\u5BB9/\u6536\u7F29\u53D8\u66F4\uFF09:");
|
|
10413
|
+
for (const line of lines) {
|
|
10414
|
+
msgLines.push(line);
|
|
10415
|
+
}
|
|
10416
|
+
msgLines.push("\u8BF4\u660E: \u4EC5\u5141\u8BB8\u540C\u7C7B\u578B\u7684\u5BBD\u5316\u53D8\u66F4\uFF08\u5982 TINYINT->SMALLINT->INT->BIGINT\uFF09\uFF0C\u4EE5\u53CA\u90E8\u5206\u517C\u5BB9\u53D8\u66F4\uFF08\u5982 VARCHAR->TEXT\u3001CHAR/VARCHAR \u4E92\u8F6C\u3001float->double\uFF09\u3002");
|
|
10417
|
+
msgLines.push("\u63D0\u793A: \u82E5\u786E\u9700\u6536\u7F29\uFF0C\u8BF7\u5148\u624B\u5DE5\u8FC1\u79FB/\u6E05\u6D17\u6570\u636E\u540E\u518D\u6267\u884C\u540C\u6B65\u3002");
|
|
10418
|
+
const err = new Error(msgLines.join(`
|
|
10419
|
+
`));
|
|
10420
|
+
err.__syncTableNoLog = true;
|
|
10421
|
+
throw err;
|
|
10422
|
+
}
|
|
10423
|
+
for (const task of tableTasks) {
|
|
10424
|
+
if (!task.existsTable) {
|
|
10425
|
+
continue;
|
|
10426
|
+
}
|
|
10427
|
+
if (!task.existingColumns || !task.existingIndexes) {
|
|
10428
|
+
throw new Error(`\u540C\u6B65\u8868\uFF1A\u5185\u90E8\u9519\u8BEF\uFF1A\u9884\u68C0\u9636\u6BB5\u7F3A\u5931\u8868\u5143\u4FE1\u606F\uFF08\u8868=${task.tableName}\uFF09`);
|
|
10429
|
+
}
|
|
10430
|
+
const built = SyncTable.buildTablePlan({
|
|
10431
|
+
tableName: task.tableName,
|
|
10432
|
+
fields: task.tableFields,
|
|
10433
|
+
existingColumns: task.existingColumns,
|
|
10434
|
+
existingIndexes: task.existingIndexes
|
|
10435
|
+
});
|
|
10436
|
+
task.plan = built.plan;
|
|
10437
|
+
task.planSummary = built.summary;
|
|
10438
|
+
task.planDetails = built.details;
|
|
10439
|
+
}
|
|
10440
|
+
for (const task of tableTasks) {
|
|
10441
|
+
const item = task.item;
|
|
10442
|
+
const tableName = task.tableName;
|
|
10443
|
+
const tableFields = task.tableFields;
|
|
10444
|
+
const existsTable = task.existsTable;
|
|
10240
10445
|
try {
|
|
10241
10446
|
if (existsTable) {
|
|
10242
|
-
|
|
10447
|
+
const plan = task.plan;
|
|
10448
|
+
const summary = task.planSummary;
|
|
10449
|
+
const details = task.planDetails;
|
|
10450
|
+
if (plan && plan.changed && summary && details) {
|
|
10451
|
+
const msg = `[\u8868 ${tableName}] \u53D8\u66F4\u6C47\u603B\uFF0C\u65B0\u589E\u5B57\u6BB5=${summary.addedBusiness}\uFF0C\u65B0\u589E\u7CFB\u7EDF\u5B57\u6BB5=${summary.addedSystem}\uFF0C\u4FEE\u6539\u5B57\u6BB5=${summary.modified}\uFF0C\u7D22\u5F15\u53D8\u66F4=${summary.indexChanges}`;
|
|
10452
|
+
const detailLines = details.fieldChanges.flatMap((d) => d.changes.map((change) => {
|
|
10453
|
+
const current = String(change.current ?? "");
|
|
10454
|
+
const expected = String(change.expected ?? "");
|
|
10455
|
+
return `- ${d.dbFieldName}.${change.type}: ${current} -> ${expected}`;
|
|
10456
|
+
}));
|
|
10457
|
+
const indexLines = details.indexChanges.map((change) => {
|
|
10458
|
+
const indexLabel = `idx_${change.fieldName}` === change.indexName ? change.indexName : change.indexName;
|
|
10459
|
+
if (change.action === "create") {
|
|
10460
|
+
return `- index.${indexLabel}: \u65E0 -> ${change.indexName}(${change.fieldName})`;
|
|
10461
|
+
}
|
|
10462
|
+
return `- index.${indexLabel}: ${change.indexName}(${change.fieldName}) -> \u65E0`;
|
|
10463
|
+
});
|
|
10464
|
+
const allLines = [];
|
|
10465
|
+
for (const line of detailLines) {
|
|
10466
|
+
allLines.push(line);
|
|
10467
|
+
}
|
|
10468
|
+
for (const line of indexLines) {
|
|
10469
|
+
allLines.push(line);
|
|
10470
|
+
}
|
|
10471
|
+
Logger.debug(msg);
|
|
10472
|
+
for (const line of allLines) {
|
|
10473
|
+
Logger.debug(`[\u8868 ${tableName}] \u53D8\u66F4\u660E\u7EC6 ${line}`);
|
|
10474
|
+
}
|
|
10475
|
+
await SyncTable.applyTablePlan(this.db, tableName, plan);
|
|
10476
|
+
}
|
|
10243
10477
|
} else {
|
|
10244
10478
|
await SyncTable.createTable(this.db, tableName, tableFields);
|
|
10245
10479
|
}
|
|
@@ -10268,6 +10502,9 @@ class SyncTable {
|
|
|
10268
10502
|
if (error?.__syncTableLogged === true) {
|
|
10269
10503
|
throw error;
|
|
10270
10504
|
}
|
|
10505
|
+
if (error?.__syncTableNoLog === true) {
|
|
10506
|
+
throw error;
|
|
10507
|
+
}
|
|
10271
10508
|
const errMsg = String(error?.message || error);
|
|
10272
10509
|
const sqlInfo = error?.sqlInfo;
|
|
10273
10510
|
Logger.error({
|
|
@@ -10594,6 +10831,32 @@ class SyncTable {
|
|
|
10594
10831
|
throw new Error([`\u7981\u6B62\u5B57\u6BB5\u7C7B\u578B\u53D8\u66F4: ${tableName}.${dbFieldName}`, `\u5F53\u524D\u7C7B\u578B: ${typeChange.current}`, `\u76EE\u6807\u7C7B\u578B: ${typeChange.expected}`, "\u8BF4\u660E: \u4EC5\u5141\u8BB8\u5BBD\u5316\u578B\u53D8\u66F4\uFF08\u5982 INT->BIGINT, VARCHAR->TEXT\uFF09\uFF0C\u4EE5\u53CA CHAR/VARCHAR \u4E92\u8F6C\uFF1BDATETIME \u4E0E BIGINT \u4E0D\u5141\u8BB8\u4E92\u8F6C\uFF08\u9700\u8981\u624B\u52A8\u8FC1\u79FB\u6570\u636E\uFF09"].join(`
|
|
10595
10832
|
`));
|
|
10596
10833
|
}
|
|
10834
|
+
static collectIncompatibleTypeChanges(tableName, existingColumns, fields) {
|
|
10835
|
+
const out = [];
|
|
10836
|
+
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
10837
|
+
const dbFieldName = snakeCase(fieldKey);
|
|
10838
|
+
const existing = existingColumns[dbFieldName];
|
|
10839
|
+
if (!existing)
|
|
10840
|
+
continue;
|
|
10841
|
+
const comparison = SyncTable.compareFieldDefinition(existing, fieldDef);
|
|
10842
|
+
const typeChange = comparison.find((c) => c.type === "datatype");
|
|
10843
|
+
if (!typeChange)
|
|
10844
|
+
continue;
|
|
10845
|
+
const currentType = String(typeChange.current || "").toLowerCase();
|
|
10846
|
+
const expectedType = String(typeChange.expected || "").toLowerCase();
|
|
10847
|
+
const currentBase = currentType.replace(/\s*unsigned/gi, "").replace(/\([^)]*\)/g, "").trim();
|
|
10848
|
+
const expectedBase = expectedType.replace(/\s*unsigned/gi, "").replace(/\([^)]*\)/g, "").trim();
|
|
10849
|
+
if (currentBase !== expectedBase && !SyncTable.isCompatibleTypeChange(currentType, expectedType)) {
|
|
10850
|
+
out.push({
|
|
10851
|
+
tableName,
|
|
10852
|
+
dbFieldName,
|
|
10853
|
+
currentType: String(typeChange.current ?? ""),
|
|
10854
|
+
expectedType: String(typeChange.expected ?? "")
|
|
10855
|
+
});
|
|
10856
|
+
}
|
|
10857
|
+
}
|
|
10858
|
+
return out;
|
|
10859
|
+
}
|
|
10597
10860
|
static truncateForLog(input, maxLen) {
|
|
10598
10861
|
const s = String(input);
|
|
10599
10862
|
if (maxLen <= 0)
|
|
@@ -13216,7 +13479,16 @@ class CacheHelper {
|
|
|
13216
13479
|
}
|
|
13217
13480
|
} catch (error) {
|
|
13218
13481
|
Logger.error({ err: error, msg: "\u26A0\uFE0F \u89D2\u8272\u6743\u9650\u7F13\u5B58\u5F02\u5E38\uFF08\u5C06\u963B\u65AD\u542F\u52A8\uFF09" });
|
|
13219
|
-
throw
|
|
13482
|
+
throw new CoreError({
|
|
13483
|
+
kind: "runtime",
|
|
13484
|
+
message: "\u26A0\uFE0F \u89D2\u8272\u6743\u9650\u7F13\u5B58\u5F02\u5E38\uFF08\u5C06\u963B\u65AD\u542F\u52A8\uFF09",
|
|
13485
|
+
logged: true,
|
|
13486
|
+
cause: error,
|
|
13487
|
+
meta: {
|
|
13488
|
+
subsystem: "cache",
|
|
13489
|
+
operation: "rebuildRoleApiPermissions"
|
|
13490
|
+
}
|
|
13491
|
+
});
|
|
13220
13492
|
}
|
|
13221
13493
|
}
|
|
13222
13494
|
async refreshRoleApiPermissions(roleCode, apiPaths) {
|
|
@@ -13301,10 +13573,10 @@ var cachePlugin = {
|
|
|
13301
13573
|
deps: ["logger", "redis", "db"],
|
|
13302
13574
|
async handler(befly) {
|
|
13303
13575
|
if (!befly.db) {
|
|
13304
|
-
throw new
|
|
13576
|
+
throw new CoreError({ message: "\u7F13\u5B58\u521D\u59CB\u5316\u5931\u8D25\uFF1Actx.db \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
13305
13577
|
}
|
|
13306
13578
|
if (!befly.redis) {
|
|
13307
|
-
throw new
|
|
13579
|
+
throw new CoreError({ message: "\u7F13\u5B58\u521D\u59CB\u5316\u5931\u8D25\uFF1Actx.redis \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
13308
13580
|
}
|
|
13309
13581
|
return new CacheHelper({ db: befly.db, redis: befly.redis });
|
|
13310
13582
|
}
|
|
@@ -15092,7 +15364,20 @@ class DbHelper {
|
|
|
15092
15364
|
fields: insertFields,
|
|
15093
15365
|
msg: "\u6279\u91CF\u63D2\u5165\u5931\u8D25"
|
|
15094
15366
|
});
|
|
15095
|
-
throw
|
|
15367
|
+
throw new CoreError({
|
|
15368
|
+
kind: "runtime",
|
|
15369
|
+
message: "\u6279\u91CF\u63D2\u5165\u5931\u8D25",
|
|
15370
|
+
logged: true,
|
|
15371
|
+
cause: error,
|
|
15372
|
+
meta: {
|
|
15373
|
+
subsystem: "sql",
|
|
15374
|
+
operation: "insBatch",
|
|
15375
|
+
table,
|
|
15376
|
+
snakeTable,
|
|
15377
|
+
count: dataList.length,
|
|
15378
|
+
fields: insertFields
|
|
15379
|
+
}
|
|
15380
|
+
});
|
|
15096
15381
|
}
|
|
15097
15382
|
}
|
|
15098
15383
|
async delForceBatch(table, ids) {
|
|
@@ -15370,10 +15655,10 @@ var dbPlugin = {
|
|
|
15370
15655
|
const env = befly.config?.nodeEnv;
|
|
15371
15656
|
const dbName = String(befly.config?.db?.database || "");
|
|
15372
15657
|
if (!dbName) {
|
|
15373
|
-
throw new
|
|
15658
|
+
throw new CoreError({ message: "\u6570\u636E\u5E93\u521D\u59CB\u5316\u5931\u8D25\uFF1Abefly.config.db.database \u7F3A\u5931", kind: "validation" });
|
|
15374
15659
|
}
|
|
15375
15660
|
if (!befly.redis) {
|
|
15376
|
-
throw new
|
|
15661
|
+
throw new CoreError({ message: "Redis \u672A\u521D\u59CB\u5316", kind: "validation" });
|
|
15377
15662
|
}
|
|
15378
15663
|
try {
|
|
15379
15664
|
const sql = Connect.getSql();
|
|
@@ -15383,7 +15668,16 @@ var dbPlugin = {
|
|
|
15383
15668
|
return dbManager;
|
|
15384
15669
|
} catch (error) {
|
|
15385
15670
|
Logger.error({ env, err: error, msg: "\u6570\u636E\u5E93\u521D\u59CB\u5316\u5931\u8D25" });
|
|
15386
|
-
throw
|
|
15671
|
+
throw new CoreError({
|
|
15672
|
+
kind: "runtime",
|
|
15673
|
+
message: "\u6570\u636E\u5E93\u521D\u59CB\u5316\u5931\u8D25",
|
|
15674
|
+
logged: true,
|
|
15675
|
+
cause: error,
|
|
15676
|
+
meta: {
|
|
15677
|
+
subsystem: "db",
|
|
15678
|
+
operation: "init"
|
|
15679
|
+
}
|
|
15680
|
+
});
|
|
15387
15681
|
}
|
|
15388
15682
|
}
|
|
15389
15683
|
};
|
|
@@ -15853,7 +16147,16 @@ class RedisHelper {
|
|
|
15853
16147
|
return res;
|
|
15854
16148
|
} catch (error) {
|
|
15855
16149
|
Logger.error({ err: error, msg: "Redis ping \u9519\u8BEF" });
|
|
15856
|
-
throw
|
|
16150
|
+
throw new CoreError({
|
|
16151
|
+
kind: "runtime",
|
|
16152
|
+
message: "Redis ping \u9519\u8BEF",
|
|
16153
|
+
logged: true,
|
|
16154
|
+
cause: error,
|
|
16155
|
+
meta: {
|
|
16156
|
+
subsystem: "redis",
|
|
16157
|
+
operation: "ping"
|
|
16158
|
+
}
|
|
16159
|
+
});
|
|
15857
16160
|
}
|
|
15858
16161
|
}
|
|
15859
16162
|
}
|
|
@@ -15871,7 +16174,16 @@ var redisPlugin = {
|
|
|
15871
16174
|
return new RedisHelper(redisPrefix);
|
|
15872
16175
|
} catch (error) {
|
|
15873
16176
|
Logger.error({ env, err: error, msg: "Redis \u521D\u59CB\u5316\u5931\u8D25" });
|
|
15874
|
-
throw
|
|
16177
|
+
throw new CoreError({
|
|
16178
|
+
kind: "runtime",
|
|
16179
|
+
message: "Redis \u521D\u59CB\u5316\u5931\u8D25",
|
|
16180
|
+
logged: true,
|
|
16181
|
+
cause: error,
|
|
16182
|
+
meta: {
|
|
16183
|
+
subsystem: "redis",
|
|
16184
|
+
operation: "init"
|
|
16185
|
+
}
|
|
16186
|
+
});
|
|
15875
16187
|
}
|
|
15876
16188
|
}
|
|
15877
16189
|
};
|
|
@@ -16221,7 +16533,49 @@ class Befly {
|
|
|
16221
16533
|
Logger.info(`\u670D\u52A1\u5668\u76D1\u542C\u5730\u5740: ${server.url}`);
|
|
16222
16534
|
return server;
|
|
16223
16535
|
} catch (error) {
|
|
16224
|
-
|
|
16536
|
+
const errMessage = error instanceof Error ? error.message : String(error);
|
|
16537
|
+
let kind = "runtime";
|
|
16538
|
+
let alreadyLogged = false;
|
|
16539
|
+
let noLog = false;
|
|
16540
|
+
if (isCoreError(error)) {
|
|
16541
|
+
kind = error.kind;
|
|
16542
|
+
alreadyLogged = error.logged === true;
|
|
16543
|
+
noLog = error.noLog === true;
|
|
16544
|
+
} else {
|
|
16545
|
+
const anyErr = error;
|
|
16546
|
+
if (anyErr && anyErr.__syncTableLogged === true) {
|
|
16547
|
+
alreadyLogged = true;
|
|
16548
|
+
}
|
|
16549
|
+
if (anyErr && anyErr.__syncTableNoLog === true) {
|
|
16550
|
+
kind = "policy";
|
|
16551
|
+
}
|
|
16552
|
+
if (anyErr && anyErr.__coreLogged === true) {
|
|
16553
|
+
alreadyLogged = true;
|
|
16554
|
+
}
|
|
16555
|
+
if (anyErr && anyErr.__coreNoLog === true) {
|
|
16556
|
+
noLog = true;
|
|
16557
|
+
}
|
|
16558
|
+
}
|
|
16559
|
+
if (alreadyLogged) {
|
|
16560
|
+
Logger.error({
|
|
16561
|
+
msg: "\u9879\u76EE\u542F\u52A8\u5931\u8D25\uFF08\u4E0B\u5C42\u5DF2\u8BB0\u5F55\uFF09",
|
|
16562
|
+
errorKind: kind,
|
|
16563
|
+
errorMessage: errMessage
|
|
16564
|
+
});
|
|
16565
|
+
} else if (noLog) {
|
|
16566
|
+
Logger.error({
|
|
16567
|
+
msg: "\u9879\u76EE\u542F\u52A8\u5931\u8D25",
|
|
16568
|
+
errorKind: kind,
|
|
16569
|
+
errorMessage: errMessage
|
|
16570
|
+
});
|
|
16571
|
+
} else {
|
|
16572
|
+
Logger.error({
|
|
16573
|
+
msg: "\u9879\u76EE\u542F\u52A8\u5931\u8D25",
|
|
16574
|
+
errorKind: kind,
|
|
16575
|
+
errorMessage: errMessage,
|
|
16576
|
+
err: error
|
|
16577
|
+
});
|
|
16578
|
+
}
|
|
16225
16579
|
try {
|
|
16226
16580
|
await Logger.flush();
|
|
16227
16581
|
} catch {}
|