chanjs 2.7.7 → 2.7.10

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 (39) hide show
  1. package/README.md +261 -363
  2. package/config/index.js +4 -2
  3. package/core/App.js +35 -0
  4. package/core/Container.js +56 -29
  5. package/core/Database.js +58 -8
  6. package/core/EventBus.js +88 -0
  7. package/core/Lang.js +56 -0
  8. package/core/Repository.js +34 -2
  9. package/core/Task.js +87 -0
  10. package/core/errors.js +0 -5
  11. package/doc/00-README.md +208 -0
  12. package/doc/01-/346/240/270/345/277/203/347/261/273Controller-Service-Repository.md +432 -0
  13. package/doc/02-/345/223/215/345/272/224/344/270/216/351/224/231/350/257/257.md +255 -0
  14. package/doc/03-/345/256/211/345/205/250/346/250/241/345/235/227.md +264 -0
  15. package/doc/04-/345/255/230/345/202/250/344/270/216/347/274/223/345/255/230.md +157 -0
  16. package/doc/05-/345/267/245/345/205/267/344/270/216/346/240/241/351/252/214.md +309 -0
  17. package/doc/06-/345/272/224/347/224/250/347/224/237/345/221/275/345/221/250/346/234/237.md +207 -0
  18. package/doc/07-/344/272/213/344/273/266/347/263/273/347/273/237EventBus.md +324 -0
  19. package/doc/08-/345/256/232/346/227/266/344/273/273/345/212/241Task.md +262 -0
  20. package/doc/09-/345/233/275/351/231/205/345/214/226Lang.md +220 -0
  21. package/index.js +31 -2
  22. package/middleware/log.js +48 -31
  23. package/middleware/waf.js +4 -8
  24. package/package.json +21 -3
  25. package/response/code.js +0 -12
  26. package/response/response.js +8 -2
  27. package/security/keywords.js +2 -3
  28. package/utils/logger.js +60 -91
  29. package/utils/signal.js +21 -2
  30. package/USAGE.md +0 -533
  31. package/doc/Cache.md +0 -333
  32. package/doc/Common.md +0 -638
  33. package/doc/Controller.md +0 -223
  34. package/doc/Help.md +0 -390
  35. package/doc/QuickStart.md +0 -116
  36. package/doc/Repository.md +0 -560
  37. package/doc/Service.md +0 -240
  38. package/publish.bat +0 -4
  39. package/todo.md +0 -1
package/doc/Common.md DELETED
@@ -1,638 +0,0 @@
1
- # Common 公共工具模块
2
-
3
- ## 概述
4
-
5
- `common` 模块是 chanjs 框架的公共工具集合,提供响应格式化、数据解析、HTML 处理、文件操作等常用功能。
6
-
7
- ## 引入方式
8
-
9
- ```javascript
10
- import { helper } from 'chanjs';
11
-
12
- // 或从子模块精确引用
13
- import { getIp } from 'chanjs/utils/ip.js';
14
- ```
15
-
16
- ## 核心工具
17
-
18
- ### 1. 响应格式化
19
-
20
- #### success - 成功响应
21
-
22
- ```javascript
23
- helper.success({ data, msg })
24
- ```
25
-
26
- **参数**
27
-
28
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
29
- |------|------|------|--------|------|
30
- | data | any | 否 | {} | 响应数据 |
31
- | msg | string | 否 | "操作成功" | 提示信息 |
32
-
33
- **示例**
34
-
35
- ```javascript
36
- import { helper } from 'chanjs';
37
-
38
- const response = helper.success({
39
- data: { id: 1, name: '张三' },
40
- msg: '查询成功'
41
- });
42
- // { success: true, code: 0, msg: '查询成功', data: {...} }
43
- ```
44
-
45
- #### fail - 失败响应
46
-
47
- ```javascript
48
- helper.fail({ msg, code, data })
49
- ```
50
-
51
- **参数**
52
-
53
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
54
- |------|------|------|--------|------|
55
- | msg | string | 否 | "操作失败" | 错误提示 |
56
- | code | number | 否 | 1008 | 错误码 |
57
- | data | any | 否 | {} | 附加数据 |
58
-
59
- **示例**
60
-
61
- ```javascript
62
- const response = helper.fail({
63
- msg: '参数错误',
64
- code: 1006
65
- });
66
- // { success: false, code: 1006, msg: '参数错误', data: {} }
67
- ```
68
-
69
- ### 2. IP 获取
70
-
71
- #### getIp - 获取客户端真实 IP
72
-
73
- ```javascript
74
- helper.getIp(req)
75
- ```
76
-
77
- **参数**
78
-
79
- | 参数 | 类型 | 必填 | 说明 |
80
- |------|------|------|------|
81
- | req | object | 是 | Express 请求对象 |
82
-
83
- **返回值**
84
-
85
- 客户端 IP 地址(string)
86
-
87
- **示例**
88
-
89
- ```javascript
90
- app.get('/api/user', (req, res) => {
91
- const ip = helper.getIp(req);
92
- console.log('客户端 IP:', ip);
93
- });
94
- ```
95
-
96
- ### 3. 时间处理
97
-
98
- #### formatDateFields - 格式化日期字段
99
-
100
- ```javascript
101
- helper.formatDateFields(data, fields, format)
102
- ```
103
-
104
- **参数**
105
-
106
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
107
- |------|------|------|--------|------|
108
- | data | object/array | 是 | - | 待处理的数据 |
109
- | fields | string[] | 是 | - | 需要格式化的字段名列表 |
110
- | format | string | 否 | 'YYYY-MM-DD HH:mm:ss' | 日期格式 |
111
-
112
- **示例**
113
-
114
- ```javascript
115
- const user = {
116
- id: 1,
117
- name: '张三',
118
- createdAt: '2024-01-01T00:00:00.000Z'
119
- };
120
-
121
- const formatted = helper.formatDateFields(user, ['createdAt']);
122
- // { id: 1, name: '张三', createdAt: '2024-01-01 00:00:00' }
123
- ```
124
-
125
- ### 4. 文件操作
126
-
127
- #### delImg - 删除图片
128
-
129
- ```javascript
130
- helper.delImg(filePath)
131
- ```
132
-
133
- **参数**
134
-
135
- | 参数 | 类型 | 必填 | 说明 |
136
- |------|------|------|------|
137
- | filePath | string | 是 | 图片文件路径 |
138
-
139
- **返回值**
140
-
141
- - `true`:删除成功
142
- - `false`:删除失败
143
-
144
- **示例**
145
-
146
- ```javascript
147
- const success = helper.delImg('/uploads/avatar.jpg');
148
- ```
149
-
150
- #### readFileContent - 读取文件内容
151
-
152
- ```javascript
153
- helper.readFileContent(filePath, encoding)
154
- ```
155
-
156
- **参数**
157
-
158
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
159
- |------|------|------|--------|------|
160
- | filePath | string | 是 | - | 文件路径 |
161
- | encoding | string | 否 | 'utf-8' | 文件编码 |
162
-
163
- **返回值**
164
-
165
- 文件内容(string)
166
-
167
- **示例**
168
-
169
- ```javascript
170
- const content = helper.readFileContent('/config/app.json');
171
- const config = JSON.parse(content);
172
- ```
173
-
174
- #### saveFileContent - 保存文件内容
175
-
176
- ```javascript
177
- helper.saveFileContent(filePath, content, encoding)
178
- ```
179
-
180
- **参数**
181
-
182
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
183
- |------|------|------|--------|------|
184
- | filePath | string | 是 | - | 文件路径 |
185
- | content | string | 是 | - | 文件内容 |
186
- | encoding | string | 否 | 'utf-8' | 文件编码 |
187
-
188
- **示例**
189
-
190
- ```javascript
191
- helper.saveFileContent('/logs/app.log', '日志内容');
192
- ```
193
-
194
- #### getFolders - 获取文件夹列表
195
-
196
- ```javascript
197
- helper.getFolders(dirPath)
198
- ```
199
-
200
- **参数**
201
-
202
- | 参数 | 类型 | 必填 | 说明 |
203
- |------|------|------|------|
204
- | dirPath | string | 是 | 目录路径 |
205
-
206
- **返回值**
207
-
208
- 文件夹名称数组(string[])
209
-
210
- **示例**
211
-
212
- ```javascript
213
- const folders = helper.getFolders('/uploads');
214
- // ['images', 'videos', 'documents']
215
- ```
216
-
217
- #### getHtmlFilesSync - 同步获取 HTML 文件列表
218
-
219
- ```javascript
220
- helper.getHtmlFilesSync(dirPath)
221
- ```
222
-
223
- **参数**
224
-
225
- | 参数 | 类型 | 必填 | 说明 |
226
- |------|------|------|------|
227
- | dirPath | string | 是 | 目录路径 |
228
-
229
- **返回值**
230
-
231
- HTML 文件路径数组(string[])
232
-
233
- **示例**
234
-
235
- ```javascript
236
- const htmlFiles = helper.getHtmlFilesSync('/templates');
237
- // ['index.html', 'about.html', 'contact.html']
238
- ```
239
-
240
- ### 5. HTML 处理
241
-
242
- #### htmlEncode - HTML 编码
243
-
244
- ```javascript
245
- helper.htmlEncode(str)
246
- ```
247
-
248
- **参数**
249
-
250
- | 参数 | 类型 | 必填 | 说明 |
251
- |------|------|------|------|
252
- | str | string | 是 | 待编码的字符串 |
253
-
254
- **返回值**
255
-
256
- 编码后的字符串(string)
257
-
258
- **示例**
259
-
260
- ```javascript
261
- const encoded = helper.htmlEncode('<script>alert("xss")</script>');
262
- // &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;
263
- ```
264
-
265
- #### htmlDecode - HTML 解码
266
-
267
- ```javascript
268
- helper.htmlDecode(str)
269
- ```
270
-
271
- **参数**
272
-
273
- | 参数 | 类型 | 必填 | 说明 |
274
- |------|------|------|------|
275
- | str | string | 是 | 待解码的字符串 |
276
-
277
- **返回值**
278
-
279
- 解码后的字符串(string)
280
-
281
- **示例**
282
-
283
- ```javascript
284
- const decoded = helper.htmlDecode('&lt;div&gt;内容&lt;/div&gt;');
285
- // <div>内容</div>
286
- ```
287
-
288
- #### escapeScript - 转义脚本标签
289
-
290
- ```javascript
291
- helper.escapeScript(str)
292
- ```
293
-
294
- **参数**
295
-
296
- | 参数 | 类型 | 必填 | 说明 |
297
- |------|------|------|------|
298
- | str | string | 是 | 待转义的字符串 |
299
-
300
- **返回值**
301
-
302
- 转义后的字符串(string)
303
-
304
- **示例**
305
-
306
- ```javascript
307
- const safe = helper.escapeScript('<script>alert("xss")</script>');
308
- // &lt;script>alert("xss")&lt;/script>
309
- ```
310
-
311
- #### filterImgFromStr - 从文本中提取图片 URL
312
-
313
- ```javascript
314
- helper.filterImgFromStr(str)
315
- ```
316
-
317
- **参数**
318
-
319
- | 参数 | 类型 | 必填 | 说明 |
320
- |------|------|------|------|
321
- | str | string | 是 | 包含 img 标签的文本 |
322
-
323
- **返回值**
324
-
325
- 图片 URL 数组(string[])
326
-
327
- **示例**
328
-
329
- ```javascript
330
- const content = '<p>内容<img src="image1.jpg">更多<img src="image2.png"></p>';
331
- const images = helper.filterImgFromStr(content);
332
- // ['image1.jpg', 'image2.png']
333
- ```
334
-
335
- ### 6. 数据解析
336
-
337
- #### arrToObj - 数组转对象
338
-
339
- ```javascript
340
- helper.arrToObj(arr, key)
341
- ```
342
-
343
- **参数**
344
-
345
- | 参数 | 类型 | 必填 | 说明 |
346
- |------|------|------|------|
347
- | arr | array | 是 | 源数组 |
348
- | key | string | 是 | 作为对象键的字段名 |
349
-
350
- **返回值**
351
-
352
- 转换后的对象(object)
353
-
354
- **示例**
355
-
356
- ```javascript
357
- const users = [
358
- { id: 1, name: '张三' },
359
- { id: 2, name: '李四' }
360
- ];
361
-
362
- const userMap = helper.arrToObj(users, 'id');
363
- // { 1: { id: 1, name: '张三' }, 2: { id: 2, name: '李四' } }
364
- ```
365
-
366
- #### getChildrenId - 获取子分类 ID
367
-
368
- ```javascript
369
- helper.getChildrenId(categories, parentId)
370
- ```
371
-
372
- **参数**
373
-
374
- | 参数 | 类型 | 必填 | 说明 |
375
- |------|------|------|------|
376
- | categories | array | 是 | 分类树结构 |
377
- | parentId | number | 是 | 父分类 ID |
378
-
379
- **返回值**
380
-
381
- 子分类 ID 数组(number[])
382
-
383
- **示例**
384
-
385
- ```javascript
386
- const categories = [
387
- { id: 1, children: [{ id: 2 }, { id: 3 }] },
388
- { id: 4, children: [] }
389
- ];
390
-
391
- const childIds = helper.getChildrenId(categories, 1);
392
- // [2, 3]
393
- ```
394
-
395
- ### 7. 树形结构
396
-
397
- #### tree - 构建树形结构
398
-
399
- ```javascript
400
- helper.tree(list, idKey, parentKey, childrenKey)
401
- ```
402
-
403
- **参数**
404
-
405
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
406
- |------|------|------|--------|------|
407
- | list | array | 是 | - | 扁平列表 |
408
- | idKey | string | 否 | 'id' | ID 字段名 |
409
- | parentKey | string | 否 | 'parentId' | 父 ID 字段名 |
410
- | childrenKey | string | 否 | 'children' | 子节点字段名 |
411
-
412
- **返回值**
413
-
414
- 树形结构(array)
415
-
416
- **示例**
417
-
418
- ```javascript
419
- const menus = [
420
- { id: 1, parentId: 0, name: '首页' },
421
- { id: 2, parentId: 1, name: '子菜单1' },
422
- { id: 3, parentId: 1, name: '子菜单2' }
423
- ];
424
-
425
- const tree = helper.tree(menus);
426
- // [
427
- // { id: 1, parentId: 0, name: '首页', children: [
428
- // { id: 2, parentId: 1, name: '子菜单1' },
429
- // { id: 3, parentId: 1, name: '子菜单2' }
430
- // ]}
431
- // ]
432
- ```
433
-
434
- #### treeById - 根据 ID 查找树节点
435
-
436
- ```javascript
437
- helper.treeById(tree, id)
438
- ```
439
-
440
- **参数**
441
-
442
- | 参数 | 类型 | 必填 | 说明 |
443
- |------|------|------|------|
444
- | tree | array | 是 | 树形结构 |
445
- | id | number | 是 | 节点 ID |
446
-
447
- **返回值**
448
-
449
- 节点对象或 null
450
-
451
- **示例**
452
-
453
- ```javascript
454
- const node = helper.treeById(tree, 2);
455
- // { id: 2, parentId: 1, name: '子菜单1' }
456
- ```
457
-
458
- ### 8. 字段过滤
459
-
460
- #### filterFields - 过滤对象字段
461
-
462
- ```javascript
463
- helper.filterFields(obj, fields, mode)
464
- ```
465
-
466
- **参数**
467
-
468
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
469
- |------|------|------|--------|------|
470
- | obj | object | 是 | - | 源对象 |
471
- | fields | string[] | 是 | - | 字段名列表 |
472
- | mode | string | 否 | 'include' | 模式:'include' 保留指定字段,'exclude' 排除指定字段 |
473
-
474
- **返回值**
475
-
476
- 过滤后的对象(object)
477
-
478
- **示例**
479
-
480
- ```javascript
481
- const user = { id: 1, name: '张三', password: '123', age: 25 };
482
-
483
- // 保留指定字段
484
- const safe1 = helper.filterFields(user, ['id', 'name'], 'include');
485
- // { id: 1, name: '张三' }
486
-
487
- // 排除指定字段
488
- const safe2 = helper.filterFields(user, ['password'], 'exclude');
489
- // { id: 1, name: '张三', age: 25 }
490
- ```
491
-
492
- ### 9. 分页工具
493
-
494
- #### pages - 分页计算
495
-
496
- ```javascript
497
- helper.pages(total, current, pageSize)
498
- ```
499
-
500
- **参数**
501
-
502
- | 参数 | 类型 | 必填 | 说明 |
503
- |------|------|------|------|
504
- | total | number | 是 | 总记录数 |
505
- | current | number | 是 | 当前页码 |
506
- | pageSize | number | 是 | 每页条数 |
507
-
508
- **返回值**
509
-
510
- 分页信息对象(object)
511
-
512
- **示例**
513
-
514
- ```javascript
515
- const pageInfo = helper.pages(100, 2, 10);
516
- // {
517
- // total: 100,
518
- // current: 2,
519
- // pageSize: 10,
520
- // totalPages: 10,
521
- // hasPrev: true,
522
- // hasNext: true,
523
- // offset: 10
524
- // }
525
- ```
526
-
527
- ## 安全工具
528
-
529
- ### 1. XSS 过滤
530
-
531
- #### filterXSS - 过滤 XSS 攻击
532
-
533
- ```javascript
534
- import { filterXSS } from 'chanjs';
535
-
536
- filterXSS(data)
537
- ```
538
-
539
- **参数**
540
-
541
- | 参数 | 类型 | 必填 | 说明 |
542
- |------|------|------|------|
543
- | data | any | 是 | 待过滤的数据(支持字符串、对象、数组) |
544
-
545
- **返回值**
546
-
547
- 过滤后的数据
548
-
549
- **示例**
550
-
551
- ```javascript
552
- const safe = filterXSS('<script>alert("xss")</script>');
553
- // &lt;script&gt;alert("xss")&lt;/script&gt;
554
-
555
- const safeObj = filterXSS({
556
- name: '<script>alert("xss")</script>',
557
- age: 25
558
- });
559
- // { name: '&lt;script&gt;alert("xss")&lt;/script&gt;', age: 25 }
560
- ```
561
-
562
- ### 2. 关键词检测
563
-
564
- #### checkKeywords - 检测恶意关键词
565
-
566
- ```javascript
567
- import { checkKeywords } from 'chanjs';
568
-
569
- checkKeywords(text)
570
- ```
571
-
572
- **参数**
573
-
574
- | 参数 | 类型 | 必填 | 说明 |
575
- |------|------|------|------|
576
- | text | string | 是 | 待检测的文本 |
577
-
578
- **返回值**
579
-
580
- - `null`:未检测到恶意关键词
581
- - `{ category: string, keyword: string }`:检测到恶意关键词
582
-
583
- **示例**
584
-
585
- ```javascript
586
- const result = checkKeywords('SELECT * FROM users');
587
- // { category: 'sqlInjection', keyword: 'SELECT' }
588
- ```
589
-
590
- ### 3. 限流中间件
591
-
592
- #### createRateLimitMiddleware - 创建限流中间件
593
-
594
- ```javascript
595
- import { createRateLimitMiddleware } from 'chanjs';
596
-
597
- createRateLimitMiddleware(config)
598
- ```
599
-
600
- **参数**
601
-
602
- | 参数 | 类型 | 必填 | 默认值 | 说明 |
603
- |------|------|------|--------|------|
604
- | config.windowMs | number/string | 否 | 60000 | 时间窗口(毫秒或 '1m' 格式) |
605
- | config.max | number | 否 | 60 | 窗口内最大请求数 |
606
- | config.ignorePaths | string[] | 否 | [] | 忽略的路径列表 |
607
-
608
- **返回值**
609
-
610
- Express 中间件函数
611
-
612
- **示例**
613
-
614
- ```javascript
615
- const rateLimit = createRateLimitMiddleware({
616
- windowMs: '1m', // 1 分钟
617
- max: 100, // 最多 100 次请求
618
- ignorePaths: ['/api/public']
619
- });
620
-
621
- app.use(rateLimit);
622
- ```
623
-
624
- ## 注意事项
625
-
626
- 1. `helper` 是工具函数的聚合对象,不包含业务逻辑
627
- 2. 文件操作函数需要注意路径权限
628
- 3. 安全工具(filterXSS、checkKeywords)建议在中间件层统一调用
629
- 4. 分页工具的 `total` 参数必须是数字类型
630
- 5. 树形结构工具假设数据中存在循环引用,会自动处理
631
-
632
- ## 相关文档
633
-
634
- - [QuickStart](./QuickStart.md) - 快速入门
635
- - [Controller](./Controller.md) - 控制器基类
636
- - [Service](./Service.md) - 服务基类
637
- - [Repository](./Repository.md) - 数据访问层
638
- - [Cache](./Cache.md) - 缓存工具