befly 3.14.2 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/befly.config.js +1 -1
  2. package/dist/befly.js +618 -209
  3. package/dist/befly.min.js +13 -13
  4. package/dist/checks/checkApi.d.ts +1 -1
  5. package/dist/checks/checkApi.js +64 -24
  6. package/dist/checks/checkHook.js +20 -14
  7. package/dist/checks/checkPlugin.js +20 -14
  8. package/dist/checks/checkTable.js +6 -3
  9. package/dist/hooks/permission.js +1 -1
  10. package/dist/lib/cipher.js +3 -4
  11. package/dist/lib/connect.js +2 -1
  12. package/dist/lib/dbDialect.d.ts +4 -4
  13. package/dist/lib/dbDialect.js +3 -12
  14. package/dist/lib/dbHelper.d.ts +8 -3
  15. package/dist/lib/dbHelper.js +85 -35
  16. package/dist/lib/dbUtils.js +2 -2
  17. package/dist/lib/logger.d.ts +6 -11
  18. package/dist/lib/logger.js +15 -10
  19. package/dist/lib/sqlBuilder.js +10 -2
  20. package/dist/lib/validator.d.ts +3 -3
  21. package/dist/lib/validator.js +59 -7
  22. package/dist/loader/loadApis.js +38 -6
  23. package/dist/loader/loadHooks.js +12 -5
  24. package/dist/loader/loadPlugins.js +13 -6
  25. package/dist/plugins/tool.d.ts +11 -9
  26. package/dist/plugins/tool.js +1 -1
  27. package/dist/sync/syncApi.d.ts +2 -2
  28. package/dist/sync/syncApi.js +23 -11
  29. package/dist/sync/syncDev.js +2 -2
  30. package/dist/sync/syncMenu.js +3 -2
  31. package/dist/sync/syncTable.d.ts +22 -26
  32. package/dist/sync/syncTable.js +114 -25
  33. package/dist/types/api.d.ts +11 -10
  34. package/dist/types/befly.d.ts +17 -11
  35. package/dist/types/common.d.ts +23 -6
  36. package/dist/types/context.d.ts +7 -3
  37. package/dist/types/database.d.ts +50 -15
  38. package/dist/types/jwt.d.ts +3 -2
  39. package/dist/types/logger.d.ts +24 -7
  40. package/dist/types/sync.d.ts +7 -7
  41. package/dist/types/validate.d.ts +12 -4
  42. package/dist/utils/convertBigIntFields.d.ts +2 -1
  43. package/dist/utils/convertBigIntFields.js +3 -12
  44. package/dist/utils/isDirentDirectory.d.ts +2 -1
  45. package/dist/utils/loadMenuConfigs.d.ts +1 -1
  46. package/dist/utils/loadMenuConfigs.js +11 -3
  47. package/dist/utils/mergeAndConcat.d.ts +1 -1
  48. package/dist/utils/mergeAndConcat.js +22 -17
  49. package/dist/utils/normalizeFieldDefinition.d.ts +2 -1
  50. package/dist/utils/scanCoreBuiltins.js +9 -5
  51. package/dist/utils/scanFiles.d.ts +2 -2
  52. package/dist/utils/scanFiles.js +1 -1
  53. package/dist/utils/sortModules.js +8 -1
  54. package/dist/utils/sqlParams.d.ts +10 -0
  55. package/dist/utils/sqlParams.js +78 -0
  56. package/dist/utils/sqlResult.d.ts +5 -0
  57. package/dist/utils/sqlResult.js +7 -0
  58. package/dist/utils/util.d.ts +7 -6
  59. package/dist/utils/util.js +8 -5
  60. package/package.json +2 -2
package/dist/befly.js CHANGED
@@ -90,8 +90,9 @@ function forOwn(obj, iteratee) {
90
90
  if (!isPlainObject(obj)) {
91
91
  return;
92
92
  }
93
- for (const key of Object.keys(obj)) {
94
- iteratee(obj[key], key);
93
+ const record = obj;
94
+ for (const key of Object.keys(record)) {
95
+ iteratee(record[key], key);
95
96
  }
96
97
  }
97
98
  function toWordParts(input) {
@@ -559,7 +560,12 @@ class LogFileSink {
559
560
  const ok = this.stream.write(chunk);
560
561
  if (!ok) {
561
562
  await new Promise((resolve) => {
562
- this.stream.once("drain", () => resolve());
563
+ const stream = this.stream;
564
+ if (!stream) {
565
+ resolve();
566
+ return;
567
+ }
568
+ stream.once("drain", () => resolve());
563
569
  });
564
570
  }
565
571
  this.streamSizeBytes = this.streamSizeBytes + chunkBytes;
@@ -829,7 +835,8 @@ function createSinkLogger(options) {
829
835
  const write = (level, record) => {
830
836
  if (level === "debug" && config.debug !== 1)
831
837
  return;
832
- const sanitizedRecord = sanitizeLogObject(record, sanitizeOptions);
838
+ const input = isPlainObject(record) ? record : { value: record };
839
+ const sanitizedRecord = sanitizeLogObject(input, sanitizeOptions);
833
840
  const line = buildLogLine(level, sanitizedRecord);
834
841
  fileSink.enqueue(line);
835
842
  if (consoleSink)
@@ -871,8 +878,8 @@ function metaToObject() {
871
878
  }
872
879
  function mergeMetaIntoObject(input, meta) {
873
880
  const merged = {};
874
- for (const [key, value] of Object.entries(input)) {
875
- merged[key] = value;
881
+ for (const key of Object.keys(input)) {
882
+ merged[key] = input[key];
876
883
  }
877
884
  const keys = ["requestId", "method", "route", "ip", "now", "durationSinceNowMs", "userId", "roleCode", "nickname", "roleType"];
878
885
  for (const key of keys) {
@@ -919,28 +926,27 @@ class LoggerFacade {
919
926
  info(input) {
920
927
  const record0 = withRequestMetaRecord(toRecord(input));
921
928
  const record = this.maybeSanitizeForMock(record0);
922
- return getSink("app").info(record);
929
+ getSink("app").info(record);
923
930
  }
924
931
  warn(input) {
925
932
  const record0 = withRequestMetaRecord(toRecord(input));
926
933
  const record = this.maybeSanitizeForMock(record0);
927
- return getSink("app").warn(record);
934
+ getSink("app").warn(record);
928
935
  }
929
936
  error(input) {
930
937
  const record0 = withRequestMetaRecord(toRecord(input));
931
938
  const record = this.maybeSanitizeForMock(record0);
932
- const ret = getSink("app").error(record);
939
+ getSink("app").error(record);
933
940
  if (mockInstance)
934
- return ret;
941
+ return;
935
942
  getSink("error").error(record);
936
- return ret;
937
943
  }
938
944
  debug(input) {
939
945
  if (config.debug !== 1)
940
946
  return;
941
947
  const record0 = withRequestMetaRecord(toRecord(input));
942
948
  const record = this.maybeSanitizeForMock(record0);
943
- return getSink("app").debug(record);
949
+ getSink("app").debug(record);
944
950
  }
945
951
  async flush() {
946
952
  await flush();
@@ -1255,12 +1261,20 @@ function normalizeViewDirMeta(input) {
1255
1261
  if (!input || typeof input !== "object") {
1256
1262
  return null;
1257
1263
  }
1258
- if (typeof input.title !== "string" || !input.title) {
1264
+ const record = input;
1265
+ const title = record["title"];
1266
+ if (typeof title !== "string" || !title) {
1259
1267
  return null;
1260
1268
  }
1261
- const order = typeof input.order === "number" && Number.isFinite(input.order) && Number.isInteger(input.order) && input.order >= 0 ? input.order : undefined;
1269
+ const orderRaw = record["order"];
1270
+ const order = typeof orderRaw === "number" && Number.isFinite(orderRaw) && Number.isInteger(orderRaw) && orderRaw >= 0 ? orderRaw : undefined;
1271
+ if (order === undefined) {
1272
+ return {
1273
+ title
1274
+ };
1275
+ }
1262
1276
  return {
1263
- title: input.title,
1277
+ title,
1264
1278
  order
1265
1279
  };
1266
1280
  }
@@ -7446,8 +7460,9 @@ function cloneDeepLoose(value) {
7446
7460
  }
7447
7461
  if (isPlainObject(value)) {
7448
7462
  const out = {};
7449
- for (const key of Object.keys(value)) {
7450
- out[key] = cloneDeepLoose(value[key]);
7463
+ const record = value;
7464
+ for (const key of Object.keys(record)) {
7465
+ out[key] = cloneDeepLoose(record[key]);
7451
7466
  }
7452
7467
  return out;
7453
7468
  }
@@ -7458,18 +7473,28 @@ function mergeInto(target, source) {
7458
7473
  return target;
7459
7474
  }
7460
7475
  if (Array.isArray(target) && Array.isArray(source)) {
7476
+ const nextArr = [];
7477
+ for (const item of target) {
7478
+ nextArr.push(cloneDeepLoose(item));
7479
+ }
7461
7480
  for (const item of source) {
7462
- target.push(cloneDeepLoose(item));
7481
+ nextArr.push(cloneDeepLoose(item));
7463
7482
  }
7464
- return target;
7483
+ return nextArr;
7465
7484
  }
7466
7485
  if (isPlainObject(target) && isPlainObject(source)) {
7467
- for (const key of Object.keys(source)) {
7468
- const srcVal = source[key];
7486
+ const targetRecord = target;
7487
+ const sourceRecord = source;
7488
+ const out = {};
7489
+ for (const key of Object.keys(targetRecord)) {
7490
+ out[key] = cloneDeepLoose(targetRecord[key]);
7491
+ }
7492
+ for (const key of Object.keys(sourceRecord)) {
7493
+ const srcVal = sourceRecord[key];
7469
7494
  if (srcVal === undefined) {
7470
7495
  continue;
7471
7496
  }
7472
- const curVal = target[key];
7497
+ const curVal = out[key];
7473
7498
  if (Array.isArray(curVal) && Array.isArray(srcVal)) {
7474
7499
  const nextArr = [];
7475
7500
  for (const item of curVal) {
@@ -7478,16 +7503,16 @@ function mergeInto(target, source) {
7478
7503
  for (const item of srcVal) {
7479
7504
  nextArr.push(cloneDeepLoose(item));
7480
7505
  }
7481
- target[key] = nextArr;
7506
+ out[key] = nextArr;
7482
7507
  continue;
7483
7508
  }
7484
7509
  if (isPlainObject(curVal) && isPlainObject(srcVal)) {
7485
- target[key] = mergeInto(cloneDeepLoose(curVal), srcVal);
7510
+ out[key] = mergeInto(cloneDeepLoose(curVal), srcVal);
7486
7511
  continue;
7487
7512
  }
7488
- target[key] = cloneDeepLoose(srcVal);
7513
+ out[key] = cloneDeepLoose(srcVal);
7489
7514
  }
7490
- return target;
7515
+ return out;
7491
7516
  }
7492
7517
  return cloneDeepLoose(source);
7493
7518
  }
@@ -7571,7 +7596,7 @@ async function loadBeflyConfig(nodeEnv) {
7571
7596
  const envConfig = await importDefault(join(configsDir, `befly.${nodeEnv}.json`), {});
7572
7597
  const config2 = mergeAndConcat(defaultOptions, commonConfig, envConfig);
7573
7598
  config2.nodeEnv = nodeEnv;
7574
- const redisPrefix = config2?.redis?.prefix;
7599
+ const redisPrefix = config2.redis?.prefix;
7575
7600
  if (typeof redisPrefix === "string") {
7576
7601
  const trimmedPrefix = redisPrefix.trim();
7577
7602
  if (trimmedPrefix.includes(":")) {
@@ -7586,63 +7611,100 @@ init_logger();
7586
7611
  init_util();
7587
7612
  async function checkApi(apis) {
7588
7613
  let hasError = false;
7614
+ const seenPaths = new Set;
7589
7615
  for (const api of apis) {
7590
7616
  try {
7591
- if (typeof api?.name !== "string" || api.name.trim() === "") {
7592
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 name \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32" }));
7617
+ if (!isPlainObject(api)) {
7618
+ Logger.warn({ item: api, msg: "\u63A5\u53E3\u5FC5\u987B\u662F\u5BF9\u8C61" });
7619
+ hasError = true;
7620
+ continue;
7621
+ }
7622
+ const record = api;
7623
+ const name = record["name"];
7624
+ if (typeof name !== "string" || name.trim() === "") {
7625
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 name \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32" }));
7593
7626
  hasError = true;
7594
7627
  continue;
7595
7628
  }
7596
- if (typeof api?.handler !== "function") {
7597
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 handler \u5C5E\u6027\u5FC5\u987B\u662F\u51FD\u6570" }));
7629
+ const handler = record["handler"];
7630
+ if (typeof handler !== "function") {
7631
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 handler \u5C5E\u6027\u5FC5\u987B\u662F\u51FD\u6570" }));
7598
7632
  hasError = true;
7599
7633
  continue;
7600
7634
  }
7601
- if (typeof api?.path !== "string" || api.path.trim() === "") {
7602
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7635
+ const rawPath = record["path"];
7636
+ if (typeof rawPath !== "string" || rawPath.trim() === "") {
7637
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7603
7638
  hasError = true;
7604
7639
  } else {
7605
- const path = api.path.trim();
7640
+ const path = rawPath.trim();
7641
+ if (seenPaths.has(path)) {
7642
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u91CD\u590D\uFF08\u4E25\u683C\u6A21\u5F0F\u7981\u6B62\u91CD\u590D path\uFF09" }));
7643
+ hasError = true;
7644
+ } else {
7645
+ seenPaths.add(path);
7646
+ }
7606
7647
  if (/^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/i.test(path)) {
7607
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u5305\u542B method \u524D\u7F00\uFF0C\u5E94\u4E3A url.pathname\uFF08\u4F8B\u5982 /api/app/xxx\uFF09" }));
7648
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u5305\u542B method \u524D\u7F00\uFF0C\u5E94\u4E3A url.pathname\uFF08\u4F8B\u5982 /api/app/xxx\uFF09" }));
7608
7649
  hasError = true;
7609
7650
  }
7610
7651
  if (!path.startsWith("/api/")) {
7611
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u5FC5\u987B\u4EE5 /api/ \u5F00\u5934" }));
7652
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u5FC5\u987B\u4EE5 /api/ \u5F00\u5934" }));
7612
7653
  hasError = true;
7613
7654
  }
7614
7655
  if (path.includes(" ")) {
7615
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u5305\u542B\u7A7A\u683C" }));
7656
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u5305\u542B\u7A7A\u683C" }));
7616
7657
  hasError = true;
7617
7658
  }
7618
7659
  if (path.includes("/api//")) {
7619
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u51FA\u73B0 /api//\uFF08\u91CD\u590D\u659C\u6760\uFF09" }));
7660
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 path \u4E0D\u5141\u8BB8\u51FA\u73B0 /api//\uFF08\u91CD\u590D\u659C\u6760\uFF09" }));
7620
7661
  hasError = true;
7621
7662
  }
7622
7663
  }
7623
- if (typeof api?.routePrefix !== "string" || api.routePrefix.trim() === "") {
7624
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 routePrefix \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7664
+ const routePrefix = record["routePrefix"];
7665
+ const routePrefixTrimmed = typeof routePrefix === "string" ? routePrefix.trim() : "";
7666
+ if (routePrefixTrimmed === "") {
7667
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 routePrefix \u5C5E\u6027\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7625
7668
  hasError = true;
7669
+ } else {
7670
+ if (!(routePrefixTrimmed === "/app" || routePrefixTrimmed.startsWith("/addon/"))) {
7671
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 routePrefix \u5FC5\u987B\u662F /app \u6216 /addon/<name>\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7672
+ hasError = true;
7673
+ }
7674
+ if (typeof rawPath === "string" && rawPath.trim() !== "") {
7675
+ const path = rawPath.trim();
7676
+ const expectedPrefix = `/api${routePrefixTrimmed}/`;
7677
+ if (!path.startsWith(expectedPrefix)) {
7678
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { expectedPrefix, msg: "\u63A5\u53E3\u7684 path \u4E0E routePrefix \u4E0D\u4E00\u81F4\uFF1A\u5E94\u4EE5 /api${routePrefix}/ \u5F00\u5934\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF09" }));
7679
+ hasError = true;
7680
+ }
7681
+ }
7626
7682
  }
7627
- if (api.method && !["GET", "POST", "GET,POST", "POST,GET"].includes(String(api.method).toUpperCase())) {
7628
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 method \u5C5E\u6027\u5FC5\u987B\u662F\u6709\u6548\u7684 HTTP \u65B9\u6CD5 (GET, POST, GET,POST, POST,GET)" }));
7683
+ const method = record["method"];
7684
+ if (method !== undefined && !["GET", "POST", "GET,POST"].includes(String(method).toUpperCase())) {
7685
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 method \u5C5E\u6027\u5FC5\u987B\u662F\u6709\u6548\u7684 HTTP \u65B9\u6CD5 (GET, POST, GET,POST)" }));
7629
7686
  hasError = true;
7630
7687
  }
7631
- if (api.auth !== undefined && typeof api.auth !== "boolean") {
7632
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 auth \u5C5E\u6027\u5FC5\u987B\u662F\u5E03\u5C14\u503C (true=\u9700\u767B\u5F55, false=\u516C\u5F00)" }));
7688
+ const auth = record["auth"];
7689
+ if (auth !== undefined && typeof auth !== "boolean") {
7690
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 auth \u5C5E\u6027\u5FC5\u987B\u662F\u5E03\u5C14\u503C (true=\u9700\u767B\u5F55, false=\u516C\u5F00)" }));
7633
7691
  hasError = true;
7634
7692
  }
7635
- if (api.fields && !isPlainObject(api.fields)) {
7636
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 fields \u5C5E\u6027\u5FC5\u987B\u662F\u5BF9\u8C61" }));
7693
+ const fields = record["fields"];
7694
+ if (fields !== undefined && fields !== null && !isPlainObject(fields)) {
7695
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 fields \u5C5E\u6027\u5FC5\u987B\u662F\u5BF9\u8C61" }));
7637
7696
  hasError = true;
7638
7697
  }
7639
- if (api.required && !Array.isArray(api.required)) {
7640
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 required \u5C5E\u6027\u5FC5\u987B\u662F\u6570\u7EC4" }));
7698
+ const required = record["required"];
7699
+ if (required !== undefined && !Array.isArray(required)) {
7700
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 required \u5C5E\u6027\u5FC5\u987B\u662F\u6570\u7EC4" }));
7641
7701
  hasError = true;
7642
7702
  }
7643
- if (api.required && api.required.some((reqItem) => typeof reqItem !== "string")) {
7644
- Logger.warn(Object.assign({}, omit(api, ["handler"]), { msg: "\u63A5\u53E3\u7684 required \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7645
- hasError = true;
7703
+ if (Array.isArray(required)) {
7704
+ if (required.some((reqItem) => typeof reqItem !== "string")) {
7705
+ Logger.warn(Object.assign({}, omit(record, ["handler"]), { msg: "\u63A5\u53E3\u7684 required \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7706
+ hasError = true;
7707
+ }
7646
7708
  }
7647
7709
  } catch (error) {
7648
7710
  Logger.error({ err: error, item: api, msg: "\u63A5\u53E3\u89E3\u6790\u5931\u8D25" });
@@ -7668,12 +7730,14 @@ async function checkHook(hooks) {
7668
7730
  hasError = true;
7669
7731
  continue;
7670
7732
  }
7671
- if (typeof hook.moduleName !== "string" || hook.moduleName.trim() === "") {
7733
+ const record = hook;
7734
+ const moduleName = record["moduleName"];
7735
+ if (typeof moduleName !== "string" || moduleName.trim() === "") {
7672
7736
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u7684 moduleName \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF0C\u7528\u4E8E deps \u4E0E\u8FD0\u884C\u65F6\u6302\u8F7D\uFF09" }));
7673
7737
  hasError = true;
7674
7738
  continue;
7675
7739
  }
7676
- const customKeys = hook.customKeys;
7740
+ const customKeys = record["customKeys"];
7677
7741
  if (!Array.isArray(customKeys)) {
7678
7742
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u626B\u63CF\u7ED3\u679C\u7F3A\u5C11 customKeys\uFF08\u65E0\u6CD5\u5224\u65AD\u7528\u6237\u5BFC\u51FA\u7684\u5B57\u6BB5\u662F\u5426\u5408\u6CD5\uFF09" }));
7679
7743
  hasError = true;
@@ -7693,16 +7757,17 @@ async function checkHook(hooks) {
7693
7757
  const hasCustomEnable = customKeys.includes("enable");
7694
7758
  const hasCustomDeps = customKeys.includes("deps");
7695
7759
  if (hasCustomEnable) {
7696
- if (typeof hook.enable !== "boolean") {
7760
+ const enable = record["enable"];
7761
+ if (typeof enable !== "boolean") {
7697
7762
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u7684 enable \u5C5E\u6027\u5FC5\u987B\u662F boolean\uFF08true/false\uFF09\uFF0C\u4E0D\u5141\u8BB8 0/1 \u7B49\u5176\u4ED6\u7C7B\u578B" }));
7698
7763
  hasError = true;
7699
7764
  continue;
7700
7765
  }
7701
7766
  } else {
7702
- hook.enable = true;
7767
+ record["enable"] = true;
7703
7768
  }
7704
- if (hook.source === "core") {
7705
- const name = typeof hook.name === "string" ? hook.name : "";
7769
+ if (record["source"] === "core") {
7770
+ const name = typeof record["name"] === "string" ? record["name"] : "";
7706
7771
  if (name === "") {
7707
7772
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "core \u5185\u7F6E\u94A9\u5B50\u5FC5\u987B\u663E\u5F0F\u8BBE\u7F6E name\uFF08string\uFF09\uFF0C\u7528\u4E8E\u786E\u5B9A\u94A9\u5B50\u540D\u79F0" }));
7708
7773
  hasError = true;
@@ -7713,39 +7778,42 @@ async function checkHook(hooks) {
7713
7778
  hasError = true;
7714
7779
  continue;
7715
7780
  }
7716
- if (!coreBuiltinNameRegexp.test(hook.moduleName)) {
7781
+ if (!coreBuiltinNameRegexp.test(String(record["moduleName"]))) {
7717
7782
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "core \u5185\u7F6E\u94A9\u5B50\u7684 moduleName \u5FC5\u987B\u6EE1\u8DB3\u5C0F\u5199\u5B57\u6BCD+\u4E0B\u5212\u7EBF\u683C\u5F0F\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF0C\u4E14\u5FC5\u987B\u4E0E name \u4E00\u81F4\uFF09" }));
7718
7783
  hasError = true;
7719
7784
  continue;
7720
7785
  }
7721
- if (name !== hook.moduleName) {
7786
+ if (name !== String(record["moduleName"])) {
7722
7787
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "core \u5185\u7F6E\u94A9\u5B50\u7684 name \u5FC5\u987B\u4E0E moduleName \u5B8C\u5168\u4E00\u81F4" }));
7723
7788
  hasError = true;
7724
7789
  continue;
7725
7790
  }
7726
- if (typeof hook.filePath !== "string" || !hook.filePath.startsWith(`core:hook:${name}`)) {
7791
+ const filePath = record["filePath"];
7792
+ if (typeof filePath !== "string" || !filePath.startsWith(`core:hook:${name}`)) {
7727
7793
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "core \u5185\u7F6E\u94A9\u5B50\u5FC5\u987B\u6765\u81EA\u9759\u6001\u6CE8\u518C\uFF08filePath \u5FC5\u987B\u4EE5 core:hook:<name> \u5F00\u5934\uFF09\uFF0C\u4E0D\u5141\u8BB8\u901A\u8FC7\u626B\u63CF\u76EE\u5F55\u52A0\u8F7D" }));
7728
7794
  hasError = true;
7729
7795
  continue;
7730
7796
  }
7731
7797
  }
7732
7798
  if (hasCustomDeps) {
7733
- if (!Array.isArray(hook.deps)) {
7799
+ const deps = record["deps"];
7800
+ if (!Array.isArray(deps)) {
7734
7801
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u7684 deps \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7735
7802
  hasError = true;
7736
7803
  continue;
7737
7804
  }
7738
- if (hook.deps.some((depItem) => typeof depItem !== "string")) {
7805
+ if (deps.some((depItem) => typeof depItem !== "string")) {
7739
7806
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u7684 deps \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7740
7807
  hasError = true;
7741
7808
  continue;
7742
7809
  }
7743
7810
  } else {
7744
- if (!Array.isArray(hook.deps)) {
7745
- hook.deps = [];
7811
+ const deps = record["deps"];
7812
+ if (!Array.isArray(deps)) {
7813
+ record["deps"] = [];
7746
7814
  }
7747
7815
  }
7748
- if (typeof hook.handler !== "function") {
7816
+ if (typeof record["handler"] !== "function") {
7749
7817
  Logger.warn(Object.assign({}, omit(hook, ["handler"]), { msg: "\u94A9\u5B50\u7684 handler \u5C5E\u6027\u5FC5\u987B\u662F\u51FD\u6570" }));
7750
7818
  hasError = true;
7751
7819
  continue;
@@ -7880,12 +7948,14 @@ async function checkPlugin(plugins) {
7880
7948
  hasError = true;
7881
7949
  continue;
7882
7950
  }
7883
- if (typeof plugin.moduleName !== "string" || plugin.moduleName.trim() === "") {
7951
+ const record = plugin;
7952
+ const moduleName = record["moduleName"];
7953
+ if (typeof moduleName !== "string" || moduleName.trim() === "") {
7884
7954
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u7684 moduleName \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF0C\u7528\u4E8E deps \u4E0E\u8FD0\u884C\u65F6\u6302\u8F7D\uFF09" }));
7885
7955
  hasError = true;
7886
7956
  continue;
7887
7957
  }
7888
- const customKeys = plugin.customKeys;
7958
+ const customKeys = record["customKeys"];
7889
7959
  if (!Array.isArray(customKeys)) {
7890
7960
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u626B\u63CF\u7ED3\u679C\u7F3A\u5C11 customKeys\uFF08\u65E0\u6CD5\u5224\u65AD\u7528\u6237\u5BFC\u51FA\u7684\u5B57\u6BB5\u662F\u5426\u5408\u6CD5\uFF09" }));
7891
7961
  hasError = true;
@@ -7905,16 +7975,17 @@ async function checkPlugin(plugins) {
7905
7975
  const hasCustomEnable = customKeys.includes("enable");
7906
7976
  const hasCustomDeps = customKeys.includes("deps");
7907
7977
  if (hasCustomEnable) {
7908
- if (typeof plugin.enable !== "boolean") {
7978
+ const enable = record["enable"];
7979
+ if (typeof enable !== "boolean") {
7909
7980
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u7684 enable \u5C5E\u6027\u5FC5\u987B\u662F boolean\uFF08true/false\uFF09\uFF0C\u4E0D\u5141\u8BB8 0/1 \u7B49\u5176\u4ED6\u7C7B\u578B" }));
7910
7981
  hasError = true;
7911
7982
  continue;
7912
7983
  }
7913
7984
  } else {
7914
- plugin.enable = true;
7985
+ record["enable"] = true;
7915
7986
  }
7916
- if (plugin.source === "core") {
7917
- const name = typeof plugin.name === "string" ? plugin.name : "";
7987
+ if (record["source"] === "core") {
7988
+ const name = typeof record["name"] === "string" ? record["name"] : "";
7918
7989
  if (name === "") {
7919
7990
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "core \u5185\u7F6E\u63D2\u4EF6\u5FC5\u987B\u663E\u5F0F\u8BBE\u7F6E name\uFF08string\uFF09\uFF0C\u7528\u4E8E\u786E\u5B9A\u63D2\u4EF6\u540D\u79F0" }));
7920
7991
  hasError = true;
@@ -7925,39 +7996,42 @@ async function checkPlugin(plugins) {
7925
7996
  hasError = true;
7926
7997
  continue;
7927
7998
  }
7928
- if (!coreBuiltinNameRegexp.test(plugin.moduleName)) {
7999
+ if (!coreBuiltinNameRegexp.test(String(record["moduleName"]))) {
7929
8000
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "core \u5185\u7F6E\u63D2\u4EF6\u7684 moduleName \u5FC5\u987B\u6EE1\u8DB3\u5C0F\u5199\u5B57\u6BCD+\u4E0B\u5212\u7EBF\u683C\u5F0F\uFF08\u7531\u7CFB\u7EDF\u751F\u6210\uFF0C\u4E14\u5FC5\u987B\u4E0E name \u4E00\u81F4\uFF09" }));
7930
8001
  hasError = true;
7931
8002
  continue;
7932
8003
  }
7933
- if (name !== plugin.moduleName) {
8004
+ if (name !== String(record["moduleName"])) {
7934
8005
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "core \u5185\u7F6E\u63D2\u4EF6\u7684 name \u5FC5\u987B\u4E0E moduleName \u5B8C\u5168\u4E00\u81F4" }));
7935
8006
  hasError = true;
7936
8007
  continue;
7937
8008
  }
7938
- if (typeof plugin.filePath !== "string" || !plugin.filePath.startsWith(`core:plugin:${name}`)) {
8009
+ const filePath = record["filePath"];
8010
+ if (typeof filePath !== "string" || !filePath.startsWith(`core:plugin:${name}`)) {
7939
8011
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "core \u5185\u7F6E\u63D2\u4EF6\u5FC5\u987B\u6765\u81EA\u9759\u6001\u6CE8\u518C\uFF08filePath \u5FC5\u987B\u4EE5 core:plugin:<name> \u5F00\u5934\uFF09\uFF0C\u4E0D\u5141\u8BB8\u901A\u8FC7\u626B\u63CF\u76EE\u5F55\u52A0\u8F7D" }));
7940
8012
  hasError = true;
7941
8013
  continue;
7942
8014
  }
7943
8015
  }
7944
8016
  if (hasCustomDeps) {
7945
- if (!Array.isArray(plugin.deps)) {
8017
+ const deps = record["deps"];
8018
+ if (!Array.isArray(deps)) {
7946
8019
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u7684 deps \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7947
8020
  hasError = true;
7948
8021
  continue;
7949
8022
  }
7950
- if (plugin.deps.some((depItem) => typeof depItem !== "string")) {
8023
+ if (deps.some((depItem) => typeof depItem !== "string")) {
7951
8024
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u7684 deps \u5C5E\u6027\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4" }));
7952
8025
  hasError = true;
7953
8026
  continue;
7954
8027
  }
7955
8028
  } else {
7956
- if (!Array.isArray(plugin.deps)) {
7957
- plugin.deps = [];
8029
+ const deps = record["deps"];
8030
+ if (!Array.isArray(deps)) {
8031
+ record["deps"] = [];
7958
8032
  }
7959
8033
  }
7960
- if (typeof plugin.handler !== "function") {
8034
+ if (typeof record["handler"] !== "function") {
7961
8035
  Logger.warn(Object.assign({}, omit(plugin, ["handler"]), { msg: "\u63D2\u4EF6\u7684 handler \u5C5E\u6027\u5FC5\u987B\u662F\u51FD\u6570" }));
7962
8036
  hasError = true;
7963
8037
  continue;
@@ -7975,8 +8049,11 @@ async function checkPlugin(plugins) {
7975
8049
  // checks/checkTable.ts
7976
8050
  init_logger();
7977
8051
  var RESERVED_FIELDS = ["id", "created_at", "updated_at", "deleted_at", "state"];
8052
+ var RESERVED_FIELD_SET = new Set(RESERVED_FIELDS);
7978
8053
  var FIELD_TYPES = ["string", "number", "text", "array_string", "array_text", "array_number_string", "array_number_text"];
8054
+ var FIELD_TYPE_SET = new Set(FIELD_TYPES);
7979
8055
  var ALLOWED_FIELD_PROPERTIES = ["name", "type", "min", "max", "default", "detail", "index", "unique", "nullable", "unsigned", "regexp"];
8056
+ var ALLOWED_FIELD_PROPERTY_SET = new Set(ALLOWED_FIELD_PROPERTIES);
7980
8057
  var LOWER_CAMEL_CASE_REGEX = /^_?[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
7981
8058
  var FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
7982
8059
  var MAX_VARCHAR_LENGTH = 65535;
@@ -8002,13 +8079,13 @@ async function checkTable(tables) {
8002
8079
  hasError = true;
8003
8080
  continue;
8004
8081
  }
8005
- if (RESERVED_FIELDS.includes(colKey)) {
8082
+ if (RESERVED_FIELD_SET.has(colKey)) {
8006
8083
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6\u5305\u542B\u4FDD\u7559\u5B57\u6BB5 ${colKey}\uFF0C` + `\u4E0D\u80FD\u5728\u8868\u5B9A\u4E49\u4E2D\u4F7F\u7528\u4EE5\u4E0B\u5B57\u6BB5: ${RESERVED_FIELDS.join(", ")}`);
8007
8084
  hasError = true;
8008
8085
  }
8009
8086
  const field = fieldDef;
8010
8087
  const fieldKeys = Object.keys(field);
8011
- const illegalProps = fieldKeys.filter((key) => !ALLOWED_FIELD_PROPERTIES.includes(key));
8088
+ const illegalProps = fieldKeys.filter((key) => !ALLOWED_FIELD_PROPERTY_SET.has(key));
8012
8089
  if (illegalProps.length > 0) {
8013
8090
  Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5305\u542B\u975E\u6CD5\u5C5E\u6027: ${illegalProps.join(", ")}\uFF0C` + `\u5141\u8BB8\u7684\u5C5E\u6027\u4E3A: ${ALLOWED_FIELD_PROPERTIES.join(", ")}`);
8014
8091
  hasError = true;
@@ -8060,7 +8137,7 @@ async function checkTable(tables) {
8060
8137
  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`);
8061
8138
  hasError = true;
8062
8139
  }
8063
- if (!FIELD_TYPES.includes(fieldType)) {
8140
+ if (!FIELD_TYPE_SET.has(fieldType)) {
8064
8141
  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`);
8065
8142
  hasError = true;
8066
8143
  }
@@ -8266,7 +8343,8 @@ class Connect {
8266
8343
  await this.connectSql(config2.db || {});
8267
8344
  await this.connectRedis(config2.redis || {});
8268
8345
  } catch (error) {
8269
- Logger.error({ env: config2.nodeEnv, err: error, msg: "\u6570\u636E\u5E93\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25" });
8346
+ const env = typeof process?.env?.NODE_ENV === "string" ? "development" : "";
8347
+ Logger.error({ env, err: error, msg: "\u6570\u636E\u5E93\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25" });
8270
8348
  await this.disconnect();
8271
8349
  throw error;
8272
8350
  }
@@ -8320,11 +8398,42 @@ init_logger();
8320
8398
  async function loadApis(apis) {
8321
8399
  const apisMap = new Map;
8322
8400
  for (const api of apis) {
8323
- if (Object.hasOwn(api, "type") && api.type !== "api") {
8324
- continue;
8325
- }
8326
8401
  try {
8327
- apisMap.set(api.path, api);
8402
+ if (Object.hasOwn(api, "type") && api.type !== "api") {
8403
+ continue;
8404
+ }
8405
+ const record = api;
8406
+ const path = record["path"];
8407
+ const route = {
8408
+ name: record["name"],
8409
+ handler: record["handler"],
8410
+ route: path
8411
+ };
8412
+ const method = record["method"];
8413
+ if (typeof method === "string") {
8414
+ const upperMethod = method.toUpperCase();
8415
+ const normalized = upperMethod === "POST,GET" ? "GET,POST" : upperMethod;
8416
+ route.method = ["GET", "POST", "GET,POST"].includes(normalized) ? normalized : "POST";
8417
+ } else {
8418
+ route.method = "POST";
8419
+ }
8420
+ const auth = record["auth"];
8421
+ if (auth !== undefined) {
8422
+ route.auth = auth;
8423
+ }
8424
+ const fields = record["fields"];
8425
+ if (fields !== undefined) {
8426
+ route.fields = fields;
8427
+ }
8428
+ const required = record["required"];
8429
+ if (required !== undefined) {
8430
+ route.required = required;
8431
+ }
8432
+ const rawBody = record["rawBody"];
8433
+ if (rawBody !== undefined) {
8434
+ route.rawBody = rawBody;
8435
+ }
8436
+ apisMap.set(path, route);
8328
8437
  } catch (error) {
8329
8438
  Logger.error({ err: error, api: api.relativePath, file: api.filePath, msg: "\u63A5\u53E3\u52A0\u8F7D\u5931\u8D25" });
8330
8439
  throw error;
@@ -8345,7 +8454,13 @@ function sortModules(items, options = {}) {
8345
8454
  }
8346
8455
  return camelCase(item.fileName);
8347
8456
  });
8348
- const getDeps = options.getDeps || ((item) => item.deps);
8457
+ const getDeps = options.getDeps || ((item) => {
8458
+ const deps = item.deps;
8459
+ if (!Array.isArray(deps)) {
8460
+ return [];
8461
+ }
8462
+ return deps.filter((x) => typeof x === "string");
8463
+ });
8349
8464
  const result = [];
8350
8465
  const visited = new Set;
8351
8466
  const visiting = new Set;
@@ -8425,11 +8540,12 @@ function sortModules(items, options = {}) {
8425
8540
  async function loadHooks(hooks) {
8426
8541
  const hooksMap = [];
8427
8542
  const enabledHooks = hooks.filter((item) => {
8428
- const moduleName = item?.moduleName;
8543
+ const moduleName = item.moduleName;
8429
8544
  if (typeof moduleName !== "string" || moduleName.trim() === "") {
8430
8545
  return false;
8431
8546
  }
8432
- if (item?.enable === false) {
8547
+ const enable = Object.hasOwn(item, "enable") ? item.enable : undefined;
8548
+ if (enable === false) {
8433
8549
  return false;
8434
8550
  }
8435
8551
  return true;
@@ -8440,12 +8556,18 @@ async function loadHooks(hooks) {
8440
8556
  }
8441
8557
  for (const item of sortedHooks) {
8442
8558
  const hookName = item.moduleName;
8443
- const hook = item;
8559
+ const depsRaw = Object.hasOwn(item, "deps") ? item.deps : undefined;
8560
+ const deps = Array.isArray(depsRaw) ? depsRaw.filter((x) => typeof x === "string") : [];
8561
+ const handlerRaw = Object.hasOwn(item, "handler") ? item.handler : undefined;
8562
+ if (typeof handlerRaw !== "function") {
8563
+ throw new Error(`Hook '${hookName}' handler \u5FC5\u987B\u662F\u51FD\u6570`);
8564
+ }
8565
+ const handler = handlerRaw;
8444
8566
  hooksMap.push({
8445
8567
  name: hookName,
8446
8568
  enable: true,
8447
- deps: Array.isArray(hook.deps) ? hook.deps : [],
8448
- handler: hook.handler
8569
+ deps,
8570
+ handler
8449
8571
  });
8450
8572
  }
8451
8573
  return hooksMap;
@@ -8456,11 +8578,12 @@ init_logger();
8456
8578
  async function loadPlugins(plugins, context) {
8457
8579
  const pluginsMap = [];
8458
8580
  const enabledPlugins = plugins.filter((item) => {
8459
- const moduleName = item?.moduleName;
8581
+ const moduleName = item.moduleName;
8460
8582
  if (typeof moduleName !== "string" || moduleName.trim() === "") {
8461
8583
  return false;
8462
8584
  }
8463
- if (item?.enable === false) {
8585
+ const enable = Object.hasOwn(item, "enable") ? item.enable : undefined;
8586
+ if (enable === false) {
8464
8587
  return false;
8465
8588
  }
8466
8589
  return true;
@@ -8471,15 +8594,21 @@ async function loadPlugins(plugins, context) {
8471
8594
  }
8472
8595
  for (const item of sortedPlugins) {
8473
8596
  const pluginName = item.moduleName;
8474
- const plugin = item;
8597
+ const depsRaw = Object.hasOwn(item, "deps") ? item.deps : undefined;
8598
+ const deps = Array.isArray(depsRaw) ? depsRaw.filter((x) => typeof x === "string") : [];
8599
+ const handlerRaw = Object.hasOwn(item, "handler") ? item.handler : undefined;
8600
+ if (typeof handlerRaw !== "function") {
8601
+ throw new Error(`\u63D2\u4EF6 '${pluginName}' handler \u5FC5\u987B\u662F\u51FD\u6570`);
8602
+ }
8603
+ const handler = handlerRaw;
8475
8604
  try {
8476
- const pluginInstance = typeof plugin.handler === "function" ? await plugin.handler(context) : {};
8605
+ const pluginInstance = await handler(context);
8477
8606
  context[pluginName] = pluginInstance;
8478
8607
  pluginsMap.push({
8479
8608
  name: pluginName,
8480
8609
  enable: true,
8481
- deps: Array.isArray(plugin.deps) ? plugin.deps : [],
8482
- handler: plugin.handler
8610
+ deps,
8611
+ handler
8483
8612
  });
8484
8613
  } catch (error) {
8485
8614
  Logger.error({ err: error, plugin: pluginName, msg: "\u63D2\u4EF6\u521D\u59CB\u5316\u5931\u8D25" });
@@ -8795,28 +8924,40 @@ async function syncApi(ctx, apis) {
8795
8924
  if (api.type !== "api") {
8796
8925
  continue;
8797
8926
  }
8798
- const auth = api.auth === false || api.auth === 0 ? 0 : 1;
8799
- const parentPath = getApiParentPath(api.path);
8800
- apiRouteKeys.add(api.path);
8801
- const item = allDbApiMap[api.path];
8927
+ const record = api;
8928
+ const path = record["path"];
8929
+ const name = record["name"];
8930
+ const addonNameRaw = record["addonName"];
8931
+ if (typeof path !== "string" || path.trim() === "") {
8932
+ continue;
8933
+ }
8934
+ if (typeof name !== "string" || name.trim() === "") {
8935
+ continue;
8936
+ }
8937
+ const addonName = typeof addonNameRaw === "string" ? addonNameRaw : "";
8938
+ const authRaw = record["auth"];
8939
+ const auth = authRaw === false || authRaw === 0 ? 0 : 1;
8940
+ const parentPath = getApiParentPath(path);
8941
+ apiRouteKeys.add(path);
8942
+ const item = allDbApiMap[path];
8802
8943
  if (item) {
8803
- const shouldUpdate = api.name !== item.name || api.path !== item.path || api.addonName !== item.addonName || parentPath !== item.parentPath || auth !== item.auth;
8944
+ const shouldUpdate = name !== item.name || path !== item.path || addonName !== item.addonName || parentPath !== item.parentPath || auth !== item.auth;
8804
8945
  if (shouldUpdate) {
8805
8946
  updData.push({
8806
8947
  id: item.id,
8807
- name: api.name,
8808
- path: api.path,
8948
+ name,
8949
+ path,
8809
8950
  parentPath,
8810
- addonName: api.addonName,
8951
+ addonName,
8811
8952
  auth
8812
8953
  });
8813
8954
  }
8814
8955
  } else {
8815
8956
  insData.push({
8816
- name: api.name,
8817
- path: api.path,
8957
+ name,
8958
+ path,
8818
8959
  parentPath,
8819
- addonName: api.addonName,
8960
+ addonName,
8820
8961
  auth
8821
8962
  });
8822
8963
  }
@@ -8956,10 +9097,7 @@ class Cipher {
8956
9097
  }
8957
9098
  }
8958
9099
  static async hashPassword(password, options = {}) {
8959
- const finalOptions = {
8960
- algorithm: "bcrypt",
8961
- ...options
8962
- };
9100
+ const finalOptions = Object.assign({}, options, { algorithm: "bcrypt" });
8963
9101
  return await Bun.password.hash(password, finalOptions);
8964
9102
  }
8965
9103
  static async verifyPassword(password, hash) {
@@ -9034,8 +9172,8 @@ async function syncDev(ctx, config2 = {}) {
9034
9172
  code: "dev",
9035
9173
  name: "\u5F00\u53D1\u8005\u89D2\u8272",
9036
9174
  description: "\u62E5\u6709\u6240\u6709\u83DC\u5355\u548C\u63A5\u53E3\u6743\u9650\u7684\u5F00\u53D1\u8005\u89D2\u8272",
9037
- menus: allMenus.data.lists.map((item) => item.path).filter((v) => v),
9038
- apis: allApis.data.lists.map((item) => item.path).filter((v) => v),
9175
+ menus: allMenus.data.lists.map((item) => item.path).filter((v) => typeof v === "string" && v.length > 0),
9176
+ apis: allApis.data.lists.map((item) => item.path).filter((v) => typeof v === "string" && v.length > 0),
9039
9177
  sort: 0
9040
9178
  };
9041
9179
  if (typeof devRole.data.id === "number") {
@@ -9173,12 +9311,13 @@ function createDisableMenuMatcher(ctx) {
9173
9311
  candidates.push(`/${trimmed}`);
9174
9312
  }
9175
9313
  for (const glob of globs) {
9176
- const match = glob.match;
9314
+ const match = typeof glob === "object" && glob !== null && "match" in glob ? glob.match : undefined;
9177
9315
  if (typeof match !== "function") {
9178
9316
  throw new Error("syncMenu: \u5F53\u524D Bun \u7248\u672C\u4E0D\u652F\u6301 Bun.Glob.match\uFF0C\u65E0\u6CD5\u6309 disableMenus \u505A glob \u5339\u914D");
9179
9317
  }
9318
+ const matchFn = match;
9180
9319
  for (const candidate of candidates) {
9181
- if (match.call(glob, candidate)) {
9320
+ if (matchFn.call(glob, candidate)) {
9182
9321
  return true;
9183
9322
  }
9184
9323
  }
@@ -9511,12 +9650,9 @@ class MySqlDialect {
9511
9650
  return { sql: `SHOW COLUMNS FROM ${quotedTable}`, params: [] };
9512
9651
  }
9513
9652
  getTableColumnsFromResult(result) {
9514
- if (!Array.isArray(result)) {
9515
- return [];
9516
- }
9517
9653
  const columnNames = [];
9518
9654
  for (const row of result) {
9519
- const name = row?.Field;
9655
+ const name = row["Field"];
9520
9656
  if (typeof name === "string" && name.length > 0) {
9521
9657
  columnNames.push(name);
9522
9658
  }
@@ -9557,12 +9693,9 @@ class PostgresDialect {
9557
9693
  return { sql: "SELECT column_name FROM information_schema.columns WHERE table_schema = current_schema() AND table_name = ? ORDER BY ordinal_position", params: [table] };
9558
9694
  }
9559
9695
  getTableColumnsFromResult(result) {
9560
- if (!Array.isArray(result)) {
9561
- return [];
9562
- }
9563
9696
  const columnNames = [];
9564
9697
  for (const row of result) {
9565
- const name = row?.column_name;
9698
+ const name = row["column_name"];
9566
9699
  if (typeof name === "string" && name.length > 0) {
9567
9700
  columnNames.push(name);
9568
9701
  }
@@ -9598,12 +9731,9 @@ class SqliteDialect {
9598
9731
  return { sql: `PRAGMA table_info(${quotedTable})`, params: [] };
9599
9732
  }
9600
9733
  getTableColumnsFromResult(result) {
9601
- if (!Array.isArray(result)) {
9602
- return [];
9603
- }
9604
9734
  const columnNames = [];
9605
9735
  for (const row of result) {
9606
- const name = row?.name;
9736
+ const name = row["name"];
9607
9737
  if (typeof name === "string" && name.length > 0) {
9608
9738
  columnNames.push(name);
9609
9739
  }
@@ -9696,10 +9826,11 @@ var syncTable = async (ctx, items) => {
9696
9826
  applyFieldDefaults(fieldDef);
9697
9827
  }
9698
9828
  const existsTable = await tableExistsRuntime(runtime, tableName);
9829
+ const tableFields = tableDefinition;
9699
9830
  if (existsTable) {
9700
- await modifyTableRuntime(runtime, tableName, tableDefinition);
9831
+ await modifyTableRuntime(runtime, tableName, tableFields);
9701
9832
  } else {
9702
- await createTable(runtime, tableName, tableDefinition);
9833
+ await createTable(runtime, tableName, tableFields);
9703
9834
  }
9704
9835
  processedTables.push(tableName);
9705
9836
  }
@@ -9832,19 +9963,99 @@ function quoteIdentifier(dbDialect, identifier) {
9832
9963
  function escapeComment(str) {
9833
9964
  return String(str).replace(/"/g, "\\\"");
9834
9965
  }
9966
+ function normalizeColumnDefaultValue(value) {
9967
+ if (value === null)
9968
+ return null;
9969
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
9970
+ return value;
9971
+ if (Array.isArray(value)) {
9972
+ const items = [];
9973
+ for (const v of value) {
9974
+ items.push(normalizeColumnDefaultValue(v));
9975
+ }
9976
+ return items;
9977
+ }
9978
+ return String(value);
9979
+ }
9980
+ function isJsonValue(value) {
9981
+ if (value === null)
9982
+ return true;
9983
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
9984
+ return true;
9985
+ if (Array.isArray(value)) {
9986
+ return value.every((v) => isJsonValue(v));
9987
+ }
9988
+ if (typeof value === "object") {
9989
+ for (const v of Object.values(value)) {
9990
+ if (v === undefined)
9991
+ continue;
9992
+ if (!isJsonValue(v))
9993
+ return false;
9994
+ }
9995
+ return true;
9996
+ }
9997
+ return false;
9998
+ }
9835
9999
  function applyFieldDefaults(fieldDef) {
9836
10000
  if (!fieldDef || typeof fieldDef !== "object")
9837
10001
  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;
10002
+ const record = fieldDef;
10003
+ const name = record["name"];
10004
+ const type = record["type"];
10005
+ if (typeof name !== "string" || typeof type !== "string")
10006
+ return;
10007
+ const minRaw = record["min"];
10008
+ const maxRaw = record["max"];
10009
+ const defaultRaw = record["default"];
10010
+ const detailRaw = record["detail"];
10011
+ const indexRaw = record["index"];
10012
+ const uniqueRaw = record["unique"];
10013
+ const nullableRaw = record["nullable"];
10014
+ const unsignedRaw = record["unsigned"];
10015
+ const regexpRaw = record["regexp"];
10016
+ const input = {
10017
+ name,
10018
+ type
10019
+ };
10020
+ if (typeof detailRaw === "string") {
10021
+ input.detail = detailRaw;
10022
+ }
10023
+ if (typeof minRaw === "number" || minRaw === null) {
10024
+ input.min = minRaw;
10025
+ }
10026
+ if (typeof maxRaw === "number" || maxRaw === null) {
10027
+ input.max = maxRaw;
10028
+ }
10029
+ if (defaultRaw === null) {
10030
+ input.default = null;
10031
+ } else if (isJsonValue(defaultRaw)) {
10032
+ input.default = defaultRaw;
10033
+ }
10034
+ if (typeof indexRaw === "boolean") {
10035
+ input.index = indexRaw;
10036
+ }
10037
+ if (typeof uniqueRaw === "boolean") {
10038
+ input.unique = uniqueRaw;
10039
+ }
10040
+ if (typeof nullableRaw === "boolean") {
10041
+ input.nullable = nullableRaw;
10042
+ }
10043
+ if (typeof unsignedRaw === "boolean") {
10044
+ input.unsigned = unsignedRaw;
10045
+ }
10046
+ if (typeof regexpRaw === "string" || regexpRaw === null) {
10047
+ input.regexp = regexpRaw;
10048
+ }
10049
+ const normalized = normalizeFieldDefinition(input);
10050
+ record["detail"] = normalized.detail;
10051
+ record["min"] = normalized.min;
10052
+ record["max"] = normalized.max;
10053
+ record["default"] = normalized.default;
10054
+ record["index"] = normalized.index;
10055
+ record["unique"] = normalized.unique;
10056
+ record["nullable"] = normalized.nullable;
10057
+ record["unsigned"] = normalized.unsigned;
10058
+ record["regexp"] = normalized.regexp;
9848
10059
  }
9849
10060
  function isStringOrArrayType(fieldType) {
9850
10061
  return fieldType === "string" || fieldType === "array_string" || fieldType === "array_number_string";
@@ -10022,7 +10233,8 @@ function isCompatibleTypeChange(currentType, newType) {
10022
10233
  return false;
10023
10234
  }
10024
10235
  async function tableExistsRuntime(runtime, tableName) {
10025
- if (!runtime.db)
10236
+ const db = runtime.db;
10237
+ if (!db)
10026
10238
  throw new Error("SQL \u6267\u884C\u5668\u672A\u521D\u59CB\u5316");
10027
10239
  try {
10028
10240
  let schema = undefined;
@@ -10032,7 +10244,7 @@ async function tableExistsRuntime(runtime, tableName) {
10032
10244
  schema = "public";
10033
10245
  }
10034
10246
  const q = getDialectByName(runtime.dbDialect).tableExistsQuery(tableName, schema);
10035
- const res = await runtime.db.unsafe(q.sql, q.params);
10247
+ const res = await db.unsafe(q.sql, q.params);
10036
10248
  return (res.data?.[0]?.count || 0) > 0;
10037
10249
  } catch (error) {
10038
10250
  const errMsg = String(error?.message || error);
@@ -10044,12 +10256,15 @@ async function tableExistsRuntime(runtime, tableName) {
10044
10256
  }
10045
10257
  async function getTableColumnsRuntime(runtime, tableName) {
10046
10258
  const columns = {};
10259
+ const db = runtime.db;
10260
+ if (!db)
10261
+ throw new Error("SQL \u6267\u884C\u5668\u672A\u521D\u59CB\u5316");
10047
10262
  try {
10048
10263
  if (runtime.dbDialect === "mysql") {
10049
10264
  const q = getSyncTableColumnsInfoQuery({ dialect: "mysql", table: tableName, dbName: runtime.dbName });
10050
- const result = await runtime.db.unsafe(q.columns.sql, q.columns.params);
10265
+ const result = await db.unsafe(q.columns.sql, q.columns.params);
10051
10266
  for (const row of result.data) {
10052
- const defaultValue = row.COLUMN_DEFAULT;
10267
+ const defaultValue = normalizeColumnDefaultValue(row.COLUMN_DEFAULT);
10053
10268
  columns[row.COLUMN_NAME] = {
10054
10269
  type: row.DATA_TYPE,
10055
10270
  columnType: row.COLUMN_TYPE,
@@ -10062,8 +10277,8 @@ async function getTableColumnsRuntime(runtime, tableName) {
10062
10277
  }
10063
10278
  } else if (runtime.dbDialect === "postgresql") {
10064
10279
  const q = getSyncTableColumnsInfoQuery({ dialect: "postgresql", table: tableName, dbName: runtime.dbName });
10065
- const result = await runtime.db.unsafe(q.columns.sql, q.columns.params);
10066
- const comments = q.comments ? (await runtime.db.unsafe(q.comments.sql, q.comments.params)).data : [];
10280
+ const result = await db.unsafe(q.columns.sql, q.columns.params);
10281
+ const comments = q.comments ? (await db.unsafe(q.comments.sql, q.comments.params)).data : [];
10067
10282
  const commentMap = {};
10068
10283
  for (const r of comments)
10069
10284
  commentMap[r.column_name] = r.column_comment;
@@ -10074,13 +10289,13 @@ async function getTableColumnsRuntime(runtime, tableName) {
10074
10289
  length: row.character_maximum_length,
10075
10290
  max: row.character_maximum_length,
10076
10291
  nullable: String(row.is_nullable).toUpperCase() === "YES",
10077
- defaultValue: row.column_default,
10292
+ defaultValue: normalizeColumnDefaultValue(row.column_default),
10078
10293
  comment: commentMap[row.column_name] ?? null
10079
10294
  };
10080
10295
  }
10081
10296
  } else if (runtime.dbDialect === "sqlite") {
10082
10297
  const q = getSyncTableColumnsInfoQuery({ dialect: "sqlite", table: tableName, dbName: runtime.dbName });
10083
- const result = await runtime.db.unsafe(q.columns.sql, q.columns.params);
10298
+ const result = await db.unsafe(q.columns.sql, q.columns.params);
10084
10299
  for (const row of result.data) {
10085
10300
  let baseType = String(row.type || "").toUpperCase();
10086
10301
  let max = null;
@@ -10101,7 +10316,7 @@ async function getTableColumnsRuntime(runtime, tableName) {
10101
10316
  length: max,
10102
10317
  max,
10103
10318
  nullable: row.notnull === 0,
10104
- defaultValue: row.dflt_value,
10319
+ defaultValue: normalizeColumnDefaultValue(row.dflt_value),
10105
10320
  comment: null
10106
10321
  };
10107
10322
  }
@@ -10117,10 +10332,13 @@ async function getTableColumnsRuntime(runtime, tableName) {
10117
10332
  }
10118
10333
  async function getTableIndexesRuntime(runtime, tableName) {
10119
10334
  const indexes = {};
10335
+ const db = runtime.db;
10336
+ if (!db)
10337
+ throw new Error("SQL \u6267\u884C\u5668\u672A\u521D\u59CB\u5316");
10120
10338
  try {
10121
10339
  if (runtime.dbDialect === "mysql") {
10122
10340
  const q = getSyncTableIndexesQuery({ dialect: "mysql", table: tableName, dbName: runtime.dbName });
10123
- const result = await runtime.db.unsafe(q.sql, q.params);
10341
+ const result = await db.unsafe(q.sql, q.params);
10124
10342
  for (const row of result.data) {
10125
10343
  const indexName = row.INDEX_NAME;
10126
10344
  const current = indexes[indexName];
@@ -10132,7 +10350,7 @@ async function getTableIndexesRuntime(runtime, tableName) {
10132
10350
  }
10133
10351
  } else if (runtime.dbDialect === "postgresql") {
10134
10352
  const q = getSyncTableIndexesQuery({ dialect: "postgresql", table: tableName, dbName: runtime.dbName });
10135
- const result = await runtime.db.unsafe(q.sql, q.params);
10353
+ const result = await db.unsafe(q.sql, q.params);
10136
10354
  for (const row of result.data) {
10137
10355
  const m = /\(([^)]+)\)/.exec(row.indexdef);
10138
10356
  if (m) {
@@ -10143,10 +10361,10 @@ async function getTableIndexesRuntime(runtime, tableName) {
10143
10361
  }
10144
10362
  } else if (runtime.dbDialect === "sqlite") {
10145
10363
  const quotedTable = quoteIdentifier("sqlite", tableName);
10146
- const list = await runtime.db.unsafe(`PRAGMA index_list(${quotedTable})`);
10364
+ const list = await db.unsafe(`PRAGMA index_list(${quotedTable})`);
10147
10365
  for (const idx of list.data) {
10148
10366
  const quotedIndex = quoteIdentifier("sqlite", idx.name);
10149
- const info = await runtime.db.unsafe(`PRAGMA index_info(${quotedIndex})`);
10367
+ const info = await db.unsafe(`PRAGMA index_info(${quotedIndex})`);
10150
10368
  const cols = info.data.map((r) => r.name);
10151
10369
  if (cols.length === 1)
10152
10370
  indexes[idx.name] = cols;
@@ -12173,7 +12391,7 @@ var permissionHook = {
12173
12391
  if (ctx.api.auth === false) {
12174
12392
  return;
12175
12393
  }
12176
- if (!ctx.user || !ctx.user.id) {
12394
+ if (typeof ctx.user.id !== "number") {
12177
12395
  ctx.response = ErrorResponse(ctx, "\u672A\u767B\u5F55", 1, null, null, "auth");
12178
12396
  return;
12179
12397
  }
@@ -12285,28 +12503,75 @@ function getCompiledRegex(pattern, flags) {
12285
12503
  }
12286
12504
 
12287
12505
  // lib/validator.ts
12506
+ init_util();
12507
+
12288
12508
  class Validator {
12289
12509
  static validate(data, rules, required = []) {
12290
12510
  const fieldErrors = {};
12291
- if (!data || typeof data !== "object" || Array.isArray(data)) {
12511
+ if (!isPlainObject(data)) {
12292
12512
  return this.buildResult({ _error: "\u6570\u636E\u5FC5\u987B\u662F\u5BF9\u8C61\u683C\u5F0F" });
12293
12513
  }
12294
- if (!rules || typeof rules !== "object") {
12514
+ if (!isPlainObject(rules)) {
12295
12515
  return this.buildResult({ _error: "\u9A8C\u8BC1\u89C4\u5219\u5FC5\u987B\u662F\u5BF9\u8C61\u683C\u5F0F" });
12296
12516
  }
12517
+ const dataRecord = data;
12518
+ const rulesRecord = rules;
12297
12519
  for (const field of required) {
12298
- const value = data[field];
12520
+ const value = dataRecord[field];
12299
12521
  if (value === undefined || value === null) {
12300
- const label = rules[field]?.name || field;
12522
+ const rawRule = rulesRecord[field];
12523
+ const label = isPlainObject(rawRule) && typeof rawRule["name"] === "string" ? rawRule["name"] : field;
12301
12524
  fieldErrors[field] = `${label}\u4E3A\u5FC5\u586B\u9879`;
12302
12525
  }
12303
12526
  }
12304
- for (const [field, rule] of Object.entries(rules)) {
12527
+ for (const [field, rawRule] of Object.entries(rulesRecord)) {
12305
12528
  if (fieldErrors[field])
12306
12529
  continue;
12307
- if (data[field] === undefined && !required.includes(field))
12530
+ if (dataRecord[field] === undefined && !required.includes(field))
12531
+ continue;
12532
+ if (!isPlainObject(rawRule)) {
12533
+ fieldErrors[field] = `${field}\u9A8C\u8BC1\u89C4\u5219\u5FC5\u987B\u662F\u5BF9\u8C61\u683C\u5F0F`;
12534
+ continue;
12535
+ }
12536
+ const ruleName = rawRule["name"];
12537
+ const ruleType = rawRule["type"];
12538
+ if (typeof ruleName !== "string" || typeof ruleType !== "string") {
12539
+ fieldErrors[field] = `${field}\u9A8C\u8BC1\u89C4\u5219\u65E0\u6548`;
12308
12540
  continue;
12309
- const error = this.checkField(data[field], rule, field);
12541
+ }
12542
+ const rule = {
12543
+ name: ruleName,
12544
+ type: ruleType
12545
+ };
12546
+ const min = rawRule["min"];
12547
+ if (typeof min === "number" || min === null)
12548
+ rule.min = min;
12549
+ const max = rawRule["max"];
12550
+ if (typeof max === "number" || max === null)
12551
+ rule.max = max;
12552
+ const def = rawRule["default"];
12553
+ if (def === null || typeof def === "string" || typeof def === "number" || typeof def === "boolean" || Array.isArray(def) || isPlainObject(def)) {
12554
+ rule.default = def;
12555
+ }
12556
+ const detail = rawRule["detail"];
12557
+ if (typeof detail === "string")
12558
+ rule.detail = detail;
12559
+ const index = rawRule["index"];
12560
+ if (typeof index === "boolean")
12561
+ rule.index = index;
12562
+ const unique = rawRule["unique"];
12563
+ if (typeof unique === "boolean")
12564
+ rule.unique = unique;
12565
+ const nullable = rawRule["nullable"];
12566
+ if (typeof nullable === "boolean")
12567
+ rule.nullable = nullable;
12568
+ const unsigned = rawRule["unsigned"];
12569
+ if (typeof unsigned === "boolean")
12570
+ rule.unsigned = unsigned;
12571
+ const regexp = rawRule["regexp"];
12572
+ if (typeof regexp === "string" || regexp === null)
12573
+ rule.regexp = regexp;
12574
+ const error = this.checkField(dataRecord[field], rule, field);
12310
12575
  if (error)
12311
12576
  fieldErrors[field] = error;
12312
12577
  }
@@ -12392,6 +12657,8 @@ class Validator {
12392
12657
  const regex = this.resolveRegex(regexp);
12393
12658
  switch (type.toLowerCase()) {
12394
12659
  case "number":
12660
+ if (typeof value !== "number")
12661
+ return "\u5FC5\u987B\u662F\u6570\u5B57";
12395
12662
  if (min !== null && value < min)
12396
12663
  return `\u4E0D\u80FD\u5C0F\u4E8E${min}`;
12397
12664
  if (max !== null && max > 0 && value > max)
@@ -12401,6 +12668,8 @@ class Validator {
12401
12668
  break;
12402
12669
  case "string":
12403
12670
  case "text":
12671
+ if (typeof value !== "string")
12672
+ return "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32";
12404
12673
  if (min !== null && value.length < min)
12405
12674
  return `\u957F\u5EA6\u4E0D\u80FD\u5C11\u4E8E${min}\u4E2A\u5B57\u7B26`;
12406
12675
  if (max !== null && max > 0 && value.length > max)
@@ -12412,6 +12681,8 @@ class Validator {
12412
12681
  case "array_text":
12413
12682
  case "array_number_string":
12414
12683
  case "array_number_text":
12684
+ if (!Array.isArray(value))
12685
+ return "\u5FC5\u987B\u662F\u6570\u7EC4";
12415
12686
  if (min !== null && value.length < min)
12416
12687
  return `\u81F3\u5C11\u9700\u8981${min}\u4E2A\u5143\u7D20`;
12417
12688
  if (max !== null && max > 0 && value.length > max)
@@ -12769,8 +13040,9 @@ function convertBigIntFields(arr, fields = ["id", "pid", "sort"]) {
12769
13040
  return arr;
12770
13041
  }
12771
13042
  return arr.map((item) => {
13043
+ const source = item;
12772
13044
  const converted = {};
12773
- for (const [key, value] of Object.entries(item)) {
13045
+ for (const [key, value] of Object.entries(source)) {
12774
13046
  converted[key] = value;
12775
13047
  }
12776
13048
  for (const [key, value] of Object.entries(converted)) {
@@ -12780,7 +13052,7 @@ function convertBigIntFields(arr, fields = ["id", "pid", "sort"]) {
12780
13052
  const shouldConvert = fields.includes(key) || key.endsWith("Id") || key.endsWith("_id") || key.endsWith("At") || key.endsWith("_at");
12781
13053
  if (shouldConvert && typeof value === "string") {
12782
13054
  const num = Number(value);
12783
- if (!isNaN(num)) {
13055
+ if (!Number.isNaN(num)) {
12784
13056
  converted[key] = num;
12785
13057
  }
12786
13058
  }
@@ -12839,6 +13111,82 @@ function fieldClear(data, options = {}) {
12839
13111
  return data;
12840
13112
  }
12841
13113
 
13114
+ // utils/sqlParams.ts
13115
+ function isJsonPrimitive(value) {
13116
+ if (value === null)
13117
+ return true;
13118
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
13119
+ }
13120
+ function isJsonObject(value) {
13121
+ if (!value || typeof value !== "object")
13122
+ return false;
13123
+ if (value instanceof Date)
13124
+ return false;
13125
+ if (Array.isArray(value))
13126
+ return false;
13127
+ return true;
13128
+ }
13129
+ function isJsonValue2(value) {
13130
+ if (isJsonPrimitive(value))
13131
+ return true;
13132
+ if (Array.isArray(value)) {
13133
+ for (const item of value) {
13134
+ if (!isJsonValue2(item))
13135
+ return false;
13136
+ }
13137
+ return true;
13138
+ }
13139
+ if (isJsonObject(value)) {
13140
+ for (const v of Object.values(value)) {
13141
+ if (v === undefined)
13142
+ continue;
13143
+ if (!isJsonValue2(v))
13144
+ return false;
13145
+ }
13146
+ return true;
13147
+ }
13148
+ return false;
13149
+ }
13150
+ function toSqlParams(params) {
13151
+ if (!Array.isArray(params)) {
13152
+ return [];
13153
+ }
13154
+ const out = [];
13155
+ for (const value of params) {
13156
+ if (value === null) {
13157
+ out.push(null);
13158
+ continue;
13159
+ }
13160
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
13161
+ out.push(value);
13162
+ continue;
13163
+ }
13164
+ if (typeof value === "bigint") {
13165
+ out.push(String(value));
13166
+ continue;
13167
+ }
13168
+ if (value instanceof Date) {
13169
+ out.push(value);
13170
+ continue;
13171
+ }
13172
+ if (isJsonValue2(value)) {
13173
+ out.push(value);
13174
+ continue;
13175
+ }
13176
+ out.push(String(value));
13177
+ }
13178
+ return out;
13179
+ }
13180
+
13181
+ // utils/sqlResult.ts
13182
+ function toNumberFromSql(value) {
13183
+ if (typeof value === "number")
13184
+ return value;
13185
+ if (typeof value === "bigint")
13186
+ return Number(value);
13187
+ return 0;
13188
+ }
13189
+
12842
13190
  // lib/dbHelper.ts
12843
13191
  init_util();
12844
13192
 
@@ -13065,7 +13413,7 @@ class DbUtils {
13065
13413
  for (const [key, value] of Object.entries(where)) {
13066
13414
  const newKey = DbUtils.processJoinWhereKey(key);
13067
13415
  if (key === "$or" || key === "$and") {
13068
- result[newKey] = value.map((item) => DbUtils.processJoinWhere(item));
13416
+ result[newKey] = Array.isArray(value) ? value.map((item) => DbUtils.processJoinWhere(item)) : [];
13069
13417
  } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
13070
13418
  result[newKey] = DbUtils.processJoinWhere(value);
13071
13419
  } else {
@@ -13124,7 +13472,7 @@ class DbUtils {
13124
13472
  const result = {};
13125
13473
  for (const [key, value] of Object.entries(where)) {
13126
13474
  if (key === "$or" || key === "$and") {
13127
- result[key] = value.map((item) => DbUtils.whereKeysToSnake(item));
13475
+ result[key] = Array.isArray(value) ? value.map((item) => DbUtils.whereKeysToSnake(item)) : [];
13128
13476
  continue;
13129
13477
  }
13130
13478
  if (key.includes("$")) {
@@ -13661,13 +14009,20 @@ class SqlBuilder {
13661
14009
  }
13662
14010
  if (key === "$and") {
13663
14011
  if (Array.isArray(value)) {
13664
- value.forEach((condition) => this._processWhereConditions(condition));
14012
+ value.forEach((condition) => {
14013
+ if (condition && typeof condition === "object" && !Array.isArray(condition)) {
14014
+ this._processWhereConditions(condition);
14015
+ }
14016
+ });
13665
14017
  }
13666
14018
  } else if (key === "$or") {
13667
14019
  if (Array.isArray(value)) {
13668
14020
  const orConditions = [];
13669
14021
  const tempParams = [];
13670
14022
  value.forEach((condition) => {
14023
+ if (!condition || typeof condition !== "object" || Array.isArray(condition)) {
14024
+ return;
14025
+ }
13671
14026
  const tempBuilder = new SqlBuilder({ quoteIdent: this._quoteIdent });
13672
14027
  tempBuilder._processWhereConditions(condition);
13673
14028
  if (tempBuilder._where.length > 0) {
@@ -13912,7 +14267,8 @@ class SqlBuilder {
13912
14267
  throw new Error(SqlBuilderError.INSERT_NEED_AT_LEAST_ONE_FIELD(table));
13913
14268
  }
13914
14269
  for (const field of fields) {
13915
- this._validateParam(data[field]);
14270
+ const record = data;
14271
+ this._validateParam(record[field]);
13916
14272
  }
13917
14273
  const escapedFields = fields.map((field) => this._escapeField(field));
13918
14274
  const placeholders = fields.map(() => "?").join(", ");
@@ -14049,6 +14405,23 @@ class SqlBuilder {
14049
14405
 
14050
14406
  // lib/dbHelper.ts
14051
14407
  var TABLE_COLUMNS_CACHE_TTL_SECONDS = 3600;
14408
+ function hasBegin(sql) {
14409
+ return typeof sql.begin === "function";
14410
+ }
14411
+
14412
+ class DbSqlError extends Error {
14413
+ originalError;
14414
+ params;
14415
+ duration;
14416
+ sqlInfo;
14417
+ constructor(message, options) {
14418
+ super(message);
14419
+ this.originalError = options.originalError;
14420
+ this.params = options.params;
14421
+ this.duration = options.duration;
14422
+ this.sqlInfo = options.sqlInfo;
14423
+ }
14424
+ }
14052
14425
 
14053
14426
  class DbHelper {
14054
14427
  redis;
@@ -14071,7 +14444,7 @@ class DbHelper {
14071
14444
  return columns;
14072
14445
  }
14073
14446
  const query = this.dialect.getTableColumnsQuery(table);
14074
- const execRes = await this.executeWithConn(query.sql, query.params);
14447
+ const execRes = await this.executeSelect(query.sql, query.params);
14075
14448
  const result = execRes.data;
14076
14449
  if (!result || result.length === 0) {
14077
14450
  throw new Error(`\u8868 ${table} \u4E0D\u5B58\u5728\u6216\u6CA1\u6709\u5B57\u6BB5`);
@@ -14133,6 +14506,12 @@ class DbHelper {
14133
14506
  }
14134
14507
  }
14135
14508
  }
14509
+ async executeSelect(sqlStr, params) {
14510
+ return await this.executeWithConn(sqlStr, params);
14511
+ }
14512
+ async executeRun(sqlStr, params) {
14513
+ return await this.executeWithConn(sqlStr, params);
14514
+ }
14136
14515
  async executeWithConn(sqlStr, params) {
14137
14516
  if (!this.sql) {
14138
14517
  throw new Error("\u6570\u636E\u5E93\u8FDE\u63A5\u672A\u521D\u59CB\u5316");
@@ -14141,7 +14520,7 @@ class DbHelper {
14141
14520
  throw new Error(`executeWithConn \u53EA\u63A5\u53D7\u5B57\u7B26\u4E32\u7C7B\u578B\u7684 SQL\uFF0C\u6536\u5230\u7C7B\u578B: ${typeof sqlStr}\uFF0C\u503C: ${JSON.stringify(sqlStr)}`);
14142
14521
  }
14143
14522
  const startTime = Date.now();
14144
- const safeParams = Array.isArray(params) ? params : [];
14523
+ const safeParams = toSqlParams(params);
14145
14524
  try {
14146
14525
  let result;
14147
14526
  if (safeParams.length > 0) {
@@ -14161,16 +14540,17 @@ class DbHelper {
14161
14540
  };
14162
14541
  } catch (error) {
14163
14542
  const duration = Date.now() - startTime;
14164
- const enhancedError = new Error(`SQL\u6267\u884C\u5931\u8D25: ${error.message}`);
14165
- enhancedError.originalError = error;
14166
- enhancedError.params = safeParams;
14167
- enhancedError.duration = duration;
14168
- enhancedError.sqlInfo = {
14169
- sql: sqlStr,
14543
+ const msg = error instanceof Error ? error.message : String(error);
14544
+ throw new DbSqlError(`SQL\u6267\u884C\u5931\u8D25: ${msg}`, {
14545
+ originalError: error,
14170
14546
  params: safeParams,
14171
- duration
14172
- };
14173
- throw enhancedError;
14547
+ duration,
14548
+ sqlInfo: {
14549
+ sql: sqlStr,
14550
+ params: safeParams,
14551
+ duration
14552
+ }
14553
+ });
14174
14554
  }
14175
14555
  }
14176
14556
  async unsafe(sqlStr, params) {
@@ -14179,7 +14559,7 @@ class DbHelper {
14179
14559
  async tableExists(tableName) {
14180
14560
  const snakeTableName = snakeCase(tableName);
14181
14561
  const query = this.dialect.tableExistsQuery(snakeTableName);
14182
- const execRes = await this.executeWithConn(query.sql, query.params);
14562
+ const execRes = await this.executeSelect(query.sql, query.params);
14183
14563
  const exists = (execRes.data?.[0]?.count || 0) > 0;
14184
14564
  return {
14185
14565
  data: exists,
@@ -14192,7 +14572,7 @@ class DbHelper {
14192
14572
  const builder = this.createSqlBuilder().selectRaw("COUNT(*) as count").from(table).where(DbUtils.addDefaultStateFilter(where, tableQualifier, hasJoins));
14193
14573
  this.applyJoins(builder, joins);
14194
14574
  const { sql, params } = builder.toSelectSql();
14195
- const execRes = await this.executeWithConn(sql, params);
14575
+ const execRes = await this.executeSelect(sql, params);
14196
14576
  const count = execRes.data?.[0]?.count || 0;
14197
14577
  return {
14198
14578
  data: count,
@@ -14205,7 +14585,7 @@ class DbHelper {
14205
14585
  const builder = this.createSqlBuilder().select(fields).from(table).where(DbUtils.addDefaultStateFilter(where, tableQualifier, hasJoins));
14206
14586
  this.applyJoins(builder, joins);
14207
14587
  const { sql, params } = builder.toSelectSql();
14208
- const execRes = await this.executeWithConn(sql, params);
14588
+ const execRes = await this.executeSelect(sql, params);
14209
14589
  const result = execRes.data;
14210
14590
  const row = result?.[0] || null;
14211
14591
  if (!row) {
@@ -14244,7 +14624,7 @@ class DbHelper {
14244
14624
  const countBuilder = this.createSqlBuilder().selectRaw("COUNT(*) as total").from(prepared.table).where(whereFiltered);
14245
14625
  this.applyJoins(countBuilder, prepared.joins);
14246
14626
  const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
14247
- const countExecRes = await this.executeWithConn(countSql, countParams);
14627
+ const countExecRes = await this.executeSelect(countSql, countParams);
14248
14628
  const total = countExecRes.data?.[0]?.total || 0;
14249
14629
  if (total === 0) {
14250
14630
  return {
@@ -14267,7 +14647,7 @@ class DbHelper {
14267
14647
  dataBuilder.orderBy(prepared.orderBy);
14268
14648
  }
14269
14649
  const { sql: dataSql, params: dataParams } = dataBuilder.toSelectSql();
14270
- const dataExecRes = await this.executeWithConn(dataSql, dataParams);
14650
+ const dataExecRes = await this.executeSelect(dataSql, dataParams);
14271
14651
  const list = dataExecRes.data || [];
14272
14652
  const camelList = arrayKeysToCamel(list);
14273
14653
  const deserializedList = camelList.map((item) => DbUtils.deserializeArrayFields(item)).filter((item) => item !== null);
@@ -14306,7 +14686,7 @@ class DbHelper {
14306
14686
  const countBuilder = this.createSqlBuilder().selectRaw("COUNT(*) as total").from(prepared.table).where(whereFiltered);
14307
14687
  this.applyJoins(countBuilder, prepared.joins);
14308
14688
  const { sql: countSql, params: countParams } = countBuilder.toSelectSql();
14309
- const countExecRes = await this.executeWithConn(countSql, countParams);
14689
+ const countExecRes = await this.executeSelect(countSql, countParams);
14310
14690
  const total = countExecRes.data?.[0]?.total || 0;
14311
14691
  if (total === 0) {
14312
14692
  return {
@@ -14325,7 +14705,7 @@ class DbHelper {
14325
14705
  dataBuilder.orderBy(prepared.orderBy);
14326
14706
  }
14327
14707
  const { sql: dataSql, params: dataParams } = dataBuilder.toSelectSql();
14328
- const dataExecRes = await this.executeWithConn(dataSql, dataParams);
14708
+ const dataExecRes = await this.executeSelect(dataSql, dataParams);
14329
14709
  const result = dataExecRes.data || [];
14330
14710
  if (result.length >= WARNING_LIMIT) {
14331
14711
  Logger.warn({ table: options.table, count: result.length, total, msg: "getAll \u8FD4\u56DE\u6570\u636E\u8FC7\u591A\uFF0C\u5EFA\u8BAE\u4F7F\u7528 getList \u5206\u9875\u67E5\u8BE2" });
@@ -14361,8 +14741,11 @@ class DbHelper {
14361
14741
  SqlCheck.assertNoUndefinedInRecord(processed, `insData \u63D2\u5165\u6570\u636E (table: ${snakeTable})`);
14362
14742
  const builder = this.createSqlBuilder();
14363
14743
  const { sql, params } = builder.toInsertSql(snakeTable, processed);
14364
- const execRes = await this.executeWithConn(sql, params);
14365
- const insertedId = processed["id"] || execRes.data?.lastInsertRowid || 0;
14744
+ const execRes = await this.executeRun(sql, params);
14745
+ const processedId = processed["id"];
14746
+ const processedIdNum = typeof processedId === "number" ? processedId : 0;
14747
+ const lastInsertRowidNum = toNumberFromSql(execRes.data?.lastInsertRowid);
14748
+ const insertedId = processedIdNum || lastInsertRowidNum || 0;
14366
14749
  return {
14367
14750
  data: insertedId,
14368
14751
  sql: execRes.sql
@@ -14397,7 +14780,7 @@ class DbHelper {
14397
14780
  const builder = this.createSqlBuilder();
14398
14781
  const { sql, params } = builder.toInsertSql(snakeTable, processedList);
14399
14782
  try {
14400
- const execRes = await this.executeWithConn(sql, params);
14783
+ const execRes = await this.executeRun(sql, params);
14401
14784
  return {
14402
14785
  data: ids,
14403
14786
  sql: execRes.sql
@@ -14429,8 +14812,8 @@ class DbHelper {
14429
14812
  ids,
14430
14813
  quoteIdent: this.dialect.quoteIdent.bind(this.dialect)
14431
14814
  });
14432
- const execRes = await this.executeWithConn(query.sql, query.params);
14433
- const changes = execRes.data?.changes || 0;
14815
+ const execRes = await this.executeRun(query.sql, query.params);
14816
+ const changes = toNumberFromSql(execRes.data?.changes);
14434
14817
  return {
14435
14818
  data: changes,
14436
14819
  sql: execRes.sql
@@ -14474,8 +14857,8 @@ class DbHelper {
14474
14857
  stateField: "state",
14475
14858
  stateGtZero: true
14476
14859
  });
14477
- const execRes = await this.executeWithConn(query.sql, query.params);
14478
- const changes = execRes.data?.changes || 0;
14860
+ const execRes = await this.executeRun(query.sql, query.params);
14861
+ const changes = toNumberFromSql(execRes.data?.changes);
14479
14862
  return {
14480
14863
  data: changes,
14481
14864
  sql: execRes.sql
@@ -14490,8 +14873,8 @@ class DbHelper {
14490
14873
  const whereFiltered = DbUtils.addDefaultStateFilter(snakeWhere, snakeTable, false);
14491
14874
  const builder = this.createSqlBuilder().where(whereFiltered);
14492
14875
  const { sql, params } = builder.toUpdateSql(snakeTable, processed);
14493
- const execRes = await this.executeWithConn(sql, params);
14494
- const changes = execRes.data?.changes || 0;
14876
+ const execRes = await this.executeRun(sql, params);
14877
+ const changes = toNumberFromSql(execRes.data?.changes);
14495
14878
  return {
14496
14879
  data: changes,
14497
14880
  sql: execRes.sql
@@ -14512,8 +14895,8 @@ class DbHelper {
14512
14895
  const snakeWhere = DbUtils.whereKeysToSnake(cleanWhere);
14513
14896
  const builder = this.createSqlBuilder().where(snakeWhere);
14514
14897
  const { sql, params } = builder.toDeleteSql(snakeTable);
14515
- const execRes = await this.executeWithConn(sql, params);
14516
- const changes = execRes.data?.changes || 0;
14898
+ const execRes = await this.executeRun(sql, params);
14899
+ const changes = toNumberFromSql(execRes.data?.changes);
14517
14900
  return {
14518
14901
  data: changes,
14519
14902
  sql: execRes.sql
@@ -14543,7 +14926,14 @@ class DbHelper {
14543
14926
  if (this.isTransaction) {
14544
14927
  return await callback(this);
14545
14928
  }
14546
- return await this.sql.begin(async (tx) => {
14929
+ const sql = this.sql;
14930
+ if (!sql) {
14931
+ throw new Error("\u6570\u636E\u5E93\u8FDE\u63A5\u672A\u521D\u59CB\u5316");
14932
+ }
14933
+ if (!hasBegin(sql)) {
14934
+ throw new Error("\u5F53\u524D SQL \u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u4E8B\u52A1 begin() \u65B9\u6CD5");
14935
+ }
14936
+ return await sql.begin(async (tx) => {
14547
14937
  const trans = new DbHelper({ redis: this.redis, sql: tx, dialect: this.dialect });
14548
14938
  return await callback(trans);
14549
14939
  });
@@ -14552,10 +14942,19 @@ class DbHelper {
14552
14942
  return await this.executeWithConn(sql, params);
14553
14943
  }
14554
14944
  async exists(options) {
14555
- const { table, where, tableQualifier } = await this.prepareQueryOptions({ ...options, page: 1, limit: 1 });
14945
+ const prepareOptions = {
14946
+ table: options.table,
14947
+ page: 1,
14948
+ limit: 1
14949
+ };
14950
+ if (options.where !== undefined)
14951
+ prepareOptions.where = options.where;
14952
+ if (options.joins !== undefined)
14953
+ prepareOptions.joins = options.joins;
14954
+ const { table, where, tableQualifier } = await this.prepareQueryOptions(prepareOptions);
14556
14955
  const builder = this.createSqlBuilder().selectRaw("COUNT(1) as cnt").from(table).where(DbUtils.addDefaultStateFilter(where, tableQualifier, false)).limit(1);
14557
14956
  const { sql, params } = builder.toSelectSql();
14558
- const execRes = await this.executeWithConn(sql, params);
14957
+ const execRes = await this.executeSelect(sql, params);
14559
14958
  const exists = (execRes.data?.[0]?.cnt || 0) > 0;
14560
14959
  return {
14561
14960
  data: exists,
@@ -14583,6 +14982,12 @@ class DbHelper {
14583
14982
  oneOptions.fields = [field];
14584
14983
  const oneRes = await this.getOne(oneOptions);
14585
14984
  const result = oneRes.data;
14985
+ if (!isPlainObject(result)) {
14986
+ return {
14987
+ data: null,
14988
+ sql: oneRes.sql
14989
+ };
14990
+ }
14586
14991
  if (Object.hasOwn(result, field)) {
14587
14992
  return {
14588
14993
  data: result[field],
@@ -14628,8 +15033,8 @@ class DbHelper {
14628
15033
  const quotedTable = this.dialect.quoteIdent(snakeTable);
14629
15034
  const quotedField = this.dialect.quoteIdent(snakeField);
14630
15035
  const sql = whereClause ? `UPDATE ${quotedTable} SET ${quotedField} = ${quotedField} + ? WHERE ${whereClause}` : `UPDATE ${quotedTable} SET ${quotedField} = ${quotedField} + ?`;
14631
- const execRes = await this.executeWithConn(sql, [value, ...whereParams]);
14632
- const changes = execRes.data?.changes || 0;
15036
+ const execRes = await this.executeRun(sql, [value, ...whereParams]);
15037
+ const changes = toNumberFromSql(execRes.data?.changes);
14633
15038
  return {
14634
15039
  data: changes,
14635
15040
  sql: execRes.sql
@@ -15211,9 +15616,12 @@ var tool_default = toolPlugin;
15211
15616
  // utils/scanCoreBuiltins.ts
15212
15617
  init_util();
15213
15618
  function toCoreBuiltinScanFileResult(type, item) {
15214
- const name = item.name;
15619
+ const record = isPlainObject(item) ? item : {};
15620
+ const name = typeof record["name"] === "string" ? String(record["name"]) : "";
15215
15621
  const customKeys = isPlainObject(item) ? Object.keys(item) : [];
15216
- return {
15622
+ const depsRaw = record["deps"];
15623
+ const deps = Array.isArray(depsRaw) ? depsRaw.filter((x) => typeof x === "string") : [];
15624
+ const out = {
15217
15625
  source: "core",
15218
15626
  type,
15219
15627
  sourceName: "\u6838\u5FC3",
@@ -15225,11 +15633,12 @@ function toCoreBuiltinScanFileResult(type, item) {
15225
15633
  fileBaseName: name,
15226
15634
  fileDir: "(builtin)",
15227
15635
  name,
15228
- enable: item ? item.enable : undefined,
15229
- deps: Array.isArray(item && item.deps) ? item.deps : [],
15230
- handler: item ? item.handler : null,
15636
+ enable: record["enable"],
15637
+ deps,
15638
+ handler: record["handler"] ?? null,
15231
15639
  customKeys
15232
15640
  };
15641
+ return out;
15233
15642
  }
15234
15643
  function scanCoreBuiltinPlugins() {
15235
15644
  const plugins = [];
@@ -15344,7 +15753,7 @@ async function scanFiles(dir, source, type, pattern) {
15344
15753
  customKeys: isPlainObject(content) ? Object.keys(content) : []
15345
15754
  };
15346
15755
  if (type === "table") {
15347
- base["content"] = content;
15756
+ base["content"] = isPlainObject(content) ? content : {};
15348
15757
  results.push(base);
15349
15758
  continue;
15350
15759
  }