@taicode/common-base 1.7.0 → 1.7.2

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.
@@ -0,0 +1,358 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { BatchingBuffer } from './batching-buffer';
3
+ describe('BatchingBuffer', () => {
4
+ let batchProcessor;
5
+ let itemProcessor;
6
+ beforeEach(() => {
7
+ batchProcessor = vi.fn();
8
+ itemProcessor = vi.fn();
9
+ vi.useFakeTimers();
10
+ });
11
+ afterEach(() => {
12
+ vi.useRealTimers();
13
+ vi.clearAllMocks();
14
+ });
15
+ describe('构造函数', () => {
16
+ it('应该正确初始化批量处理模式', () => {
17
+ const buffer = new BatchingBuffer({
18
+ batchProcessor: batchProcessor,
19
+ bufferSize: 10,
20
+ flushInterval: 5000
21
+ });
22
+ expect(buffer.size).toBe(0);
23
+ expect(buffer.isEmpty).toBe(true);
24
+ expect(buffer.destroyed).toBe(false);
25
+ });
26
+ it('应该正确初始化单个处理模式', () => {
27
+ const buffer = new BatchingBuffer({
28
+ itemProcessor: itemProcessor,
29
+ bufferSize: 5,
30
+ flushInterval: 3000
31
+ });
32
+ expect(buffer.size).toBe(0);
33
+ expect(buffer.isEmpty).toBe(true);
34
+ expect(buffer.destroyed).toBe(false);
35
+ });
36
+ it('应该使用默认配置', () => {
37
+ const buffer = new BatchingBuffer({
38
+ batchProcessor: batchProcessor
39
+ });
40
+ expect(buffer.size).toBe(0);
41
+ expect(buffer.isEmpty).toBe(true);
42
+ });
43
+ it('应该在没有提供处理器时抛出错误', () => {
44
+ expect(() => {
45
+ new BatchingBuffer({});
46
+ }).toThrow('必须提供 batchProcessor 或 itemProcessor 其中之一');
47
+ });
48
+ it('应该在同时提供两个处理器时抛出错误', () => {
49
+ expect(() => {
50
+ new BatchingBuffer({
51
+ batchProcessor: batchProcessor,
52
+ itemProcessor: itemProcessor
53
+ });
54
+ }).toThrow('只能选择 batchProcessor 或 itemProcessor 中的一个');
55
+ });
56
+ it('应该在 bufferSize 无效时抛出错误', () => {
57
+ expect(() => {
58
+ new BatchingBuffer({
59
+ batchProcessor: batchProcessor,
60
+ bufferSize: 0
61
+ });
62
+ }).toThrow('bufferSize 必须大于 0');
63
+ expect(() => {
64
+ new BatchingBuffer({
65
+ batchProcessor: batchProcessor,
66
+ bufferSize: -1
67
+ });
68
+ }).toThrow('bufferSize 必须大于 0');
69
+ });
70
+ it('应该在 flushInterval 无效时抛出错误', () => {
71
+ expect(() => {
72
+ new BatchingBuffer({
73
+ batchProcessor: batchProcessor,
74
+ flushInterval: 0
75
+ });
76
+ }).toThrow('flushInterval 必须大于 0');
77
+ expect(() => {
78
+ new BatchingBuffer({
79
+ batchProcessor: batchProcessor,
80
+ flushInterval: -1
81
+ });
82
+ }).toThrow('flushInterval 必须大于 0');
83
+ });
84
+ });
85
+ describe('批量处理模式', () => {
86
+ let buffer;
87
+ beforeEach(() => {
88
+ buffer = new BatchingBuffer({
89
+ batchProcessor: batchProcessor,
90
+ bufferSize: 3,
91
+ flushInterval: 1000
92
+ });
93
+ });
94
+ afterEach(async () => {
95
+ await buffer.destroy();
96
+ });
97
+ it('应该在达到缓冲区大小时触发批量处理', () => {
98
+ buffer.add('item1');
99
+ buffer.add('item2');
100
+ expect(batchProcessor).not.toHaveBeenCalled();
101
+ buffer.add('item3');
102
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
103
+ expect(batchProcessor).toHaveBeenCalledWith(['item1', 'item2', 'item3']);
104
+ expect(buffer.size).toBe(0);
105
+ });
106
+ it('应该在时间间隔到达时触发批量处理', async () => {
107
+ buffer.add('item1');
108
+ buffer.add('item2');
109
+ expect(batchProcessor).not.toHaveBeenCalled();
110
+ vi.advanceTimersByTime(1000);
111
+ await vi.runAllTimersAsync();
112
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
113
+ expect(batchProcessor).toHaveBeenCalledWith(['item1', 'item2']);
114
+ expect(buffer.size).toBe(0);
115
+ });
116
+ it('应该支持手动刷新', async () => {
117
+ buffer.add('item1');
118
+ buffer.add('item2');
119
+ await buffer.flush();
120
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
121
+ expect(batchProcessor).toHaveBeenCalledWith(['item1', 'item2']);
122
+ expect(buffer.size).toBe(0);
123
+ });
124
+ it('应该支持批量添加数据', () => {
125
+ buffer.addBatch(['item1', 'item2', 'item3', 'item4', 'item5']);
126
+ expect(batchProcessor).toHaveBeenCalledTimes(2);
127
+ expect(batchProcessor).toHaveBeenNthCalledWith(1, ['item1', 'item2', 'item3']);
128
+ expect(batchProcessor).toHaveBeenNthCalledWith(2, ['item4', 'item5']);
129
+ expect(buffer.size).toBe(0);
130
+ });
131
+ it('应该正确处理处理器异常', () => {
132
+ const error = new Error('处理失败');
133
+ batchProcessor.mockImplementationOnce(() => {
134
+ throw error;
135
+ });
136
+ buffer.add('item1');
137
+ buffer.add('item2');
138
+ expect(() => {
139
+ buffer.add('item3');
140
+ }).toThrow('处理失败');
141
+ // 数据应该重新放回缓冲区
142
+ expect(buffer.size).toBe(3);
143
+ });
144
+ });
145
+ describe('单个处理模式', () => {
146
+ let buffer;
147
+ beforeEach(() => {
148
+ buffer = new BatchingBuffer({
149
+ itemProcessor: itemProcessor,
150
+ bufferSize: 3,
151
+ flushInterval: 1000
152
+ });
153
+ });
154
+ afterEach(async () => {
155
+ await buffer.destroy();
156
+ });
157
+ it('应该在达到缓冲区大小时触发单个处理', () => {
158
+ buffer.add('item1');
159
+ buffer.add('item2');
160
+ expect(itemProcessor).not.toHaveBeenCalled();
161
+ buffer.add('item3');
162
+ expect(itemProcessor).toHaveBeenCalledTimes(3);
163
+ expect(itemProcessor).toHaveBeenNthCalledWith(1, 'item1');
164
+ expect(itemProcessor).toHaveBeenNthCalledWith(2, 'item2');
165
+ expect(itemProcessor).toHaveBeenNthCalledWith(3, 'item3');
166
+ expect(buffer.size).toBe(0);
167
+ });
168
+ it('应该在时间间隔到达时触发单个处理', async () => {
169
+ buffer.add('item1');
170
+ buffer.add('item2');
171
+ expect(itemProcessor).not.toHaveBeenCalled();
172
+ vi.advanceTimersByTime(1000);
173
+ await vi.runAllTimersAsync();
174
+ expect(itemProcessor).toHaveBeenCalledTimes(2);
175
+ expect(itemProcessor).toHaveBeenNthCalledWith(1, 'item1');
176
+ expect(itemProcessor).toHaveBeenNthCalledWith(2, 'item2');
177
+ expect(buffer.size).toBe(0);
178
+ });
179
+ it('应该正确处理单个处理器异常', () => {
180
+ const error = new Error('单个处理失败');
181
+ itemProcessor.mockImplementationOnce(() => {
182
+ throw error;
183
+ });
184
+ buffer.add('item1');
185
+ buffer.add('item2');
186
+ expect(() => {
187
+ buffer.add('item3');
188
+ }).toThrow('单个处理失败');
189
+ // 数据应该重新放回缓冲区
190
+ expect(buffer.size).toBe(3);
191
+ });
192
+ });
193
+ describe('缓冲区状态', () => {
194
+ let buffer;
195
+ beforeEach(() => {
196
+ buffer = new BatchingBuffer({
197
+ batchProcessor: batchProcessor,
198
+ bufferSize: 5,
199
+ flushInterval: 2000
200
+ });
201
+ });
202
+ afterEach(async () => {
203
+ await buffer.destroy();
204
+ });
205
+ it('应该正确报告缓冲区大小', () => {
206
+ expect(buffer.size).toBe(0);
207
+ expect(buffer.isEmpty).toBe(true);
208
+ buffer.add(1);
209
+ expect(buffer.size).toBe(1);
210
+ expect(buffer.isEmpty).toBe(false);
211
+ buffer.add(2);
212
+ buffer.add(3);
213
+ expect(buffer.size).toBe(3);
214
+ expect(buffer.isEmpty).toBe(false);
215
+ });
216
+ it('应该正确报告距离上次刷新的时间', async () => {
217
+ const startTime = Date.now();
218
+ buffer.add(1);
219
+ vi.advanceTimersByTime(500);
220
+ expect(buffer.timeSinceLastFlush).toBeGreaterThanOrEqual(500);
221
+ await buffer.flush();
222
+ expect(buffer.timeSinceLastFlush).toBeLessThan(100);
223
+ });
224
+ });
225
+ describe('销毁功能', () => {
226
+ let buffer;
227
+ beforeEach(() => {
228
+ buffer = new BatchingBuffer({
229
+ batchProcessor: batchProcessor,
230
+ bufferSize: 5,
231
+ flushInterval: 1000
232
+ });
233
+ });
234
+ it('应该在销毁时处理剩余数据', async () => {
235
+ buffer.add('item1');
236
+ buffer.add('item2');
237
+ await buffer.destroy();
238
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
239
+ expect(batchProcessor).toHaveBeenCalledWith(['item1', 'item2']);
240
+ expect(buffer.destroyed).toBe(true);
241
+ expect(buffer.size).toBe(0);
242
+ });
243
+ it('应该在销毁时丢弃剩余数据(如果指定)', async () => {
244
+ buffer.add('item1');
245
+ buffer.add('item2');
246
+ await buffer.destroy(false);
247
+ expect(batchProcessor).not.toHaveBeenCalled();
248
+ expect(buffer.destroyed).toBe(true);
249
+ expect(buffer.size).toBe(0);
250
+ });
251
+ it('应该在销毁后拒绝添加新数据', async () => {
252
+ await buffer.destroy();
253
+ expect(() => {
254
+ buffer.add('item1');
255
+ }).toThrow('BatchingBuffer 已被销毁,不能添加新数据');
256
+ expect(() => {
257
+ buffer.addBatch(['item1', 'item2']);
258
+ }).toThrow('BatchingBuffer 已被销毁,不能添加新数据');
259
+ });
260
+ it('应该支持重复销毁', async () => {
261
+ await buffer.destroy();
262
+ await buffer.destroy();
263
+ expect(buffer.destroyed).toBe(true);
264
+ });
265
+ });
266
+ describe('自动刷新配置', () => {
267
+ it('应该在 autoFlush=false 时不自动启动定时器', async () => {
268
+ const buffer = new BatchingBuffer({
269
+ batchProcessor: batchProcessor,
270
+ bufferSize: 5,
271
+ flushInterval: 1000,
272
+ autoFlush: false
273
+ });
274
+ buffer.add('item1');
275
+ buffer.add('item2');
276
+ vi.advanceTimersByTime(2000);
277
+ await vi.runAllTimersAsync();
278
+ expect(batchProcessor).not.toHaveBeenCalled();
279
+ expect(buffer.size).toBe(2);
280
+ await buffer.destroy();
281
+ });
282
+ it('应该在 autoFlush=false 时仍支持基于大小的触发', async () => {
283
+ const buffer = new BatchingBuffer({
284
+ batchProcessor: batchProcessor,
285
+ bufferSize: 2,
286
+ flushInterval: 1000,
287
+ autoFlush: false
288
+ });
289
+ buffer.add('item1');
290
+ buffer.add('item2');
291
+ await vi.runAllTimersAsync();
292
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
293
+ expect(batchProcessor).toHaveBeenCalledWith(['item1', 'item2']);
294
+ await buffer.destroy();
295
+ });
296
+ });
297
+ describe('复杂数据类型', () => {
298
+ let buffer;
299
+ beforeEach(() => {
300
+ buffer = new BatchingBuffer({
301
+ batchProcessor: batchProcessor,
302
+ bufferSize: 2,
303
+ flushInterval: 1000
304
+ });
305
+ });
306
+ afterEach(async () => {
307
+ await buffer.destroy();
308
+ });
309
+ it('应该正确处理复杂对象', async () => {
310
+ const data1 = { id: 1, name: 'test1' };
311
+ const data2 = { id: 2, name: 'test2' };
312
+ buffer.add(data1);
313
+ buffer.add(data2);
314
+ await vi.runAllTimersAsync();
315
+ expect(batchProcessor).toHaveBeenCalledTimes(1);
316
+ expect(batchProcessor).toHaveBeenCalledWith([data1, data2]);
317
+ });
318
+ });
319
+ describe('异步处理器', () => {
320
+ let asyncBatchProcessor;
321
+ let asyncItemProcessor;
322
+ beforeEach(() => {
323
+ asyncBatchProcessor = vi.fn().mockImplementation(async (items) => {
324
+ await new Promise(resolve => setTimeout(resolve, 100));
325
+ return `处理了 ${items.length} 个项目`;
326
+ });
327
+ asyncItemProcessor = vi.fn().mockImplementation(async (item) => {
328
+ await new Promise(resolve => setTimeout(resolve, 50));
329
+ return `处理了项目: ${item}`;
330
+ });
331
+ });
332
+ it('应该正确处理异步批量处理器', () => {
333
+ const buffer = new BatchingBuffer({
334
+ batchProcessor: asyncBatchProcessor,
335
+ bufferSize: 2,
336
+ flushInterval: 1000
337
+ });
338
+ buffer.add('item1');
339
+ buffer.add('item2');
340
+ expect(asyncBatchProcessor).toHaveBeenCalledTimes(1);
341
+ expect(asyncBatchProcessor).toHaveBeenCalledWith(['item1', 'item2']);
342
+ buffer.destroy();
343
+ });
344
+ it('应该正确处理异步单个处理器', () => {
345
+ const buffer = new BatchingBuffer({
346
+ itemProcessor: asyncItemProcessor,
347
+ bufferSize: 2,
348
+ flushInterval: 1000
349
+ });
350
+ buffer.add('item1');
351
+ buffer.add('item2');
352
+ expect(asyncItemProcessor).toHaveBeenCalledTimes(2);
353
+ expect(asyncItemProcessor).toHaveBeenNthCalledWith(1, 'item1');
354
+ expect(asyncItemProcessor).toHaveBeenNthCalledWith(2, 'item2');
355
+ buffer.destroy();
356
+ });
357
+ });
358
+ });
@@ -0,0 +1,3 @@
1
+ export { BatchingBuffer } from './batching-buffer';
2
+ export type { BatchingBufferOptions } from './batching-buffer';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/batching-buffer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -0,0 +1 @@
1
+ export { BatchingBuffer } from './batching-buffer';
package/output/index.d.ts CHANGED
@@ -3,7 +3,10 @@ export * from './event-emitter';
3
3
  export * from './logger';
4
4
  export * from './error';
5
5
  export * from './service';
6
+ export * from './ttl-cache';
6
7
  export * from './lru-cache';
8
+ export * from './ring-cache';
9
+ export * from './batching-buffer';
7
10
  export * from './string';
8
11
  export * from './color';
9
12
  export * from './object';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAG1B,cAAc,iBAAiB,CAAA;AAG/B,cAAc,UAAU,CAAA;AAGxB,cAAc,SAAS,CAAA;AAGvB,cAAc,WAAW,CAAA;AAGzB,cAAc,aAAa,CAAA;AAG3B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AAGvB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAG1B,cAAc,iBAAiB,CAAA;AAG/B,cAAc,UAAU,CAAA;AAGxB,cAAc,SAAS,CAAA;AAGvB,cAAc,WAAW,CAAA;AAGzB,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAG5B,cAAc,mBAAmB,CAAA;AAGjC,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AAGvB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
package/output/index.js CHANGED
@@ -9,7 +9,11 @@ export * from './error';
9
9
  // === 服务管理 ===
10
10
  export * from './service';
11
11
  // === 缓存系统 ===
12
+ export * from './ttl-cache';
12
13
  export * from './lru-cache';
14
+ export * from './ring-cache';
15
+ // === 数据管理 ===
16
+ export * from './batching-buffer';
13
17
  // === 基础工具 ===
14
18
  export * from './string';
15
19
  export * from './color';
@@ -1,5 +1,5 @@
1
- import { LogFormatter } from './formatter';
2
1
  import { LogTransport } from './transport';
2
+ import { LogFormatter } from './formatter';
3
3
  export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
4
4
  export interface LoggerOptions {
5
5
  level?: LogLevel;
@@ -12,8 +12,8 @@ export interface LoggerOptions {
12
12
  }
13
13
  export declare class Logger {
14
14
  private _level;
15
- private transports;
16
15
  private formatter;
16
+ private transports;
17
17
  private print?;
18
18
  constructor(options?: LoggerOptions);
19
19
  private defaultPrint;
@@ -48,7 +48,7 @@ export declare class Logger {
48
48
  /**
49
49
  * 关闭所有 LogTransports
50
50
  */
51
- close(): Promise<void>;
51
+ closeTransports(): Promise<void>;
52
52
  /**
53
53
  * Pino 兼容的 child 方法
54
54
  * 创建一个共享配置的子 logger
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../source/logger/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAA4C,YAAY,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,YAAY,EAAa,MAAM,aAAa,CAAA;AAErD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAE9E,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,oCAAoC;IACpC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAA;IAC3B,aAAa;IACb,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAClD;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,KAAK,CAAC,CAA2C;gBAE7C,OAAO,GAAE,aAAkB;IAYvC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,SAAS;IAKjB;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOnB,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOnB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,MAAM;IAIN;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;IAI3C;;OAEG;IACH,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;IACH,aAAa,IAAI,SAAS,YAAY,EAAE;IAIxC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM;IAkB/E;;OAEG;IACH,IAAI,KAAK,IAAI,QAAQ,CAEpB;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAE3B;CACF;AAED,eAAO,MAAM,MAAM,QAAe,CAAA"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../source/logger/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAa,MAAM,aAAa,CAAA;AACrD,OAAO,EAAuB,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAE9E,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,oCAAoC;IACpC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAA;IAC3B,aAAa;IACb,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAClD;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,KAAK,CAAC,CAA2C;gBAE7C,OAAO,GAAE,aAAkB;IAYvC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,SAAS;IAKjB;;OAEG;IACH,OAAO,CAAC,eAAe;IA2BvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOnB,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOnB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,KAAK,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE;IAOpB,MAAM;IAIN;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;IAI3C;;OAEG;IACH,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;IACH,aAAa,IAAI,SAAS,YAAY,EAAE;IAIxC;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtC;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM;IAkB/E;;OAEG;IACH,IAAI,KAAK,IAAI,QAAQ,CAEpB;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAE3B;CACF;AAED,eAAO,MAAM,MAAM,QAAe,CAAA"}
@@ -1,9 +1,8 @@
1
- // 基础 Logger 实现,支持简单的日志输出和扩展能力
2
1
  import { defaultLogFormatter } from './formatter';
3
2
  export class Logger {
4
3
  _level;
5
- transports;
6
4
  formatter;
5
+ transports;
7
6
  print;
8
7
  constructor(options = {}) {
9
8
  this._level = options.level || 'info';
@@ -143,7 +142,7 @@ export class Logger {
143
142
  /**
144
143
  * 关闭所有 LogTransports
145
144
  */
146
- async close() {
145
+ async closeTransports() {
147
146
  const closePromises = this.transports
148
147
  .map(transport => transport.close?.())
149
148
  .filter(Boolean);
@@ -229,7 +229,7 @@ describe('Logger Transport 集成', () => {
229
229
  close: mockClose2
230
230
  };
231
231
  const logger = new Logger({ transports: [transport1, transport2] });
232
- await logger.close();
232
+ await logger.closeTransports();
233
233
  expect(mockClose1).toHaveBeenCalled();
234
234
  expect(mockClose2).toHaveBeenCalled();
235
235
  });
@@ -0,0 +1,2 @@
1
+ export { TtlCache, type TtlCacheOptions, type TtlCacheStats } from './ttl-cache';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/ttl-cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1 @@
1
+ export { TtlCache } from './ttl-cache';
@@ -0,0 +1,148 @@
1
+ /**
2
+ * TTL 缓存配置选项
3
+ */
4
+ export interface TtlCacheOptions {
5
+ /** 默认 TTL 时间(毫秒),默认为 5 分钟 */
6
+ defaultTtl?: number;
7
+ /** 清理间隔(毫秒),默认为 1 分钟 */
8
+ cleanupInterval?: number;
9
+ /** 最大缓存条目数量,默认无限制 */
10
+ maxSize?: number;
11
+ /** 是否启用自动清理,默认为 true */
12
+ enableCleanup?: boolean;
13
+ }
14
+ /**
15
+ * TTL 缓存统计信息
16
+ */
17
+ export interface TtlCacheStats {
18
+ /** 当前条目数量 */
19
+ size: number;
20
+ /** 最大条目数量限制 */
21
+ maxSize?: number;
22
+ /** 命中次数 */
23
+ hits: number;
24
+ /** 未命中次数 */
25
+ misses: number;
26
+ /** 过期次数 */
27
+ expiredCount: number;
28
+ /** 命中率 */
29
+ hitRate: number;
30
+ }
31
+ /**
32
+ * TTL(Time To Live)缓存实现
33
+ * 支持过期时间、自动清理、统计信息等功能
34
+ *
35
+ * 特点:
36
+ * - 支持为每个条目设置独立的 TTL
37
+ * - 自动定期清理过期条目
38
+ * - 支持最大容量限制
39
+ * - 提供详细的统计信息
40
+ * - 优雅的资源清理机制
41
+ */
42
+ export declare class TtlCache<T> {
43
+ private cache;
44
+ private cleanupTimer?;
45
+ private readonly options;
46
+ private stats;
47
+ constructor(options?: TtlCacheOptions);
48
+ /**
49
+ * 设置缓存项
50
+ * @param key 缓存键
51
+ * @param value 缓存值
52
+ * @param ttl 过期时间(毫秒),默认使用构造函数中的值
53
+ */
54
+ set(key: string, value: T, ttl?: number): void;
55
+ /**
56
+ * 获取缓存项
57
+ * @param key 缓存键
58
+ * @returns 缓存值或 undefined
59
+ */
60
+ get(key: string): T | undefined;
61
+ /**
62
+ * 检查缓存项是否存在且未过期
63
+ * @param key 缓存键
64
+ */
65
+ has(key: string): boolean;
66
+ /**
67
+ * 删除缓存项
68
+ * @param key 缓存键
69
+ * @returns 是否成功删除
70
+ */
71
+ delete(key: string): boolean;
72
+ /**
73
+ * 清空所有缓存
74
+ */
75
+ clear(): void;
76
+ /**
77
+ * 获取当前缓存大小
78
+ */
79
+ get size(): number;
80
+ /**
81
+ * 获取缓存容量
82
+ */
83
+ get capacity(): number;
84
+ /**
85
+ * 获取所有未过期的键
86
+ */
87
+ keys(): string[];
88
+ /**
89
+ * 获取所有未过期的值
90
+ */
91
+ values(): T[];
92
+ /**
93
+ * 获取所有未过期的键值对
94
+ */
95
+ entries(): Array<[string, T]>;
96
+ /**
97
+ * 获取或设置缓存(如果不存在)
98
+ * @param key 缓存键
99
+ * @param factory 工厂函数,用于生成缓存值
100
+ * @param ttl 过期时间(毫秒)
101
+ */
102
+ getOrSet(key: string, factory: () => Promise<T>, ttl?: number): Promise<T>;
103
+ getOrSet(key: string, factory: () => T, ttl?: number): T;
104
+ /**
105
+ * 获取缓存统计信息
106
+ */
107
+ getStats(): TtlCacheStats;
108
+ /**
109
+ * 重置统计信息
110
+ */
111
+ resetStats(): void;
112
+ /**
113
+ * 手动清理过期缓存
114
+ * @returns 清理的条目数量
115
+ */
116
+ cleanup(): number;
117
+ /**
118
+ * 获取指定键的剩余 TTL 时间
119
+ * @param key 缓存键
120
+ * @returns 剩余时间(毫秒),如果不存在或已过期返回 -1
121
+ */
122
+ getTtl(key: string): number;
123
+ /**
124
+ * 销毁缓存实例,清理所有资源
125
+ */
126
+ destroy(): void;
127
+ /**
128
+ * 启动定期清理过期缓存
129
+ */
130
+ private startCleanup;
131
+ /**
132
+ * 停止定期清理
133
+ */
134
+ private stopCleanup;
135
+ /**
136
+ * 驱逐最旧的缓存条目
137
+ */
138
+ private evictOldest;
139
+ /**
140
+ * 更新统计信息
141
+ */
142
+ private updateStats;
143
+ /**
144
+ * 更新命中率
145
+ */
146
+ private updateHitRate;
147
+ }
148
+ //# sourceMappingURL=ttl-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ttl-cache.d.ts","sourceRoot":"","sources":["../../source/ttl-cache/ttl-cache.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wBAAwB;IACxB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wBAAwB;IACxB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,WAAW;IACX,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU;IACV,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,YAAY,CAAC,CAAK;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,KAAK,CAAe;gBAEhB,OAAO,GAAE,eAAoB;IAiCzC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IA0B9C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAuB/B;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiBzB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQ5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;IAahB;;OAEG;IACH,MAAM,IAAI,CAAC,EAAE;IAab;;OAEG;IACH,OAAO,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAa7B;;;;;OAKG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC;IAoBxD;;OAEG;IACH,QAAQ,IAAI,aAAa;IAKzB;;OAEG;IACH,UAAU,IAAI,IAAI;IAWlB;;;OAGG;IACH,OAAO,IAAI,MAAM;IAmBjB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAc3B;;OAEG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,OAAO,CAAC,aAAa;CAItB"}