chanjs 2.7.3 → 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 +11 -3
  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
package/doc/Cache.md CHANGED
@@ -1,160 +1,333 @@
1
- # Cache 工具类文档
1
+ # Cache 缓存工具
2
+
2
3
  ## 概述
3
- `Cache` 是一个基于内存实现的 LRU(最近最少使用)缓存类,支持 TTL(生存时间)过期策略和自动过期清理机制。该类通过两个 `Map` 分别存储缓存数据和访问顺序,既保证了缓存的快速存取,又能实现 LRU 淘汰策略,适用于需要临时缓存数据且对内存使用有控制需求的场景。
4
4
 
5
- ## 安装与引入
6
- 从 `chanjs/helper` 模块中引入 `Cache` 类和默认实例:
7
- ```javascript
8
- import { Cache } from 'chanjs/helper';
9
- // 或引入预创建的默认缓存实例
10
- import { cache } from 'chanjs/helper';
11
- ```
5
+ `Cache` 是基于单 Map 实现的 LRU + 惰性 TTL 过期清理缓存类,对齐 Redis incr 行为,专用于限流场景的内存存储。
6
+
7
+ ## 特性
12
8
 
13
- ## 类构造器
14
- ### `constructor(options = {})`
15
- 创建缓存实例,初始化最大容量和默认过期时间。
9
+ - **LRU 淘汰**:访问刷新 LRU 顺序,容量超限时自动淘汰最久未使用的条目
10
+ - **惰性 TTL**:自增不续期,批量惰性清理过期条目
11
+ - **容量淘汰**:达到最大容量时自动 LRU 淘汰
12
+ - **高性能**:10w 容量,定时批量清理避免阻塞事件循环
16
13
 
17
- | 参数 | 类型 | 默认值 | 说明 |
18
- |------|------|--------|------|
19
- | options.maxSize | number | 1000 | 缓存最大条目数,达到该数量时会自动淘汰最久未使用的条目 |
20
- | options.defaultTTL | number | 300000(5分钟) | 默认过期时间(毫秒),未指定 TTL 时使用该值 |
14
+ ## 引入方式
21
15
 
22
- **示例**:
23
16
  ```javascript
24
- // 创建自定义配置的缓存实例
25
- const customCache = new Cache({
26
- maxSize: 500, // 最大缓存500条
27
- defaultTTL: 60000 // 默认1分钟过期
28
- });
17
+ import { cache } from 'chanjs';
29
18
 
30
- // 使用默认配置的缓存实例(maxSize=1000,defaultTTL=5分钟)
31
- const defaultCache = new Cache();
19
+ // 或创建自定义实例
20
+ import Cache from 'chanjs/storage/cache.js';
21
+ const customCache = new Cache({ maxSize: 50000, defaultTTL: 60000 });
32
22
  ```
33
23
 
24
+ ## 构造函数
25
+
26
+ ```javascript
27
+ new Cache(opts = {})
28
+ ```
29
+
30
+ **参数**
31
+
32
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
33
+ |------|------|------|--------|------|
34
+ | opts.maxSize | number | 否 | 100000 | 缓存最大条目数 |
35
+ | opts.defaultTTL | number | 否 | 300000 (5分钟) | 默认过期时间(毫秒) |
36
+
34
37
  ## 核心方法
35
- ### 1. 设置缓存值
36
- #### `set(key, value, ttl = this.defaultTTL)`
37
- 将键值对存入缓存,若缓存达到最大容量且键不存在,则自动淘汰最久未使用的条目,每次设置会更新访问时间。
38
38
 
39
- | 参数 | 类型 | 默认值 | 说明 |
40
- |------|------|--------|------|
41
- | key | string | - | 缓存键(非空字符串) |
42
- | value | * | - | 要缓存的任意类型数据 |
43
- | ttl | number | 实例默认TTL | 该缓存条目的过期时间(毫秒) |
39
+ ### 1. set - 写入缓存
40
+
41
+ ```javascript
42
+ set(key, value, ttl = this.defaultTTL)
43
+ ```
44
+
45
+ **参数**
46
+
47
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
48
+ |------|------|------|--------|------|
49
+ | key | string | 是 | - | 缓存键 |
50
+ | value | any | 是 | - | 缓存值 |
51
+ | ttl | number | 否 | defaultTTL | 过期时间(毫秒),<=0 视为永久存储 |
52
+
53
+ **示例**
44
54
 
45
- **示例**:
46
55
  ```javascript
47
- // 设置60秒后过期的缓存
48
- customCache.set('user:123', { name: '张三', age: 20 }, 60000);
56
+ import { cache } from 'chanjs';
57
+
58
+ // 设置 60 秒过期的缓存
59
+ cache.set('user:1001', { name: '张三' }, 60000);
49
60
 
50
- // 使用默认过期时间(5分钟)
51
- customCache.set('config:theme', { color: 'blue' });
61
+ // 永久存储(ttl <= 0)
62
+ cache.set('config:app', { version: '1.0' }, 0);
52
63
  ```
53
64
 
54
- ### 2. 获取缓存值
55
- #### `get(key)`
56
- 获取指定键的缓存值,若键不存在或已过期则返回 `null`;过期条目会自动删除,命中的条目会更新访问时间。
65
+ ### 2. get - 读取缓存
66
+
67
+ ```javascript
68
+ get(key)
69
+ ```
57
70
 
58
- | 参数 | 类型 | 说明 |
59
- |------|------|------|
60
- | key | string | 要获取的缓存键 |
71
+ **参数**
61
72
 
62
- | 返回值 | 类型 | 说明 |
63
- |--------|------|------|
64
- | - | * | 缓存的原始值(命中且未过期);`null`(未命中/已过期) |
73
+ | 参数 | 类型 | 必填 | 说明 |
74
+ |------|------|------|------|
75
+ | key | string | | 缓存键 |
76
+
77
+ **返回值**
78
+
79
+ - 缓存值:存在且未过期
80
+ - `null`:不存在或已过期
81
+
82
+ **示例**
65
83
 
66
- **示例**:
67
84
  ```javascript
68
- const user = customCache.get('user:123');
69
- if (user !== null) {
70
- console.log('缓存命中:', user); // { name: '张三', age: 20 }
85
+ const user = cache.get('user:1001');
86
+ if (user) {
87
+ console.log('用户信息:', user);
71
88
  } else {
72
- console.log('缓存未命中或已过期');
89
+ console.log('缓存不存在或已过期');
73
90
  }
74
91
  ```
75
92
 
76
- ### 3. 删除缓存条目
77
- #### `del(key)`
78
- 从缓存中删除指定键的条目,同时删除对应的访问记录。
93
+ ### 3. has - 检查存在
94
+
95
+ ```javascript
96
+ has(key)
97
+ ```
98
+
99
+ **参数**
100
+
101
+ | 参数 | 类型 | 必填 | 说明 |
102
+ |------|------|------|------|
103
+ | key | string | 是 | 缓存键 |
104
+
105
+ **返回值**
106
+
107
+ - `true`:存在且未过期
108
+ - `false`:不存在或已过期
109
+
110
+ **示例**
111
+
112
+ ```javascript
113
+ if (cache.has('user:1001')) {
114
+ console.log('缓存存在');
115
+ }
116
+ ```
117
+
118
+ ### 4. del - 删除缓存
119
+
120
+ ```javascript
121
+ del(key)
122
+ ```
123
+
124
+ **示例**
125
+
126
+ ```javascript
127
+ cache.del('user:1001');
128
+ ```
129
+
130
+ ### 5. clear - 清空所有
131
+
132
+ ```javascript
133
+ clear()
134
+ ```
135
+
136
+ **示例**
137
+
138
+ ```javascript
139
+ cache.clear();
140
+ ```
141
+
142
+ ### 6. size - 获取数量
143
+
144
+ ```javascript
145
+ size()
146
+ ```
147
+
148
+ **返回值**
149
+
150
+ 缓存条目总数(近似值,包含未惰性清理的过期项)
79
151
 
80
- | 参数 | 类型 | 说明 |
81
- |------|------|------|
82
- | key | string | 要删除的缓存键 |
152
+ **示例**
83
153
 
84
- **示例**:
85
154
  ```javascript
86
- customCache.del('user:123'); // 删除指定缓存
155
+ const count = cache.size();
156
+ console.log(`缓存条目数:${count}`);
87
157
  ```
88
158
 
89
- ### 4. 清空所有缓存
90
- #### `clear()`
91
- 删除所有缓存条目和访问记录,清空整个缓存。
159
+ ### 7. incr - 自增(限流专用)
92
160
 
93
- **示例**:
94
161
  ```javascript
95
- customCache.clear(); // 清空所有缓存
162
+ incr(key, ttlMs = 60000)
96
163
  ```
97
164
 
98
- ### 5. 检查缓存键是否存在
99
- #### `has(key)`
100
- 检查指定键是否存在且未过期,若已过期则自动删除条目并返回 `false`。
165
+ **参数**
101
166
 
102
- | 参数 | 类型 | 说明 |
103
- |------|------|------|
104
- | key | string | 要检查的缓存键 |
167
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
168
+ |------|------|------|--------|------|
169
+ | key | string | | - | 缓存键 |
170
+ | ttlMs | number | 否 | 60000 | 新建 key 的过期时间(毫秒),存量不续期 |
105
171
 
106
- | 返回值 | 类型 | 说明 |
107
- |--------|------|------|
108
- | - | boolean | `true`(存在且未过期);`false`(不存在/已过期) |
172
+ **返回值**
173
+
174
+ 自增后的值(number)
175
+
176
+ **特性**
177
+
178
+ - 新建 key 使用指定 TTL
179
+ - 存量 key 不续期 TTL
180
+ - 支持容量超限自动 LRU 淘汰
181
+
182
+ **示例**
109
183
 
110
- **示例**:
111
184
  ```javascript
112
- if (customCache.has('config:theme')) {
113
- console.log('缓存存在且有效');
185
+ // 限流场景:60 秒内最多 100 次请求
186
+ const count = cache.incr('rate:192.168.1.1', 60000);
187
+ if (count > 100) {
188
+ console.log('请求过于频繁');
114
189
  } else {
115
- console.log('缓存不存在或已过期');
190
+ console.log(`当前第 ${count} 次请求`);
116
191
  }
117
192
  ```
118
193
 
119
- ### 6. 获取缓存有效条目数
120
- #### `size()`
121
- 返回当前缓存中的有效条目数量(会先自动清理已过期条目)。
194
+ ### 8. incrAndExpire - 自增并设置过期时间
195
+
196
+ ```javascript
197
+ incrAndExpire(key, ttlMs)
198
+ ```
199
+
200
+ **参数**
201
+
202
+ | 参数 | 类型 | 必填 | 说明 |
203
+ |------|------|------|------|
204
+ | key | string | 是 | 缓存键 |
205
+ | ttlMs | number | 是 | 新建 key 的过期时间(毫秒) |
122
206
 
123
- | 返回值 | 类型 | 说明 |
124
- |--------|------|------|
125
- | - | number | 有效缓存条目数 |
207
+ **返回值**
208
+
209
+ 自增后的值(number
210
+
211
+ **示例**
126
212
 
127
- **示例**:
128
213
  ```javascript
129
- console.log(`当前缓存有效条目数: ${customCache.size()}`);
214
+ const count = cache.incrAndExpire('limit:api:1001', 30000);
130
215
  ```
131
216
 
132
- ## 内部方法(私有)
133
- ### 1. `_evictLRU()`
134
- 淘汰最久未使用的缓存条目,当缓存达到最大容量时自动调用。遍历访问顺序 `Map`,找到访问时间最早的键并删除对应的缓存和访问记录。
217
+ ### 9. expire - 刷新过期时间
218
+
219
+ ```javascript
220
+ expire(key, ttlMs)
221
+ ```
222
+
223
+ **参数**
224
+
225
+ | 参数 | 类型 | 必填 | 说明 |
226
+ |------|------|------|------|
227
+ | key | string | 是 | 缓存键 |
228
+ | ttlMs | number | 是 | 新的过期时间(毫秒) |
229
+
230
+ **返回值**
231
+
232
+ - `true`:刷新成功
233
+ - `false`:key 不存在或已过期
135
234
 
136
- ### 2. `_cleanupExpired()`
137
- 清理所有已过期的缓存条目,在调用 `size()` 方法时自动触发。遍历缓存 `Map`,删除所有过期的条目及对应的访问记录。
235
+ **示例**
138
236
 
139
- ## 预创建实例
140
- 模块导出了一个默认的 `cache` 实例,使用默认配置(`maxSize=1000`,`defaultTTL=5分钟`),可直接使用:
141
237
  ```javascript
142
- import { cache } from 'chanjs/helper';
238
+ // 续期 30
239
+ cache.expire('session:1001', 30000);
240
+ ```
241
+
242
+ ## 内部机制
243
+
244
+ ### LRU 淘汰
245
+
246
+ - 使用 Map 的插入顺序特性
247
+ - 访问时删除再插入,刷新到最新位置
248
+ - 容量超限时淘汰最久未使用的条目
249
+
250
+ ### 惰性清理
251
+
252
+ - 每 10 秒触发一次批量清理
253
+ - 单次最多清理 1000 条,避免阻塞事件循环
254
+ - 读取时检查过期状态,过期则删除
255
+
256
+ ### 容量配置
143
257
 
144
- // 直接使用默认实例
145
- cache.set('global:token', 'abc123', 1800000); // 30分钟过期
146
- const token = cache.get('global:token');
258
+ - 默认最大容量:100,000 条
259
+ - 达到容量上限时自动 LRU 淘汰
260
+ - 可通过构造函数自定义
261
+
262
+ ## 使用场景
263
+
264
+ ### 1. 接口限流
265
+
266
+ ```javascript
267
+ import { cache } from 'chanjs';
268
+
269
+ function rateLimitMiddleware(req, res, next) {
270
+ const ip = req.ip;
271
+ const key = `rate:${ip}`;
272
+ const count = cache.incr(key, 60000); // 60 秒窗口
273
+
274
+ if (count > 100) {
275
+ return res.status(429).json({
276
+ success: false,
277
+ code: 1009,
278
+ msg: '请求过于频繁'
279
+ });
280
+ }
281
+
282
+ next();
283
+ }
147
284
  ```
148
285
 
149
- ## 核心特性
150
- 1. **LRU 淘汰**:缓存达到最大容量时,自动删除最久未使用的条目;
151
- 2. **TTL 过期**:支持自定义过期时间,过期条目自动清理;
152
- 3. **自动清理**:获取缓存大小、检查键存在性时,自动清理过期条目;
153
- 4. **访问更新**:每次设置/获取缓存,都会更新该条目的访问时间,保证 LRU 策略准确性;
154
- 5. **内存安全**:通过最大条目数限制,避免缓存无限制占用内存。
286
+ ### 2. 会话缓存
287
+
288
+ ```javascript
289
+ // 存储用户会话
290
+ cache.set(`session:${userId}`, {
291
+ userId,
292
+ loginTime: Date.now(),
293
+ role: 'admin'
294
+ }, 3600000); // 1 小时
295
+
296
+ // 读取会话
297
+ const session = cache.get(`session:${userId}`);
298
+ ```
299
+
300
+ ### 3. 数据缓存
301
+
302
+ ```javascript
303
+ // 缓存数据库查询结果
304
+ async function getUserWithCache(userId) {
305
+ const key = `user:${userId}`;
306
+ let user = cache.get(key);
307
+
308
+ if (!user) {
309
+ user = await db('users').where({ id: userId }).first();
310
+ if (user) {
311
+ cache.set(key, user, 300000); // 缓存 5 分钟
312
+ }
313
+ }
314
+
315
+ return user;
316
+ }
317
+ ```
155
318
 
156
319
  ## 注意事项
157
- 1. 缓存数据存储在内存中,应用重启后会丢失,不适用于持久化存储场景;
158
- 2. 键必须为字符串类型,非字符串键可能导致不可预期的问题;
159
- 3. 缓存值建议为可序列化的数据(如对象、字符串、数字等),避免存储复杂对象(如 DOM 元素、函数)导致内存泄漏;
160
- 4. 若需高频清理过期条目,可手动调用 `size()` 方法触发清理(不建议频繁调用,会遍历全量缓存)。
320
+
321
+ 1. **内存占用**:缓存存储在内存中,应用重启后数据丢失
322
+ 2. **容量限制**:默认 10w 条目,超限自动 LRU 淘汰
323
+ 3. **过期精度**:惰性清理,过期时间可能有几秒误差
324
+ 4. **并发安全**:单线程环境,无需考虑并发问题
325
+ 5. **适用场景**:限流计数、临时缓存、会话存储等短 TTL 数据
326
+ 6. **不适用**:持久化存储、跨进程共享、大数据量存储
327
+
328
+ ## 与 Store 的关系
329
+
330
+ - `Cache` 是底层内存缓存实现
331
+ - `Store` 是统一存储适配层,封装了 `Cache` 和 Redis
332
+ - 业务层推荐使用 `Store`,自动切换内存/Redis
333
+ - 仅在使用纯内存场景时直接使用 `Cache`