chanjs 2.7.4 → 2.7.6

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 (94) hide show
  1. package/USAGE.md +533 -0
  2. package/config/index.js +37 -6
  3. package/core/App.js +166 -0
  4. package/core/BaseComponent.js +27 -0
  5. package/core/Container.js +68 -0
  6. package/core/Controller.js +29 -0
  7. package/core/Database.js +93 -0
  8. package/core/Repository.js +323 -0
  9. package/core/Service.js +11 -0
  10. package/core/bootstrap/error-handler.js +101 -0
  11. package/core/bootstrap/hook-runner.js +64 -0
  12. package/core/bootstrap/middleware.js +35 -0
  13. package/core/bootstrap/router-loader.js +53 -0
  14. package/core/errors.js +251 -0
  15. package/core/loader.js +89 -0
  16. package/core/registry.js +17 -0
  17. package/doc/Cache.md +279 -106
  18. package/doc/Common.md +590 -134
  19. package/doc/Controller.md +166 -95
  20. package/doc/Help.md +299 -698
  21. package/doc/QuickStart.md +116 -0
  22. package/doc/Repository.md +560 -0
  23. package/doc/Service.md +201 -527
  24. package/index.js +61 -37
  25. package/middleware/body.js +17 -0
  26. package/middleware/cookie.js +7 -15
  27. package/middleware/cors.js +9 -27
  28. package/middleware/favicon.js +15 -17
  29. package/middleware/header.js +15 -16
  30. package/middleware/index.js +11 -11
  31. package/middleware/log.js +26 -56
  32. package/middleware/static.js +15 -28
  33. package/middleware/template.js +75 -115
  34. package/middleware/validate.js +79 -0
  35. package/middleware/waf.js +176 -197
  36. package/package.json +9 -2
  37. package/response/code.js +73 -0
  38. package/response/index.js +9 -6
  39. package/response/response.js +82 -236
  40. package/security/checker.js +26 -74
  41. package/security/index.js +4 -9
  42. package/security/jwt.js +84 -139
  43. package/security/keywords.js +33 -137
  44. package/security/rate-limit.js +38 -80
  45. package/security/sign.js +83 -176
  46. package/security/xss-filter.js +21 -53
  47. package/storage/cache.js +58 -198
  48. package/storage/index.js +3 -6
  49. package/storage/redis.js +124 -181
  50. package/storage/store.js +163 -188
  51. package/utils/data-parse.js +42 -186
  52. package/utils/file.js +73 -244
  53. package/utils/filter.js +22 -25
  54. package/utils/html.js +49 -33
  55. package/utils/index.js +20 -7
  56. package/utils/ip.js +31 -71
  57. package/utils/logger.js +117 -0
  58. package/utils/pages.js +55 -0
  59. package/utils/paths.js +18 -0
  60. package/utils/request.js +95 -136
  61. package/utils/signal.js +87 -0
  62. package/utils/time.js +33 -75
  63. package/utils/tree.js +112 -104
  64. package/App.js +0 -533
  65. package/base/Aop.js +0 -195
  66. package/base/Container.js +0 -161
  67. package/base/Controller.js +0 -65
  68. package/base/Database.js +0 -133
  69. package/base/Event.js +0 -61
  70. package/base/Repository.js +0 -644
  71. package/common/api.js +0 -35
  72. package/common/code.js +0 -52
  73. package/common/email.js +0 -191
  74. package/common/index.js +0 -5
  75. package/common/pages.js +0 -120
  76. package/common/utils.js +0 -73
  77. package/config/code.js +0 -166
  78. package/config/paths.js +0 -60
  79. package/doc/Aop.md +0 -269
  80. package/doc/Email.md +0 -114
  81. package/doc/Event.md +0 -232
  82. package/global/env.js +0 -11
  83. package/global/import.js +0 -39
  84. package/global/index.js +0 -8
  85. package/helper/index.js +0 -79
  86. package/loader/index.js +0 -6
  87. package/loader/loader.js +0 -138
  88. package/middleware/compress.js +0 -185
  89. package/middleware/setBody.js +0 -32
  90. package/realtime/index.js +0 -7
  91. package/realtime/sse.js +0 -424
  92. package/realtime/websocket.js +0 -540
  93. package/schedule/index.js +0 -6
  94. package/schedule/schedule.js +0 -491
@@ -0,0 +1,116 @@
1
+ # ChanJS 快速入门
2
+
3
+ ## 安装
4
+
5
+ ```bash
6
+ npm install chanjs
7
+ ```
8
+
9
+ ## 最小化启动
10
+
11
+ ### 1. 创建入口文件 `index.js`
12
+
13
+ ```javascript
14
+ import Chan from 'chanjs';
15
+
16
+ const app = new Chan();
17
+ await app.start();
18
+ app.run(port => {
19
+ console.log(`服务启动在端口 ${port}`);
20
+ });
21
+ ```
22
+
23
+ ### 2. 创建配置文件 `config/index.js`
24
+
25
+ ```javascript
26
+ export default {
27
+ PORT: 3000,
28
+ NODE_ENV: 'dev',
29
+
30
+ // 数据库配置(可选)
31
+ db: [{
32
+ key: 'default',
33
+ client: 'mysql2',
34
+ connection: {
35
+ host: '127.0.0.1',
36
+ user: 'root',
37
+ password: '',
38
+ database: 'test'
39
+ }
40
+ }],
41
+
42
+ // 模块列表
43
+ modules: ['web', 'api']
44
+ };
45
+ ```
46
+
47
+ ### 3. 创建模块目录结构
48
+
49
+ ```
50
+ app/
51
+ ├── modules/
52
+ │ ├── web/
53
+ │ │ ├── controller/
54
+ │ │ │ └── IndexController.js
55
+ │ │ └── router.js
56
+ │ └── api/
57
+ │ ├── controller/
58
+ │ │ └── UserController.js
59
+ │ └── router.js
60
+ ```
61
+
62
+ ### 4. 创建控制器
63
+
64
+ ```javascript
65
+ // app/modules/api/controller/UserController.js
66
+ import { Controller } from 'chanjs';
67
+
68
+ export default class UserController extends Controller {
69
+ async getUser(req, res) {
70
+ const { id } = req.params;
71
+ // 业务逻辑
72
+ return this.success({ data: { id, name: '张三' } });
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### 5. 创建路由
78
+
79
+ ```javascript
80
+ // app/modules/api/router.js
81
+ import { loader } from 'chanjs';
82
+
83
+ export default async function(app, router, config) {
84
+ const userCtrl = await loader.loadController('api', 'UserController');
85
+
86
+ router.get('/user/:id', userCtrl.getUser);
87
+ }
88
+ ```
89
+
90
+ ## 访问测试
91
+
92
+ ```bash
93
+ curl http://localhost:3000/api/user/1
94
+ ```
95
+
96
+ 响应:
97
+ ```json
98
+ {
99
+ "success": true,
100
+ "code": 0,
101
+ "msg": "操作成功",
102
+ "data": {
103
+ "id": "1",
104
+ "name": "张三"
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## 下一步
110
+
111
+ - [Controller 控制器](./Controller.md) - 学习控制器编写规范
112
+ - [Service 服务层](./Service.md) - 业务逻辑层使用
113
+ - [Repository 数据层](./Repository.md) - 数据库操作
114
+ - [Cache 缓存](./Cache.md) - 缓存使用
115
+ - [Common 公共配置](./Common.md) - 全局配置说明
116
+ - [Help API 参考](./Help.md) - 完整 API 文档
@@ -0,0 +1,560 @@
1
+ # Repository 数据访问层
2
+
3
+ ## 概述
4
+
5
+ `Repository` 是数据访问层基类,继承自 `Container`,封装了常用的数据库 CRUD 操作。基于 Knex.js 构建,提供统一的查询接口和错误处理。
6
+
7
+ ## 继承关系
8
+
9
+ ```
10
+ Container <── Repository
11
+ ```
12
+
13
+ ## 构造函数
14
+
15
+ ```javascript
16
+ constructor(tableName, dbName = 'default')
17
+ ```
18
+
19
+ **参数**
20
+
21
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
22
+ |------|------|------|--------|------|
23
+ | tableName | string | 是 | - | 数据库表名 |
24
+ | dbName | string | 否 | 'default' | 数据库连接名称 |
25
+
26
+ **示例**
27
+
28
+ ```javascript
29
+ import { Repository } from 'chanjs';
30
+
31
+ class UserRepo extends Repository {
32
+ constructor() {
33
+ super('users', 'default');
34
+ }
35
+ }
36
+
37
+ export default new UserRepo();
38
+ ```
39
+
40
+ ## 核心方法
41
+
42
+ ### 1. all - 查询全部
43
+
44
+ ```javascript
45
+ all({ query, sort, fields, limit })
46
+ ```
47
+
48
+ **参数**
49
+
50
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
51
+ |------|------|------|--------|------|
52
+ | query | object | 否 | {} | 查询条件 |
53
+ | sort | object | 否 | {} | 排序规则 |
54
+ | fields | string[] | 否 | [] | 返回字段,空数组返回全部 |
55
+ | limit | number | 否 | 1000 | 返回数量上限 |
56
+
57
+ **返回值**
58
+
59
+ ```javascript
60
+ {
61
+ success: true,
62
+ code: 0,
63
+ msg: '操作成功',
64
+ data: [...]
65
+ }
66
+ ```
67
+
68
+ **示例**
69
+
70
+ ```javascript
71
+ // 查询所有用户
72
+ const users = await userRepo.all();
73
+
74
+ // 条件查询 + 排序
75
+ const activeUsers = await userRepo.all({
76
+ query: { status: 1 },
77
+ sort: { createdAt: 'desc' },
78
+ fields: ['id', 'name', 'email'],
79
+ limit: 100
80
+ });
81
+ ```
82
+
83
+ ### 2. find - 分页查询
84
+
85
+ ```javascript
86
+ find({ query, sort, fields, limit, offset })
87
+ ```
88
+
89
+ **参数**
90
+
91
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
92
+ |------|------|------|--------|------|
93
+ | query | object | 否 | {} | 查询条件 |
94
+ | sort | object | 否 | {} | 排序规则 |
95
+ | fields | string[] | 否 | [] | 返回字段 |
96
+ | limit | number | 否 | 10 | 每页数量 |
97
+ | offset | number | 否 | 0 | 偏移量 |
98
+
99
+ **返回值**
100
+
101
+ ```javascript
102
+ {
103
+ success: true,
104
+ code: 0,
105
+ msg: '操作成功',
106
+ data: {
107
+ list: [...],
108
+ total: 100,
109
+ limit: 10,
110
+ offset: 0
111
+ }
112
+ }
113
+ ```
114
+
115
+ **示例**
116
+
117
+ ```javascript
118
+ const result = await userRepo.find({
119
+ query: { status: 1 },
120
+ sort: { id: 'desc' },
121
+ limit: 20,
122
+ offset: 40 // 第 3 页
123
+ });
124
+ ```
125
+
126
+ ### 3. findOne - 查询单条
127
+
128
+ ```javascript
129
+ findOne({ query, fields })
130
+ ```
131
+
132
+ **参数**
133
+
134
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
135
+ |------|------|------|--------|------|
136
+ | query | object | 是 | - | 查询条件 |
137
+ | fields | string[] | 否 | [] | 返回字段 |
138
+
139
+ **返回值**
140
+
141
+ ```javascript
142
+ {
143
+ success: true,
144
+ code: 0,
145
+ msg: '操作成功',
146
+ data: { ... } // 或 null
147
+ }
148
+ ```
149
+
150
+ **示例**
151
+
152
+ ```javascript
153
+ const user = await userRepo.findOne({
154
+ query: { email: 'test@example.com' }
155
+ });
156
+ ```
157
+
158
+ ### 4. findById - 根据 ID 查询
159
+
160
+ ```javascript
161
+ findById(id, { fields })
162
+ ```
163
+
164
+ **参数**
165
+
166
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
167
+ |------|------|------|--------|------|
168
+ | id | number/string | 是 | - | 记录 ID |
169
+ | fields | string[] | 否 | [] | 返回字段 |
170
+
171
+ **示例**
172
+
173
+ ```javascript
174
+ const user = await userRepo.findById(1);
175
+ ```
176
+
177
+ ### 5. insert - 插入记录
178
+
179
+ ```javascript
180
+ insert(data)
181
+ ```
182
+
183
+ **参数**
184
+
185
+ | 参数 | 类型 | 必填 | 说明 |
186
+ |------|------|------|------|
187
+ | data | object | 是 | 插入的数据 |
188
+
189
+ **返回值**
190
+
191
+ ```javascript
192
+ {
193
+ success: true,
194
+ code: 0,
195
+ msg: '操作成功',
196
+ data: { insertId: 1 }
197
+ }
198
+ ```
199
+
200
+ **示例**
201
+
202
+ ```javascript
203
+ const result = await userRepo.insert({
204
+ name: '张三',
205
+ email: 'zhangsan@example.com',
206
+ status: 1
207
+ });
208
+ ```
209
+
210
+ ### 6. insertMany - 批量插入
211
+
212
+ ```javascript
213
+ insertMany(records)
214
+ ```
215
+
216
+ **参数**
217
+
218
+ | 参数 | 类型 | 必填 | 说明 |
219
+ |------|------|------|------|
220
+ | records | object[] | 是 | 记录数组 |
221
+
222
+ **示例**
223
+
224
+ ```javascript
225
+ await userRepo.insertMany([
226
+ { name: '张三', email: 'zhangsan@example.com' },
227
+ { name: '李四', email: 'lisi@example.com' }
228
+ ]);
229
+ ```
230
+
231
+ ### 7. updateById - 根据 ID 更新
232
+
233
+ ```javascript
234
+ updateById(id, data)
235
+ ```
236
+
237
+ **参数**
238
+
239
+ | 参数 | 类型 | 必填 | 说明 |
240
+ |------|------|------|------|
241
+ | id | number/string | 是 | 记录 ID |
242
+ | data | object | 是 | 更新的数据 |
243
+
244
+ **返回值**
245
+
246
+ ```javascript
247
+ {
248
+ success: true,
249
+ code: 0,
250
+ msg: '操作成功',
251
+ data: { affectedRows: 1 }
252
+ }
253
+ ```
254
+
255
+ **示例**
256
+
257
+ ```javascript
258
+ await userRepo.updateById(1, {
259
+ name: '张三丰',
260
+ updatedAt: new Date()
261
+ });
262
+ ```
263
+
264
+ ### 8. updateByQuery - 条件更新
265
+
266
+ ```javascript
267
+ updateByQuery({ query, data })
268
+ ```
269
+
270
+ **参数**
271
+
272
+ | 参数 | 类型 | 必填 | 说明 |
273
+ |------|------|------|------|
274
+ | query | object | 是 | 更新条件 |
275
+ | data | object | 是 | 更新的数据 |
276
+
277
+ **示例**
278
+
279
+ ```javascript
280
+ await userRepo.updateByQuery({
281
+ query: { status: 0 },
282
+ data: { status: 1 }
283
+ });
284
+ ```
285
+
286
+ ### 9. del - 条件删除
287
+
288
+ ```javascript
289
+ del(query)
290
+ ```
291
+
292
+ **参数**
293
+
294
+ | 参数 | 类型 | 必填 | 说明 |
295
+ |------|------|------|------|
296
+ | query | object | 是 | 删除条件 |
297
+
298
+ **返回值**
299
+
300
+ ```javascript
301
+ {
302
+ success: true,
303
+ code: 0,
304
+ msg: '操作成功',
305
+ data: { affectedRows: 1 }
306
+ }
307
+ ```
308
+
309
+ **示例**
310
+
311
+ ```javascript
312
+ await userRepo.del({ status: -1 });
313
+ ```
314
+
315
+ ### 10. deleteById - 根据 ID 删除
316
+
317
+ ```javascript
318
+ deleteById(id)
319
+ ```
320
+
321
+ **示例**
322
+
323
+ ```javascript
324
+ await userRepo.deleteById(1);
325
+ ```
326
+
327
+ ### 11. deleteMany - 批量删除
328
+
329
+ ```javascript
330
+ deleteMany(ids)
331
+ ```
332
+
333
+ **参数**
334
+
335
+ | 参数 | 类型 | 必填 | 说明 |
336
+ |------|------|------|------|
337
+ | ids | array | 是 | ID 数组 |
338
+
339
+ **示例**
340
+
341
+ ```javascript
342
+ await userRepo.deleteMany([1, 2, 3]);
343
+ ```
344
+
345
+ ### 12. count - 统计数量
346
+
347
+ ```javascript
348
+ count(query)
349
+ ```
350
+
351
+ **参数**
352
+
353
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
354
+ |------|------|------|--------|------|
355
+ | query | object | 否 | {} | 查询条件 |
356
+
357
+ **返回值**
358
+
359
+ ```javascript
360
+ {
361
+ success: true,
362
+ code: 0,
363
+ msg: '操作成功',
364
+ data: { count: 100 }
365
+ }
366
+ ```
367
+
368
+ **示例**
369
+
370
+ ```javascript
371
+ const result = await userRepo.count({ status: 1 });
372
+ console.log(result.data.count); // 100
373
+ ```
374
+
375
+ ### 13. exists - 判断是否存在
376
+
377
+ ```javascript
378
+ exists(query)
379
+ ```
380
+
381
+ **参数**
382
+
383
+ | 参数 | 类型 | 必填 | 说明 |
384
+ |------|------|------|------|
385
+ | query | object | 是 | 查询条件 |
386
+
387
+ **返回值**
388
+
389
+ ```javascript
390
+ {
391
+ success: true,
392
+ code: 0,
393
+ msg: '操作成功',
394
+ data: { exists: true }
395
+ }
396
+ ```
397
+
398
+ **示例**
399
+
400
+ ```javascript
401
+ const result = await userRepo.exists({ email: 'test@example.com' });
402
+ if (result.data.exists) {
403
+ console.log('用户已存在');
404
+ }
405
+ ```
406
+
407
+ ### 14. join - 联表查询
408
+
409
+ ```javascript
410
+ join({ joinTable, localField, foreignField, fields, query, sort })
411
+ ```
412
+
413
+ **参数**
414
+
415
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
416
+ |------|------|------|--------|------|
417
+ | joinTable | string | 是 | - | 关联表名 |
418
+ | localField | string | 是 | - | 本表关联字段 |
419
+ | foreignField | string | 是 | - | 关联表字段 |
420
+ | fields | string[] | 否 | [] | 返回字段 |
421
+ | query | object | 否 | {} | 查询条件 |
422
+ | sort | object | 否 | {} | 排序规则 |
423
+
424
+ **示例**
425
+
426
+ ```javascript
427
+ const result = await userRepo.join({
428
+ joinTable: 'orders',
429
+ localField: 'id',
430
+ foreignField: 'userId',
431
+ fields: ['users.name', 'orders.total'],
432
+ query: { 'orders.status': 1 }
433
+ });
434
+ ```
435
+
436
+ ### 15. stats - 统计总数和今日新增
437
+
438
+ ```javascript
439
+ stats(dateField = 'createdAt')
440
+ ```
441
+
442
+ **参数**
443
+
444
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
445
+ |------|------|------|--------|------|
446
+ | dateField | string | 否 | 'createdAt' | 日期字段名 |
447
+
448
+ **返回值**
449
+
450
+ ```javascript
451
+ {
452
+ success: true,
453
+ code: 0,
454
+ msg: '操作成功',
455
+ data: {
456
+ total: 1000,
457
+ today: 50
458
+ }
459
+ }
460
+ ```
461
+
462
+ **示例**
463
+
464
+ ```javascript
465
+ const result = await userRepo.stats('createdAt');
466
+ console.log(`总数:${result.data.total},今日新增:${result.data.today}`);
467
+ ```
468
+
469
+ ## 查询条件语法
470
+
471
+ Repository 支持灵活的查询条件语法:
472
+
473
+ ### 等值查询
474
+
475
+ ```javascript
476
+ { field: value }
477
+ ```
478
+
479
+ ### 范围查询
480
+
481
+ ```javascript
482
+ { field: { $gt: 10, $lt: 20 } } // 大于 10 且小于 20
483
+ { field: { $gte: 10, $lte: 20 } } // 大于等于 10 且小于等于 20
484
+ ```
485
+
486
+ ### 模糊查询
487
+
488
+ ```javascript
489
+ { field: { $like: '%keyword%' } }
490
+ ```
491
+
492
+ ### IN 查询
493
+
494
+ ```javascript
495
+ { field: { $in: [1, 2, 3] } }
496
+ ```
497
+
498
+ ### NOT 查询
499
+
500
+ ```javascript
501
+ { field: { $ne: value } }
502
+ ```
503
+
504
+ ### NULL 查询
505
+
506
+ ```javascript
507
+ { field: { $null: true } } // IS NULL
508
+ { field: { $notNull: true } } // IS NOT NULL
509
+ ```
510
+
511
+ ## 完整示例
512
+
513
+ ```javascript
514
+ import { Repository } from 'chanjs';
515
+
516
+ class UserRepo extends Repository {
517
+ constructor() {
518
+ super('users', 'default');
519
+ }
520
+
521
+ // 自定义业务方法
522
+ async findActiveUsers() {
523
+ return this.all({
524
+ query: { status: 1 },
525
+ sort: { createdAt: 'desc' }
526
+ });
527
+ }
528
+
529
+ async findByEmail(email) {
530
+ return this.findOne({
531
+ query: { email }
532
+ });
533
+ }
534
+
535
+ async deactivateUser(id) {
536
+ return this.updateById(id, {
537
+ status: 0,
538
+ deactivatedAt: new Date()
539
+ });
540
+ }
541
+ }
542
+
543
+ export default new UserRepo();
544
+ ```
545
+
546
+ ## 注意事项
547
+
548
+ 1. Repository 封装了 Knex.js,所有查询都会经过参数校验和 SQL 注入防护
549
+ 2. 返回结果统一使用 `{ success, code, msg, data }` 格式
550
+ 3. 错误会自动转换为框架标准错误类
551
+ 4. 支持多数据库连接,通过构造函数的 `dbName` 参数指定
552
+ 5. 日期字段会自动进行格式化处理
553
+
554
+ ## 相关文档
555
+
556
+ - [QuickStart](./QuickStart.md) - 快速入门
557
+ - [Controller](./Controller.md) - 控制器基类
558
+ - [Service](./Service.md) - 服务基类
559
+ - [Cache](./Cache.md) - 缓存工具
560
+ - [Common](./Common.md) - 公共工具模块