befly 3.15.2 → 3.15.4

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.
@@ -12,6 +12,7 @@ const defaultOptions = {
12
12
  devPassword: "beflydev123456",
13
13
  bodyLimit: 1048576, // 1MB
14
14
  tz: "Asia/Shanghai",
15
+ strict: true,
15
16
  // ========== 日志配置 ==========
16
17
  logger: {
17
18
  debug: 1,
@@ -24,6 +25,7 @@ const defaultOptions = {
24
25
  },
25
26
  // ========== 数据库配置 ==========
26
27
  db: {
28
+ idMode: "timeId",
27
29
  host: "127.0.0.1",
28
30
  port: 3306,
29
31
  username: "root",
@@ -93,5 +95,17 @@ export async function loadBeflyConfig(nodeEnv) {
93
95
  throw new Error(`配置错误:redis.prefix 不允许包含 ':'(RedisHelper 会自动拼接分隔符 ':'),请改为不带冒号的前缀,例如 'befly_demo',当前值=${redisPrefix}`);
94
96
  }
95
97
  }
98
+ const idMode = config.db?.idMode;
99
+ if (idMode !== undefined && idMode !== "timeId" && idMode !== "autoId") {
100
+ throw new Error(`配置错误:db.idMode 只能是 'timeId' 或 'autoId',当前值=${String(idMode)}`);
101
+ }
102
+ const strict = config.strict;
103
+ if (strict !== undefined && typeof strict !== "boolean") {
104
+ throw new Error(`配置错误:strict 必须为 boolean,当前值=${String(strict)}`);
105
+ }
106
+ const legacyCheckTable = config.checkTable;
107
+ if (legacyCheckTable !== undefined) {
108
+ throw new Error(`配置错误:checkTable 配置已废弃,请使用根属性 strict(例如 { "strict": false }),当前值=${String(legacyCheckTable)}`);
109
+ }
96
110
  return config;
97
111
  }
package/dist/befly.js CHANGED
@@ -7537,6 +7537,7 @@ var defaultOptions = {
7537
7537
  devPassword: "beflydev123456",
7538
7538
  bodyLimit: 1048576,
7539
7539
  tz: "Asia/Shanghai",
7540
+ strict: true,
7540
7541
  logger: {
7541
7542
  debug: 1,
7542
7543
  excludeFields: ["password", "token", "secret"],
@@ -7547,6 +7548,7 @@ var defaultOptions = {
7547
7548
  maxArrayItems: 100
7548
7549
  },
7549
7550
  db: {
7551
+ idMode: "timeId",
7550
7552
  host: "127.0.0.1",
7551
7553
  port: 3306,
7552
7554
  username: "root",
@@ -7602,6 +7604,18 @@ async function loadBeflyConfig(nodeEnv) {
7602
7604
  throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Aredis.prefix \u4E0D\u5141\u8BB8\u5305\u542B ':'\uFF08RedisHelper \u4F1A\u81EA\u52A8\u62FC\u63A5\u5206\u9694\u7B26 ':'\uFF09\uFF0C\u8BF7\u6539\u4E3A\u4E0D\u5E26\u5192\u53F7\u7684\u524D\u7F00\uFF0C\u4F8B\u5982 'befly_demo'\uFF0C\u5F53\u524D\u503C=${redisPrefix}`);
7603
7605
  }
7604
7606
  }
7607
+ const idMode = config2.db?.idMode;
7608
+ if (idMode !== undefined && idMode !== "timeId" && idMode !== "autoId") {
7609
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Adb.idMode \u53EA\u80FD\u662F 'timeId' \u6216 'autoId'\uFF0C\u5F53\u524D\u503C=${String(idMode)}`);
7610
+ }
7611
+ const strict = config2.strict;
7612
+ if (strict !== undefined && typeof strict !== "boolean") {
7613
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Astrict \u5FC5\u987B\u4E3A boolean\uFF0C\u5F53\u524D\u503C=${String(strict)}`);
7614
+ }
7615
+ const legacyCheckTable = config2.checkTable;
7616
+ if (legacyCheckTable !== undefined) {
7617
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AcheckTable \u914D\u7F6E\u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528\u6839\u5C5E\u6027 strict\uFF08\u4F8B\u5982 { "strict": false }\uFF09\uFF0C\u5F53\u524D\u503C=${String(legacyCheckTable)}`);
7618
+ }
7605
7619
  return config2;
7606
7620
  }
7607
7621
 
@@ -7725,6 +7739,19 @@ function isValidPort(value) {
7725
7739
  function isValidNonNegativeInt(value) {
7726
7740
  return typeof value === "number" && Number.isFinite(value) && value >= 0 && Math.floor(value) === value;
7727
7741
  }
7742
+ function isValidPositiveInt(value) {
7743
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 && Math.floor(value) === value;
7744
+ }
7745
+ function isValidTimeZone(value) {
7746
+ if (!isNonEmptyString(value))
7747
+ return false;
7748
+ try {
7749
+ new Intl.DateTimeFormat("en-US", { timeZone: value }).format(0);
7750
+ return true;
7751
+ } catch {
7752
+ return false;
7753
+ }
7754
+ }
7728
7755
  function validateDbConfig(db) {
7729
7756
  if (!db) {
7730
7757
  throw new Error("\u914D\u7F6E\u9519\u8BEF\uFF1A\u7F3A\u5C11 db \u914D\u7F6E\uFF08config.db\uFF09");
@@ -7780,6 +7807,11 @@ async function checkConfig(config2) {
7780
7807
  if (config2.nodeEnv !== "development" && config2.nodeEnv !== "production") {
7781
7808
  throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AnodeEnv \u53EA\u80FD\u662F development/production\uFF0C\u5F53\u524D\u503C=${String(config2.nodeEnv)}`);
7782
7809
  }
7810
+ if (config2.appName !== undefined) {
7811
+ if (!isNonEmptyString(config2.appName)) {
7812
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappName \u5FC5\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5F53\u524D\u503C=${String(config2.appName)}`);
7813
+ }
7814
+ }
7783
7815
  if (config2.appPort !== undefined) {
7784
7816
  if (!isValidPort(config2.appPort)) {
7785
7817
  throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappPort \u5FC5\u987B\u4E3A 1..65535 \u7684\u6570\u5B57\uFF0C\u5F53\u524D\u503C=${String(config2.appPort)}`);
@@ -7790,6 +7822,33 @@ async function checkConfig(config2) {
7790
7822
  throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AappHost \u5FC5\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF0C\u5F53\u524D\u503C=${String(config2.appHost)}`);
7791
7823
  }
7792
7824
  }
7825
+ if (config2.devEmail !== undefined) {
7826
+ if (typeof config2.devEmail !== "string") {
7827
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevEmail \u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\uFF08\u5141\u8BB8\u4E3A\u7A7A\u5B57\u7B26\u4E32\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devEmail)}`);
7828
+ }
7829
+ const trimmedDevEmail = config2.devEmail.trim();
7830
+ if (trimmedDevEmail.length > 0 && !trimmedDevEmail.includes("@")) {
7831
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevEmail \u683C\u5F0F\u9519\u8BEF\uFF08\u5FC5\u987B\u5305\u542B '@'\uFF0C\u6216\u7F6E\u4E3A\u7A7A\u5B57\u7B26\u4E32\u4EE5\u7981\u7528 syncDev\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devEmail)}`);
7832
+ }
7833
+ }
7834
+ if (config2.devPassword !== undefined) {
7835
+ if (typeof config2.devPassword !== "string") {
7836
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AdevPassword \u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\uFF08\u5141\u8BB8\u4E3A\u7A7A\u5B57\u7B26\u4E32\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.devPassword)}`);
7837
+ }
7838
+ }
7839
+ if (config2.bodyLimit !== undefined) {
7840
+ if (!isValidPositiveInt(config2.bodyLimit)) {
7841
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1AbodyLimit \u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF08\u5B57\u8282\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.bodyLimit)}`);
7842
+ }
7843
+ }
7844
+ if (config2.tz !== undefined) {
7845
+ if (!isValidTimeZone(config2.tz)) {
7846
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Atz \u5FC5\u987B\u4E3A\u6709\u6548\u7684 IANA \u65F6\u533A\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 'Asia/Shanghai'\uFF09\uFF0C\u5F53\u524D\u503C=${String(config2.tz)}`);
7847
+ }
7848
+ }
7849
+ if (typeof config2.strict !== "boolean") {
7850
+ throw new Error(`\u914D\u7F6E\u9519\u8BEF\uFF1Astrict \u5FC5\u987B\u4E3A true \u6216 false\uFF0C\u5F53\u524D\u503C=${String(config2.strict)}`);
7851
+ }
7793
7852
  validateDbConfig(config2.db);
7794
7853
  validateRedisConfig(config2.redis);
7795
7854
  }
@@ -8196,7 +8255,7 @@ var FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
8196
8255
  var MAX_VARCHAR_LENGTH = 16383;
8197
8256
  var MAX_INDEX_STRING_LENGTH_FOR_INDEX = 500;
8198
8257
  var MAX_INDEX_STRING_LENGTH_FOR_UNIQUE = 180;
8199
- async function checkTable(tables) {
8258
+ async function checkTable(tables, config2) {
8200
8259
  let hasError = false;
8201
8260
  for (const item of tables) {
8202
8261
  if (item.type !== "table") {
@@ -8285,87 +8344,88 @@ async function checkTable(tables) {
8285
8344
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 default \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A\u53EF JSON \u5E8F\u5217\u5316\u7684\u503C\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
8286
8345
  hasError = true;
8287
8346
  }
8288
- const { name: fieldName, type: fieldType, min: fieldMin, max: fieldMax, default: fieldDefault } = field;
8289
- if (!FIELD_NAME_REGEX.test(fieldName)) {
8290
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u540D\u79F0 "${fieldName}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A\u4E2D\u6587\u3001\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u77ED\u6A2A\u7EBF\u3001\u7A7A\u683C`);
8291
- hasError = true;
8347
+ if (config2.strict) {
8348
+ if (!FIELD_NAME_REGEX.test(field.name)) {
8349
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u540D\u79F0 "${field.name}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A\u4E2D\u6587\u3001\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u77ED\u6A2A\u7EBF\u3001\u7A7A\u683C`);
8350
+ hasError = true;
8351
+ }
8292
8352
  }
8293
- if (!FIELD_TYPE_SET.has(fieldType)) {
8294
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B "${fieldType}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A${FIELD_TYPES.join("\u3001")}\u4E4B\u4E00`);
8353
+ if (!FIELD_TYPE_SET.has(field.type)) {
8354
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B "${field.type}" \u683C\u5F0F\u9519\u8BEF\uFF0C` + `\u5FC5\u987B\u4E3A${FIELD_TYPES.join("\u3001")}\u4E4B\u4E00`);
8295
8355
  hasError = true;
8296
8356
  }
8297
- if (fieldType !== "number" && field.unsigned !== undefined) {
8298
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${fieldType}\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned\uFF08\u4EC5 number \u7C7B\u578B\u6709\u6548\uFF09`);
8357
+ if (field.type !== "number" && field.unsigned !== undefined) {
8358
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${field.type}\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned\uFF08\u4EC5 number \u7C7B\u578B\u6709\u6548\uFF09`);
8299
8359
  hasError = true;
8300
8360
  }
8301
8361
  if (field.unique === true && field.index === true) {
8302
8362
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u540C\u65F6\u8BBE\u7F6E\u4E86 unique=true \u548C index=true\uFF0C` + `unique \u548C index \u4E0D\u80FD\u540C\u65F6\u8BBE\u7F6E\uFF0C\u8BF7\u5220\u9664\u5176\u4E00\uFF08\u5426\u5219\u4F1A\u521B\u5EFA\u91CD\u590D\u7D22\u5F15\uFF09`);
8303
8363
  hasError = true;
8304
8364
  }
8305
- if (fieldMin !== undefined && fieldMax !== undefined && fieldMin !== null && fieldMax !== null) {
8306
- if (fieldMin > fieldMax) {
8307
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5C0F\u503C "${fieldMin}" \u4E0D\u80FD\u5927\u4E8E\u6700\u5927\u503C "${fieldMax}"`);
8365
+ if (field.min !== undefined && field.max !== undefined && field.min !== null && field.max !== null) {
8366
+ if (field.min > field.max) {
8367
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5C0F\u503C "${field.min}" \u4E0D\u80FD\u5927\u4E8E\u6700\u5927\u503C "${field.max}"`);
8308
8368
  hasError = true;
8309
8369
  }
8310
8370
  }
8311
- if (fieldType === "text" || fieldType === "array_text" || fieldType === "array_number_text") {
8312
- if (fieldMin !== undefined && fieldMin !== null) {
8313
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${fieldType} \u7C7B\u578B\u6700\u5C0F\u503C\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${fieldMin}"`);
8371
+ if (field.type === "text" || field.type === "array_text" || field.type === "array_number_text") {
8372
+ if (field.min !== undefined && field.min !== null) {
8373
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${field.type} \u7C7B\u578B\u6700\u5C0F\u503C\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.min}"`);
8314
8374
  hasError = true;
8315
8375
  }
8316
- if (fieldMax !== undefined && fieldMax !== null) {
8317
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${fieldType} \u7C7B\u578B\u6700\u5927\u957F\u5EA6\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${fieldMax}"`);
8376
+ if (field.max !== undefined && field.max !== null) {
8377
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u7684 ${field.type} \u7C7B\u578B\u6700\u5927\u957F\u5EA6\u5E94\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.max}"`);
8318
8378
  hasError = true;
8319
8379
  }
8320
- if (fieldDefault !== undefined && fieldDefault !== null) {
8321
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${fieldDefault}"`);
8380
+ if (field.default !== undefined && field.default !== null) {
8381
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A null\uFF0C\u5F53\u524D\u4E3A "${field.default}"`);
8322
8382
  hasError = true;
8323
8383
  }
8324
8384
  if (field.index === true) {
8325
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u521B\u5EFA\u7D22\u5F15\uFF08index=true \u65E0\u6548\uFF09`);
8385
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u521B\u5EFA\u7D22\u5F15\uFF08index=true \u65E0\u6548\uFF09`);
8326
8386
  hasError = true;
8327
8387
  }
8328
8388
  if (field.unique === true) {
8329
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u552F\u4E00\u7EA6\u675F\uFF08unique=true \u65E0\u6548\uFF09`);
8389
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u4E0D\u652F\u6301\u552F\u4E00\u7EA6\u675F\uFF08unique=true \u65E0\u6548\uFF09`);
8330
8390
  hasError = true;
8331
8391
  }
8332
- } else if (fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string") {
8333
- if (fieldMax === undefined || fieldMax === null || typeof fieldMax !== "number") {
8334
- 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}"`);
8392
+ } else if (field.type === "string" || field.type === "array_string" || field.type === "array_number_string") {
8393
+ if (field.max === undefined || field.max === null || typeof field.max !== "number") {
8394
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \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 "${field.max}"`);
8335
8395
  hasError = true;
8336
- } else if (fieldMax > MAX_VARCHAR_LENGTH) {
8337
- 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`);
8396
+ } else if (field.max > MAX_VARCHAR_LENGTH) {
8397
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u6700\u5927\u957F\u5EA6 ${field.max} \u8D8A\u754C\uFF0C` + `${field.type} \u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728 1..${MAX_VARCHAR_LENGTH} \u8303\u56F4\u5185`);
8338
8398
  hasError = true;
8339
8399
  } else {
8340
- if (field.index === true && fieldMax > MAX_INDEX_STRING_LENGTH_FOR_INDEX) {
8341
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 index=true\uFF0C` + `\u4F46 max=${fieldMax} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_INDEX}\uFF09`);
8400
+ if (field.index === true && field.max > MAX_INDEX_STRING_LENGTH_FOR_INDEX) {
8401
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 index=true\uFF0C` + `\u4F46 max=${field.max} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_INDEX}\uFF09`);
8342
8402
  hasError = true;
8343
8403
  }
8344
- if (field.unique === true && fieldMax > MAX_INDEX_STRING_LENGTH_FOR_UNIQUE) {
8345
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 unique=true\uFF0C` + `\u4F46 max=${fieldMax} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_UNIQUE}\uFF09`);
8404
+ if (field.unique === true && field.max > MAX_INDEX_STRING_LENGTH_FOR_UNIQUE) {
8405
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u8BBE\u7F6E\u4E86 unique=true\uFF0C` + `\u4F46 max=${field.max} \u8D85\u51FA\u5141\u8BB8\u8303\u56F4\uFF08\u8981\u6C42 <= ${MAX_INDEX_STRING_LENGTH_FOR_UNIQUE}\uFF09`);
8346
8406
  hasError = true;
8347
8407
  }
8348
8408
  }
8349
- if (fieldDefault !== undefined && fieldDefault !== null) {
8350
- if (typeof fieldDefault !== "string") {
8351
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\u6216 null` + `\uFF08typeof=${typeof fieldDefault}\uFF0Cvalue=${formatValuePreview(fieldDefault)}\uFF09`);
8409
+ if (field.default !== undefined && field.default !== null) {
8410
+ if (typeof field.default !== "string") {
8411
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
8352
8412
  hasError = true;
8353
- } else if (fieldType !== "string") {
8413
+ } else if (field.type !== "string") {
8354
8414
  try {
8355
- const parsed = JSON.parse(fieldDefault);
8415
+ const parsed = JSON.parse(field.default);
8356
8416
  if (!Array.isArray(parsed)) {
8357
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(fieldDefault)}\uFF09`);
8417
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(field.default)}\uFF09`);
8358
8418
  hasError = true;
8359
8419
  }
8360
8420
  } catch {
8361
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${fieldType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(fieldDefault)}\uFF09`);
8421
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${field.type} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5E94\u4E3A JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF08\u4F8B\u5982 "[]"\uFF09` + `\uFF08value=${formatValuePreview(field.default)}\uFF09`);
8362
8422
  hasError = true;
8363
8423
  }
8364
8424
  }
8365
8425
  }
8366
- } else if (fieldType === "number") {
8367
- if (fieldDefault !== undefined && fieldDefault !== null && typeof fieldDefault !== "number") {
8368
- Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A number \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof fieldDefault}\uFF0Cvalue=${formatValuePreview(fieldDefault)}\uFF09`);
8426
+ } else if (field.type === "number") {
8427
+ if (field.default !== undefined && field.default !== null && typeof field.default !== "number") {
8428
+ Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A number \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
8369
8429
  hasError = true;
8370
8430
  }
8371
8431
  }
@@ -13324,7 +13384,12 @@ class DbUtils {
13324
13384
  for (const [key, value] of Object.entries(userData)) {
13325
13385
  result[key] = value;
13326
13386
  }
13327
- result["id"] = options.id;
13387
+ if (options.idMode === "timeId") {
13388
+ if (!Number.isFinite(options.id) || options.id <= 0) {
13389
+ throw new Error(`buildInsertRow(timeId) \u5931\u8D25\uFF1Aid \u5FC5\u987B\u4E3A > 0 \u7684\u6709\u9650 number (id: ${String(options.id)})`);
13390
+ }
13391
+ result["id"] = options.id;
13392
+ }
13328
13393
  result["created_at"] = options.now;
13329
13394
  result["updated_at"] = options.now;
13330
13395
  result["state"] = 1;
@@ -14095,6 +14160,7 @@ class DbHelper {
14095
14160
  dbName;
14096
14161
  sql = null;
14097
14162
  isTransaction = false;
14163
+ idMode;
14098
14164
  constructor(options) {
14099
14165
  this.redis = options.redis;
14100
14166
  if (typeof options.dbName !== "string" || options.dbName.trim() === "") {
@@ -14103,6 +14169,7 @@ class DbHelper {
14103
14169
  this.dbName = options.dbName;
14104
14170
  this.sql = options.sql || null;
14105
14171
  this.isTransaction = Boolean(options.sql);
14172
+ this.idMode = options.idMode === "autoId" ? "autoId" : "timeId";
14106
14173
  }
14107
14174
  createSqlBuilder() {
14108
14175
  return new SqlBuilder({ quoteIdent: quoteIdentMySql });
@@ -14397,13 +14464,18 @@ class DbHelper {
14397
14464
  const { table, data } = options;
14398
14465
  const snakeTable = snakeCase(table);
14399
14466
  const now = Date.now();
14400
- let id;
14401
- try {
14402
- id = await this.redis.genTimeID();
14403
- } catch (error) {
14404
- throw new Error(`\u751F\u6210 ID \u5931\u8D25\uFF0CRedis \u53EF\u80FD\u4E0D\u53EF\u7528 (table: ${table})`, { cause: error });
14467
+ let processed;
14468
+ if (this.idMode === "autoId") {
14469
+ processed = DbUtils.buildInsertRow({ idMode: "autoId", data, now });
14470
+ } else {
14471
+ let id;
14472
+ try {
14473
+ id = await this.redis.genTimeID();
14474
+ } catch (error) {
14475
+ throw new Error(`\u751F\u6210 ID \u5931\u8D25\uFF0CRedis \u53EF\u80FD\u4E0D\u53EF\u7528 (table: ${table})`, { cause: error });
14476
+ }
14477
+ processed = DbUtils.buildInsertRow({ idMode: "timeId", data, id, now });
14405
14478
  }
14406
- const processed = DbUtils.buildInsertRow({ data, id, now });
14407
14479
  SqlCheck.assertNoUndefinedInRecord(processed, `insData \u63D2\u5165\u6570\u636E (table: ${snakeTable})`);
14408
14480
  const builder = this.createSqlBuilder();
14409
14481
  const { sql, params } = builder.toInsertSql(snakeTable, processed);
@@ -14411,7 +14483,10 @@ class DbHelper {
14411
14483
  const processedId = processed["id"];
14412
14484
  const processedIdNum = typeof processedId === "number" ? processedId : 0;
14413
14485
  const lastInsertRowidNum = toNumberFromSql(execRes.data?.lastInsertRowid);
14414
- const insertedId = processedIdNum || lastInsertRowidNum || 0;
14486
+ const insertedId = this.idMode === "autoId" ? lastInsertRowidNum || 0 : processedIdNum || lastInsertRowidNum || 0;
14487
+ if (this.idMode === "autoId" && insertedId <= 0) {
14488
+ throw new Error(`\u63D2\u5165\u5931\u8D25\uFF1AautoId \u6A21\u5F0F\u4E0B\u65E0\u6CD5\u83B7\u53D6 lastInsertRowid (table: ${table})`);
14489
+ }
14415
14490
  return {
14416
14491
  data: insertedId,
14417
14492
  sql: execRes.sql
@@ -14430,23 +14505,46 @@ class DbHelper {
14430
14505
  throw new Error(`\u6279\u91CF\u63D2\u5165\u6570\u91CF ${dataList.length} \u8D85\u8FC7\u6700\u5927\u9650\u5236 ${MAX_BATCH_SIZE}`);
14431
14506
  }
14432
14507
  const snakeTable = snakeCase(table);
14433
- const ids = [];
14434
- for (let i = 0;i < dataList.length; i++) {
14435
- ids.push(await this.redis.genTimeID());
14436
- }
14437
14508
  const now = Date.now();
14438
- const processedList = dataList.map((data, index) => {
14439
- const id = ids[index];
14440
- if (typeof id !== "number") {
14441
- throw new Error(`\u6279\u91CF\u63D2\u5165\u751F\u6210 ID \u5931\u8D25\uFF1Aids[${index}] \u4E0D\u662F number (table: ${snakeTable})`);
14509
+ let ids = [];
14510
+ let processedList;
14511
+ if (this.idMode === "autoId") {
14512
+ processedList = dataList.map((data) => {
14513
+ return DbUtils.buildInsertRow({ idMode: "autoId", data, now });
14514
+ });
14515
+ } else {
14516
+ const nextIds = [];
14517
+ for (let i = 0;i < dataList.length; i++) {
14518
+ nextIds.push(await this.redis.genTimeID());
14442
14519
  }
14443
- return DbUtils.buildInsertRow({ data, id, now });
14444
- });
14520
+ ids = nextIds;
14521
+ processedList = dataList.map((data, index) => {
14522
+ const id = nextIds[index];
14523
+ if (typeof id !== "number") {
14524
+ throw new Error(`\u6279\u91CF\u63D2\u5165\u751F\u6210 ID \u5931\u8D25\uFF1Aids[${index}] \u4E0D\u662F number (table: ${snakeTable})`);
14525
+ }
14526
+ return DbUtils.buildInsertRow({ idMode: "timeId", data, id, now });
14527
+ });
14528
+ }
14445
14529
  const insertFields = SqlCheck.assertBatchInsertRowsConsistent(processedList, { table: snakeTable });
14446
14530
  const builder = this.createSqlBuilder();
14447
14531
  const { sql, params } = builder.toInsertSql(snakeTable, processedList);
14448
14532
  try {
14449
14533
  const execRes = await this.executeRun(sql, params);
14534
+ if (this.idMode === "autoId") {
14535
+ const firstId = toNumberFromSql(execRes.data?.lastInsertRowid);
14536
+ if (firstId <= 0) {
14537
+ throw new Error(`\u6279\u91CF\u63D2\u5165\u5931\u8D25\uFF1AautoId \u6A21\u5F0F\u4E0B\u65E0\u6CD5\u83B7\u53D6 lastInsertRowid (table: ${table})`);
14538
+ }
14539
+ const outIds = [];
14540
+ for (let i = 0;i < dataList.length; i++) {
14541
+ outIds.push(firstId + i);
14542
+ }
14543
+ return {
14544
+ data: outIds,
14545
+ sql: execRes.sql
14546
+ };
14547
+ }
14450
14548
  return {
14451
14549
  data: ids,
14452
14550
  sql: execRes.sql
@@ -14600,7 +14698,7 @@ class DbHelper {
14600
14698
  throw new Error("\u5F53\u524D SQL \u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u4E8B\u52A1 begin() \u65B9\u6CD5");
14601
14699
  }
14602
14700
  return await sql.begin(async (tx) => {
14603
- const trans = new DbHelper({ redis: this.redis, dbName: this.dbName, sql: tx });
14701
+ const trans = new DbHelper({ redis: this.redis, dbName: this.dbName, sql: tx, idMode: this.idMode });
14604
14702
  return await callback(trans);
14605
14703
  });
14606
14704
  }
@@ -14745,7 +14843,9 @@ var dbPlugin = {
14745
14843
  }
14746
14844
  try {
14747
14845
  const sql = Connect.getSql();
14748
- const dbManager = new DbHelper({ redis: befly.redis, dbName, sql });
14846
+ const idMode = befly.config?.db?.idMode;
14847
+ const normalizedIdMode = idMode === "autoId" ? "autoId" : "timeId";
14848
+ const dbManager = new DbHelper({ redis: befly.redis, dbName, sql, idMode: normalizedIdMode });
14749
14849
  return dbManager;
14750
14850
  } catch (error) {
14751
14851
  Logger.error({ env, err: error, msg: "\u6570\u636E\u5E93\u521D\u59CB\u5316\u5931\u8D25" });
@@ -15533,7 +15633,7 @@ class Befly {
15533
15633
  const { apis, tables, plugins, hooks, addons } = await scanSources();
15534
15634
  this.context["addons"] = addons;
15535
15635
  await checkApi(apis);
15536
- await checkTable(tables);
15636
+ await checkTable(tables, this.config);
15537
15637
  await checkPlugin(plugins);
15538
15638
  await checkHook(hooks);
15539
15639
  const checkedMenus = await checkMenu(addons);