befly 3.14.0 → 3.14.2
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 +395 -205
- package/dist/befly.min.js +13 -13
- package/dist/checks/checkTable.js +5 -3
- package/dist/hooks/validator.js +4 -2
- package/dist/index.js +14 -5
- package/dist/lib/asyncContext.js +4 -4
- package/dist/lib/cacheHelper.d.ts +2 -2
- package/dist/lib/dbHelper.d.ts +29 -13
- package/dist/lib/dbHelper.js +66 -25
- package/dist/lib/dbUtils.js +95 -20
- package/dist/lib/jwt.js +31 -19
- package/dist/lib/logger.js +7 -7
- package/dist/lib/sqlBuilder.js +53 -13
- package/dist/lib/validator.js +10 -3
- package/dist/loader/loadApis.js +2 -6
- package/dist/loader/loadHooks.js +1 -1
- package/dist/loader/loadPlugins.js +1 -1
- package/dist/router/api.js +7 -6
- package/dist/sync/syncDev.js +2 -2
- package/dist/sync/syncTable.d.ts +1 -1
- package/dist/sync/syncTable.js +70 -41
- package/dist/types/common.d.ts +9 -9
- package/dist/types/database.d.ts +25 -22
- package/dist/types/validate.d.ts +40 -13
- package/dist/utils/loadMenuConfigs.js +1 -1
- package/dist/utils/loggerUtils.js +7 -3
- package/dist/utils/normalizeFieldDefinition.d.ts +15 -0
- package/dist/utils/normalizeFieldDefinition.js +15 -0
- package/dist/utils/processInfo.js +2 -2
- package/dist/utils/scanFiles.js +12 -12
- package/dist/utils/util.js +10 -3
- package/package.json +2 -2
- package/dist/configs/presetFields.d.ts +0 -4
- package/dist/configs/presetFields.js +0 -10
- package/dist/utils/processAtSymbol.d.ts +0 -4
- package/dist/utils/processAtSymbol.js +0 -21
package/dist/befly.js
CHANGED
|
@@ -105,16 +105,20 @@ function upperFirst(s) {
|
|
|
105
105
|
if (s.length === 0) {
|
|
106
106
|
return s;
|
|
107
107
|
}
|
|
108
|
-
return s
|
|
108
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
109
109
|
}
|
|
110
110
|
function camelCase(input) {
|
|
111
111
|
const parts = toWordParts(input);
|
|
112
112
|
if (parts.length === 0) {
|
|
113
113
|
return "";
|
|
114
114
|
}
|
|
115
|
-
const
|
|
115
|
+
const firstPart = parts[0];
|
|
116
|
+
if (!firstPart) {
|
|
117
|
+
return "";
|
|
118
|
+
}
|
|
119
|
+
const first = firstPart.toLowerCase();
|
|
116
120
|
const rest = parts.slice(1).map((p) => upperFirst(p.toLowerCase()));
|
|
117
|
-
return [first
|
|
121
|
+
return [first].concat(rest).join("");
|
|
118
122
|
}
|
|
119
123
|
function normalizeToWords(input) {
|
|
120
124
|
return String(input).replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").trim();
|
|
@@ -235,7 +239,7 @@ function sanitizeErrorValue(err, options) {
|
|
|
235
239
|
message: truncateString(err.message || "", options.maxStringLen)
|
|
236
240
|
};
|
|
237
241
|
if (typeof err.stack === "string") {
|
|
238
|
-
out
|
|
242
|
+
out["stack"] = truncateString(err.stack, options.maxStringLen);
|
|
239
243
|
}
|
|
240
244
|
return out;
|
|
241
245
|
}
|
|
@@ -323,8 +327,12 @@ function sanitizeAny(value, options, state, depth, visited) {
|
|
|
323
327
|
const entries = Object.entries(obj);
|
|
324
328
|
const limit = entries.length > options.sanitizeObjectKeys ? options.sanitizeObjectKeys : entries.length;
|
|
325
329
|
for (let i = 0;i < limit; i++) {
|
|
326
|
-
const
|
|
327
|
-
|
|
330
|
+
const entry = entries[i];
|
|
331
|
+
if (!entry) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const key = entry[0];
|
|
335
|
+
const child = entry[1];
|
|
328
336
|
if (isSensitiveKey(key, options.sensitiveKeyMatcher)) {
|
|
329
337
|
out[key] = "[MASKED]";
|
|
330
338
|
continue;
|
|
@@ -365,10 +373,10 @@ function setCtxUser(userId, roleCode, nickname, roleType) {
|
|
|
365
373
|
const store = storage.getStore();
|
|
366
374
|
if (!store)
|
|
367
375
|
return;
|
|
368
|
-
store.userId = userId;
|
|
369
|
-
store.roleCode = roleCode;
|
|
370
|
-
store.nickname = nickname;
|
|
371
|
-
store.roleType = roleType;
|
|
376
|
+
store.userId = userId === undefined ? null : userId;
|
|
377
|
+
store.roleCode = roleCode === undefined ? null : roleCode;
|
|
378
|
+
store.nickname = nickname === undefined ? null : nickname;
|
|
379
|
+
store.roleType = roleType === undefined ? null : roleType;
|
|
372
380
|
}
|
|
373
381
|
var storage;
|
|
374
382
|
var init_asyncContext = __esm(() => {
|
|
@@ -798,8 +806,8 @@ function buildLogLine(level, record) {
|
|
|
798
806
|
return `${safeJsonStringify(out)}
|
|
799
807
|
`;
|
|
800
808
|
}
|
|
801
|
-
if (base
|
|
802
|
-
base
|
|
809
|
+
if (base["msg"] === undefined) {
|
|
810
|
+
base["msg"] = "";
|
|
803
811
|
}
|
|
804
812
|
return `${safeJsonStringify(base)}
|
|
805
813
|
`;
|
|
@@ -809,7 +817,7 @@ function safeJsonStringify(obj) {
|
|
|
809
817
|
return JSON.stringify(obj);
|
|
810
818
|
} catch {
|
|
811
819
|
try {
|
|
812
|
-
return JSON.stringify({ level: obj
|
|
820
|
+
return JSON.stringify({ level: obj["level"], time: obj["time"], pid: obj["pid"], hostname: obj["hostname"], msg: "[Unserializable log record]" });
|
|
813
821
|
} catch {
|
|
814
822
|
return '{"msg":"[Unserializable log record]"}';
|
|
815
823
|
}
|
|
@@ -855,10 +863,10 @@ function metaToObject() {
|
|
|
855
863
|
now: meta.now,
|
|
856
864
|
durationSinceNowMs
|
|
857
865
|
};
|
|
858
|
-
obj
|
|
859
|
-
obj
|
|
860
|
-
obj
|
|
861
|
-
obj
|
|
866
|
+
obj["userId"] = meta.userId;
|
|
867
|
+
obj["roleCode"] = meta.roleCode;
|
|
868
|
+
obj["nickname"] = meta.nickname;
|
|
869
|
+
obj["roleType"] = meta.roleType;
|
|
862
870
|
return obj;
|
|
863
871
|
}
|
|
864
872
|
function mergeMetaIntoObject(input, meta) {
|
|
@@ -1309,7 +1317,7 @@ async function scanViewsDirToMenuConfigs(viewsDir, prefix, parentPath = "") {
|
|
|
1309
1317
|
return menus;
|
|
1310
1318
|
}
|
|
1311
1319
|
function getParentPath(path) {
|
|
1312
|
-
const parts = path.split("/").filter((p) =>
|
|
1320
|
+
const parts = path.split("/").filter((p) => Boolean(p));
|
|
1313
1321
|
if (parts.length <= 1) {
|
|
1314
1322
|
return "";
|
|
1315
1323
|
}
|
|
@@ -8092,10 +8100,10 @@ async function checkTable(tables) {
|
|
|
8092
8100
|
hasError = true;
|
|
8093
8101
|
}
|
|
8094
8102
|
} else if (fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string") {
|
|
8095
|
-
if (fieldMax
|
|
8096
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C` + `\
|
|
8103
|
+
if (fieldMax === undefined || fieldMax === null || typeof fieldMax !== "number") {
|
|
8104
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C` + `\u5FC5\u987B\u8BBE\u7F6E max \u4E14\u7C7B\u578B\u4E3A\u6570\u5B57\uFF1B\u5176\u4E2D array_*_string \u7684 max \u8868\u793A\u5355\u4E2A\u5143\u7D20\u957F\u5EA6\uFF0C\u5F53\u524D\u4E3A "${fieldMax}"`);
|
|
8097
8105
|
hasError = true;
|
|
8098
|
-
} else if (fieldMax
|
|
8106
|
+
} else if (fieldMax > MAX_VARCHAR_LENGTH) {
|
|
8099
8107
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5927\u957F\u5EA6 ${fieldMax} \u8D8A\u754C\uFF0C` + `${fieldType} \u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728 1..${MAX_VARCHAR_LENGTH} \u8303\u56F4\u5185`);
|
|
8100
8108
|
hasError = true;
|
|
8101
8109
|
}
|
|
@@ -8309,46 +8317,14 @@ init_logger();
|
|
|
8309
8317
|
|
|
8310
8318
|
// loader/loadApis.ts
|
|
8311
8319
|
init_logger();
|
|
8312
|
-
|
|
8313
|
-
// configs/presetFields.ts
|
|
8314
|
-
var presetFields = {
|
|
8315
|
-
"@id": { name: "ID", type: "number", min: 1, max: null },
|
|
8316
|
-
"@page": { name: "\u9875\u7801", type: "number", min: 1, max: 9999, default: 1 },
|
|
8317
|
-
"@limit": { name: "\u6BCF\u9875\u6570\u91CF", type: "number", min: 1, max: 100, default: 30 },
|
|
8318
|
-
"@keyword": { name: "\u5173\u952E\u8BCD", type: "string", min: 0, max: 50 },
|
|
8319
|
-
"@state": { name: "\u72B6\u6001", type: "number", regex: "^[0-2]$" }
|
|
8320
|
-
};
|
|
8321
|
-
|
|
8322
|
-
// utils/processAtSymbol.ts
|
|
8323
|
-
function processAtSymbol(fields, apiName, path) {
|
|
8324
|
-
if (!fields || typeof fields !== "object")
|
|
8325
|
-
return fields;
|
|
8326
|
-
const processed = {};
|
|
8327
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
8328
|
-
if (typeof value === "string" && value.startsWith("@")) {
|
|
8329
|
-
if (presetFields[value]) {
|
|
8330
|
-
processed[key] = presetFields[value];
|
|
8331
|
-
continue;
|
|
8332
|
-
}
|
|
8333
|
-
const validKeys = Object.keys(presetFields).join(", ");
|
|
8334
|
-
throw new Error(`API [${apiName}] (${path}) \u5B57\u6BB5 [${key}] \u5F15\u7528\u4E86\u672A\u5B9A\u4E49\u7684\u9884\u8BBE\u5B57\u6BB5 "${value}"\u3002\u53EF\u7528\u7684\u9884\u8BBE\u5B57\u6BB5\u6709: ${validKeys}`);
|
|
8335
|
-
}
|
|
8336
|
-
processed[key] = value;
|
|
8337
|
-
}
|
|
8338
|
-
return processed;
|
|
8339
|
-
}
|
|
8340
|
-
|
|
8341
|
-
// loader/loadApis.ts
|
|
8342
8320
|
async function loadApis(apis) {
|
|
8343
8321
|
const apisMap = new Map;
|
|
8344
8322
|
for (const api of apis) {
|
|
8345
|
-
if (api.type !== "api") {
|
|
8323
|
+
if (Object.hasOwn(api, "type") && api.type !== "api") {
|
|
8346
8324
|
continue;
|
|
8347
8325
|
}
|
|
8348
8326
|
try {
|
|
8349
|
-
|
|
8350
|
-
apiRoute.fields = processAtSymbol(apiRoute.fields || {}, apiRoute.name, apiRoute.path);
|
|
8351
|
-
apisMap.set(apiRoute.path, apiRoute);
|
|
8327
|
+
apisMap.set(api.path, api);
|
|
8352
8328
|
} catch (error) {
|
|
8353
8329
|
Logger.error({ err: error, api: api.relativePath, file: api.filePath, msg: "\u63A5\u53E3\u52A0\u8F7D\u5931\u8D25" });
|
|
8354
8330
|
throw error;
|
|
@@ -8468,7 +8444,7 @@ async function loadHooks(hooks) {
|
|
|
8468
8444
|
hooksMap.push({
|
|
8469
8445
|
name: hookName,
|
|
8470
8446
|
enable: true,
|
|
8471
|
-
deps: hook.deps,
|
|
8447
|
+
deps: Array.isArray(hook.deps) ? hook.deps : [],
|
|
8472
8448
|
handler: hook.handler
|
|
8473
8449
|
});
|
|
8474
8450
|
}
|
|
@@ -8502,7 +8478,7 @@ async function loadPlugins(plugins, context) {
|
|
|
8502
8478
|
pluginsMap.push({
|
|
8503
8479
|
name: pluginName,
|
|
8504
8480
|
enable: true,
|
|
8505
|
-
deps: plugin.deps,
|
|
8481
|
+
deps: Array.isArray(plugin.deps) ? plugin.deps : [],
|
|
8506
8482
|
handler: plugin.handler
|
|
8507
8483
|
});
|
|
8508
8484
|
} catch (error) {
|
|
@@ -8641,11 +8617,12 @@ function apiHandler(apis, hooks, context) {
|
|
|
8641
8617
|
requestId,
|
|
8642
8618
|
corsHeaders: {
|
|
8643
8619
|
"X-Request-ID": requestId
|
|
8644
|
-
}
|
|
8645
|
-
api: apis.get(apiPath),
|
|
8646
|
-
response: undefined,
|
|
8647
|
-
result: undefined
|
|
8620
|
+
}
|
|
8648
8621
|
};
|
|
8622
|
+
const api = apis.get(apiPath);
|
|
8623
|
+
if (api) {
|
|
8624
|
+
ctx.api = api;
|
|
8625
|
+
}
|
|
8649
8626
|
return withCtx({
|
|
8650
8627
|
requestId,
|
|
8651
8628
|
method: req.method,
|
|
@@ -8666,9 +8643,9 @@ function apiHandler(apis, hooks, context) {
|
|
|
8666
8643
|
apiName: ctx.api.name
|
|
8667
8644
|
};
|
|
8668
8645
|
if (ctx.body && Object.keys(ctx.body).length > 0) {
|
|
8669
|
-
logData
|
|
8646
|
+
logData["body"] = ctx.body;
|
|
8670
8647
|
}
|
|
8671
|
-
logData
|
|
8648
|
+
logData["msg"] = "request";
|
|
8672
8649
|
Logger.info(logData);
|
|
8673
8650
|
}
|
|
8674
8651
|
if (!ctx.api) {
|
|
@@ -9061,7 +9038,7 @@ async function syncDev(ctx, config2 = {}) {
|
|
|
9061
9038
|
apis: allApis.data.lists.map((item) => item.path).filter((v) => v),
|
|
9062
9039
|
sort: 0
|
|
9063
9040
|
};
|
|
9064
|
-
if (devRole.data) {
|
|
9041
|
+
if (typeof devRole.data.id === "number") {
|
|
9065
9042
|
await ctx.db.updData({
|
|
9066
9043
|
table: "addon_admin_role",
|
|
9067
9044
|
where: { code: "dev" },
|
|
@@ -9091,7 +9068,7 @@ async function syncDev(ctx, config2 = {}) {
|
|
|
9091
9068
|
table: "addon_admin_admin",
|
|
9092
9069
|
where: { username: "dev" }
|
|
9093
9070
|
});
|
|
9094
|
-
if (devAdmin.data) {
|
|
9071
|
+
if (typeof devAdmin.data.id === "number") {
|
|
9095
9072
|
await ctx.db.updData({
|
|
9096
9073
|
table: "addon_admin_admin",
|
|
9097
9074
|
where: { username: "dev" },
|
|
@@ -9643,6 +9620,25 @@ class SqliteDialect {
|
|
|
9643
9620
|
|
|
9644
9621
|
// sync/syncTable.ts
|
|
9645
9622
|
init_logger();
|
|
9623
|
+
|
|
9624
|
+
// utils/normalizeFieldDefinition.ts
|
|
9625
|
+
function normalizeFieldDefinition(fieldDef) {
|
|
9626
|
+
return {
|
|
9627
|
+
name: fieldDef.name,
|
|
9628
|
+
type: fieldDef.type,
|
|
9629
|
+
detail: fieldDef.detail ?? "",
|
|
9630
|
+
min: fieldDef.min ?? null,
|
|
9631
|
+
max: fieldDef.max ?? null,
|
|
9632
|
+
default: fieldDef.default ?? null,
|
|
9633
|
+
index: fieldDef.index ?? false,
|
|
9634
|
+
unique: fieldDef.unique ?? false,
|
|
9635
|
+
nullable: fieldDef.nullable ?? false,
|
|
9636
|
+
unsigned: fieldDef.unsigned ?? false,
|
|
9637
|
+
regexp: fieldDef.regexp ?? null
|
|
9638
|
+
};
|
|
9639
|
+
}
|
|
9640
|
+
|
|
9641
|
+
// sync/syncTable.ts
|
|
9646
9642
|
init_util();
|
|
9647
9643
|
var syncTable = async (ctx, items) => {
|
|
9648
9644
|
try {
|
|
@@ -9837,15 +9833,18 @@ function escapeComment(str) {
|
|
|
9837
9833
|
return String(str).replace(/"/g, "\\\"");
|
|
9838
9834
|
}
|
|
9839
9835
|
function applyFieldDefaults(fieldDef) {
|
|
9840
|
-
fieldDef
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
fieldDef.
|
|
9844
|
-
fieldDef.
|
|
9845
|
-
fieldDef.
|
|
9846
|
-
fieldDef.
|
|
9847
|
-
fieldDef.
|
|
9848
|
-
fieldDef.
|
|
9836
|
+
if (!fieldDef || typeof fieldDef !== "object")
|
|
9837
|
+
return;
|
|
9838
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
9839
|
+
fieldDef.detail = normalized.detail;
|
|
9840
|
+
fieldDef.min = normalized.min;
|
|
9841
|
+
fieldDef.max = normalized.max;
|
|
9842
|
+
fieldDef.default = normalized.default;
|
|
9843
|
+
fieldDef.index = normalized.index;
|
|
9844
|
+
fieldDef.unique = normalized.unique;
|
|
9845
|
+
fieldDef.nullable = normalized.nullable;
|
|
9846
|
+
fieldDef.unsigned = normalized.unsigned;
|
|
9847
|
+
fieldDef.regexp = normalized.regexp;
|
|
9849
9848
|
}
|
|
9850
9849
|
function isStringOrArrayType(fieldType) {
|
|
9851
9850
|
return fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string";
|
|
@@ -9944,15 +9943,16 @@ function buildSystemColumnDefs(dbDialect) {
|
|
|
9944
9943
|
function buildBusinessColumnDefs(dbDialect, fields) {
|
|
9945
9944
|
const colDefs = [];
|
|
9946
9945
|
for (const [fieldKey, fieldDef] of Object.entries(fields)) {
|
|
9946
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
9947
9947
|
const dbFieldName = snakeCase(fieldKey);
|
|
9948
9948
|
const colQuoted = quoteIdentifier(dbDialect, dbFieldName);
|
|
9949
|
-
const sqlType = getSqlType(dbDialect,
|
|
9950
|
-
const actualDefault = resolveDefaultValue(
|
|
9951
|
-
const defaultSql = generateDefaultSql(actualDefault,
|
|
9952
|
-
const uniqueSql =
|
|
9953
|
-
const nullableSql =
|
|
9949
|
+
const sqlType = getSqlType(dbDialect, normalized.type, normalized.max, normalized.unsigned);
|
|
9950
|
+
const actualDefault = resolveDefaultValue(normalized.default, normalized.type);
|
|
9951
|
+
const defaultSql = generateDefaultSql(actualDefault, normalized.type);
|
|
9952
|
+
const uniqueSql = normalized.unique ? " UNIQUE" : "";
|
|
9953
|
+
const nullableSql = normalized.nullable ? " NULL" : " NOT NULL";
|
|
9954
9954
|
if (dbDialect === "mysql") {
|
|
9955
|
-
colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(
|
|
9955
|
+
colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(normalized.name)}"`);
|
|
9956
9956
|
} else {
|
|
9957
9957
|
colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql}`);
|
|
9958
9958
|
}
|
|
@@ -9962,13 +9962,14 @@ function buildBusinessColumnDefs(dbDialect, fields) {
|
|
|
9962
9962
|
function generateDDLClause(dbDialect, fieldKey, fieldDef, isAdd = false) {
|
|
9963
9963
|
const dbFieldName = snakeCase(fieldKey);
|
|
9964
9964
|
const colQuoted = quoteIdentifier(dbDialect, dbFieldName);
|
|
9965
|
-
const
|
|
9966
|
-
const
|
|
9967
|
-
const
|
|
9968
|
-
const
|
|
9969
|
-
const
|
|
9965
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
9966
|
+
const sqlType = getSqlType(dbDialect, normalized.type, normalized.max, normalized.unsigned);
|
|
9967
|
+
const actualDefault = resolveDefaultValue(normalized.default, normalized.type);
|
|
9968
|
+
const defaultSql = generateDefaultSql(actualDefault, normalized.type);
|
|
9969
|
+
const uniqueSql = normalized.unique ? " UNIQUE" : "";
|
|
9970
|
+
const nullableSql = normalized.nullable ? " NULL" : " NOT NULL";
|
|
9970
9971
|
if (dbDialect === "mysql") {
|
|
9971
|
-
return `${isAdd ? "ADD COLUMN" : "MODIFY COLUMN"} ${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(
|
|
9972
|
+
return `${isAdd ? "ADD COLUMN" : "MODIFY COLUMN"} ${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(normalized.name)}"`;
|
|
9972
9973
|
}
|
|
9973
9974
|
if (dbDialect === "postgresql") {
|
|
9974
9975
|
if (isAdd)
|
|
@@ -10085,8 +10086,14 @@ async function getTableColumnsRuntime(runtime, tableName) {
|
|
|
10085
10086
|
let max = null;
|
|
10086
10087
|
const m = /^(\w+)\s*\((\d+)\)/.exec(baseType);
|
|
10087
10088
|
if (m) {
|
|
10088
|
-
|
|
10089
|
-
|
|
10089
|
+
const base = m[1];
|
|
10090
|
+
const maxText = m[2];
|
|
10091
|
+
if (typeof base === "string") {
|
|
10092
|
+
baseType = base;
|
|
10093
|
+
}
|
|
10094
|
+
if (typeof maxText === "string") {
|
|
10095
|
+
max = Number(maxText);
|
|
10096
|
+
}
|
|
10090
10097
|
}
|
|
10091
10098
|
columns[row.name] = {
|
|
10092
10099
|
type: baseType.toLowerCase(),
|
|
@@ -10115,9 +10122,13 @@ async function getTableIndexesRuntime(runtime, tableName) {
|
|
|
10115
10122
|
const q = getSyncTableIndexesQuery({ dialect: "mysql", table: tableName, dbName: runtime.dbName });
|
|
10116
10123
|
const result = await runtime.db.unsafe(q.sql, q.params);
|
|
10117
10124
|
for (const row of result.data) {
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10125
|
+
const indexName = row.INDEX_NAME;
|
|
10126
|
+
const current = indexes[indexName];
|
|
10127
|
+
if (Array.isArray(current)) {
|
|
10128
|
+
current.push(row.COLUMN_NAME);
|
|
10129
|
+
} else {
|
|
10130
|
+
indexes[indexName] = [row.COLUMN_NAME];
|
|
10131
|
+
}
|
|
10121
10132
|
}
|
|
10122
10133
|
} else if (runtime.dbDialect === "postgresql") {
|
|
10123
10134
|
const q = getSyncTableIndexesQuery({ dialect: "postgresql", table: tableName, dbName: runtime.dbName });
|
|
@@ -10125,7 +10136,8 @@ async function getTableIndexesRuntime(runtime, tableName) {
|
|
|
10125
10136
|
for (const row of result.data) {
|
|
10126
10137
|
const m = /\(([^)]+)\)/.exec(row.indexdef);
|
|
10127
10138
|
if (m) {
|
|
10128
|
-
const
|
|
10139
|
+
const colPart = m[1];
|
|
10140
|
+
const col = typeof colPart === "string" ? colPart.replace(/"/g, "").trim() : "";
|
|
10129
10141
|
indexes[row.indexname] = [col];
|
|
10130
10142
|
}
|
|
10131
10143
|
}
|
|
@@ -10158,7 +10170,8 @@ async function ensureDbVersion(dbDialect, db) {
|
|
|
10158
10170
|
throw new Error("\u65E0\u6CD5\u83B7\u53D6 MySQL \u7248\u672C\u4FE1\u606F");
|
|
10159
10171
|
}
|
|
10160
10172
|
const version = r.data[0].version;
|
|
10161
|
-
const
|
|
10173
|
+
const majorPart = String(version).split(".")[0] || "0";
|
|
10174
|
+
const majorVersion = parseInt(majorPart, 10);
|
|
10162
10175
|
if (!Number.isFinite(majorVersion) || majorVersion < DB_VERSION_REQUIREMENTS.MYSQL_MIN_MAJOR) {
|
|
10163
10176
|
throw new Error(`\u6B64\u811A\u672C\u4EC5\u652F\u6301 MySQL ${DB_VERSION_REQUIREMENTS.MYSQL_MIN_MAJOR}.0+\uFF0C\u5F53\u524D\u7248\u672C: ${version}`);
|
|
10164
10177
|
}
|
|
@@ -10171,7 +10184,8 @@ async function ensureDbVersion(dbDialect, db) {
|
|
|
10171
10184
|
}
|
|
10172
10185
|
const versionText = r.data[0].version;
|
|
10173
10186
|
const m = /PostgreSQL\s+(\d+)/i.exec(versionText);
|
|
10174
|
-
const
|
|
10187
|
+
const majorText = m ? m[1] : undefined;
|
|
10188
|
+
const major = typeof majorText === "string" ? parseInt(majorText, 10) : NaN;
|
|
10175
10189
|
if (!Number.isFinite(major) || major < DB_VERSION_REQUIREMENTS.POSTGRES_MIN_MAJOR) {
|
|
10176
10190
|
throw new Error(`\u6B64\u811A\u672C\u8981\u6C42 PostgreSQL >= ${DB_VERSION_REQUIREMENTS.POSTGRES_MIN_MAJOR}\uFF0C\u5F53\u524D: ${versionText}`);
|
|
10177
10191
|
}
|
|
@@ -10183,7 +10197,10 @@ async function ensureDbVersion(dbDialect, db) {
|
|
|
10183
10197
|
throw new Error("\u65E0\u6CD5\u83B7\u53D6 SQLite \u7248\u672C\u4FE1\u606F");
|
|
10184
10198
|
}
|
|
10185
10199
|
const version = r.data[0].version;
|
|
10186
|
-
const
|
|
10200
|
+
const parts = String(version).split(".").map((v) => parseInt(v, 10) || 0);
|
|
10201
|
+
const maj = parts[0] ?? 0;
|
|
10202
|
+
const min = parts[1] ?? 0;
|
|
10203
|
+
const patch = parts[2] ?? 0;
|
|
10187
10204
|
const vnum = maj * 1e4 + min * 100 + patch;
|
|
10188
10205
|
if (!Number.isFinite(vnum) || vnum < DB_VERSION_REQUIREMENTS.SQLITE_MIN_VERSION_NUM) {
|
|
10189
10206
|
throw new Error(`\u6B64\u811A\u672C\u8981\u6C42 SQLite >= ${DB_VERSION_REQUIREMENTS.SQLITE_MIN_VERSION}\uFF0C\u5F53\u524D: ${version}`);
|
|
@@ -10193,27 +10210,33 @@ async function ensureDbVersion(dbDialect, db) {
|
|
|
10193
10210
|
}
|
|
10194
10211
|
function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
|
|
10195
10212
|
const changes = [];
|
|
10196
|
-
|
|
10197
|
-
|
|
10213
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
10214
|
+
if (dbDialect !== "sqlite" && isStringOrArrayType(normalized.type)) {
|
|
10215
|
+
const expectedMax = normalized.max;
|
|
10216
|
+
if (expectedMax !== null && existingColumn.max !== expectedMax) {
|
|
10198
10217
|
changes.push({
|
|
10199
10218
|
type: "length",
|
|
10200
10219
|
current: existingColumn.max,
|
|
10201
|
-
expected:
|
|
10220
|
+
expected: expectedMax
|
|
10202
10221
|
});
|
|
10203
10222
|
}
|
|
10204
10223
|
}
|
|
10205
10224
|
if (dbDialect !== "sqlite") {
|
|
10206
10225
|
const currentComment = existingColumn.comment || "";
|
|
10207
|
-
if (currentComment !==
|
|
10226
|
+
if (currentComment !== normalized.name) {
|
|
10208
10227
|
changes.push({
|
|
10209
10228
|
type: "comment",
|
|
10210
10229
|
current: currentComment,
|
|
10211
|
-
expected:
|
|
10230
|
+
expected: normalized.name
|
|
10212
10231
|
});
|
|
10213
10232
|
}
|
|
10214
10233
|
}
|
|
10215
10234
|
const typeMapping = getTypeMapping(dbDialect);
|
|
10216
|
-
const
|
|
10235
|
+
const mapped = typeMapping[normalized.type];
|
|
10236
|
+
if (typeof mapped !== "string") {
|
|
10237
|
+
throw new Error(`\u672A\u77E5\u5B57\u6BB5\u7C7B\u578B\u6620\u5C04\uFF1Adialect=${dbDialect} type=${String(normalized.type)}`);
|
|
10238
|
+
}
|
|
10239
|
+
const expectedType = mapped.toLowerCase();
|
|
10217
10240
|
const currentType = existingColumn.type.toLowerCase();
|
|
10218
10241
|
if (currentType !== expectedType) {
|
|
10219
10242
|
changes.push({
|
|
@@ -10222,7 +10245,7 @@ function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
|
|
|
10222
10245
|
expected: expectedType
|
|
10223
10246
|
});
|
|
10224
10247
|
}
|
|
10225
|
-
const expectedNullable =
|
|
10248
|
+
const expectedNullable = normalized.nullable;
|
|
10226
10249
|
if (existingColumn.nullable !== expectedNullable) {
|
|
10227
10250
|
changes.push({
|
|
10228
10251
|
type: "nullable",
|
|
@@ -10230,7 +10253,7 @@ function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
|
|
|
10230
10253
|
expected: expectedNullable
|
|
10231
10254
|
});
|
|
10232
10255
|
}
|
|
10233
|
-
const expectedDefault = resolveDefaultValue(
|
|
10256
|
+
const expectedDefault = resolveDefaultValue(normalized.default, normalized.type);
|
|
10234
10257
|
if (String(existingColumn.defaultValue) !== String(expectedDefault)) {
|
|
10235
10258
|
changes.push({
|
|
10236
10259
|
type: "default",
|
|
@@ -10390,7 +10413,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
|
|
|
10390
10413
|
const changeLabel = CHANGE_TYPE_LABELS[c.type] || "\u672A\u77E5";
|
|
10391
10414
|
Logger.debug(` ~ \u4FEE\u6539 ${dbFieldName} ${changeLabel}: ${c.current} -> ${c.expected}`);
|
|
10392
10415
|
}
|
|
10393
|
-
if (isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && fieldDef.max
|
|
10416
|
+
if (isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && typeof fieldDef.max === "number") {
|
|
10394
10417
|
if (existingColumns[dbFieldName].max > fieldDef.max) {
|
|
10395
10418
|
Logger.warn(`[\u8DF3\u8FC7\u5371\u9669\u53D8\u66F4] ${tableName}.${dbFieldName} \u957F\u5EA6\u6536\u7F29 ${existingColumns[dbFieldName].max} -> ${fieldDef.max} \u5DF2\u88AB\u8DF3\u8FC7\uFF08\u9700\u624B\u52A8\u5904\u7406\uFF09`);
|
|
10396
10419
|
}
|
|
@@ -10412,7 +10435,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
|
|
|
10412
10435
|
Logger.debug(`[\u517C\u5BB9\u7C7B\u578B\u53D8\u66F4] ${tableName}.${dbFieldName} ${currentType} -> ${expectedType}`);
|
|
10413
10436
|
}
|
|
10414
10437
|
if (defaultChanged) {
|
|
10415
|
-
const actualDefault = resolveDefaultValue(fieldDef.default, fieldDef.type);
|
|
10438
|
+
const actualDefault = resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
|
|
10416
10439
|
let v = null;
|
|
10417
10440
|
if (actualDefault !== "null") {
|
|
10418
10441
|
const defaultSql = generateDefaultSql(actualDefault, fieldDef.type);
|
|
@@ -10432,7 +10455,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
|
|
|
10432
10455
|
}
|
|
10433
10456
|
if (!onlyDefaultChanged) {
|
|
10434
10457
|
let skipModify = false;
|
|
10435
|
-
if (hasLengthChange && isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && fieldDef.max
|
|
10458
|
+
if (hasLengthChange && isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && typeof fieldDef.max === "number") {
|
|
10436
10459
|
const isShrink = existingColumns[dbFieldName].max > fieldDef.max;
|
|
10437
10460
|
if (isShrink)
|
|
10438
10461
|
skipModify = true;
|
|
@@ -10523,8 +10546,8 @@ var calcPerfTime = (startTime, endTime = Bun.nanoseconds()) => {
|
|
|
10523
10546
|
// utils/processInfo.ts
|
|
10524
10547
|
function getProcessRole(env) {
|
|
10525
10548
|
const runtimeEnv = env || {};
|
|
10526
|
-
const bunWorkerId = runtimeEnv
|
|
10527
|
-
const pm2InstanceId = runtimeEnv
|
|
10549
|
+
const bunWorkerId = runtimeEnv["BUN_WORKER_ID"];
|
|
10550
|
+
const pm2InstanceId = runtimeEnv["PM2_INSTANCE_ID"];
|
|
10528
10551
|
if (bunWorkerId !== undefined) {
|
|
10529
10552
|
return {
|
|
10530
10553
|
role: bunWorkerId === "" ? "primary" : "worker",
|
|
@@ -12290,7 +12313,9 @@ class Validator {
|
|
|
12290
12313
|
return this.buildResult(fieldErrors);
|
|
12291
12314
|
}
|
|
12292
12315
|
static single(value, fieldDef) {
|
|
12293
|
-
const
|
|
12316
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
12317
|
+
const type = normalized.type;
|
|
12318
|
+
const defaultValue = normalized.default;
|
|
12294
12319
|
if (value === undefined || value === null || value === "") {
|
|
12295
12320
|
return { value: this.defaultFor(type, defaultValue), error: null };
|
|
12296
12321
|
}
|
|
@@ -12311,7 +12336,7 @@ class Validator {
|
|
|
12311
12336
|
return {
|
|
12312
12337
|
code: failed ? 1 : 0,
|
|
12313
12338
|
failed,
|
|
12314
|
-
firstError: failed ? errors[0] : null,
|
|
12339
|
+
firstError: failed ? errors[0] ?? null : null,
|
|
12315
12340
|
errors,
|
|
12316
12341
|
errorFields,
|
|
12317
12342
|
fieldErrors
|
|
@@ -12359,7 +12384,11 @@ class Validator {
|
|
|
12359
12384
|
}
|
|
12360
12385
|
}
|
|
12361
12386
|
static checkRule(value, fieldDef) {
|
|
12362
|
-
const
|
|
12387
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
12388
|
+
const type = normalized.type;
|
|
12389
|
+
const min = normalized.min;
|
|
12390
|
+
const max = normalized.max;
|
|
12391
|
+
const regexp = normalized.regexp;
|
|
12363
12392
|
const regex = this.resolveRegex(regexp);
|
|
12364
12393
|
switch (type.toLowerCase()) {
|
|
12365
12394
|
case "number":
|
|
@@ -12461,6 +12490,7 @@ var validatorHook = {
|
|
|
12461
12490
|
const rawBody = isPlainObject(ctx.body) ? ctx.body : {};
|
|
12462
12491
|
const nextBody = {};
|
|
12463
12492
|
for (const [field, fieldDef] of Object.entries(ctx.api.fields)) {
|
|
12493
|
+
const normalized = normalizeFieldDefinition(fieldDef);
|
|
12464
12494
|
let value = rawBody[field];
|
|
12465
12495
|
if (value === undefined) {
|
|
12466
12496
|
const snakeField = snakeCase(field);
|
|
@@ -12468,8 +12498,8 @@ var validatorHook = {
|
|
|
12468
12498
|
value = rawBody[snakeField];
|
|
12469
12499
|
}
|
|
12470
12500
|
}
|
|
12471
|
-
if (value === undefined &&
|
|
12472
|
-
value =
|
|
12501
|
+
if (value === undefined && normalized.default !== null) {
|
|
12502
|
+
value = normalized.default;
|
|
12473
12503
|
}
|
|
12474
12504
|
if (value !== undefined) {
|
|
12475
12505
|
nextBody[field] = value;
|
|
@@ -12825,18 +12855,44 @@ class DbUtils {
|
|
|
12825
12855
|
throw new Error("tableRef \u4E0D\u80FD\u4E3A\u7A7A");
|
|
12826
12856
|
}
|
|
12827
12857
|
const parts = trimmed.split(/\s+/).filter((p) => p.length > 0);
|
|
12858
|
+
if (parts.length === 0) {
|
|
12859
|
+
throw new Error("tableRef \u4E0D\u80FD\u4E3A\u7A7A");
|
|
12860
|
+
}
|
|
12828
12861
|
if (parts.length > 2) {
|
|
12829
12862
|
throw new Error(`\u4E0D\u652F\u6301\u7684\u8868\u5F15\u7528\u683C\u5F0F\uFF08\u5305\u542B\u8FC7\u591A\u7247\u6BB5\uFF09\u3002\u8BF7\u4F7F\u7528\u6700\u7B80\u5F62\u5F0F\uFF1Atable \u6216 table alias \u6216 schema.table \u6216 schema.table alias (tableRef: ${trimmed})`);
|
|
12830
12863
|
}
|
|
12831
12864
|
const namePart = parts[0];
|
|
12832
|
-
|
|
12865
|
+
if (typeof namePart !== "string" || namePart.trim() === "") {
|
|
12866
|
+
throw new Error(`tableRef \u89E3\u6790\u5931\u8D25\uFF1A\u7F3A\u5C11\u8868\u540D (tableRef: ${trimmed})`);
|
|
12867
|
+
}
|
|
12868
|
+
let aliasPart = null;
|
|
12869
|
+
if (parts.length === 2) {
|
|
12870
|
+
const alias = parts[1];
|
|
12871
|
+
if (typeof alias !== "string" || alias.trim() === "") {
|
|
12872
|
+
throw new Error(`tableRef \u89E3\u6790\u5931\u8D25\uFF1A\u7F3A\u5C11 alias (tableRef: ${trimmed})`);
|
|
12873
|
+
}
|
|
12874
|
+
aliasPart = alias;
|
|
12875
|
+
}
|
|
12833
12876
|
const nameSegments = namePart.split(".");
|
|
12834
12877
|
if (nameSegments.length > 2) {
|
|
12835
12878
|
throw new Error(`\u4E0D\u652F\u6301\u7684\u8868\u5F15\u7528\u683C\u5F0F\uFF08schema \u5C42\u7EA7\u8FC7\u6DF1\uFF09 (tableRef: ${trimmed})`);
|
|
12836
12879
|
}
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
12880
|
+
if (nameSegments.length === 2) {
|
|
12881
|
+
const schema = nameSegments[0];
|
|
12882
|
+
const table2 = nameSegments[1];
|
|
12883
|
+
if (typeof schema !== "string" || schema.trim() === "") {
|
|
12884
|
+
throw new Error(`tableRef \u89E3\u6790\u5931\u8D25\uFF1Aschema \u4E3A\u7A7A (tableRef: ${trimmed})`);
|
|
12885
|
+
}
|
|
12886
|
+
if (typeof table2 !== "string" || table2.trim() === "") {
|
|
12887
|
+
throw new Error(`tableRef \u89E3\u6790\u5931\u8D25\uFF1Atable \u4E3A\u7A7A (tableRef: ${trimmed})`);
|
|
12888
|
+
}
|
|
12889
|
+
return { schema, table: table2, alias: aliasPart };
|
|
12890
|
+
}
|
|
12891
|
+
const table = nameSegments[0];
|
|
12892
|
+
if (typeof table !== "string" || table.trim() === "") {
|
|
12893
|
+
throw new Error(`tableRef \u89E3\u6790\u5931\u8D25\uFF1Atable \u4E3A\u7A7A (tableRef: ${trimmed})`);
|
|
12894
|
+
}
|
|
12895
|
+
return { schema: null, table, alias: aliasPart };
|
|
12840
12896
|
}
|
|
12841
12897
|
static normalizeTableRef(tableRef) {
|
|
12842
12898
|
const parsed = DbUtils.parseTableRef(tableRef);
|
|
@@ -12914,7 +12970,15 @@ class DbUtils {
|
|
|
12914
12970
|
if (typeof item !== "string" || !item.includes("#")) {
|
|
12915
12971
|
return item;
|
|
12916
12972
|
}
|
|
12917
|
-
const
|
|
12973
|
+
const parts = item.split("#");
|
|
12974
|
+
if (parts.length !== 2) {
|
|
12975
|
+
return item;
|
|
12976
|
+
}
|
|
12977
|
+
const field = parts[0];
|
|
12978
|
+
const direction = parts[1];
|
|
12979
|
+
if (typeof field !== "string" || typeof direction !== "string") {
|
|
12980
|
+
return item;
|
|
12981
|
+
}
|
|
12918
12982
|
return `${snakeCase(field.trim())}#${direction.trim()}`;
|
|
12919
12983
|
});
|
|
12920
12984
|
}
|
|
@@ -12924,14 +12988,26 @@ class DbUtils {
|
|
|
12924
12988
|
}
|
|
12925
12989
|
if (field.toUpperCase().includes(" AS ")) {
|
|
12926
12990
|
const parts = field.split(/\s+AS\s+/i);
|
|
12927
|
-
const fieldPart = parts[0]
|
|
12928
|
-
const aliasPart = parts[1]
|
|
12929
|
-
|
|
12991
|
+
const fieldPart = parts[0];
|
|
12992
|
+
const aliasPart = parts[1];
|
|
12993
|
+
if (typeof fieldPart !== "string" || typeof aliasPart !== "string") {
|
|
12994
|
+
return field;
|
|
12995
|
+
}
|
|
12996
|
+
return `${DbUtils.processJoinField(fieldPart.trim())} AS ${aliasPart.trim()}`;
|
|
12930
12997
|
}
|
|
12931
12998
|
if (field.includes(".")) {
|
|
12932
12999
|
const parts = field.split(".");
|
|
12933
|
-
|
|
12934
|
-
|
|
13000
|
+
if (parts.length < 2) {
|
|
13001
|
+
return snakeCase(field);
|
|
13002
|
+
}
|
|
13003
|
+
if (parts.some((p) => p.trim() === "")) {
|
|
13004
|
+
return field;
|
|
13005
|
+
}
|
|
13006
|
+
const fieldName = parts[parts.length - 1];
|
|
13007
|
+
const tableName = parts.slice(0, parts.length - 1).join(".");
|
|
13008
|
+
if (typeof fieldName !== "string" || typeof tableName !== "string") {
|
|
13009
|
+
return snakeCase(field);
|
|
13010
|
+
}
|
|
12935
13011
|
return `${tableName.trim()}.${snakeCase(fieldName)}`;
|
|
12936
13012
|
}
|
|
12937
13013
|
return snakeCase(field);
|
|
@@ -12946,16 +13022,34 @@ class DbUtils {
|
|
|
12946
13022
|
const operator = key.substring(lastDollarIndex);
|
|
12947
13023
|
if (fieldPart.includes(".")) {
|
|
12948
13024
|
const parts = fieldPart.split(".");
|
|
12949
|
-
|
|
12950
|
-
|
|
13025
|
+
if (parts.length < 2) {
|
|
13026
|
+
return `${snakeCase(fieldPart)}${operator}`;
|
|
13027
|
+
}
|
|
13028
|
+
if (parts.some((p) => p.trim() === "")) {
|
|
13029
|
+
return `${snakeCase(fieldPart)}${operator}`;
|
|
13030
|
+
}
|
|
13031
|
+
const fieldName = parts[parts.length - 1];
|
|
13032
|
+
const tableName = parts.slice(0, parts.length - 1).join(".");
|
|
13033
|
+
if (typeof fieldName !== "string" || typeof tableName !== "string") {
|
|
13034
|
+
return `${snakeCase(fieldPart)}${operator}`;
|
|
13035
|
+
}
|
|
12951
13036
|
return `${tableName.trim()}.${snakeCase(fieldName)}${operator}`;
|
|
12952
13037
|
}
|
|
12953
13038
|
return `${snakeCase(fieldPart)}${operator}`;
|
|
12954
13039
|
}
|
|
12955
13040
|
if (key.includes(".")) {
|
|
12956
13041
|
const parts = key.split(".");
|
|
12957
|
-
|
|
12958
|
-
|
|
13042
|
+
if (parts.length < 2) {
|
|
13043
|
+
return snakeCase(key);
|
|
13044
|
+
}
|
|
13045
|
+
if (parts.some((p) => p.trim() === "")) {
|
|
13046
|
+
return snakeCase(key);
|
|
13047
|
+
}
|
|
13048
|
+
const fieldName = parts[parts.length - 1];
|
|
13049
|
+
const tableName = parts.slice(0, parts.length - 1).join(".");
|
|
13050
|
+
if (typeof fieldName !== "string" || typeof tableName !== "string") {
|
|
13051
|
+
return snakeCase(key);
|
|
13052
|
+
}
|
|
12959
13053
|
return `${tableName.trim()}.${snakeCase(fieldName)}`;
|
|
12960
13054
|
}
|
|
12961
13055
|
return snakeCase(key);
|
|
@@ -12988,7 +13082,15 @@ class DbUtils {
|
|
|
12988
13082
|
if (typeof item !== "string" || !item.includes("#")) {
|
|
12989
13083
|
return item;
|
|
12990
13084
|
}
|
|
12991
|
-
const
|
|
13085
|
+
const parts = item.split("#");
|
|
13086
|
+
if (parts.length !== 2) {
|
|
13087
|
+
return item;
|
|
13088
|
+
}
|
|
13089
|
+
const field = parts[0];
|
|
13090
|
+
const direction = parts[1];
|
|
13091
|
+
if (typeof field !== "string" || typeof direction !== "string") {
|
|
13092
|
+
return item;
|
|
13093
|
+
}
|
|
12992
13094
|
return `${DbUtils.processJoinField(field.trim())}#${direction.trim()}`;
|
|
12993
13095
|
});
|
|
12994
13096
|
}
|
|
@@ -13109,10 +13211,10 @@ class DbUtils {
|
|
|
13109
13211
|
for (const [key, value] of Object.entries(userData)) {
|
|
13110
13212
|
result[key] = value;
|
|
13111
13213
|
}
|
|
13112
|
-
result
|
|
13113
|
-
result
|
|
13114
|
-
result
|
|
13115
|
-
result
|
|
13214
|
+
result["id"] = options.id;
|
|
13215
|
+
result["created_at"] = options.now;
|
|
13216
|
+
result["updated_at"] = options.now;
|
|
13217
|
+
result["state"] = 1;
|
|
13116
13218
|
return result;
|
|
13117
13219
|
}
|
|
13118
13220
|
static buildUpdateRow(options) {
|
|
@@ -13122,7 +13224,7 @@ class DbUtils {
|
|
|
13122
13224
|
for (const [key, value] of Object.entries(userData)) {
|
|
13123
13225
|
result[key] = value;
|
|
13124
13226
|
}
|
|
13125
|
-
result
|
|
13227
|
+
result["updated_at"] = options.now;
|
|
13126
13228
|
return result;
|
|
13127
13229
|
}
|
|
13128
13230
|
static buildPartialUpdateData(options) {
|
|
@@ -13246,6 +13348,7 @@ var SqlBuilderError = {
|
|
|
13246
13348
|
QUOTE_IDENT_NEED_STRING: (identifier) => `quoteIdent \u9700\u8981\u5B57\u7B26\u4E32\u7C7B\u578B\u6807\u8BC6\u7B26 (identifier: ${String(identifier)})`,
|
|
13247
13349
|
IDENT_EMPTY: "SQL \u6807\u8BC6\u7B26\u4E0D\u80FD\u4E3A\u7A7A",
|
|
13248
13350
|
FIELD_EXPR_NOT_ALLOWED: (field) => `\u5B57\u6BB5\u5305\u542B\u51FD\u6570/\u8868\u8FBE\u5F0F\uFF0C\u8BF7\u4F7F\u7528 selectRaw/whereRaw (field: ${field})`,
|
|
13351
|
+
FIELD_INVALID: (field) => `\u5B57\u6BB5\u683C\u5F0F\u975E\u6CD5\uFF0C\u8BF7\u4F7F\u7528\u7B80\u5355\u5B57\u6BB5\u540D\u6216\u5B89\u5168\u5F15\u7528\uFF0C\u590D\u6742\u8868\u8FBE\u5F0F\u8BF7\u4F7F\u7528 selectRaw/whereRaw (field: ${field})`,
|
|
13249
13352
|
FROM_EMPTY: "FROM \u8868\u540D\u4E0D\u80FD\u4E3A\u7A7A",
|
|
13250
13353
|
FROM_NEED_NON_EMPTY: (table) => `FROM \u8868\u540D\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32 (table: ${String(table)})`,
|
|
13251
13354
|
FROM_REQUIRED: "FROM \u8868\u540D\u662F\u5FC5\u9700\u7684",
|
|
@@ -13349,10 +13452,18 @@ class SqlBuilder {
|
|
|
13349
13452
|
}
|
|
13350
13453
|
if (field.toUpperCase().includes(" AS ")) {
|
|
13351
13454
|
const parts = field.split(/\s+AS\s+/i);
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13455
|
+
if (parts.length !== 2) {
|
|
13456
|
+
throw new Error(SqlBuilderError.FIELD_INVALID(field));
|
|
13457
|
+
}
|
|
13458
|
+
const fieldPart = parts[0];
|
|
13459
|
+
const aliasPart = parts[1];
|
|
13460
|
+
if (typeof fieldPart !== "string" || typeof aliasPart !== "string") {
|
|
13461
|
+
throw new Error(SqlBuilderError.FIELD_INVALID(field));
|
|
13462
|
+
}
|
|
13463
|
+
const cleanFieldPart = fieldPart.trim();
|
|
13464
|
+
const cleanAliasPart = aliasPart.trim();
|
|
13465
|
+
SqlCheck.assertSafeAlias(cleanAliasPart);
|
|
13466
|
+
return `${this._escapeField(cleanFieldPart)} AS ${cleanAliasPart}`;
|
|
13356
13467
|
}
|
|
13357
13468
|
if (field.includes(".")) {
|
|
13358
13469
|
const parts = field.split(".");
|
|
@@ -13386,16 +13497,26 @@ class SqlBuilder {
|
|
|
13386
13497
|
if (parts.length > 2) {
|
|
13387
13498
|
throw new Error(SqlBuilderError.TABLE_REF_TOO_MANY_PARTS(table));
|
|
13388
13499
|
}
|
|
13389
|
-
const
|
|
13390
|
-
|
|
13500
|
+
const namePartRaw = parts[0];
|
|
13501
|
+
if (typeof namePartRaw !== "string" || namePartRaw.trim() === "") {
|
|
13502
|
+
throw new Error(SqlBuilderError.FROM_EMPTY);
|
|
13503
|
+
}
|
|
13504
|
+
const namePart = namePartRaw.trim();
|
|
13505
|
+
const aliasPartRaw = parts.length === 2 ? parts[1] : null;
|
|
13506
|
+
const aliasPart = typeof aliasPartRaw === "string" ? aliasPartRaw.trim() : null;
|
|
13391
13507
|
const nameSegments = namePart.split(".");
|
|
13392
13508
|
if (nameSegments.length > 2) {
|
|
13393
13509
|
throw new Error(SqlBuilderError.TABLE_REF_SCHEMA_TOO_DEEP(table));
|
|
13394
13510
|
}
|
|
13395
13511
|
let escapedName = "";
|
|
13396
13512
|
if (nameSegments.length === 2) {
|
|
13397
|
-
const
|
|
13398
|
-
const
|
|
13513
|
+
const schemaRaw = nameSegments[0];
|
|
13514
|
+
const tableNameRaw = nameSegments[1];
|
|
13515
|
+
if (typeof schemaRaw !== "string" || typeof tableNameRaw !== "string") {
|
|
13516
|
+
throw new Error(SqlBuilderError.TABLE_REF_SCHEMA_TOO_DEEP(table));
|
|
13517
|
+
}
|
|
13518
|
+
const schema = schemaRaw.trim();
|
|
13519
|
+
const tableName = tableNameRaw.trim();
|
|
13399
13520
|
const escapedSchema = this._isQuotedIdent(schema) ? schema : (() => {
|
|
13400
13521
|
if (this._startsWithQuote(schema) && !this._isQuotedIdent(schema)) {
|
|
13401
13522
|
throw new Error(SqlBuilderError.SCHEMA_QUOTE_NOT_PAIRED(schema));
|
|
@@ -13412,7 +13533,11 @@ class SqlBuilder {
|
|
|
13412
13533
|
})();
|
|
13413
13534
|
escapedName = `${escapedSchema}.${escapedTableName}`;
|
|
13414
13535
|
} else {
|
|
13415
|
-
const
|
|
13536
|
+
const tableNameRaw = nameSegments[0];
|
|
13537
|
+
if (typeof tableNameRaw !== "string") {
|
|
13538
|
+
throw new Error(SqlBuilderError.FROM_EMPTY);
|
|
13539
|
+
}
|
|
13540
|
+
const tableName = tableNameRaw.trim();
|
|
13416
13541
|
if (this._isQuotedIdent(tableName)) {
|
|
13417
13542
|
escapedName = tableName;
|
|
13418
13543
|
} else {
|
|
@@ -13670,7 +13795,15 @@ class SqlBuilder {
|
|
|
13670
13795
|
if (typeof item !== "string" || !item.includes("#")) {
|
|
13671
13796
|
throw new Error(SqlBuilderError.ORDER_BY_ITEM_NEED_HASH(item));
|
|
13672
13797
|
}
|
|
13673
|
-
const
|
|
13798
|
+
const parts = item.split("#");
|
|
13799
|
+
if (parts.length !== 2) {
|
|
13800
|
+
throw new Error(SqlBuilderError.ORDER_BY_ITEM_NEED_HASH(item));
|
|
13801
|
+
}
|
|
13802
|
+
const fieldName = parts[0];
|
|
13803
|
+
const direction = parts[1];
|
|
13804
|
+
if (typeof fieldName !== "string" || typeof direction !== "string") {
|
|
13805
|
+
throw new Error(SqlBuilderError.ORDER_BY_ITEM_NEED_HASH(item));
|
|
13806
|
+
}
|
|
13674
13807
|
const cleanField = fieldName.trim();
|
|
13675
13808
|
const cleanDir = direction.trim().toUpperCase();
|
|
13676
13809
|
if (!cleanField) {
|
|
@@ -13767,7 +13900,9 @@ class SqlBuilder {
|
|
|
13767
13900
|
for (let i = 0;i < data.length; i++) {
|
|
13768
13901
|
const row = data[i];
|
|
13769
13902
|
for (const field of fields) {
|
|
13770
|
-
|
|
13903
|
+
const value = row[field];
|
|
13904
|
+
this._validateParam(value);
|
|
13905
|
+
params.push(value);
|
|
13771
13906
|
}
|
|
13772
13907
|
}
|
|
13773
13908
|
return { sql, params };
|
|
@@ -13782,7 +13917,12 @@ class SqlBuilder {
|
|
|
13782
13917
|
const escapedFields = fields.map((field) => this._escapeField(field));
|
|
13783
13918
|
const placeholders = fields.map(() => "?").join(", ");
|
|
13784
13919
|
const sql = `INSERT INTO ${escapedTable} (${escapedFields.join(", ")}) VALUES (${placeholders})`;
|
|
13785
|
-
const params =
|
|
13920
|
+
const params = [];
|
|
13921
|
+
for (const field of fields) {
|
|
13922
|
+
const value = data[field];
|
|
13923
|
+
this._validateParam(value);
|
|
13924
|
+
params.push(value);
|
|
13925
|
+
}
|
|
13786
13926
|
return { sql, params };
|
|
13787
13927
|
}
|
|
13788
13928
|
}
|
|
@@ -13884,7 +14024,9 @@ class SqlBuilder {
|
|
|
13884
14024
|
}
|
|
13885
14025
|
whenList.push("WHEN ? THEN ?");
|
|
13886
14026
|
args.push(row.id);
|
|
13887
|
-
|
|
14027
|
+
const value = row.data[field];
|
|
14028
|
+
SqlCheck.assertNoUndefinedParam(value, "SQL \u53C2\u6570\u503C");
|
|
14029
|
+
args.push(value);
|
|
13888
14030
|
}
|
|
13889
14031
|
if (whenList.length === 0) {
|
|
13890
14032
|
continue;
|
|
@@ -13916,7 +14058,7 @@ class DbHelper {
|
|
|
13916
14058
|
constructor(options) {
|
|
13917
14059
|
this.redis = options.redis;
|
|
13918
14060
|
this.sql = options.sql || null;
|
|
13919
|
-
this.isTransaction =
|
|
14061
|
+
this.isTransaction = Boolean(options.sql);
|
|
13920
14062
|
this.dialect = options.dialect ? options.dialect : new MySqlDialect;
|
|
13921
14063
|
}
|
|
13922
14064
|
createSqlBuilder() {
|
|
@@ -14046,7 +14188,8 @@ class DbHelper {
|
|
|
14046
14188
|
}
|
|
14047
14189
|
async getCount(options) {
|
|
14048
14190
|
const { table, where, joins, tableQualifier } = await this.prepareQueryOptions(options);
|
|
14049
|
-
const
|
|
14191
|
+
const hasJoins = Array.isArray(joins) && joins.length > 0;
|
|
14192
|
+
const builder = this.createSqlBuilder().selectRaw("COUNT(*) as count").from(table).where(DbUtils.addDefaultStateFilter(where, tableQualifier, hasJoins));
|
|
14050
14193
|
this.applyJoins(builder, joins);
|
|
14051
14194
|
const { sql, params } = builder.toSelectSql();
|
|
14052
14195
|
const execRes = await this.executeWithConn(sql, params);
|
|
@@ -14058,7 +14201,8 @@ class DbHelper {
|
|
|
14058
14201
|
}
|
|
14059
14202
|
async getOne(options) {
|
|
14060
14203
|
const { table, fields, where, joins, tableQualifier } = await this.prepareQueryOptions(options);
|
|
14061
|
-
const
|
|
14204
|
+
const hasJoins = Array.isArray(joins) && joins.length > 0;
|
|
14205
|
+
const builder = this.createSqlBuilder().select(fields).from(table).where(DbUtils.addDefaultStateFilter(where, tableQualifier, hasJoins));
|
|
14062
14206
|
this.applyJoins(builder, joins);
|
|
14063
14207
|
const { sql, params } = builder.toSelectSql();
|
|
14064
14208
|
const execRes = await this.executeWithConn(sql, params);
|
|
@@ -14066,7 +14210,7 @@ class DbHelper {
|
|
|
14066
14210
|
const row = result?.[0] || null;
|
|
14067
14211
|
if (!row) {
|
|
14068
14212
|
return {
|
|
14069
|
-
data:
|
|
14213
|
+
data: {},
|
|
14070
14214
|
sql: execRes.sql
|
|
14071
14215
|
};
|
|
14072
14216
|
}
|
|
@@ -14074,16 +14218,20 @@ class DbHelper {
|
|
|
14074
14218
|
const deserialized = DbUtils.deserializeArrayFields(camelRow);
|
|
14075
14219
|
if (!deserialized) {
|
|
14076
14220
|
return {
|
|
14077
|
-
data:
|
|
14221
|
+
data: {},
|
|
14078
14222
|
sql: execRes.sql
|
|
14079
14223
|
};
|
|
14080
14224
|
}
|
|
14081
|
-
const
|
|
14225
|
+
const convertedList = convertBigIntFields([deserialized]);
|
|
14226
|
+
const data = convertedList[0] ?? deserialized;
|
|
14082
14227
|
return {
|
|
14083
14228
|
data,
|
|
14084
14229
|
sql: execRes.sql
|
|
14085
14230
|
};
|
|
14086
14231
|
}
|
|
14232
|
+
async getDetail(options) {
|
|
14233
|
+
return await this.getOne(options);
|
|
14234
|
+
}
|
|
14087
14235
|
async getList(options) {
|
|
14088
14236
|
const prepared = await this.prepareQueryOptions(options);
|
|
14089
14237
|
if (prepared.page < 1 || prepared.page > 1e4) {
|
|
@@ -14092,7 +14240,7 @@ class DbHelper {
|
|
|
14092
14240
|
if (prepared.limit < 1 || prepared.limit > 1000) {
|
|
14093
14241
|
throw new Error(`\u6BCF\u9875\u6570\u91CF\u5FC5\u987B\u5728 1 \u5230 1000 \u4E4B\u95F4 (table: ${options.table}, page: ${prepared.page}, limit: ${prepared.limit})`);
|
|
14094
14242
|
}
|
|
14095
|
-
const whereFiltered = DbUtils.addDefaultStateFilter(prepared.where, prepared.tableQualifier,
|
|
14243
|
+
const whereFiltered = DbUtils.addDefaultStateFilter(prepared.where, prepared.tableQualifier, Array.isArray(prepared.joins) && prepared.joins.length > 0);
|
|
14096
14244
|
const countBuilder = this.createSqlBuilder().selectRaw("COUNT(*) as total").from(prepared.table).where(whereFiltered);
|
|
14097
14245
|
this.applyJoins(countBuilder, prepared.joins);
|
|
14098
14246
|
const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
|
|
@@ -14140,8 +14288,21 @@ class DbHelper {
|
|
|
14140
14288
|
async getAll(options) {
|
|
14141
14289
|
const MAX_LIMIT = 1e4;
|
|
14142
14290
|
const WARNING_LIMIT = 1000;
|
|
14143
|
-
const
|
|
14144
|
-
|
|
14291
|
+
const prepareOptions = {
|
|
14292
|
+
table: options.table,
|
|
14293
|
+
page: 1,
|
|
14294
|
+
limit: 10
|
|
14295
|
+
};
|
|
14296
|
+
if (options.fields !== undefined)
|
|
14297
|
+
prepareOptions.fields = options.fields;
|
|
14298
|
+
if (options.where !== undefined)
|
|
14299
|
+
prepareOptions.where = options.where;
|
|
14300
|
+
if (options.joins !== undefined)
|
|
14301
|
+
prepareOptions.joins = options.joins;
|
|
14302
|
+
if (options.orderBy !== undefined)
|
|
14303
|
+
prepareOptions.orderBy = options.orderBy;
|
|
14304
|
+
const prepared = await this.prepareQueryOptions(prepareOptions);
|
|
14305
|
+
const whereFiltered = DbUtils.addDefaultStateFilter(prepared.where, prepared.tableQualifier, Array.isArray(prepared.joins) && prepared.joins.length > 0);
|
|
14145
14306
|
const countBuilder = this.createSqlBuilder().selectRaw("COUNT(*) as total").from(prepared.table).where(whereFiltered);
|
|
14146
14307
|
this.applyJoins(countBuilder, prepared.joins);
|
|
14147
14308
|
const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
|
|
@@ -14201,7 +14362,7 @@ class DbHelper {
|
|
|
14201
14362
|
const builder = this.createSqlBuilder();
|
|
14202
14363
|
const { sql, params } = builder.toInsertSql(snakeTable, processed);
|
|
14203
14364
|
const execRes = await this.executeWithConn(sql, params);
|
|
14204
|
-
const insertedId = processed
|
|
14365
|
+
const insertedId = processed["id"] || execRes.data?.lastInsertRowid || 0;
|
|
14205
14366
|
return {
|
|
14206
14367
|
data: insertedId,
|
|
14207
14368
|
sql: execRes.sql
|
|
@@ -14226,7 +14387,11 @@ class DbHelper {
|
|
|
14226
14387
|
}
|
|
14227
14388
|
const now = Date.now();
|
|
14228
14389
|
const processedList = dataList.map((data, index) => {
|
|
14229
|
-
|
|
14390
|
+
const id = ids[index];
|
|
14391
|
+
if (typeof id !== "number") {
|
|
14392
|
+
throw new Error(`\u6279\u91CF\u63D2\u5165\u751F\u6210 ID \u5931\u8D25\uFF1Aids[${index}] \u4E0D\u662F number (table: ${snakeTable})`);
|
|
14393
|
+
}
|
|
14394
|
+
return DbUtils.buildInsertRow({ data, id, now });
|
|
14230
14395
|
});
|
|
14231
14396
|
const insertFields = SqlCheck.assertBatchInsertRowsConsistent(processedList, { table: snakeTable });
|
|
14232
14397
|
const builder = this.createSqlBuilder();
|
|
@@ -14398,36 +14563,41 @@ class DbHelper {
|
|
|
14398
14563
|
};
|
|
14399
14564
|
}
|
|
14400
14565
|
async getFieldValue(options) {
|
|
14401
|
-
const
|
|
14566
|
+
const field = options.field;
|
|
14402
14567
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(field)) {
|
|
14403
14568
|
throw new Error(`\u65E0\u6548\u7684\u5B57\u6BB5\u540D: ${field}\uFF0C\u53EA\u5141\u8BB8\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF`);
|
|
14404
14569
|
}
|
|
14405
|
-
const
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14570
|
+
const oneOptions = {
|
|
14571
|
+
table: options.table
|
|
14572
|
+
};
|
|
14573
|
+
if (options.where !== undefined)
|
|
14574
|
+
oneOptions.where = options.where;
|
|
14575
|
+
if (options.joins !== undefined)
|
|
14576
|
+
oneOptions.joins = options.joins;
|
|
14577
|
+
if (options.orderBy !== undefined)
|
|
14578
|
+
oneOptions.orderBy = options.orderBy;
|
|
14579
|
+
if (options.page !== undefined)
|
|
14580
|
+
oneOptions.page = options.page;
|
|
14581
|
+
if (options.limit !== undefined)
|
|
14582
|
+
oneOptions.limit = options.limit;
|
|
14583
|
+
oneOptions.fields = [field];
|
|
14584
|
+
const oneRes = await this.getOne(oneOptions);
|
|
14409
14585
|
const result = oneRes.data;
|
|
14410
|
-
if (
|
|
14411
|
-
return {
|
|
14412
|
-
data: null,
|
|
14413
|
-
sql: oneRes.sql
|
|
14414
|
-
};
|
|
14415
|
-
}
|
|
14416
|
-
if (field in result) {
|
|
14586
|
+
if (Object.hasOwn(result, field)) {
|
|
14417
14587
|
return {
|
|
14418
14588
|
data: result[field],
|
|
14419
14589
|
sql: oneRes.sql
|
|
14420
14590
|
};
|
|
14421
14591
|
}
|
|
14422
14592
|
const camelField = field.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
14423
|
-
if (camelField !== field && camelField
|
|
14593
|
+
if (camelField !== field && Object.hasOwn(result, camelField)) {
|
|
14424
14594
|
return {
|
|
14425
14595
|
data: result[camelField],
|
|
14426
14596
|
sql: oneRes.sql
|
|
14427
14597
|
};
|
|
14428
14598
|
}
|
|
14429
14599
|
const snakeField = field.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
14430
|
-
if (snakeField !== field && snakeField
|
|
14600
|
+
if (snakeField !== field && Object.hasOwn(result, snakeField)) {
|
|
14431
14601
|
return {
|
|
14432
14602
|
data: result[snakeField],
|
|
14433
14603
|
sql: oneRes.sql
|
|
@@ -14509,38 +14679,50 @@ class Jwt {
|
|
|
14509
14679
|
};
|
|
14510
14680
|
}
|
|
14511
14681
|
sign(payload, options = {}) {
|
|
14512
|
-
const key = options.secret || this.config.secret
|
|
14682
|
+
const key = options.secret || this.config.secret;
|
|
14513
14683
|
const algorithm = options.algorithm || this.config.algorithm || "HS256";
|
|
14514
|
-
const
|
|
14684
|
+
const signerOptions = {
|
|
14515
14685
|
key,
|
|
14516
14686
|
algorithm,
|
|
14517
|
-
expiresIn: options.expiresIn
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14687
|
+
expiresIn: options.expiresIn ?? this.config.expiresIn
|
|
14688
|
+
};
|
|
14689
|
+
if (options.issuer !== undefined)
|
|
14690
|
+
signerOptions.iss = options.issuer;
|
|
14691
|
+
if (options.audience !== undefined)
|
|
14692
|
+
signerOptions.aud = options.audience;
|
|
14693
|
+
if (options.subject !== undefined)
|
|
14694
|
+
signerOptions.sub = options.subject;
|
|
14695
|
+
if (options.jwtId !== undefined)
|
|
14696
|
+
signerOptions.jti = options.jwtId;
|
|
14697
|
+
if (typeof options.notBefore === "number")
|
|
14698
|
+
signerOptions.notBefore = options.notBefore;
|
|
14699
|
+
const signer = import_fast_jwt.createSigner(signerOptions);
|
|
14524
14700
|
return signer(payload);
|
|
14525
14701
|
}
|
|
14526
14702
|
verify(token, options = {}) {
|
|
14527
14703
|
if (!token || typeof token !== "string") {
|
|
14528
14704
|
throw new Error("Token\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
14529
14705
|
}
|
|
14530
|
-
const key = options.secret || this.config.secret
|
|
14706
|
+
const key = options.secret || this.config.secret;
|
|
14531
14707
|
const algorithm = this.config.algorithm || "HS256";
|
|
14532
14708
|
const algorithms = options.algorithms ? options.algorithms : [algorithm];
|
|
14533
|
-
const
|
|
14709
|
+
const verifierOptions = {
|
|
14534
14710
|
key,
|
|
14535
14711
|
algorithms,
|
|
14536
|
-
allowedIss: options.issuer,
|
|
14537
|
-
allowedAud: options.audience,
|
|
14538
|
-
allowedSub: options.subject,
|
|
14539
|
-
ignoreExpiration: options.ignoreExpiration,
|
|
14540
|
-
ignoreNotBefore: options.ignoreNotBefore,
|
|
14541
14712
|
cache: true,
|
|
14542
14713
|
cacheTTL: 600000
|
|
14543
|
-
}
|
|
14714
|
+
};
|
|
14715
|
+
if (options.issuer !== undefined)
|
|
14716
|
+
verifierOptions.allowedIss = options.issuer;
|
|
14717
|
+
if (options.audience !== undefined)
|
|
14718
|
+
verifierOptions.allowedAud = options.audience;
|
|
14719
|
+
if (options.subject !== undefined)
|
|
14720
|
+
verifierOptions.allowedSub = options.subject;
|
|
14721
|
+
if (typeof options.ignoreExpiration === "boolean")
|
|
14722
|
+
verifierOptions.ignoreExpiration = options.ignoreExpiration;
|
|
14723
|
+
if (typeof options.ignoreNotBefore === "boolean")
|
|
14724
|
+
verifierOptions.ignoreNotBefore = options.ignoreNotBefore;
|
|
14725
|
+
const verifier = import_fast_jwt.createVerifier(verifierOptions);
|
|
14544
14726
|
return verifier(token);
|
|
14545
14727
|
}
|
|
14546
14728
|
decode(token, complete = false) {
|
|
@@ -15151,7 +15333,7 @@ async function scanFiles(dir, source, type, pattern) {
|
|
|
15151
15333
|
const base = {
|
|
15152
15334
|
source,
|
|
15153
15335
|
type,
|
|
15154
|
-
sourceName:
|
|
15336
|
+
sourceName: source === "core" ? "\u6838\u5FC3" : source === "addon" ? "\u7EC4\u4EF6" : "\u9879\u76EE",
|
|
15155
15337
|
filePath: normalizedFile,
|
|
15156
15338
|
relativePath,
|
|
15157
15339
|
fileName,
|
|
@@ -15162,28 +15344,28 @@ async function scanFiles(dir, source, type, pattern) {
|
|
|
15162
15344
|
customKeys: isPlainObject(content) ? Object.keys(content) : []
|
|
15163
15345
|
};
|
|
15164
15346
|
if (type === "table") {
|
|
15165
|
-
base
|
|
15347
|
+
base["content"] = content;
|
|
15166
15348
|
results.push(base);
|
|
15167
15349
|
continue;
|
|
15168
15350
|
}
|
|
15169
15351
|
if (type === "api") {
|
|
15170
|
-
base
|
|
15171
|
-
base
|
|
15172
|
-
base
|
|
15173
|
-
base
|
|
15174
|
-
base
|
|
15352
|
+
base["auth"] = true;
|
|
15353
|
+
base["rawBody"] = false;
|
|
15354
|
+
base["method"] = "POST";
|
|
15355
|
+
base["fields"] = {};
|
|
15356
|
+
base["required"] = [];
|
|
15175
15357
|
}
|
|
15176
15358
|
if (type === "plugin" || type === "hook") {
|
|
15177
|
-
base
|
|
15178
|
-
base
|
|
15179
|
-
base
|
|
15359
|
+
base["deps"] = [];
|
|
15360
|
+
base["name"] = "";
|
|
15361
|
+
base["handler"] = null;
|
|
15180
15362
|
}
|
|
15181
15363
|
forOwn(content, (value, key) => {
|
|
15182
15364
|
base[key] = value;
|
|
15183
15365
|
});
|
|
15184
15366
|
if (type === "api") {
|
|
15185
|
-
base
|
|
15186
|
-
base
|
|
15367
|
+
base["routePrefix"] = source === "app" ? "/app" : `/addon/${addonName}`;
|
|
15368
|
+
base["path"] = `/api${base["routePrefix"]}/${relativePath}`;
|
|
15187
15369
|
}
|
|
15188
15370
|
results.push(base);
|
|
15189
15371
|
}
|
|
@@ -15239,11 +15421,11 @@ class Befly {
|
|
|
15239
15421
|
async start(env = {}) {
|
|
15240
15422
|
try {
|
|
15241
15423
|
const serverStartTime = Bun.nanoseconds();
|
|
15242
|
-
this.config = await loadBeflyConfig(env
|
|
15424
|
+
this.config = await loadBeflyConfig(env["NODE_ENV"] || "development");
|
|
15243
15425
|
this.context.config = this.config;
|
|
15244
15426
|
this.context.env = env;
|
|
15245
15427
|
const { apis, tables, plugins, hooks, addons } = await scanSources();
|
|
15246
|
-
this.context
|
|
15428
|
+
this.context["addons"] = addons;
|
|
15247
15429
|
await checkApi(apis);
|
|
15248
15430
|
await checkTable(tables);
|
|
15249
15431
|
await checkPlugin(plugins);
|
|
@@ -15266,15 +15448,23 @@ class Befly {
|
|
|
15266
15448
|
await syncTable(this.context, tables);
|
|
15267
15449
|
await syncApi(this.context, apis);
|
|
15268
15450
|
await syncMenu(this.context, checkedMenus);
|
|
15269
|
-
|
|
15451
|
+
const devEmail = this.config.devEmail;
|
|
15452
|
+
const devPassword = this.config.devPassword;
|
|
15453
|
+
if (typeof devEmail === "string" && devEmail.length > 0 && typeof devPassword === "string" && devPassword.length > 0) {
|
|
15454
|
+
await syncDev(this.context, { devEmail, devPassword });
|
|
15455
|
+
} else {
|
|
15456
|
+
Logger.debug("\u8DF3\u8FC7 syncDev\uFF1A\u672A\u914D\u7F6E devEmail/devPassword");
|
|
15457
|
+
}
|
|
15270
15458
|
await syncCache(this.context);
|
|
15271
15459
|
this.hooks = await loadHooks(hooks);
|
|
15272
15460
|
this.apis = await loadApis(apis);
|
|
15273
15461
|
const apiFetch = apiHandler(this.apis, this.hooks, this.context);
|
|
15274
15462
|
const staticFetch = staticHandler(this.config.cors);
|
|
15463
|
+
const port = typeof this.config.appPort === "number" ? this.config.appPort : 3000;
|
|
15464
|
+
const hostname = typeof this.config.appHost === "string" && this.config.appHost.length > 0 ? this.config.appHost : "0.0.0.0";
|
|
15275
15465
|
const server = Bun.serve({
|
|
15276
|
-
port
|
|
15277
|
-
hostname
|
|
15466
|
+
port,
|
|
15467
|
+
hostname,
|
|
15278
15468
|
development: this.config.nodeEnv === "development",
|
|
15279
15469
|
idleTimeout: 30,
|
|
15280
15470
|
fetch: async (req, bunServer) => {
|