@maiyunnet/kebab 2.0.9 → 2.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -3,10 +3,12 @@
3
3
  * Date: 2019-3-30 12:46:41
4
4
  * Last: 2020-3-8 21:04:24, 2022-07-22 14:20:34, 2023-5-24 01:34:57, 2025-6-13 14:49:27
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
+ * ------------------------
6
7
  * --- npx tsc-alias -w ---
8
+ * ------------------------
7
9
  */
8
10
  /** --- 当前系统版本号 --- */
9
- export declare const VER = "2.0.9";
11
+ export declare const VER = "2.0.11";
10
12
  /** --- 框架根目录,以 / 结尾 --- */
11
13
  export declare const ROOT_PATH: string;
12
14
  export declare const LIB_PATH: string;
package/index.js CHANGED
@@ -4,12 +4,14 @@
4
4
  * Date: 2019-3-30 12:46:41
5
5
  * Last: 2020-3-8 21:04:24, 2022-07-22 14:20:34, 2023-5-24 01:34:57, 2025-6-13 14:49:27
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
+ * ------------------------
7
8
  * --- npx tsc-alias -w ---
9
+ * ------------------------
8
10
  */
9
11
  Object.defineProperty(exports, "__esModule", { value: true });
10
12
  exports.MOD_CWD = exports.FTMP_CWD = exports.IND_CWD = exports.WWW_CWD = exports.LOG_CWD = exports.LIB_CWD = exports.VHOST_CWD = exports.CERT_CWD = exports.CONF_CWD = exports.ROOT_CWD = exports.SYS_PATH = exports.LIB_PATH = exports.ROOT_PATH = exports.VER = void 0;
11
13
  /** --- 当前系统版本号 --- */
12
- exports.VER = '2.0.9';
14
+ exports.VER = '2.0.11';
13
15
  // --- 服务端用的路径 ---
14
16
  /** --- /xxx/xxx --- */
15
17
  const dirname = __dirname.replace(/\\/g, '/');
@@ -0,0 +1,15 @@
1
+ import * as sCtr from '../sys/ctr';
2
+ /**
3
+ * 0. CloudFlare:https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
4
+ * 1. 腾讯云:https://cloud.tencent.com/document/product/1110/36926
5
+ */
6
+ /** --- 厂家 --- */
7
+ export declare enum EFACTORY {
8
+ 'CLOUDFLARE' = 0,
9
+ 'TENCENT' = 1
10
+ }
11
+ export declare function verify(ctr: sCtr.Ctr, opt: {
12
+ 'factory': EFACTORY;
13
+ 'token': string;
14
+ 'ip': string;
15
+ }): Promise<boolean>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EFACTORY = void 0;
37
+ exports.verify = verify;
38
+ /**
39
+ * Project: Kebab, User: JianSuoQiYue
40
+ * Date: 2025-6-11
41
+ * Last: 2025-6-11 21:50:31
42
+ */
43
+ const tc = __importStar(require("tencentcloud-sdk-nodejs"));
44
+ // --- 库和定义 ---
45
+ const lNet = __importStar(require("../lib/net"));
46
+ const lText = __importStar(require("../lib/text"));
47
+ /**
48
+ * 0. CloudFlare:https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
49
+ * 1. 腾讯云:https://cloud.tencent.com/document/product/1110/36926
50
+ */
51
+ /** --- 厂家 --- */
52
+ var EFACTORY;
53
+ (function (EFACTORY) {
54
+ EFACTORY[EFACTORY["CLOUDFLARE"] = 0] = "CLOUDFLARE";
55
+ EFACTORY[EFACTORY["TENCENT"] = 1] = "TENCENT";
56
+ })(EFACTORY || (exports.EFACTORY = EFACTORY = {}));
57
+ async function verify(ctr, opt) {
58
+ const config = ctr.getPrototype('_config');
59
+ switch (opt.factory) {
60
+ case EFACTORY.CLOUDFLARE: {
61
+ // --- CloudFlare 验证 ---
62
+ const res = await lNet.postJson('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
63
+ 'secret': config.turnstile['CF'].skey,
64
+ 'response': opt.token,
65
+ 'remoteip': opt.ip,
66
+ });
67
+ const content = await res.getContent();
68
+ if (!content) {
69
+ return false;
70
+ }
71
+ const str = content.toString();
72
+ const json = lText.parseJson(str);
73
+ if (!json) {
74
+ return false;
75
+ }
76
+ return json.success;
77
+ }
78
+ case EFACTORY.TENCENT: {
79
+ // --- 腾讯云验证 ---
80
+ const client = new tc.captcha.v20190722.Client({
81
+ 'credential': {
82
+ 'secretId': config.turnstile['TENCENT'].sid,
83
+ 'secretKey': config.turnstile['TENCENT'].skey,
84
+ },
85
+ 'profile': {
86
+ 'signMethod': 'HmacSHA256', // 签名方法
87
+ 'httpProfile': {
88
+ 'reqMethod': 'POST', // 请求方法
89
+ 'reqTimeout': 30, // 请求超时时间,默认60s
90
+ }
91
+ }
92
+ });
93
+ const io = opt.token.indexOf('|');
94
+ if (io === -1) {
95
+ return false;
96
+ }
97
+ const res = await client.DescribeCaptchaResult({
98
+ 'CaptchaType': 9,
99
+ 'Ticket': opt.token.slice(0, io),
100
+ 'UserIp': opt.ip,
101
+ 'Randstr': opt.token.slice(io + 1),
102
+ 'CaptchaAppId': parseInt(config.turnstile['TENCENT'].aid), // --- 防止后期又不是 number 了还要改config,这样只需要更新代码无损升级 ---
103
+ 'AppSecretKey': config.turnstile['TENCENT'].akey,
104
+ });
105
+ return res.CaptchaCode === 1;
106
+ }
107
+ }
108
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maiyunnet/kebab",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
4
4
  "description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
5
5
  "keywords": [
6
6
  "kebab",
package/sys/cmd.js CHANGED
@@ -169,6 +169,16 @@ async function run() {
169
169
  config.s3['TENCENT'].skey = '';
170
170
  config.s3['TENCENT'].region = '';
171
171
  config.s3['TENCENT'].bucket = '';
172
+ // --- config - turnstile ---
173
+ config.turnstile ??= {};
174
+ config.turnstile['CF'] ??= {};
175
+ config.turnstile['CF'].sid ??= '';
176
+ config.turnstile['CF'].skey ??= '';
177
+ config.turnstile['TENCENT'] ??= {};
178
+ config.turnstile['TENCENT'].sid ??= '';
179
+ config.turnstile['TENCENT'].skey ??= '';
180
+ config.turnstile['TENCENT'].aid ??= '';
181
+ config.turnstile['TENCENT'].akey ??= '';
172
182
  // --- 保存 config.json ---
173
183
  if (!await lFs.putContent(kebab.CONF_CWD + 'config.json', lText.stringifyJson(config, 4))) {
174
184
  lCore.display('KEBAB', 'CREATE', 'FILE', kebab.CONF_CWD + 'config.json', '[FAILED]');
package/sys/ctr.js CHANGED
@@ -690,7 +690,7 @@ class Ctr {
690
690
  this._res.setHeader('access-control-allow-headers', '*');
691
691
  this._res.setHeader('access-control-allow-methods', '*');
692
692
  if (this._req.method === 'OPTIONS') {
693
- this._res.setHeader('access-control-max-age', '600');
693
+ this._res.setHeader('access-control-max-age', '3600');
694
694
  return false;
695
695
  }
696
696
  return true;
package/sys/mod.d.ts CHANGED
@@ -33,6 +33,8 @@ export default class Mod {
33
33
  protected static _$primary: string;
34
34
  /** --- 设置后将由 _keyGenerator 函数生成唯一字段 --- */
35
35
  protected static _$key: string;
36
+ /** --- 若使用 _$key 并且有多个 unique 索引,这里指定 _$key 的索引名 --- */
37
+ protected static _$index: string;
36
38
  /** ---- 可开启软删软更新软新增 --- */
37
39
  protected static _$soft: boolean;
38
40
  /** --- 要 update 的内容 --- */
package/sys/mod.js CHANGED
@@ -353,8 +353,8 @@ class Mod {
353
353
  if (typeof opt.index === 'string') {
354
354
  opt.index = [opt.index];
355
355
  }
356
- else if (!opt.index) {
357
- opt.index = [''];
356
+ else {
357
+ opt.index ??= [''];
358
358
  }
359
359
  if (this._$soft && !opt.raw) {
360
360
  if (typeof where === 'string') {
@@ -657,9 +657,7 @@ class Mod {
657
657
  for (const k in this._updates) {
658
658
  updates[k] = this._data[k];
659
659
  }
660
- if (!table) {
661
- table = cstr._$table + (this._index ? ('_' + this._index[0]) : '');
662
- }
660
+ table ??= cstr._$table + (this._index ? ('_' + this._index[0]) : '');
663
661
  let r = null;
664
662
  if ((cstr._$key !== '') && (updates[cstr._$key] === undefined)) {
665
663
  let count = 0;
@@ -682,18 +680,29 @@ class Mod {
682
680
  if (!r.error) {
683
681
  break;
684
682
  }
685
- if (r.error.errno !== 1062) {
686
- await lCore.log(this._ctr ?? {
687
- 'path': '',
688
- 'urlFull': '',
689
- 'hostname': '',
690
- 'req': null,
691
- 'get': {},
692
- 'cookie': {},
693
- 'headers': {}
694
- }, '[create0, mod] [' + table + '] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
695
- return false;
683
+ if (r.error.errno === 1062) {
684
+ // --- 与唯一键冲突 ---
685
+ if (!cstr._$index) {
686
+ // --- 没设置 index,那就当做是本次生成的 key 重复了 ---
687
+ continue;
688
+ }
689
+ const match = /for key '([\w.]+)'/.exec(r.error.message);
690
+ if (match?.[1].includes(cstr._$index)) {
691
+ // --- 确实重复了 ---
692
+ continue;
693
+ }
696
694
  }
695
+ // --- 未处理的错误 ---
696
+ await lCore.log(this._ctr ?? {
697
+ 'path': '',
698
+ 'urlFull': '',
699
+ 'hostname': '',
700
+ 'req': null,
701
+ 'get': {},
702
+ 'cookie': {},
703
+ 'headers': {}
704
+ }, '[create0, mod] [' + table + '] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
705
+ return false;
697
706
  }
698
707
  }
699
708
  else {
@@ -1603,6 +1612,8 @@ Mod._$table = '';
1603
1612
  Mod._$primary = 'id';
1604
1613
  /** --- 设置后将由 _keyGenerator 函数生成唯一字段 --- */
1605
1614
  Mod._$key = '';
1615
+ /** --- 若使用 _$key 并且有多个 unique 索引,这里指定 _$key 的索引名 --- */
1616
+ Mod._$index = '';
1606
1617
  /** ---- 可开启软删软更新软新增 --- */
1607
1618
  Mod._$soft = false;
1608
1619
  exports.default = Mod;
@@ -548,6 +548,7 @@ Result:<pre id="result">Nothing.</pre>` + this._getEnd();
548
548
  'ctr': this
549
549
  });
550
550
  test.set({
551
+ 'name': 'nam' + lCore.rand(0, 3).toString(),
551
552
  'point': { 'x': lCore.rand(0, 99), 'y': lCore.rand(0, 99) },
552
553
  'polygon': [
553
554
  [
@@ -566,6 +567,7 @@ const test = mTest.getCreate<mTest>(db, {
566
567
  'ctr': this
567
568
  });
568
569
  test.set({
570
+ 'name': 'nam' + lCore.rand(0, 4).toString(),
569
571
  'point': { 'x': lCore.rand(0, 99), 'y': lCore.rand(0, 99) },
570
572
  'polygon': [
571
573
  [
@@ -744,6 +746,7 @@ CREATE TABLE \`m_test_data_0\` (
744
746
  'ctr': this
745
747
  });
746
748
  test.set({
749
+ 'name': lCore.random(4),
747
750
  'token': lCore.random(lCore.rand(8, 32)),
748
751
  'point': {
749
752
  'x': 10,
@@ -4,7 +4,9 @@ export default class extends sMod {
4
4
  protected static _$table: string;
5
5
  protected static _$primary: string;
6
6
  protected static _$key: string;
7
+ protected static _$index: string;
7
8
  id: number;
9
+ name: string;
8
10
  token: string;
9
11
  point: {
10
12
  'x': number;
@@ -39,25 +39,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  const lCore = __importStar(require("../../../lib/core"));
40
40
  const mod_1 = __importDefault(require("../../../sys/mod"));
41
41
  /*
42
- CREATE TABLE `m_test` (
43
- `id` INT NOT NULL AUTO_INCREMENT,
44
- `token` CHAR(16) NOT NULL COLLATE 'ascii_bin',
45
- `point` POINT NOT NULL,
46
- `polygon` POLYGON NULL DEFAULT NULL,
47
- `json` JSON NULL DEFAULT NULL,
48
- `time_add` BIGINT NOT NULL,
42
+ CREATE TABLE `m_test` (
43
+ `id` int NOT NULL AUTO_INCREMENT,
44
+ `name` char(4) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
45
+ `token` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
46
+ `point` point NOT NULL,
47
+ `polygon` polygon NULL,
48
+ `json` json NULL,
49
+ `time_add` bigint NOT NULL,
49
50
  PRIMARY KEY (`id`) USING BTREE,
50
- UNIQUE INDEX `token` (`token`) USING BTREE,
51
- INDEX `time_add` (`time_add`) USING BTREE
52
- ) ENGINE=InnoDB COLLATE=utf8mb4_general_ci;
51
+ INDEX `time_add`(`time_add` ASC) USING BTREE,
52
+ UNIQUE INDEX `utoken`(`token` ASC) USING BTREE,
53
+ UNIQUE INDEX `uname`(`name` ASC) USING BTREE
54
+ ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
53
55
  */
54
56
  class default_1 extends mod_1.default {
55
57
  /* eslint-enable */
56
58
  _keyGenerator() {
57
- return 'test_' + lCore.rand(0, 5).toString();
59
+ return 'test_' + lCore.rand(0, 3).toString();
58
60
  }
59
61
  }
60
62
  default_1._$table = 'test';
61
63
  default_1._$primary = 'id';
62
64
  default_1._$key = 'token';
65
+ default_1._$index = 'utoken';
63
66
  exports.default = default_1;