befly 3.9.38 → 3.9.39

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 (155) hide show
  1. package/README.md +37 -38
  2. package/befly.config.ts +62 -40
  3. package/checks/checkApi.ts +16 -16
  4. package/checks/checkApp.ts +19 -25
  5. package/checks/checkTable.ts +42 -42
  6. package/docs/README.md +42 -35
  7. package/docs/{api.md → api/api.md} +223 -231
  8. package/docs/cipher.md +71 -69
  9. package/docs/database.md +143 -141
  10. package/docs/{examples.md → guide/examples.md} +181 -181
  11. package/docs/guide/quickstart.md +331 -0
  12. package/docs/hooks/auth.md +38 -0
  13. package/docs/hooks/cors.md +28 -0
  14. package/docs/{hook.md → hooks/hook.md} +140 -57
  15. package/docs/hooks/parser.md +19 -0
  16. package/docs/hooks/rateLimit.md +47 -0
  17. package/docs/{redis.md → infra/redis.md} +84 -93
  18. package/docs/plugins/cipher.md +61 -0
  19. package/docs/plugins/database.md +128 -0
  20. package/docs/{plugin.md → plugins/plugin.md} +83 -81
  21. package/docs/quickstart.md +26 -26
  22. package/docs/{addon.md → reference/addon.md} +46 -46
  23. package/docs/{config.md → reference/config.md} +32 -80
  24. package/docs/{logger.md → reference/logger.md} +52 -52
  25. package/docs/{sync.md → reference/sync.md} +32 -35
  26. package/docs/{table.md → reference/table.md} +1 -1
  27. package/docs/{validator.md → reference/validator.md} +57 -57
  28. package/hooks/auth.ts +8 -4
  29. package/hooks/cors.ts +13 -13
  30. package/hooks/parser.ts +37 -17
  31. package/hooks/permission.ts +26 -14
  32. package/hooks/rateLimit.ts +276 -0
  33. package/hooks/validator.ts +7 -7
  34. package/lib/asyncContext.ts +43 -0
  35. package/lib/cacheHelper.ts +212 -77
  36. package/lib/cacheKeys.ts +38 -0
  37. package/lib/cipher.ts +30 -30
  38. package/lib/connect.ts +28 -28
  39. package/lib/dbHelper.ts +183 -102
  40. package/lib/jwt.ts +16 -16
  41. package/lib/logger.ts +610 -19
  42. package/lib/redisHelper.ts +185 -44
  43. package/lib/sqlBuilder.ts +90 -91
  44. package/lib/validator.ts +59 -39
  45. package/loader/loadApis.ts +48 -44
  46. package/loader/loadHooks.ts +40 -14
  47. package/loader/loadPlugins.ts +16 -17
  48. package/main.ts +57 -47
  49. package/package.json +47 -45
  50. package/paths.ts +15 -14
  51. package/plugins/cache.ts +5 -4
  52. package/plugins/cipher.ts +3 -3
  53. package/plugins/config.ts +2 -2
  54. package/plugins/db.ts +9 -9
  55. package/plugins/jwt.ts +3 -3
  56. package/plugins/logger.ts +8 -12
  57. package/plugins/redis.ts +8 -8
  58. package/plugins/tool.ts +6 -6
  59. package/router/api.ts +85 -56
  60. package/router/static.ts +12 -12
  61. package/sync/syncAll.ts +12 -12
  62. package/sync/syncApi.ts +55 -52
  63. package/sync/syncDb/apply.ts +20 -19
  64. package/sync/syncDb/constants.ts +25 -23
  65. package/sync/syncDb/ddl.ts +35 -36
  66. package/sync/syncDb/helpers.ts +6 -9
  67. package/sync/syncDb/schema.ts +10 -9
  68. package/sync/syncDb/sqlite.ts +7 -8
  69. package/sync/syncDb/table.ts +37 -35
  70. package/sync/syncDb/tableCreate.ts +21 -20
  71. package/sync/syncDb/types.ts +23 -20
  72. package/sync/syncDb/version.ts +10 -10
  73. package/sync/syncDb.ts +43 -36
  74. package/sync/syncDev.ts +74 -65
  75. package/sync/syncMenu.ts +190 -55
  76. package/tests/api-integration-array-number.test.ts +282 -0
  77. package/tests/befly-config-env.test.ts +78 -0
  78. package/tests/cacheHelper.test.ts +135 -104
  79. package/tests/cacheKeys.test.ts +41 -0
  80. package/tests/cipher.test.ts +90 -89
  81. package/tests/dbHelper-advanced.test.ts +140 -134
  82. package/tests/dbHelper-all-array-types.test.ts +316 -0
  83. package/tests/dbHelper-array-serialization.test.ts +258 -0
  84. package/tests/dbHelper-columns.test.ts +56 -55
  85. package/tests/dbHelper-execute.test.ts +45 -44
  86. package/tests/dbHelper-joins.test.ts +124 -119
  87. package/tests/fields-redis-cache.test.ts +29 -27
  88. package/tests/fields-validate.test.ts +38 -38
  89. package/tests/getClientIp.test.ts +54 -0
  90. package/tests/integration.test.ts +69 -67
  91. package/tests/jwt.test.ts +27 -26
  92. package/tests/logger.test.ts +267 -34
  93. package/tests/rateLimit-hook.test.ts +477 -0
  94. package/tests/redisHelper.test.ts +187 -188
  95. package/tests/redisKeys.test.ts +6 -73
  96. package/tests/scanConfig.test.ts +144 -0
  97. package/tests/sqlBuilder-advanced.test.ts +217 -215
  98. package/tests/sqlBuilder.test.ts +92 -91
  99. package/tests/sync-connection.test.ts +29 -29
  100. package/tests/syncDb-apply.test.ts +97 -96
  101. package/tests/syncDb-array-number.test.ts +160 -0
  102. package/tests/syncDb-constants.test.ts +48 -47
  103. package/tests/syncDb-ddl.test.ts +99 -98
  104. package/tests/syncDb-helpers.test.ts +29 -28
  105. package/tests/syncDb-schema.test.ts +61 -60
  106. package/tests/syncDb-types.test.ts +60 -59
  107. package/tests/syncMenu-paths.test.ts +68 -0
  108. package/tests/util.test.ts +42 -41
  109. package/tests/validator-array-number.test.ts +310 -0
  110. package/tests/validator-default.test.ts +373 -0
  111. package/tests/validator.test.ts +271 -266
  112. package/tsconfig.json +4 -5
  113. package/types/api.d.ts +7 -12
  114. package/types/befly.d.ts +60 -13
  115. package/types/cache.d.ts +8 -4
  116. package/types/common.d.ts +17 -9
  117. package/types/context.d.ts +2 -2
  118. package/types/crypto.d.ts +23 -0
  119. package/types/database.d.ts +19 -19
  120. package/types/hook.d.ts +2 -2
  121. package/types/jwt.d.ts +118 -0
  122. package/types/logger.d.ts +30 -0
  123. package/types/plugin.d.ts +4 -4
  124. package/types/redis.d.ts +7 -3
  125. package/types/roleApisCache.ts +23 -0
  126. package/types/sync.d.ts +10 -10
  127. package/types/table.d.ts +50 -9
  128. package/types/validate.d.ts +69 -0
  129. package/utils/addonHelper.ts +90 -0
  130. package/utils/arrayKeysToCamel.ts +18 -0
  131. package/utils/calcPerfTime.ts +13 -0
  132. package/utils/configTypes.ts +3 -0
  133. package/utils/cors.ts +19 -0
  134. package/utils/fieldClear.ts +75 -0
  135. package/utils/genShortId.ts +12 -0
  136. package/utils/getClientIp.ts +45 -0
  137. package/utils/keysToCamel.ts +22 -0
  138. package/utils/keysToSnake.ts +22 -0
  139. package/utils/modules.ts +98 -0
  140. package/utils/pickFields.ts +19 -0
  141. package/utils/process.ts +56 -0
  142. package/utils/regex.ts +225 -0
  143. package/utils/response.ts +115 -0
  144. package/utils/route.ts +23 -0
  145. package/utils/scanConfig.ts +142 -0
  146. package/utils/scanFiles.ts +48 -0
  147. package/.prettierignore +0 -2
  148. package/.prettierrc +0 -12
  149. package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
  150. package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
  151. package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
  152. package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
  153. package/hooks/requestLogger.ts +0 -84
  154. package/types/index.ts +0 -24
  155. package/util.ts +0 -283
package/docs/cipher.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > 哈希、签名、密码加密与 JWT 令牌
4
4
 
5
+ > 本文档已迁移到:[`./plugins/cipher.md`](./plugins/cipher.md)
6
+
5
7
  ## 目录
6
8
 
7
9
  - [概述](#概述)
@@ -37,7 +39,7 @@ Befly 提供两个安全相关的工具:
37
39
  ### 基本导入
38
40
 
39
41
  ```typescript
40
- import { Cipher } from '../lib/cipher.js';
42
+ import { Cipher } from "../lib/cipher.js";
41
43
  ```
42
44
 
43
45
  ### 哈希算法
@@ -46,31 +48,31 @@ import { Cipher } from '../lib/cipher.js';
46
48
 
47
49
  ```typescript
48
50
  // 基本用法
49
- const hash = Cipher.md5('hello');
51
+ const hash = Cipher.md5("hello");
50
52
  // '5d41402abc4b2a76b9719d911017c592'
51
53
 
52
54
  // 指定编码
53
- const hashBase64 = Cipher.md5('hello', 'base64');
55
+ const hashBase64 = Cipher.md5("hello", "base64");
54
56
  ```
55
57
 
56
58
  #### SHA-1
57
59
 
58
60
  ```typescript
59
- const hash = Cipher.sha1('hello');
61
+ const hash = Cipher.sha1("hello");
60
62
  // 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
61
63
  ```
62
64
 
63
65
  #### SHA-256
64
66
 
65
67
  ```typescript
66
- const hash = Cipher.sha256('hello');
68
+ const hash = Cipher.sha256("hello");
67
69
  // '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
68
70
  ```
69
71
 
70
72
  #### SHA-512
71
73
 
72
74
  ```typescript
73
- const hash = Cipher.sha512('hello');
75
+ const hash = Cipher.sha512("hello");
74
76
  // '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca...'
75
77
  ```
76
78
 
@@ -78,9 +80,9 @@ const hash = Cipher.sha512('hello');
78
80
 
79
81
  ```typescript
80
82
  // 支持多种算法
81
- const hash = Cipher.hash('sha256', 'hello');
82
- const hash2 = Cipher.hash('sha384', 'hello');
83
- const hash3 = Cipher.hash('blake2b256', 'hello');
83
+ const hash = Cipher.hash("sha256", "hello");
84
+ const hash2 = Cipher.hash("sha384", "hello");
85
+ const hash3 = Cipher.hash("blake2b256", "hello");
84
86
  ```
85
87
 
86
88
  #### 支持的算法
@@ -108,22 +110,22 @@ const hash3 = Cipher.hash('blake2b256', 'hello');
108
110
  HMAC 使用密钥进行签名,用于数据完整性验证:
109
111
 
110
112
  ```typescript
111
- const key = 'my-secret-key';
113
+ const key = "my-secret-key";
112
114
 
113
115
  // HMAC-MD5
114
- const sig1 = Cipher.hmacMd5(key, 'data');
116
+ const sig1 = Cipher.hmacMd5(key, "data");
115
117
 
116
118
  // HMAC-SHA1
117
- const sig2 = Cipher.hmacSha1(key, 'data');
119
+ const sig2 = Cipher.hmacSha1(key, "data");
118
120
 
119
121
  // HMAC-SHA256(推荐)
120
- const sig3 = Cipher.hmacSha256(key, 'data');
122
+ const sig3 = Cipher.hmacSha256(key, "data");
121
123
 
122
124
  // HMAC-SHA512
123
- const sig4 = Cipher.hmacSha512(key, 'data');
125
+ const sig4 = Cipher.hmacSha512(key, "data");
124
126
 
125
127
  // 通用 HMAC
126
- const sig5 = Cipher.hmac('sha256', key, 'data');
128
+ const sig5 = Cipher.hmac("sha256", key, "data");
127
129
  ```
128
130
 
129
131
  #### RSA-SHA256 签名
@@ -135,9 +137,9 @@ const privateKey = `-----BEGIN PRIVATE KEY-----
135
137
  MIIEvQIBADANBg...
136
138
  -----END PRIVATE KEY-----`;
137
139
 
138
- const signature = Cipher.rsaSha256('data to sign', privateKey);
140
+ const signature = Cipher.rsaSha256("data to sign", privateKey);
139
141
  // 或指定编码
140
- const signatureBase64 = Cipher.rsaSha256('data to sign', privateKey, 'base64');
142
+ const signatureBase64 = Cipher.rsaSha256("data to sign", privateKey, "base64");
141
143
  ```
142
144
 
143
145
  ### 密码加密
@@ -148,17 +150,17 @@ const signatureBase64 = Cipher.rsaSha256('data to sign', privateKey, 'base64');
148
150
 
149
151
  ```typescript
150
152
  // 默认配置(推荐)
151
- const hash = await Cipher.hashPassword('123456');
153
+ const hash = await Cipher.hashPassword("123456");
152
154
  // '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92...'
153
155
 
154
156
  // 自定义强度(cost 越高越安全但越慢)
155
- const hash2 = await Cipher.hashPassword('123456', { cost: 12 });
157
+ const hash2 = await Cipher.hashPassword("123456", { cost: 12 });
156
158
  ```
157
159
 
158
160
  #### 验证密码
159
161
 
160
162
  ```typescript
161
- const isValid = await Cipher.verifyPassword('123456', storedHash);
163
+ const isValid = await Cipher.verifyPassword("123456", storedHash);
162
164
  if (isValid) {
163
165
  // 密码正确
164
166
  }
@@ -182,11 +184,11 @@ if (isValid) {
182
184
 
183
185
  ```typescript
184
186
  // 编码
185
- const encoded = Cipher.base64Encode('hello');
187
+ const encoded = Cipher.base64Encode("hello");
186
188
  // 'aGVsbG8='
187
189
 
188
190
  // 解码
189
- const decoded = Cipher.base64Decode('aGVsbG8=');
191
+ const decoded = Cipher.base64Decode("aGVsbG8=");
190
192
  // 'hello'
191
193
  ```
192
194
 
@@ -202,19 +204,19 @@ const random = Cipher.randomString(32);
202
204
 
203
205
  ```typescript
204
206
  // 计算文件哈希(异步)
205
- const fileHash = await Cipher.hashFile('/path/to/file.txt');
207
+ const fileHash = await Cipher.hashFile("/path/to/file.txt");
206
208
  // 默认 SHA-256
207
209
 
208
210
  // 指定算法
209
- const md5Hash = await Cipher.hashFile('/path/to/file.txt', 'md5');
211
+ const md5Hash = await Cipher.hashFile("/path/to/file.txt", "md5");
210
212
  ```
211
213
 
212
214
  #### 快速哈希(非密码学)
213
215
 
214
216
  ```typescript
215
217
  // 高性能哈希,用于数据指纹、去重等
216
- const hash = Cipher.fastHash('data');
217
- const hashWithSeed = Cipher.fastHash('data', 12345);
218
+ const hash = Cipher.fastHash("data");
219
+ const hashWithSeed = Cipher.fastHash("data", 12345);
218
220
  ```
219
221
 
220
222
  ---
@@ -226,12 +228,12 @@ JWT (JSON Web Token) 用于用户认证和 API 授权。
226
228
  ### 基本导入
227
229
 
228
230
  ```typescript
229
- import { Jwt } from '../lib/jwt.js';
231
+ import { Jwt } from "../lib/jwt.js";
230
232
 
231
233
  const jwt = new Jwt({
232
- secret: 'your-secret-key',
233
- expiresIn: '7d',
234
- algorithm: 'HS256'
234
+ secret: "your-secret-key",
235
+ expiresIn: "7d",
236
+ algorithm: "HS256"
235
237
  });
236
238
  ```
237
239
 
@@ -283,17 +285,17 @@ interface AuthConfig {
283
285
 
284
286
  ```typescript
285
287
  // 基本用法
286
- const token = jwt.sign({ userId: 123, role: 'admin' });
288
+ const token = jwt.sign({ userId: 123, role: "admin" });
287
289
 
288
290
  // 自定义选项
289
291
  const token2 = jwt.sign(
290
292
  { userId: 123 },
291
293
  {
292
- expiresIn: '1h',
293
- issuer: 'my-app',
294
- audience: 'users',
295
- subject: 'auth',
296
- jwtId: 'unique-id'
294
+ expiresIn: "1h",
295
+ issuer: "my-app",
296
+ audience: "users",
297
+ subject: "auth",
298
+ jwtId: "unique-id"
297
299
  }
298
300
  );
299
301
  ```
@@ -329,10 +331,10 @@ try {
329
331
  const payload = jwt.verify(token, {
330
332
  ignoreExpiration: false, // 是否忽略过期
331
333
  ignoreNotBefore: false, // 是否忽略 nbf
332
- issuer: 'my-app', // 验证签发者
333
- audience: 'users', // 验证受众
334
- subject: 'auth', // 验证主题
335
- algorithms: ['HS256'] // 允许的算法
334
+ issuer: "my-app", // 验证签发者
335
+ audience: "users", // 验证受众
336
+ subject: "auth", // 验证主题
337
+ algorithms: ["HS256"] // 允许的算法
336
338
  });
337
339
  ```
338
340
 
@@ -361,11 +363,11 @@ console.log(decoded.signature); // 签名字符串
361
363
  ```typescript
362
364
  // 通过 befly 访问
363
365
  export default {
364
- name: '示例接口',
366
+ name: "示例接口",
365
367
  handler: async (befly, ctx) => {
366
- const hash = befly.cipher.sha256('data');
368
+ const hash = befly.cipher.sha256("data");
367
369
  const isValid = await befly.cipher.verifyPassword(password, storedHash);
368
- return Yes('成功');
370
+ return Yes("成功");
369
371
  }
370
372
  } as ApiRoute;
371
373
  ```
@@ -375,7 +377,7 @@ export default {
375
377
  JWT 插件自动读取配置文件中的 `auth` 配置:
376
378
 
377
379
  ```json
378
- // befly.dev.json
380
+ // befly.development.json
379
381
  {
380
382
  "auth": {
381
383
  "secret": "your-dev-secret",
@@ -388,12 +390,12 @@ JWT 插件自动读取配置文件中的 `auth` 配置:
388
390
  ```typescript
389
391
  // 通过 befly 访问
390
392
  export default {
391
- name: '登录',
393
+ name: "登录",
392
394
  auth: false,
393
395
  handler: async (befly, ctx) => {
394
396
  // 签发令牌
395
397
  const token = befly.jwt.sign({ userId: user.id, role: user.role });
396
- return Yes('登录成功', { token: token });
398
+ return Yes("登录成功", { token: token });
397
399
  }
398
400
  } as ApiRoute;
399
401
  ```
@@ -406,27 +408,27 @@ export default {
406
408
 
407
409
  ```typescript
408
410
  export default {
409
- name: '用户注册',
411
+ name: "用户注册",
410
412
  auth: false,
411
413
  fields: {
412
- email: { name: '邮箱', type: 'string', regexp: '@email' },
413
- password: { name: '密码', type: 'string', min: 6, max: 100 }
414
+ email: { name: "邮箱", type: "string", regexp: "@email" },
415
+ password: { name: "密码", type: "string", min: 6, max: 100 }
414
416
  },
415
- required: ['email', 'password'],
417
+ required: ["email", "password"],
416
418
  handler: async (befly, ctx) => {
417
419
  // 加密密码
418
420
  const hashedPassword = await befly.cipher.hashPassword(ctx.body.password);
419
421
 
420
422
  // 存储用户
421
423
  await befly.db.insData({
422
- table: 'user',
424
+ table: "user",
423
425
  data: {
424
426
  email: ctx.body.email,
425
427
  password: hashedPassword
426
428
  }
427
429
  });
428
430
 
429
- return Yes('注册成功');
431
+ return Yes("注册成功");
430
432
  }
431
433
  } as ApiRoute;
432
434
  ```
@@ -435,29 +437,29 @@ export default {
435
437
 
436
438
  ```typescript
437
439
  export default {
438
- name: '用户登录',
440
+ name: "用户登录",
439
441
  auth: false,
440
442
  fields: {
441
- email: { name: '邮箱', type: 'string', regexp: '@email' },
442
- password: { name: '密码', type: 'string', min: 6, max: 100 }
443
+ email: { name: "邮箱", type: "string", regexp: "@email" },
444
+ password: { name: "密码", type: "string", min: 6, max: 100 }
443
445
  },
444
- required: ['email', 'password'],
446
+ required: ["email", "password"],
445
447
  handler: async (befly, ctx) => {
446
448
  // 查询用户
447
449
  const user = await befly.db.getDetail({
448
- table: 'user',
449
- columns: ['id', 'email', 'password', 'role'],
450
+ table: "user",
451
+ columns: ["id", "email", "password", "role"],
450
452
  where: { email: ctx.body.email }
451
453
  });
452
454
 
453
455
  if (!user?.id) {
454
- return No('用户不存在');
456
+ return No("用户不存在");
455
457
  }
456
458
 
457
459
  // 验证密码
458
460
  const isValid = await befly.cipher.verifyPassword(ctx.body.password, user.password);
459
461
  if (!isValid) {
460
- return No('密码错误');
462
+ return No("密码错误");
461
463
  }
462
464
 
463
465
  // 签发令牌
@@ -466,7 +468,7 @@ export default {
466
468
  role: user.role
467
469
  });
468
470
 
469
- return Yes('登录成功', { token: token });
471
+ return Yes("登录成功", { token: token });
470
472
  }
471
473
  } as ApiRoute;
472
474
  ```
@@ -475,25 +477,25 @@ export default {
475
477
 
476
478
  ```typescript
477
479
  export default {
478
- name: '第三方回调',
480
+ name: "第三方回调",
479
481
  auth: false,
480
482
  handler: async (befly, ctx) => {
481
483
  const { data, signature, timestamp } = ctx.body;
482
484
 
483
485
  // 验证时间戳(5分钟内有效)
484
486
  if (Date.now() - timestamp > 5 * 60 * 1000) {
485
- return No('请求已过期');
487
+ return No("请求已过期");
486
488
  }
487
489
 
488
490
  // 验证签名
489
- const expectedSig = befly.cipher.hmacSha256('api-secret-key', `${data}${timestamp}`);
491
+ const expectedSig = befly.cipher.hmacSha256("api-secret-key", `${data}${timestamp}`);
490
492
 
491
493
  if (signature !== expectedSig) {
492
- return No('签名验证失败');
494
+ return No("签名验证失败");
493
495
  }
494
496
 
495
497
  // 处理业务逻辑
496
- return Yes('验证成功');
498
+ return Yes("验证成功");
497
499
  }
498
500
  } as ApiRoute;
499
501
  ```
@@ -502,7 +504,7 @@ export default {
502
504
 
503
505
  ```typescript
504
506
  export default {
505
- name: '上传文件',
507
+ name: "上传文件",
506
508
  handler: async (befly, ctx) => {
507
509
  const { filePath, expectedHash } = ctx.body;
508
510
 
@@ -510,10 +512,10 @@ export default {
510
512
  const actualHash = await befly.cipher.hashFile(filePath);
511
513
 
512
514
  if (actualHash !== expectedHash) {
513
- return No('文件校验失败');
515
+ return No("文件校验失败");
514
516
  }
515
517
 
516
- return Yes('文件校验通过');
518
+ return Yes("文件校验通过");
517
519
  }
518
520
  } as ApiRoute;
519
521
  ```