imean-service-engine 2.0.0 → 2.0.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.
Files changed (72) hide show
  1. package/dist/index.d.mts +77 -52
  2. package/dist/index.d.ts +77 -52
  3. package/dist/index.js +2078 -1945
  4. package/dist/index.mjs +2076 -1944
  5. package/package.json +9 -2
  6. package/.vscode/settings.json +0 -8
  7. package/src/core/checker.ts +0 -33
  8. package/src/core/decorators.test.ts +0 -96
  9. package/src/core/decorators.ts +0 -68
  10. package/src/core/engine.test.ts +0 -218
  11. package/src/core/engine.ts +0 -635
  12. package/src/core/errors.ts +0 -28
  13. package/src/core/factory.test.ts +0 -73
  14. package/src/core/factory.ts +0 -92
  15. package/src/core/logger.ts +0 -65
  16. package/src/core/testing.ts +0 -73
  17. package/src/core/types.ts +0 -191
  18. package/src/index.ts +0 -49
  19. package/src/metadata/README.md +0 -422
  20. package/src/metadata/metadata.test.ts +0 -369
  21. package/src/metadata/metadata.ts +0 -512
  22. package/src/plugins/action/action-plugin.test.ts +0 -660
  23. package/src/plugins/action/decorator.ts +0 -14
  24. package/src/plugins/action/index.ts +0 -4
  25. package/src/plugins/action/plugin.ts +0 -349
  26. package/src/plugins/action/types.ts +0 -49
  27. package/src/plugins/action/utils.test.ts +0 -196
  28. package/src/plugins/action/utils.ts +0 -111
  29. package/src/plugins/cache/adapter.test.ts +0 -689
  30. package/src/plugins/cache/adapter.ts +0 -324
  31. package/src/plugins/cache/cache-plugin.test.ts +0 -269
  32. package/src/plugins/cache/decorator.ts +0 -26
  33. package/src/plugins/cache/index.ts +0 -20
  34. package/src/plugins/cache/plugin.ts +0 -299
  35. package/src/plugins/cache/types.ts +0 -69
  36. package/src/plugins/client-code/client-code-plugin.test.ts +0 -511
  37. package/src/plugins/client-code/format.ts +0 -9
  38. package/src/plugins/client-code/generator.test.ts +0 -52
  39. package/src/plugins/client-code/generator.ts +0 -263
  40. package/src/plugins/client-code/index.ts +0 -15
  41. package/src/plugins/client-code/plugin.ts +0 -158
  42. package/src/plugins/client-code/types.ts +0 -52
  43. package/src/plugins/client-code/utils.ts +0 -164
  44. package/src/plugins/graceful-shutdown/graceful-shutdown-plugin.test.ts +0 -401
  45. package/src/plugins/graceful-shutdown/index.ts +0 -3
  46. package/src/plugins/graceful-shutdown/plugin.ts +0 -279
  47. package/src/plugins/graceful-shutdown/types.ts +0 -17
  48. package/src/plugins/rate-limit/rate-limit-plugin.example.ts +0 -171
  49. package/src/plugins/route/components/Layout.tsx +0 -42
  50. package/src/plugins/route/components/ServiceStatusPage.tsx +0 -141
  51. package/src/plugins/route/decorator.ts +0 -50
  52. package/src/plugins/route/index.ts +0 -16
  53. package/src/plugins/route/plugin.ts +0 -218
  54. package/src/plugins/route/route-plugin.test.ts +0 -759
  55. package/src/plugins/route/types.ts +0 -72
  56. package/src/plugins/schedule/README.md +0 -309
  57. package/src/plugins/schedule/decorator.ts +0 -25
  58. package/src/plugins/schedule/index.ts +0 -12
  59. package/src/plugins/schedule/mock-etcd.ts +0 -145
  60. package/src/plugins/schedule/plugin.ts +0 -164
  61. package/src/plugins/schedule/schedule-plugin.test.ts +0 -312
  62. package/src/plugins/schedule/scheduler.ts +0 -164
  63. package/src/plugins/schedule/types.ts +0 -94
  64. package/src/plugins/schedule/utils.test.ts +0 -163
  65. package/src/plugins/schedule/utils.ts +0 -41
  66. package/tests/integration/client.test.ts +0 -203
  67. package/tests/integration/dev-service.ts +0 -301
  68. package/tests/integration/generated/client.ts +0 -123
  69. package/tests/integration/start-service.ts +0 -21
  70. package/tsconfig.json +0 -27
  71. package/tsup.config.ts +0 -16
  72. package/vitest.config.ts +0 -19
@@ -1,324 +0,0 @@
1
- /**
2
- * Cache Adapter 接口
3
- * 定义缓存存储的抽象接口,支持不同的存储后端
4
- */
5
-
6
- import { CacheItem } from "./types";
7
-
8
- /**
9
- * 缓存适配器接口
10
- */
11
- export interface CacheAdapter {
12
- /**
13
- * 获取缓存项
14
- * @param key 缓存键
15
- * @returns 缓存项,如果不存在或已过期则返回 null
16
- */
17
- get<T = any>(key: string): Promise<CacheItem<T> | null>;
18
-
19
- /**
20
- * 设置缓存项
21
- * @param key 缓存键
22
- * @param item 缓存项
23
- */
24
- set<T = any>(key: string, item: CacheItem<T>): Promise<void>;
25
-
26
- /**
27
- * 删除缓存项
28
- * @param key 缓存键
29
- * @returns 是否删除成功
30
- */
31
- delete(key: string): Promise<boolean>;
32
-
33
- /**
34
- * 清空所有缓存
35
- */
36
- clear(): Promise<void>;
37
-
38
- /**
39
- * 获取所有缓存键(用于统计)
40
- * @returns 缓存键数组(不包含过期项)
41
- */
42
- keys(): Promise<string[]>;
43
-
44
- /**
45
- * 清理所有过期项(高效批量清理)
46
- * @returns 清理的过期项数量
47
- */
48
- cleanupExpired?(): Promise<number>;
49
-
50
- /**
51
- * 获取缓存统计信息
52
- */
53
- getStats(): Promise<{
54
- size: number;
55
- entries: Array<{ key: string; expiresAt: number; createdAt: number }>;
56
- }>;
57
- }
58
-
59
- /**
60
- * 内存缓存适配器
61
- * 使用 Map 存储,适合单进程应用
62
- *
63
- * 注意:过期项会在以下情况被自动清理:
64
- * 1. get() 时检查并删除过期项
65
- * 2. keys() 和 getStats() 会过滤过期项
66
- * 3. 建议通过 CachePlugin 的定期清理机制主动清理过期项
67
- */
68
- export class MemoryCacheAdapter implements CacheAdapter {
69
- private cache: Map<string, CacheItem> = new Map();
70
-
71
- async get<T = any>(key: string): Promise<CacheItem<T> | null> {
72
- const item = this.cache.get(key);
73
- if (!item) {
74
- return null;
75
- }
76
-
77
- // 检查是否过期,过期则删除
78
- if (item.expiresAt <= Date.now()) {
79
- this.cache.delete(key);
80
- return null;
81
- }
82
-
83
- return item as CacheItem<T>;
84
- }
85
-
86
- async set<T = any>(key: string, item: CacheItem<T>): Promise<void> {
87
- this.cache.set(key, item);
88
- }
89
-
90
- async delete(key: string): Promise<boolean> {
91
- return this.cache.delete(key);
92
- }
93
-
94
- async clear(): Promise<void> {
95
- this.cache.clear();
96
- }
97
-
98
- async keys(): Promise<string[]> {
99
- // 过滤过期项,避免返回无效键
100
- const now = Date.now();
101
- return Array.from(this.cache.entries())
102
- .filter(([_, item]) => item.expiresAt > now)
103
- .map(([key]) => key);
104
- }
105
-
106
- /**
107
- * 清理所有过期项(高效批量清理)
108
- * 这个方法比通过 keys() + get() + delete() 更高效
109
- */
110
- async cleanupExpired(): Promise<number> {
111
- const now = Date.now();
112
- let cleaned = 0;
113
-
114
- // 直接遍历 Map 并删除过期项
115
- for (const [key, item] of this.cache.entries()) {
116
- if (item.expiresAt <= now) {
117
- this.cache.delete(key);
118
- cleaned++;
119
- }
120
- }
121
-
122
- return cleaned;
123
- }
124
-
125
- async getStats(): Promise<{
126
- size: number;
127
- entries: Array<{ key: string; expiresAt: number; createdAt: number }>;
128
- }> {
129
- const now = Date.now();
130
- const validEntries = Array.from(this.cache.entries())
131
- .filter(([_, item]) => item.expiresAt > now)
132
- .map(([key, item]) => ({
133
- key,
134
- expiresAt: item.expiresAt,
135
- createdAt: item.createdAt,
136
- }));
137
-
138
- return {
139
- size: validEntries.length,
140
- entries: validEntries,
141
- };
142
- }
143
- }
144
-
145
- /**
146
- * Redis 缓存适配器配置
147
- */
148
- export interface RedisCacheAdapterOptions {
149
- /**
150
- * Redis 客户端实例(需要实现基本的 get/set/del/keys 方法)
151
- * 可以是 ioredis、node-redis 等
152
- */
153
- client: {
154
- get(key: string): Promise<string | null>;
155
- set(
156
- key: string,
157
- value: string,
158
- expiryMode?: string,
159
- time?: number
160
- ): Promise<string | null>;
161
- del(key: string): Promise<number>;
162
- keys(pattern: string): Promise<string[]>;
163
- };
164
-
165
- /**
166
- * 键前缀,用于区分不同应用的缓存
167
- * 默认:'cache:'
168
- */
169
- keyPrefix?: string;
170
- }
171
-
172
- /**
173
- * Redis 缓存适配器
174
- * 使用 Redis 作为存储后端,适合分布式应用
175
- *
176
- * 注意:Redis 本身支持 TTL(Time To Live),过期键会自动删除,
177
- * 因此不需要手动清理过期项。当使用 SET key value EX seconds 时,
178
- * Redis 会在过期后自动删除键。
179
- */
180
- export class RedisCacheAdapter implements CacheAdapter {
181
- private client: RedisCacheAdapterOptions["client"];
182
- private keyPrefix: string;
183
-
184
- constructor(options: RedisCacheAdapterOptions) {
185
- this.client = options.client;
186
- this.keyPrefix = options.keyPrefix || "cache:";
187
- }
188
-
189
- private getKey(key: string): string {
190
- return `${this.keyPrefix}${key}`;
191
- }
192
-
193
- async get<T = any>(key: string): Promise<CacheItem<T> | null> {
194
- const redisKey = this.getKey(key);
195
- const data = await this.client.get(redisKey);
196
-
197
- // Redis 会自动删除过期键,如果键已过期,get() 会返回 null
198
- if (!data) {
199
- return null;
200
- }
201
-
202
- try {
203
- const item: CacheItem<T> = JSON.parse(data);
204
-
205
- // 双重检查:虽然 Redis 会自动删除过期键,但为了兼容性
206
- // (某些 Redis 客户端或测试环境可能不会立即删除),
207
- // 仍然检查 expiresAt。在真实 Redis 环境中,这个检查通常是多余的。
208
- if (item.expiresAt <= Date.now()) {
209
- await this.delete(key);
210
- return null;
211
- }
212
-
213
- return item;
214
- } catch (error) {
215
- // 解析失败,删除无效数据
216
- await this.delete(key);
217
- return null;
218
- }
219
- }
220
-
221
- async set<T = any>(key: string, item: CacheItem<T>): Promise<void> {
222
- const redisKey = this.getKey(key);
223
- const data = JSON.stringify(item);
224
-
225
- // 计算 TTL(秒)
226
- const ttl = Math.max(0, Math.floor((item.expiresAt - Date.now()) / 1000));
227
-
228
- // 使用 SET 命令的 EX 选项设置过期时间
229
- await this.client.set(redisKey, data, "EX", ttl);
230
- }
231
-
232
- async delete(key: string): Promise<boolean> {
233
- const redisKey = this.getKey(key);
234
- const result = await this.client.del(redisKey);
235
- return result > 0;
236
- }
237
-
238
- async clear(): Promise<void> {
239
- const pattern = `${this.keyPrefix}*`;
240
- const keys = await this.client.keys(pattern);
241
-
242
- if (keys.length > 0) {
243
- // 批量删除(注意:这里假设 client 支持批量删除)
244
- // 如果不支持,可以逐个删除
245
- await Promise.all(keys.map((key) => this.client.del(key)));
246
- }
247
- }
248
-
249
- async keys(): Promise<string[]> {
250
- const pattern = `${this.keyPrefix}*`;
251
- const redisKeys = await this.client.keys(pattern);
252
-
253
- // 移除前缀
254
- return redisKeys.map((key) => key.replace(this.keyPrefix, ""));
255
- }
256
-
257
- /**
258
- * 清理所有过期项
259
- *
260
- * 注意:Redis 本身支持自动过期(通过 SET key value EX seconds),
261
- * 过期键会被 Redis 自动删除。但在某些情况下(如测试环境、某些 Redis 客户端),
262
- * 可能需要手动清理。此方法会检查并清理:
263
- * 1. 已过期但尚未被 Redis 删除的键(双重保险)
264
- * 2. JSON 解析失败的数据
265
- */
266
- async cleanupExpired(): Promise<number> {
267
- const pattern = `${this.keyPrefix}*`;
268
- const redisKeys = await this.client.keys(pattern);
269
- let cleaned = 0;
270
-
271
- // 检查并清理过期项和无效数据
272
- for (const redisKey of redisKeys) {
273
- const data = await this.client.get(redisKey);
274
- if (!data) {
275
- // 已被 Redis 自动过期删除,跳过
276
- continue;
277
- }
278
-
279
- try {
280
- const item: CacheItem = JSON.parse(data);
281
- // 检查是否过期(双重保险,虽然 Redis 应该已经删除了)
282
- if (item.expiresAt <= Date.now()) {
283
- await this.client.del(redisKey);
284
- cleaned++;
285
- }
286
- } catch {
287
- // JSON 解析失败,删除无效数据
288
- await this.client.del(redisKey);
289
- cleaned++;
290
- }
291
- }
292
-
293
- return cleaned;
294
- }
295
-
296
- async getStats(): Promise<{
297
- size: number;
298
- entries: Array<{ key: string; expiresAt: number; createdAt: number }>;
299
- }> {
300
- const allKeys = await this.keys();
301
- const entries: Array<{
302
- key: string;
303
- expiresAt: number;
304
- createdAt: number;
305
- }> = [];
306
-
307
- // 获取所有缓存项的元数据
308
- for (const key of allKeys) {
309
- const item = await this.get(key);
310
- if (item) {
311
- entries.push({
312
- key,
313
- expiresAt: item.expiresAt,
314
- createdAt: item.createdAt,
315
- });
316
- }
317
- }
318
-
319
- return {
320
- size: entries.length,
321
- entries,
322
- };
323
- }
324
- }
@@ -1,269 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
- import { Testing } from "../../core/testing";
3
- import { Cache, CachePlugin } from "./index";
4
-
5
- describe("CachePlugin", () => {
6
- let engine: ReturnType<typeof Testing.createTestEngine>["engine"];
7
- let Module: ReturnType<typeof Testing.createTestEngine>["Module"];
8
- let cachePlugin: CachePlugin;
9
-
10
- beforeEach(() => {
11
- // 每个测试都会创建新的 Factory,使用不同的 key,自动隔离
12
- cachePlugin = new CachePlugin();
13
- const testEngine = Testing.createTestEngine({ plugins: [cachePlugin] });
14
- engine = testEngine.engine;
15
- Module = testEngine.Module;
16
- });
17
-
18
- afterEach(async () => {
19
- // 清理:停止引擎并清空缓存
20
- if (engine) {
21
- await engine.stop().catch(() => {});
22
- }
23
- await cachePlugin.clear();
24
- });
25
-
26
- describe("插件配置", () => {
27
- it("应该有正确的插件名称", () => {
28
- expect(cachePlugin.name).toBe("cache-plugin");
29
- });
30
-
31
- it("应该声明Module配置Schema", () => {
32
- const schema = cachePlugin.getModuleOptionsSchema?.();
33
- expect(schema).toBeDefined();
34
- expect(schema?.validate).toBeDefined();
35
- });
36
-
37
- it("应该校验Module配置", () => {
38
- const schema = cachePlugin.getModuleOptionsSchema?.();
39
- if (!schema?.validate) return;
40
-
41
- // 有效的配置
42
- expect(schema.validate({ cacheDefaultTtl: 5000 })).toBe(true);
43
-
44
- // 无效的配置(TTL为负数)
45
- const result = schema.validate({ cacheDefaultTtl: -1 });
46
- expect(result).not.toBe(true);
47
- expect(typeof result).toBe("string");
48
- });
49
- });
50
-
51
- describe("缓存功能", () => {
52
- it("应该能够缓存方法结果", async () => {
53
- let callCount = 0;
54
-
55
- @Module("test-module")
56
- class TestService {
57
- @Cache({ ttl: 1000 })
58
- async getData(id: number) {
59
- callCount++;
60
- return { id, value: `data-${id}` };
61
- }
62
- }
63
-
64
- // 启动引擎,让插件正常初始化和处理 handlers
65
- await engine.start();
66
-
67
- const instance = engine.get(TestService);
68
-
69
- // 第一次调用,应该执行原始方法
70
- const result1 = await instance.getData(1);
71
- expect(result1).toEqual({ id: 1, value: "data-1" });
72
- expect(callCount).toBe(1);
73
-
74
- // 第二次调用,应该从缓存返回
75
- const result2 = await instance.getData(1);
76
- expect(result2).toEqual({ id: 1, value: "data-1" });
77
- expect(callCount).toBe(1); // 调用次数不变
78
-
79
- await engine.stop();
80
- });
81
-
82
- it("应该支持自定义 key 函数", async () => {
83
- @Module("test-module")
84
- class TestService {
85
- @Cache({
86
- ttl: 1000,
87
- key: (id: number) => ({ id }), // key 函数返回对象
88
- })
89
- async getData(id: number) {
90
- return { id };
91
- }
92
- }
93
-
94
- await engine.start();
95
- const instance = engine.get(TestService);
96
- await instance.getData(1);
97
-
98
- const stats = await cachePlugin.getStats();
99
- // 缓存键格式:模块名:方法名:hash
100
- expect(stats.entries.length).toBeGreaterThan(0);
101
- const cacheKey = stats.entries[0].key;
102
- expect(cacheKey).toMatch(/^test-module:getData:[a-f0-9]{64}$/);
103
-
104
- await engine.stop();
105
- });
106
-
107
- it("应该使用模块名和方法名作为缓存键前缀", async () => {
108
- @Module("user-service")
109
- class UserService {
110
- @Cache({ ttl: 1000 })
111
- async getUser(id: number) {
112
- return { id, name: "User" };
113
- }
114
- }
115
-
116
- @Module("order-service")
117
- class OrderService {
118
- @Cache({ ttl: 1000 })
119
- async getOrder(id: number) {
120
- return { id, total: 100 };
121
- }
122
- }
123
-
124
- await engine.start();
125
- const userInstance = engine.get(UserService);
126
- const orderInstance = engine.get(OrderService);
127
-
128
- await userInstance.getUser(1);
129
- await orderInstance.getOrder(1);
130
-
131
- const stats = await cachePlugin.getStats();
132
- expect(stats.entries.length).toBe(2);
133
-
134
- // 验证缓存键前缀
135
- const userKey = stats.entries.find((e) => e.key.startsWith("user-service:getUser:"));
136
- const orderKey = stats.entries.find((e) => e.key.startsWith("order-service:getOrder:"));
137
-
138
- expect(userKey).toBeDefined();
139
- expect(orderKey).toBeDefined();
140
- expect(userKey?.key).not.toBe(orderKey?.key); // 不同模块的相同参数应该有不同的键
141
-
142
- await engine.stop();
143
- });
144
-
145
- it("应该对 key 函数的返回值进行 ejson 序列化和 hash", async () => {
146
- @Module("test-module")
147
- class TestService {
148
- @Cache({
149
- ttl: 1000,
150
- key: (id: number, name: string) => ({
151
- id,
152
- name,
153
- date: new Date("2024-01-01"),
154
- map: new Map([["key", "value"]]),
155
- }),
156
- })
157
- async getData(id: number, name: string) {
158
- return { id, name };
159
- }
160
- }
161
-
162
- await engine.start();
163
- const instance = engine.get(TestService);
164
-
165
- // 相同参数应该使用相同的缓存键
166
- await instance.getData(1, "test");
167
- await instance.getData(1, "test");
168
-
169
- const stats = await cachePlugin.getStats();
170
- expect(stats.entries.length).toBe(1); // 应该只有一条缓存
171
-
172
- // 不同参数应该使用不同的缓存键
173
- await instance.getData(2, "test");
174
- expect((await cachePlugin.getStats()).entries.length).toBe(2);
175
-
176
- await engine.stop();
177
- });
178
-
179
- it("应该在不提供 key 函数时使用入参生成缓存键", async () => {
180
- @Module("test-module")
181
- class TestService {
182
- @Cache({ ttl: 1000 })
183
- async getData(id: number, name: string) {
184
- return { id, name };
185
- }
186
- }
187
-
188
- await engine.start();
189
- const instance = engine.get(TestService);
190
-
191
- await instance.getData(1, "test");
192
-
193
- const stats = await cachePlugin.getStats();
194
- expect(stats.entries.length).toBe(1);
195
- const cacheKey = stats.entries[0].key;
196
- // 缓存键格式:模块名:方法名:hash(hash 基于 args)
197
- expect(cacheKey).toMatch(/^test-module:getData:[a-f0-9]{64}$/);
198
-
199
- await engine.stop();
200
- });
201
-
202
- it("应该支持模块级默认TTL", async () => {
203
- @Module("test-module", {
204
- cacheDefaultTtl: 2000,
205
- })
206
- class TestService {
207
- @Cache() // 使用模块默认TTL
208
- async getData() {
209
- return { value: "data" };
210
- }
211
- }
212
-
213
- await engine.start();
214
- const instance = engine.get(TestService);
215
- await instance.getData();
216
-
217
- const stats = await cachePlugin.getStats();
218
- const entry = stats.entries[0];
219
- if (entry) {
220
- expect(entry.expiresAt - entry.createdAt).toBeGreaterThanOrEqual(2000);
221
- } else {
222
- throw new Error("No cache entry found");
223
- }
224
-
225
- await engine.stop();
226
- });
227
- });
228
-
229
- describe("缓存管理", () => {
230
- it("应该能够获取缓存统计信息", async () => {
231
- const stats = await cachePlugin.getStats();
232
- expect(stats).toHaveProperty("size");
233
- expect(stats).toHaveProperty("entries");
234
- expect(Array.isArray(stats.entries)).toBe(true);
235
- });
236
-
237
- it("应该能够清空所有缓存", async () => {
238
- await cachePlugin.clear();
239
- const stats = await cachePlugin.getStats();
240
- expect(stats.size).toBe(0);
241
- });
242
-
243
- it("应该能够删除指定的缓存项", async () => {
244
- @Module("test-module")
245
- class TestService {
246
- @Cache({ ttl: 1000 })
247
- async getData(id: number) {
248
- return { id };
249
- }
250
- }
251
-
252
- await engine.start();
253
- const instance = engine.get(TestService);
254
- await instance.getData(1);
255
-
256
- const stats = await cachePlugin.getStats();
257
- const key = stats.entries[0]?.key;
258
-
259
- if (key) {
260
- const deleted = await cachePlugin.delete(key);
261
- expect(deleted).toBe(true);
262
- const newStats = await cachePlugin.getStats();
263
- expect(newStats.size).toBe(0);
264
- }
265
-
266
- await engine.stop();
267
- });
268
- });
269
- });
@@ -1,26 +0,0 @@
1
- import { Handler } from "../../core/decorators";
2
- import { CacheOptions } from "./types";
3
-
4
- /**
5
- * Cache装饰器
6
- * 用于标记需要缓存的方法
7
- *
8
- * @example
9
- * ```typescript
10
- * @Cache({ ttl: 5000 })
11
- * async getUser(id: number) {
12
- * return { id, name: "John" };
13
- * }
14
- * ```
15
- */
16
- export function Cache(options: CacheOptions = {}) {
17
- return Handler({
18
- type: "cache",
19
- options: {
20
- ttl: options.ttl ?? 60000, // 默认1分钟
21
- key: options.key, // key 函数
22
- enabled: options.enabled ?? true,
23
- },
24
- });
25
- }
26
-
@@ -1,20 +0,0 @@
1
- /**
2
- * Cache Plugin - 缓存插件
3
- *
4
- * 提供缓存功能,支持多种存储后端(内存、Redis等),支持TTL和自定义键生成器
5
- */
6
-
7
- export { CachePlugin } from "./plugin";
8
- export { Cache } from "./decorator";
9
- export {
10
- CacheAdapter,
11
- MemoryCacheAdapter,
12
- RedisCacheAdapter,
13
- } from "./adapter";
14
- export type {
15
- CacheModuleOptions,
16
- CacheOptions,
17
- CacheItem,
18
- } from "./types";
19
- export type { RedisCacheAdapterOptions } from "./adapter";
20
-