befly 3.14.1 → 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 CHANGED
@@ -8100,10 +8100,10 @@ async function checkTable(tables) {
8100
8100
  hasError = true;
8101
8101
  }
8102
8102
  } else if (fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string") {
8103
- if (fieldMax !== undefined && (fieldMax === null || typeof fieldMax !== "number")) {
8104
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C` + `\u6700\u5927\u957F\u5EA6\u5FC5\u987B\u4E3A\u6570\u5B57\uFF0C\u5F53\u524D\u4E3A "${fieldMax}"`);
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}"`);
8105
8105
  hasError = true;
8106
- } else if (fieldMax !== undefined && fieldMax > MAX_VARCHAR_LENGTH) {
8106
+ } else if (fieldMax > MAX_VARCHAR_LENGTH) {
8107
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`);
8108
8108
  hasError = true;
8109
8109
  }
@@ -8317,46 +8317,14 @@ init_logger();
8317
8317
 
8318
8318
  // loader/loadApis.ts
8319
8319
  init_logger();
8320
-
8321
- // configs/presetFields.ts
8322
- var presetFields = {
8323
- "@id": { name: "ID", type: "number", min: 1, max: null },
8324
- "@page": { name: "\u9875\u7801", type: "number", min: 1, max: 9999, default: 1 },
8325
- "@limit": { name: "\u6BCF\u9875\u6570\u91CF", type: "number", min: 1, max: 100, default: 30 },
8326
- "@keyword": { name: "\u5173\u952E\u8BCD", type: "string", min: 0, max: 50 },
8327
- "@state": { name: "\u72B6\u6001", type: "number", regex: "^[0-2]$" }
8328
- };
8329
-
8330
- // utils/processAtSymbol.ts
8331
- function processAtSymbol(fields, apiName, path) {
8332
- if (!fields || typeof fields !== "object")
8333
- return fields;
8334
- const processed = {};
8335
- for (const [key, value] of Object.entries(fields)) {
8336
- if (typeof value === "string" && value.startsWith("@")) {
8337
- if (presetFields[value]) {
8338
- processed[key] = presetFields[value];
8339
- continue;
8340
- }
8341
- const validKeys = Object.keys(presetFields).join(", ");
8342
- 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}`);
8343
- }
8344
- processed[key] = value;
8345
- }
8346
- return processed;
8347
- }
8348
-
8349
- // loader/loadApis.ts
8350
8320
  async function loadApis(apis) {
8351
8321
  const apisMap = new Map;
8352
8322
  for (const api of apis) {
8353
- if (api.type !== "api") {
8323
+ if (Object.hasOwn(api, "type") && api.type !== "api") {
8354
8324
  continue;
8355
8325
  }
8356
8326
  try {
8357
- const apiRoute = api;
8358
- apiRoute.fields = processAtSymbol(apiRoute.fields || {}, apiRoute.name, apiRoute.path);
8359
- apisMap.set(apiRoute.path, apiRoute);
8327
+ apisMap.set(api.path, api);
8360
8328
  } catch (error) {
8361
8329
  Logger.error({ err: error, api: api.relativePath, file: api.filePath, msg: "\u63A5\u53E3\u52A0\u8F7D\u5931\u8D25" });
8362
8330
  throw error;
@@ -9070,7 +9038,7 @@ async function syncDev(ctx, config2 = {}) {
9070
9038
  apis: allApis.data.lists.map((item) => item.path).filter((v) => v),
9071
9039
  sort: 0
9072
9040
  };
9073
- if (devRole.data) {
9041
+ if (typeof devRole.data.id === "number") {
9074
9042
  await ctx.db.updData({
9075
9043
  table: "addon_admin_role",
9076
9044
  where: { code: "dev" },
@@ -9100,7 +9068,7 @@ async function syncDev(ctx, config2 = {}) {
9100
9068
  table: "addon_admin_admin",
9101
9069
  where: { username: "dev" }
9102
9070
  });
9103
- if (devAdmin.data) {
9071
+ if (typeof devAdmin.data.id === "number") {
9104
9072
  await ctx.db.updData({
9105
9073
  table: "addon_admin_admin",
9106
9074
  where: { username: "dev" },
@@ -9652,6 +9620,25 @@ class SqliteDialect {
9652
9620
 
9653
9621
  // sync/syncTable.ts
9654
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
9655
9642
  init_util();
9656
9643
  var syncTable = async (ctx, items) => {
9657
9644
  try {
@@ -9846,15 +9833,18 @@ function escapeComment(str) {
9846
9833
  return String(str).replace(/"/g, "\\\"");
9847
9834
  }
9848
9835
  function applyFieldDefaults(fieldDef) {
9849
- fieldDef.detail = fieldDef.detail ?? "";
9850
- fieldDef.min = fieldDef.min ?? 0;
9851
- fieldDef.max = fieldDef.max ?? (fieldDef.type === "number" ? Number.MAX_SAFE_INTEGER : 100);
9852
- fieldDef.default = fieldDef.default ?? null;
9853
- fieldDef.index = fieldDef.index ?? false;
9854
- fieldDef.unique = fieldDef.unique ?? false;
9855
- fieldDef.nullable = fieldDef.nullable ?? false;
9856
- fieldDef.unsigned = fieldDef.unsigned ?? true;
9857
- fieldDef.regexp = fieldDef.regexp ?? null;
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;
9858
9848
  }
9859
9849
  function isStringOrArrayType(fieldType) {
9860
9850
  return fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string";
@@ -9953,15 +9943,16 @@ function buildSystemColumnDefs(dbDialect) {
9953
9943
  function buildBusinessColumnDefs(dbDialect, fields) {
9954
9944
  const colDefs = [];
9955
9945
  for (const [fieldKey, fieldDef] of Object.entries(fields)) {
9946
+ const normalized = normalizeFieldDefinition(fieldDef);
9956
9947
  const dbFieldName = snakeCase(fieldKey);
9957
9948
  const colQuoted = quoteIdentifier(dbDialect, dbFieldName);
9958
- const sqlType = getSqlType(dbDialect, fieldDef.type, fieldDef.max, fieldDef.unsigned);
9959
- const actualDefault = resolveDefaultValue(fieldDef.default, fieldDef.type);
9960
- const defaultSql = generateDefaultSql(actualDefault, fieldDef.type);
9961
- const uniqueSql = fieldDef.unique ? " UNIQUE" : "";
9962
- const nullableSql = fieldDef.nullable ? " NULL" : " NOT NULL";
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";
9963
9954
  if (dbDialect === "mysql") {
9964
- colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(fieldDef.name)}"`);
9955
+ colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(normalized.name)}"`);
9965
9956
  } else {
9966
9957
  colDefs.push(`${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql}`);
9967
9958
  }
@@ -9971,13 +9962,14 @@ function buildBusinessColumnDefs(dbDialect, fields) {
9971
9962
  function generateDDLClause(dbDialect, fieldKey, fieldDef, isAdd = false) {
9972
9963
  const dbFieldName = snakeCase(fieldKey);
9973
9964
  const colQuoted = quoteIdentifier(dbDialect, dbFieldName);
9974
- const sqlType = getSqlType(dbDialect, fieldDef.type, fieldDef.max, fieldDef.unsigned);
9975
- const actualDefault = resolveDefaultValue(fieldDef.default, fieldDef.type);
9976
- const defaultSql = generateDefaultSql(actualDefault, fieldDef.type);
9977
- const uniqueSql = fieldDef.unique ? " UNIQUE" : "";
9978
- const nullableSql = fieldDef.nullable ? " NULL" : " NOT NULL";
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";
9979
9971
  if (dbDialect === "mysql") {
9980
- return `${isAdd ? "ADD COLUMN" : "MODIFY COLUMN"} ${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(fieldDef.name)}"`;
9972
+ return `${isAdd ? "ADD COLUMN" : "MODIFY COLUMN"} ${colQuoted} ${sqlType}${uniqueSql}${nullableSql}${defaultSql} COMMENT "${escapeComment(normalized.name)}"`;
9981
9973
  }
9982
9974
  if (dbDialect === "postgresql") {
9983
9975
  if (isAdd)
@@ -10218,29 +10210,31 @@ async function ensureDbVersion(dbDialect, db) {
10218
10210
  }
10219
10211
  function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
10220
10212
  const changes = [];
10221
- if (dbDialect !== "sqlite" && isStringOrArrayType(fieldDef.type)) {
10222
- if (existingColumn.max !== fieldDef.max) {
10213
+ const normalized = normalizeFieldDefinition(fieldDef);
10214
+ if (dbDialect !== "sqlite" && isStringOrArrayType(normalized.type)) {
10215
+ const expectedMax = normalized.max;
10216
+ if (expectedMax !== null && existingColumn.max !== expectedMax) {
10223
10217
  changes.push({
10224
10218
  type: "length",
10225
10219
  current: existingColumn.max,
10226
- expected: fieldDef.max
10220
+ expected: expectedMax
10227
10221
  });
10228
10222
  }
10229
10223
  }
10230
10224
  if (dbDialect !== "sqlite") {
10231
10225
  const currentComment = existingColumn.comment || "";
10232
- if (currentComment !== fieldDef.name) {
10226
+ if (currentComment !== normalized.name) {
10233
10227
  changes.push({
10234
10228
  type: "comment",
10235
10229
  current: currentComment,
10236
- expected: fieldDef.name
10230
+ expected: normalized.name
10237
10231
  });
10238
10232
  }
10239
10233
  }
10240
10234
  const typeMapping = getTypeMapping(dbDialect);
10241
- const mapped = typeMapping[fieldDef.type];
10235
+ const mapped = typeMapping[normalized.type];
10242
10236
  if (typeof mapped !== "string") {
10243
- throw new Error(`\u672A\u77E5\u5B57\u6BB5\u7C7B\u578B\u6620\u5C04\uFF1Adialect=${dbDialect} type=${String(fieldDef.type)}`);
10237
+ throw new Error(`\u672A\u77E5\u5B57\u6BB5\u7C7B\u578B\u6620\u5C04\uFF1Adialect=${dbDialect} type=${String(normalized.type)}`);
10244
10238
  }
10245
10239
  const expectedType = mapped.toLowerCase();
10246
10240
  const currentType = existingColumn.type.toLowerCase();
@@ -10251,7 +10245,7 @@ function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
10251
10245
  expected: expectedType
10252
10246
  });
10253
10247
  }
10254
- const expectedNullable = fieldDef.nullable;
10248
+ const expectedNullable = normalized.nullable;
10255
10249
  if (existingColumn.nullable !== expectedNullable) {
10256
10250
  changes.push({
10257
10251
  type: "nullable",
@@ -10259,7 +10253,7 @@ function compareFieldDefinition(dbDialect, existingColumn, fieldDef) {
10259
10253
  expected: expectedNullable
10260
10254
  });
10261
10255
  }
10262
- const expectedDefault = resolveDefaultValue(fieldDef.default, fieldDef.type);
10256
+ const expectedDefault = resolveDefaultValue(normalized.default, normalized.type);
10263
10257
  if (String(existingColumn.defaultValue) !== String(expectedDefault)) {
10264
10258
  changes.push({
10265
10259
  type: "default",
@@ -10419,7 +10413,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
10419
10413
  const changeLabel = CHANGE_TYPE_LABELS[c.type] || "\u672A\u77E5";
10420
10414
  Logger.debug(` ~ \u4FEE\u6539 ${dbFieldName} ${changeLabel}: ${c.current} -> ${c.expected}`);
10421
10415
  }
10422
- if (isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && fieldDef.max !== null) {
10416
+ if (isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && typeof fieldDef.max === "number") {
10423
10417
  if (existingColumns[dbFieldName].max > fieldDef.max) {
10424
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`);
10425
10419
  }
@@ -10441,7 +10435,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
10441
10435
  Logger.debug(`[\u517C\u5BB9\u7C7B\u578B\u53D8\u66F4] ${tableName}.${dbFieldName} ${currentType} -> ${expectedType}`);
10442
10436
  }
10443
10437
  if (defaultChanged) {
10444
- const actualDefault = resolveDefaultValue(fieldDef.default, fieldDef.type);
10438
+ const actualDefault = resolveDefaultValue(fieldDef.default ?? null, fieldDef.type);
10445
10439
  let v = null;
10446
10440
  if (actualDefault !== "null") {
10447
10441
  const defaultSql = generateDefaultSql(actualDefault, fieldDef.type);
@@ -10461,7 +10455,7 @@ async function modifyTableRuntime(runtime, tableName, fields) {
10461
10455
  }
10462
10456
  if (!onlyDefaultChanged) {
10463
10457
  let skipModify = false;
10464
- if (hasLengthChange && isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && fieldDef.max !== null) {
10458
+ if (hasLengthChange && isStringOrArrayType(fieldDef.type) && existingColumns[dbFieldName].max && typeof fieldDef.max === "number") {
10465
10459
  const isShrink = existingColumns[dbFieldName].max > fieldDef.max;
10466
10460
  if (isShrink)
10467
10461
  skipModify = true;
@@ -12319,7 +12313,9 @@ class Validator {
12319
12313
  return this.buildResult(fieldErrors);
12320
12314
  }
12321
12315
  static single(value, fieldDef) {
12322
- const { type, default: defaultValue } = fieldDef;
12316
+ const normalized = normalizeFieldDefinition(fieldDef);
12317
+ const type = normalized.type;
12318
+ const defaultValue = normalized.default;
12323
12319
  if (value === undefined || value === null || value === "") {
12324
12320
  return { value: this.defaultFor(type, defaultValue), error: null };
12325
12321
  }
@@ -12388,7 +12384,11 @@ class Validator {
12388
12384
  }
12389
12385
  }
12390
12386
  static checkRule(value, fieldDef) {
12391
- const { type, min, max, regexp } = fieldDef;
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;
12392
12392
  const regex = this.resolveRegex(regexp);
12393
12393
  switch (type.toLowerCase()) {
12394
12394
  case "number":
@@ -12490,6 +12490,7 @@ var validatorHook = {
12490
12490
  const rawBody = isPlainObject(ctx.body) ? ctx.body : {};
12491
12491
  const nextBody = {};
12492
12492
  for (const [field, fieldDef] of Object.entries(ctx.api.fields)) {
12493
+ const normalized = normalizeFieldDefinition(fieldDef);
12493
12494
  let value = rawBody[field];
12494
12495
  if (value === undefined) {
12495
12496
  const snakeField = snakeCase(field);
@@ -12497,8 +12498,8 @@ var validatorHook = {
12497
12498
  value = rawBody[snakeField];
12498
12499
  }
12499
12500
  }
12500
- if (value === undefined && fieldDef?.default !== undefined && fieldDef?.default !== null) {
12501
- value = fieldDef.default;
12501
+ if (value === undefined && normalized.default !== null) {
12502
+ value = normalized.default;
12502
12503
  }
12503
12504
  if (value !== undefined) {
12504
12505
  nextBody[field] = value;
@@ -14209,7 +14210,7 @@ class DbHelper {
14209
14210
  const row = result?.[0] || null;
14210
14211
  if (!row) {
14211
14212
  return {
14212
- data: null,
14213
+ data: {},
14213
14214
  sql: execRes.sql
14214
14215
  };
14215
14216
  }
@@ -14217,7 +14218,7 @@ class DbHelper {
14217
14218
  const deserialized = DbUtils.deserializeArrayFields(camelRow);
14218
14219
  if (!deserialized) {
14219
14220
  return {
14220
- data: null,
14221
+ data: {},
14221
14222
  sql: execRes.sql
14222
14223
  };
14223
14224
  }
@@ -14562,36 +14563,41 @@ class DbHelper {
14562
14563
  };
14563
14564
  }
14564
14565
  async getFieldValue(options) {
14565
- const { field, ...queryOptions } = options;
14566
+ const field = options.field;
14566
14567
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(field)) {
14567
14568
  throw new Error(`\u65E0\u6548\u7684\u5B57\u6BB5\u540D: ${field}\uFF0C\u53EA\u5141\u8BB8\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF`);
14568
14569
  }
14569
- const oneRes = await this.getOne({
14570
- ...queryOptions,
14571
- fields: [field]
14572
- });
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);
14573
14585
  const result = oneRes.data;
14574
- if (!result) {
14575
- return {
14576
- data: null,
14577
- sql: oneRes.sql
14578
- };
14579
- }
14580
- if (field in result) {
14586
+ if (Object.hasOwn(result, field)) {
14581
14587
  return {
14582
14588
  data: result[field],
14583
14589
  sql: oneRes.sql
14584
14590
  };
14585
14591
  }
14586
14592
  const camelField = field.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
14587
- if (camelField !== field && camelField in result) {
14593
+ if (camelField !== field && Object.hasOwn(result, camelField)) {
14588
14594
  return {
14589
14595
  data: result[camelField],
14590
14596
  sql: oneRes.sql
14591
14597
  };
14592
14598
  }
14593
14599
  const snakeField = field.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
14594
- if (snakeField !== field && snakeField in result) {
14600
+ if (snakeField !== field && Object.hasOwn(result, snakeField)) {
14595
14601
  return {
14596
14602
  data: result[snakeField],
14597
14603
  sql: oneRes.sql