@lytjs/cache 6.8.0 → 6.9.0

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ MemoryCache: () => MemoryCache,
24
+ MultiLayerCache: () => MultiLayerCache,
25
+ createCache: () => createCache,
26
+ getDefaultCache: () => getDefaultCache
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var DEFAULT_TTL = 36e5;
30
+ var MAX_SIZE = 100 * 1024 * 1024;
31
+ var MemoryCache = class {
32
+ constructor(options = {}) {
33
+ this.cache = /* @__PURE__ */ new Map();
34
+ this.tagIndex = /* @__PURE__ */ new Map();
35
+ this.stats = {
36
+ size: 0,
37
+ totalSize: 0,
38
+ hits: 0,
39
+ misses: 0,
40
+ hitRate: 0
41
+ };
42
+ this.defaultTTL = options.ttl ?? DEFAULT_TTL;
43
+ this.maxSize = options.maxSize ?? MAX_SIZE;
44
+ }
45
+ async get(key) {
46
+ const entry = this.cache.get(key);
47
+ if (!entry) {
48
+ this.stats.misses++;
49
+ this.updateHitRate();
50
+ return void 0;
51
+ }
52
+ const now = Date.now();
53
+ if (entry.expiresAt < now) {
54
+ this.delete(key);
55
+ this.stats.misses++;
56
+ this.updateHitRate();
57
+ return void 0;
58
+ }
59
+ this.stats.hits++;
60
+ this.updateHitRate();
61
+ return entry.value;
62
+ }
63
+ async set(key, value, options = {}) {
64
+ const now = Date.now();
65
+ const ttl = options.ttl ?? this.defaultTTL;
66
+ const tags = options.tags ?? [];
67
+ const size = this.calculateSize(value);
68
+ if (this.stats.totalSize + size > this.maxSize) {
69
+ this.evictOldest();
70
+ }
71
+ const entry = {
72
+ value,
73
+ createdAt: now,
74
+ expiresAt: now + ttl,
75
+ tags,
76
+ size
77
+ };
78
+ this.cache.set(key, entry);
79
+ for (const tag of tags) {
80
+ if (!this.tagIndex.has(tag)) {
81
+ this.tagIndex.set(tag, /* @__PURE__ */ new Set());
82
+ }
83
+ this.tagIndex.get(tag).add(key);
84
+ }
85
+ this.stats.size = this.cache.size;
86
+ this.stats.totalSize += size;
87
+ }
88
+ async delete(key) {
89
+ const entry = this.cache.get(key);
90
+ if (!entry) {
91
+ return false;
92
+ }
93
+ for (const tag of entry.tags) {
94
+ const tagKeys = this.tagIndex.get(tag);
95
+ if (tagKeys) {
96
+ tagKeys.delete(key);
97
+ if (tagKeys.size === 0) {
98
+ this.tagIndex.delete(tag);
99
+ }
100
+ }
101
+ }
102
+ if (entry.size) {
103
+ this.stats.totalSize -= entry.size;
104
+ }
105
+ this.stats.size = this.cache.size - 1;
106
+ return this.cache.delete(key);
107
+ }
108
+ async has(key) {
109
+ const entry = this.cache.get(key);
110
+ if (!entry) {
111
+ return false;
112
+ }
113
+ if (Date.now() > entry.expiresAt) {
114
+ await this.delete(key);
115
+ return false;
116
+ }
117
+ return true;
118
+ }
119
+ async clear() {
120
+ this.cache.clear();
121
+ this.tagIndex.clear();
122
+ this.stats = {
123
+ size: 0,
124
+ totalSize: 0,
125
+ hits: 0,
126
+ misses: 0,
127
+ hitRate: 0
128
+ };
129
+ }
130
+ async invalidateTag(tag) {
131
+ const keys = this.tagIndex.get(tag);
132
+ if (!keys) {
133
+ return;
134
+ }
135
+ for (const key of keys) {
136
+ await this.delete(key);
137
+ }
138
+ }
139
+ async invalidateTags(tags) {
140
+ for (const tag of tags) {
141
+ await this.invalidateTag(tag);
142
+ }
143
+ }
144
+ async getStats() {
145
+ return { ...this.stats };
146
+ }
147
+ /**
148
+ * 计算值的大小(字节)
149
+ */
150
+ calculateSize(value) {
151
+ try {
152
+ const str = JSON.stringify(value);
153
+ return new TextEncoder().encode(str).length;
154
+ } catch {
155
+ return 100;
156
+ }
157
+ }
158
+ /**
159
+ * 淘汰最旧的条目
160
+ */
161
+ evictOldest() {
162
+ let oldestKey = null;
163
+ let oldestTime = Infinity;
164
+ for (const [key, entry] of this.cache) {
165
+ if (entry.createdAt < oldestTime) {
166
+ oldestTime = entry.createdAt;
167
+ oldestKey = key;
168
+ }
169
+ }
170
+ if (oldestKey) {
171
+ this.delete(oldestKey);
172
+ }
173
+ }
174
+ /**
175
+ * 更新命中率
176
+ */
177
+ updateHitRate() {
178
+ const total = this.stats.hits + this.stats.misses;
179
+ this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
180
+ }
181
+ };
182
+ var MultiLayerCache = class {
183
+ constructor(config = {}) {
184
+ this.layers = [];
185
+ if (config.memory !== false) {
186
+ const memoryOptions = typeof config.memory === "object" ? config.memory : void 0;
187
+ this.layers.push(new MemoryCache(memoryOptions));
188
+ }
189
+ if (config.redis) {
190
+ }
191
+ if (config.http) {
192
+ }
193
+ }
194
+ async get(key) {
195
+ for (const layer of this.layers) {
196
+ const value = await layer.get(key);
197
+ if (value !== void 0) {
198
+ for (let i = 0; i < this.layers.indexOf(layer); i++) {
199
+ await this.layers[i].set(key, value);
200
+ }
201
+ return value;
202
+ }
203
+ }
204
+ return void 0;
205
+ }
206
+ async set(key, value, options) {
207
+ for (const layer of this.layers) {
208
+ await layer.set(key, value, options);
209
+ }
210
+ }
211
+ async delete(key) {
212
+ let result = false;
213
+ for (const layer of this.layers) {
214
+ const layerResult = await layer.delete(key);
215
+ if (layerResult) {
216
+ result = true;
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+ async has(key) {
222
+ for (const layer of this.layers) {
223
+ if (await layer.has(key)) {
224
+ return true;
225
+ }
226
+ }
227
+ return false;
228
+ }
229
+ async clear() {
230
+ for (const layer of this.layers) {
231
+ await layer.clear();
232
+ }
233
+ }
234
+ async invalidateTag(tag) {
235
+ for (const layer of this.layers) {
236
+ await layer.invalidateTag(tag);
237
+ }
238
+ }
239
+ async invalidateTags(tags) {
240
+ for (const tag of tags) {
241
+ await this.invalidateTag(tag);
242
+ }
243
+ }
244
+ async getStats() {
245
+ const statsList = await Promise.all(this.layers.map((layer) => layer.getStats()));
246
+ const merged = {
247
+ size: statsList.reduce((sum, stat) => sum + stat.size, 0),
248
+ totalSize: statsList.reduce((sum, stat) => sum + stat.totalSize, 0),
249
+ hits: statsList.reduce((sum, stat) => sum + stat.hits, 0),
250
+ misses: statsList.reduce((sum, stat) => sum + stat.misses, 0),
251
+ hitRate: 0
252
+ };
253
+ const total = merged.hits + merged.misses;
254
+ merged.hitRate = total > 0 ? merged.hits / total : 0;
255
+ return merged;
256
+ }
257
+ };
258
+ function createCache(options) {
259
+ if (options?.type === "multi") {
260
+ return new MultiLayerCache(options.config);
261
+ }
262
+ return new MemoryCache(options?.config);
263
+ }
264
+ var defaultCache = null;
265
+ function getDefaultCache() {
266
+ if (!defaultCache) {
267
+ defaultCache = new MemoryCache();
268
+ }
269
+ return defaultCache;
270
+ }
271
+ // Annotate the CommonJS export names for ESM import in node:
272
+ 0 && (module.exports = {
273
+ MemoryCache,
274
+ MultiLayerCache,
275
+ createCache,
276
+ getDefaultCache
277
+ });
278
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @lytjs/cache - 统一缓存系统入口\n *\n * 提供多层缓存(Memory → Redis → HTTP)支持,\n * 包含缓存标签、TTL、统计等功能。\n */\n\n/**\n * 缓存条目接口\n */\nexport interface CacheEntry<T = unknown> {\n /** 缓存值 */\n value: T;\n /** 创建时间戳 */\n createdAt: number;\n /** 过期时间戳 */\n expiresAt: number;\n /** 缓存标签 */\n tags: string[];\n /** 数据大小(字节) */\n size?: number;\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheOptions {\n /** 生存时间(毫秒) */\n ttl?: number;\n /** 缓存标签 */\n tags?: string[];\n /** 重新验证时间(毫秒) */\n revalidate?: number;\n /** 最大大小(字节) */\n maxSize?: number;\n}\n\n/**\n * 统一缓存接口\n */\nexport interface Cache {\n /**\n * 获取缓存值\n */\n get<T>(key: string): Promise<T | undefined>;\n\n /**\n * 设置缓存值\n */\n set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;\n\n /**\n * 删除缓存值\n */\n delete(key: string): Promise<boolean>;\n\n /**\n * 检查缓存是否存在\n */\n has(key: string): Promise<boolean>;\n\n /**\n * 清除所有缓存\n */\n clear(): Promise<void>;\n\n /**\n * 按标签无效化缓存\n */\n invalidateTag(tag: string): Promise<void>;\n\n /**\n * 批量按标签无效化缓存\n */\n invalidateTags(tags: string[]): Promise<void>;\n\n /**\n * 获取缓存统计信息\n */\n getStats(): Promise<CacheStats>;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStats {\n /** 键的数量 */\n size: number;\n /** 总大小(字节) */\n totalSize: number;\n /** 命中次数 */\n hits: number;\n /** 未命中次数 */\n misses: number;\n /** 命中率 */\n hitRate: number;\n}\n\n/**\n * 多层缓存配置\n */\nexport interface MultiLayerCacheConfig {\n /** 内存缓存配置 */\n memory?: CacheOptions | boolean;\n /** Redis 缓存配置 */\n redis?: CacheOptions & {\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n };\n /** HTTP 缓存配置 */\n http?: CacheOptions & {\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * 数据预取上下文\n */\nexport interface PrefetchContext {\n /** 路径 */\n path?: string;\n /** 参数 */\n params?: Record<string, string>;\n /** 查询参数 */\n query?: Record<string, string>;\n}\n\n/**\n * 预取结果\n */\nexport interface PrefetchResult<T = unknown> {\n /** 预取的数据 */\n data: T;\n /** 过期时间戳 */\n expiresAt?: number;\n /** 缓存标签 */\n tags?: string[];\n}\n\nconst DEFAULT_TTL = 3600000; // 1 小时\nconst MAX_SIZE = 100 * 1024 * 1024; // 100 MB\n\n/**\n * 内存缓存实现\n */\nexport class MemoryCache implements Cache {\n private cache: Map<string, CacheEntry> = new Map();\n private tagIndex: Map<string, Set<string>> = new Map();\n private stats: CacheStats = {\n size: 0,\n totalSize: 0,\n hits: 0,\n misses: 0,\n hitRate: 0,\n };\n private defaultTTL: number;\n private maxSize: number;\n\n constructor(options: CacheOptions = {}) {\n this.defaultTTL = options.ttl ?? DEFAULT_TTL;\n this.maxSize = options.maxSize ?? MAX_SIZE;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const entry = this.cache.get(key);\n if (!entry) {\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n const now = Date.now();\n if (entry.expiresAt < now) {\n this.delete(key);\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n this.stats.hits++;\n this.updateHitRate();\n return entry.value as T;\n }\n\n async set<T>(key: string, value: T, options: CacheOptions = {}): Promise<void> {\n const now = Date.now();\n const ttl = options.ttl ?? this.defaultTTL;\n const tags = options.tags ?? [];\n const size = this.calculateSize(value);\n\n // 检查是否超出最大大小\n if (this.stats.totalSize + size > this.maxSize) {\n this.evictOldest();\n }\n\n const entry: CacheEntry = {\n value,\n createdAt: now,\n expiresAt: now + ttl,\n tags,\n size,\n };\n\n // 更新缓存\n this.cache.set(key, entry);\n\n // 更新标签索引\n for (const tag of tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(key);\n }\n\n // 更新统计\n this.stats.size = this.cache.size;\n this.stats.totalSize += size;\n }\n\n async delete(key: string): Promise<boolean> {\n const entry = this.cache.get(key);\n if (!entry) {\n return false;\n }\n\n // 从标签索引中删除\n for (const tag of entry.tags) {\n const tagKeys = this.tagIndex.get(tag);\n if (tagKeys) {\n tagKeys.delete(key);\n if (tagKeys.size === 0) {\n this.tagIndex.delete(tag);\n }\n }\n }\n\n // 更新统计\n if (entry.size) {\n this.stats.totalSize -= entry.size;\n }\n this.stats.size = this.cache.size - 1;\n\n return this.cache.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n const entry = this.cache.get(key);\n if (!entry) {\n return false;\n }\n if (Date.now() > entry.expiresAt) {\n await this.delete(key);\n return false;\n }\n return true;\n }\n\n async clear(): Promise<void> {\n this.cache.clear();\n this.tagIndex.clear();\n this.stats = {\n size: 0,\n totalSize: 0,\n hits: 0,\n misses: 0,\n hitRate: 0,\n };\n }\n\n async invalidateTag(tag: string): Promise<void> {\n const keys = this.tagIndex.get(tag);\n if (!keys) {\n return;\n }\n\n for (const key of keys) {\n await this.delete(key);\n }\n }\n\n async invalidateTags(tags: string[]): Promise<void> {\n for (const tag of tags) {\n await this.invalidateTag(tag);\n }\n }\n\n async getStats(): Promise<CacheStats> {\n return { ...this.stats };\n }\n\n /**\n * 计算值的大小(字节)\n */\n private calculateSize(value: unknown): number {\n try {\n const str = JSON.stringify(value);\n return new TextEncoder().encode(str).length;\n } catch {\n return 100; // 估算大小\n }\n }\n\n /**\n * 淘汰最旧的条目\n */\n private evictOldest(): void {\n let oldestKey: string | null = null;\n let oldestTime = Infinity;\n\n for (const [key, entry] of this.cache) {\n if (entry.createdAt < oldestTime) {\n oldestTime = entry.createdAt;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.delete(oldestKey);\n }\n }\n\n /**\n * 更新命中率\n */\n private updateHitRate(): void {\n const total = this.stats.hits + this.stats.misses;\n this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;\n }\n}\n\n/**\n * 多层缓存实现(Memory → Redis → HTTP)\n */\nexport class MultiLayerCache implements Cache {\n private layers: Cache[];\n\n constructor(config: MultiLayerCacheConfig = {}) {\n this.layers = [];\n\n // 内存缓存始终作为第一层\n if (config.memory !== false) {\n const memoryOptions = typeof config.memory === 'object' ? config.memory : undefined;\n this.layers.push(new MemoryCache(memoryOptions));\n }\n\n // Redis 缓存作为第二层(可选)\n if (config.redis) {\n // Redis 缓存可以在实际环境配置\n // 这里我们预留接口\n }\n\n // HTTP 缓存作为第三层(可选)\n if (config.http) {\n // HTTP 缓存可以在实际环境配置\n }\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n for (const layer of this.layers) {\n const value = await layer.get<T>(key);\n if (value !== undefined) {\n // 回写上层缓存\n for (let i = 0; i < this.layers.indexOf(layer); i++) {\n await this.layers[i].set(key, value);\n }\n return value;\n }\n }\n return undefined;\n }\n\n async set<T>(key: string, value: T, options?: CacheOptions): Promise<void> {\n // 写入所有层\n for (const layer of this.layers) {\n await layer.set(key, value, options);\n }\n }\n\n async delete(key: string): Promise<boolean> {\n let result = false;\n for (const layer of this.layers) {\n const layerResult = await layer.delete(key);\n if (layerResult) {\n result = true;\n }\n }\n return result;\n }\n\n async has(key: string): Promise<boolean> {\n for (const layer of this.layers) {\n if (await layer.has(key)) {\n return true;\n }\n }\n return false;\n }\n\n async clear(): Promise<void> {\n for (const layer of this.layers) {\n await layer.clear();\n }\n }\n\n async invalidateTag(tag: string): Promise<void> {\n for (const layer of this.layers) {\n await layer.invalidateTag(tag);\n }\n }\n\n async invalidateTags(tags: string[]): Promise<void> {\n for (const tag of tags) {\n await this.invalidateTag(tag);\n }\n }\n\n async getStats(): Promise<CacheStats> {\n // 合并所有层的统计信息\n const statsList = await Promise.all(this.layers.map((layer) => layer.getStats()));\n const merged: CacheStats = {\n size: statsList.reduce((sum, stat) => sum + stat.size, 0),\n totalSize: statsList.reduce((sum, stat) => sum + stat.totalSize, 0),\n hits: statsList.reduce((sum, stat) => sum + stat.hits, 0),\n misses: statsList.reduce((sum, stat) => sum + stat.misses, 0),\n hitRate: 0,\n };\n const total = merged.hits + merged.misses;\n merged.hitRate = total > 0 ? merged.hits / total : 0;\n return merged;\n }\n}\n\n/**\n * 创建默认缓存实例\n */\nexport function createCache(options?: {\n type?: 'memory' | 'multi';\n config?: CacheOptions | MultiLayerCacheConfig;\n}) {\n if (options?.type === 'multi') {\n return new MultiLayerCache(options.config as MultiLayerCacheConfig);\n }\n return new MemoryCache(options?.config as CacheOptions);\n}\n\n// 默认实例\nlet defaultCache: MemoryCache | null = null;\n\nexport function getDefaultCache() {\n if (!defaultCache) {\n defaultCache = new MemoryCache();\n }\n return defaultCache;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * @lytjs/cache - 统一缓存系统入口
3
+ *
4
+ * 提供多层缓存(Memory → Redis → HTTP)支持,
5
+ * 包含缓存标签、TTL、统计等功能。
6
+ */
7
+ /**
8
+ * 缓存条目接口
9
+ */
10
+ interface CacheEntry<T = unknown> {
11
+ /** 缓存值 */
12
+ value: T;
13
+ /** 创建时间戳 */
14
+ createdAt: number;
15
+ /** 过期时间戳 */
16
+ expiresAt: number;
17
+ /** 缓存标签 */
18
+ tags: string[];
19
+ /** 数据大小(字节) */
20
+ size?: number;
21
+ }
22
+ /**
23
+ * 缓存配置选项
24
+ */
25
+ interface CacheOptions {
26
+ /** 生存时间(毫秒) */
27
+ ttl?: number;
28
+ /** 缓存标签 */
29
+ tags?: string[];
30
+ /** 重新验证时间(毫秒) */
31
+ revalidate?: number;
32
+ /** 最大大小(字节) */
33
+ maxSize?: number;
34
+ }
35
+ /**
36
+ * 统一缓存接口
37
+ */
38
+ interface Cache {
39
+ /**
40
+ * 获取缓存值
41
+ */
42
+ get<T>(key: string): Promise<T | undefined>;
43
+ /**
44
+ * 设置缓存值
45
+ */
46
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
47
+ /**
48
+ * 删除缓存值
49
+ */
50
+ delete(key: string): Promise<boolean>;
51
+ /**
52
+ * 检查缓存是否存在
53
+ */
54
+ has(key: string): Promise<boolean>;
55
+ /**
56
+ * 清除所有缓存
57
+ */
58
+ clear(): Promise<void>;
59
+ /**
60
+ * 按标签无效化缓存
61
+ */
62
+ invalidateTag(tag: string): Promise<void>;
63
+ /**
64
+ * 批量按标签无效化缓存
65
+ */
66
+ invalidateTags(tags: string[]): Promise<void>;
67
+ /**
68
+ * 获取缓存统计信息
69
+ */
70
+ getStats(): Promise<CacheStats>;
71
+ }
72
+ /**
73
+ * 缓存统计信息
74
+ */
75
+ interface CacheStats {
76
+ /** 键的数量 */
77
+ size: number;
78
+ /** 总大小(字节) */
79
+ totalSize: number;
80
+ /** 命中次数 */
81
+ hits: number;
82
+ /** 未命中次数 */
83
+ misses: number;
84
+ /** 命中率 */
85
+ hitRate: number;
86
+ }
87
+ /**
88
+ * 多层缓存配置
89
+ */
90
+ interface MultiLayerCacheConfig {
91
+ /** 内存缓存配置 */
92
+ memory?: CacheOptions | boolean;
93
+ /** Redis 缓存配置 */
94
+ redis?: CacheOptions & {
95
+ host?: string;
96
+ port?: number;
97
+ password?: string;
98
+ db?: number;
99
+ };
100
+ /** HTTP 缓存配置 */
101
+ http?: CacheOptions & {
102
+ baseUrl?: string;
103
+ headers?: Record<string, string>;
104
+ };
105
+ }
106
+ /**
107
+ * 数据预取上下文
108
+ */
109
+ interface PrefetchContext {
110
+ /** 路径 */
111
+ path?: string;
112
+ /** 参数 */
113
+ params?: Record<string, string>;
114
+ /** 查询参数 */
115
+ query?: Record<string, string>;
116
+ }
117
+ /**
118
+ * 预取结果
119
+ */
120
+ interface PrefetchResult<T = unknown> {
121
+ /** 预取的数据 */
122
+ data: T;
123
+ /** 过期时间戳 */
124
+ expiresAt?: number;
125
+ /** 缓存标签 */
126
+ tags?: string[];
127
+ }
128
+ /**
129
+ * 内存缓存实现
130
+ */
131
+ declare class MemoryCache implements Cache {
132
+ private cache;
133
+ private tagIndex;
134
+ private stats;
135
+ private defaultTTL;
136
+ private maxSize;
137
+ constructor(options?: CacheOptions);
138
+ get<T>(key: string): Promise<T | undefined>;
139
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
140
+ delete(key: string): Promise<boolean>;
141
+ has(key: string): Promise<boolean>;
142
+ clear(): Promise<void>;
143
+ invalidateTag(tag: string): Promise<void>;
144
+ invalidateTags(tags: string[]): Promise<void>;
145
+ getStats(): Promise<CacheStats>;
146
+ /**
147
+ * 计算值的大小(字节)
148
+ */
149
+ private calculateSize;
150
+ /**
151
+ * 淘汰最旧的条目
152
+ */
153
+ private evictOldest;
154
+ /**
155
+ * 更新命中率
156
+ */
157
+ private updateHitRate;
158
+ }
159
+ /**
160
+ * 多层缓存实现(Memory → Redis → HTTP)
161
+ */
162
+ declare class MultiLayerCache implements Cache {
163
+ private layers;
164
+ constructor(config?: MultiLayerCacheConfig);
165
+ get<T>(key: string): Promise<T | undefined>;
166
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
167
+ delete(key: string): Promise<boolean>;
168
+ has(key: string): Promise<boolean>;
169
+ clear(): Promise<void>;
170
+ invalidateTag(tag: string): Promise<void>;
171
+ invalidateTags(tags: string[]): Promise<void>;
172
+ getStats(): Promise<CacheStats>;
173
+ }
174
+ /**
175
+ * 创建默认缓存实例
176
+ */
177
+ declare function createCache(options?: {
178
+ type?: 'memory' | 'multi';
179
+ config?: CacheOptions | MultiLayerCacheConfig;
180
+ }): MemoryCache | MultiLayerCache;
181
+ declare function getDefaultCache(): MemoryCache;
182
+
183
+ export { type Cache, type CacheEntry, type CacheOptions, type CacheStats, MemoryCache, MultiLayerCache, type MultiLayerCacheConfig, type PrefetchContext, type PrefetchResult, createCache, getDefaultCache };
@@ -0,0 +1,183 @@
1
+ /**
2
+ * @lytjs/cache - 统一缓存系统入口
3
+ *
4
+ * 提供多层缓存(Memory → Redis → HTTP)支持,
5
+ * 包含缓存标签、TTL、统计等功能。
6
+ */
7
+ /**
8
+ * 缓存条目接口
9
+ */
10
+ interface CacheEntry<T = unknown> {
11
+ /** 缓存值 */
12
+ value: T;
13
+ /** 创建时间戳 */
14
+ createdAt: number;
15
+ /** 过期时间戳 */
16
+ expiresAt: number;
17
+ /** 缓存标签 */
18
+ tags: string[];
19
+ /** 数据大小(字节) */
20
+ size?: number;
21
+ }
22
+ /**
23
+ * 缓存配置选项
24
+ */
25
+ interface CacheOptions {
26
+ /** 生存时间(毫秒) */
27
+ ttl?: number;
28
+ /** 缓存标签 */
29
+ tags?: string[];
30
+ /** 重新验证时间(毫秒) */
31
+ revalidate?: number;
32
+ /** 最大大小(字节) */
33
+ maxSize?: number;
34
+ }
35
+ /**
36
+ * 统一缓存接口
37
+ */
38
+ interface Cache {
39
+ /**
40
+ * 获取缓存值
41
+ */
42
+ get<T>(key: string): Promise<T | undefined>;
43
+ /**
44
+ * 设置缓存值
45
+ */
46
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
47
+ /**
48
+ * 删除缓存值
49
+ */
50
+ delete(key: string): Promise<boolean>;
51
+ /**
52
+ * 检查缓存是否存在
53
+ */
54
+ has(key: string): Promise<boolean>;
55
+ /**
56
+ * 清除所有缓存
57
+ */
58
+ clear(): Promise<void>;
59
+ /**
60
+ * 按标签无效化缓存
61
+ */
62
+ invalidateTag(tag: string): Promise<void>;
63
+ /**
64
+ * 批量按标签无效化缓存
65
+ */
66
+ invalidateTags(tags: string[]): Promise<void>;
67
+ /**
68
+ * 获取缓存统计信息
69
+ */
70
+ getStats(): Promise<CacheStats>;
71
+ }
72
+ /**
73
+ * 缓存统计信息
74
+ */
75
+ interface CacheStats {
76
+ /** 键的数量 */
77
+ size: number;
78
+ /** 总大小(字节) */
79
+ totalSize: number;
80
+ /** 命中次数 */
81
+ hits: number;
82
+ /** 未命中次数 */
83
+ misses: number;
84
+ /** 命中率 */
85
+ hitRate: number;
86
+ }
87
+ /**
88
+ * 多层缓存配置
89
+ */
90
+ interface MultiLayerCacheConfig {
91
+ /** 内存缓存配置 */
92
+ memory?: CacheOptions | boolean;
93
+ /** Redis 缓存配置 */
94
+ redis?: CacheOptions & {
95
+ host?: string;
96
+ port?: number;
97
+ password?: string;
98
+ db?: number;
99
+ };
100
+ /** HTTP 缓存配置 */
101
+ http?: CacheOptions & {
102
+ baseUrl?: string;
103
+ headers?: Record<string, string>;
104
+ };
105
+ }
106
+ /**
107
+ * 数据预取上下文
108
+ */
109
+ interface PrefetchContext {
110
+ /** 路径 */
111
+ path?: string;
112
+ /** 参数 */
113
+ params?: Record<string, string>;
114
+ /** 查询参数 */
115
+ query?: Record<string, string>;
116
+ }
117
+ /**
118
+ * 预取结果
119
+ */
120
+ interface PrefetchResult<T = unknown> {
121
+ /** 预取的数据 */
122
+ data: T;
123
+ /** 过期时间戳 */
124
+ expiresAt?: number;
125
+ /** 缓存标签 */
126
+ tags?: string[];
127
+ }
128
+ /**
129
+ * 内存缓存实现
130
+ */
131
+ declare class MemoryCache implements Cache {
132
+ private cache;
133
+ private tagIndex;
134
+ private stats;
135
+ private defaultTTL;
136
+ private maxSize;
137
+ constructor(options?: CacheOptions);
138
+ get<T>(key: string): Promise<T | undefined>;
139
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
140
+ delete(key: string): Promise<boolean>;
141
+ has(key: string): Promise<boolean>;
142
+ clear(): Promise<void>;
143
+ invalidateTag(tag: string): Promise<void>;
144
+ invalidateTags(tags: string[]): Promise<void>;
145
+ getStats(): Promise<CacheStats>;
146
+ /**
147
+ * 计算值的大小(字节)
148
+ */
149
+ private calculateSize;
150
+ /**
151
+ * 淘汰最旧的条目
152
+ */
153
+ private evictOldest;
154
+ /**
155
+ * 更新命中率
156
+ */
157
+ private updateHitRate;
158
+ }
159
+ /**
160
+ * 多层缓存实现(Memory → Redis → HTTP)
161
+ */
162
+ declare class MultiLayerCache implements Cache {
163
+ private layers;
164
+ constructor(config?: MultiLayerCacheConfig);
165
+ get<T>(key: string): Promise<T | undefined>;
166
+ set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;
167
+ delete(key: string): Promise<boolean>;
168
+ has(key: string): Promise<boolean>;
169
+ clear(): Promise<void>;
170
+ invalidateTag(tag: string): Promise<void>;
171
+ invalidateTags(tags: string[]): Promise<void>;
172
+ getStats(): Promise<CacheStats>;
173
+ }
174
+ /**
175
+ * 创建默认缓存实例
176
+ */
177
+ declare function createCache(options?: {
178
+ type?: 'memory' | 'multi';
179
+ config?: CacheOptions | MultiLayerCacheConfig;
180
+ }): MemoryCache | MultiLayerCache;
181
+ declare function getDefaultCache(): MemoryCache;
182
+
183
+ export { type Cache, type CacheEntry, type CacheOptions, type CacheStats, MemoryCache, MultiLayerCache, type MultiLayerCacheConfig, type PrefetchContext, type PrefetchResult, createCache, getDefaultCache };
package/dist/index.js ADDED
@@ -0,0 +1,250 @@
1
+ // src/index.ts
2
+ var DEFAULT_TTL = 36e5;
3
+ var MAX_SIZE = 100 * 1024 * 1024;
4
+ var MemoryCache = class {
5
+ constructor(options = {}) {
6
+ this.cache = /* @__PURE__ */ new Map();
7
+ this.tagIndex = /* @__PURE__ */ new Map();
8
+ this.stats = {
9
+ size: 0,
10
+ totalSize: 0,
11
+ hits: 0,
12
+ misses: 0,
13
+ hitRate: 0
14
+ };
15
+ this.defaultTTL = options.ttl ?? DEFAULT_TTL;
16
+ this.maxSize = options.maxSize ?? MAX_SIZE;
17
+ }
18
+ async get(key) {
19
+ const entry = this.cache.get(key);
20
+ if (!entry) {
21
+ this.stats.misses++;
22
+ this.updateHitRate();
23
+ return void 0;
24
+ }
25
+ const now = Date.now();
26
+ if (entry.expiresAt < now) {
27
+ this.delete(key);
28
+ this.stats.misses++;
29
+ this.updateHitRate();
30
+ return void 0;
31
+ }
32
+ this.stats.hits++;
33
+ this.updateHitRate();
34
+ return entry.value;
35
+ }
36
+ async set(key, value, options = {}) {
37
+ const now = Date.now();
38
+ const ttl = options.ttl ?? this.defaultTTL;
39
+ const tags = options.tags ?? [];
40
+ const size = this.calculateSize(value);
41
+ if (this.stats.totalSize + size > this.maxSize) {
42
+ this.evictOldest();
43
+ }
44
+ const entry = {
45
+ value,
46
+ createdAt: now,
47
+ expiresAt: now + ttl,
48
+ tags,
49
+ size
50
+ };
51
+ this.cache.set(key, entry);
52
+ for (const tag of tags) {
53
+ if (!this.tagIndex.has(tag)) {
54
+ this.tagIndex.set(tag, /* @__PURE__ */ new Set());
55
+ }
56
+ this.tagIndex.get(tag).add(key);
57
+ }
58
+ this.stats.size = this.cache.size;
59
+ this.stats.totalSize += size;
60
+ }
61
+ async delete(key) {
62
+ const entry = this.cache.get(key);
63
+ if (!entry) {
64
+ return false;
65
+ }
66
+ for (const tag of entry.tags) {
67
+ const tagKeys = this.tagIndex.get(tag);
68
+ if (tagKeys) {
69
+ tagKeys.delete(key);
70
+ if (tagKeys.size === 0) {
71
+ this.tagIndex.delete(tag);
72
+ }
73
+ }
74
+ }
75
+ if (entry.size) {
76
+ this.stats.totalSize -= entry.size;
77
+ }
78
+ this.stats.size = this.cache.size - 1;
79
+ return this.cache.delete(key);
80
+ }
81
+ async has(key) {
82
+ const entry = this.cache.get(key);
83
+ if (!entry) {
84
+ return false;
85
+ }
86
+ if (Date.now() > entry.expiresAt) {
87
+ await this.delete(key);
88
+ return false;
89
+ }
90
+ return true;
91
+ }
92
+ async clear() {
93
+ this.cache.clear();
94
+ this.tagIndex.clear();
95
+ this.stats = {
96
+ size: 0,
97
+ totalSize: 0,
98
+ hits: 0,
99
+ misses: 0,
100
+ hitRate: 0
101
+ };
102
+ }
103
+ async invalidateTag(tag) {
104
+ const keys = this.tagIndex.get(tag);
105
+ if (!keys) {
106
+ return;
107
+ }
108
+ for (const key of keys) {
109
+ await this.delete(key);
110
+ }
111
+ }
112
+ async invalidateTags(tags) {
113
+ for (const tag of tags) {
114
+ await this.invalidateTag(tag);
115
+ }
116
+ }
117
+ async getStats() {
118
+ return { ...this.stats };
119
+ }
120
+ /**
121
+ * 计算值的大小(字节)
122
+ */
123
+ calculateSize(value) {
124
+ try {
125
+ const str = JSON.stringify(value);
126
+ return new TextEncoder().encode(str).length;
127
+ } catch {
128
+ return 100;
129
+ }
130
+ }
131
+ /**
132
+ * 淘汰最旧的条目
133
+ */
134
+ evictOldest() {
135
+ let oldestKey = null;
136
+ let oldestTime = Infinity;
137
+ for (const [key, entry] of this.cache) {
138
+ if (entry.createdAt < oldestTime) {
139
+ oldestTime = entry.createdAt;
140
+ oldestKey = key;
141
+ }
142
+ }
143
+ if (oldestKey) {
144
+ this.delete(oldestKey);
145
+ }
146
+ }
147
+ /**
148
+ * 更新命中率
149
+ */
150
+ updateHitRate() {
151
+ const total = this.stats.hits + this.stats.misses;
152
+ this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
153
+ }
154
+ };
155
+ var MultiLayerCache = class {
156
+ constructor(config = {}) {
157
+ this.layers = [];
158
+ if (config.memory !== false) {
159
+ const memoryOptions = typeof config.memory === "object" ? config.memory : void 0;
160
+ this.layers.push(new MemoryCache(memoryOptions));
161
+ }
162
+ if (config.redis) {
163
+ }
164
+ if (config.http) {
165
+ }
166
+ }
167
+ async get(key) {
168
+ for (const layer of this.layers) {
169
+ const value = await layer.get(key);
170
+ if (value !== void 0) {
171
+ for (let i = 0; i < this.layers.indexOf(layer); i++) {
172
+ await this.layers[i].set(key, value);
173
+ }
174
+ return value;
175
+ }
176
+ }
177
+ return void 0;
178
+ }
179
+ async set(key, value, options) {
180
+ for (const layer of this.layers) {
181
+ await layer.set(key, value, options);
182
+ }
183
+ }
184
+ async delete(key) {
185
+ let result = false;
186
+ for (const layer of this.layers) {
187
+ const layerResult = await layer.delete(key);
188
+ if (layerResult) {
189
+ result = true;
190
+ }
191
+ }
192
+ return result;
193
+ }
194
+ async has(key) {
195
+ for (const layer of this.layers) {
196
+ if (await layer.has(key)) {
197
+ return true;
198
+ }
199
+ }
200
+ return false;
201
+ }
202
+ async clear() {
203
+ for (const layer of this.layers) {
204
+ await layer.clear();
205
+ }
206
+ }
207
+ async invalidateTag(tag) {
208
+ for (const layer of this.layers) {
209
+ await layer.invalidateTag(tag);
210
+ }
211
+ }
212
+ async invalidateTags(tags) {
213
+ for (const tag of tags) {
214
+ await this.invalidateTag(tag);
215
+ }
216
+ }
217
+ async getStats() {
218
+ const statsList = await Promise.all(this.layers.map((layer) => layer.getStats()));
219
+ const merged = {
220
+ size: statsList.reduce((sum, stat) => sum + stat.size, 0),
221
+ totalSize: statsList.reduce((sum, stat) => sum + stat.totalSize, 0),
222
+ hits: statsList.reduce((sum, stat) => sum + stat.hits, 0),
223
+ misses: statsList.reduce((sum, stat) => sum + stat.misses, 0),
224
+ hitRate: 0
225
+ };
226
+ const total = merged.hits + merged.misses;
227
+ merged.hitRate = total > 0 ? merged.hits / total : 0;
228
+ return merged;
229
+ }
230
+ };
231
+ function createCache(options) {
232
+ if (options?.type === "multi") {
233
+ return new MultiLayerCache(options.config);
234
+ }
235
+ return new MemoryCache(options?.config);
236
+ }
237
+ var defaultCache = null;
238
+ function getDefaultCache() {
239
+ if (!defaultCache) {
240
+ defaultCache = new MemoryCache();
241
+ }
242
+ return defaultCache;
243
+ }
244
+ export {
245
+ MemoryCache,
246
+ MultiLayerCache,
247
+ createCache,
248
+ getDefaultCache
249
+ };
250
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @lytjs/cache - 统一缓存系统入口\n *\n * 提供多层缓存(Memory → Redis → HTTP)支持,\n * 包含缓存标签、TTL、统计等功能。\n */\n\n/**\n * 缓存条目接口\n */\nexport interface CacheEntry<T = unknown> {\n /** 缓存值 */\n value: T;\n /** 创建时间戳 */\n createdAt: number;\n /** 过期时间戳 */\n expiresAt: number;\n /** 缓存标签 */\n tags: string[];\n /** 数据大小(字节) */\n size?: number;\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheOptions {\n /** 生存时间(毫秒) */\n ttl?: number;\n /** 缓存标签 */\n tags?: string[];\n /** 重新验证时间(毫秒) */\n revalidate?: number;\n /** 最大大小(字节) */\n maxSize?: number;\n}\n\n/**\n * 统一缓存接口\n */\nexport interface Cache {\n /**\n * 获取缓存值\n */\n get<T>(key: string): Promise<T | undefined>;\n\n /**\n * 设置缓存值\n */\n set<T>(key: string, value: T, options?: CacheOptions): Promise<void>;\n\n /**\n * 删除缓存值\n */\n delete(key: string): Promise<boolean>;\n\n /**\n * 检查缓存是否存在\n */\n has(key: string): Promise<boolean>;\n\n /**\n * 清除所有缓存\n */\n clear(): Promise<void>;\n\n /**\n * 按标签无效化缓存\n */\n invalidateTag(tag: string): Promise<void>;\n\n /**\n * 批量按标签无效化缓存\n */\n invalidateTags(tags: string[]): Promise<void>;\n\n /**\n * 获取缓存统计信息\n */\n getStats(): Promise<CacheStats>;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStats {\n /** 键的数量 */\n size: number;\n /** 总大小(字节) */\n totalSize: number;\n /** 命中次数 */\n hits: number;\n /** 未命中次数 */\n misses: number;\n /** 命中率 */\n hitRate: number;\n}\n\n/**\n * 多层缓存配置\n */\nexport interface MultiLayerCacheConfig {\n /** 内存缓存配置 */\n memory?: CacheOptions | boolean;\n /** Redis 缓存配置 */\n redis?: CacheOptions & {\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n };\n /** HTTP 缓存配置 */\n http?: CacheOptions & {\n baseUrl?: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * 数据预取上下文\n */\nexport interface PrefetchContext {\n /** 路径 */\n path?: string;\n /** 参数 */\n params?: Record<string, string>;\n /** 查询参数 */\n query?: Record<string, string>;\n}\n\n/**\n * 预取结果\n */\nexport interface PrefetchResult<T = unknown> {\n /** 预取的数据 */\n data: T;\n /** 过期时间戳 */\n expiresAt?: number;\n /** 缓存标签 */\n tags?: string[];\n}\n\nconst DEFAULT_TTL = 3600000; // 1 小时\nconst MAX_SIZE = 100 * 1024 * 1024; // 100 MB\n\n/**\n * 内存缓存实现\n */\nexport class MemoryCache implements Cache {\n private cache: Map<string, CacheEntry> = new Map();\n private tagIndex: Map<string, Set<string>> = new Map();\n private stats: CacheStats = {\n size: 0,\n totalSize: 0,\n hits: 0,\n misses: 0,\n hitRate: 0,\n };\n private defaultTTL: number;\n private maxSize: number;\n\n constructor(options: CacheOptions = {}) {\n this.defaultTTL = options.ttl ?? DEFAULT_TTL;\n this.maxSize = options.maxSize ?? MAX_SIZE;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const entry = this.cache.get(key);\n if (!entry) {\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n const now = Date.now();\n if (entry.expiresAt < now) {\n this.delete(key);\n this.stats.misses++;\n this.updateHitRate();\n return undefined;\n }\n\n this.stats.hits++;\n this.updateHitRate();\n return entry.value as T;\n }\n\n async set<T>(key: string, value: T, options: CacheOptions = {}): Promise<void> {\n const now = Date.now();\n const ttl = options.ttl ?? this.defaultTTL;\n const tags = options.tags ?? [];\n const size = this.calculateSize(value);\n\n // 检查是否超出最大大小\n if (this.stats.totalSize + size > this.maxSize) {\n this.evictOldest();\n }\n\n const entry: CacheEntry = {\n value,\n createdAt: now,\n expiresAt: now + ttl,\n tags,\n size,\n };\n\n // 更新缓存\n this.cache.set(key, entry);\n\n // 更新标签索引\n for (const tag of tags) {\n if (!this.tagIndex.has(tag)) {\n this.tagIndex.set(tag, new Set());\n }\n this.tagIndex.get(tag)!.add(key);\n }\n\n // 更新统计\n this.stats.size = this.cache.size;\n this.stats.totalSize += size;\n }\n\n async delete(key: string): Promise<boolean> {\n const entry = this.cache.get(key);\n if (!entry) {\n return false;\n }\n\n // 从标签索引中删除\n for (const tag of entry.tags) {\n const tagKeys = this.tagIndex.get(tag);\n if (tagKeys) {\n tagKeys.delete(key);\n if (tagKeys.size === 0) {\n this.tagIndex.delete(tag);\n }\n }\n }\n\n // 更新统计\n if (entry.size) {\n this.stats.totalSize -= entry.size;\n }\n this.stats.size = this.cache.size - 1;\n\n return this.cache.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n const entry = this.cache.get(key);\n if (!entry) {\n return false;\n }\n if (Date.now() > entry.expiresAt) {\n await this.delete(key);\n return false;\n }\n return true;\n }\n\n async clear(): Promise<void> {\n this.cache.clear();\n this.tagIndex.clear();\n this.stats = {\n size: 0,\n totalSize: 0,\n hits: 0,\n misses: 0,\n hitRate: 0,\n };\n }\n\n async invalidateTag(tag: string): Promise<void> {\n const keys = this.tagIndex.get(tag);\n if (!keys) {\n return;\n }\n\n for (const key of keys) {\n await this.delete(key);\n }\n }\n\n async invalidateTags(tags: string[]): Promise<void> {\n for (const tag of tags) {\n await this.invalidateTag(tag);\n }\n }\n\n async getStats(): Promise<CacheStats> {\n return { ...this.stats };\n }\n\n /**\n * 计算值的大小(字节)\n */\n private calculateSize(value: unknown): number {\n try {\n const str = JSON.stringify(value);\n return new TextEncoder().encode(str).length;\n } catch {\n return 100; // 估算大小\n }\n }\n\n /**\n * 淘汰最旧的条目\n */\n private evictOldest(): void {\n let oldestKey: string | null = null;\n let oldestTime = Infinity;\n\n for (const [key, entry] of this.cache) {\n if (entry.createdAt < oldestTime) {\n oldestTime = entry.createdAt;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.delete(oldestKey);\n }\n }\n\n /**\n * 更新命中率\n */\n private updateHitRate(): void {\n const total = this.stats.hits + this.stats.misses;\n this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;\n }\n}\n\n/**\n * 多层缓存实现(Memory → Redis → HTTP)\n */\nexport class MultiLayerCache implements Cache {\n private layers: Cache[];\n\n constructor(config: MultiLayerCacheConfig = {}) {\n this.layers = [];\n\n // 内存缓存始终作为第一层\n if (config.memory !== false) {\n const memoryOptions = typeof config.memory === 'object' ? config.memory : undefined;\n this.layers.push(new MemoryCache(memoryOptions));\n }\n\n // Redis 缓存作为第二层(可选)\n if (config.redis) {\n // Redis 缓存可以在实际环境配置\n // 这里我们预留接口\n }\n\n // HTTP 缓存作为第三层(可选)\n if (config.http) {\n // HTTP 缓存可以在实际环境配置\n }\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n for (const layer of this.layers) {\n const value = await layer.get<T>(key);\n if (value !== undefined) {\n // 回写上层缓存\n for (let i = 0; i < this.layers.indexOf(layer); i++) {\n await this.layers[i].set(key, value);\n }\n return value;\n }\n }\n return undefined;\n }\n\n async set<T>(key: string, value: T, options?: CacheOptions): Promise<void> {\n // 写入所有层\n for (const layer of this.layers) {\n await layer.set(key, value, options);\n }\n }\n\n async delete(key: string): Promise<boolean> {\n let result = false;\n for (const layer of this.layers) {\n const layerResult = await layer.delete(key);\n if (layerResult) {\n result = true;\n }\n }\n return result;\n }\n\n async has(key: string): Promise<boolean> {\n for (const layer of this.layers) {\n if (await layer.has(key)) {\n return true;\n }\n }\n return false;\n }\n\n async clear(): Promise<void> {\n for (const layer of this.layers) {\n await layer.clear();\n }\n }\n\n async invalidateTag(tag: string): Promise<void> {\n for (const layer of this.layers) {\n await layer.invalidateTag(tag);\n }\n }\n\n async invalidateTags(tags: string[]): Promise<void> {\n for (const tag of tags) {\n await this.invalidateTag(tag);\n }\n }\n\n async getStats(): Promise<CacheStats> {\n // 合并所有层的统计信息\n const statsList = await Promise.all(this.layers.map((layer) => layer.getStats()));\n const merged: CacheStats = {\n size: statsList.reduce((sum, stat) => sum + stat.size, 0),\n totalSize: statsList.reduce((sum, stat) => sum + stat.totalSize, 0),\n hits: statsList.reduce((sum, stat) => sum + stat.hits, 0),\n misses: statsList.reduce((sum, stat) => sum + stat.misses, 0),\n hitRate: 0,\n };\n const total = merged.hits + merged.misses;\n merged.hitRate = total > 0 ? merged.hits / total : 0;\n return merged;\n }\n}\n\n/**\n * 创建默认缓存实例\n */\nexport function createCache(options?: {\n type?: 'memory' | 'multi';\n config?: CacheOptions | MultiLayerCacheConfig;\n}) {\n if (options?.type === 'multi') {\n return new MultiLayerCache(options.config as MultiLayerCacheConfig);\n }\n return new MemoryCache(options?.config as CacheOptions);\n}\n\n// 默认实例\nlet defaultCache: MemoryCache | null = null;\n\nexport function getDefaultCache() {\n if (!defaultCache) {\n defaultCache = new MemoryCache();\n }\n return defaultCache;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lytjs/cache",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "description": "LytJS unified caching system with memory, Redis, and HTTP cache support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,8 +24,8 @@
24
24
  "clean": "rm -rf dist"
25
25
  },
26
26
  "dependencies": {
27
- "@lytjs/common-cache": "workspace:*",
28
- "@lytjs/common-is": "workspace:*"
27
+ "@lytjs/common-cache": "^6.9.0",
28
+ "@lytjs/common-is": "^6.9.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "tsup": "^8.0.0",