chanjs 2.7.2 → 2.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/App.js +232 -16
  2. package/base/Aop.js +20 -3
  3. package/base/Container.js +80 -3
  4. package/base/Controller.js +38 -9
  5. package/base/Database.js +50 -0
  6. package/base/Event.js +12 -0
  7. package/base/{Service.js → Repository.js} +644 -539
  8. package/common/api.js +18 -8
  9. package/common/code.js +25 -15
  10. package/common/email.js +98 -17
  11. package/common/index.js +1 -1
  12. package/config/code.js +138 -82
  13. package/global/index.js +1 -1
  14. package/helper/index.js +43 -41
  15. package/index.js +19 -6
  16. package/loader/index.js +6 -0
  17. package/{helper → loader}/loader.js +41 -27
  18. package/middleware/compress.js +185 -0
  19. package/middleware/cors.js +36 -24
  20. package/middleware/header.js +5 -10
  21. package/middleware/index.js +1 -0
  22. package/middleware/log.js +27 -3
  23. package/middleware/setBody.js +9 -1
  24. package/middleware/static.js +2 -1
  25. package/middleware/template.js +139 -4
  26. package/middleware/waf.js +136 -76
  27. package/package.json +4 -4
  28. package/realtime/index.js +7 -0
  29. package/realtime/sse.js +424 -0
  30. package/realtime/websocket.js +540 -0
  31. package/response/index.js +12 -0
  32. package/response/response.js +258 -0
  33. package/schedule/index.js +6 -0
  34. package/schedule/schedule.js +491 -0
  35. package/{helper → security}/checker.js +23 -8
  36. package/security/index.js +14 -0
  37. package/{helper → security}/jwt.js +175 -107
  38. package/security/keywords.js +179 -0
  39. package/security/rate-limit.js +105 -0
  40. package/security/sign.js +210 -0
  41. package/security/xss-filter.js +63 -0
  42. package/storage/cache.js +258 -0
  43. package/storage/index.js +9 -0
  44. package/storage/redis.js +258 -0
  45. package/storage/store.js +266 -0
  46. package/{helper → utils}/file.js +106 -15
  47. package/{helper → utils}/filter.js +2 -1
  48. package/{helper → utils}/html.js +19 -1
  49. package/utils/index.js +34 -0
  50. package/{helper → utils}/ip.js +25 -16
  51. package/utils/request.js +172 -0
  52. package/{helper → utils}/time.js +1 -1
  53. package/utils/tree.js +121 -0
  54. package/common/category.js +0 -22
  55. package/common/sms.js +0 -104
  56. package/extend/art-template.js +0 -129
  57. package/extend/index.js +0 -6
  58. package/global/global.js +0 -63
  59. package/helper/cache.js +0 -187
  60. package/helper/keywords.js +0 -132
  61. package/helper/rate-limit.js +0 -116
  62. package/helper/request.js +0 -47
  63. package/helper/response.js +0 -180
  64. package/helper/sign.js +0 -96
  65. package/helper/tree.js +0 -77
  66. package/helper/xss-filter.js +0 -42
  67. /package/{helper → utils}/data-parse.js +0 -0
package/common/api.js CHANGED
@@ -1,21 +1,31 @@
1
1
  /**
2
- * API响应常量定义
3
- * 提供统一的响应状态码和消息
2
+ * API 响应常量定义(旧版对象形式,保留向后兼容)
3
+ *
4
+ * ============================================================
5
+ * 重要说明
6
+ * ============================================================
7
+ * 业务侧推荐使用 helper/response.js 的函数式响应(success/fail/error),
8
+ * 通过 Controller 的 this.success() / this.fail() 调用。
9
+ *
10
+ * 本文件的 success/fail/error 为旧版对象常量,仅用于兼容历史代码。
11
+ * code 值已对齐新体系(0/1008/5001),不再使用 200/201/500。
12
+ *
13
+ * @deprecated 推荐使用 helper/response.js 的函数式响应
4
14
  */
5
15
 
6
16
  export const success = {
7
- code: 200,
8
- msg: "success",
17
+ code: 0,
18
+ msg: "操作成功",
9
19
  };
10
20
 
11
21
  export const fail = {
12
- code: 201,
13
- msg: "error",
22
+ code: 1008,
23
+ msg: "操作失败",
14
24
  };
15
25
 
16
26
  export const error = {
17
- code: 500,
18
- msg: "error",
27
+ code: 5001,
28
+ msg: "系统错误",
19
29
  };
20
30
 
21
31
  export default {
package/common/code.js CHANGED
@@ -1,42 +1,52 @@
1
1
  /**
2
- * 响应状态码常量定义
3
- * 提供标准的状态码和对应消息
2
+ * 响应状态码常量定义(旧版对象形式,保留向后兼容)
3
+ *
4
+ * ============================================================
5
+ * 重要说明
6
+ * ============================================================
7
+ * 业务侧推荐使用 config/code.js 的三层 code 体系(0/1xxx/5xxx/6xxx),
8
+ * 该文件提供完整的 CODE 字典、CODE_RANGE 段位常量、语义化别名、DB_ERROR 映射。
9
+ *
10
+ * 本文件的 CODE 对象为旧版形式,仅用于兼容历史代码。
11
+ * code 值已对齐新体系,不再使用 200/201/500。
12
+ *
13
+ * @deprecated 推荐使用 config/code.js 的新体系
4
14
  */
5
15
 
6
16
  export const CODE = {
7
17
  /**
8
- * 操作成功
18
+ * 操作成功(code: 0,不再用 200)
9
19
  */
10
20
  SUCCESS: {
11
- code: 200,
21
+ code: 0,
12
22
  message: "操作成功",
13
23
  },
14
24
  /**
15
- * 操作失败
25
+ * 操作失败(code: 1008 业务处理失败)
16
26
  */
17
27
  FAIL: {
18
- code: 201,
28
+ code: 1008,
19
29
  message: "操作失败",
20
30
  },
21
31
  /**
22
- * 服务器错误
32
+ * 系统错误(code: 5001 系统内部错误)
23
33
  */
24
34
  ERROR: {
25
- code: 500,
26
- message: "服务器错误",
35
+ code: 5001,
36
+ message: "系统错误",
27
37
  },
28
38
  /**
29
- * 未授权
39
+ * 未授权(code: 1001 认证失败)
30
40
  */
31
41
  UNAUTHORIZED: {
32
- code: 401,
33
- message: "未授权",
42
+ code: 1001,
43
+ message: "认证失败",
34
44
  },
35
45
  /**
36
- * 禁止访问
46
+ * 禁止访问(code: 1003 权限不足)
37
47
  */
38
48
  FORBIDDEN: {
39
- code: 403,
40
- message: "禁止访问",
49
+ code: 1003,
50
+ message: "权限不足",
41
51
  },
42
52
  };
package/common/email.js CHANGED
@@ -1,10 +1,81 @@
1
1
  import nodemailer from "nodemailer";
2
+ import Chan from "../App.js";
2
3
 
3
4
  /**
4
5
  * 邮件发送工具
5
6
  * 提供邮件发送和HTML模板生成功能
7
+ * 通过 import Chan 获取应用配置(不依赖 global.Chan)
6
8
  */
7
9
 
10
+ /**
11
+ * 邮箱地址正则(基础校验,防注入和拼写错误)
12
+ */
13
+ const EMAIL_REGEX = /^[^\s@<>'"`]+@[^\s@<>'"`]+\.[^\s@<>'"`]+$/;
14
+
15
+ /**
16
+ * 模块级 transporter 缓存(避免每次发邮件都创建连接池)
17
+ * 配置不变时复用同一个 transporter,提升性能
18
+ */
19
+ let _transporter = null;
20
+ let _transporterKey = '';
21
+
22
+ /**
23
+ * HTML 特殊字符转义,防止邮件模板注入
24
+ * @param {string} str - 待转义的字符串
25
+ * @returns {string} 转义后的字符串
26
+ */
27
+ function escapeHtml(str) {
28
+ if (str == null) return '';
29
+ return String(str)
30
+ .replace(/&/g, '&amp;')
31
+ .replace(/</g, '&lt;')
32
+ .replace(/>/g, '&gt;')
33
+ .replace(/"/g, '&quot;')
34
+ .replace(/'/g, '&#39;');
35
+ }
36
+
37
+ /**
38
+ * 校验收件人邮箱格式(基础规则,拒绝含特殊字符的非法地址)
39
+ * @param {string} email - 邮箱地址
40
+ * @returns {boolean} 是否合法
41
+ */
42
+ function isValidEmail(email) {
43
+ return typeof email === 'string' && EMAIL_REGEX.test(email) && email.length <= 254;
44
+ }
45
+
46
+ /**
47
+ * 获取或创建 transporter(带缓存)
48
+ * @param {Object} EMAIL - 邮件配置
49
+ * @returns {Object} nodemailer transporter
50
+ */
51
+ function getTransporter(EMAIL) {
52
+ // 用 host+port+user 作为缓存 key,配置变化时自动重建
53
+ const key = `${EMAIL.HOST}:${EMAIL.PORT}:${EMAIL.USER}`;
54
+ if (_transporter && _transporterKey === key) {
55
+ return _transporter;
56
+ }
57
+
58
+ _transporter = nodemailer.createTransport({
59
+ host: EMAIL.HOST,
60
+ port: parseInt(EMAIL.PORT),
61
+ secure: EMAIL.SECURE === "true",
62
+ auth: {
63
+ user: EMAIL.USER,
64
+ pass: EMAIL.PASS,
65
+ },
66
+ // 连接池配置:避免每次发邮件都握手,降低 SMTP 服务器压力
67
+ pool: true,
68
+ maxConnections: 5,
69
+ maxMessages: 100,
70
+ // 超时控制,避免 SMTP 卡死拖垮业务
71
+ connectionTimeout: 10 * 1000,
72
+ greetingTimeout: 10 * 1000,
73
+ socketTimeout: 30 * 1000,
74
+ });
75
+ _transporterKey = key;
76
+ return _transporter;
77
+ }
78
+
8
79
  /**
9
80
  * 发送邮件
10
81
  * @param {string} to - 收件人邮箱
@@ -13,19 +84,19 @@ import nodemailer from "nodemailer";
13
84
  * @param {string|null} html - 邮件HTML内容,默认为null
14
85
  * @returns {Promise<Object>} 发送结果
15
86
  * @throws {Error} 邮件服务未配置或发送失败时抛出异常
87
+ * @description
88
+ * - 收件人邮箱格式校验,拒绝非法地址
89
+ * - transporter 模块级缓存,避免每次创建连接池
16
90
  */
17
91
  export const sendMail = async (to, subject, text, html = null) => {
92
+ // 收件人邮箱格式校验
93
+ if (!isValidEmail(to)) {
94
+ throw new Error(`[email] 收件人邮箱格式非法: ${to}`);
95
+ }
96
+
18
97
  const { EMAIL, APP_NAME } = Chan.config;
19
98
 
20
- const transporter = nodemailer.createTransport({
21
- host: EMAIL.HOST,
22
- port: parseInt(EMAIL.PORT),
23
- secure: EMAIL.SECURE === "true",
24
- auth: {
25
- user: EMAIL.USER,
26
- pass: EMAIL.PASS,
27
- },
28
- });
99
+ const transporter = getTransporter(EMAIL);
29
100
 
30
101
  let res = await transporter.verify();
31
102
  if (!res) {
@@ -54,26 +125,31 @@ export const sendMail = async (to, subject, text, html = null) => {
54
125
  * @param {string} code - 验证码
55
126
  * @param {number} minutes - 有效期(分钟),默认10分钟
56
127
  * @returns {string} HTML字符串
128
+ * @description
129
+ * 安全改进:所有动态内容(code、APP_NAME)都经 escapeHtml 转义,防止 HTML 注入
57
130
  */
58
131
  export const genRegEmailHtml = (code, minutes = 10) => {
59
132
  const { APP_NAME } = Chan.config;
133
+ // 转义防止 HTML 注入
134
+ const safeCode = escapeHtml(code);
135
+ const safeAppName = escapeHtml(APP_NAME);
60
136
  return `
61
137
  <div style="font-family: Arial, sans-serif; max-width: 750px; margin: auto; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;">
62
138
  <div style="background-color: #007bff; color: white; padding: 10px; text-align: center;">
63
- <h2>${APP_NAME} 欢迎注册!</h2>
139
+ <h2>${safeAppName} 欢迎注册!</h2>
64
140
  </div>
65
141
  <div style="padding: 20px; line-height: 1.6;">
66
142
  <p>您好,感谢您注册我们的服务!</p>
67
143
  <p>您的注册验证码是:</p>
68
144
  <div style="font-size: 24px; font-weight: bold; color: #007bff; text-align: center; margin: 20px 0;">
69
- ${code}
145
+ ${safeCode}
70
146
  </div>
71
- <p>请在 <strong>${minutes} 分钟内</strong> 输入该验证码,完成账户验证。</p>
147
+ <p>请在 <strong>${escapeHtml(minutes)} 分钟内</strong> 输入该验证码,完成账户验证。</p>
72
148
  <p>如非本人操作,请忽略此邮件。</p>
73
149
  <p>祝您使用愉快!</p>
74
150
  </div>
75
151
  <div style="background-color: #f8f9fa; padding: 10px; text-align: center; font-size: 12px; color: #666;">
76
- &copy; ${new Date().getFullYear()} ${APP_NAME}. 保留所有权利。
152
+ &copy; ${new Date().getFullYear()} ${safeAppName}. 保留所有权利。
77
153
  </div>
78
154
  </div>
79
155
  `;
@@ -84,26 +160,31 @@ export const genRegEmailHtml = (code, minutes = 10) => {
84
160
  * @param {string} code - 验证码
85
161
  * @param {number} minutes - 有效期(分钟),默认10分钟
86
162
  * @returns {string} HTML字符串
163
+ * @description
164
+ * 安全改进:所有动态内容(code、APP_NAME)都经 escapeHtml 转义,防止 HTML 注入
87
165
  */
88
166
  export const genResetPasswordEmail = (code, minutes = 10) => {
89
167
  const { APP_NAME } = Chan.config;
168
+ // 转义防止 HTML 注入
169
+ const safeCode = escapeHtml(code);
170
+ const safeAppName = escapeHtml(APP_NAME);
90
171
  return `
91
172
  <div style="font-family: Arial, sans-serif; max-width: 600px; margin: auto; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;">
92
173
  <div style="background-color: #28a745; color: white; padding: 20px; text-align: center;">
93
- <h2>重置密码_${APP_NAME}</h2>
174
+ <h2>重置密码_${safeAppName}</h2>
94
175
  </div>
95
176
  <div style="padding: 20px; line-height: 1.6;">
96
177
  <p>您好,我们收到了您重置密码的请求。</p>
97
178
  <p>您的重置密码验证码是:</p>
98
179
  <div style="font-size: 24px; font-weight: bold; color: #007bff; text-align: center; margin: 20px 0;">
99
- ${code}
180
+ ${safeCode}
100
181
  </div>
101
- <p>请在 <strong>${minutes} 分钟内</strong> 输入该验证码,完成账户验证。</p>
182
+ <p>请在 <strong>${escapeHtml(minutes)} 分钟内</strong> 输入该验证码,完成账户验证。</p>
102
183
  <p>如非本人操作,请忽略此邮件。</p>
103
184
  <p>祝您使用愉快!</p>
104
185
  </div>
105
186
  <div style="background-color: #f8f9fa; padding: 10px; text-align: center; font-size: 12px; color: #666;">
106
- &copy; ${new Date().getFullYear()} ${APP_NAME}. 保留所有权利。
187
+ &copy; ${new Date().getFullYear()} ${safeAppName}. 保留所有权利。
107
188
  </div>
108
189
  </div>
109
190
  `;
package/common/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { success, fail, error } from "./api.js";
2
- export { getChildrenId } from "./category.js";
2
+ export { getChildrenId } from "./utils.js";
3
3
  export { CODE } from "./code.js";
4
4
  export { sendMail, genRegEmailHtml, genResetPasswordEmail } from "./email.js";
5
5
  export { pages, getHtmlFilesSync } from "./pages.js";
package/config/code.js CHANGED
@@ -1,102 +1,127 @@
1
1
  /**
2
- * 业务状态码和数据库错误码映射
3
- * 定义系统中使用的各种状态码和错误码
2
+ * 业务状态码定义(统一三层 code 体系)
3
+ *
4
+ * ============================================================
5
+ * 设计原则
6
+ * ============================================================
7
+ * 1. 业务 code 与 HTTP Status 彻底解耦
8
+ * - HTTP Status 由网关/Express 控制(200/400/401/403/404/500)
9
+ * - 业务 code 由业务层控制(0 / 1xxx / 5xxx / 6xxx)
10
+ * - 前端 axios 先看 HTTP Status,再看业务 code
11
+ *
12
+ * 2. 0 表示成功(不再用 200,避免与 HTTP 200 混淆)
13
+ *
14
+ * 3. 错误按业务域分段
15
+ * - 1xxx 通用业务错误(认证/权限/参数/资源)
16
+ * - 2xxx CMS 业务专用错误(保留扩展段)
17
+ * - 5xxx 系统错误
18
+ * - 6xxx 数据库错误
19
+ *
20
+ * 4. 每个 code 都有默认 msg,业务可覆盖
21
+ *
22
+ * ============================================================
23
+ * Code 段位定义
24
+ * ============================================================
25
+ * 0 → 成功
26
+ * 1001 → 认证失败(token 无效/未登录)
27
+ * 1002 → token 已过期
28
+ * 1003 → 权限不足
29
+ * 1004 → 资源不存在
30
+ * 1005 → 资源已存在
31
+ * 1006 → 参数无效
32
+ * 1007 → 参数缺失
33
+ * 1008 → 业务处理失败(通用兜底)
34
+ * 1009 → 请求过于频繁(限流)
35
+ * 1010 → 登录设备异常
36
+ * 2xxx → CMS 业务专用错误(保留扩展段)
37
+ * 5001 → 系统内部错误
38
+ * 5002 → 服务繁忙,请稍后再试
39
+ * 6001 → 数据库连接失败
40
+ * 6002 → 数据库访问被拒绝
41
+ * 6003 → 存在关联数据,操作失败
42
+ * 6004 → 数据库字段错误
43
+ * 6005 → 数据重复,违反唯一性约束
44
+ * 6006 → 目标表不存在
45
+ * 6007 → 数据库操作超时
46
+ * 6008 → 数据库语法错误
47
+ * 6009 → 数据库连接已关闭
4
48
  */
5
49
 
50
+ /**
51
+ * 业务状态码 → 默认消息
52
+ * @type {Object<number, string>}
53
+ */
6
54
  export const CODE = {
7
- /**
8
- * 操作成功
9
- */
10
- 200: "操作成功",
11
- /**
12
- * 操作失败
13
- */
14
- 201: "操作失败",
15
- /**
16
- * 业务处理失败
17
- */
18
- 1001: "业务处理失败",
19
- /**
20
- * 参数无效
21
- */
22
- 2001: "参数无效",
23
- /**
24
- * 参数缺失
25
- */
26
- 2002: "参数缺失",
27
- /**
28
- * 认证失败
29
- */
30
- 3001: "认证失败",
31
- /**
32
- * 令牌已过期
33
- */
34
- 3002: "令牌已过期",
35
- /**
36
- * 权限不足
37
- */
38
- 3003: "权限不足",
39
- /**
40
- * 资源不存在
41
- */
42
- 4001: "资源不存在",
43
- /**
44
- * 资源已锁定
45
- */
46
- 4002: "资源已锁定",
47
- /**
48
- * 资源已存在
49
- */
50
- 4003: "资源已存在",
51
- /**
52
- * 系统内部错误
53
- */
55
+ // 成功
56
+ 0: "操作成功",
57
+
58
+ // 1xxx 通用业务错误
59
+ 1001: "认证失败",
60
+ 1002: "令牌已过期",
61
+ 1003: "权限不足",
62
+ 1004: "资源不存在",
63
+ 1005: "资源已存在",
64
+ 1006: "参数无效",
65
+ 1007: "参数缺失",
66
+ 1008: "业务处理失败",
67
+ 1009: "请求过于频繁",
68
+ 1010: "登录设备异常",
69
+
70
+ // 2xxx CMS 业务专用错误(保留扩展段,业务方可自定义)
71
+ // 例如:2001 文章不存在 / 2002 栏目不存在 等
72
+
73
+ // 5xxx 系统错误
54
74
  5001: "系统内部错误",
55
- /**
56
- * 服务繁忙,请稍后再试
57
- */
58
75
  5002: "服务繁忙,请稍后再试",
59
- /**
60
- * 数据库连接失败
61
- */
76
+
77
+ // 6xxx 数据库错误
62
78
  6001: "数据库连接失败",
63
- /**
64
- * 数据库访问被拒绝
65
- */
66
79
  6002: "数据库访问被拒绝",
67
- /**
68
- * 存在关联数据,操作失败
69
- */
70
80
  6003: "存在关联数据,操作失败",
71
- /**
72
- * 数据库字段错误
73
- */
74
81
  6004: "数据库字段错误",
75
- /**
76
- * 数据重复,违反唯一性约束
77
- */
78
82
  6005: "数据重复,违反唯一性约束",
79
- /**
80
- * 目标表不存在
81
- */
82
83
  6006: "目标表不存在",
83
- /**
84
- * 数据库操作超时
85
- */
86
84
  6007: "数据库操作超时",
87
- /**
88
- * 数据库语法错误,请检查查询语句
89
- */
90
85
  6008: "数据库语法错误,请检查查询语句",
91
- /**
92
- * 数据库连接已关闭,请重试
93
- */
94
86
  6009: "数据库连接已关闭,请重试",
95
87
  };
96
88
 
97
89
  /**
98
- * 数据库错误码映射
99
- * 将数据库原生错误码映射为业务状态码
90
+ * 业务 code 段位常量
91
+ * 便于业务方判断 code 归属段位
92
+ * @example
93
+ * if (code >= CODE_RANGE.SYSTEM[0] && code <= CODE_RANGE.SYSTEM[1]) { ... }
94
+ */
95
+ export const CODE_RANGE = {
96
+ SUCCESS: [0, 0], // 成功
97
+ BUSINESS: [1000, 1999], // 通用业务错误
98
+ CMS: [2000, 2999], // CMS 业务错误(保留扩展段)
99
+ SYSTEM: [5000, 5999], // 系统错误
100
+ DATABASE: [6000, 6999], // 数据库错误
101
+ };
102
+
103
+ /**
104
+ * 常用 code 语义化别名
105
+ * 业务方可直接用 CODE_OK / CODE_AUTH_FAILED 等语义化常量,避免硬编码数字
106
+ */
107
+ export const CODE_OK = 0; // 成功
108
+ export const CODE_AUTH_FAILED = 1001; // 认证失败
109
+ export const CODE_TOKEN_EXPIRED = 1002; // token 过期
110
+ export const CODE_FORBIDDEN = 1003; // 权限不足
111
+ export const CODE_NOT_FOUND = 1004; // 资源不存在
112
+ export const CODE_CONFLICT = 1005; // 资源已存在
113
+ export const CODE_PARAM_INVALID = 1006; // 参数无效
114
+ export const CODE_PARAM_MISSING = 1007; // 参数缺失
115
+ export const CODE_BUSINESS_FAIL = 1008; // 业务处理失败(通用)
116
+ export const CODE_RATE_LIMIT = 1009; // 限流
117
+ export const CODE_DEVICE_ERROR = 1010; // 登录设备异常
118
+ export const CODE_SYSTEM_ERROR = 5001; // 系统内部错误
119
+ export const CODE_SERVICE_BUSY = 5002; // 服务繁忙
120
+
121
+ /**
122
+ * 数据库原生错误码 → 业务 code 映射
123
+ * 将 MySQL/Knex 等数据库原生错误码转换为业务 code
124
+ * @type {Object<string, number>}
100
125
  */
101
126
  export const DB_ERROR = {
102
127
  ECONNREFUSED: 6001,
@@ -106,5 +131,36 @@ export const DB_ERROR = {
106
131
  ER_DUP_ENTRY: 6005,
107
132
  ER_NO_SUCH_TABLE: 6006,
108
133
  ETIMEOUT: 6007,
109
- ER_TABLE_EXISTS_ERROR: 4003,
134
+ ER_TABLE_EXISTS_ERROR: 1005, // 表已存在 → 资源已存在
110
135
  };
136
+
137
+ /**
138
+ * 判断 code 是否为成功
139
+ * @param {number} code - 业务 code
140
+ * @returns {boolean}
141
+ */
142
+ export function isSuccessCode(code) {
143
+ return code === CODE_OK;
144
+ }
145
+
146
+ /**
147
+ * 判断 code 所属段位
148
+ * @param {number} code - 业务 code
149
+ * @returns {string} 段位名:SUCCESS / BUSINESS / CMS / SYSTEM / DATABASE / UNKNOWN
150
+ */
151
+ export function getCodeRange(code) {
152
+ for (const [name, [min, max]] of Object.entries(CODE_RANGE)) {
153
+ if (code >= min && code <= max) return name;
154
+ }
155
+ return 'UNKNOWN';
156
+ }
157
+
158
+ /**
159
+ * 获取 code 的默认消息
160
+ * @param {number} code - 业务 code
161
+ * @param {string} [fallback='操作失败'] - 兜底消息
162
+ * @returns {string}
163
+ */
164
+ export function getCodeMsg(code, fallback = '操作失败') {
165
+ return CODE[code] || fallback;
166
+ }
package/global/index.js CHANGED
@@ -3,6 +3,6 @@
3
3
  * 导入所有全局配置和功能
4
4
  */
5
5
 
6
- import "./global.js";
6
+
7
7
  import "./import.js";
8
8
  import "./env.js";
package/helper/index.js CHANGED
@@ -1,11 +1,25 @@
1
- // 加载器相关
2
- export { loaderSort, loadConfig, clearConfigCache, loadController } from "./loader.js";
1
+ /**
2
+ * 聚合导出层 - 从各子模块统一 re-export
3
+ *
4
+ * 框架内部已按职责拆分到 storage/security/realtime/schedule/loader/response/utils
5
+ * 本文件提供扁平化聚合访问,业务侧可用:
6
+ * import { helper } from "chanjs";
7
+ * const { getIp, formatDateFields, filterXSS } = helper;
8
+ *
9
+ * 也可直接从子模块导入(更精确):
10
+ * import { utils, security, storage } from "chanjs";
11
+ */
12
+
13
+ // 加载器
14
+ export { loaderSort, loadConfig, clearConfigCache, loadController } from "../loader/index.js";
3
15
 
4
16
  // 时间处理
5
- export { formatTime, formatDateFields } from "./time.js";
17
+ export { formatTime, formatDateFields } from "../utils/time.js";
6
18
 
7
- // 缓存相关
8
- export { cache } from "./cache.js";
19
+ // 存储相关
20
+ export { cache, DEFAULT_INCR_TTL } from "../storage/index.js";
21
+ export { store } from "../storage/index.js";
22
+ export { default as RedisBackend } from "../storage/redis.js";
9
23
 
10
24
  // 文件操作
11
25
  export {
@@ -15,47 +29,32 @@ export {
15
29
  readFileContent,
16
30
  saveFileContent,
17
31
  isPathSafe,
18
- getFolders
19
- } from "./file.js";
32
+ getFolders,
33
+ } from "../utils/file.js";
20
34
 
21
- // HTML处理
22
- export { htmlDecode, htmlEncode,escapeScript } from "./html.js";
35
+ // HTML 处理
36
+ export { htmlDecode, htmlEncode, escapeScript } from "../utils/html.js";
23
37
 
24
- // IP相关
25
- export { getIp } from "./ip.js";
38
+ // IP 获取
39
+ export { getIp } from "../utils/ip.js";
26
40
 
27
- // JWT令牌
28
- export {
29
- verifyToken,
30
- generateToken,
31
- setToken,
32
- getToken
33
- } from "./jwt.js";
41
+ // JWT 令牌
42
+ export { verifyToken, generateToken, setToken, getToken } from "../security/jwt.js";
34
43
 
35
44
  // 签名/加密
36
- export {
37
- signData,
38
- verifySign,
39
- aesEncrypt,
40
- aesDecrypt
41
- } from "./sign.js";
45
+ export { signData, verifySign, aesEncrypt, aesDecrypt } from "../security/sign.js";
42
46
 
43
47
  // 网络请求
44
- export { request } from "./request.js";
48
+ export { request } from "../utils/request.js";
45
49
 
46
50
  // 数据解析
47
- export {
48
- dataParse,
49
- arrToObj,
50
- parseJsonFields,
51
- buildTree
52
- } from "./data-parse.js";
51
+ export { dataParse, arrToObj, parseJsonFields, buildTree } from "../utils/data-parse.js";
53
52
 
54
53
  // 树形结构
55
- export { tree, treeById } from "./tree.js";
54
+ export { tree, treeById } from "../utils/tree.js";
56
55
 
57
56
  // 字段过滤
58
- export { filterFields } from "./filter.js";
57
+ export { filterFields } from "../utils/filter.js";
59
58
 
60
59
  // 响应格式化
61
60
  export {
@@ -64,14 +63,17 @@ export {
64
63
  error,
65
64
  parseDatabaseError,
66
65
  notFoundResponse,
67
- errorResponse
68
- } from "./response.js";
66
+ errorResponse,
67
+ } from "../response/index.js";
69
68
 
70
- // 内容检查
71
- export { checkKeywords, isIgnored } from "./checker.js";
69
+ // 安全检查
70
+ export { checkKeywords, isIgnored } from "../security/checker.js";
71
+ export { filterXSS } from "../security/xss-filter.js";
72
+ export { createRateLimitMiddleware } from "../security/rate-limit.js";
72
73
 
73
- // XSS过滤
74
- export { filterXSS } from "./xss-filter.js";
74
+ // 定时任务
75
+ export { schedule } from "../schedule/index.js";
75
76
 
76
- // 限流中间件
77
- export { createRateLimitMiddleware } from "./rate-limit.js";
77
+ // 实时通信
78
+ export { sse, SSEManager } from "../realtime/index.js";
79
+ export { websocket, WebSocketManager } from "../realtime/index.js";