chanjs 2.7.4 → 2.7.5

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 (93) 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/Container.js +77 -0
  5. package/core/Controller.js +29 -0
  6. package/core/Database.js +93 -0
  7. package/core/Repository.js +327 -0
  8. package/core/Service.js +11 -0
  9. package/core/bootstrap/error-handler.js +104 -0
  10. package/core/bootstrap/hook-runner.js +64 -0
  11. package/core/bootstrap/middleware.js +35 -0
  12. package/core/bootstrap/router-loader.js +53 -0
  13. package/core/errors.js +224 -0
  14. package/core/loader.js +89 -0
  15. package/core/registry.js +17 -0
  16. package/doc/Cache.md +279 -106
  17. package/doc/Common.md +590 -134
  18. package/doc/Controller.md +166 -95
  19. package/doc/Help.md +299 -698
  20. package/doc/QuickStart.md +116 -0
  21. package/doc/Repository.md +560 -0
  22. package/doc/Service.md +201 -527
  23. package/index.js +75 -37
  24. package/middleware/body.js +17 -0
  25. package/middleware/cookie.js +7 -15
  26. package/middleware/cors.js +9 -27
  27. package/middleware/favicon.js +7 -17
  28. package/middleware/header.js +15 -16
  29. package/middleware/index.js +11 -11
  30. package/middleware/log.js +26 -56
  31. package/middleware/static.js +15 -28
  32. package/middleware/template.js +75 -115
  33. package/middleware/validate.js +79 -0
  34. package/middleware/waf.js +174 -197
  35. package/package.json +9 -2
  36. package/response/code.js +73 -0
  37. package/response/index.js +9 -6
  38. package/response/response.js +82 -236
  39. package/security/checker.js +26 -74
  40. package/security/index.js +4 -9
  41. package/security/jwt.js +69 -142
  42. package/security/keywords.js +32 -136
  43. package/security/rate-limit.js +38 -80
  44. package/security/sign.js +83 -176
  45. package/security/xss-filter.js +21 -53
  46. package/storage/cache.js +57 -196
  47. package/storage/index.js +3 -6
  48. package/storage/redis.js +123 -181
  49. package/storage/store.js +163 -188
  50. package/utils/data-parse.js +42 -186
  51. package/utils/file.js +73 -244
  52. package/utils/filter.js +22 -25
  53. package/utils/html.js +49 -33
  54. package/utils/index.js +21 -7
  55. package/utils/ip.js +31 -71
  56. package/utils/logger.js +117 -0
  57. package/utils/pages.js +55 -0
  58. package/utils/paths.js +18 -0
  59. package/utils/request.js +94 -136
  60. package/utils/signal.js +87 -0
  61. package/utils/time.js +33 -75
  62. package/utils/tree.js +112 -104
  63. package/App.js +0 -533
  64. package/base/Aop.js +0 -195
  65. package/base/Container.js +0 -161
  66. package/base/Controller.js +0 -65
  67. package/base/Database.js +0 -133
  68. package/base/Event.js +0 -61
  69. package/base/Repository.js +0 -644
  70. package/common/api.js +0 -35
  71. package/common/code.js +0 -52
  72. package/common/email.js +0 -191
  73. package/common/index.js +0 -5
  74. package/common/pages.js +0 -120
  75. package/common/utils.js +0 -73
  76. package/config/code.js +0 -166
  77. package/config/paths.js +0 -60
  78. package/doc/Aop.md +0 -269
  79. package/doc/Email.md +0 -114
  80. package/doc/Event.md +0 -232
  81. package/global/env.js +0 -11
  82. package/global/import.js +0 -39
  83. package/global/index.js +0 -8
  84. package/helper/index.js +0 -79
  85. package/loader/index.js +0 -6
  86. package/loader/loader.js +0 -138
  87. package/middleware/compress.js +0 -185
  88. package/middleware/setBody.js +0 -32
  89. package/realtime/index.js +0 -7
  90. package/realtime/sse.js +0 -424
  91. package/realtime/websocket.js +0 -540
  92. package/schedule/index.js +0 -6
  93. 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) - 公共工具模块