@keyv/redis 4.5.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -8
- package/dist/index.cjs +184 -108
- package/dist/index.d.cts +62 -16
- package/dist/index.d.ts +62 -16
- package/dist/index.js +184 -108
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ Redis storage adapter for [Keyv](https://github.com/jaredwray/keyv).
|
|
|
29
29
|
* [Using Generic Types](#using-generic-types)
|
|
30
30
|
* [Performance Considerations](#performance-considerations)
|
|
31
31
|
* [High Memory Usage on Redis Server](#high-memory-usage-on-redis-server)
|
|
32
|
-
* [Gracefully Handling
|
|
32
|
+
* [Gracefully Handling Errors and Timeouts](#gracefully-handling-errors-and-timeouts)
|
|
33
33
|
* [Using Cacheable with Redis](#using-cacheable-with-redis)
|
|
34
34
|
* [Clustering and TLS Support](#clustering-and-tls-support)
|
|
35
35
|
* [API](#api)
|
|
@@ -131,10 +131,26 @@ export type KeyvRedisOptions = {
|
|
|
131
131
|
noNamespaceAffectsAll?: boolean;
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
134
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
135
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
136
136
|
*/
|
|
137
|
-
|
|
137
|
+
throwOnConnectError?: boolean;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
141
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
142
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
143
|
+
* and returns no-op responses.
|
|
144
|
+
* @default false
|
|
145
|
+
*/
|
|
146
|
+
throwErrors?: boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Timeout in milliseconds for the connection. Default is undefined, which uses the default timeout of the Redis client.
|
|
150
|
+
* If set, it will throw an error if the connection does not succeed within the specified time.
|
|
151
|
+
* @default undefined
|
|
152
|
+
*/
|
|
153
|
+
connectionTimeout?: number;
|
|
138
154
|
};
|
|
139
155
|
```
|
|
140
156
|
You can pass these options when creating a new `KeyvRedis` instance:
|
|
@@ -241,7 +257,7 @@ const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379', { useUnl
|
|
|
241
257
|
keyv.useUnlink = false;
|
|
242
258
|
```
|
|
243
259
|
|
|
244
|
-
# Gracefully Handling
|
|
260
|
+
# Gracefully Handling Errors and Timeouts
|
|
245
261
|
|
|
246
262
|
When using `@keyv/redis`, it is important to handle connection errors gracefully. You can do this by listening to the `error` event on the `KeyvRedis` instance. Here is an example of how to do that:
|
|
247
263
|
|
|
@@ -254,11 +270,13 @@ keyv.on('error', (error) => {
|
|
|
254
270
|
});
|
|
255
271
|
```
|
|
256
272
|
|
|
257
|
-
|
|
273
|
+
By default, the `KeyvRedis` instance will `throw an error` if the connection fails to connect. You can disable this behavior by setting the `throwOnConnectError` option to `false` when creating the `KeyvRedis` instance:
|
|
274
|
+
|
|
275
|
+
On `get`, `getMany`, `set`, `setMany`, `delete`, and `deleteMany`, if the connection is lost, it will emit an error and return a no-op value. You can catch this error and handle it accordingly. This is important to ensure that your application does not crash due to a lost connection to Redis.
|
|
258
276
|
|
|
259
|
-
|
|
277
|
+
If you want to handle connection errors, retries, and timeouts more gracefully, you can use the `throwErrors` option. This will throw an error if any operation fails, allowing you to catch it and handle it accordingly:
|
|
260
278
|
|
|
261
|
-
|
|
279
|
+
There is a default `Reconnect Strategy` if you pass in just a `uri` connection string we will automatically create a Redis client for you with the following reconnect strategy:
|
|
262
280
|
|
|
263
281
|
```typescript
|
|
264
282
|
export const defaultReconnectStrategy = (attempts: number): number | Error => {
|
package/dist/index.cjs
CHANGED
|
@@ -39,14 +39,14 @@ __export(index_exports, {
|
|
|
39
39
|
defaultReconnectStrategy: () => defaultReconnectStrategy
|
|
40
40
|
});
|
|
41
41
|
module.exports = __toCommonJS(index_exports);
|
|
42
|
-
var import_node_events = __toESM(require("events"), 1);
|
|
43
42
|
var import_client = require("@redis/client");
|
|
43
|
+
var import_hookified = require("hookified");
|
|
44
44
|
var import_keyv = require("keyv");
|
|
45
45
|
var import_cluster_key_slot = __toESM(require("cluster-key-slot"), 1);
|
|
46
46
|
var import_client2 = require("@redis/client");
|
|
47
47
|
var import_keyv2 = require("keyv");
|
|
48
48
|
var RedisErrorMessages = /* @__PURE__ */ ((RedisErrorMessages2) => {
|
|
49
|
-
RedisErrorMessages2["
|
|
49
|
+
RedisErrorMessages2["RedisClientNotConnectedThrown"] = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true.";
|
|
50
50
|
return RedisErrorMessages2;
|
|
51
51
|
})(RedisErrorMessages || {});
|
|
52
52
|
var defaultReconnectStrategy = (attempts) => {
|
|
@@ -54,17 +54,16 @@ var defaultReconnectStrategy = (attempts) => {
|
|
|
54
54
|
const jitter = (Math.random() - 0.5) * 100;
|
|
55
55
|
return backoff + jitter;
|
|
56
56
|
};
|
|
57
|
-
var KeyvRedis = class extends
|
|
57
|
+
var KeyvRedis = class extends import_hookified.Hookified {
|
|
58
58
|
_client = (0, import_client.createClient)();
|
|
59
59
|
_namespace;
|
|
60
60
|
_keyPrefixSeparator = "::";
|
|
61
61
|
_clearBatchSize = 1e3;
|
|
62
62
|
_useUnlink = true;
|
|
63
63
|
_noNamespaceAffectsAll = false;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// Whether to reconnect the client
|
|
64
|
+
_throwOnConnectError = true;
|
|
65
|
+
_throwErrors = false;
|
|
66
|
+
_connectionTimeout;
|
|
68
67
|
/**
|
|
69
68
|
* KeyvRedis constructor.
|
|
70
69
|
* @param {string | RedisClientOptions | RedisClientType} [connect] How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client.
|
|
@@ -74,6 +73,7 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
74
73
|
super();
|
|
75
74
|
const socket = {
|
|
76
75
|
reconnectStrategy: defaultReconnectStrategy
|
|
76
|
+
// Default timeout for the connection
|
|
77
77
|
};
|
|
78
78
|
if (connect) {
|
|
79
79
|
if (typeof connect === "string") {
|
|
@@ -116,6 +116,10 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
116
116
|
keyPrefixSeparator: this._keyPrefixSeparator,
|
|
117
117
|
clearBatchSize: this._clearBatchSize,
|
|
118
118
|
noNamespaceAffectsAll: this._noNamespaceAffectsAll,
|
|
119
|
+
useUnlink: this._useUnlink,
|
|
120
|
+
throwOnConnectError: this._throwOnConnectError,
|
|
121
|
+
throwErrors: this._throwErrors,
|
|
122
|
+
connectionTimeout: this._connectionTimeout,
|
|
119
123
|
dialect: "redis",
|
|
120
124
|
url
|
|
121
125
|
};
|
|
@@ -199,49 +203,82 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
199
203
|
this._noNamespaceAffectsAll = value;
|
|
200
204
|
}
|
|
201
205
|
/**
|
|
202
|
-
* Get
|
|
203
|
-
*
|
|
206
|
+
* Get if throwOnConnectError is set to true.
|
|
207
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
208
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
209
|
+
* @default true
|
|
204
210
|
*/
|
|
205
|
-
get
|
|
206
|
-
return this.
|
|
211
|
+
get throwOnConnectError() {
|
|
212
|
+
return this._throwOnConnectError;
|
|
207
213
|
}
|
|
208
214
|
/**
|
|
209
|
-
* Set
|
|
210
|
-
*
|
|
215
|
+
* Set if throwOnConnectError is set to true.
|
|
216
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
217
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
211
218
|
*/
|
|
212
|
-
set
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
set throwOnConnectError(value) {
|
|
220
|
+
this._throwOnConnectError = value;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get if throwErrors is set to true.
|
|
224
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
225
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
226
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
227
|
+
* and returns no-op responses.
|
|
228
|
+
* @default false
|
|
229
|
+
*/
|
|
230
|
+
get throwErrors() {
|
|
231
|
+
return this._throwErrors;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Set if throwErrors is set to true.
|
|
235
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
236
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
237
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
238
|
+
* and returns no-op responses.
|
|
239
|
+
*/
|
|
240
|
+
set throwErrors(value) {
|
|
241
|
+
this._throwErrors = value;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
245
|
+
* @default undefined
|
|
246
|
+
*/
|
|
247
|
+
get connectionTimeout() {
|
|
248
|
+
return this._connectionTimeout;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Set the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
252
|
+
* @default undefined
|
|
253
|
+
*/
|
|
254
|
+
set connectionTimeout(value) {
|
|
255
|
+
this._connectionTimeout = value;
|
|
219
256
|
}
|
|
220
257
|
/**
|
|
221
258
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
222
259
|
*/
|
|
223
260
|
async getClient() {
|
|
224
|
-
if (this._client.isOpen
|
|
261
|
+
if (this._client.isOpen) {
|
|
225
262
|
return this._client;
|
|
226
263
|
}
|
|
227
|
-
if (this._reconnectClient && this._client.isOpen) {
|
|
228
|
-
await this._client.disconnect();
|
|
229
|
-
}
|
|
230
264
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.initClient();
|
|
240
|
-
return this._client;
|
|
265
|
+
if (this._connectionTimeout === void 0) {
|
|
266
|
+
await this._client.connect();
|
|
267
|
+
} else {
|
|
268
|
+
await Promise.race([
|
|
269
|
+
this._client.connect(),
|
|
270
|
+
this.createTimeoutPromise(this._connectionTimeout)
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
241
273
|
} catch (error) {
|
|
242
274
|
this.emit("error", error);
|
|
243
|
-
|
|
275
|
+
if (this._throwOnConnectError) {
|
|
276
|
+
throw new Error("Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true." /* RedisClientNotConnectedThrown */);
|
|
277
|
+
}
|
|
278
|
+
await this.disconnect(true);
|
|
244
279
|
}
|
|
280
|
+
this.initClient();
|
|
281
|
+
return this._client;
|
|
245
282
|
}
|
|
246
283
|
/**
|
|
247
284
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
@@ -251,15 +288,18 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
251
288
|
*/
|
|
252
289
|
async set(key, value, ttl) {
|
|
253
290
|
const client = await this.getClient();
|
|
254
|
-
|
|
255
|
-
this.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
291
|
+
try {
|
|
292
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
293
|
+
if (ttl) {
|
|
294
|
+
await client.set(key, value, { PX: ttl });
|
|
295
|
+
} else {
|
|
296
|
+
await client.set(key, value);
|
|
297
|
+
}
|
|
298
|
+
} catch (error) {
|
|
299
|
+
this.emit("error", error);
|
|
300
|
+
if (this._throwErrors) {
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
263
303
|
}
|
|
264
304
|
}
|
|
265
305
|
/**
|
|
@@ -268,20 +308,23 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
268
308
|
*/
|
|
269
309
|
async setMany(entries) {
|
|
270
310
|
const client = await this.getClient();
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
311
|
+
try {
|
|
312
|
+
const multi = client.multi();
|
|
313
|
+
for (const { key, value, ttl } of entries) {
|
|
314
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
315
|
+
if (ttl) {
|
|
316
|
+
multi.set(prefixedKey, value, { PX: ttl });
|
|
317
|
+
} else {
|
|
318
|
+
multi.set(prefixedKey, value);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
await multi.exec();
|
|
322
|
+
} catch (error) {
|
|
323
|
+
this.emit("error", error);
|
|
324
|
+
if (this._throwErrors) {
|
|
325
|
+
throw error;
|
|
282
326
|
}
|
|
283
327
|
}
|
|
284
|
-
await multi.exec();
|
|
285
328
|
}
|
|
286
329
|
/**
|
|
287
330
|
* Check if a key exists in the store.
|
|
@@ -290,13 +333,17 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
290
333
|
*/
|
|
291
334
|
async has(key) {
|
|
292
335
|
const client = await this.getClient();
|
|
293
|
-
|
|
294
|
-
this.
|
|
336
|
+
try {
|
|
337
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
338
|
+
const exists = await client.exists(key);
|
|
339
|
+
return exists === 1;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
this.emit("error", error);
|
|
342
|
+
if (this._throwErrors) {
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
295
345
|
return false;
|
|
296
346
|
}
|
|
297
|
-
key = this.createKeyPrefix(key, this._namespace);
|
|
298
|
-
const exists = await client.exists(key);
|
|
299
|
-
return exists === 1;
|
|
300
347
|
}
|
|
301
348
|
/**
|
|
302
349
|
* Check if many keys exist in the store. This will be done as a single transaction.
|
|
@@ -305,17 +352,21 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
305
352
|
*/
|
|
306
353
|
async hasMany(keys) {
|
|
307
354
|
const client = await this.getClient();
|
|
308
|
-
|
|
309
|
-
|
|
355
|
+
try {
|
|
356
|
+
const multi = client.multi();
|
|
357
|
+
for (const key of keys) {
|
|
358
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
359
|
+
multi.exists(prefixedKey);
|
|
360
|
+
}
|
|
361
|
+
const results = await multi.exec();
|
|
362
|
+
return results.map((result) => result === 1);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
this.emit("error", error);
|
|
365
|
+
if (this._throwErrors) {
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
310
368
|
return Array.from({ length: keys.length }).fill(false);
|
|
311
369
|
}
|
|
312
|
-
const multi = client.multi();
|
|
313
|
-
for (const key of keys) {
|
|
314
|
-
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
315
|
-
multi.exists(prefixedKey);
|
|
316
|
-
}
|
|
317
|
-
const results = await multi.exec();
|
|
318
|
-
return results.map((result) => result === 1);
|
|
319
370
|
}
|
|
320
371
|
/**
|
|
321
372
|
* Get a value from the store. If the key does not exist, it will return undefined.
|
|
@@ -324,16 +375,20 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
324
375
|
*/
|
|
325
376
|
async get(key) {
|
|
326
377
|
const client = await this.getClient();
|
|
327
|
-
|
|
328
|
-
this.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
378
|
+
try {
|
|
379
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
380
|
+
const value = await client.get(key);
|
|
381
|
+
if (value === null) {
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
384
|
+
return value;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
this.emit("error", error);
|
|
387
|
+
if (this._throwErrors) {
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
334
390
|
return void 0;
|
|
335
391
|
}
|
|
336
|
-
return value;
|
|
337
392
|
}
|
|
338
393
|
/**
|
|
339
394
|
* Get many values from the store. If a key does not exist, it will return undefined.
|
|
@@ -350,6 +405,9 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
350
405
|
return values;
|
|
351
406
|
} catch (error) {
|
|
352
407
|
this.emit("error", error);
|
|
408
|
+
if (this._throwErrors) {
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
353
411
|
return Array.from({ length: keys.length }).fill(void 0);
|
|
354
412
|
}
|
|
355
413
|
}
|
|
@@ -360,14 +418,18 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
360
418
|
*/
|
|
361
419
|
async delete(key) {
|
|
362
420
|
const client = await this.getClient();
|
|
363
|
-
|
|
364
|
-
this.
|
|
421
|
+
try {
|
|
422
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
423
|
+
let deleted = 0;
|
|
424
|
+
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
425
|
+
return deleted > 0;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
this.emit("error", error);
|
|
428
|
+
if (this._throwErrors) {
|
|
429
|
+
throw error;
|
|
430
|
+
}
|
|
365
431
|
return false;
|
|
366
432
|
}
|
|
367
|
-
key = this.createKeyPrefix(key, this._namespace);
|
|
368
|
-
let deleted = 0;
|
|
369
|
-
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
370
|
-
return deleted > 0;
|
|
371
433
|
}
|
|
372
434
|
/**
|
|
373
435
|
* Delete many keys from the store. This will be done as a single transaction.
|
|
@@ -377,23 +439,26 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
377
439
|
async deleteMany(keys) {
|
|
378
440
|
let result = false;
|
|
379
441
|
const client = await this.getClient();
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
} else {
|
|
390
|
-
multi.del(prefixedKey);
|
|
442
|
+
try {
|
|
443
|
+
const multi = client.multi();
|
|
444
|
+
for (const key of keys) {
|
|
445
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
446
|
+
if (this._useUnlink) {
|
|
447
|
+
multi.unlink(prefixedKey);
|
|
448
|
+
} else {
|
|
449
|
+
multi.del(prefixedKey);
|
|
450
|
+
}
|
|
391
451
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
452
|
+
const results = await multi.exec();
|
|
453
|
+
for (const deleted of results) {
|
|
454
|
+
if (typeof deleted === "number" && deleted > 0) {
|
|
455
|
+
result = true;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
} catch (error) {
|
|
459
|
+
this.emit("error", error);
|
|
460
|
+
if (this._throwErrors) {
|
|
461
|
+
throw error;
|
|
397
462
|
}
|
|
398
463
|
}
|
|
399
464
|
return result;
|
|
@@ -551,9 +616,6 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
551
616
|
*/
|
|
552
617
|
async getSlotMaster(slot) {
|
|
553
618
|
const connection = await this.getClient();
|
|
554
|
-
if (!connection) {
|
|
555
|
-
throw new Error("Redis client is not connected or has failed to connect" /* RedisClientNotConnected */);
|
|
556
|
-
}
|
|
557
619
|
if (this.isCluster()) {
|
|
558
620
|
const cluster = connection;
|
|
559
621
|
const mainNode = cluster.slots[slot].master;
|
|
@@ -606,14 +668,17 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
606
668
|
if (options.noNamespaceAffectsAll !== void 0) {
|
|
607
669
|
this._noNamespaceAffectsAll = options.noNamespaceAffectsAll;
|
|
608
670
|
}
|
|
609
|
-
if (options.
|
|
610
|
-
this.
|
|
671
|
+
if (options.throwOnConnectError !== void 0) {
|
|
672
|
+
this._throwOnConnectError = options.throwOnConnectError;
|
|
673
|
+
}
|
|
674
|
+
if (options.throwErrors !== void 0) {
|
|
675
|
+
this._throwErrors = options.throwErrors;
|
|
676
|
+
}
|
|
677
|
+
if (options.connectionTimeout !== void 0) {
|
|
678
|
+
this._connectionTimeout = options.connectionTimeout;
|
|
611
679
|
}
|
|
612
680
|
}
|
|
613
681
|
initClient() {
|
|
614
|
-
this._client.on("error", (error) => {
|
|
615
|
-
this.emit("error", error);
|
|
616
|
-
});
|
|
617
682
|
this._client.on("connect", () => {
|
|
618
683
|
this.emit("connect", this._client);
|
|
619
684
|
});
|
|
@@ -624,6 +689,17 @@ var KeyvRedis = class extends import_node_events.default {
|
|
|
624
689
|
this.emit("reconnecting", reconnectInfo);
|
|
625
690
|
});
|
|
626
691
|
}
|
|
692
|
+
async createTimeoutPromise(timeoutMs) {
|
|
693
|
+
return new Promise((_, reject) => (
|
|
694
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
695
|
+
setTimeout(
|
|
696
|
+
() => {
|
|
697
|
+
reject(new Error(`Redis timed out after ${timeoutMs}ms`));
|
|
698
|
+
},
|
|
699
|
+
timeoutMs
|
|
700
|
+
)
|
|
701
|
+
));
|
|
702
|
+
}
|
|
627
703
|
};
|
|
628
704
|
function createKeyv(connect, options) {
|
|
629
705
|
connect ??= "redis://localhost:6379";
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import EventEmitter from 'node:events';
|
|
2
1
|
import { RedisClientOptions, RedisClusterOptions, RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts } from '@redis/client';
|
|
3
2
|
export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from '@redis/client';
|
|
3
|
+
import { Hookified } from 'hookified';
|
|
4
4
|
import { KeyvStoreAdapter, KeyvEntry, Keyv } from 'keyv';
|
|
5
5
|
export { Keyv } from 'keyv';
|
|
6
6
|
|
|
@@ -28,10 +28,24 @@ type KeyvRedisOptions = {
|
|
|
28
28
|
*/
|
|
29
29
|
noNamespaceAffectsAll?: boolean;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
32
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
throwOnConnectError?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
37
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
38
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
39
|
+
* and returns no-op responses.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
throwErrors?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Timeout in milliseconds for the connection. Default is undefined, which uses the default timeout of the Redis client.
|
|
45
|
+
* If set, it will throw an error if the connection does not succeed within the specified time.
|
|
46
|
+
* @default undefined
|
|
47
|
+
*/
|
|
48
|
+
connectionTimeout?: number;
|
|
35
49
|
};
|
|
36
50
|
type KeyvRedisPropertyOptions = KeyvRedisOptions & {
|
|
37
51
|
/**
|
|
@@ -59,21 +73,22 @@ type KeyvRedisEntry<T> = {
|
|
|
59
73
|
};
|
|
60
74
|
declare enum RedisErrorMessages {
|
|
61
75
|
/**
|
|
62
|
-
* Error message when the Redis client is not connected.
|
|
76
|
+
* Error message when the Redis client is not connected and throwOnConnectError is set to true.
|
|
63
77
|
*/
|
|
64
|
-
|
|
78
|
+
RedisClientNotConnectedThrown = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true."
|
|
65
79
|
}
|
|
66
80
|
declare const defaultReconnectStrategy: (attempts: number) => number | Error;
|
|
67
81
|
type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
|
|
68
|
-
declare class KeyvRedis<T> extends
|
|
82
|
+
declare class KeyvRedis<T> extends Hookified implements KeyvStoreAdapter {
|
|
69
83
|
private _client;
|
|
70
84
|
private _namespace;
|
|
71
85
|
private _keyPrefixSeparator;
|
|
72
86
|
private _clearBatchSize;
|
|
73
87
|
private _useUnlink;
|
|
74
88
|
private _noNamespaceAffectsAll;
|
|
75
|
-
private
|
|
76
|
-
private
|
|
89
|
+
private _throwOnConnectError;
|
|
90
|
+
private _throwErrors;
|
|
91
|
+
private _connectionTimeout;
|
|
77
92
|
/**
|
|
78
93
|
* KeyvRedis constructor.
|
|
79
94
|
* @param {string | RedisClientOptions | RedisClientType} [connect] How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client.
|
|
@@ -144,19 +159,49 @@ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
|
|
|
144
159
|
*/
|
|
145
160
|
set noNamespaceAffectsAll(value: boolean);
|
|
146
161
|
/**
|
|
147
|
-
* Get
|
|
148
|
-
*
|
|
162
|
+
* Get if throwOnConnectError is set to true.
|
|
163
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
164
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
165
|
+
* @default true
|
|
166
|
+
*/
|
|
167
|
+
get throwOnConnectError(): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Set if throwOnConnectError is set to true.
|
|
170
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
171
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
149
172
|
*/
|
|
150
|
-
|
|
173
|
+
set throwOnConnectError(value: boolean);
|
|
151
174
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
175
|
+
* Get if throwErrors is set to true.
|
|
176
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
177
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
178
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
179
|
+
* and returns no-op responses.
|
|
180
|
+
* @default false
|
|
181
|
+
*/
|
|
182
|
+
get throwErrors(): boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Set if throwErrors is set to true.
|
|
185
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
186
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
187
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
188
|
+
* and returns no-op responses.
|
|
189
|
+
*/
|
|
190
|
+
set throwErrors(value: boolean);
|
|
191
|
+
/**
|
|
192
|
+
* Get the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
193
|
+
* @default undefined
|
|
194
|
+
*/
|
|
195
|
+
get connectionTimeout(): number | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Set the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
198
|
+
* @default undefined
|
|
154
199
|
*/
|
|
155
|
-
set
|
|
200
|
+
set connectionTimeout(value: number | undefined);
|
|
156
201
|
/**
|
|
157
202
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
158
203
|
*/
|
|
159
|
-
getClient(): Promise<RedisClientConnectionType
|
|
204
|
+
getClient(): Promise<RedisClientConnectionType>;
|
|
160
205
|
/**
|
|
161
206
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
162
207
|
* @param {string} key - the key to set
|
|
@@ -275,6 +320,7 @@ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
|
|
|
275
320
|
private isClientCluster;
|
|
276
321
|
private setOptions;
|
|
277
322
|
private initClient;
|
|
323
|
+
private createTimeoutPromise;
|
|
278
324
|
}
|
|
279
325
|
/**
|
|
280
326
|
* Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import EventEmitter from 'node:events';
|
|
2
1
|
import { RedisClientOptions, RedisClusterOptions, RedisClientType, RedisClusterType, RedisModules, RedisFunctions, RedisScripts } from '@redis/client';
|
|
3
2
|
export { RedisClientOptions, RedisClientType, RedisClusterOptions, RedisClusterType, createClient, createCluster } from '@redis/client';
|
|
3
|
+
import { Hookified } from 'hookified';
|
|
4
4
|
import { KeyvStoreAdapter, KeyvEntry, Keyv } from 'keyv';
|
|
5
5
|
export { Keyv } from 'keyv';
|
|
6
6
|
|
|
@@ -28,10 +28,24 @@ type KeyvRedisOptions = {
|
|
|
28
28
|
*/
|
|
29
29
|
noNamespaceAffectsAll?: boolean;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
32
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
throwOnConnectError?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
37
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
38
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
39
|
+
* and returns no-op responses.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
throwErrors?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Timeout in milliseconds for the connection. Default is undefined, which uses the default timeout of the Redis client.
|
|
45
|
+
* If set, it will throw an error if the connection does not succeed within the specified time.
|
|
46
|
+
* @default undefined
|
|
47
|
+
*/
|
|
48
|
+
connectionTimeout?: number;
|
|
35
49
|
};
|
|
36
50
|
type KeyvRedisPropertyOptions = KeyvRedisOptions & {
|
|
37
51
|
/**
|
|
@@ -59,21 +73,22 @@ type KeyvRedisEntry<T> = {
|
|
|
59
73
|
};
|
|
60
74
|
declare enum RedisErrorMessages {
|
|
61
75
|
/**
|
|
62
|
-
* Error message when the Redis client is not connected.
|
|
76
|
+
* Error message when the Redis client is not connected and throwOnConnectError is set to true.
|
|
63
77
|
*/
|
|
64
|
-
|
|
78
|
+
RedisClientNotConnectedThrown = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true."
|
|
65
79
|
}
|
|
66
80
|
declare const defaultReconnectStrategy: (attempts: number) => number | Error;
|
|
67
81
|
type RedisClientConnectionType = RedisClientType | RedisClusterType<RedisModules, RedisFunctions, RedisScripts>;
|
|
68
|
-
declare class KeyvRedis<T> extends
|
|
82
|
+
declare class KeyvRedis<T> extends Hookified implements KeyvStoreAdapter {
|
|
69
83
|
private _client;
|
|
70
84
|
private _namespace;
|
|
71
85
|
private _keyPrefixSeparator;
|
|
72
86
|
private _clearBatchSize;
|
|
73
87
|
private _useUnlink;
|
|
74
88
|
private _noNamespaceAffectsAll;
|
|
75
|
-
private
|
|
76
|
-
private
|
|
89
|
+
private _throwOnConnectError;
|
|
90
|
+
private _throwErrors;
|
|
91
|
+
private _connectionTimeout;
|
|
77
92
|
/**
|
|
78
93
|
* KeyvRedis constructor.
|
|
79
94
|
* @param {string | RedisClientOptions | RedisClientType} [connect] How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client.
|
|
@@ -144,19 +159,49 @@ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
|
|
|
144
159
|
*/
|
|
145
160
|
set noNamespaceAffectsAll(value: boolean);
|
|
146
161
|
/**
|
|
147
|
-
* Get
|
|
148
|
-
*
|
|
162
|
+
* Get if throwOnConnectError is set to true.
|
|
163
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
164
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
165
|
+
* @default true
|
|
166
|
+
*/
|
|
167
|
+
get throwOnConnectError(): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Set if throwOnConnectError is set to true.
|
|
170
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
171
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
149
172
|
*/
|
|
150
|
-
|
|
173
|
+
set throwOnConnectError(value: boolean);
|
|
151
174
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
175
|
+
* Get if throwErrors is set to true.
|
|
176
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
177
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
178
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
179
|
+
* and returns no-op responses.
|
|
180
|
+
* @default false
|
|
181
|
+
*/
|
|
182
|
+
get throwErrors(): boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Set if throwErrors is set to true.
|
|
185
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
186
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
187
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
188
|
+
* and returns no-op responses.
|
|
189
|
+
*/
|
|
190
|
+
set throwErrors(value: boolean);
|
|
191
|
+
/**
|
|
192
|
+
* Get the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
193
|
+
* @default undefined
|
|
194
|
+
*/
|
|
195
|
+
get connectionTimeout(): number | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Set the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
198
|
+
* @default undefined
|
|
154
199
|
*/
|
|
155
|
-
set
|
|
200
|
+
set connectionTimeout(value: number | undefined);
|
|
156
201
|
/**
|
|
157
202
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
158
203
|
*/
|
|
159
|
-
getClient(): Promise<RedisClientConnectionType
|
|
204
|
+
getClient(): Promise<RedisClientConnectionType>;
|
|
160
205
|
/**
|
|
161
206
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
162
207
|
* @param {string} key - the key to set
|
|
@@ -275,6 +320,7 @@ declare class KeyvRedis<T> extends EventEmitter implements KeyvStoreAdapter {
|
|
|
275
320
|
private isClientCluster;
|
|
276
321
|
private setOptions;
|
|
277
322
|
private initClient;
|
|
323
|
+
private createTimeoutPromise;
|
|
278
324
|
}
|
|
279
325
|
/**
|
|
280
326
|
* Will create a Keyv instance with the Redis adapter. This will also set the namespace and useKeyPrefix to false.
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import EventEmitter from "events";
|
|
3
2
|
import {
|
|
4
3
|
createClient,
|
|
5
4
|
createCluster
|
|
6
5
|
} from "@redis/client";
|
|
6
|
+
import { Hookified } from "hookified";
|
|
7
7
|
import { Keyv } from "keyv";
|
|
8
8
|
import calculateSlot from "cluster-key-slot";
|
|
9
9
|
import {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
Keyv as Keyv2
|
|
15
15
|
} from "keyv";
|
|
16
16
|
var RedisErrorMessages = /* @__PURE__ */ ((RedisErrorMessages2) => {
|
|
17
|
-
RedisErrorMessages2["
|
|
17
|
+
RedisErrorMessages2["RedisClientNotConnectedThrown"] = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true.";
|
|
18
18
|
return RedisErrorMessages2;
|
|
19
19
|
})(RedisErrorMessages || {});
|
|
20
20
|
var defaultReconnectStrategy = (attempts) => {
|
|
@@ -22,17 +22,16 @@ var defaultReconnectStrategy = (attempts) => {
|
|
|
22
22
|
const jitter = (Math.random() - 0.5) * 100;
|
|
23
23
|
return backoff + jitter;
|
|
24
24
|
};
|
|
25
|
-
var KeyvRedis = class extends
|
|
25
|
+
var KeyvRedis = class extends Hookified {
|
|
26
26
|
_client = createClient();
|
|
27
27
|
_namespace;
|
|
28
28
|
_keyPrefixSeparator = "::";
|
|
29
29
|
_clearBatchSize = 1e3;
|
|
30
30
|
_useUnlink = true;
|
|
31
31
|
_noNamespaceAffectsAll = false;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// Whether to reconnect the client
|
|
32
|
+
_throwOnConnectError = true;
|
|
33
|
+
_throwErrors = false;
|
|
34
|
+
_connectionTimeout;
|
|
36
35
|
/**
|
|
37
36
|
* KeyvRedis constructor.
|
|
38
37
|
* @param {string | RedisClientOptions | RedisClientType} [connect] How to connect to the Redis server. If string pass in the url, if object pass in the options, if RedisClient pass in the client.
|
|
@@ -42,6 +41,7 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
42
41
|
super();
|
|
43
42
|
const socket = {
|
|
44
43
|
reconnectStrategy: defaultReconnectStrategy
|
|
44
|
+
// Default timeout for the connection
|
|
45
45
|
};
|
|
46
46
|
if (connect) {
|
|
47
47
|
if (typeof connect === "string") {
|
|
@@ -84,6 +84,10 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
84
84
|
keyPrefixSeparator: this._keyPrefixSeparator,
|
|
85
85
|
clearBatchSize: this._clearBatchSize,
|
|
86
86
|
noNamespaceAffectsAll: this._noNamespaceAffectsAll,
|
|
87
|
+
useUnlink: this._useUnlink,
|
|
88
|
+
throwOnConnectError: this._throwOnConnectError,
|
|
89
|
+
throwErrors: this._throwErrors,
|
|
90
|
+
connectionTimeout: this._connectionTimeout,
|
|
87
91
|
dialect: "redis",
|
|
88
92
|
url
|
|
89
93
|
};
|
|
@@ -167,49 +171,82 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
167
171
|
this._noNamespaceAffectsAll = value;
|
|
168
172
|
}
|
|
169
173
|
/**
|
|
170
|
-
* Get
|
|
171
|
-
*
|
|
174
|
+
* Get if throwOnConnectError is set to true.
|
|
175
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
176
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
177
|
+
* @default true
|
|
172
178
|
*/
|
|
173
|
-
get
|
|
174
|
-
return this.
|
|
179
|
+
get throwOnConnectError() {
|
|
180
|
+
return this._throwOnConnectError;
|
|
175
181
|
}
|
|
176
182
|
/**
|
|
177
|
-
* Set
|
|
178
|
-
*
|
|
183
|
+
* Set if throwOnConnectError is set to true.
|
|
184
|
+
* This is used to throw an error if the client is not connected when trying to connect. By default, this is
|
|
185
|
+
* set to true so that it throws an error when trying to connect to the Redis server fails.
|
|
179
186
|
*/
|
|
180
|
-
set
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
set throwOnConnectError(value) {
|
|
188
|
+
this._throwOnConnectError = value;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get if throwErrors is set to true.
|
|
192
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
193
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
194
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
195
|
+
* and returns no-op responses.
|
|
196
|
+
* @default false
|
|
197
|
+
*/
|
|
198
|
+
get throwErrors() {
|
|
199
|
+
return this._throwErrors;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Set if throwErrors is set to true.
|
|
203
|
+
* This is used to throw an error if at any point there is a failure. Use this if you want to
|
|
204
|
+
* ensure that all operations are successful and you want to handle errors. By default, this is
|
|
205
|
+
* set to false so that it does not throw an error on every operation and instead emits an error event
|
|
206
|
+
* and returns no-op responses.
|
|
207
|
+
*/
|
|
208
|
+
set throwErrors(value) {
|
|
209
|
+
this._throwErrors = value;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
213
|
+
* @default undefined
|
|
214
|
+
*/
|
|
215
|
+
get connectionTimeout() {
|
|
216
|
+
return this._connectionTimeout;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Set the connection timeout in milliseconds such as 5000 (5 seconds). Default is undefined. If undefined, it will use the default.
|
|
220
|
+
* @default undefined
|
|
221
|
+
*/
|
|
222
|
+
set connectionTimeout(value) {
|
|
223
|
+
this._connectionTimeout = value;
|
|
187
224
|
}
|
|
188
225
|
/**
|
|
189
226
|
* Get the Redis URL used to connect to the server. This is used to get a connected client.
|
|
190
227
|
*/
|
|
191
228
|
async getClient() {
|
|
192
|
-
if (this._client.isOpen
|
|
229
|
+
if (this._client.isOpen) {
|
|
193
230
|
return this._client;
|
|
194
231
|
}
|
|
195
|
-
if (this._reconnectClient && this._client.isOpen) {
|
|
196
|
-
await this._client.disconnect();
|
|
197
|
-
}
|
|
198
232
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
this.initClient();
|
|
208
|
-
return this._client;
|
|
233
|
+
if (this._connectionTimeout === void 0) {
|
|
234
|
+
await this._client.connect();
|
|
235
|
+
} else {
|
|
236
|
+
await Promise.race([
|
|
237
|
+
this._client.connect(),
|
|
238
|
+
this.createTimeoutPromise(this._connectionTimeout)
|
|
239
|
+
]);
|
|
240
|
+
}
|
|
209
241
|
} catch (error) {
|
|
210
242
|
this.emit("error", error);
|
|
211
|
-
|
|
243
|
+
if (this._throwOnConnectError) {
|
|
244
|
+
throw new Error("Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true." /* RedisClientNotConnectedThrown */);
|
|
245
|
+
}
|
|
246
|
+
await this.disconnect(true);
|
|
212
247
|
}
|
|
248
|
+
this.initClient();
|
|
249
|
+
return this._client;
|
|
213
250
|
}
|
|
214
251
|
/**
|
|
215
252
|
* Set a key value pair in the store. TTL is in milliseconds.
|
|
@@ -219,15 +256,18 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
219
256
|
*/
|
|
220
257
|
async set(key, value, ttl) {
|
|
221
258
|
const client = await this.getClient();
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
259
|
+
try {
|
|
260
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
261
|
+
if (ttl) {
|
|
262
|
+
await client.set(key, value, { PX: ttl });
|
|
263
|
+
} else {
|
|
264
|
+
await client.set(key, value);
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
this.emit("error", error);
|
|
268
|
+
if (this._throwErrors) {
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
231
271
|
}
|
|
232
272
|
}
|
|
233
273
|
/**
|
|
@@ -236,20 +276,23 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
236
276
|
*/
|
|
237
277
|
async setMany(entries) {
|
|
238
278
|
const client = await this.getClient();
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
279
|
+
try {
|
|
280
|
+
const multi = client.multi();
|
|
281
|
+
for (const { key, value, ttl } of entries) {
|
|
282
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
283
|
+
if (ttl) {
|
|
284
|
+
multi.set(prefixedKey, value, { PX: ttl });
|
|
285
|
+
} else {
|
|
286
|
+
multi.set(prefixedKey, value);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
await multi.exec();
|
|
290
|
+
} catch (error) {
|
|
291
|
+
this.emit("error", error);
|
|
292
|
+
if (this._throwErrors) {
|
|
293
|
+
throw error;
|
|
250
294
|
}
|
|
251
295
|
}
|
|
252
|
-
await multi.exec();
|
|
253
296
|
}
|
|
254
297
|
/**
|
|
255
298
|
* Check if a key exists in the store.
|
|
@@ -258,13 +301,17 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
258
301
|
*/
|
|
259
302
|
async has(key) {
|
|
260
303
|
const client = await this.getClient();
|
|
261
|
-
|
|
262
|
-
this.
|
|
304
|
+
try {
|
|
305
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
306
|
+
const exists = await client.exists(key);
|
|
307
|
+
return exists === 1;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
this.emit("error", error);
|
|
310
|
+
if (this._throwErrors) {
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
263
313
|
return false;
|
|
264
314
|
}
|
|
265
|
-
key = this.createKeyPrefix(key, this._namespace);
|
|
266
|
-
const exists = await client.exists(key);
|
|
267
|
-
return exists === 1;
|
|
268
315
|
}
|
|
269
316
|
/**
|
|
270
317
|
* Check if many keys exist in the store. This will be done as a single transaction.
|
|
@@ -273,17 +320,21 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
273
320
|
*/
|
|
274
321
|
async hasMany(keys) {
|
|
275
322
|
const client = await this.getClient();
|
|
276
|
-
|
|
277
|
-
|
|
323
|
+
try {
|
|
324
|
+
const multi = client.multi();
|
|
325
|
+
for (const key of keys) {
|
|
326
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
327
|
+
multi.exists(prefixedKey);
|
|
328
|
+
}
|
|
329
|
+
const results = await multi.exec();
|
|
330
|
+
return results.map((result) => result === 1);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
this.emit("error", error);
|
|
333
|
+
if (this._throwErrors) {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
278
336
|
return Array.from({ length: keys.length }).fill(false);
|
|
279
337
|
}
|
|
280
|
-
const multi = client.multi();
|
|
281
|
-
for (const key of keys) {
|
|
282
|
-
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
283
|
-
multi.exists(prefixedKey);
|
|
284
|
-
}
|
|
285
|
-
const results = await multi.exec();
|
|
286
|
-
return results.map((result) => result === 1);
|
|
287
338
|
}
|
|
288
339
|
/**
|
|
289
340
|
* Get a value from the store. If the key does not exist, it will return undefined.
|
|
@@ -292,16 +343,20 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
292
343
|
*/
|
|
293
344
|
async get(key) {
|
|
294
345
|
const client = await this.getClient();
|
|
295
|
-
|
|
296
|
-
this.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
346
|
+
try {
|
|
347
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
348
|
+
const value = await client.get(key);
|
|
349
|
+
if (value === null) {
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
return value;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
this.emit("error", error);
|
|
355
|
+
if (this._throwErrors) {
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
302
358
|
return void 0;
|
|
303
359
|
}
|
|
304
|
-
return value;
|
|
305
360
|
}
|
|
306
361
|
/**
|
|
307
362
|
* Get many values from the store. If a key does not exist, it will return undefined.
|
|
@@ -318,6 +373,9 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
318
373
|
return values;
|
|
319
374
|
} catch (error) {
|
|
320
375
|
this.emit("error", error);
|
|
376
|
+
if (this._throwErrors) {
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
321
379
|
return Array.from({ length: keys.length }).fill(void 0);
|
|
322
380
|
}
|
|
323
381
|
}
|
|
@@ -328,14 +386,18 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
328
386
|
*/
|
|
329
387
|
async delete(key) {
|
|
330
388
|
const client = await this.getClient();
|
|
331
|
-
|
|
332
|
-
this.
|
|
389
|
+
try {
|
|
390
|
+
key = this.createKeyPrefix(key, this._namespace);
|
|
391
|
+
let deleted = 0;
|
|
392
|
+
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
393
|
+
return deleted > 0;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
this.emit("error", error);
|
|
396
|
+
if (this._throwErrors) {
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
333
399
|
return false;
|
|
334
400
|
}
|
|
335
|
-
key = this.createKeyPrefix(key, this._namespace);
|
|
336
|
-
let deleted = 0;
|
|
337
|
-
deleted = await (this._useUnlink ? client.unlink(key) : client.del(key));
|
|
338
|
-
return deleted > 0;
|
|
339
401
|
}
|
|
340
402
|
/**
|
|
341
403
|
* Delete many keys from the store. This will be done as a single transaction.
|
|
@@ -345,23 +407,26 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
345
407
|
async deleteMany(keys) {
|
|
346
408
|
let result = false;
|
|
347
409
|
const client = await this.getClient();
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
} else {
|
|
358
|
-
multi.del(prefixedKey);
|
|
410
|
+
try {
|
|
411
|
+
const multi = client.multi();
|
|
412
|
+
for (const key of keys) {
|
|
413
|
+
const prefixedKey = this.createKeyPrefix(key, this._namespace);
|
|
414
|
+
if (this._useUnlink) {
|
|
415
|
+
multi.unlink(prefixedKey);
|
|
416
|
+
} else {
|
|
417
|
+
multi.del(prefixedKey);
|
|
418
|
+
}
|
|
359
419
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
420
|
+
const results = await multi.exec();
|
|
421
|
+
for (const deleted of results) {
|
|
422
|
+
if (typeof deleted === "number" && deleted > 0) {
|
|
423
|
+
result = true;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
} catch (error) {
|
|
427
|
+
this.emit("error", error);
|
|
428
|
+
if (this._throwErrors) {
|
|
429
|
+
throw error;
|
|
365
430
|
}
|
|
366
431
|
}
|
|
367
432
|
return result;
|
|
@@ -519,9 +584,6 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
519
584
|
*/
|
|
520
585
|
async getSlotMaster(slot) {
|
|
521
586
|
const connection = await this.getClient();
|
|
522
|
-
if (!connection) {
|
|
523
|
-
throw new Error("Redis client is not connected or has failed to connect" /* RedisClientNotConnected */);
|
|
524
|
-
}
|
|
525
587
|
if (this.isCluster()) {
|
|
526
588
|
const cluster = connection;
|
|
527
589
|
const mainNode = cluster.slots[slot].master;
|
|
@@ -574,14 +636,17 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
574
636
|
if (options.noNamespaceAffectsAll !== void 0) {
|
|
575
637
|
this._noNamespaceAffectsAll = options.noNamespaceAffectsAll;
|
|
576
638
|
}
|
|
577
|
-
if (options.
|
|
578
|
-
this.
|
|
639
|
+
if (options.throwOnConnectError !== void 0) {
|
|
640
|
+
this._throwOnConnectError = options.throwOnConnectError;
|
|
641
|
+
}
|
|
642
|
+
if (options.throwErrors !== void 0) {
|
|
643
|
+
this._throwErrors = options.throwErrors;
|
|
644
|
+
}
|
|
645
|
+
if (options.connectionTimeout !== void 0) {
|
|
646
|
+
this._connectionTimeout = options.connectionTimeout;
|
|
579
647
|
}
|
|
580
648
|
}
|
|
581
649
|
initClient() {
|
|
582
|
-
this._client.on("error", (error) => {
|
|
583
|
-
this.emit("error", error);
|
|
584
|
-
});
|
|
585
650
|
this._client.on("connect", () => {
|
|
586
651
|
this.emit("connect", this._client);
|
|
587
652
|
});
|
|
@@ -592,6 +657,17 @@ var KeyvRedis = class extends EventEmitter {
|
|
|
592
657
|
this.emit("reconnecting", reconnectInfo);
|
|
593
658
|
});
|
|
594
659
|
}
|
|
660
|
+
async createTimeoutPromise(timeoutMs) {
|
|
661
|
+
return new Promise((_, reject) => (
|
|
662
|
+
// eslint-disable-next-line no-promise-executor-return
|
|
663
|
+
setTimeout(
|
|
664
|
+
() => {
|
|
665
|
+
reject(new Error(`Redis timed out after ${timeoutMs}ms`));
|
|
666
|
+
},
|
|
667
|
+
timeoutMs
|
|
668
|
+
)
|
|
669
|
+
));
|
|
670
|
+
}
|
|
595
671
|
};
|
|
596
672
|
function createKeyv(connect, options) {
|
|
597
673
|
connect ??= "redis://localhost:6379";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyv/redis",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "Redis storage adapter for Keyv",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -35,19 +35,20 @@
|
|
|
35
35
|
"homepage": "https://github.com/jaredwray/keyv",
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@redis/client": "^1.6.0",
|
|
38
|
-
"cluster-key-slot": "^1.1.2"
|
|
38
|
+
"cluster-key-slot": "^1.1.2",
|
|
39
|
+
"hookified": "^1.10.0"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"keyv": "^5.3.4"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@faker-js/faker": "^9.
|
|
45
|
-
"@vitest/coverage-v8": "^3.2.
|
|
45
|
+
"@faker-js/faker": "^9.9.0",
|
|
46
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
46
47
|
"rimraf": "^6.0.1",
|
|
47
48
|
"timekeeper": "^2.3.1",
|
|
48
49
|
"tsd": "^0.32.0",
|
|
49
|
-
"vitest": "^3.2.
|
|
50
|
-
"xo": "^1.1.
|
|
50
|
+
"vitest": "^3.2.4",
|
|
51
|
+
"xo": "^1.1.1",
|
|
51
52
|
"@keyv/test-suite": "^2.0.8"
|
|
52
53
|
},
|
|
53
54
|
"tsd": {
|