cachimbo 0.0.1 → 0.0.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.
package/README.md CHANGED
@@ -1,23 +1,28 @@
1
- <img align="right" src="./docs/assets/cachimbo.png" alt="Cachimbo" width="150" height="150">
1
+ <p align="center">
2
+ <img width="200" src="https://raw.githubusercontent.com/Guichaguri/cachimbo/main/docs/assets/cachimbo.png">
3
+ </p>
2
4
 
3
- # cachimbo
5
+ <h1 align="center">Cachimbo</h1>
4
6
 
5
- Cachimbo is a caching library that allows you to layer different strategies in order to maximize the performance.
7
+ Cachimbo is an advanced caching library that allows you to layer different strategies in order to maximize the performance.
6
8
 
7
9
  ## Features
8
10
 
9
11
  - Supports external cache stores
10
12
  - Redis
13
+ - Valkey
11
14
  - Memcached
12
15
  - Cloudflare Workers KV
16
+ - Keyv
13
17
  - Supports in-memory cache stores
14
- - Least Recently Used (LRU)
15
- - Time To Live (TTL)
16
- - Map-based
18
+ - Least Recently Used (LRU) eviction
19
+ - Time-based (TTL) eviction
20
+ - FIFO eviction
17
21
  - Supports intermediary cache strategies
18
22
  - Request coalescing (deduplication)
19
23
  - Multi-layer caching (tiered cache)
20
24
  - Stale-While-Revalidate
25
+ - TTL jittering
21
26
  - Metrics collection
22
27
  - Easily extendable
23
28
 
@@ -65,25 +70,25 @@ In-memory caches offer extremely low latency since data is stored directly in th
65
70
 
66
71
  External caches (like Redis, Memcached, etc) provide fast, scalable, shared storage that can be accessed across multiple application instances. They offer high throughput, larger memory capacity, and centralized cache management beyond what in-memory caches can reliably provide.
67
72
 
68
- - [In-memory](./docs/stores/in-memory.md)
69
- - [Redis](docs/stores/redis-valkey.md) (and Valkey)
70
- - [Memcached](./docs/stores/memcached.md)
71
- - [Cloudflare Workers KV](./docs/stores/cloudflare-workers-kv.md)
72
- - [Keyv](./stores/keyv.md)
73
+ - [In-memory](/docs/stores/in-memory.md)
74
+ - [Redis](/docs/stores/redis-valkey.md) (and Valkey)
75
+ - [Memcached](/docs/stores/memcached.md)
76
+ - [Cloudflare Workers KV](/docs/stores/cloudflare-workers-kv.md)
77
+ - [Keyv](/docs/stores/keyv.md)
73
78
 
74
79
  ## Cache Layers
75
80
 
76
81
  These layers work just like "middlewares" but for caches, they customize how a cache is handled.
77
82
 
78
- - [Request Coalescing](./docs/layers/request-coalescing.md) (deduplication)
79
- - [Tiered Caching](./docs/layers/tiered.md) (multi-layer caching)
80
- - [Stale-While-Revalidate](./docs/layers/stale-while-revalidate.md)
81
- - [TTL Jittering](./docs/layers/jittering.md)
82
- - [Async/Lazy Initialization](./docs/layers/async-lazy.md)
83
- - [Key Transformation](./docs/layers/key-transformation.md)
84
- - [Metrics Collection](./docs/layers/metrics-collection.md)
83
+ - [Request Coalescing](/docs/layers/request-coalescing.md) (deduplication)
84
+ - [Tiered Caching](/docs/layers/tiered.md) (multi-layer caching)
85
+ - [Stale-While-Revalidate](/docs/layers/stale-while-revalidate.md)
86
+ - [TTL Jittering](/docs/layers/jittering.md)
87
+ - [Async/Lazy Initialization](/docs/layers/async-lazy.md)
88
+ - [Key Transformation](/docs/layers/key-transformation.md)
89
+ - [Metrics Collection](/docs/layers/metrics-collection.md)
85
90
 
86
91
  ## Guides
87
- - [Choosing the right combination of layers](./docs/guides/choosing-layers.md)
88
- - [Disabling cache](./docs/guides/disabling.md)
89
- - [Extending](./docs/guides/extending.md)
92
+ - [Choosing the right combination of layers](/docs/guides/choosing-layers.md)
93
+ - [Disabling cache](/docs/guides/disabling.md)
94
+ - [Extending](/docs/guides/extending.md)
package/dist/index.cjs CHANGED
@@ -40,6 +40,67 @@ var BaseCache = class {
40
40
  }
41
41
  };
42
42
 
43
+ //#endregion
44
+ //#region src/base/local.ts
45
+ var BaseLocalCache = class extends BaseCache {
46
+ disposeListeners = [];
47
+ /**
48
+ * Reads cached resources by their keys. (synchronous version)
49
+ * @protected
50
+ */
51
+ _getMany(keys) {
52
+ return Object.fromEntries(keys.map((key) => [key, this._get(key)]));
53
+ }
54
+ /**
55
+ * Writes resources into cache. (synchronous version)
56
+ * @protected
57
+ */
58
+ _setMany(data, options) {
59
+ for (const [key, value] of Object.entries(data)) this._set(key, value, options);
60
+ }
61
+ /**
62
+ * Deletes many cached resources by their keys. (synchronous version)
63
+ * @protected
64
+ */
65
+ _deleteMany(keys) {
66
+ for (const key of keys) this._delete(key);
67
+ }
68
+ /**
69
+ * Adds a listener that will be called when a cached item is disposed.
70
+ *
71
+ * @param listener The listener function to add.
72
+ * @protected
73
+ */
74
+ _addDisposeListener(listener) {
75
+ this.disposeListeners.push(listener);
76
+ }
77
+ get(key) {
78
+ return Promise.resolve(this._get(key));
79
+ }
80
+ set(key, value, options) {
81
+ this._set(key, value, options);
82
+ return Promise.resolve();
83
+ }
84
+ delete(key) {
85
+ this._delete(key);
86
+ return Promise.resolve();
87
+ }
88
+ getMany(keys) {
89
+ return Promise.resolve(this._getMany(keys));
90
+ }
91
+ setMany(data, options) {
92
+ this._setMany(data, options);
93
+ return Promise.resolve();
94
+ }
95
+ deleteMany(keys) {
96
+ this._deleteMany(keys);
97
+ return Promise.resolve();
98
+ }
99
+ onDispose(key, value, reason) {
100
+ for (const listener of this.disposeListeners) listener(key, value, reason);
101
+ }
102
+ };
103
+
43
104
  //#endregion
44
105
  //#region src/local/lru/index.ts
45
106
  /**
@@ -49,7 +110,7 @@ var BaseCache = class {
49
110
  *
50
111
  * Once the limit of items is reached, the least recently used items will be purged.
51
112
  */
52
- var LocalLRUCache = class extends BaseCache {
113
+ var LocalLRUCache = class extends BaseLocalCache {
53
114
  cache;
54
115
  shouldUseFetch;
55
116
  constructor(options = {}) {
@@ -62,16 +123,29 @@ var LocalLRUCache = class extends BaseCache {
62
123
  ttl: options.ttl ? options.ttl * 1e3 : void 0,
63
124
  max: options.max || 1e4,
64
125
  ttlAutopurge: false,
65
- fetchMethod: (_key, _staleValue, options$1) => options$1.context()
126
+ fetchMethod: (_key, _staleValue, options$1) => options$1.context(),
127
+ disposeAfter: (value, key, reason) => this.onDispose(key, value, reason)
66
128
  });
67
129
  this.shouldUseFetch = true;
68
130
  }
69
131
  }
70
- async get(key) {
132
+ /** @internal */
133
+ _get(key) {
71
134
  this.logger?.debug(this.name, "[get]", "key =", key);
72
135
  const data = this.cache.get(key);
73
136
  return data === void 0 ? null : data;
74
137
  }
138
+ /** @internal */
139
+ _set(key, value, options) {
140
+ this.logger?.debug(this.name, "[set]", "key =", key);
141
+ const ttl = options?.ttl;
142
+ this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
143
+ }
144
+ /** @internal */
145
+ _delete(key) {
146
+ this.logger?.debug(this.name, "[delete]", "key =", key);
147
+ this.cache.delete(key);
148
+ }
75
149
  getOrLoad(key, load, options) {
76
150
  if (!this.shouldUseFetch) return super.getOrLoad(key, load, options);
77
151
  this.logger?.debug(this.name, "[getOrLoad] Running LRUCache's fetch...", "key =", key);
@@ -81,15 +155,6 @@ var LocalLRUCache = class extends BaseCache {
81
155
  ttl: ttl ? ttl * 1e3 : void 0
82
156
  });
83
157
  }
84
- async set(key, value, options) {
85
- this.logger?.debug(this.name, "[set]", "key =", key);
86
- const ttl = options?.ttl;
87
- this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
88
- }
89
- async delete(key) {
90
- this.logger?.debug(this.name, "[delete]", "key =", key);
91
- this.cache.delete(key);
92
- }
93
158
  };
94
159
 
95
160
  //#endregion
@@ -99,27 +164,31 @@ var LocalLRUCache = class extends BaseCache {
99
164
  *
100
165
  * Once the limit of items is reached, the soonest expiring items will be purged.
101
166
  */
102
- var LocalTTLCache = class extends BaseCache {
167
+ var LocalTTLCache = class extends BaseLocalCache {
103
168
  cache;
104
169
  constructor(options = {}) {
105
170
  super(options);
106
171
  if ("cache" in options) this.cache = options.cache;
107
172
  else this.cache = new __isaacs_ttlcache.TTLCache({
108
173
  max: options.max,
109
- ttl: options.ttl ? options.ttl * 1e3 : void 0
174
+ ttl: options.ttl ? options.ttl * 1e3 : void 0,
175
+ dispose: (value, key, reason) => this.onDispose(key, value, reason)
110
176
  });
111
177
  }
112
- async get(key) {
178
+ /** @internal */
179
+ _get(key) {
113
180
  this.logger?.debug(this.name, "[get]", "key =", key);
114
181
  const data = this.cache.get(key);
115
182
  return data === void 0 ? null : data;
116
183
  }
117
- async set(key, value, options) {
184
+ /** @internal */
185
+ _set(key, value, options) {
118
186
  this.logger?.debug(this.name, "[set]", "key =", key);
119
187
  const ttl = options?.ttl;
120
188
  this.cache.set(key, value, { ttl: ttl ? ttl * 1e3 : void 0 });
121
189
  }
122
- async delete(key) {
190
+ /** @internal */
191
+ _delete(key) {
123
192
  this.logger?.debug(this.name, "[delete]", "key =", key);
124
193
  this.cache.delete(key);
125
194
  }
@@ -132,9 +201,10 @@ var LocalTTLCache = class extends BaseCache {
132
201
  *
133
202
  * It ignores expiration times, but a limit of cached items can be set.
134
203
  *
204
+ * It implements a simple FIFO eviction policy:
135
205
  * Once the limit of items is reached, the first inserted keys will be purged.
136
206
  */
137
- var LocalMapCache = class extends BaseCache {
207
+ var LocalMapCache = class extends BaseLocalCache {
138
208
  cache;
139
209
  max;
140
210
  constructor(options = {}) {
@@ -142,38 +212,55 @@ var LocalMapCache = class extends BaseCache {
142
212
  this.cache = options.cache ?? /* @__PURE__ */ new Map();
143
213
  this.max = options.max ?? Infinity;
144
214
  }
145
- async get(key) {
215
+ /** @internal */
216
+ _get(key) {
146
217
  this.logger?.debug(this.name, "[get]", "key =", key);
147
218
  const data = this.cache.get(key);
148
219
  return data === void 0 ? null : data;
149
220
  }
150
- async set(key, value, options) {
221
+ /** @internal */
222
+ _set(key, value, options) {
151
223
  this.logger?.debug(this.name, "[set]", "key =", key);
152
- if (this.cache.size >= this.max && !this.cache.has(key)) this.evict(1);
224
+ const previousValue = this.cache.get(key);
225
+ if (this.cache.size >= this.max && previousValue === void 0) this.evict(1);
153
226
  this.cache.set(key, value);
227
+ this.onDispose(key, previousValue, "set");
154
228
  }
155
- async delete(key) {
229
+ /** @internal */
230
+ _delete(key) {
156
231
  this.logger?.debug(this.name, "[delete]", "key =", key);
232
+ const previousValue = this.cache.get(key);
157
233
  this.cache.delete(key);
234
+ this.onDispose(key, previousValue, "delete");
158
235
  }
159
236
  async setMany(data, options) {
160
237
  this.logger?.debug(this.name, "[setMany]", "data =", data);
161
238
  const entries = Object.entries(data);
162
239
  const newEntries = entries.filter(([key]) => !this.cache.has(key)).length;
163
240
  if (this.cache.size + newEntries > this.max) this.evict(this.cache.size + newEntries - this.max);
164
- for (const [key, value] of entries) this.cache.set(key, value);
241
+ for (const [key, value] of entries) {
242
+ const previousValue = this.cache.get(key);
243
+ this.cache.set(key, value);
244
+ this.onDispose(key, previousValue, "set");
245
+ }
165
246
  }
166
247
  clear() {
167
248
  this.logger?.debug(this.name, "[clear]");
249
+ for (const key of this.cache.keys()) this.onDispose(key, this.cache.get(key), "delete");
168
250
  this.cache.clear();
169
251
  }
252
+ onDispose(key, value, reason) {
253
+ if (value !== void 0) super.onDispose(key, value, reason);
254
+ }
170
255
  evict(length) {
171
256
  const keys = this.cache.keys();
172
257
  for (let i = 0; i < length; i++) {
173
258
  const key = keys.next();
174
259
  if (key.done) break;
175
260
  this.logger?.debug(this.name, "[evict]", "key = ", key);
261
+ const previousValue = this.cache.get(key.value);
176
262
  this.cache.delete(key.value);
263
+ this.onDispose(key.value, previousValue, "evict");
177
264
  }
178
265
  }
179
266
  };
@@ -182,7 +269,7 @@ var LocalMapCache = class extends BaseCache {
182
269
  //#region src/local/noop/index.ts
183
270
  /**
184
271
  * A cache implementation that does nothing.
185
- * It's useful for disabling cache.
272
+ * It's useful for disabling cache and unit testing.
186
273
  *
187
274
  * @example
188
275
  * ```ts
@@ -214,12 +301,14 @@ var NoOpCache = class {
214
301
  var IORedisCache = class extends BaseCache {
215
302
  client;
216
303
  defaultTTL;
304
+ isUNLINKSupported;
217
305
  isMSETEXSupported;
218
306
  constructor(options) {
219
307
  super(options);
220
308
  this.client = options.client;
221
309
  this.defaultTTL = options.defaultTTL;
222
- this.isMSETEXSupported = options.isMSETEXSupported;
310
+ this.isUNLINKSupported = options.isUNLINKSupported ?? true;
311
+ this.isMSETEXSupported = options.isMSETEXSupported ?? false;
223
312
  }
224
313
  async get(key) {
225
314
  this.logger?.debug(this.name, "[get] Running \"GET\" command...", "key =", key);
@@ -234,8 +323,13 @@ var IORedisCache = class extends BaseCache {
234
323
  else await this.client.set(key, raw);
235
324
  }
236
325
  async delete(key) {
237
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
238
- await this.client.del(key);
326
+ if (this.isUNLINKSupported) {
327
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
328
+ await this.client.unlink(key);
329
+ } else {
330
+ this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
331
+ await this.client.del(key);
332
+ }
239
333
  }
240
334
  async getMany(keys) {
241
335
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -256,8 +350,13 @@ var IORedisCache = class extends BaseCache {
256
350
  await this.client.call("MSETEX", entries.length, ...raw, ...ttl ? ["EX", ttl] : []);
257
351
  }
258
352
  async deleteMany(keys) {
259
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
260
- await this.client.del(keys);
353
+ if (this.isUNLINKSupported) {
354
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
355
+ await this.client.unlink(keys);
356
+ } else {
357
+ this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
358
+ await this.client.del(keys);
359
+ }
261
360
  }
262
361
  };
263
362
 
@@ -269,12 +368,14 @@ var IORedisCache = class extends BaseCache {
269
368
  var RedisCache = class extends BaseCache {
270
369
  client;
271
370
  defaultTTL;
371
+ isUNLINKSupported;
272
372
  isMSETEXSupported;
273
373
  constructor(options) {
274
374
  super(options);
275
375
  this.client = options.client;
276
376
  this.defaultTTL = options.defaultTTL;
277
- this.isMSETEXSupported = options.isMSETEXSupported;
377
+ this.isUNLINKSupported = options.isUNLINKSupported ?? true;
378
+ this.isMSETEXSupported = options.isMSETEXSupported ?? false;
278
379
  }
279
380
  async get(key) {
280
381
  this.logger?.debug(this.name, "[get] Running \"GET\" command...", "key =", key);
@@ -290,8 +391,13 @@ var RedisCache = class extends BaseCache {
290
391
  } : void 0 });
291
392
  }
292
393
  async delete(key) {
293
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
294
- await this.client.del(key);
394
+ if (this.isUNLINKSupported) {
395
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
396
+ await this.client.unlink(key);
397
+ } else {
398
+ this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
399
+ await this.client.del(key);
400
+ }
295
401
  }
296
402
  async getMany(keys) {
297
403
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -315,8 +421,13 @@ var RedisCache = class extends BaseCache {
315
421
  } : void 0 });
316
422
  }
317
423
  async deleteMany(keys) {
318
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
319
- await this.client.del(keys);
424
+ if (this.isUNLINKSupported) {
425
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
426
+ await this.client.unlink(keys);
427
+ } else {
428
+ this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
429
+ await this.client.del(keys);
430
+ }
320
431
  }
321
432
  };
322
433
 
@@ -347,8 +458,8 @@ var ValkeyGlideCache = class extends BaseCache {
347
458
  } : void 0 });
348
459
  }
349
460
  async delete(key) {
350
- this.logger?.debug(this.name, "[delete] Running \"DEL\" command...", "key =", key);
351
- await this.client.del([key]);
461
+ this.logger?.debug(this.name, "[delete] Running \"UNLINK\" command...", "key =", key);
462
+ await this.client.unlink([key]);
352
463
  }
353
464
  async getMany(keys) {
354
465
  this.logger?.debug(this.name, "[getMany] Running \"MGET\" command...", "keys =", keys);
@@ -361,8 +472,8 @@ var ValkeyGlideCache = class extends BaseCache {
361
472
  return data;
362
473
  }
363
474
  async deleteMany(keys) {
364
- this.logger?.debug(this.name, "[deleteMany] Running \"DEL\" command...", "keys =", keys);
365
- await this.client.del(keys);
475
+ this.logger?.debug(this.name, "[deleteMany] Running \"UNLINK\" command...", "keys =", keys);
476
+ await this.client.unlink(keys);
366
477
  }
367
478
  };
368
479
 
package/dist/index.d.cts CHANGED
@@ -119,6 +119,56 @@ declare abstract class BaseCache implements ICache {
119
119
  deleteMany(keys: string[]): Promise<void>;
120
120
  }
121
121
  //#endregion
122
+ //#region src/base/local.d.ts
123
+ type LocalCacheDisposeListener<T = any> = (key: string, value: T, reason?: string) => void;
124
+ declare abstract class BaseLocalCache extends BaseCache {
125
+ protected disposeListeners: LocalCacheDisposeListener[];
126
+ /**
127
+ * Reads the cached resource from a key (synchronous version)
128
+ * @protected
129
+ */
130
+ abstract _get<T>(key: string): T | null;
131
+ /**
132
+ * Writes a resource into cache (synchronous version)
133
+ * @protected
134
+ */
135
+ abstract _set<T>(key: string, value: T, options?: SetCacheOptions): void;
136
+ /**
137
+ * Deletes a cached resource by a key. (synchronous version)
138
+ * @protected
139
+ */
140
+ abstract _delete(key: string): void;
141
+ /**
142
+ * Reads cached resources by their keys. (synchronous version)
143
+ * @protected
144
+ */
145
+ _getMany<T>(keys: string[]): Record<string, T | null>;
146
+ /**
147
+ * Writes resources into cache. (synchronous version)
148
+ * @protected
149
+ */
150
+ _setMany<T>(data: Record<string, T>, options?: SetCacheOptions): void;
151
+ /**
152
+ * Deletes many cached resources by their keys. (synchronous version)
153
+ * @protected
154
+ */
155
+ _deleteMany(keys: string[]): void;
156
+ /**
157
+ * Adds a listener that will be called when a cached item is disposed.
158
+ *
159
+ * @param listener The listener function to add.
160
+ * @protected
161
+ */
162
+ _addDisposeListener(listener: LocalCacheDisposeListener): void;
163
+ get<T>(key: string): Promise<T | null>;
164
+ set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;
165
+ delete(key: string): Promise<void>;
166
+ getMany<T>(keys: string[]): Promise<Record<string, T | null>>;
167
+ setMany<T>(data: Record<string, T>, options?: SetCacheOptions): Promise<void>;
168
+ deleteMany(keys: string[]): Promise<void>;
169
+ protected onDispose(key: string, value: any, reason?: string): void;
170
+ }
171
+ //#endregion
122
172
  //#region src/local/lru/index.d.ts
123
173
  interface ExistingLRUCacheOptions extends BaseCacheOptions {
124
174
  /**
@@ -154,14 +204,11 @@ interface LocalLRUCacheOptions extends BaseCacheOptions {
154
204
  *
155
205
  * Once the limit of items is reached, the least recently used items will be purged.
156
206
  */
157
- declare class LocalLRUCache extends BaseCache {
207
+ declare class LocalLRUCache extends BaseLocalCache {
158
208
  protected readonly cache: LRUCache<string, any, () => Promise<any>>;
159
209
  protected shouldUseFetch?: boolean;
160
210
  constructor(options?: LocalLRUCacheOptions | ExistingLRUCacheOptions);
161
- get<T>(key: string): Promise<T | null>;
162
211
  getOrLoad<T>(key: string, load: () => Promise<T>, options?: SetCacheOptions): Promise<T>;
163
- set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;
164
- delete(key: string): Promise<void>;
165
212
  }
166
213
  //#endregion
167
214
  //#region src/local/ttl/index.d.ts
@@ -186,12 +233,9 @@ interface LocalTTLCacheOptions extends BaseCacheOptions {
186
233
  *
187
234
  * Once the limit of items is reached, the soonest expiring items will be purged.
188
235
  */
189
- declare class LocalTTLCache extends BaseCache {
236
+ declare class LocalTTLCache extends BaseLocalCache {
190
237
  protected readonly cache: TTLCache<string, any>;
191
238
  constructor(options?: LocalTTLCacheOptions | ExistingTTLCacheOptions);
192
- get<T>(key: string): Promise<T | null>;
193
- set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;
194
- delete(key: string): Promise<void>;
195
239
  }
196
240
  //#endregion
197
241
  //#region src/local/map/index.d.ts
@@ -220,24 +264,23 @@ interface MapLike<K, V> {
220
264
  *
221
265
  * It ignores expiration times, but a limit of cached items can be set.
222
266
  *
267
+ * It implements a simple FIFO eviction policy:
223
268
  * Once the limit of items is reached, the first inserted keys will be purged.
224
269
  */
225
- declare class LocalMapCache extends BaseCache {
270
+ declare class LocalMapCache extends BaseLocalCache {
226
271
  protected readonly cache: MapLike<string, any>;
227
272
  protected max: number;
228
273
  constructor(options?: LocalMapCacheOptions);
229
- get<T>(key: string): Promise<T | null>;
230
- set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;
231
- delete(key: string): Promise<void>;
232
274
  setMany(data: Record<string, any>, options?: SetCacheOptions): Promise<void>;
233
275
  clear(): void;
276
+ protected onDispose(key: string, value: any, reason?: string): void;
234
277
  protected evict(length: number): void;
235
278
  }
236
279
  //#endregion
237
280
  //#region src/local/noop/index.d.ts
238
281
  /**
239
282
  * A cache implementation that does nothing.
240
- * It's useful for disabling cache.
283
+ * It's useful for disabling cache and unit testing.
241
284
  *
242
285
  * @example
243
286
  * ```ts
@@ -265,6 +308,17 @@ interface IORedisCacheOptions extends BaseCacheOptions {
265
308
  * The default Time To Live in seconds
266
309
  */
267
310
  defaultTTL?: number;
311
+ /**
312
+ * Indicates whether the Redis server supports the UNLINK command.
313
+ *
314
+ * {@link IORedisCache#delete} and {@link IORedisCache#deleteMany} will use UNLINK instead of DEL if this
315
+ * option is set to `true`. This is recommended to improve the deletion performance.
316
+ *
317
+ * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.
318
+ *
319
+ * @defaultValue true
320
+ */
321
+ isUNLINKSupported?: boolean;
268
322
  /**
269
323
  * Indicates whether the Redis server supports the MSETEX command.
270
324
  *
@@ -272,6 +326,8 @@ interface IORedisCacheOptions extends BaseCacheOptions {
272
326
  *
273
327
  * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.
274
328
  * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)
329
+ *
330
+ * @defaultValue false
275
331
  */
276
332
  isMSETEXSupported?: boolean;
277
333
  }
@@ -281,7 +337,8 @@ interface IORedisCacheOptions extends BaseCacheOptions {
281
337
  declare class IORedisCache extends BaseCache {
282
338
  protected readonly client: Redis | Redis$1;
283
339
  protected defaultTTL?: number;
284
- protected isMSETEXSupported?: boolean;
340
+ protected isUNLINKSupported: boolean;
341
+ protected isMSETEXSupported: boolean;
285
342
  constructor(options: IORedisCacheOptions);
286
343
  get<T>(key: string): Promise<T | null>;
287
344
  set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;
@@ -303,12 +360,26 @@ interface RedisCacheOptions extends BaseCacheOptions {
303
360
  */
304
361
  defaultTTL?: number;
305
362
  /**
306
- * Indicates whether the Redis server supports MSETEX command.
363
+ * Indicates whether the Redis server supports the UNLINK command.
364
+ *
365
+ * {@link RedisCache#delete} and {@link RedisCache#deleteMany} will use UNLINK instead of DEL if this
366
+ * option is set to `true`. This is recommended to improve the deletion performance.
367
+ *
368
+ * This option should be set to `true` if the server runs Redis OSS 4.0.0 or above.
369
+ *
370
+ * @defaultValue true
371
+ */
372
+ isUNLINKSupported?: boolean;
373
+ /**
374
+ * Indicates whether the Redis server supports the MSETEX command.
307
375
  *
308
376
  * {@link RedisCache#setMany} will use MSETEX if this option is set to `true`.
377
+ * This is recommended to improve the performance of setting multiple items.
309
378
  *
310
379
  * This option should be set to `true` if the server runs Redis OSS 8.4.0 or above.
311
380
  * Valkey does not support this yet. (see https://github.com/valkey-io/valkey/issues/2592)
381
+ *
382
+ * @defaultValue false
312
383
  */
313
384
  isMSETEXSupported?: boolean;
314
385
  }
@@ -318,7 +389,8 @@ interface RedisCacheOptions extends BaseCacheOptions {
318
389
  declare class RedisCache extends BaseCache {
319
390
  protected readonly client: Redis$2;
320
391
  protected defaultTTL?: number;
321
- protected isMSETEXSupported?: boolean;
392
+ protected isUNLINKSupported: boolean;
393
+ protected isMSETEXSupported: boolean;
322
394
  constructor(options: RedisCacheOptions);
323
395
  get<T>(key: string): Promise<T | null>;
324
396
  set<T>(key: string, value: T, options?: SetCacheOptions): Promise<void>;