@warlock.js/cache 4.0.31 → 4.0.41
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/cjs/index.js +1702 -1
- package/cjs/index.js.map +1 -1
- package/esm/index.js +1681 -1
- package/esm/index.js.map +1 -1
- package/package.json +51 -37
- package/cjs/cache-manager.d.ts +0 -159
- package/cjs/cache-manager.d.ts.map +0 -1
- package/cjs/cache-manager.js +0 -312
- package/cjs/cache-manager.js.map +0 -1
- package/cjs/drivers/base-cache-driver.d.ts +0 -144
- package/cjs/drivers/base-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/base-cache-driver.js +0 -311
- package/cjs/drivers/base-cache-driver.js.map +0 -1
- package/cjs/drivers/file-cache-driver.d.ts +0 -45
- package/cjs/drivers/file-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/file-cache-driver.js +0 -133
- package/cjs/drivers/file-cache-driver.js.map +0 -1
- package/cjs/drivers/index.d.ts +0 -8
- package/cjs/drivers/index.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/cjs/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.js +0 -252
- package/cjs/drivers/lru-memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-cache-driver.d.ts +0 -82
- package/cjs/drivers/memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-cache-driver.js +0 -218
- package/cjs/drivers/memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/cjs/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.js +0 -25
- package/cjs/drivers/memory-extended-cache-driver.js.map +0 -1
- package/cjs/drivers/null-cache-driver.d.ts +0 -58
- package/cjs/drivers/null-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/null-cache-driver.js +0 -84
- package/cjs/drivers/null-cache-driver.js.map +0 -1
- package/cjs/drivers/redis-cache-driver.d.ts +0 -57
- package/cjs/drivers/redis-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/redis-cache-driver.js +0 -223
- package/cjs/drivers/redis-cache-driver.js.map +0 -1
- package/cjs/index.d.ts +0 -6
- package/cjs/index.d.ts.map +0 -1
- package/cjs/tagged-cache.d.ts +0 -77
- package/cjs/tagged-cache.d.ts.map +0 -1
- package/cjs/tagged-cache.js +0 -160
- package/cjs/tagged-cache.js.map +0 -1
- package/cjs/types.d.ts +0 -381
- package/cjs/types.d.ts.map +0 -1
- package/cjs/types.js +0 -36
- package/cjs/types.js.map +0 -1
- package/cjs/utils.d.ts +0 -20
- package/cjs/utils.d.ts.map +0 -1
- package/cjs/utils.js +0 -27
- package/cjs/utils.js.map +0 -1
- package/esm/cache-manager.d.ts +0 -159
- package/esm/cache-manager.d.ts.map +0 -1
- package/esm/cache-manager.js +0 -312
- package/esm/cache-manager.js.map +0 -1
- package/esm/drivers/base-cache-driver.d.ts +0 -144
- package/esm/drivers/base-cache-driver.d.ts.map +0 -1
- package/esm/drivers/base-cache-driver.js +0 -311
- package/esm/drivers/base-cache-driver.js.map +0 -1
- package/esm/drivers/file-cache-driver.d.ts +0 -45
- package/esm/drivers/file-cache-driver.d.ts.map +0 -1
- package/esm/drivers/file-cache-driver.js +0 -133
- package/esm/drivers/file-cache-driver.js.map +0 -1
- package/esm/drivers/index.d.ts +0 -8
- package/esm/drivers/index.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/esm/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.js +0 -252
- package/esm/drivers/lru-memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-cache-driver.d.ts +0 -82
- package/esm/drivers/memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-cache-driver.js +0 -218
- package/esm/drivers/memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/esm/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.js +0 -25
- package/esm/drivers/memory-extended-cache-driver.js.map +0 -1
- package/esm/drivers/null-cache-driver.d.ts +0 -58
- package/esm/drivers/null-cache-driver.d.ts.map +0 -1
- package/esm/drivers/null-cache-driver.js +0 -84
- package/esm/drivers/null-cache-driver.js.map +0 -1
- package/esm/drivers/redis-cache-driver.d.ts +0 -57
- package/esm/drivers/redis-cache-driver.d.ts.map +0 -1
- package/esm/drivers/redis-cache-driver.js +0 -223
- package/esm/drivers/redis-cache-driver.js.map +0 -1
- package/esm/index.d.ts +0 -6
- package/esm/index.d.ts.map +0 -1
- package/esm/tagged-cache.d.ts +0 -77
- package/esm/tagged-cache.d.ts.map +0 -1
- package/esm/tagged-cache.js +0 -160
- package/esm/tagged-cache.js.map +0 -1
- package/esm/types.d.ts +0 -381
- package/esm/types.d.ts.map +0 -1
- package/esm/types.js +0 -36
- package/esm/types.js.map +0 -1
- package/esm/utils.d.ts +0 -20
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -27
- package/esm/utils.js.map +0 -1
package/esm/index.js
CHANGED
|
@@ -1 +1,1681 @@
|
|
|
1
|
-
|
|
1
|
+
import { log } from '@warlock.js/logger';
|
|
2
|
+
import { rtrim, unset, get, set } from '@mongez/reinforcements';
|
|
3
|
+
import { removeDirectoryAsync, ensureDirectoryAsync, putJsonFileAsync, getJsonFileAsync } from '@mongez/fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// ../../warlock.js/cache/src/types.ts
|
|
7
|
+
var CacheError = class extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "CacheError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var CacheConnectionError = class extends CacheError {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "CacheConnectionError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var CacheConfigurationError = class extends CacheError {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "CacheConfigurationError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var CacheDriverNotInitializedError = class extends CacheError {
|
|
26
|
+
constructor(message = "No cache driver initialized. Call cache.init() or cache.use() first.") {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = "CacheDriverNotInitializedError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// ../../warlock.js/cache/src/cache-manager.ts
|
|
33
|
+
var CacheManager = class {
|
|
34
|
+
/**
|
|
35
|
+
* Cache Driver
|
|
36
|
+
*/
|
|
37
|
+
currentDriver;
|
|
38
|
+
/**
|
|
39
|
+
* Loaded drivers
|
|
40
|
+
*/
|
|
41
|
+
loadedDrivers = {};
|
|
42
|
+
/**
|
|
43
|
+
* Configurations list
|
|
44
|
+
*/
|
|
45
|
+
configurations = {
|
|
46
|
+
drivers: {},
|
|
47
|
+
options: {}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Global event listeners
|
|
51
|
+
*/
|
|
52
|
+
globalEventListeners = /* @__PURE__ */ new Map();
|
|
53
|
+
/**
|
|
54
|
+
* {@inheritdoc}
|
|
55
|
+
*/
|
|
56
|
+
name = "cacheManager";
|
|
57
|
+
/**
|
|
58
|
+
* {@inheritdoc}
|
|
59
|
+
*/
|
|
60
|
+
get client() {
|
|
61
|
+
return this.currentDriver?.client;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Set the cache configurations
|
|
65
|
+
*/
|
|
66
|
+
setCacheConfigurations(configurations) {
|
|
67
|
+
this.configurations.default = configurations.default;
|
|
68
|
+
this.configurations.drivers = configurations.drivers;
|
|
69
|
+
this.configurations.options = configurations.options;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Use the given driver
|
|
73
|
+
*/
|
|
74
|
+
async use(driver) {
|
|
75
|
+
if (typeof driver === "string") {
|
|
76
|
+
const driverInstance = await this.load(driver);
|
|
77
|
+
if (!driverInstance) {
|
|
78
|
+
throw new CacheConfigurationError(
|
|
79
|
+
`Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
driver = driverInstance;
|
|
83
|
+
}
|
|
84
|
+
this.attachGlobalListeners(driver);
|
|
85
|
+
this.currentDriver = driver;
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Ensure driver is initialized before operations
|
|
90
|
+
*/
|
|
91
|
+
ensureDriverInitialized() {
|
|
92
|
+
if (!this.currentDriver) {
|
|
93
|
+
throw new CacheDriverNotInitializedError();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* {@inheritdoc}
|
|
98
|
+
*/
|
|
99
|
+
async get(key) {
|
|
100
|
+
this.ensureDriverInitialized();
|
|
101
|
+
return this.currentDriver.get(key);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Set a value in the cache
|
|
105
|
+
*
|
|
106
|
+
* @param key The cache key, could be an object or string
|
|
107
|
+
* @param value The value to be stored in the cache
|
|
108
|
+
* @param ttl The time to live in seconds
|
|
109
|
+
*/
|
|
110
|
+
async set(key, value, ttl) {
|
|
111
|
+
this.ensureDriverInitialized();
|
|
112
|
+
return this.currentDriver.set(key, value, ttl);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* {@inheritdoc}
|
|
116
|
+
*/
|
|
117
|
+
async remove(key) {
|
|
118
|
+
this.ensureDriverInitialized();
|
|
119
|
+
return this.currentDriver.remove(key);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* {@inheritdoc}
|
|
123
|
+
*/
|
|
124
|
+
async removeNamespace(namespace) {
|
|
125
|
+
this.ensureDriverInitialized();
|
|
126
|
+
return this.currentDriver.removeNamespace(namespace);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* {@inheritdoc}
|
|
130
|
+
*/
|
|
131
|
+
async flush() {
|
|
132
|
+
this.ensureDriverInitialized();
|
|
133
|
+
return this.currentDriver.flush();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* {@inheritdoc}
|
|
137
|
+
*/
|
|
138
|
+
async connect() {
|
|
139
|
+
this.ensureDriverInitialized();
|
|
140
|
+
return this.currentDriver.connect();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* {@inheritdoc}
|
|
144
|
+
*/
|
|
145
|
+
parseKey(key) {
|
|
146
|
+
this.ensureDriverInitialized();
|
|
147
|
+
return this.currentDriver.parseKey(key);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* {@inheritdoc}
|
|
151
|
+
*/
|
|
152
|
+
get options() {
|
|
153
|
+
this.ensureDriverInitialized();
|
|
154
|
+
return this.currentDriver.options;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* {@inheritdoc}
|
|
158
|
+
*/
|
|
159
|
+
setOptions(options) {
|
|
160
|
+
this.ensureDriverInitialized();
|
|
161
|
+
return this.currentDriver.setOptions(options || {});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get an instance of the cache driver
|
|
165
|
+
*/
|
|
166
|
+
async driver(driverName) {
|
|
167
|
+
return this.loadedDrivers[driverName] || await this.load(driverName);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Initialize the cache manager and pick the default driver
|
|
171
|
+
*/
|
|
172
|
+
async init() {
|
|
173
|
+
const defaultCacheDriverName = this.configurations.default;
|
|
174
|
+
if (!defaultCacheDriverName) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const driver = await this.driver(defaultCacheDriverName);
|
|
178
|
+
await this.use(driver);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Load the given cache driver name
|
|
182
|
+
*/
|
|
183
|
+
async load(driver) {
|
|
184
|
+
if (this.loadedDrivers[driver]) return this.loadedDrivers[driver];
|
|
185
|
+
const Driver = this.configurations.drivers[driver];
|
|
186
|
+
if (!Driver) {
|
|
187
|
+
throw new CacheConfigurationError(
|
|
188
|
+
`Cache driver ${driver} is not found, please declare it in the cache drivers in the configurations list.`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
const driverInstance = new Driver();
|
|
192
|
+
driverInstance.setOptions(
|
|
193
|
+
this.configurations.options[driver] || {}
|
|
194
|
+
);
|
|
195
|
+
await driverInstance.connect();
|
|
196
|
+
this.attachGlobalListeners(driverInstance);
|
|
197
|
+
this.loadedDrivers[driver] = driverInstance;
|
|
198
|
+
return driverInstance;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Register and bind a driver
|
|
202
|
+
*/
|
|
203
|
+
registerDriver(driverName, driverClass) {
|
|
204
|
+
this.configurations.drivers[driverName] = driverClass;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Disconnect the cache manager
|
|
208
|
+
*/
|
|
209
|
+
async disconnect() {
|
|
210
|
+
if (this.currentDriver) {
|
|
211
|
+
await this.currentDriver.disconnect();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* {@inheritdoc}
|
|
216
|
+
*/
|
|
217
|
+
async has(key) {
|
|
218
|
+
this.ensureDriverInitialized();
|
|
219
|
+
return this.currentDriver.has(key);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* {@inheritdoc}
|
|
223
|
+
*/
|
|
224
|
+
async remember(key, ttl, callback) {
|
|
225
|
+
this.ensureDriverInitialized();
|
|
226
|
+
return this.currentDriver.remember(key, ttl, callback);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* {@inheritdoc}
|
|
230
|
+
*/
|
|
231
|
+
async pull(key) {
|
|
232
|
+
this.ensureDriverInitialized();
|
|
233
|
+
return this.currentDriver.pull(key);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* {@inheritdoc}
|
|
237
|
+
*/
|
|
238
|
+
async forever(key, value) {
|
|
239
|
+
this.ensureDriverInitialized();
|
|
240
|
+
return this.currentDriver.forever(key, value);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* {@inheritdoc}
|
|
244
|
+
*/
|
|
245
|
+
async increment(key, value) {
|
|
246
|
+
this.ensureDriverInitialized();
|
|
247
|
+
return this.currentDriver.increment(key, value);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* {@inheritdoc}
|
|
251
|
+
*/
|
|
252
|
+
async decrement(key, value) {
|
|
253
|
+
this.ensureDriverInitialized();
|
|
254
|
+
return this.currentDriver.decrement(key, value);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* {@inheritdoc}
|
|
258
|
+
*/
|
|
259
|
+
async many(keys) {
|
|
260
|
+
this.ensureDriverInitialized();
|
|
261
|
+
return this.currentDriver.many(keys);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* {@inheritdoc}
|
|
265
|
+
*/
|
|
266
|
+
async setMany(items, ttl) {
|
|
267
|
+
this.ensureDriverInitialized();
|
|
268
|
+
return this.currentDriver.setMany(items, ttl);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Register a global event listener (applies to all drivers)
|
|
272
|
+
*/
|
|
273
|
+
on(event, handler) {
|
|
274
|
+
if (!this.globalEventListeners.has(event)) {
|
|
275
|
+
this.globalEventListeners.set(event, /* @__PURE__ */ new Set());
|
|
276
|
+
}
|
|
277
|
+
this.globalEventListeners.get(event).add(handler);
|
|
278
|
+
if (this.currentDriver) {
|
|
279
|
+
this.currentDriver.on(event, handler);
|
|
280
|
+
}
|
|
281
|
+
for (const driver of Object.values(this.loadedDrivers)) {
|
|
282
|
+
driver.on(event, handler);
|
|
283
|
+
}
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Remove a global event listener
|
|
288
|
+
*/
|
|
289
|
+
off(event, handler) {
|
|
290
|
+
const handlers = this.globalEventListeners.get(event);
|
|
291
|
+
if (handlers) {
|
|
292
|
+
handlers.delete(handler);
|
|
293
|
+
}
|
|
294
|
+
if (this.currentDriver) {
|
|
295
|
+
this.currentDriver.off(event, handler);
|
|
296
|
+
}
|
|
297
|
+
for (const driver of Object.values(this.loadedDrivers)) {
|
|
298
|
+
driver.off(event, handler);
|
|
299
|
+
}
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Register a one-time global event listener
|
|
304
|
+
*/
|
|
305
|
+
once(event, handler) {
|
|
306
|
+
const onceHandler = async (data) => {
|
|
307
|
+
await handler(data);
|
|
308
|
+
this.off(event, onceHandler);
|
|
309
|
+
};
|
|
310
|
+
return this.on(event, onceHandler);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Attach global listeners to a driver
|
|
314
|
+
*/
|
|
315
|
+
attachGlobalListeners(driver) {
|
|
316
|
+
for (const [event, handlers] of this.globalEventListeners) {
|
|
317
|
+
for (const handler of handlers) {
|
|
318
|
+
driver.on(event, handler);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Set if not exists (atomic operation)
|
|
324
|
+
* Returns true if key was set, false if key already existed
|
|
325
|
+
* Note: Only supported by drivers that implement setNX (e.g., Redis)
|
|
326
|
+
*/
|
|
327
|
+
async setNX(key, value, ttl) {
|
|
328
|
+
this.ensureDriverInitialized();
|
|
329
|
+
if (!this.currentDriver.setNX) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
`setNX is not supported by the current cache driver: ${this.currentDriver.name}`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
return this.currentDriver.setNX(key, value, ttl);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Create a tagged cache instance for the given tags
|
|
338
|
+
*/
|
|
339
|
+
tags(tags) {
|
|
340
|
+
this.ensureDriverInitialized();
|
|
341
|
+
return this.currentDriver.tags(tags);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var cache = new CacheManager();
|
|
345
|
+
|
|
346
|
+
// ../../warlock.js/cache/src/tagged-cache.ts
|
|
347
|
+
var TaggedCache = class {
|
|
348
|
+
/**
|
|
349
|
+
* The tags associated with this tagged cache instance
|
|
350
|
+
*/
|
|
351
|
+
cacheTags;
|
|
352
|
+
/**
|
|
353
|
+
* The underlying cache driver
|
|
354
|
+
*/
|
|
355
|
+
driver;
|
|
356
|
+
/**
|
|
357
|
+
* Constructor
|
|
358
|
+
*/
|
|
359
|
+
constructor(tags, driver) {
|
|
360
|
+
this.cacheTags = tags;
|
|
361
|
+
this.driver = driver;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get the tag key prefix for storing tag-key relationships
|
|
365
|
+
*/
|
|
366
|
+
tagKey(tag) {
|
|
367
|
+
return `cache:tags:${tag}`;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Store tag-key relationship
|
|
371
|
+
*/
|
|
372
|
+
async storeTaggedKey(key) {
|
|
373
|
+
for (const tag of this.cacheTags) {
|
|
374
|
+
const tagKey = this.tagKey(tag);
|
|
375
|
+
const keys = await this.driver.get(tagKey) || [];
|
|
376
|
+
if (!keys.includes(key)) {
|
|
377
|
+
keys.push(key);
|
|
378
|
+
await this.driver.set(tagKey, keys, Infinity);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Get all keys associated with tags
|
|
384
|
+
*/
|
|
385
|
+
async getTaggedKeys() {
|
|
386
|
+
const allKeys = /* @__PURE__ */ new Set();
|
|
387
|
+
for (const tag of this.cacheTags) {
|
|
388
|
+
const tagKey = this.tagKey(tag);
|
|
389
|
+
const keys = await this.driver.get(tagKey) || [];
|
|
390
|
+
for (const key of keys) {
|
|
391
|
+
allKeys.add(key);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return allKeys;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* {@inheritdoc}
|
|
398
|
+
*/
|
|
399
|
+
async set(key, value, ttl) {
|
|
400
|
+
const parsedKey = this.driver.parseKey(key);
|
|
401
|
+
await this.driver.set(key, value, ttl);
|
|
402
|
+
await this.storeTaggedKey(parsedKey);
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* {@inheritdoc}
|
|
407
|
+
*/
|
|
408
|
+
async get(key) {
|
|
409
|
+
return this.driver.get(key);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* {@inheritdoc}
|
|
413
|
+
*/
|
|
414
|
+
async remove(key) {
|
|
415
|
+
const parsedKey = this.driver.parseKey(key);
|
|
416
|
+
await this.driver.remove(key);
|
|
417
|
+
for (const tag of this.cacheTags) {
|
|
418
|
+
const tagKey = this.tagKey(tag);
|
|
419
|
+
const keys = await this.driver.get(tagKey) || [];
|
|
420
|
+
const updatedKeys = keys.filter((k) => k !== parsedKey);
|
|
421
|
+
await this.driver.set(tagKey, updatedKeys, Infinity);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Invalidate (clear) all keys associated with the current tags
|
|
426
|
+
*/
|
|
427
|
+
async invalidate() {
|
|
428
|
+
const keysToRemove = await this.getTaggedKeys();
|
|
429
|
+
for (const key of keysToRemove) {
|
|
430
|
+
await this.driver.remove(key);
|
|
431
|
+
}
|
|
432
|
+
for (const tag of this.cacheTags) {
|
|
433
|
+
await this.driver.remove(this.tagKey(tag));
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Flush all keys associated with the current tags
|
|
438
|
+
* @deprecated Use invalidate() instead for better semantics
|
|
439
|
+
*/
|
|
440
|
+
async flush() {
|
|
441
|
+
return this.invalidate();
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* {@inheritdoc}
|
|
445
|
+
*/
|
|
446
|
+
async has(key) {
|
|
447
|
+
return this.driver.has(key);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* {@inheritdoc}
|
|
451
|
+
*/
|
|
452
|
+
async remember(key, ttl, callback) {
|
|
453
|
+
const value = await this.get(key);
|
|
454
|
+
if (value !== null) {
|
|
455
|
+
return value;
|
|
456
|
+
}
|
|
457
|
+
const result = await callback();
|
|
458
|
+
await this.set(key, result, ttl);
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* {@inheritdoc}
|
|
463
|
+
*/
|
|
464
|
+
async pull(key) {
|
|
465
|
+
const value = await this.get(key);
|
|
466
|
+
if (value !== null) {
|
|
467
|
+
await this.remove(key);
|
|
468
|
+
}
|
|
469
|
+
return value;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* {@inheritdoc}
|
|
473
|
+
*/
|
|
474
|
+
async forever(key, value) {
|
|
475
|
+
return this.set(key, value, Infinity);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* {@inheritdoc}
|
|
479
|
+
*/
|
|
480
|
+
async increment(key, value = 1) {
|
|
481
|
+
const current = await this.get(key) || 0;
|
|
482
|
+
if (typeof current !== "number") {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`Cannot increment non-numeric value for key: ${this.driver.parseKey(key)}`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
const newValue = current + value;
|
|
488
|
+
await this.set(key, newValue);
|
|
489
|
+
return newValue;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* {@inheritdoc}
|
|
493
|
+
*/
|
|
494
|
+
async decrement(key, value = 1) {
|
|
495
|
+
return this.increment(key, -value);
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
function parseCacheKey(key, options = {}) {
|
|
499
|
+
if (typeof key === "object") {
|
|
500
|
+
key = JSON.stringify(key);
|
|
501
|
+
}
|
|
502
|
+
key = key.replace(/[{}"[\]]/g, "").replaceAll(/[:,]/g, ".");
|
|
503
|
+
const cachePrefix = typeof options.globalPrefix === "function" ? options.globalPrefix() : options.globalPrefix;
|
|
504
|
+
return rtrim(String(cachePrefix ? rtrim(cachePrefix, ".") + "." + key : key), ".");
|
|
505
|
+
}
|
|
506
|
+
var CACHE_FOR = /* @__PURE__ */ ((CACHE_FOR2) => {
|
|
507
|
+
CACHE_FOR2[CACHE_FOR2["HALF_HOUR"] = 1800] = "HALF_HOUR";
|
|
508
|
+
CACHE_FOR2[CACHE_FOR2["ONE_HOUR"] = 3600] = "ONE_HOUR";
|
|
509
|
+
CACHE_FOR2[CACHE_FOR2["HALF_DAY"] = 43200] = "HALF_DAY";
|
|
510
|
+
CACHE_FOR2[CACHE_FOR2["ONE_DAY"] = 86400] = "ONE_DAY";
|
|
511
|
+
CACHE_FOR2[CACHE_FOR2["ONE_WEEK"] = 604800] = "ONE_WEEK";
|
|
512
|
+
CACHE_FOR2[CACHE_FOR2["HALF_MONTH"] = 1296e3] = "HALF_MONTH";
|
|
513
|
+
CACHE_FOR2[CACHE_FOR2["ONE_MONTH"] = 2592e3] = "ONE_MONTH";
|
|
514
|
+
CACHE_FOR2[CACHE_FOR2["TWO_MONTHS"] = 5184e3] = "TWO_MONTHS";
|
|
515
|
+
CACHE_FOR2[CACHE_FOR2["SIX_MONTHS"] = 15768e3] = "SIX_MONTHS";
|
|
516
|
+
CACHE_FOR2[CACHE_FOR2["ONE_YEAR"] = 31536e3] = "ONE_YEAR";
|
|
517
|
+
return CACHE_FOR2;
|
|
518
|
+
})(CACHE_FOR || {});
|
|
519
|
+
|
|
520
|
+
// ../../warlock.js/cache/src/drivers/base-cache-driver.ts
|
|
521
|
+
var messages = {
|
|
522
|
+
clearing: "Clearing namespace",
|
|
523
|
+
cleared: "Namespace cleared",
|
|
524
|
+
fetching: "Fetching key",
|
|
525
|
+
fetched: "Key fetched",
|
|
526
|
+
caching: "Caching key",
|
|
527
|
+
cached: "Key cached",
|
|
528
|
+
flushing: "Flushing cache",
|
|
529
|
+
flushed: "Cache flushed",
|
|
530
|
+
removing: "Removing key",
|
|
531
|
+
removed: "Key removed",
|
|
532
|
+
expired: "Key expired",
|
|
533
|
+
notFound: "Key not found",
|
|
534
|
+
connecting: "Connecting to the cache engine.",
|
|
535
|
+
connected: "Connected to the cache engine.",
|
|
536
|
+
disconnecting: "Disconnecting from the cache engine.",
|
|
537
|
+
disconnected: "Disconnected from the cache engine.",
|
|
538
|
+
error: "Error occurred"
|
|
539
|
+
};
|
|
540
|
+
var BaseCacheDriver = class {
|
|
541
|
+
/**
|
|
542
|
+
* CLient driver
|
|
543
|
+
*/
|
|
544
|
+
clientDriver;
|
|
545
|
+
/**
|
|
546
|
+
* {@inheritdoc}
|
|
547
|
+
*/
|
|
548
|
+
get client() {
|
|
549
|
+
return this.clientDriver || this;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Set client driver
|
|
553
|
+
*/
|
|
554
|
+
set client(client) {
|
|
555
|
+
this.clientDriver = client;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Options list
|
|
559
|
+
*/
|
|
560
|
+
options;
|
|
561
|
+
/**
|
|
562
|
+
* Event listeners storage
|
|
563
|
+
*/
|
|
564
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
565
|
+
/**
|
|
566
|
+
* {@inheritdoc}
|
|
567
|
+
*/
|
|
568
|
+
parseKey(key) {
|
|
569
|
+
return parseCacheKey(key, this.options);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* {@inheritdoc}
|
|
573
|
+
*/
|
|
574
|
+
setOptions(options) {
|
|
575
|
+
this.options = options || {};
|
|
576
|
+
return this;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Register an event listener
|
|
580
|
+
*/
|
|
581
|
+
on(event, handler) {
|
|
582
|
+
if (!this.eventListeners.has(event)) {
|
|
583
|
+
this.eventListeners.set(event, /* @__PURE__ */ new Set());
|
|
584
|
+
}
|
|
585
|
+
this.eventListeners.get(event).add(handler);
|
|
586
|
+
return this;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Remove an event listener
|
|
590
|
+
*/
|
|
591
|
+
off(event, handler) {
|
|
592
|
+
const handlers = this.eventListeners.get(event);
|
|
593
|
+
if (handlers) {
|
|
594
|
+
handlers.delete(handler);
|
|
595
|
+
}
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Register a one-time event listener
|
|
600
|
+
*/
|
|
601
|
+
once(event, handler) {
|
|
602
|
+
const onceHandler = async (data) => {
|
|
603
|
+
await handler(data);
|
|
604
|
+
this.off(event, onceHandler);
|
|
605
|
+
};
|
|
606
|
+
return this.on(event, onceHandler);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Emit an event to all registered listeners
|
|
610
|
+
*/
|
|
611
|
+
async emit(event, data = {}) {
|
|
612
|
+
const handlers = this.eventListeners.get(event);
|
|
613
|
+
if (!handlers || handlers.size === 0) return;
|
|
614
|
+
const eventData = {
|
|
615
|
+
driver: this.name,
|
|
616
|
+
...data
|
|
617
|
+
};
|
|
618
|
+
const promises = [];
|
|
619
|
+
for (const handler of handlers) {
|
|
620
|
+
try {
|
|
621
|
+
const result = handler(eventData);
|
|
622
|
+
if (result instanceof Promise) {
|
|
623
|
+
promises.push(result);
|
|
624
|
+
}
|
|
625
|
+
} catch (error) {
|
|
626
|
+
this.logError(`Error in event handler for '${event}'`, error);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (promises.length > 0) {
|
|
630
|
+
await Promise.allSettled(promises);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* {@inheritdoc}
|
|
635
|
+
*/
|
|
636
|
+
async has(key) {
|
|
637
|
+
const value = await this.get(key);
|
|
638
|
+
return value !== null;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Lock storage for preventing cache stampede
|
|
642
|
+
*/
|
|
643
|
+
locks = /* @__PURE__ */ new Map();
|
|
644
|
+
/**
|
|
645
|
+
* {@inheritdoc}
|
|
646
|
+
*/
|
|
647
|
+
async remember(key, ttl, callback) {
|
|
648
|
+
const parsedKey = this.parseKey(key);
|
|
649
|
+
const cachedValue = await this.get(key);
|
|
650
|
+
if (cachedValue !== null) {
|
|
651
|
+
return cachedValue;
|
|
652
|
+
}
|
|
653
|
+
const existingLock = this.locks.get(parsedKey);
|
|
654
|
+
if (existingLock) {
|
|
655
|
+
return existingLock;
|
|
656
|
+
}
|
|
657
|
+
const promise = callback().then(async (result) => {
|
|
658
|
+
await this.set(key, result, ttl);
|
|
659
|
+
this.locks.delete(parsedKey);
|
|
660
|
+
return result;
|
|
661
|
+
}).catch((err) => {
|
|
662
|
+
this.locks.delete(parsedKey);
|
|
663
|
+
throw err;
|
|
664
|
+
});
|
|
665
|
+
this.locks.set(parsedKey, promise);
|
|
666
|
+
return promise;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* {@inheritdoc}
|
|
670
|
+
*/
|
|
671
|
+
async pull(key) {
|
|
672
|
+
const value = await this.get(key);
|
|
673
|
+
if (value !== null) {
|
|
674
|
+
await this.remove(key);
|
|
675
|
+
}
|
|
676
|
+
return value;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* {@inheritdoc}
|
|
680
|
+
*/
|
|
681
|
+
async forever(key, value) {
|
|
682
|
+
return this.set(key, value, Infinity);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* {@inheritdoc}
|
|
686
|
+
*/
|
|
687
|
+
async increment(key, value = 1) {
|
|
688
|
+
const current = await this.get(key) || 0;
|
|
689
|
+
if (typeof current !== "number") {
|
|
690
|
+
throw new Error(`Cannot increment non-numeric value for key: ${this.parseKey(key)}`);
|
|
691
|
+
}
|
|
692
|
+
const newValue = current + value;
|
|
693
|
+
await this.set(key, newValue);
|
|
694
|
+
return newValue;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* {@inheritdoc}
|
|
698
|
+
*/
|
|
699
|
+
async decrement(key, value = 1) {
|
|
700
|
+
return this.increment(key, -value);
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* {@inheritdoc}
|
|
704
|
+
*/
|
|
705
|
+
async many(keys) {
|
|
706
|
+
return Promise.all(keys.map((key) => this.get(key)));
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* {@inheritdoc}
|
|
710
|
+
*/
|
|
711
|
+
async setMany(items, ttl) {
|
|
712
|
+
await Promise.all(Object.entries(items).map(([key, value]) => this.set(key, value, ttl)));
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Log the operation
|
|
716
|
+
*/
|
|
717
|
+
log(operation, key) {
|
|
718
|
+
if (key) {
|
|
719
|
+
key = key.replaceAll("/", ".");
|
|
720
|
+
}
|
|
721
|
+
if (operation == "notFound" || operation == "expired") {
|
|
722
|
+
return log.warn(
|
|
723
|
+
"cache:" + this.name,
|
|
724
|
+
operation,
|
|
725
|
+
(key ? key + " " : "") + messages[operation]
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
if (operation.endsWith("ed")) {
|
|
729
|
+
return log.success(
|
|
730
|
+
"cache:" + this.name,
|
|
731
|
+
operation,
|
|
732
|
+
(key ? key + " " : "") + messages[operation]
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
log.info("cache:" + this.name, operation, (key ? key + " " : "") + messages[operation]);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Log error message
|
|
739
|
+
*/
|
|
740
|
+
logError(message, error) {
|
|
741
|
+
log.error("cache:" + this.name, "error", message);
|
|
742
|
+
if (error) {
|
|
743
|
+
console.log(error);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Get time to live value
|
|
748
|
+
*/
|
|
749
|
+
get ttl() {
|
|
750
|
+
return this.options.ttl !== void 0 ? this.options.ttl : Infinity;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Get time to live value in milliseconds
|
|
754
|
+
*/
|
|
755
|
+
getExpiresAt(ttl = this.ttl) {
|
|
756
|
+
if (ttl) {
|
|
757
|
+
return (/* @__PURE__ */ new Date()).getTime() + ttl * 1e3;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Prepare data for storage
|
|
762
|
+
*/
|
|
763
|
+
prepareDataForStorage(data, ttl) {
|
|
764
|
+
const preparedData = {
|
|
765
|
+
data
|
|
766
|
+
};
|
|
767
|
+
if (ttl) {
|
|
768
|
+
preparedData.ttl = ttl;
|
|
769
|
+
preparedData.expiresAt = this.getExpiresAt(ttl);
|
|
770
|
+
}
|
|
771
|
+
return preparedData;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Parse fetched data from cache
|
|
775
|
+
*/
|
|
776
|
+
async parseCachedData(key, data) {
|
|
777
|
+
this.log("fetched", key);
|
|
778
|
+
if (data.expiresAt && data.expiresAt < Date.now()) {
|
|
779
|
+
this.remove(key);
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
const value = data.data;
|
|
783
|
+
if (value === null || value === void 0) {
|
|
784
|
+
return value;
|
|
785
|
+
}
|
|
786
|
+
const type = typeof value;
|
|
787
|
+
if (type === "string" || type === "number" || type === "boolean") {
|
|
788
|
+
return value;
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
return structuredClone(value);
|
|
792
|
+
} catch (error) {
|
|
793
|
+
console.log(value);
|
|
794
|
+
this.logError(
|
|
795
|
+
`Failed to clone cached value for ${key}, typeof value: ${typeof value}`,
|
|
796
|
+
error
|
|
797
|
+
);
|
|
798
|
+
throw error;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* {@inheritdoc}
|
|
803
|
+
*/
|
|
804
|
+
async connect() {
|
|
805
|
+
this.log("connecting");
|
|
806
|
+
this.log("connected");
|
|
807
|
+
await this.emit("connected");
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* {@inheritdoc}
|
|
811
|
+
*/
|
|
812
|
+
async disconnect() {
|
|
813
|
+
this.log("disconnected");
|
|
814
|
+
await this.emit("disconnected");
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Create a tagged cache instance for the given tags
|
|
818
|
+
*/
|
|
819
|
+
tags(tags) {
|
|
820
|
+
return new TaggedCache(tags, this);
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
var FileCacheDriver = class extends BaseCacheDriver {
|
|
824
|
+
/**
|
|
825
|
+
* {@inheritdoc}
|
|
826
|
+
*/
|
|
827
|
+
name = "file";
|
|
828
|
+
/**
|
|
829
|
+
* {@inheritdoc}
|
|
830
|
+
*/
|
|
831
|
+
setOptions(options) {
|
|
832
|
+
if (!options.directory) {
|
|
833
|
+
throw new CacheConfigurationError(
|
|
834
|
+
"File driver requires 'directory' option to be configured."
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
return super.setOptions(options);
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Get the cache directory
|
|
841
|
+
*/
|
|
842
|
+
get directory() {
|
|
843
|
+
const directory = this.options.directory;
|
|
844
|
+
if (typeof directory === "function") {
|
|
845
|
+
return directory();
|
|
846
|
+
}
|
|
847
|
+
throw new CacheConfigurationError(
|
|
848
|
+
"Cache directory is not defined, please define it in the file driver options"
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Get file name
|
|
853
|
+
*/
|
|
854
|
+
get fileName() {
|
|
855
|
+
const fileName = this.options.fileName;
|
|
856
|
+
if (typeof fileName === "function") {
|
|
857
|
+
return fileName();
|
|
858
|
+
}
|
|
859
|
+
return "cache.json";
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* {@inheritdoc}
|
|
863
|
+
*/
|
|
864
|
+
async removeNamespace(namespace) {
|
|
865
|
+
this.log("clearing", namespace);
|
|
866
|
+
try {
|
|
867
|
+
await removeDirectoryAsync(path.resolve(this.directory, namespace));
|
|
868
|
+
this.log("cleared", namespace);
|
|
869
|
+
} catch (error) {
|
|
870
|
+
}
|
|
871
|
+
return this;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* {@inheritdoc}
|
|
875
|
+
*/
|
|
876
|
+
async set(key, value, ttl) {
|
|
877
|
+
key = this.parseKey(key);
|
|
878
|
+
this.log("caching", key);
|
|
879
|
+
const data = this.prepareDataForStorage(value, ttl);
|
|
880
|
+
const fileDirectory = path.resolve(this.directory, key);
|
|
881
|
+
await ensureDirectoryAsync(fileDirectory);
|
|
882
|
+
await putJsonFileAsync(path.resolve(fileDirectory, this.fileName), data);
|
|
883
|
+
this.log("cached", key);
|
|
884
|
+
await this.emit("set", { key, value, ttl });
|
|
885
|
+
return this;
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* {@inheritdoc}
|
|
889
|
+
*/
|
|
890
|
+
async get(key) {
|
|
891
|
+
const parsedKey = this.parseKey(key);
|
|
892
|
+
this.log("fetching", parsedKey);
|
|
893
|
+
const fileDirectory = path.resolve(this.directory, parsedKey);
|
|
894
|
+
try {
|
|
895
|
+
const value = await getJsonFileAsync(
|
|
896
|
+
path.resolve(fileDirectory, this.fileName)
|
|
897
|
+
);
|
|
898
|
+
const result = await this.parseCachedData(parsedKey, value);
|
|
899
|
+
if (result === null) {
|
|
900
|
+
await this.emit("miss", { key: parsedKey });
|
|
901
|
+
} else {
|
|
902
|
+
await this.emit("hit", { key: parsedKey, value: result });
|
|
903
|
+
}
|
|
904
|
+
return result;
|
|
905
|
+
} catch (error) {
|
|
906
|
+
this.log("notFound", parsedKey);
|
|
907
|
+
await this.emit("miss", { key: parsedKey });
|
|
908
|
+
this.remove(key);
|
|
909
|
+
return null;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* {@inheritdoc}
|
|
914
|
+
*/
|
|
915
|
+
async remove(key) {
|
|
916
|
+
const parsedKey = this.parseKey(key);
|
|
917
|
+
this.log("removing", parsedKey);
|
|
918
|
+
const fileDirectory = path.resolve(this.directory, parsedKey);
|
|
919
|
+
try {
|
|
920
|
+
await removeDirectoryAsync(fileDirectory);
|
|
921
|
+
this.log("removed", parsedKey);
|
|
922
|
+
await this.emit("removed", { key: parsedKey });
|
|
923
|
+
} catch (error) {
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* {@inheritdoc}
|
|
928
|
+
*/
|
|
929
|
+
async flush() {
|
|
930
|
+
this.log("flushing");
|
|
931
|
+
if (this.options.globalPrefix) {
|
|
932
|
+
await this.removeNamespace("");
|
|
933
|
+
} else {
|
|
934
|
+
await removeDirectoryAsync(this.directory);
|
|
935
|
+
}
|
|
936
|
+
this.log("flushed");
|
|
937
|
+
await this.emit("flushed");
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* {@inheritdoc}
|
|
941
|
+
*/
|
|
942
|
+
async connect() {
|
|
943
|
+
this.log("connecting");
|
|
944
|
+
await ensureDirectoryAsync(this.directory);
|
|
945
|
+
this.log("connected");
|
|
946
|
+
await this.emit("connected");
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// ../../warlock.js/cache/src/drivers/lru-memory-cache-driver.ts
|
|
951
|
+
var CacheNode = class {
|
|
952
|
+
constructor(key, value, ttl) {
|
|
953
|
+
this.key = key;
|
|
954
|
+
this.value = value;
|
|
955
|
+
if (ttl && ttl !== Infinity) {
|
|
956
|
+
this.expiresAt = Date.now() + ttl * 1e3;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
next = null;
|
|
960
|
+
prev = null;
|
|
961
|
+
expiresAt;
|
|
962
|
+
get isExpired() {
|
|
963
|
+
return this.expiresAt !== void 0 && this.expiresAt < Date.now();
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
var LRUMemoryCacheDriver = class extends BaseCacheDriver {
|
|
967
|
+
/**
|
|
968
|
+
* {@inheritdoc}
|
|
969
|
+
*/
|
|
970
|
+
name = "lru";
|
|
971
|
+
/**
|
|
972
|
+
* Cache map
|
|
973
|
+
*/
|
|
974
|
+
cache = /* @__PURE__ */ new Map();
|
|
975
|
+
/**
|
|
976
|
+
* Head of the cache
|
|
977
|
+
*/
|
|
978
|
+
head = new CacheNode("", null);
|
|
979
|
+
/**
|
|
980
|
+
* Tail of the cache
|
|
981
|
+
*/
|
|
982
|
+
tail = new CacheNode("", null);
|
|
983
|
+
/**
|
|
984
|
+
* Cleanup interval reference
|
|
985
|
+
*/
|
|
986
|
+
cleanupInterval;
|
|
987
|
+
/**
|
|
988
|
+
* {@inheritdoc}
|
|
989
|
+
*/
|
|
990
|
+
constructor() {
|
|
991
|
+
super();
|
|
992
|
+
this.init();
|
|
993
|
+
this.startCleanup();
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Initialize the cache
|
|
997
|
+
*/
|
|
998
|
+
init() {
|
|
999
|
+
this.head.next = this.tail;
|
|
1000
|
+
this.tail.prev = this.head;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Start the cleanup process for expired items
|
|
1004
|
+
*/
|
|
1005
|
+
startCleanup() {
|
|
1006
|
+
if (this.cleanupInterval) {
|
|
1007
|
+
clearInterval(this.cleanupInterval);
|
|
1008
|
+
}
|
|
1009
|
+
this.cleanupInterval = setInterval(async () => {
|
|
1010
|
+
const now = Date.now();
|
|
1011
|
+
const expiredKeys = [];
|
|
1012
|
+
for (const [key, node] of this.cache) {
|
|
1013
|
+
if (node.expiresAt && node.expiresAt <= now) {
|
|
1014
|
+
expiredKeys.push(key);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
for (const key of expiredKeys) {
|
|
1018
|
+
const node = this.cache.get(key);
|
|
1019
|
+
if (node) {
|
|
1020
|
+
this.removeNode(node);
|
|
1021
|
+
this.cache.delete(key);
|
|
1022
|
+
this.log("expired", key);
|
|
1023
|
+
await this.emit("expired", { key });
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}, 1e3);
|
|
1027
|
+
this.cleanupInterval.unref();
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* {@inheritdoc}
|
|
1031
|
+
*/
|
|
1032
|
+
async removeNamespace(_namespace) {
|
|
1033
|
+
throw new Error("Namespace is not supported in LRU cache driver.");
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* {@inheritdoc}
|
|
1037
|
+
*/
|
|
1038
|
+
async set(key, value, ttl) {
|
|
1039
|
+
key = this.parseKey(key);
|
|
1040
|
+
this.log("caching", key);
|
|
1041
|
+
if (ttl === void 0) {
|
|
1042
|
+
ttl = this.ttl;
|
|
1043
|
+
}
|
|
1044
|
+
const existingNode = this.cache.get(key);
|
|
1045
|
+
if (existingNode) {
|
|
1046
|
+
existingNode.value = value;
|
|
1047
|
+
if (ttl && ttl !== Infinity) {
|
|
1048
|
+
existingNode.expiresAt = Date.now() + ttl * 1e3;
|
|
1049
|
+
} else {
|
|
1050
|
+
existingNode.expiresAt = void 0;
|
|
1051
|
+
}
|
|
1052
|
+
this.moveHead(existingNode);
|
|
1053
|
+
} else {
|
|
1054
|
+
const newNode = new CacheNode(key, value, ttl);
|
|
1055
|
+
this.cache.set(key, newNode);
|
|
1056
|
+
this.addNode(newNode);
|
|
1057
|
+
if (this.cache.size > this.capacity) {
|
|
1058
|
+
this.removeTail();
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
this.log("cached", key);
|
|
1062
|
+
await this.emit("set", { key, value, ttl });
|
|
1063
|
+
return this;
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Move the node to the head
|
|
1067
|
+
*/
|
|
1068
|
+
moveHead(node) {
|
|
1069
|
+
this.removeNode(node);
|
|
1070
|
+
this.addNode(node);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Remove the node from the cache
|
|
1074
|
+
*/
|
|
1075
|
+
removeNode(node) {
|
|
1076
|
+
node.prev.next = node.next;
|
|
1077
|
+
node.next.prev = node.prev;
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Add the node to the head
|
|
1081
|
+
*/
|
|
1082
|
+
addNode(node) {
|
|
1083
|
+
node.next = this.head.next;
|
|
1084
|
+
node.prev = this.head;
|
|
1085
|
+
this.head.next.prev = node;
|
|
1086
|
+
this.head.next = node;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Remove the tail node
|
|
1090
|
+
*/
|
|
1091
|
+
removeTail() {
|
|
1092
|
+
const node = this.tail.prev;
|
|
1093
|
+
this.removeNode(node);
|
|
1094
|
+
this.cache.delete(node.key);
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* {@inheritdoc}
|
|
1098
|
+
*/
|
|
1099
|
+
async get(key) {
|
|
1100
|
+
const parsedKey = this.parseKey(key);
|
|
1101
|
+
this.log("fetching", parsedKey);
|
|
1102
|
+
const node = this.cache.get(parsedKey);
|
|
1103
|
+
if (!node) {
|
|
1104
|
+
this.log("notFound", parsedKey);
|
|
1105
|
+
await this.emit("miss", { key: parsedKey });
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
if (node.isExpired) {
|
|
1109
|
+
this.removeNode(node);
|
|
1110
|
+
this.cache.delete(parsedKey);
|
|
1111
|
+
this.log("expired", parsedKey);
|
|
1112
|
+
await this.emit("expired", { key: parsedKey });
|
|
1113
|
+
await this.emit("miss", { key: parsedKey });
|
|
1114
|
+
return null;
|
|
1115
|
+
}
|
|
1116
|
+
this.moveHead(node);
|
|
1117
|
+
this.log("fetched", parsedKey);
|
|
1118
|
+
const value = node.value;
|
|
1119
|
+
if (value === null || value === void 0) {
|
|
1120
|
+
return value;
|
|
1121
|
+
}
|
|
1122
|
+
const type = typeof value;
|
|
1123
|
+
if (type === "string" || type === "number" || type === "boolean") {
|
|
1124
|
+
await this.emit("hit", { key: parsedKey, value });
|
|
1125
|
+
return value;
|
|
1126
|
+
}
|
|
1127
|
+
try {
|
|
1128
|
+
const clonedValue = structuredClone(value);
|
|
1129
|
+
await this.emit("hit", { key: parsedKey, value: clonedValue });
|
|
1130
|
+
return clonedValue;
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
this.logError(`Failed to clone cached value for ${parsedKey}`, error);
|
|
1133
|
+
throw error;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* {@inheritdoc}
|
|
1138
|
+
*/
|
|
1139
|
+
async remove(key) {
|
|
1140
|
+
const parsedKey = this.parseKey(key);
|
|
1141
|
+
this.log("removing", parsedKey);
|
|
1142
|
+
const node = this.cache.get(parsedKey);
|
|
1143
|
+
if (node) {
|
|
1144
|
+
this.removeNode(node);
|
|
1145
|
+
this.cache.delete(parsedKey);
|
|
1146
|
+
}
|
|
1147
|
+
this.log("removed", parsedKey);
|
|
1148
|
+
await this.emit("removed", { key: parsedKey });
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* {@inheritdoc}
|
|
1152
|
+
*/
|
|
1153
|
+
async flush() {
|
|
1154
|
+
this.log("flushing");
|
|
1155
|
+
this.cache.clear();
|
|
1156
|
+
this.init();
|
|
1157
|
+
this.log("flushed");
|
|
1158
|
+
await this.emit("flushed");
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Get lru capacity
|
|
1162
|
+
*/
|
|
1163
|
+
get capacity() {
|
|
1164
|
+
return this.options.capacity || 1e3;
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* {@inheritdoc}
|
|
1168
|
+
*/
|
|
1169
|
+
async disconnect() {
|
|
1170
|
+
if (this.cleanupInterval) {
|
|
1171
|
+
clearInterval(this.cleanupInterval);
|
|
1172
|
+
this.cleanupInterval = void 0;
|
|
1173
|
+
}
|
|
1174
|
+
await super.disconnect();
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
var MemoryCacheDriver = class extends BaseCacheDriver {
|
|
1178
|
+
/**
|
|
1179
|
+
* {@inheritdoc}
|
|
1180
|
+
*/
|
|
1181
|
+
name = "memory";
|
|
1182
|
+
/**
|
|
1183
|
+
* Cached data
|
|
1184
|
+
*/
|
|
1185
|
+
data = {};
|
|
1186
|
+
/**
|
|
1187
|
+
* List of data that will be cleared from cache
|
|
1188
|
+
*/
|
|
1189
|
+
temporaryData = {};
|
|
1190
|
+
/**
|
|
1191
|
+
* Cleanup interval reference
|
|
1192
|
+
*/
|
|
1193
|
+
cleanupInterval;
|
|
1194
|
+
/**
|
|
1195
|
+
* Access order tracking for LRU eviction (when maxSize is set)
|
|
1196
|
+
*/
|
|
1197
|
+
accessOrder = [];
|
|
1198
|
+
/**
|
|
1199
|
+
* {@inheritdoc}
|
|
1200
|
+
*/
|
|
1201
|
+
constructor() {
|
|
1202
|
+
super();
|
|
1203
|
+
this.startCleanup();
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Start the cleanup process whenever a data that has a cache key is set
|
|
1207
|
+
*/
|
|
1208
|
+
startCleanup() {
|
|
1209
|
+
if (this.cleanupInterval) {
|
|
1210
|
+
clearInterval(this.cleanupInterval);
|
|
1211
|
+
}
|
|
1212
|
+
this.cleanupInterval = setInterval(async () => {
|
|
1213
|
+
const now = Date.now();
|
|
1214
|
+
for (const key in this.temporaryData) {
|
|
1215
|
+
if (this.temporaryData[key].expiresAt <= now) {
|
|
1216
|
+
await this.remove(this.temporaryData[key].key);
|
|
1217
|
+
delete this.temporaryData[key];
|
|
1218
|
+
this.log("expired", key);
|
|
1219
|
+
await this.emit("expired", { key });
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}, 1e3);
|
|
1223
|
+
this.cleanupInterval.unref();
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* {@inheritdoc}
|
|
1227
|
+
*/
|
|
1228
|
+
async removeNamespace(namespace) {
|
|
1229
|
+
this.log("clearing", namespace);
|
|
1230
|
+
namespace = this.parseKey(namespace);
|
|
1231
|
+
unset(this.data, [namespace]);
|
|
1232
|
+
this.log("cleared", namespace);
|
|
1233
|
+
return this;
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* {@inheritdoc}
|
|
1237
|
+
*/
|
|
1238
|
+
async set(key, value, ttl) {
|
|
1239
|
+
const parsedKey = this.parseKey(key);
|
|
1240
|
+
this.log("caching", parsedKey);
|
|
1241
|
+
if (ttl === void 0) {
|
|
1242
|
+
ttl = this.ttl;
|
|
1243
|
+
}
|
|
1244
|
+
const data = this.prepareDataForStorage(value, ttl);
|
|
1245
|
+
if (ttl) {
|
|
1246
|
+
this.setTemporaryData(key, parsedKey, ttl);
|
|
1247
|
+
}
|
|
1248
|
+
const existingData = get(this.data, parsedKey);
|
|
1249
|
+
const isNewKey = !existingData;
|
|
1250
|
+
set(this.data, parsedKey, data);
|
|
1251
|
+
this.trackAccess(parsedKey);
|
|
1252
|
+
if (isNewKey && this.options.maxSize) {
|
|
1253
|
+
await this.enforceMaxSize();
|
|
1254
|
+
}
|
|
1255
|
+
this.log("cached", parsedKey);
|
|
1256
|
+
await this.emit("set", { key: parsedKey, value, ttl });
|
|
1257
|
+
return this;
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* {@inheritdoc}
|
|
1261
|
+
*/
|
|
1262
|
+
async get(key) {
|
|
1263
|
+
const parsedKey = this.parseKey(key);
|
|
1264
|
+
this.log("fetching", parsedKey);
|
|
1265
|
+
const value = get(this.data, parsedKey);
|
|
1266
|
+
if (!value) {
|
|
1267
|
+
this.log("notFound", parsedKey);
|
|
1268
|
+
await this.emit("miss", { key: parsedKey });
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
const result = await this.parseCachedData(parsedKey, value);
|
|
1272
|
+
if (result === null) {
|
|
1273
|
+
await this.emit("miss", { key: parsedKey });
|
|
1274
|
+
} else {
|
|
1275
|
+
this.trackAccess(parsedKey);
|
|
1276
|
+
await this.emit("hit", { key: parsedKey, value: result });
|
|
1277
|
+
}
|
|
1278
|
+
return result;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* {@inheritdoc}
|
|
1282
|
+
*/
|
|
1283
|
+
async remove(key) {
|
|
1284
|
+
const parsedKey = this.parseKey(key);
|
|
1285
|
+
this.log("removing", parsedKey);
|
|
1286
|
+
unset(this.data, [parsedKey]);
|
|
1287
|
+
delete this.temporaryData[parsedKey];
|
|
1288
|
+
this.removeFromAccessOrder(parsedKey);
|
|
1289
|
+
this.log("removed", parsedKey);
|
|
1290
|
+
await this.emit("removed", { key: parsedKey });
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* {@inheritdoc}
|
|
1294
|
+
*/
|
|
1295
|
+
async flush() {
|
|
1296
|
+
this.log("flushing");
|
|
1297
|
+
if (this.options.globalPrefix) {
|
|
1298
|
+
this.removeNamespace("");
|
|
1299
|
+
} else {
|
|
1300
|
+
this.data = {};
|
|
1301
|
+
this.accessOrder = [];
|
|
1302
|
+
}
|
|
1303
|
+
this.log("flushed");
|
|
1304
|
+
await this.emit("flushed");
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Set the temporary data
|
|
1308
|
+
*/
|
|
1309
|
+
setTemporaryData(key, parsedKey, ttl) {
|
|
1310
|
+
this.temporaryData[parsedKey] = {
|
|
1311
|
+
key: JSON.stringify(key),
|
|
1312
|
+
expiresAt: Date.now() + ttl * 1e3
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Track access for LRU eviction
|
|
1317
|
+
*/
|
|
1318
|
+
trackAccess(key) {
|
|
1319
|
+
if (!this.options.maxSize) return;
|
|
1320
|
+
const index = this.accessOrder.indexOf(key);
|
|
1321
|
+
if (index > -1) {
|
|
1322
|
+
this.accessOrder.splice(index, 1);
|
|
1323
|
+
}
|
|
1324
|
+
this.accessOrder.push(key);
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* Remove key from access order tracking
|
|
1328
|
+
*/
|
|
1329
|
+
removeFromAccessOrder(key) {
|
|
1330
|
+
const index = this.accessOrder.indexOf(key);
|
|
1331
|
+
if (index > -1) {
|
|
1332
|
+
this.accessOrder.splice(index, 1);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Enforce max size by evicting least recently used items
|
|
1337
|
+
*/
|
|
1338
|
+
async enforceMaxSize() {
|
|
1339
|
+
if (!this.options.maxSize) return;
|
|
1340
|
+
const cacheSize = this.getCacheSize();
|
|
1341
|
+
while (cacheSize > this.options.maxSize && this.accessOrder.length > 0) {
|
|
1342
|
+
const lruKey = this.accessOrder.shift();
|
|
1343
|
+
if (lruKey) {
|
|
1344
|
+
this.log("removing", lruKey);
|
|
1345
|
+
unset(this.data, [lruKey]);
|
|
1346
|
+
delete this.temporaryData[lruKey];
|
|
1347
|
+
this.log("removed", lruKey);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Get current cache size (number of cached items)
|
|
1353
|
+
*/
|
|
1354
|
+
getCacheSize() {
|
|
1355
|
+
return Object.keys(this.data).length;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* {@inheritdoc}
|
|
1359
|
+
*/
|
|
1360
|
+
async disconnect() {
|
|
1361
|
+
if (this.cleanupInterval) {
|
|
1362
|
+
clearInterval(this.cleanupInterval);
|
|
1363
|
+
this.cleanupInterval = void 0;
|
|
1364
|
+
}
|
|
1365
|
+
await super.disconnect();
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
var MemoryExtendedCacheDriver = class extends MemoryCacheDriver {
|
|
1369
|
+
/**
|
|
1370
|
+
* {@inheritdoc}
|
|
1371
|
+
*/
|
|
1372
|
+
name = "memoryExtended";
|
|
1373
|
+
/**
|
|
1374
|
+
* {@inheritdoc}
|
|
1375
|
+
*/
|
|
1376
|
+
async get(key) {
|
|
1377
|
+
const parsedKey = this.parseKey(key);
|
|
1378
|
+
this.log("fetching", parsedKey);
|
|
1379
|
+
const value = get(this.data, parsedKey);
|
|
1380
|
+
if (!value) {
|
|
1381
|
+
this.log("notFound", parsedKey);
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
const ttl = value.ttl || this.options.ttl;
|
|
1385
|
+
if (ttl) {
|
|
1386
|
+
this.setTemporaryData(key, parsedKey, ttl);
|
|
1387
|
+
value.expiresAt = this.getExpiresAt(ttl);
|
|
1388
|
+
}
|
|
1389
|
+
return this.parseCachedData(parsedKey, value);
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
var NullCacheDriver = class extends BaseCacheDriver {
|
|
1393
|
+
/**
|
|
1394
|
+
* Options list
|
|
1395
|
+
*/
|
|
1396
|
+
options = {};
|
|
1397
|
+
/**
|
|
1398
|
+
* {@inheritdoc}
|
|
1399
|
+
*/
|
|
1400
|
+
name = "null";
|
|
1401
|
+
/**
|
|
1402
|
+
* Cached data
|
|
1403
|
+
*/
|
|
1404
|
+
data = {};
|
|
1405
|
+
/**
|
|
1406
|
+
* {@inheritdoc}
|
|
1407
|
+
*/
|
|
1408
|
+
get client() {
|
|
1409
|
+
return this;
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Constructor
|
|
1413
|
+
*/
|
|
1414
|
+
constructor(options = {}) {
|
|
1415
|
+
super();
|
|
1416
|
+
this.setOptions(options);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* {@inheritdoc}
|
|
1420
|
+
*/
|
|
1421
|
+
setOptions(options) {
|
|
1422
|
+
this.options = options;
|
|
1423
|
+
return this;
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* {@inheritdoc}
|
|
1427
|
+
*/
|
|
1428
|
+
parseKey(_key) {
|
|
1429
|
+
return "";
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* {@inheritdoc}
|
|
1433
|
+
*/
|
|
1434
|
+
async removeNamespace(namespace) {
|
|
1435
|
+
log.info("cache", "clearing namespace", namespace);
|
|
1436
|
+
log.success("cache", "namespace cleared", namespace);
|
|
1437
|
+
return this;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* {@inheritdoc}
|
|
1441
|
+
*/
|
|
1442
|
+
async set(key, _value) {
|
|
1443
|
+
log.info("cache", "setting key", key);
|
|
1444
|
+
log.success("cache", "key set", key);
|
|
1445
|
+
return this;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* {@inheritdoc}
|
|
1449
|
+
*/
|
|
1450
|
+
async get(key) {
|
|
1451
|
+
log.info("cache", "fetching", key);
|
|
1452
|
+
log.success("cache", "fetched", key);
|
|
1453
|
+
return null;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* {@inheritdoc}
|
|
1457
|
+
*/
|
|
1458
|
+
async remove(key) {
|
|
1459
|
+
log.info("cache", "removing", key);
|
|
1460
|
+
log.success("cache", "removed", key);
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* {@inheritdoc}
|
|
1464
|
+
*/
|
|
1465
|
+
async flush() {
|
|
1466
|
+
log.info("cache", "flushing", "all");
|
|
1467
|
+
log.success("cache", "flushed", "all");
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* {@inheritdoc}
|
|
1471
|
+
*/
|
|
1472
|
+
async connect() {
|
|
1473
|
+
log.success("cache", "connected", "Connected to null cache driver");
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
var RedisCacheDriver = class extends BaseCacheDriver {
|
|
1477
|
+
/**
|
|
1478
|
+
* Cache driver name
|
|
1479
|
+
*/
|
|
1480
|
+
name = "redis";
|
|
1481
|
+
/**
|
|
1482
|
+
* {@inheritdoc}
|
|
1483
|
+
*/
|
|
1484
|
+
setOptions(options) {
|
|
1485
|
+
if (!options.url && !options.host) {
|
|
1486
|
+
throw new CacheConfigurationError(
|
|
1487
|
+
"Redis driver requires either 'url' or 'host' option to be configured."
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
return super.setOptions(options);
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* {@inheritDoc}
|
|
1494
|
+
*/
|
|
1495
|
+
async removeNamespace(namespace) {
|
|
1496
|
+
namespace = this.parseKey(namespace);
|
|
1497
|
+
this.log("clearing", namespace);
|
|
1498
|
+
const keys = await this.client?.keys(`${namespace}*`);
|
|
1499
|
+
if (!keys || keys.length === 0) {
|
|
1500
|
+
this.log("notFound", namespace);
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
await this.client?.del(keys);
|
|
1504
|
+
this.log("cleared", namespace);
|
|
1505
|
+
return keys;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* {@inheritDoc}
|
|
1509
|
+
*/
|
|
1510
|
+
async set(key, value, ttl) {
|
|
1511
|
+
key = this.parseKey(key);
|
|
1512
|
+
this.log("caching", key);
|
|
1513
|
+
if (ttl === void 0) {
|
|
1514
|
+
ttl = this.ttl;
|
|
1515
|
+
}
|
|
1516
|
+
if (ttl && ttl !== Infinity) {
|
|
1517
|
+
await this.client?.set(key, JSON.stringify(value), { EX: ttl });
|
|
1518
|
+
} else {
|
|
1519
|
+
await this.client?.set(key, JSON.stringify(value));
|
|
1520
|
+
}
|
|
1521
|
+
this.log("cached", key);
|
|
1522
|
+
await this.emit("set", { key, value, ttl });
|
|
1523
|
+
return value;
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* {@inheritDoc}
|
|
1527
|
+
*/
|
|
1528
|
+
async get(key) {
|
|
1529
|
+
key = this.parseKey(key);
|
|
1530
|
+
this.log("fetching", key);
|
|
1531
|
+
const value = await this.client?.get(key);
|
|
1532
|
+
if (!value) {
|
|
1533
|
+
this.log("notFound", key);
|
|
1534
|
+
await this.emit("miss", { key });
|
|
1535
|
+
return null;
|
|
1536
|
+
}
|
|
1537
|
+
this.log("fetched", key);
|
|
1538
|
+
const parsedValue = JSON.parse(value);
|
|
1539
|
+
if (parsedValue === null || parsedValue === void 0) {
|
|
1540
|
+
await this.emit("hit", { key, value: parsedValue });
|
|
1541
|
+
return parsedValue;
|
|
1542
|
+
}
|
|
1543
|
+
const type = typeof parsedValue;
|
|
1544
|
+
if (type === "string" || type === "number" || type === "boolean") {
|
|
1545
|
+
await this.emit("hit", { key, value: parsedValue });
|
|
1546
|
+
return parsedValue;
|
|
1547
|
+
}
|
|
1548
|
+
try {
|
|
1549
|
+
const clonedValue = structuredClone(parsedValue);
|
|
1550
|
+
await this.emit("hit", { key, value: clonedValue });
|
|
1551
|
+
return clonedValue;
|
|
1552
|
+
} catch (error) {
|
|
1553
|
+
this.logError(`Failed to clone cached value for ${key}`, error);
|
|
1554
|
+
throw error;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* {@inheritDoc}
|
|
1559
|
+
*/
|
|
1560
|
+
async remove(key) {
|
|
1561
|
+
key = this.parseKey(key);
|
|
1562
|
+
this.log("removing", key);
|
|
1563
|
+
await this.client?.del(key);
|
|
1564
|
+
this.log("removed", key);
|
|
1565
|
+
await this.emit("removed", { key });
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* {@inheritDoc}
|
|
1569
|
+
*/
|
|
1570
|
+
async flush() {
|
|
1571
|
+
this.log("flushing");
|
|
1572
|
+
if (this.options.globalPrefix) {
|
|
1573
|
+
await this.removeNamespace("");
|
|
1574
|
+
} else {
|
|
1575
|
+
await this.client?.flushAll();
|
|
1576
|
+
}
|
|
1577
|
+
this.log("flushed");
|
|
1578
|
+
await this.emit("flushed");
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* {@inheritDoc}
|
|
1582
|
+
*/
|
|
1583
|
+
async connect() {
|
|
1584
|
+
if (this.clientDriver) return;
|
|
1585
|
+
const options = this.options;
|
|
1586
|
+
if (options && !options.url && options.host) {
|
|
1587
|
+
const auth = options.password || options.username ? `${options.username}:${options.password}@` : "";
|
|
1588
|
+
if (!options.url) {
|
|
1589
|
+
const host = options.host || "localhost";
|
|
1590
|
+
const port = options.port || 6379;
|
|
1591
|
+
options.url = `redis://${auth}${host}:${port}`;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
const clientOptions = {
|
|
1595
|
+
...options,
|
|
1596
|
+
...this.options.clientOptions || {}
|
|
1597
|
+
};
|
|
1598
|
+
this.log("connecting");
|
|
1599
|
+
const { createClient } = await import('redis');
|
|
1600
|
+
this.client = createClient(clientOptions);
|
|
1601
|
+
this.client.on("error", (error) => {
|
|
1602
|
+
this.log("error", error.message);
|
|
1603
|
+
});
|
|
1604
|
+
try {
|
|
1605
|
+
await this.client.connect();
|
|
1606
|
+
this.log("connected");
|
|
1607
|
+
await this.emit("connected");
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
log.error("cache", "redis", error);
|
|
1610
|
+
await this.emit("error", { error });
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* {@inheritDoc}
|
|
1615
|
+
*/
|
|
1616
|
+
async disconnect() {
|
|
1617
|
+
if (!this.client) return;
|
|
1618
|
+
this.log("disconnecting");
|
|
1619
|
+
await this.client.quit();
|
|
1620
|
+
this.log("disconnected");
|
|
1621
|
+
await this.emit("disconnected");
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Atomic increment using Redis native INCRBY command
|
|
1625
|
+
* {@inheritdoc}
|
|
1626
|
+
*/
|
|
1627
|
+
async increment(key, value = 1) {
|
|
1628
|
+
const parsedKey = this.parseKey(key);
|
|
1629
|
+
this.log("caching", parsedKey);
|
|
1630
|
+
const result = await this.client?.incrBy(parsedKey, value);
|
|
1631
|
+
this.log("cached", parsedKey);
|
|
1632
|
+
await this.emit("set", { key: parsedKey, value: result, ttl: void 0 });
|
|
1633
|
+
return result || 0;
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Atomic decrement using Redis native DECRBY command
|
|
1637
|
+
* {@inheritdoc}
|
|
1638
|
+
*/
|
|
1639
|
+
async decrement(key, value = 1) {
|
|
1640
|
+
const parsedKey = this.parseKey(key);
|
|
1641
|
+
this.log("caching", parsedKey);
|
|
1642
|
+
const result = await this.client?.decrBy(parsedKey, value);
|
|
1643
|
+
this.log("cached", parsedKey);
|
|
1644
|
+
await this.emit("set", { key: parsedKey, value: result, ttl: void 0 });
|
|
1645
|
+
return result || 0;
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Set if not exists (atomic operation)
|
|
1649
|
+
* Returns true if key was set, false if key already existed
|
|
1650
|
+
*/
|
|
1651
|
+
async setNX(key, value, ttl) {
|
|
1652
|
+
const parsedKey = this.parseKey(key);
|
|
1653
|
+
this.log("caching", parsedKey);
|
|
1654
|
+
if (ttl === void 0) {
|
|
1655
|
+
ttl = this.ttl;
|
|
1656
|
+
}
|
|
1657
|
+
let result;
|
|
1658
|
+
if (ttl && ttl !== Infinity) {
|
|
1659
|
+
result = await this.client?.set(parsedKey, JSON.stringify(value), {
|
|
1660
|
+
NX: true,
|
|
1661
|
+
EX: ttl
|
|
1662
|
+
});
|
|
1663
|
+
} else {
|
|
1664
|
+
result = await this.client?.set(parsedKey, JSON.stringify(value), {
|
|
1665
|
+
NX: true
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
const wasSet = result === "OK";
|
|
1669
|
+
if (wasSet) {
|
|
1670
|
+
this.log("cached", parsedKey);
|
|
1671
|
+
await this.emit("set", { key: parsedKey, value, ttl });
|
|
1672
|
+
} else {
|
|
1673
|
+
this.log("notFound", parsedKey);
|
|
1674
|
+
}
|
|
1675
|
+
return wasSet;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1679
|
+
export { BaseCacheDriver, CACHE_FOR, CacheConfigurationError, CacheConnectionError, CacheDriverNotInitializedError, CacheError, CacheManager, FileCacheDriver, LRUMemoryCacheDriver, MemoryCacheDriver, MemoryExtendedCacheDriver, NullCacheDriver, RedisCacheDriver, TaggedCache, cache, parseCacheKey };
|
|
1680
|
+
//# sourceMappingURL=index.js.map
|
|
1681
|
+
//# sourceMappingURL=index.js.map
|