befly 3.9.37 → 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 +38 -39
  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} +225 -235
  8. package/docs/cipher.md +71 -69
  9. package/docs/database.md +155 -153
  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} +7 -7
  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 +15 -7
  34. package/lib/asyncContext.ts +43 -0
  35. package/lib/cacheHelper.ts +212 -81
  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 +211 -109
  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 +53 -47
  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 -54
  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 -66
  75. package/sync/syncMenu.ts +190 -57
  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
@@ -5,95 +5,95 @@
5
5
 
6
6
  // 模拟测试函数(从 dbHelper 复制的逻辑)
7
7
  function validateAndClassifyFields(fields?: string[]): {
8
- type: 'all' | 'include' | 'exclude';
8
+ type: "all" | "include" | "exclude";
9
9
  fields: string[];
10
10
  } {
11
11
  // 情况1:空数组或 undefined,表示查询所有
12
12
  if (!fields || fields.length === 0) {
13
- return { type: 'all', fields: [] };
13
+ return { type: "all", fields: [] };
14
14
  }
15
15
 
16
16
  // 检测是否有星号(禁止)
17
- if (fields.some((f) => f === '*')) {
18
- throw new Error('fields 不支持 * 星号,请使用空数组 [] 或不传参数表示查询所有字段');
17
+ if (fields.some((f) => f === "*")) {
18
+ throw new Error("fields 不支持 * 星号,请使用空数组 [] 或不传参数表示查询所有字段");
19
19
  }
20
20
 
21
21
  // 检测是否有空字符串或无效值
22
- if (fields.some((f) => !f || typeof f !== 'string' || f.trim() === '')) {
23
- throw new Error('fields 不能包含空字符串或无效值');
22
+ if (fields.some((f) => !f || typeof f !== "string" || f.trim() === "")) {
23
+ throw new Error("fields 不能包含空字符串或无效值");
24
24
  }
25
25
 
26
26
  // 统计包含字段和排除字段
27
- const includeFields = fields.filter((f) => !f.startsWith('!'));
28
- const excludeFields = fields.filter((f) => f.startsWith('!'));
27
+ const includeFields = fields.filter((f) => !f.startsWith("!"));
28
+ const excludeFields = fields.filter((f) => f.startsWith("!"));
29
29
 
30
30
  // 情况2:全部是包含字段
31
31
  if (includeFields.length > 0 && excludeFields.length === 0) {
32
- return { type: 'include', fields: includeFields };
32
+ return { type: "include", fields: includeFields };
33
33
  }
34
34
 
35
35
  // 情况3:全部是排除字段
36
36
  if (excludeFields.length > 0 && includeFields.length === 0) {
37
37
  // 去掉感叹号前缀
38
38
  const cleanExcludeFields = excludeFields.map((f) => f.substring(1));
39
- return { type: 'exclude', fields: cleanExcludeFields };
39
+ return { type: "exclude", fields: cleanExcludeFields };
40
40
  }
41
41
 
42
42
  // 混用情况:报错
43
43
  throw new Error('fields 不能同时包含普通字段和排除字段(! 开头)。只能使用以下3种方式之一:\n1. 空数组 [] 或不传(查询所有)\n2. 全部指定字段 ["id", "name"]\n3. 全部排除字段 ["!password", "!token"]');
44
44
  }
45
45
 
46
- console.log('\n========== 测试 validateAndClassifyFields ==========\n');
46
+ console.log("\n========== 测试 validateAndClassifyFields ==========\n");
47
47
 
48
48
  // 测试1:空数组
49
- console.log('【测试1】空数组');
49
+ console.log("【测试1】空数组");
50
50
  const test1 = validateAndClassifyFields([]);
51
- console.log('结果:', test1);
52
- console.log('✅ 通过\n');
51
+ console.log("结果:", test1);
52
+ console.log("✅ 通过\n");
53
53
 
54
54
  // 测试2:undefined
55
- console.log('【测试2】undefined');
55
+ console.log("【测试2】undefined");
56
56
  const test2 = validateAndClassifyFields(undefined);
57
- console.log('结果:', test2);
58
- console.log('✅ 通过\n');
57
+ console.log("结果:", test2);
58
+ console.log("✅ 通过\n");
59
59
 
60
60
  // 测试3:包含字段
61
- console.log('【测试3】包含字段');
62
- const test3 = validateAndClassifyFields(['id', 'name', 'email']);
63
- console.log('结果:', test3);
64
- console.log('✅ 通过\n');
61
+ console.log("【测试3】包含字段");
62
+ const test3 = validateAndClassifyFields(["id", "name", "email"]);
63
+ console.log("结果:", test3);
64
+ console.log("✅ 通过\n");
65
65
 
66
66
  // 测试4:排除字段
67
- console.log('【测试4】排除字段');
68
- const test4 = validateAndClassifyFields(['!password', '!salt']);
69
- console.log('结果:', test4);
70
- console.log('✅ 通过\n');
67
+ console.log("【测试4】排除字段");
68
+ const test4 = validateAndClassifyFields(["!password", "!salt"]);
69
+ console.log("结果:", test4);
70
+ console.log("✅ 通过\n");
71
71
 
72
72
  // 测试5:混用(应该报错)
73
- console.log('【测试5】混用(应该报错)');
73
+ console.log("【测试5】混用(应该报错)");
74
74
  try {
75
- validateAndClassifyFields(['id', '!password']);
76
- console.log('❌ 没有抛出错误\n');
75
+ validateAndClassifyFields(["id", "!password"]);
76
+ console.log("❌ 没有抛出错误\n");
77
77
  } catch (error: any) {
78
- console.log('✅ 成功捕获错误:', error.message, '\n');
78
+ console.log("✅ 成功捕获错误:", error.message, "\n");
79
79
  }
80
80
 
81
81
  // 测试6:星号(应该报错)
82
- console.log('【测试6】星号(应该报错)');
82
+ console.log("【测试6】星号(应该报错)");
83
83
  try {
84
- validateAndClassifyFields(['*']);
85
- console.log('❌ 没有抛出错误\n');
84
+ validateAndClassifyFields(["*"]);
85
+ console.log("❌ 没有抛出错误\n");
86
86
  } catch (error: any) {
87
- console.log('✅ 成功捕获错误:', error.message, '\n');
87
+ console.log("✅ 成功捕获错误:", error.message, "\n");
88
88
  }
89
89
 
90
90
  // 测试7:空字符串(应该报错)
91
- console.log('【测试7】空字符串(应该报错)');
91
+ console.log("【测试7】空字符串(应该报错)");
92
92
  try {
93
- validateAndClassifyFields(['id', '', 'name']);
94
- console.log('❌ 没有抛出错误\n');
93
+ validateAndClassifyFields(["id", "", "name"]);
94
+ console.log("❌ 没有抛出错误\n");
95
95
  } catch (error: any) {
96
- console.log('✅ 成功捕获错误:', error.message, '\n');
96
+ console.log("✅ 成功捕获错误:", error.message, "\n");
97
97
  }
98
98
 
99
- console.log('========== 所有测试完成 ==========\n');
99
+ console.log("========== 所有测试完成 ==========\n");
@@ -0,0 +1,54 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { getClientIp } from "../utils/getClientIp";
4
+
5
+ describe("utils - getClientIp", () => {
6
+ test("优先使用 x-forwarded-for 的第一个值", () => {
7
+ const req = new Request("http://localhost/api/test", {
8
+ method: "GET",
9
+ headers: {
10
+ "x-forwarded-for": " 8.8.8.8, 1.1.1.1 "
11
+ }
12
+ });
13
+
14
+ const ip = getClientIp(req);
15
+ expect(ip).toBe("8.8.8.8");
16
+ });
17
+
18
+ test("x-forwarded-for 为空时回退到 x-real-ip", () => {
19
+ const req = new Request("http://localhost/api/test", {
20
+ method: "GET",
21
+ headers: {
22
+ "x-forwarded-for": " ",
23
+ "x-real-ip": "9.9.9.9"
24
+ }
25
+ });
26
+
27
+ const ip = getClientIp(req);
28
+ expect(ip).toBe("9.9.9.9");
29
+ });
30
+
31
+ test("无代理头时使用 server.requestIP(req) 兜底", () => {
32
+ const req = new Request("http://localhost/api/test", {
33
+ method: "GET"
34
+ });
35
+
36
+ const server = {
37
+ requestIP(_req: Request) {
38
+ return { address: "7.7.7.7" };
39
+ }
40
+ };
41
+
42
+ const ip = getClientIp(req, server);
43
+ expect(ip).toBe("7.7.7.7");
44
+ });
45
+
46
+ test("全都没有时返回 unknown", () => {
47
+ const req = new Request("http://localhost/api/test", {
48
+ method: "GET"
49
+ });
50
+
51
+ const ip = getClientIp(req);
52
+ expect(ip).toBe("unknown");
53
+ });
54
+ });
@@ -1,15 +1,17 @@
1
- import { describe, test, expect } from 'bun:test';
2
- import { XMLParser } from 'fast-xml-parser';
3
- import { Cipher } from '../lib/cipher';
4
- import { Jwt } from '../lib/jwt';
5
- import { Validator } from '../lib/validator';
6
- import { SqlBuilder } from '../lib/sqlBuilder';
7
- import { keysToCamel } from 'befly-shared/keysToCamel';
8
- import { keysToSnake } from 'befly-shared/keysToSnake';
9
-
10
- describe('Integration - 密码验证流程', () => {
11
- test('用户注册:密码加密 + 验证', async () => {
12
- const password = 'MySecurePass123';
1
+ import { describe, test, expect } from "bun:test";
2
+
3
+ import { XMLParser } from "fast-xml-parser";
4
+
5
+ import { Cipher } from "../lib/cipher";
6
+ import { Jwt } from "../lib/jwt";
7
+ import { SqlBuilder } from "../lib/sqlBuilder";
8
+ import { Validator } from "../lib/validator";
9
+ import { keysToCamel } from "../utils/keysToCamel";
10
+ import { keysToSnake } from "../utils/keysToSnake";
11
+
12
+ describe("Integration - 密码验证流程", () => {
13
+ test("用户注册:密码加密 + 验证", async () => {
14
+ const password = "MySecurePass123";
13
15
 
14
16
  // 1. 密码加密
15
17
  const hashedPassword = await Cipher.hashPassword(password);
@@ -21,123 +23,123 @@ describe('Integration - 密码验证流程', () => {
21
23
  expect(isValid).toBe(true);
22
24
 
23
25
  // 3. 错误密码验证
24
- const isInvalid = await Cipher.verifyPassword('WrongPassword', hashedPassword);
26
+ const isInvalid = await Cipher.verifyPassword("WrongPassword", hashedPassword);
25
27
  expect(isInvalid).toBe(false);
26
28
  });
27
29
  });
28
30
 
29
- describe('Integration - JWT + 权限验证', () => {
31
+ describe("Integration - JWT + 权限验证", () => {
30
32
  const jwt = new Jwt({
31
- secret: 'test-integration-secret',
32
- algorithm: 'HS256',
33
- expiresIn: '1h'
33
+ secret: "test-integration-secret",
34
+ algorithm: "HS256",
35
+ expiresIn: "1h"
34
36
  });
35
37
 
36
- test('用户登录:JWT 签名 + 验证', () => {
38
+ test("用户登录:JWT 签名 + 验证", () => {
37
39
  // 1. 用户登录生成 token
38
40
  const payload = {
39
41
  userId: 123,
40
- username: 'john',
41
- roles: ['admin', 'user'],
42
- permissions: ['read', 'write', 'delete']
42
+ username: "john",
43
+ roles: ["admin", "user"],
44
+ permissions: ["read", "write", "delete"]
43
45
  };
44
46
 
45
47
  const token = jwt.sign(payload);
46
48
  expect(token).toBeDefined();
47
- expect(typeof token).toBe('string');
49
+ expect(typeof token).toBe("string");
48
50
 
49
51
  // 2. 验证 token
50
52
  const verified = jwt.verify(token);
51
53
  expect(verified.userId).toBe(123);
52
- expect(verified.username).toBe('john');
53
- expect(verified.roles).toContain('admin');
54
- expect(verified.permissions).toContain('write');
54
+ expect(verified.username).toBe("john");
55
+ expect(verified.roles).toContain("admin");
56
+ expect(verified.permissions).toContain("write");
55
57
  });
56
58
  });
57
59
 
58
- describe('Integration - 数据验证 + SQL 构建', () => {
59
- test('API 请求:验证数据 + 构建查询', () => {
60
+ describe("Integration - 数据验证 + SQL 构建", () => {
61
+ test("API 请求:验证数据 + 构建查询", () => {
60
62
  // 1. 验证用户输入
61
63
  const userData = {
62
- email: 'test@example.com',
64
+ email: "test@example.com",
63
65
  age: 25,
64
- username: 'john'
66
+ username: "john"
65
67
  };
66
68
 
67
69
  const rules = {
68
- email: { name: '邮箱', type: 'string', regexp: '@email' },
69
- age: { name: '年龄', type: 'number', min: 0, max: 150 },
70
- username: { name: '用户名', type: 'string', min: 2, max: 20 }
70
+ email: { name: "邮箱", type: "string", regexp: "@email" },
71
+ age: { name: "年龄", type: "number", min: 0, max: 150 },
72
+ username: { name: "用户名", type: "string", min: 2, max: 20 }
71
73
  };
72
74
 
73
- const validationResult = Validator.validate(userData, rules, ['email', 'username']);
75
+ const validationResult = Validator.validate(userData, rules, ["email", "username"]);
74
76
  expect(validationResult.code).toBe(0);
75
77
 
76
78
  // 2. 验证通过后构建 SQL 查询
77
79
  const builder = new SqlBuilder();
78
- const sqlResult = builder.select(['id', 'username', 'email']).from('users').where({ email: userData.email }).toSelectSql();
80
+ const sqlResult = builder.select(["id", "username", "email"]).from("users").where({ email: userData.email }).toSelectSql();
79
81
 
80
- expect(sqlResult.sql).toContain('SELECT');
81
- expect(sqlResult.sql).toContain('FROM `users`');
82
- expect(sqlResult.sql).toContain('WHERE `email` = ?');
83
- expect(sqlResult.params).toContain('test@example.com');
82
+ expect(sqlResult.sql).toContain("SELECT");
83
+ expect(sqlResult.sql).toContain("FROM `users`");
84
+ expect(sqlResult.sql).toContain("WHERE `email` = ?");
85
+ expect(sqlResult.params).toContain("test@example.com");
84
86
  });
85
87
 
86
- test('数据插入:验证 + 字段转换 + SQL 构建', () => {
88
+ test("数据插入:验证 + 字段转换 + SQL 构建", () => {
87
89
  // 1. 验证数据
88
90
  const newUser = {
89
- userName: 'jane',
90
- userEmail: 'jane@example.com',
91
+ userName: "jane",
92
+ userEmail: "jane@example.com",
91
93
  userAge: 30
92
94
  };
93
95
 
94
96
  const rules = {
95
- userName: { name: '用户名', type: 'string', min: 2, max: 20 },
96
- userEmail: { name: '邮箱', type: 'string', regexp: '@email' },
97
- userAge: { name: '年龄', type: 'number', min: 0, max: 150 }
97
+ userName: { name: "用户名", type: "string", min: 2, max: 20 },
98
+ userEmail: { name: "邮箱", type: "string", regexp: "@email" },
99
+ userAge: { name: "年龄", type: "number", min: 0, max: 150 }
98
100
  };
99
101
 
100
- const validationResult = Validator.validate(newUser, rules, ['userName', 'userEmail']);
102
+ const validationResult = Validator.validate(newUser, rules, ["userName", "userEmail"]);
101
103
  expect(validationResult.code).toBe(0);
102
104
 
103
105
  // 2. 字段转换(驼峰转下划线)
104
106
  const dbData = keysToSnake(newUser);
105
- expect(dbData.user_name).toBe('jane');
106
- expect(dbData.user_email).toBe('jane@example.com');
107
+ expect(dbData.user_name).toBe("jane");
108
+ expect(dbData.user_email).toBe("jane@example.com");
107
109
  expect(dbData.user_age).toBe(30);
108
110
 
109
111
  // 3. 构建插入 SQL
110
112
  const builder = new SqlBuilder();
111
- const sqlResult = builder.toInsertSql('users', dbData);
113
+ const sqlResult = builder.toInsertSql("users", dbData);
112
114
 
113
- expect(sqlResult.sql).toContain('INSERT INTO `users`');
114
- expect(sqlResult.params).toContain('jane');
115
- expect(sqlResult.params).toContain('jane@example.com');
115
+ expect(sqlResult.sql).toContain("INSERT INTO `users`");
116
+ expect(sqlResult.params).toContain("jane");
117
+ expect(sqlResult.params).toContain("jane@example.com");
116
118
  });
117
119
  });
118
120
 
119
- describe('Integration - XML 解析 + 数据转换', () => {
120
- test('XML API 响应:解析 + 字段转换', () => {
121
+ describe("Integration - XML 解析 + 数据转换", () => {
122
+ test("XML API 响应:解析 + 字段转换", () => {
121
123
  const xmlParser = new XMLParser();
122
124
 
123
125
  // 1. 解析 XML 响应
124
- const xmlData = '<response><user_id>123</user_id><user_name>John</user_name><is_active>true</is_active></response>';
126
+ const xmlData = "<response><user_id>123</user_id><user_name>John</user_name><is_active>true</is_active></response>";
125
127
  const parsed = xmlParser.parse(xmlData).response as any;
126
128
 
127
129
  expect(parsed.user_id).toBe(123);
128
- expect(parsed.user_name).toBe('John');
130
+ expect(parsed.user_name).toBe("John");
129
131
  expect(parsed.is_active).toBe(true);
130
132
 
131
133
  // 2. 字段转换(下划线转驼峰)
132
134
  const camelData = keysToCamel(parsed);
133
135
  expect(camelData.userId).toBe(123);
134
- expect(camelData.userName).toBe('John');
136
+ expect(camelData.userName).toBe("John");
135
137
  expect(camelData.isActive).toBe(true);
136
138
  });
137
139
  });
138
140
 
139
- describe('Integration - 加密 + JWT + 哈希', () => {
140
- test('安全令牌生成:多层加密', () => {
141
+ describe("Integration - 加密 + JWT + 哈希", () => {
142
+ test("安全令牌生成:多层加密", () => {
141
143
  // 1. 生成随机字符串作为 secret
142
144
  const secret = Cipher.randomString(32);
143
145
  expect(secret.length).toBe(32);
@@ -147,7 +149,7 @@ describe('Integration - 加密 + JWT + 哈希', () => {
147
149
  expect(hashedSecret.length).toBe(64);
148
150
 
149
151
  // 3. 使用 HMAC 签名
150
- const data = 'user123:session456';
152
+ const data = "user123:session456";
151
153
  const signature = Cipher.hmacSha256(data, hashedSecret);
152
154
  expect(signature).toBeDefined();
153
155
 
@@ -161,14 +163,14 @@ describe('Integration - 加密 + JWT + 哈希', () => {
161
163
  });
162
164
  });
163
165
 
164
- describe('Integration - SQL 构建 + 字段转换', () => {
165
- test('复杂查询:驼峰转下划线 + WHERE 条件 + 排序分页', () => {
166
+ describe("Integration - SQL 构建 + 字段转换", () => {
167
+ test("复杂查询:驼峰转下划线 + WHERE 条件 + 排序分页", () => {
166
168
  const builder = new SqlBuilder();
167
169
 
168
170
  // 1. 原始查询条件(驼峰格式)
169
171
  const queryConditions = {
170
172
  userId: 123,
171
- userStatus: 'active',
173
+ userStatus: "active",
172
174
  createdAt: { $gte: 1609459200000 }
173
175
  };
174
176
 
@@ -176,12 +178,12 @@ describe('Integration - SQL 构建 + 字段转换', () => {
176
178
  const dbConditions = keysToSnake(queryConditions);
177
179
 
178
180
  // 3. 构建复杂查询
179
- const sqlResult = builder.select(['id', 'user_name', 'user_email', 'created_at']).from('users').where(dbConditions).orderBy(['created_at#DESC']).limit(20).offset(0).toSelectSql();
181
+ const sqlResult = builder.select(["id", "user_name", "user_email", "created_at"]).from("users").where(dbConditions).orderBy(["created_at#DESC"]).limit(20).offset(0).toSelectSql();
180
182
 
181
- expect(sqlResult.sql).toContain('SELECT');
182
- expect(sqlResult.sql).toContain('WHERE');
183
- expect(sqlResult.sql).toContain('ORDER BY');
184
- expect(sqlResult.sql).toContain('LIMIT 20');
183
+ expect(sqlResult.sql).toContain("SELECT");
184
+ expect(sqlResult.sql).toContain("WHERE");
185
+ expect(sqlResult.sql).toContain("ORDER BY");
186
+ expect(sqlResult.sql).toContain("LIMIT 20");
185
187
  expect(sqlResult.params.length).toBeGreaterThan(0);
186
188
  });
187
189
  });
package/tests/jwt.test.ts CHANGED
@@ -1,60 +1,61 @@
1
- import { describe, test, expect } from 'bun:test';
2
- import { Jwt } from '../lib/jwt';
1
+ import { describe, test, expect } from "bun:test";
2
+
3
+ import { Jwt } from "../lib/jwt";
3
4
 
4
5
  const jwt = new Jwt({
5
- secret: 'test-secret',
6
- algorithm: 'HS256',
7
- expiresIn: '7d'
6
+ secret: "test-secret",
7
+ algorithm: "HS256",
8
+ expiresIn: "7d"
8
9
  });
9
10
 
10
- describe('JWT - sign', () => {
11
- test('签名创建 token', () => {
12
- const token = jwt.sign({ userId: 1, name: 'test' });
13
- expect(typeof token).toBe('string');
14
- expect(token.split('.').length).toBe(3);
11
+ describe("JWT - sign", () => {
12
+ test("签名创建 token", () => {
13
+ const token = jwt.sign({ userId: 1, name: "test" });
14
+ expect(typeof token).toBe("string");
15
+ expect(token.split(".").length).toBe(3);
15
16
  });
16
17
 
17
- test('自定义密钥', () => {
18
- const secret = 'custom-secret';
18
+ test("自定义密钥", () => {
19
+ const secret = "custom-secret";
19
20
  const token = jwt.sign({ userId: 1 }, { secret: secret });
20
21
  const decoded = jwt.verify(token, { secret: secret });
21
22
  expect(decoded.userId).toBe(1);
22
23
  });
23
24
  });
24
25
 
25
- describe('JWT - verify', () => {
26
- test('验证有效 token', () => {
27
- const token = jwt.sign({ userId: 123, email: 'test@test.com' });
26
+ describe("JWT - verify", () => {
27
+ test("验证有效 token", () => {
28
+ const token = jwt.sign({ userId: 123, email: "test@test.com" });
28
29
  const decoded = jwt.verify(token);
29
30
  expect(decoded.userId).toBe(123);
30
- expect(decoded.email).toBe('test@test.com');
31
+ expect(decoded.email).toBe("test@test.com");
31
32
  });
32
33
 
33
- test('验证过期 token 抛出错误', () => {
34
- const token = jwt.sign({ userId: 1 }, { expiresIn: '-1s' });
34
+ test("验证过期 token 抛出错误", () => {
35
+ const token = jwt.sign({ userId: 1 }, { expiresIn: "-1s" });
35
36
  expect(() => jwt.verify(token)).toThrow();
36
37
  });
37
38
 
38
- test('忽略过期验证', () => {
39
- const token = jwt.sign({ userId: 1 }, { expiresIn: '-1s' });
39
+ test("忽略过期验证", () => {
40
+ const token = jwt.sign({ userId: 1 }, { expiresIn: "-1s" });
40
41
  const decoded = jwt.verify(token, { ignoreExpiration: true });
41
42
  expect(decoded.userId).toBe(1);
42
43
  });
43
44
 
44
- test('密钥不匹配验证失败', () => {
45
- const token = jwt.sign({ userId: 1 }, { secret: 'secret1' });
46
- expect(() => jwt.verify(token, { secret: 'secret2' })).toThrow();
45
+ test("密钥不匹配验证失败", () => {
46
+ const token = jwt.sign({ userId: 1 }, { secret: "secret1" });
47
+ expect(() => jwt.verify(token, { secret: "secret2" })).toThrow();
47
48
  });
48
49
  });
49
50
 
50
- describe('JWT - decode', () => {
51
- test('解码不验证签名', () => {
51
+ describe("JWT - decode", () => {
52
+ test("解码不验证签名", () => {
52
53
  const token = jwt.sign({ userId: 456 });
53
54
  const decoded = jwt.decode(token);
54
55
  expect(decoded.userId).toBe(456);
55
56
  });
56
57
 
57
- test('解码完整信息', () => {
58
+ test("解码完整信息", () => {
58
59
  const token = jwt.sign({ userId: 1 });
59
60
  const decoded = jwt.decode(token, true);
60
61
  expect(decoded.header).toBeDefined();