@taicode/common-base 1.7.1 → 1.7.3

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 (45) hide show
  1. package/output/batching-buffer/batching-buffer.d.ts +10 -17
  2. package/output/batching-buffer/batching-buffer.d.ts.map +1 -1
  3. package/output/batching-buffer/batching-buffer.js +37 -46
  4. package/output/batching-buffer/batching-buffer.test.js +8 -161
  5. package/output/events/disposer.d.ts +6 -0
  6. package/output/events/disposer.d.ts.map +1 -0
  7. package/output/events/disposer.js +19 -0
  8. package/output/events/disposer.test.d.ts +2 -0
  9. package/output/events/disposer.test.d.ts.map +1 -0
  10. package/output/events/disposer.test.js +192 -0
  11. package/output/events/event-emitter.d.ts +33 -0
  12. package/output/events/event-emitter.d.ts.map +1 -0
  13. package/output/events/event-emitter.js +66 -0
  14. package/output/events/event-emitter.test.d.ts +2 -0
  15. package/output/events/event-emitter.test.d.ts.map +1 -0
  16. package/output/events/event-emitter.test.js +213 -0
  17. package/output/events/index.d.ts +3 -0
  18. package/output/events/index.d.ts.map +1 -0
  19. package/output/events/index.js +3 -0
  20. package/output/flow-queue/flow-queue.d.ts +418 -0
  21. package/output/flow-queue/flow-queue.d.ts.map +1 -0
  22. package/output/flow-queue/flow-queue.js +582 -0
  23. package/output/flow-queue/flow-queue.test.d.ts +2 -0
  24. package/output/flow-queue/flow-queue.test.d.ts.map +1 -0
  25. package/output/flow-queue/flow-queue.test.js +1033 -0
  26. package/output/flow-queue/index.d.ts +3 -0
  27. package/output/flow-queue/index.d.ts.map +1 -0
  28. package/output/flow-queue/index.js +3 -0
  29. package/output/index.d.ts +2 -0
  30. package/output/index.d.ts.map +1 -1
  31. package/output/index.js +2 -0
  32. package/output/logger/logger.d.ts +3 -3
  33. package/output/logger/logger.d.ts.map +1 -1
  34. package/output/logger/logger.js +2 -3
  35. package/output/logger/logger.test.js +1 -1
  36. package/output/ttl-cache/index.d.ts +2 -0
  37. package/output/ttl-cache/index.d.ts.map +1 -0
  38. package/output/ttl-cache/index.js +1 -0
  39. package/output/ttl-cache/ttl-cache.d.ts +148 -0
  40. package/output/ttl-cache/ttl-cache.d.ts.map +1 -0
  41. package/output/ttl-cache/ttl-cache.js +313 -0
  42. package/output/ttl-cache/ttl-cache.test.d.ts +2 -0
  43. package/output/ttl-cache/ttl-cache.test.d.ts.map +1 -0
  44. package/output/ttl-cache/ttl-cache.test.js +222 -0
  45. package/package.json +1 -1
@@ -0,0 +1,3 @@
1
+ export { FlowQueue } from './flow-queue';
2
+ export type { FlowQueueOptions, FlowQueueProcessor, FlowQueueRetryStrategy, FlowQueueRetryConfig, FlowQueueDelayConfig, FlowQueueOnGenerate } from './flow-queue';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/flow-queue/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,cAAc,CAAA"}
@@ -0,0 +1,3 @@
1
+ // Flow Queue 模块入口
2
+ // 提供流式处理队列功能,支持重试、延迟等高级特性
3
+ export { FlowQueue } from './flow-queue';
package/output/index.d.ts CHANGED
@@ -3,6 +3,7 @@ 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';
7
8
  export * from './ring-cache';
8
9
  export * from './batching-buffer';
@@ -13,4 +14,5 @@ export * from './number';
13
14
  export * from './catch';
14
15
  export * from './debounce';
15
16
  export * from './throttle';
17
+ export * from './flow-queue';
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -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;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"}
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;AAE1B,cAAc,cAAc,CAAA"}
package/output/index.js CHANGED
@@ -9,6 +9,7 @@ export * from './error';
9
9
  // === 服务管理 ===
10
10
  export * from './service';
11
11
  // === 缓存系统 ===
12
+ export * from './ttl-cache';
12
13
  export * from './lru-cache';
13
14
  export * from './ring-cache';
14
15
  // === 数据管理 ===
@@ -22,3 +23,4 @@ export * from './catch';
22
23
  // === 函数增强 ===
23
24
  export * from './debounce';
24
25
  export * from './throttle';
26
+ export * from './flow-queue';
@@ -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"}
@@ -0,0 +1,313 @@
1
+ /**
2
+ * TTL(Time To Live)缓存实现
3
+ * 支持过期时间、自动清理、统计信息等功能
4
+ *
5
+ * 特点:
6
+ * - 支持为每个条目设置独立的 TTL
7
+ * - 自动定期清理过期条目
8
+ * - 支持最大容量限制
9
+ * - 提供详细的统计信息
10
+ * - 优雅的资源清理机制
11
+ */
12
+ export class TtlCache {
13
+ cache;
14
+ cleanupTimer;
15
+ options;
16
+ stats;
17
+ constructor(options = {}) {
18
+ this.options = {
19
+ defaultTtl: options.defaultTtl ?? 5 * 60 * 1000, // 默认5分钟
20
+ cleanupInterval: options.cleanupInterval ?? 60 * 1000, // 默认1分钟清理一次
21
+ maxSize: options.maxSize ?? Infinity,
22
+ enableCleanup: options.enableCleanup ?? true
23
+ };
24
+ if (this.options.defaultTtl <= 0) {
25
+ throw new Error('defaultTtl must be greater than 0');
26
+ }
27
+ if (this.options.cleanupInterval <= 0) {
28
+ throw new Error('cleanupInterval must be greater than 0');
29
+ }
30
+ if (this.options.maxSize <= 0) {
31
+ throw new Error('maxSize must be greater than 0');
32
+ }
33
+ this.cache = new Map();
34
+ this.stats = {
35
+ size: 0,
36
+ maxSize: this.options.maxSize === Infinity ? undefined : this.options.maxSize,
37
+ hits: 0,
38
+ misses: 0,
39
+ expiredCount: 0,
40
+ hitRate: 0
41
+ };
42
+ if (this.options.enableCleanup) {
43
+ this.startCleanup();
44
+ }
45
+ }
46
+ /**
47
+ * 设置缓存项
48
+ * @param key 缓存键
49
+ * @param value 缓存值
50
+ * @param ttl 过期时间(毫秒),默认使用构造函数中的值
51
+ */
52
+ set(key, value, ttl) {
53
+ const now = Date.now();
54
+ const actualTtl = ttl ?? this.options.defaultTtl;
55
+ const expireAt = now + actualTtl;
56
+ // 检查容量限制
57
+ if (!this.cache.has(key) && this.cache.size >= this.options.maxSize) {
58
+ // 尝试清理过期条目
59
+ this.cleanup();
60
+ // 如果清理后仍然超过容量,删除最旧的条目
61
+ if (this.cache.size >= this.options.maxSize) {
62
+ this.evictOldest();
63
+ }
64
+ }
65
+ const entry = {
66
+ value,
67
+ expireAt,
68
+ createdAt: now
69
+ };
70
+ this.cache.set(key, entry);
71
+ this.updateStats();
72
+ }
73
+ /**
74
+ * 获取缓存项
75
+ * @param key 缓存键
76
+ * @returns 缓存值或 undefined
77
+ */
78
+ get(key) {
79
+ const entry = this.cache.get(key);
80
+ if (!entry) {
81
+ this.stats.misses++;
82
+ this.updateHitRate();
83
+ return undefined;
84
+ }
85
+ const now = Date.now();
86
+ if (now > entry.expireAt) {
87
+ this.cache.delete(key);
88
+ this.stats.expiredCount++;
89
+ this.stats.misses++;
90
+ this.updateStats();
91
+ return undefined;
92
+ }
93
+ this.stats.hits++;
94
+ this.updateHitRate();
95
+ return entry.value;
96
+ }
97
+ /**
98
+ * 检查缓存项是否存在且未过期
99
+ * @param key 缓存键
100
+ */
101
+ has(key) {
102
+ const entry = this.cache.get(key);
103
+ if (!entry) {
104
+ return false;
105
+ }
106
+ const now = Date.now();
107
+ if (now > entry.expireAt) {
108
+ this.cache.delete(key);
109
+ this.stats.expiredCount++;
110
+ this.updateStats();
111
+ return false;
112
+ }
113
+ return true;
114
+ }
115
+ /**
116
+ * 删除缓存项
117
+ * @param key 缓存键
118
+ * @returns 是否成功删除
119
+ */
120
+ delete(key) {
121
+ const result = this.cache.delete(key);
122
+ if (result) {
123
+ this.updateStats();
124
+ }
125
+ return result;
126
+ }
127
+ /**
128
+ * 清空所有缓存
129
+ */
130
+ clear() {
131
+ this.cache.clear();
132
+ this.stats.expiredCount = 0;
133
+ this.updateStats();
134
+ }
135
+ /**
136
+ * 获取当前缓存大小
137
+ */
138
+ get size() {
139
+ return this.cache.size;
140
+ }
141
+ /**
142
+ * 获取缓存容量
143
+ */
144
+ get capacity() {
145
+ return this.options.maxSize;
146
+ }
147
+ /**
148
+ * 获取所有未过期的键
149
+ */
150
+ keys() {
151
+ const keys = [];
152
+ const now = Date.now();
153
+ for (const [key, entry] of this.cache.entries()) {
154
+ if (now <= entry.expireAt) {
155
+ keys.push(key);
156
+ }
157
+ }
158
+ return keys;
159
+ }
160
+ /**
161
+ * 获取所有未过期的值
162
+ */
163
+ values() {
164
+ const values = [];
165
+ const now = Date.now();
166
+ for (const entry of this.cache.values()) {
167
+ if (now <= entry.expireAt) {
168
+ values.push(entry.value);
169
+ }
170
+ }
171
+ return values;
172
+ }
173
+ /**
174
+ * 获取所有未过期的键值对
175
+ */
176
+ entries() {
177
+ const entries = [];
178
+ const now = Date.now();
179
+ for (const [key, entry] of this.cache.entries()) {
180
+ if (now <= entry.expireAt) {
181
+ entries.push([key, entry.value]);
182
+ }
183
+ }
184
+ return entries;
185
+ }
186
+ getOrSet(key, factory, ttl) {
187
+ const cached = this.get(key);
188
+ if (cached !== undefined) {
189
+ return cached;
190
+ }
191
+ const result = factory();
192
+ if (result instanceof Promise) {
193
+ return result.then(value => {
194
+ this.set(key, value, ttl);
195
+ return value;
196
+ });
197
+ }
198
+ this.set(key, result, ttl);
199
+ return result;
200
+ }
201
+ /**
202
+ * 获取缓存统计信息
203
+ */
204
+ getStats() {
205
+ this.updateStats();
206
+ return { ...this.stats };
207
+ }
208
+ /**
209
+ * 重置统计信息
210
+ */
211
+ resetStats() {
212
+ this.stats = {
213
+ size: this.cache.size,
214
+ maxSize: this.options.maxSize === Infinity ? undefined : this.options.maxSize,
215
+ hits: 0,
216
+ misses: 0,
217
+ expiredCount: 0,
218
+ hitRate: 0
219
+ };
220
+ }
221
+ /**
222
+ * 手动清理过期缓存
223
+ * @returns 清理的条目数量
224
+ */
225
+ cleanup() {
226
+ const now = Date.now();
227
+ let expiredCount = 0;
228
+ for (const [key, entry] of this.cache.entries()) {
229
+ if (now > entry.expireAt) {
230
+ this.cache.delete(key);
231
+ expiredCount++;
232
+ }
233
+ }
234
+ if (expiredCount > 0) {
235
+ this.stats.expiredCount += expiredCount;
236
+ this.updateStats();
237
+ }
238
+ return expiredCount;
239
+ }
240
+ /**
241
+ * 获取指定键的剩余 TTL 时间
242
+ * @param key 缓存键
243
+ * @returns 剩余时间(毫秒),如果不存在或已过期返回 -1
244
+ */
245
+ getTtl(key) {
246
+ const entry = this.cache.get(key);
247
+ if (!entry) {
248
+ return -1;
249
+ }
250
+ const now = Date.now();
251
+ if (now > entry.expireAt) {
252
+ return -1;
253
+ }
254
+ return entry.expireAt - now;
255
+ }
256
+ /**
257
+ * 销毁缓存实例,清理所有资源
258
+ */
259
+ destroy() {
260
+ this.clear();
261
+ this.stopCleanup();
262
+ }
263
+ /**
264
+ * 启动定期清理过期缓存
265
+ */
266
+ startCleanup() {
267
+ if (this.cleanupTimer) {
268
+ return;
269
+ }
270
+ this.cleanupTimer = setInterval(() => {
271
+ this.cleanup();
272
+ }, this.options.cleanupInterval);
273
+ }
274
+ /**
275
+ * 停止定期清理
276
+ */
277
+ stopCleanup() {
278
+ if (this.cleanupTimer) {
279
+ clearInterval(this.cleanupTimer);
280
+ this.cleanupTimer = undefined;
281
+ }
282
+ }
283
+ /**
284
+ * 驱逐最旧的缓存条目
285
+ */
286
+ evictOldest() {
287
+ let oldestKey;
288
+ let oldestTime = Infinity;
289
+ for (const [key, entry] of this.cache.entries()) {
290
+ if (entry.createdAt < oldestTime) {
291
+ oldestTime = entry.createdAt;
292
+ oldestKey = key;
293
+ }
294
+ }
295
+ if (oldestKey) {
296
+ this.cache.delete(oldestKey);
297
+ }
298
+ }
299
+ /**
300
+ * 更新统计信息
301
+ */
302
+ updateStats() {
303
+ this.stats.size = this.cache.size;
304
+ this.updateHitRate();
305
+ }
306
+ /**
307
+ * 更新命中率
308
+ */
309
+ updateHitRate() {
310
+ const total = this.stats.hits + this.stats.misses;
311
+ this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
312
+ }
313
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ttl-cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ttl-cache.test.d.ts","sourceRoot":"","sources":["../../source/ttl-cache/ttl-cache.test.ts"],"names":[],"mappings":""}