@devbro/neko-cache 0.1.3 → 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 +31 -0
- package/dist/cache.d.mts +54 -3
- package/dist/cache.mjs +51 -3
- package/dist/cache.mjs.map +1 -1
- package/dist/index.js +338 -3
- package/dist/index.js.map +1 -1
- package/dist/providers/DisabledCacheProvider.d.mts +35 -0
- package/dist/providers/DisabledCacheProvider.mjs +33 -0
- package/dist/providers/DisabledCacheProvider.mjs.map +1 -1
- package/dist/providers/FileCacheProvider.d.mts +60 -0
- package/dist/providers/FileCacheProvider.mjs +97 -0
- package/dist/providers/FileCacheProvider.mjs.map +1 -1
- package/dist/providers/MemcacheCacheProvider.d.mts +41 -0
- package/dist/providers/MemcacheCacheProvider.mjs +52 -0
- package/dist/providers/MemcacheCacheProvider.mjs.map +1 -1
- package/dist/providers/MemoryCacheProvider.d.mts +54 -0
- package/dist/providers/MemoryCacheProvider.mjs +64 -0
- package/dist/providers/MemoryCacheProvider.mjs.map +1 -1
- package/dist/providers/RedisCacheProvider.d.mts +42 -0
- package/dist/providers/RedisCacheProvider.mjs +41 -0
- package/dist/providers/RedisCacheProvider.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -3,6 +3,10 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
3
3
|
import Memcached from "memcached";
|
|
4
4
|
class MemcacheCacheProvider {
|
|
5
5
|
// default TTL in seconds
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new MemcacheCacheProvider instance.
|
|
8
|
+
* @param config - Memcached configuration options
|
|
9
|
+
*/
|
|
6
10
|
constructor(config = {}) {
|
|
7
11
|
this.config = config;
|
|
8
12
|
this.client = new Memcached(config.location || "localhost:11211", config.options || {});
|
|
@@ -12,6 +16,11 @@ class MemcacheCacheProvider {
|
|
|
12
16
|
}
|
|
13
17
|
client;
|
|
14
18
|
defaultTTL = 3600;
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves a value from the cache.
|
|
21
|
+
* @param key - The cache key
|
|
22
|
+
* @returns The cached value or undefined if not found
|
|
23
|
+
*/
|
|
15
24
|
async get(key) {
|
|
16
25
|
return new Promise((resolve, reject) => {
|
|
17
26
|
this.client.get(key, (err, data) => {
|
|
@@ -31,6 +40,12 @@ class MemcacheCacheProvider {
|
|
|
31
40
|
});
|
|
32
41
|
});
|
|
33
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Stores a value in the cache.
|
|
45
|
+
* @param key - The cache key
|
|
46
|
+
* @param value - The value to cache
|
|
47
|
+
* @param ttl - Time to live in seconds (optional)
|
|
48
|
+
*/
|
|
34
49
|
async put(key, value, ttl) {
|
|
35
50
|
return new Promise((resolve, reject) => {
|
|
36
51
|
const serializedValue = JSON.stringify(value);
|
|
@@ -44,6 +59,10 @@ class MemcacheCacheProvider {
|
|
|
44
59
|
});
|
|
45
60
|
});
|
|
46
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Deletes a value from the cache.
|
|
64
|
+
* @param key - The cache key to delete
|
|
65
|
+
*/
|
|
47
66
|
async delete(key) {
|
|
48
67
|
return new Promise((resolve, reject) => {
|
|
49
68
|
this.client.del(key, (err) => {
|
|
@@ -55,6 +74,11 @@ class MemcacheCacheProvider {
|
|
|
55
74
|
});
|
|
56
75
|
});
|
|
57
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Checks if a key exists in the cache.
|
|
79
|
+
* @param key - The cache key to check
|
|
80
|
+
* @returns True if the key exists, false otherwise
|
|
81
|
+
*/
|
|
58
82
|
async has(key) {
|
|
59
83
|
return new Promise((resolve, reject) => {
|
|
60
84
|
this.client.get(key, (err, data) => {
|
|
@@ -66,6 +90,34 @@ class MemcacheCacheProvider {
|
|
|
66
90
|
});
|
|
67
91
|
});
|
|
68
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Increments a numeric value in the cache atomically using Memcached's native increment.
|
|
95
|
+
* If the key doesn't exist, it is initialized with the increment amount.
|
|
96
|
+
* @param key - The cache key to increment
|
|
97
|
+
* @param amount - The amount to increment by (default: 1)
|
|
98
|
+
* @returns The new value after incrementing
|
|
99
|
+
*/
|
|
100
|
+
async increment(key, amount = 1) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
this.client.incr(key, amount, (err, result) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
reject(err);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (result === false) {
|
|
108
|
+
this.client.set(key, amount.toString(), this.defaultTTL, (setErr) => {
|
|
109
|
+
if (setErr) {
|
|
110
|
+
reject(setErr);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
resolve(amount);
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
resolve(result);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
69
121
|
}
|
|
70
122
|
export {
|
|
71
123
|
MemcacheCacheProvider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/MemcacheCacheProvider.mts"],"sourcesContent":["import { CacheProviderInterface } from
|
|
1
|
+
{"version":3,"sources":["../../src/providers/MemcacheCacheProvider.mts"],"sourcesContent":["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"],"mappings":";;AAEA,OAAO,eAAe;AAgBf,MAAM,sBAAwD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnE,YAAoB,SAA0B,CAAC,GAAG;AAA9B;AAClB,SAAK,SAAS,IAAI,UAAU,OAAO,YAAY,mBAAmB,OAAO,WAAW,CAAC,CAAC;AAAA,EACxF;AAAA,EA5BF,OAkBqE;AAAA;AAAA;AAAA,EAC3D;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe7B,MAAM,IAAI,KAA0D;AAClE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,kBAAQ,MAAS;AACjB;AAAA,QACF;AAEA,YAAI;AAGF,kBAAQ,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI,IAAI;AAAA,QAC5D,SAAS,UAAU;AAEjB,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,YAAM,WAAW,OAAO,KAAK;AAE7B,WAAK,OAAO,IAAI,KAAK,iBAAiB,UAAU,CAAC,QAA2B;AAC1E,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,QAA2B;AAC/C,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ,SAAS,UAAa,SAAS,IAAI;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,WAAK,OAAO,KAAK,KAAK,QAAQ,CAAC,KAAU,WAA6B;AACpE,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAGA,YAAI,WAAW,OAAO;AAEpB,eAAK,OAAO,IAAI,KAAK,OAAO,SAAS,GAAG,KAAK,YAAY,CAAC,WAA8B;AACtF,gBAAI,QAAQ;AACV,qBAAO,MAAM;AACb;AAAA,YACF;AACA,oBAAQ,MAAM;AAAA,UAChB,CAAC;AAAA,QACH,OAAO;AACL,kBAAQ,MAAgB;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -1,24 +1,78 @@
|
|
|
1
1
|
import { JSONObject, JSONValue } from '@devbro/neko-helper';
|
|
2
2
|
import { CacheProviderInterface } from '../CacheProviderInterface.mjs';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for the in-memory cache provider.
|
|
6
|
+
*/
|
|
4
7
|
interface MemoryCacheConfig {
|
|
8
|
+
/** Maximum number of items to store in cache (default: 1000) */
|
|
5
9
|
maxSize?: number;
|
|
10
|
+
/** Default time to live in seconds (default: 3600) */
|
|
6
11
|
defaultTTL?: number;
|
|
12
|
+
/** Interval in seconds to run cleanup of expired entries (default: 600) */
|
|
7
13
|
cleanupInterval?: number;
|
|
8
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* In-memory cache provider with LRU eviction and automatic cleanup.
|
|
17
|
+
* Stores cache entries in memory with support for TTL and size limits.
|
|
18
|
+
*/
|
|
9
19
|
declare class MemoryCacheProvider implements CacheProviderInterface {
|
|
10
20
|
private cache;
|
|
11
21
|
private config;
|
|
12
22
|
private cleanupTimer?;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new MemoryCacheProvider instance.
|
|
25
|
+
* @param config - Configuration options for the cache
|
|
26
|
+
*/
|
|
13
27
|
constructor(config?: MemoryCacheConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Starts the automatic cleanup timer for expired entries.
|
|
30
|
+
*/
|
|
14
31
|
private startCleanupTimer;
|
|
32
|
+
/**
|
|
33
|
+
* Stops the automatic cleanup timer.
|
|
34
|
+
*/
|
|
15
35
|
private stopCleanupTimer;
|
|
36
|
+
/**
|
|
37
|
+
* Removes all expired entries from the cache.
|
|
38
|
+
*/
|
|
16
39
|
private cleanupExpiredEntries;
|
|
40
|
+
/**
|
|
41
|
+
* Evicts the least recently used item if cache size exceeds maximum.
|
|
42
|
+
*/
|
|
17
43
|
private evictLRU;
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves a value from the cache.
|
|
46
|
+
* @param key - The cache key
|
|
47
|
+
* @returns The cached value or undefined if not found or expired
|
|
48
|
+
*/
|
|
18
49
|
get(key: string): Promise<JSONObject | JSONValue | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Stores a value in the cache.
|
|
52
|
+
* @param key - The cache key
|
|
53
|
+
* @param value - The value to cache
|
|
54
|
+
* @param ttl - Time to live in seconds (optional)
|
|
55
|
+
*/
|
|
19
56
|
put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Deletes a value from the cache.
|
|
59
|
+
* @param key - The cache key to delete
|
|
60
|
+
*/
|
|
20
61
|
delete(key: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Checks if a key exists in the cache and has not expired.
|
|
64
|
+
* @param key - The cache key to check
|
|
65
|
+
* @returns True if the key exists and is not expired, false otherwise
|
|
66
|
+
*/
|
|
21
67
|
has(key: string): Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Increments a numeric value in the cache atomically.
|
|
70
|
+
* If the key doesn't exist or is expired, it starts from 0.
|
|
71
|
+
* @param key - The cache key to increment
|
|
72
|
+
* @param amount - The amount to increment by (default: 1)
|
|
73
|
+
* @returns The new value after incrementing
|
|
74
|
+
*/
|
|
75
|
+
increment(key: string, amount?: number): Promise<number>;
|
|
22
76
|
}
|
|
23
77
|
|
|
24
78
|
export { type MemoryCacheConfig, MemoryCacheProvider };
|
|
@@ -12,10 +12,17 @@ class MemoryCacheProvider {
|
|
|
12
12
|
// 10 minutes
|
|
13
13
|
};
|
|
14
14
|
cleanupTimer;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new MemoryCacheProvider instance.
|
|
17
|
+
* @param config - Configuration options for the cache
|
|
18
|
+
*/
|
|
15
19
|
constructor(config = {}) {
|
|
16
20
|
this.config = { ...this.config, ...config };
|
|
17
21
|
this.startCleanupTimer();
|
|
18
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Starts the automatic cleanup timer for expired entries.
|
|
25
|
+
*/
|
|
19
26
|
startCleanupTimer() {
|
|
20
27
|
if (this.config.cleanupInterval > 0) {
|
|
21
28
|
this.cleanupTimer = setInterval(() => {
|
|
@@ -23,12 +30,18 @@ class MemoryCacheProvider {
|
|
|
23
30
|
}, this.config.cleanupInterval * 1e3);
|
|
24
31
|
}
|
|
25
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Stops the automatic cleanup timer.
|
|
35
|
+
*/
|
|
26
36
|
stopCleanupTimer() {
|
|
27
37
|
if (this.cleanupTimer) {
|
|
28
38
|
clearInterval(this.cleanupTimer);
|
|
29
39
|
this.cleanupTimer = void 0;
|
|
30
40
|
}
|
|
31
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Removes all expired entries from the cache.
|
|
44
|
+
*/
|
|
32
45
|
cleanupExpiredEntries() {
|
|
33
46
|
const now = Date.now();
|
|
34
47
|
for (const [key, item] of this.cache.entries()) {
|
|
@@ -37,6 +50,9 @@ class MemoryCacheProvider {
|
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Evicts the least recently used item if cache size exceeds maximum.
|
|
55
|
+
*/
|
|
40
56
|
evictLRU() {
|
|
41
57
|
if (this.cache.size <= this.config.maxSize) {
|
|
42
58
|
return;
|
|
@@ -53,6 +69,11 @@ class MemoryCacheProvider {
|
|
|
53
69
|
this.cache.delete(oldestKey);
|
|
54
70
|
}
|
|
55
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Retrieves a value from the cache.
|
|
74
|
+
* @param key - The cache key
|
|
75
|
+
* @returns The cached value or undefined if not found or expired
|
|
76
|
+
*/
|
|
56
77
|
async get(key) {
|
|
57
78
|
const item = this.cache.get(key);
|
|
58
79
|
if (!item) {
|
|
@@ -65,6 +86,12 @@ class MemoryCacheProvider {
|
|
|
65
86
|
item.lastAccessed = Date.now();
|
|
66
87
|
return item.value;
|
|
67
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Stores a value in the cache.
|
|
91
|
+
* @param key - The cache key
|
|
92
|
+
* @param value - The value to cache
|
|
93
|
+
* @param ttl - Time to live in seconds (optional)
|
|
94
|
+
*/
|
|
68
95
|
async put(key, value, ttl) {
|
|
69
96
|
const now = Date.now();
|
|
70
97
|
const effectiveTTL = ttl ?? this.config.defaultTTL;
|
|
@@ -77,9 +104,18 @@ class MemoryCacheProvider {
|
|
|
77
104
|
this.cache.set(key, item);
|
|
78
105
|
this.evictLRU();
|
|
79
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Deletes a value from the cache.
|
|
109
|
+
* @param key - The cache key to delete
|
|
110
|
+
*/
|
|
80
111
|
async delete(key) {
|
|
81
112
|
this.cache.delete(key);
|
|
82
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Checks if a key exists in the cache and has not expired.
|
|
116
|
+
* @param key - The cache key to check
|
|
117
|
+
* @returns True if the key exists and is not expired, false otherwise
|
|
118
|
+
*/
|
|
83
119
|
async has(key) {
|
|
84
120
|
const item = this.cache.get(key);
|
|
85
121
|
if (!item) {
|
|
@@ -91,6 +127,34 @@ class MemoryCacheProvider {
|
|
|
91
127
|
}
|
|
92
128
|
return true;
|
|
93
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Increments a numeric value in the cache atomically.
|
|
132
|
+
* If the key doesn't exist or is expired, it starts from 0.
|
|
133
|
+
* @param key - The cache key to increment
|
|
134
|
+
* @param amount - The amount to increment by (default: 1)
|
|
135
|
+
* @returns The new value after incrementing
|
|
136
|
+
*/
|
|
137
|
+
async increment(key, amount = 1) {
|
|
138
|
+
const item = this.cache.get(key);
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
let currentValue = 0;
|
|
141
|
+
if (item) {
|
|
142
|
+
if (item.expiresAt && item.expiresAt < now) {
|
|
143
|
+
this.cache.delete(key);
|
|
144
|
+
} else {
|
|
145
|
+
currentValue = typeof item.value === "number" ? item.value : 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const newValue = currentValue + amount;
|
|
149
|
+
const newItem = {
|
|
150
|
+
value: newValue,
|
|
151
|
+
createdAt: item?.createdAt ?? now,
|
|
152
|
+
lastAccessed: now,
|
|
153
|
+
expiresAt: item?.expiresAt
|
|
154
|
+
};
|
|
155
|
+
this.cache.set(key, newItem);
|
|
156
|
+
return newValue;
|
|
157
|
+
}
|
|
94
158
|
}
|
|
95
159
|
export {
|
|
96
160
|
MemoryCacheProvider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/MemoryCacheProvider.mts"],"sourcesContent":["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"],"mappings":";;
|
|
1
|
+
{"version":3,"sources":["../../src/providers/MemoryCacheProvider.mts"],"sourcesContent":["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"],"mappings":"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","names":[]}
|
|
@@ -2,17 +2,59 @@ import { RedisClientOptions } from 'redis';
|
|
|
2
2
|
import { CacheProviderInterface } from '../CacheProviderInterface.mjs';
|
|
3
3
|
import { JSONValue, JSONObject } from '@devbro/neko-helper';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Redis-based cache provider that stores cache entries in a Redis server.
|
|
7
|
+
* Provides distributed caching with automatic expiration support.
|
|
8
|
+
*/
|
|
5
9
|
declare class RedisCacheProvider implements CacheProviderInterface {
|
|
6
10
|
private config;
|
|
7
11
|
private client;
|
|
8
12
|
private defaultTTL;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new RedisCacheProvider instance.
|
|
15
|
+
* @param config - Redis client configuration options
|
|
16
|
+
*/
|
|
9
17
|
constructor(config: RedisClientOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Creates a Redis client with the provided configuration.
|
|
20
|
+
* @returns A Redis client instance
|
|
21
|
+
*/
|
|
10
22
|
private createRedisClient;
|
|
23
|
+
/**
|
|
24
|
+
* Ensures the Redis client is connected before performing operations.
|
|
25
|
+
*/
|
|
11
26
|
private ensureConnection;
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves a value from the cache.
|
|
29
|
+
* @param key - The cache key
|
|
30
|
+
* @returns The cached value or undefined if not found
|
|
31
|
+
*/
|
|
12
32
|
get(key: string): Promise<JSONValue | JSONObject | undefined>;
|
|
33
|
+
/**
|
|
34
|
+
* Stores a value in the cache.
|
|
35
|
+
* @param key - The cache key
|
|
36
|
+
* @param value - The value to cache
|
|
37
|
+
* @param ttl - Time to live in seconds (optional)
|
|
38
|
+
*/
|
|
13
39
|
put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Deletes a value from the cache.
|
|
42
|
+
* @param key - The cache key to delete
|
|
43
|
+
*/
|
|
14
44
|
delete(key: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Checks if a key exists in the cache.
|
|
47
|
+
* @param key - The cache key to check
|
|
48
|
+
* @returns True if the key exists, false otherwise
|
|
49
|
+
*/
|
|
15
50
|
has(key: string): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Increments a numeric value in the cache atomically using Redis INCRBY.
|
|
53
|
+
* @param key - The cache key to increment
|
|
54
|
+
* @param amount - The amount to increment by (default: 1)
|
|
55
|
+
* @returns The new value after incrementing
|
|
56
|
+
*/
|
|
57
|
+
increment(key: string, amount?: number): Promise<number>;
|
|
16
58
|
}
|
|
17
59
|
|
|
18
60
|
export { RedisCacheProvider };
|
|
@@ -3,6 +3,10 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
3
3
|
import { createClient } from "redis";
|
|
4
4
|
class RedisCacheProvider {
|
|
5
5
|
// default TTL in seconds
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new RedisCacheProvider instance.
|
|
8
|
+
* @param config - Redis client configuration options
|
|
9
|
+
*/
|
|
6
10
|
constructor(config) {
|
|
7
11
|
this.config = config;
|
|
8
12
|
this.client = this.createRedisClient();
|
|
@@ -13,15 +17,27 @@ class RedisCacheProvider {
|
|
|
13
17
|
}
|
|
14
18
|
client;
|
|
15
19
|
defaultTTL = 3600;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a Redis client with the provided configuration.
|
|
22
|
+
* @returns A Redis client instance
|
|
23
|
+
*/
|
|
16
24
|
createRedisClient() {
|
|
17
25
|
let rc = createClient(this.config);
|
|
18
26
|
return rc;
|
|
19
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Ensures the Redis client is connected before performing operations.
|
|
30
|
+
*/
|
|
20
31
|
async ensureConnection() {
|
|
21
32
|
if (!this.client.isOpen) {
|
|
22
33
|
await this.client.connect();
|
|
23
34
|
}
|
|
24
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves a value from the cache.
|
|
38
|
+
* @param key - The cache key
|
|
39
|
+
* @returns The cached value or undefined if not found
|
|
40
|
+
*/
|
|
25
41
|
async get(key) {
|
|
26
42
|
await this.ensureConnection();
|
|
27
43
|
let rc = this.client.get(key);
|
|
@@ -32,6 +48,12 @@ class RedisCacheProvider {
|
|
|
32
48
|
return JSON.parse(value);
|
|
33
49
|
});
|
|
34
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Stores a value in the cache.
|
|
53
|
+
* @param key - The cache key
|
|
54
|
+
* @param value - The value to cache
|
|
55
|
+
* @param ttl - Time to live in seconds (optional)
|
|
56
|
+
*/
|
|
35
57
|
async put(key, value, ttl) {
|
|
36
58
|
await this.ensureConnection();
|
|
37
59
|
const serializedValue = JSON.stringify(value);
|
|
@@ -42,15 +64,34 @@ class RedisCacheProvider {
|
|
|
42
64
|
await this.client.set(key, serializedValue);
|
|
43
65
|
}
|
|
44
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Deletes a value from the cache.
|
|
69
|
+
* @param key - The cache key to delete
|
|
70
|
+
*/
|
|
45
71
|
async delete(key) {
|
|
46
72
|
await this.ensureConnection();
|
|
47
73
|
await this.client.del(key);
|
|
48
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a key exists in the cache.
|
|
77
|
+
* @param key - The cache key to check
|
|
78
|
+
* @returns True if the key exists, false otherwise
|
|
79
|
+
*/
|
|
49
80
|
async has(key) {
|
|
50
81
|
await this.ensureConnection();
|
|
51
82
|
const result = await this.client.exists(key);
|
|
52
83
|
return result === 1;
|
|
53
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Increments a numeric value in the cache atomically using Redis INCRBY.
|
|
87
|
+
* @param key - The cache key to increment
|
|
88
|
+
* @param amount - The amount to increment by (default: 1)
|
|
89
|
+
* @returns The new value after incrementing
|
|
90
|
+
*/
|
|
91
|
+
async increment(key, amount = 1) {
|
|
92
|
+
await this.ensureConnection();
|
|
93
|
+
return await this.client.incrBy(key, amount);
|
|
94
|
+
}
|
|
54
95
|
}
|
|
55
96
|
export {
|
|
56
97
|
RedisCacheProvider
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/RedisCacheProvider.mts"],"sourcesContent":["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"],"mappings":";;AAAA,SAAS,oBAAyD;
|
|
1
|
+
{"version":3,"sources":["../../src/providers/RedisCacheProvider.mts"],"sourcesContent":["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"],"mappings":";;AAAA,SAAS,oBAAyD;AAQ3D,MAAM,mBAAqD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhE,YAAoB,QAA4B;AAA5B;AAClB,SAAK,SAAS,KAAK,kBAAkB;AACrC,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EAnBF,OAQkE;AAAA;AAAA;AAAA,EACxD;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAerB,oBAAyB;AAC/B,QAAI,KAAK,aAAa,KAAK,MAAM;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC9C,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,YAAM,KAAK,OAAO,QAAQ;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA0D;AAClE,UAAM,KAAK,iBAAiB;AAC5B,QAAI,KAAK,KAAK,OAAO,IAAI,GAAG;AAC5B,WAAO,GAAG,KAAK,CAAC,UAAU;AACxB,UAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,eAAO;AAAA,MACT;AACA,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,UAAM,KAAK,iBAAiB;AAC5B,UAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,UAAM,OAAO,KAAK;AAClB,QAAI,OAAO,MAAM,GAAG;AAClB,YAAM,KAAK,OAAO,MAAM,KAAK,KAAK,eAAe;AAAA,IACnD,OAAO;AACL,YAAM,KAAK,OAAO,IAAI,KAAK,eAAe;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,GAAG;AAC3C,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,UAAM,KAAK,iBAAiB;AAE5B,WAAO,MAAM,KAAK,OAAO,OAAO,KAAK,MAAM;AAAA,EAC7C;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devbro/neko-cache",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "driver agnostic caching implementation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"husky": "^9.1.7",
|
|
37
37
|
"prettier": "^3.5.3",
|
|
38
38
|
"tsup": "^8.0.2",
|
|
39
|
-
"typescript": "^5.
|
|
39
|
+
"typescript": "^5.8.3",
|
|
40
40
|
"vitest": "^3.2.4"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|