@devbro/neko-cache 0.1.4 → 0.1.5
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/CacheProviderInterface.d.mts +30 -0
- package/dist/cache.d.mts +53 -3
- package/dist/cache.mjs +45 -3
- package/dist/cache.mjs.map +1 -1
- package/dist/index.js +235 -3
- package/dist/index.js.map +1 -1
- package/dist/providers/DisabledCacheProvider.d.mts +34 -0
- package/dist/providers/DisabledCacheProvider.mjs +30 -0
- package/dist/providers/DisabledCacheProvider.mjs.map +1 -1
- package/dist/providers/FileCacheProvider.d.mts +59 -0
- package/dist/providers/FileCacheProvider.mjs +49 -0
- package/dist/providers/FileCacheProvider.mjs.map +1 -1
- package/dist/providers/MemcacheCacheProvider.d.mts +40 -0
- package/dist/providers/MemcacheCacheProvider.mjs +31 -0
- package/dist/providers/MemcacheCacheProvider.mjs.map +1 -1
- package/dist/providers/MemoryCacheProvider.d.mts +53 -0
- package/dist/providers/MemoryCacheProvider.mjs +43 -0
- package/dist/providers/MemoryCacheProvider.mjs.map +1 -1
- package/dist/providers/RedisCacheProvider.d.mts +41 -0
- package/dist/providers/RedisCacheProvider.mjs +37 -0
- package/dist/providers/RedisCacheProvider.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -43,27 +43,67 @@ module.exports = __toCommonJS(index_exports);
|
|
|
43
43
|
// src/cache.mts
|
|
44
44
|
var import_crypto = require("crypto");
|
|
45
45
|
var Cache = class {
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new Cache instance.
|
|
48
|
+
* @param provider - The cache provider implementation to use
|
|
49
|
+
*/
|
|
46
50
|
constructor(provider) {
|
|
47
51
|
this.provider = provider;
|
|
48
52
|
}
|
|
49
53
|
static {
|
|
50
54
|
__name(this, "Cache");
|
|
51
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Retrieves a value from the cache.
|
|
58
|
+
* @template T - The expected type of the cached value
|
|
59
|
+
* @param key - The cache key (can be string, number, object, or array)
|
|
60
|
+
* @returns The cached value or undefined if not found or expired
|
|
61
|
+
*/
|
|
52
62
|
async get(key) {
|
|
53
63
|
return this.provider.get(this.generateKey(key));
|
|
54
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Stores a value in the cache.
|
|
67
|
+
* @param key - The cache key (can be string, number, object, or array)
|
|
68
|
+
* @param value - The value to cache
|
|
69
|
+
* @param ttl - Time to live in seconds (optional)
|
|
70
|
+
*/
|
|
55
71
|
async put(key, value, ttl) {
|
|
56
72
|
return this.provider.put(this.generateKey(key), value, ttl);
|
|
57
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Deletes a value from the cache.
|
|
76
|
+
* @param key - The cache key to delete
|
|
77
|
+
*/
|
|
58
78
|
async delete(key) {
|
|
59
79
|
return this.provider.delete(this.generateKey(key));
|
|
60
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Checks if a key exists in the cache.
|
|
83
|
+
* @param key - The cache key to check
|
|
84
|
+
* @returns True if the key exists and has not expired, false otherwise
|
|
85
|
+
*/
|
|
61
86
|
async has(key) {
|
|
62
87
|
return this.provider.has(this.generateKey(key));
|
|
63
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Increments a numeric value in the cache atomically.
|
|
91
|
+
* @param key - The cache key to increment
|
|
92
|
+
* @param amount - The amount to increment by (default: 1)
|
|
93
|
+
* @returns The new value after incrementing
|
|
94
|
+
*/
|
|
64
95
|
async increment(key, amount = 1) {
|
|
65
96
|
return this.provider.increment(this.generateKey(key), amount);
|
|
66
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Gets a value from cache or executes callback and caches the result.
|
|
100
|
+
* This is useful for caching expensive operations.
|
|
101
|
+
* @template T - The expected type of the value
|
|
102
|
+
* @param key - The cache key
|
|
103
|
+
* @param callback - Function to execute if cache miss occurs
|
|
104
|
+
* @param options - Cache options including TTL (default: 3600 seconds)
|
|
105
|
+
* @returns The cached value or the result of the callback
|
|
106
|
+
*/
|
|
67
107
|
async remember(key, callback, options = {}) {
|
|
68
108
|
options.ttl = options.ttl ?? 3600;
|
|
69
109
|
const cached = await this.get(key);
|
|
@@ -75,9 +115,11 @@ var Cache = class {
|
|
|
75
115
|
return result;
|
|
76
116
|
}
|
|
77
117
|
/**
|
|
78
|
-
* Generates a cache key by serializing and
|
|
79
|
-
*
|
|
80
|
-
*
|
|
118
|
+
* Generates a cache key by serializing and hashing complex keys.
|
|
119
|
+
* Simple string keys under 250 characters are returned as-is.
|
|
120
|
+
* Complex keys (objects, arrays, long strings) are MD5 hashed.
|
|
121
|
+
* @param key - The key to generate a cache key from
|
|
122
|
+
* @returns A string suitable for use as a cache key
|
|
81
123
|
*/
|
|
82
124
|
generateKey(key) {
|
|
83
125
|
if (typeof key === "string" && key.length <= 250) {
|
|
@@ -91,6 +133,10 @@ var Cache = class {
|
|
|
91
133
|
var import_redis = require("redis");
|
|
92
134
|
var RedisCacheProvider = class {
|
|
93
135
|
// default TTL in seconds
|
|
136
|
+
/**
|
|
137
|
+
* Creates a new RedisCacheProvider instance.
|
|
138
|
+
* @param config - Redis client configuration options
|
|
139
|
+
*/
|
|
94
140
|
constructor(config) {
|
|
95
141
|
this.config = config;
|
|
96
142
|
this.client = this.createRedisClient();
|
|
@@ -101,15 +147,27 @@ var RedisCacheProvider = class {
|
|
|
101
147
|
}
|
|
102
148
|
client;
|
|
103
149
|
defaultTTL = 3600;
|
|
150
|
+
/**
|
|
151
|
+
* Creates a Redis client with the provided configuration.
|
|
152
|
+
* @returns A Redis client instance
|
|
153
|
+
*/
|
|
104
154
|
createRedisClient() {
|
|
105
155
|
let rc = (0, import_redis.createClient)(this.config);
|
|
106
156
|
return rc;
|
|
107
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Ensures the Redis client is connected before performing operations.
|
|
160
|
+
*/
|
|
108
161
|
async ensureConnection() {
|
|
109
162
|
if (!this.client.isOpen) {
|
|
110
163
|
await this.client.connect();
|
|
111
164
|
}
|
|
112
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Retrieves a value from the cache.
|
|
168
|
+
* @param key - The cache key
|
|
169
|
+
* @returns The cached value or undefined if not found
|
|
170
|
+
*/
|
|
113
171
|
async get(key) {
|
|
114
172
|
await this.ensureConnection();
|
|
115
173
|
let rc = this.client.get(key);
|
|
@@ -120,6 +178,12 @@ var RedisCacheProvider = class {
|
|
|
120
178
|
return JSON.parse(value);
|
|
121
179
|
});
|
|
122
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Stores a value in the cache.
|
|
183
|
+
* @param key - The cache key
|
|
184
|
+
* @param value - The value to cache
|
|
185
|
+
* @param ttl - Time to live in seconds (optional)
|
|
186
|
+
*/
|
|
123
187
|
async put(key, value, ttl) {
|
|
124
188
|
await this.ensureConnection();
|
|
125
189
|
const serializedValue = JSON.stringify(value);
|
|
@@ -130,15 +194,30 @@ var RedisCacheProvider = class {
|
|
|
130
194
|
await this.client.set(key, serializedValue);
|
|
131
195
|
}
|
|
132
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Deletes a value from the cache.
|
|
199
|
+
* @param key - The cache key to delete
|
|
200
|
+
*/
|
|
133
201
|
async delete(key) {
|
|
134
202
|
await this.ensureConnection();
|
|
135
203
|
await this.client.del(key);
|
|
136
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Checks if a key exists in the cache.
|
|
207
|
+
* @param key - The cache key to check
|
|
208
|
+
* @returns True if the key exists, false otherwise
|
|
209
|
+
*/
|
|
137
210
|
async has(key) {
|
|
138
211
|
await this.ensureConnection();
|
|
139
212
|
const result = await this.client.exists(key);
|
|
140
213
|
return result === 1;
|
|
141
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Increments a numeric value in the cache atomically using Redis INCRBY.
|
|
217
|
+
* @param key - The cache key to increment
|
|
218
|
+
* @param amount - The amount to increment by (default: 1)
|
|
219
|
+
* @returns The new value after incrementing
|
|
220
|
+
*/
|
|
142
221
|
async increment(key, amount = 1) {
|
|
143
222
|
await this.ensureConnection();
|
|
144
223
|
return await this.client.incrBy(key, amount);
|
|
@@ -158,11 +237,18 @@ var FileCacheProvider = class {
|
|
|
158
237
|
cleanupInterval: 300 * 1e3
|
|
159
238
|
};
|
|
160
239
|
cleanupTimer;
|
|
240
|
+
/**
|
|
241
|
+
* Creates a new FileCacheProvider instance.
|
|
242
|
+
* @param config - Configuration options for the cache
|
|
243
|
+
*/
|
|
161
244
|
constructor(config = {}) {
|
|
162
245
|
this.config = { ...this.config, ...config };
|
|
163
246
|
this.ensureCacheDirectory();
|
|
164
247
|
this.startCleanupTimer();
|
|
165
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Ensures the cache directory exists, creating it if necessary.
|
|
251
|
+
*/
|
|
166
252
|
async ensureCacheDirectory() {
|
|
167
253
|
try {
|
|
168
254
|
await fs.access(this.config.cacheDirectory);
|
|
@@ -170,6 +256,9 @@ var FileCacheProvider = class {
|
|
|
170
256
|
await fs.mkdir(this.config.cacheDirectory, { recursive: true });
|
|
171
257
|
}
|
|
172
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Starts the automatic cleanup timer for expired entries.
|
|
261
|
+
*/
|
|
173
262
|
startCleanupTimer() {
|
|
174
263
|
if (this.config.cleanupInterval > 0) {
|
|
175
264
|
this.cleanupTimer = setInterval(() => {
|
|
@@ -177,16 +266,27 @@ var FileCacheProvider = class {
|
|
|
177
266
|
}, this.config.cleanupInterval);
|
|
178
267
|
}
|
|
179
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Stops the automatic cleanup timer.
|
|
271
|
+
*/
|
|
180
272
|
stopCleanupTimer() {
|
|
181
273
|
if (this.cleanupTimer) {
|
|
182
274
|
clearInterval(this.cleanupTimer);
|
|
183
275
|
this.cleanupTimer = void 0;
|
|
184
276
|
}
|
|
185
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Generates a safe file path for the given cache key.
|
|
280
|
+
* @param key - The cache key
|
|
281
|
+
* @returns The full file path for the cache entry
|
|
282
|
+
*/
|
|
186
283
|
getFilePath(key) {
|
|
187
284
|
const safeKey = key.replace(/[^a-z0-9]/gi, "_");
|
|
188
285
|
return path.join(this.config.cacheDirectory, `${safeKey}.json`);
|
|
189
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Removes all expired cache entries from the cache directory.
|
|
289
|
+
*/
|
|
190
290
|
async cleanupExpiredEntries() {
|
|
191
291
|
try {
|
|
192
292
|
const files = await fs.readdir(this.config.cacheDirectory);
|
|
@@ -209,6 +309,11 @@ var FileCacheProvider = class {
|
|
|
209
309
|
} catch (error) {
|
|
210
310
|
}
|
|
211
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Retrieves a value from the cache.
|
|
314
|
+
* @param key - The cache key
|
|
315
|
+
* @returns The cached value or undefined if not found or expired
|
|
316
|
+
*/
|
|
212
317
|
async get(key) {
|
|
213
318
|
const filePath = this.getFilePath(key);
|
|
214
319
|
try {
|
|
@@ -224,6 +329,12 @@ var FileCacheProvider = class {
|
|
|
224
329
|
return void 0;
|
|
225
330
|
}
|
|
226
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Stores a value in the cache.
|
|
334
|
+
* @param key - The cache key
|
|
335
|
+
* @param value - The value to cache
|
|
336
|
+
* @param ttl - Time to live in seconds (optional)
|
|
337
|
+
*/
|
|
227
338
|
async put(key, value, ttl) {
|
|
228
339
|
const filePath = this.getFilePath(key);
|
|
229
340
|
const now = Date.now();
|
|
@@ -236,6 +347,10 @@ var FileCacheProvider = class {
|
|
|
236
347
|
this.ensureCacheDirectory();
|
|
237
348
|
await fs.writeFile(filePath, JSON.stringify(item), "utf-8");
|
|
238
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Deletes a value from the cache.
|
|
352
|
+
* @param key - The cache key to delete
|
|
353
|
+
*/
|
|
239
354
|
async delete(key) {
|
|
240
355
|
const filePath = this.getFilePath(key);
|
|
241
356
|
try {
|
|
@@ -243,10 +358,23 @@ var FileCacheProvider = class {
|
|
|
243
358
|
} catch {
|
|
244
359
|
}
|
|
245
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Checks if a key exists in the cache and has not expired.
|
|
363
|
+
* @param key - The cache key to check
|
|
364
|
+
* @returns True if the key exists and is not expired, false otherwise
|
|
365
|
+
*/
|
|
246
366
|
async has(key) {
|
|
247
367
|
const value = await this.get(key);
|
|
248
368
|
return value !== void 0;
|
|
249
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Increments a numeric value in the cache atomically using file-based locking.
|
|
372
|
+
* If the key doesn't exist or is expired, it starts from 0.
|
|
373
|
+
* @param key - The cache key to increment
|
|
374
|
+
* @param amount - The amount to increment by (default: 1)
|
|
375
|
+
* @returns The new value after incrementing
|
|
376
|
+
* @throws Error if lock cannot be acquired after maximum retries
|
|
377
|
+
*/
|
|
250
378
|
async increment(key, amount = 1) {
|
|
251
379
|
const filePath = this.getFilePath(key);
|
|
252
380
|
const lockPath = `${filePath}.lock`;
|
|
@@ -310,10 +438,17 @@ var MemoryCacheProvider = class {
|
|
|
310
438
|
// 10 minutes
|
|
311
439
|
};
|
|
312
440
|
cleanupTimer;
|
|
441
|
+
/**
|
|
442
|
+
* Creates a new MemoryCacheProvider instance.
|
|
443
|
+
* @param config - Configuration options for the cache
|
|
444
|
+
*/
|
|
313
445
|
constructor(config = {}) {
|
|
314
446
|
this.config = { ...this.config, ...config };
|
|
315
447
|
this.startCleanupTimer();
|
|
316
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Starts the automatic cleanup timer for expired entries.
|
|
451
|
+
*/
|
|
317
452
|
startCleanupTimer() {
|
|
318
453
|
if (this.config.cleanupInterval > 0) {
|
|
319
454
|
this.cleanupTimer = setInterval(() => {
|
|
@@ -321,12 +456,18 @@ var MemoryCacheProvider = class {
|
|
|
321
456
|
}, this.config.cleanupInterval * 1e3);
|
|
322
457
|
}
|
|
323
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Stops the automatic cleanup timer.
|
|
461
|
+
*/
|
|
324
462
|
stopCleanupTimer() {
|
|
325
463
|
if (this.cleanupTimer) {
|
|
326
464
|
clearInterval(this.cleanupTimer);
|
|
327
465
|
this.cleanupTimer = void 0;
|
|
328
466
|
}
|
|
329
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Removes all expired entries from the cache.
|
|
470
|
+
*/
|
|
330
471
|
cleanupExpiredEntries() {
|
|
331
472
|
const now = Date.now();
|
|
332
473
|
for (const [key, item] of this.cache.entries()) {
|
|
@@ -335,6 +476,9 @@ var MemoryCacheProvider = class {
|
|
|
335
476
|
}
|
|
336
477
|
}
|
|
337
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Evicts the least recently used item if cache size exceeds maximum.
|
|
481
|
+
*/
|
|
338
482
|
evictLRU() {
|
|
339
483
|
if (this.cache.size <= this.config.maxSize) {
|
|
340
484
|
return;
|
|
@@ -351,6 +495,11 @@ var MemoryCacheProvider = class {
|
|
|
351
495
|
this.cache.delete(oldestKey);
|
|
352
496
|
}
|
|
353
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Retrieves a value from the cache.
|
|
500
|
+
* @param key - The cache key
|
|
501
|
+
* @returns The cached value or undefined if not found or expired
|
|
502
|
+
*/
|
|
354
503
|
async get(key) {
|
|
355
504
|
const item = this.cache.get(key);
|
|
356
505
|
if (!item) {
|
|
@@ -363,6 +512,12 @@ var MemoryCacheProvider = class {
|
|
|
363
512
|
item.lastAccessed = Date.now();
|
|
364
513
|
return item.value;
|
|
365
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* Stores a value in the cache.
|
|
517
|
+
* @param key - The cache key
|
|
518
|
+
* @param value - The value to cache
|
|
519
|
+
* @param ttl - Time to live in seconds (optional)
|
|
520
|
+
*/
|
|
366
521
|
async put(key, value, ttl) {
|
|
367
522
|
const now = Date.now();
|
|
368
523
|
const effectiveTTL = ttl ?? this.config.defaultTTL;
|
|
@@ -375,9 +530,18 @@ var MemoryCacheProvider = class {
|
|
|
375
530
|
this.cache.set(key, item);
|
|
376
531
|
this.evictLRU();
|
|
377
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Deletes a value from the cache.
|
|
535
|
+
* @param key - The cache key to delete
|
|
536
|
+
*/
|
|
378
537
|
async delete(key) {
|
|
379
538
|
this.cache.delete(key);
|
|
380
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Checks if a key exists in the cache and has not expired.
|
|
542
|
+
* @param key - The cache key to check
|
|
543
|
+
* @returns True if the key exists and is not expired, false otherwise
|
|
544
|
+
*/
|
|
381
545
|
async has(key) {
|
|
382
546
|
const item = this.cache.get(key);
|
|
383
547
|
if (!item) {
|
|
@@ -389,6 +553,13 @@ var MemoryCacheProvider = class {
|
|
|
389
553
|
}
|
|
390
554
|
return true;
|
|
391
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Increments a numeric value in the cache atomically.
|
|
558
|
+
* If the key doesn't exist or is expired, it starts from 0.
|
|
559
|
+
* @param key - The cache key to increment
|
|
560
|
+
* @param amount - The amount to increment by (default: 1)
|
|
561
|
+
* @returns The new value after incrementing
|
|
562
|
+
*/
|
|
392
563
|
async increment(key, amount = 1) {
|
|
393
564
|
const item = this.cache.get(key);
|
|
394
565
|
const now = Date.now();
|
|
@@ -416,6 +587,10 @@ var MemoryCacheProvider = class {
|
|
|
416
587
|
var import_memcached = __toESM(require("memcached"), 1);
|
|
417
588
|
var MemcacheCacheProvider = class {
|
|
418
589
|
// default TTL in seconds
|
|
590
|
+
/**
|
|
591
|
+
* Creates a new MemcacheCacheProvider instance.
|
|
592
|
+
* @param config - Memcached configuration options
|
|
593
|
+
*/
|
|
419
594
|
constructor(config = {}) {
|
|
420
595
|
this.config = config;
|
|
421
596
|
this.client = new import_memcached.default(config.location || "localhost:11211", config.options || {});
|
|
@@ -425,6 +600,11 @@ var MemcacheCacheProvider = class {
|
|
|
425
600
|
}
|
|
426
601
|
client;
|
|
427
602
|
defaultTTL = 3600;
|
|
603
|
+
/**
|
|
604
|
+
* Retrieves a value from the cache.
|
|
605
|
+
* @param key - The cache key
|
|
606
|
+
* @returns The cached value or undefined if not found
|
|
607
|
+
*/
|
|
428
608
|
async get(key) {
|
|
429
609
|
return new Promise((resolve, reject) => {
|
|
430
610
|
this.client.get(key, (err, data) => {
|
|
@@ -444,6 +624,12 @@ var MemcacheCacheProvider = class {
|
|
|
444
624
|
});
|
|
445
625
|
});
|
|
446
626
|
}
|
|
627
|
+
/**
|
|
628
|
+
* Stores a value in the cache.
|
|
629
|
+
* @param key - The cache key
|
|
630
|
+
* @param value - The value to cache
|
|
631
|
+
* @param ttl - Time to live in seconds (optional)
|
|
632
|
+
*/
|
|
447
633
|
async put(key, value, ttl) {
|
|
448
634
|
return new Promise((resolve, reject) => {
|
|
449
635
|
const serializedValue = JSON.stringify(value);
|
|
@@ -457,6 +643,10 @@ var MemcacheCacheProvider = class {
|
|
|
457
643
|
});
|
|
458
644
|
});
|
|
459
645
|
}
|
|
646
|
+
/**
|
|
647
|
+
* Deletes a value from the cache.
|
|
648
|
+
* @param key - The cache key to delete
|
|
649
|
+
*/
|
|
460
650
|
async delete(key) {
|
|
461
651
|
return new Promise((resolve, reject) => {
|
|
462
652
|
this.client.del(key, (err) => {
|
|
@@ -468,6 +658,11 @@ var MemcacheCacheProvider = class {
|
|
|
468
658
|
});
|
|
469
659
|
});
|
|
470
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Checks if a key exists in the cache.
|
|
663
|
+
* @param key - The cache key to check
|
|
664
|
+
* @returns True if the key exists, false otherwise
|
|
665
|
+
*/
|
|
471
666
|
async has(key) {
|
|
472
667
|
return new Promise((resolve, reject) => {
|
|
473
668
|
this.client.get(key, (err, data) => {
|
|
@@ -479,6 +674,13 @@ var MemcacheCacheProvider = class {
|
|
|
479
674
|
});
|
|
480
675
|
});
|
|
481
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* Increments a numeric value in the cache atomically using Memcached's native increment.
|
|
679
|
+
* If the key doesn't exist, it is initialized with the increment amount.
|
|
680
|
+
* @param key - The cache key to increment
|
|
681
|
+
* @param amount - The amount to increment by (default: 1)
|
|
682
|
+
* @returns The new value after incrementing
|
|
683
|
+
*/
|
|
482
684
|
async increment(key, amount = 1) {
|
|
483
685
|
return new Promise((resolve, reject) => {
|
|
484
686
|
this.client.incr(key, amount, (err, result) => {
|
|
@@ -504,22 +706,52 @@ var MemcacheCacheProvider = class {
|
|
|
504
706
|
|
|
505
707
|
// src/providers/DisabledCacheProvider.mts
|
|
506
708
|
var DisabledCacheProvider = class {
|
|
709
|
+
/**
|
|
710
|
+
* Creates a new DisabledCacheProvider instance.
|
|
711
|
+
* @param config - Configuration object (currently unused)
|
|
712
|
+
*/
|
|
507
713
|
constructor(config = {}) {
|
|
508
714
|
this.config = config;
|
|
509
715
|
}
|
|
510
716
|
static {
|
|
511
717
|
__name(this, "DisabledCacheProvider");
|
|
512
718
|
}
|
|
719
|
+
/**
|
|
720
|
+
* Always returns undefined (no caching).
|
|
721
|
+
* @param key - The cache key
|
|
722
|
+
* @returns Always undefined
|
|
723
|
+
*/
|
|
513
724
|
async get(key) {
|
|
514
725
|
return void 0;
|
|
515
726
|
}
|
|
727
|
+
/**
|
|
728
|
+
* Does nothing (no caching).
|
|
729
|
+
* @param key - The cache key
|
|
730
|
+
* @param value - The value to cache
|
|
731
|
+
* @param ttl - Time to live in seconds
|
|
732
|
+
*/
|
|
516
733
|
async put(key, value, ttl) {
|
|
517
734
|
}
|
|
735
|
+
/**
|
|
736
|
+
* Does nothing (no caching).
|
|
737
|
+
* @param key - The cache key to delete
|
|
738
|
+
*/
|
|
518
739
|
async delete(key) {
|
|
519
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Always returns false (no caching).
|
|
743
|
+
* @param key - The cache key to check
|
|
744
|
+
* @returns Always false
|
|
745
|
+
*/
|
|
520
746
|
async has(key) {
|
|
521
747
|
return false;
|
|
522
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Returns the increment amount as if starting from 0 (no caching).
|
|
751
|
+
* @param key - The cache key to increment
|
|
752
|
+
* @param amount - The amount to increment by (default: 1)
|
|
753
|
+
* @returns The increment amount
|
|
754
|
+
*/
|
|
523
755
|
async increment(key, amount = 1) {
|
|
524
756
|
return amount;
|
|
525
757
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\nexport type cacheOptions = {\n ttl?: number;\n};\n\nexport class Cache {\n constructor(private provider: CacheProviderInterface) {}\n\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n async increment(key: JSONValue, amount: number = 1): Promise<number> {\n return this.provider.increment(this.generateKey(key), amount);\n }\n\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and concatenating the provided parts.\n * @param parts\n * @returns\n */\n generateKey(key: JSONValue): string {\n if (typeof key === 'string' && key.length <= 250) {\n return key;\n }\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\nexport interface FileCacheConfig {\n cacheDirectory?: string;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n}\n\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\nexport interface MemoryCacheConfig {\n maxSize?: number;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n lastAccessed: number;\n}\n\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n","import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\nexport interface MemcachedConfig {\n location?: Memcached.Location;\n options?: Memcached.options;\n}\n\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class DisabledCacheProvider implements CacheProviderInterface {\n constructor(private config = {}) {}\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n async delete(key: string): Promise<void> {}\n\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\n/**\n * Options for cache operations.\n */\nexport type cacheOptions = {\n /** Time to live in seconds */\n ttl?: number;\n};\n\n/**\n * Cache class providing a unified interface for various cache providers.\n * Handles key generation, serialization, and common cache operations.\n */\nexport class Cache {\n /**\n * Creates a new Cache instance.\n * @param provider - The cache provider implementation to use\n */\n constructor(private provider: CacheProviderInterface) {}\n\n /**\n * Retrieves a value from the cache.\n * @template T - The expected type of the cached value\n * @param key - The cache key (can be string, number, object, or array)\n * @returns The cached value or undefined if not found or expired\n */\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key (can be string, number, object, or array)\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists and has not expired, false otherwise\n */\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: JSONValue, amount: number = 1): Promise<number> {\n return this.provider.increment(this.generateKey(key), amount);\n }\n\n /**\n * Gets a value from cache or executes callback and caches the result.\n * This is useful for caching expensive operations.\n * @template T - The expected type of the value\n * @param key - The cache key\n * @param callback - Function to execute if cache miss occurs\n * @param options - Cache options including TTL (default: 3600 seconds)\n * @returns The cached value or the result of the callback\n */\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and hashing complex keys.\n * Simple string keys under 250 characters are returned as-is.\n * Complex keys (objects, arrays, long strings) are MD5 hashed.\n * @param key - The key to generate a cache key from\n * @returns A string suitable for use as a cache key\n */\n generateKey(key: JSONValue): string {\n if (typeof key === 'string' && key.length <= 250) {\n return key;\n }\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * Redis-based cache provider that stores cache entries in a Redis server.\n * Provides distributed caching with automatic expiration support.\n */\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new RedisCacheProvider instance.\n * @param config - Redis client configuration options\n */\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n /**\n * Creates a Redis client with the provided configuration.\n * @returns A Redis client instance\n */\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n /**\n * Ensures the Redis client is connected before performing operations.\n */\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n /**\n * Increments a numeric value in the cache atomically using Redis INCRBY.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\n/**\n * Configuration options for the file-based cache provider.\n */\nexport interface FileCacheConfig {\n /** Directory where cache files are stored (default: './cache') */\n cacheDirectory?: string;\n /** Default time to live in milliseconds (default: 3600000) */\n defaultTTL?: number;\n /** Interval in milliseconds for cleanup of expired entries (default: 300000) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item stored in a file.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n}\n\n/**\n * File-based cache provider that stores cache entries as JSON files.\n * Provides persistent caching with automatic cleanup of expired entries.\n */\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new FileCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n /**\n * Ensures the cache directory exists, creating it if necessary.\n */\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Generates a safe file path for the given cache key.\n * @param key - The cache key\n * @returns The full file path for the cache entry\n */\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n /**\n * Removes all expired cache entries from the cache directory.\n */\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n /**\n * Increments a numeric value in the cache atomically using file-based locking.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n * @throws Error if lock cannot be acquired after maximum retries\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\n/**\n * Configuration options for the in-memory cache provider.\n */\nexport interface MemoryCacheConfig {\n /** Maximum number of items to store in cache (default: 1000) */\n maxSize?: number;\n /** Default time to live in seconds (default: 3600) */\n defaultTTL?: number;\n /** Interval in seconds to run cleanup of expired entries (default: 600) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item with metadata.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n /** Timestamp when the item was last accessed (milliseconds since epoch) */\n lastAccessed: number;\n}\n\n/**\n * In-memory cache provider with LRU eviction and automatic cleanup.\n * Stores cache entries in memory with support for TTL and size limits.\n */\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new MemoryCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Removes all expired entries from the cache.\n */\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Evicts the least recently used item if cache size exceeds maximum.\n */\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n","import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\n/**\n * Configuration options for the Memcached cache provider.\n */\nexport interface MemcachedConfig {\n /** Memcached server location(s) */\n location?: Memcached.Location;\n /** Additional Memcached options */\n options?: Memcached.options;\n}\n\n/**\n * Memcached-based cache provider that stores cache entries in a Memcached server.\n * Provides distributed caching with automatic serialization and expiration.\n */\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new MemcacheCacheProvider instance.\n * @param config - Memcached configuration options\n */\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n /**\n * Increments a numeric value in the cache atomically using Memcached's native increment.\n * If the key doesn't exist, it is initialized with the increment amount.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * A cache provider that disables caching entirely.\n * All operations are no-ops, useful for testing or disabling cache in certain environments.\n */\nexport class DisabledCacheProvider implements CacheProviderInterface {\n /**\n * Creates a new DisabledCacheProvider instance.\n * @param config - Configuration object (currently unused)\n */\n constructor(private config = {}) {}\n\n /**\n * Always returns undefined (no caching).\n * @param key - The cache key\n * @returns Always undefined\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {}\n\n /**\n * Always returns false (no caching).\n * @param key - The cache key to check\n * @returns Always false\n */\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n /**\n * Returns the increment amount as if starting from 0 (no caching).\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The increment amount\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
|