keyv 5.3.3 → 5.4.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 +47 -10
- package/dist/index.cjs +79 -17
- package/dist/index.d.cts +53 -10
- package/dist/index.d.ts +53 -10
- package/dist/index.js +79 -17
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -53,14 +53,6 @@ There are a few existing modules similar to Keyv, however Keyv is different beca
|
|
|
53
53
|
- [.deleteMany(keys)](#deletemanykeys)
|
|
54
54
|
- [.clear()](#clear)
|
|
55
55
|
- [.iterator()](#iterator)
|
|
56
|
-
- [API - Properties](#api---properties)
|
|
57
|
-
- [.namespace](#namespace-1)
|
|
58
|
-
- [.ttl](#ttl-1)
|
|
59
|
-
- [.store](#store-1)
|
|
60
|
-
- [.serialize](#serialize-1)
|
|
61
|
-
- [.deserialize](#deserialize-1)
|
|
62
|
-
- [.compression](#compression-1)
|
|
63
|
-
- [.useKeyPrefix](#usekeyprefix-1)
|
|
64
56
|
- [How to Contribute](#how-to-contribute)
|
|
65
57
|
- [License](#license)
|
|
66
58
|
|
|
@@ -83,6 +75,7 @@ npm install --save @keyv/postgres
|
|
|
83
75
|
npm install --save @keyv/mysql
|
|
84
76
|
npm install --save @keyv/etcd
|
|
85
77
|
npm install --save @keyv/memcache
|
|
78
|
+
npm install --save @keyv/dynamo
|
|
86
79
|
```
|
|
87
80
|
|
|
88
81
|
First, create a new Keyv instance.
|
|
@@ -233,7 +226,7 @@ keyv.hooks.addHandler(KeyvHooks.PRE_SET, (data) => console.log(`Setting key ${da
|
|
|
233
226
|
|
|
234
227
|
//POST_SET hook
|
|
235
228
|
const keyv = new Keyv();
|
|
236
|
-
keyv.hooks.addHandler(KeyvHooks.POST_SET, (key, value) => console.log(`Set key ${key} to ${value}`));
|
|
229
|
+
keyv.hooks.addHandler(KeyvHooks.POST_SET, ({key, value}) => console.log(`Set key ${key} to ${value}`));
|
|
237
230
|
```
|
|
238
231
|
|
|
239
232
|
In these examples you can also manipulate the value before it is set. For example, you could add a prefix to all keys.
|
|
@@ -286,6 +279,7 @@ PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/master/pack
|
|
|
286
279
|
MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/master/packages/mysql) | No
|
|
287
280
|
Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/master/packages/etcd) | Yes
|
|
288
281
|
Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/master/packages/memcache) | Yes
|
|
282
|
+
DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/master/packages/dynamo) | Yes
|
|
289
283
|
|
|
290
284
|
# Third-party Storage Adapters
|
|
291
285
|
|
|
@@ -318,7 +312,6 @@ The following are third-party storage adapters compatible with Keyv:
|
|
|
318
312
|
|
|
319
313
|
- [quick-lru](https://github.com/sindresorhus/quick-lru) - Simple "Least Recently Used" (LRU) cache
|
|
320
314
|
- [keyv-file](https://github.com/zaaack/keyv-file) - File system storage adapter for Keyv
|
|
321
|
-
- [keyv-dynamodb](https://www.npmjs.com/package/keyv-dynamodb) - DynamoDB storage adapter for Keyv
|
|
322
315
|
- [keyv-lru](https://www.npmjs.com/package/keyv-lru) - LRU storage adapter for Keyv
|
|
323
316
|
- [keyv-null](https://www.npmjs.com/package/keyv-null) - Null storage adapter for Keyv
|
|
324
317
|
- [keyv-firestore ](https://github.com/goto-bus-stop/keyv-firestore) – Firebase Cloud Firestore adapter for Keyv
|
|
@@ -623,6 +616,50 @@ keyv.useKeyPrefix = true;
|
|
|
623
616
|
console.log(keyv.useKeyPrefix); // true
|
|
624
617
|
```
|
|
625
618
|
|
|
619
|
+
With many of the storage adapters you will also need to set the `namespace` option to `undefined` to have it work correctly. This is because in `v5` we started the transition to having the storage adapter handle the namespacing and `Keyv` will no longer handle it internally via KeyPrefixing. Here is an example of doing ith with `KeyvSqlite`:
|
|
620
|
+
|
|
621
|
+
```js
|
|
622
|
+
import Keyv from 'keyv';
|
|
623
|
+
import KeyvSqlite from '@keyv/sqlite';
|
|
624
|
+
|
|
625
|
+
const store = new KeyvSqlite('sqlite://path/to/database.sqlite');
|
|
626
|
+
const keyv = new Keyv({ store });
|
|
627
|
+
keyv.useKeyPrefix = false; // disable key prefixing
|
|
628
|
+
store.namespace = undefined; // disable namespacing in the storage adapter
|
|
629
|
+
|
|
630
|
+
await keyv.set('foo', 'bar'); // true
|
|
631
|
+
await keyv.get('foo'); // 'bar'
|
|
632
|
+
await keyv.clear();
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## .throwOnErrors
|
|
636
|
+
|
|
637
|
+
Type: `Boolean`<br />
|
|
638
|
+
Default: `false`
|
|
639
|
+
|
|
640
|
+
If set to `true`, Keyv will throw an error if any operation fails. This is useful if you want to ensure that all operations are successful and you want to handle errors.
|
|
641
|
+
|
|
642
|
+
```js
|
|
643
|
+
const keyv = new Keyv({ throwOnErrors: true });
|
|
644
|
+
console.log(keyv.throwOnErrors); // true
|
|
645
|
+
keyv.throwOnErrors = false;
|
|
646
|
+
console.log(keyv.throwOnErrors); // false
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
A good example of this is with the `@keyv/redis` storage adapter. If you want to handle connection errors, retries, and timeouts more gracefully, you can use the `throwOnErrors` option. This will throw an error if any operation fails, allowing you to catch it and handle it accordingly:
|
|
650
|
+
|
|
651
|
+
```js
|
|
652
|
+
import Keyv from 'keyv';
|
|
653
|
+
import KeyvRedis from '@keyv/redis';
|
|
654
|
+
|
|
655
|
+
// create redis instance that will throw on connection error
|
|
656
|
+
const keyvRedis = new KeyvRedis('redis://user:pass@localhost:6379', { throwOnConnectErrors: true });
|
|
657
|
+
|
|
658
|
+
const keyv = new Keyv({ store: keyvRedis, throwOnErrors: true });
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
What this does is it only throw on connection errors with the Redis client.
|
|
662
|
+
|
|
626
663
|
# How to Contribute
|
|
627
664
|
|
|
628
665
|
We welcome contributions to Keyv! 🎉 Here are some guides to get you started with contributing:
|
package/dist/index.cjs
CHANGED
|
@@ -237,6 +237,7 @@ var Keyv = class extends event_manager_default {
|
|
|
237
237
|
_deserialize = import_serialize.defaultDeserialize;
|
|
238
238
|
_compression;
|
|
239
239
|
_useKeyPrefix = true;
|
|
240
|
+
_throwOnErrors = false;
|
|
240
241
|
/**
|
|
241
242
|
* Keyv Constructor
|
|
242
243
|
* @param {KeyvStoreAdapter | KeyvOptions} store
|
|
@@ -293,6 +294,9 @@ var Keyv = class extends event_manager_default {
|
|
|
293
294
|
if (this.opts.useKeyPrefix !== void 0) {
|
|
294
295
|
this._useKeyPrefix = this.opts.useKeyPrefix;
|
|
295
296
|
}
|
|
297
|
+
if (this.opts.throwOnErrors !== void 0) {
|
|
298
|
+
this._throwOnErrors = this.opts.throwOnErrors;
|
|
299
|
+
}
|
|
296
300
|
}
|
|
297
301
|
/**
|
|
298
302
|
* Get the current store
|
|
@@ -417,6 +421,21 @@ var Keyv = class extends event_manager_default {
|
|
|
417
421
|
this._useKeyPrefix = value;
|
|
418
422
|
this.opts.useKeyPrefix = value;
|
|
419
423
|
}
|
|
424
|
+
/**
|
|
425
|
+
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
426
|
+
* @return {boolean} The current throwOnErrors value.
|
|
427
|
+
*/
|
|
428
|
+
get throwOnErrors() {
|
|
429
|
+
return this._throwOnErrors;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
433
|
+
* @param {boolean} value The throwOnErrors value to set.
|
|
434
|
+
*/
|
|
435
|
+
set throwOnErrors(value) {
|
|
436
|
+
this._throwOnErrors = value;
|
|
437
|
+
this.opts.throwOnErrors = value;
|
|
438
|
+
}
|
|
420
439
|
generateIterator(iterator) {
|
|
421
440
|
const function_ = async function* () {
|
|
422
441
|
for await (const [key, raw] of typeof iterator === "function" ? iterator(this._store.namespace) : iterator) {
|
|
@@ -463,6 +482,7 @@ var Keyv = class extends event_manager_default {
|
|
|
463
482
|
_isValidStorageAdapter(store) {
|
|
464
483
|
return store instanceof Map || typeof store.get === "function" && typeof store.set === "function" && typeof store.delete === "function" && typeof store.clear === "function";
|
|
465
484
|
}
|
|
485
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
466
486
|
async get(key, options) {
|
|
467
487
|
const { store } = this.opts;
|
|
468
488
|
const isArray = Array.isArray(key);
|
|
@@ -475,7 +495,14 @@ var Keyv = class extends event_manager_default {
|
|
|
475
495
|
return this.getMany(key, { raw: false });
|
|
476
496
|
}
|
|
477
497
|
this.hooks.trigger("preGet" /* PRE_GET */, { key: keyPrefixed });
|
|
478
|
-
|
|
498
|
+
let rawData;
|
|
499
|
+
try {
|
|
500
|
+
rawData = await store.get(keyPrefixed);
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (this.throwOnErrors) {
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
479
506
|
const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
|
|
480
507
|
if (deserializedData === void 0 || deserializedData === null) {
|
|
481
508
|
this.stats.miss();
|
|
@@ -518,6 +545,7 @@ var Keyv = class extends event_manager_default {
|
|
|
518
545
|
}
|
|
519
546
|
const rawData = await store.getMany(keyPrefixed);
|
|
520
547
|
const result = [];
|
|
548
|
+
const expiredKeys = [];
|
|
521
549
|
for (const index in rawData) {
|
|
522
550
|
let row = rawData[index];
|
|
523
551
|
if (typeof row === "string") {
|
|
@@ -528,13 +556,16 @@ var Keyv = class extends event_manager_default {
|
|
|
528
556
|
continue;
|
|
529
557
|
}
|
|
530
558
|
if (isDataExpired(row)) {
|
|
531
|
-
|
|
559
|
+
expiredKeys.push(keys[index]);
|
|
532
560
|
result.push(void 0);
|
|
533
561
|
continue;
|
|
534
562
|
}
|
|
535
563
|
const value = options?.raw ? row : row.value;
|
|
536
564
|
result.push(value);
|
|
537
565
|
}
|
|
566
|
+
if (expiredKeys.length > 0) {
|
|
567
|
+
await this.deleteMany(expiredKeys);
|
|
568
|
+
}
|
|
538
569
|
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result);
|
|
539
570
|
if (result.length > 0) {
|
|
540
571
|
this.stats.hit();
|
|
@@ -552,14 +583,12 @@ var Keyv = class extends event_manager_default {
|
|
|
552
583
|
const data = { key, value, ttl };
|
|
553
584
|
this.hooks.trigger("preSet" /* PRE_SET */, data);
|
|
554
585
|
const keyPrefixed = this._getKeyPrefix(data.key);
|
|
555
|
-
|
|
556
|
-
data.ttl = this._ttl;
|
|
557
|
-
}
|
|
586
|
+
data.ttl ??= this._ttl;
|
|
558
587
|
if (data.ttl === 0) {
|
|
559
588
|
data.ttl = void 0;
|
|
560
589
|
}
|
|
561
590
|
const { store } = this.opts;
|
|
562
|
-
const expires = typeof data.ttl === "number" ? Date.now() + data.ttl :
|
|
591
|
+
const expires = typeof data.ttl === "number" ? Date.now() + data.ttl : void 0;
|
|
563
592
|
if (typeof data.value === "symbol") {
|
|
564
593
|
this.emit("error", "symbol cannot be serialized");
|
|
565
594
|
throw new Error("symbol cannot be serialized");
|
|
@@ -575,6 +604,9 @@ var Keyv = class extends event_manager_default {
|
|
|
575
604
|
} catch (error) {
|
|
576
605
|
result = false;
|
|
577
606
|
this.emit("error", error);
|
|
607
|
+
if (this._throwOnErrors) {
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
578
610
|
}
|
|
579
611
|
this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
|
|
580
612
|
this.stats.set();
|
|
@@ -588,18 +620,35 @@ var Keyv = class extends event_manager_default {
|
|
|
588
620
|
async setMany(entries) {
|
|
589
621
|
let results = [];
|
|
590
622
|
try {
|
|
591
|
-
if (this._store.setMany
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
623
|
+
if (this._store.setMany === void 0) {
|
|
624
|
+
const promises = [];
|
|
625
|
+
for (const entry of entries) {
|
|
626
|
+
promises.push(this.set(entry.key, entry.value, entry.ttl));
|
|
627
|
+
}
|
|
628
|
+
const promiseResults = await Promise.all(promises);
|
|
629
|
+
results = promiseResults;
|
|
630
|
+
} else {
|
|
631
|
+
const serializedEntries = await Promise.all(entries.map(async ({ key, value, ttl }) => {
|
|
632
|
+
ttl ??= this._ttl;
|
|
633
|
+
if (ttl === 0) {
|
|
634
|
+
ttl = void 0;
|
|
635
|
+
}
|
|
636
|
+
const expires = typeof ttl === "number" ? Date.now() + ttl : void 0;
|
|
637
|
+
if (typeof value === "symbol") {
|
|
638
|
+
this.emit("error", "symbol cannot be serialized");
|
|
639
|
+
throw new Error("symbol cannot be serialized");
|
|
640
|
+
}
|
|
641
|
+
const formattedValue = { value, expires };
|
|
642
|
+
const serializedValue = await this.serializeData(formattedValue);
|
|
643
|
+
return { key, value: serializedValue, ttl };
|
|
644
|
+
}));
|
|
645
|
+
results = await this._store.setMany(serializedEntries);
|
|
598
646
|
}
|
|
599
|
-
const promiseResults = await Promise.allSettled(promises);
|
|
600
|
-
results = promiseResults.map((result) => result.value);
|
|
601
647
|
} catch (error) {
|
|
602
648
|
this.emit("error", error);
|
|
649
|
+
if (this._throwOnErrors) {
|
|
650
|
+
throw error;
|
|
651
|
+
}
|
|
603
652
|
results = entries.map(() => false);
|
|
604
653
|
}
|
|
605
654
|
return results;
|
|
@@ -625,6 +674,9 @@ var Keyv = class extends event_manager_default {
|
|
|
625
674
|
} catch (error) {
|
|
626
675
|
result = false;
|
|
627
676
|
this.emit("error", error);
|
|
677
|
+
if (this._throwOnErrors) {
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
628
680
|
}
|
|
629
681
|
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
|
|
630
682
|
this.stats.delete();
|
|
@@ -644,12 +696,15 @@ var Keyv = class extends event_manager_default {
|
|
|
644
696
|
return await store.deleteMany(keyPrefixed);
|
|
645
697
|
}
|
|
646
698
|
const promises = keyPrefixed.map(async (key) => store.delete(key));
|
|
647
|
-
const results = await Promise.
|
|
648
|
-
const returnResult = results.every(
|
|
699
|
+
const results = await Promise.all(promises);
|
|
700
|
+
const returnResult = results.every(Boolean);
|
|
649
701
|
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
|
|
650
702
|
return returnResult;
|
|
651
703
|
} catch (error) {
|
|
652
704
|
this.emit("error", error);
|
|
705
|
+
if (this._throwOnErrors) {
|
|
706
|
+
throw error;
|
|
707
|
+
}
|
|
653
708
|
return false;
|
|
654
709
|
}
|
|
655
710
|
}
|
|
@@ -664,6 +719,9 @@ var Keyv = class extends event_manager_default {
|
|
|
664
719
|
await store.clear();
|
|
665
720
|
} catch (error) {
|
|
666
721
|
this.emit("error", error);
|
|
722
|
+
if (this._throwOnErrors) {
|
|
723
|
+
throw error;
|
|
724
|
+
}
|
|
667
725
|
}
|
|
668
726
|
}
|
|
669
727
|
async has(key) {
|
|
@@ -680,6 +738,10 @@ var Keyv = class extends event_manager_default {
|
|
|
680
738
|
rawData = await store.get(keyPrefixed);
|
|
681
739
|
} catch (error) {
|
|
682
740
|
this.emit("error", error);
|
|
741
|
+
if (this._throwOnErrors) {
|
|
742
|
+
throw error;
|
|
743
|
+
}
|
|
744
|
+
return false;
|
|
683
745
|
}
|
|
684
746
|
if (rawData) {
|
|
685
747
|
const data = await this.deserializeData(rawData);
|
package/dist/index.d.cts
CHANGED
|
@@ -42,7 +42,7 @@ declare class StatsManager extends EventManager {
|
|
|
42
42
|
|
|
43
43
|
type DeserializedData<Value> = {
|
|
44
44
|
value?: Value;
|
|
45
|
-
expires?: number |
|
|
45
|
+
expires?: number | undefined;
|
|
46
46
|
};
|
|
47
47
|
type CompressionAdapter = {
|
|
48
48
|
compress(value: any, options?: any): Promise<any>;
|
|
@@ -102,24 +102,56 @@ type KeyvStoreAdapter = {
|
|
|
102
102
|
iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
|
|
103
103
|
} & IEventEmitter;
|
|
104
104
|
type KeyvOptions = {
|
|
105
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Emit errors
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
106
109
|
emitErrors?: boolean;
|
|
107
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Namespace for the current instance.
|
|
112
|
+
* @default 'keyv'
|
|
113
|
+
*/
|
|
108
114
|
namespace?: string;
|
|
109
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* A custom serialization function.
|
|
117
|
+
* @default defaultSerialize using JSON.stringify
|
|
118
|
+
*/
|
|
110
119
|
serialize?: Serialize;
|
|
111
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* A custom deserialization function.
|
|
122
|
+
* @default defaultDeserialize using JSON.parse
|
|
123
|
+
*/
|
|
112
124
|
deserialize?: Deserialize;
|
|
113
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* The storage adapter instance to be used by Keyv.
|
|
127
|
+
* @default new Map() - in-memory store
|
|
128
|
+
*/
|
|
114
129
|
store?: KeyvStoreAdapter | Map<any, any> | any;
|
|
115
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* Default TTL. Can be overridden by specifying a TTL on `.set()`.
|
|
132
|
+
* @default undefined
|
|
133
|
+
*/
|
|
116
134
|
ttl?: number;
|
|
117
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Enable compression option
|
|
137
|
+
* @default false
|
|
138
|
+
*/
|
|
118
139
|
compression?: CompressionAdapter | any;
|
|
119
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Enable or disable statistics (default is false)
|
|
142
|
+
* @default false
|
|
143
|
+
*/
|
|
120
144
|
stats?: boolean;
|
|
121
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Enable or disable key prefixing (default is true)
|
|
147
|
+
* @default true
|
|
148
|
+
*/
|
|
122
149
|
useKeyPrefix?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Will enable throwing errors on methods in addition to emitting them.
|
|
152
|
+
* @default false
|
|
153
|
+
*/
|
|
154
|
+
throwOnErrors?: boolean;
|
|
123
155
|
};
|
|
124
156
|
type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
|
|
125
157
|
store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
|
|
@@ -146,6 +178,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
|
|
|
146
178
|
private _deserialize;
|
|
147
179
|
private _compression;
|
|
148
180
|
private _useKeyPrefix;
|
|
181
|
+
private _throwOnErrors;
|
|
149
182
|
/**
|
|
150
183
|
* Keyv Constructor
|
|
151
184
|
* @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
|
|
@@ -227,6 +260,16 @@ declare class Keyv<GenericValue = any> extends EventManager {
|
|
|
227
260
|
* @param {boolean} value The useKeyPrefix value to set.
|
|
228
261
|
*/
|
|
229
262
|
set useKeyPrefix(value: boolean);
|
|
263
|
+
/**
|
|
264
|
+
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
265
|
+
* @return {boolean} The current throwOnErrors value.
|
|
266
|
+
*/
|
|
267
|
+
get throwOnErrors(): boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
270
|
+
* @param {boolean} value The throwOnErrors value to set.
|
|
271
|
+
*/
|
|
272
|
+
set throwOnErrors(value: boolean);
|
|
230
273
|
generateIterator(iterator: IteratorFunction): IteratorFunction;
|
|
231
274
|
_checkIterableAdapter(): boolean;
|
|
232
275
|
_getKeyPrefix(key: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ declare class StatsManager extends EventManager {
|
|
|
42
42
|
|
|
43
43
|
type DeserializedData<Value> = {
|
|
44
44
|
value?: Value;
|
|
45
|
-
expires?: number |
|
|
45
|
+
expires?: number | undefined;
|
|
46
46
|
};
|
|
47
47
|
type CompressionAdapter = {
|
|
48
48
|
compress(value: any, options?: any): Promise<any>;
|
|
@@ -102,24 +102,56 @@ type KeyvStoreAdapter = {
|
|
|
102
102
|
iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
|
|
103
103
|
} & IEventEmitter;
|
|
104
104
|
type KeyvOptions = {
|
|
105
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Emit errors
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
106
109
|
emitErrors?: boolean;
|
|
107
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Namespace for the current instance.
|
|
112
|
+
* @default 'keyv'
|
|
113
|
+
*/
|
|
108
114
|
namespace?: string;
|
|
109
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* A custom serialization function.
|
|
117
|
+
* @default defaultSerialize using JSON.stringify
|
|
118
|
+
*/
|
|
110
119
|
serialize?: Serialize;
|
|
111
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* A custom deserialization function.
|
|
122
|
+
* @default defaultDeserialize using JSON.parse
|
|
123
|
+
*/
|
|
112
124
|
deserialize?: Deserialize;
|
|
113
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* The storage adapter instance to be used by Keyv.
|
|
127
|
+
* @default new Map() - in-memory store
|
|
128
|
+
*/
|
|
114
129
|
store?: KeyvStoreAdapter | Map<any, any> | any;
|
|
115
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* Default TTL. Can be overridden by specifying a TTL on `.set()`.
|
|
132
|
+
* @default undefined
|
|
133
|
+
*/
|
|
116
134
|
ttl?: number;
|
|
117
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Enable compression option
|
|
137
|
+
* @default false
|
|
138
|
+
*/
|
|
118
139
|
compression?: CompressionAdapter | any;
|
|
119
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Enable or disable statistics (default is false)
|
|
142
|
+
* @default false
|
|
143
|
+
*/
|
|
120
144
|
stats?: boolean;
|
|
121
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Enable or disable key prefixing (default is true)
|
|
147
|
+
* @default true
|
|
148
|
+
*/
|
|
122
149
|
useKeyPrefix?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Will enable throwing errors on methods in addition to emitting them.
|
|
152
|
+
* @default false
|
|
153
|
+
*/
|
|
154
|
+
throwOnErrors?: boolean;
|
|
123
155
|
};
|
|
124
156
|
type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
|
|
125
157
|
store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
|
|
@@ -146,6 +178,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
|
|
|
146
178
|
private _deserialize;
|
|
147
179
|
private _compression;
|
|
148
180
|
private _useKeyPrefix;
|
|
181
|
+
private _throwOnErrors;
|
|
149
182
|
/**
|
|
150
183
|
* Keyv Constructor
|
|
151
184
|
* @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
|
|
@@ -227,6 +260,16 @@ declare class Keyv<GenericValue = any> extends EventManager {
|
|
|
227
260
|
* @param {boolean} value The useKeyPrefix value to set.
|
|
228
261
|
*/
|
|
229
262
|
set useKeyPrefix(value: boolean);
|
|
263
|
+
/**
|
|
264
|
+
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
265
|
+
* @return {boolean} The current throwOnErrors value.
|
|
266
|
+
*/
|
|
267
|
+
get throwOnErrors(): boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
270
|
+
* @param {boolean} value The throwOnErrors value to set.
|
|
271
|
+
*/
|
|
272
|
+
set throwOnErrors(value: boolean);
|
|
230
273
|
generateIterator(iterator: IteratorFunction): IteratorFunction;
|
|
231
274
|
_checkIterableAdapter(): boolean;
|
|
232
275
|
_getKeyPrefix(key: string): string;
|
package/dist/index.js
CHANGED
|
@@ -211,6 +211,7 @@ var Keyv = class extends event_manager_default {
|
|
|
211
211
|
_deserialize = defaultDeserialize;
|
|
212
212
|
_compression;
|
|
213
213
|
_useKeyPrefix = true;
|
|
214
|
+
_throwOnErrors = false;
|
|
214
215
|
/**
|
|
215
216
|
* Keyv Constructor
|
|
216
217
|
* @param {KeyvStoreAdapter | KeyvOptions} store
|
|
@@ -267,6 +268,9 @@ var Keyv = class extends event_manager_default {
|
|
|
267
268
|
if (this.opts.useKeyPrefix !== void 0) {
|
|
268
269
|
this._useKeyPrefix = this.opts.useKeyPrefix;
|
|
269
270
|
}
|
|
271
|
+
if (this.opts.throwOnErrors !== void 0) {
|
|
272
|
+
this._throwOnErrors = this.opts.throwOnErrors;
|
|
273
|
+
}
|
|
270
274
|
}
|
|
271
275
|
/**
|
|
272
276
|
* Get the current store
|
|
@@ -391,6 +395,21 @@ var Keyv = class extends event_manager_default {
|
|
|
391
395
|
this._useKeyPrefix = value;
|
|
392
396
|
this.opts.useKeyPrefix = value;
|
|
393
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
400
|
+
* @return {boolean} The current throwOnErrors value.
|
|
401
|
+
*/
|
|
402
|
+
get throwOnErrors() {
|
|
403
|
+
return this._throwOnErrors;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
|
|
407
|
+
* @param {boolean} value The throwOnErrors value to set.
|
|
408
|
+
*/
|
|
409
|
+
set throwOnErrors(value) {
|
|
410
|
+
this._throwOnErrors = value;
|
|
411
|
+
this.opts.throwOnErrors = value;
|
|
412
|
+
}
|
|
394
413
|
generateIterator(iterator) {
|
|
395
414
|
const function_ = async function* () {
|
|
396
415
|
for await (const [key, raw] of typeof iterator === "function" ? iterator(this._store.namespace) : iterator) {
|
|
@@ -437,6 +456,7 @@ var Keyv = class extends event_manager_default {
|
|
|
437
456
|
_isValidStorageAdapter(store) {
|
|
438
457
|
return store instanceof Map || typeof store.get === "function" && typeof store.set === "function" && typeof store.delete === "function" && typeof store.clear === "function";
|
|
439
458
|
}
|
|
459
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
440
460
|
async get(key, options) {
|
|
441
461
|
const { store } = this.opts;
|
|
442
462
|
const isArray = Array.isArray(key);
|
|
@@ -449,7 +469,14 @@ var Keyv = class extends event_manager_default {
|
|
|
449
469
|
return this.getMany(key, { raw: false });
|
|
450
470
|
}
|
|
451
471
|
this.hooks.trigger("preGet" /* PRE_GET */, { key: keyPrefixed });
|
|
452
|
-
|
|
472
|
+
let rawData;
|
|
473
|
+
try {
|
|
474
|
+
rawData = await store.get(keyPrefixed);
|
|
475
|
+
} catch (error) {
|
|
476
|
+
if (this.throwOnErrors) {
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
453
480
|
const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
|
|
454
481
|
if (deserializedData === void 0 || deserializedData === null) {
|
|
455
482
|
this.stats.miss();
|
|
@@ -492,6 +519,7 @@ var Keyv = class extends event_manager_default {
|
|
|
492
519
|
}
|
|
493
520
|
const rawData = await store.getMany(keyPrefixed);
|
|
494
521
|
const result = [];
|
|
522
|
+
const expiredKeys = [];
|
|
495
523
|
for (const index in rawData) {
|
|
496
524
|
let row = rawData[index];
|
|
497
525
|
if (typeof row === "string") {
|
|
@@ -502,13 +530,16 @@ var Keyv = class extends event_manager_default {
|
|
|
502
530
|
continue;
|
|
503
531
|
}
|
|
504
532
|
if (isDataExpired(row)) {
|
|
505
|
-
|
|
533
|
+
expiredKeys.push(keys[index]);
|
|
506
534
|
result.push(void 0);
|
|
507
535
|
continue;
|
|
508
536
|
}
|
|
509
537
|
const value = options?.raw ? row : row.value;
|
|
510
538
|
result.push(value);
|
|
511
539
|
}
|
|
540
|
+
if (expiredKeys.length > 0) {
|
|
541
|
+
await this.deleteMany(expiredKeys);
|
|
542
|
+
}
|
|
512
543
|
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result);
|
|
513
544
|
if (result.length > 0) {
|
|
514
545
|
this.stats.hit();
|
|
@@ -526,14 +557,12 @@ var Keyv = class extends event_manager_default {
|
|
|
526
557
|
const data = { key, value, ttl };
|
|
527
558
|
this.hooks.trigger("preSet" /* PRE_SET */, data);
|
|
528
559
|
const keyPrefixed = this._getKeyPrefix(data.key);
|
|
529
|
-
|
|
530
|
-
data.ttl = this._ttl;
|
|
531
|
-
}
|
|
560
|
+
data.ttl ??= this._ttl;
|
|
532
561
|
if (data.ttl === 0) {
|
|
533
562
|
data.ttl = void 0;
|
|
534
563
|
}
|
|
535
564
|
const { store } = this.opts;
|
|
536
|
-
const expires = typeof data.ttl === "number" ? Date.now() + data.ttl :
|
|
565
|
+
const expires = typeof data.ttl === "number" ? Date.now() + data.ttl : void 0;
|
|
537
566
|
if (typeof data.value === "symbol") {
|
|
538
567
|
this.emit("error", "symbol cannot be serialized");
|
|
539
568
|
throw new Error("symbol cannot be serialized");
|
|
@@ -549,6 +578,9 @@ var Keyv = class extends event_manager_default {
|
|
|
549
578
|
} catch (error) {
|
|
550
579
|
result = false;
|
|
551
580
|
this.emit("error", error);
|
|
581
|
+
if (this._throwOnErrors) {
|
|
582
|
+
throw error;
|
|
583
|
+
}
|
|
552
584
|
}
|
|
553
585
|
this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
|
|
554
586
|
this.stats.set();
|
|
@@ -562,18 +594,35 @@ var Keyv = class extends event_manager_default {
|
|
|
562
594
|
async setMany(entries) {
|
|
563
595
|
let results = [];
|
|
564
596
|
try {
|
|
565
|
-
if (this._store.setMany
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
597
|
+
if (this._store.setMany === void 0) {
|
|
598
|
+
const promises = [];
|
|
599
|
+
for (const entry of entries) {
|
|
600
|
+
promises.push(this.set(entry.key, entry.value, entry.ttl));
|
|
601
|
+
}
|
|
602
|
+
const promiseResults = await Promise.all(promises);
|
|
603
|
+
results = promiseResults;
|
|
604
|
+
} else {
|
|
605
|
+
const serializedEntries = await Promise.all(entries.map(async ({ key, value, ttl }) => {
|
|
606
|
+
ttl ??= this._ttl;
|
|
607
|
+
if (ttl === 0) {
|
|
608
|
+
ttl = void 0;
|
|
609
|
+
}
|
|
610
|
+
const expires = typeof ttl === "number" ? Date.now() + ttl : void 0;
|
|
611
|
+
if (typeof value === "symbol") {
|
|
612
|
+
this.emit("error", "symbol cannot be serialized");
|
|
613
|
+
throw new Error("symbol cannot be serialized");
|
|
614
|
+
}
|
|
615
|
+
const formattedValue = { value, expires };
|
|
616
|
+
const serializedValue = await this.serializeData(formattedValue);
|
|
617
|
+
return { key, value: serializedValue, ttl };
|
|
618
|
+
}));
|
|
619
|
+
results = await this._store.setMany(serializedEntries);
|
|
572
620
|
}
|
|
573
|
-
const promiseResults = await Promise.allSettled(promises);
|
|
574
|
-
results = promiseResults.map((result) => result.value);
|
|
575
621
|
} catch (error) {
|
|
576
622
|
this.emit("error", error);
|
|
623
|
+
if (this._throwOnErrors) {
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
577
626
|
results = entries.map(() => false);
|
|
578
627
|
}
|
|
579
628
|
return results;
|
|
@@ -599,6 +648,9 @@ var Keyv = class extends event_manager_default {
|
|
|
599
648
|
} catch (error) {
|
|
600
649
|
result = false;
|
|
601
650
|
this.emit("error", error);
|
|
651
|
+
if (this._throwOnErrors) {
|
|
652
|
+
throw error;
|
|
653
|
+
}
|
|
602
654
|
}
|
|
603
655
|
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
|
|
604
656
|
this.stats.delete();
|
|
@@ -618,12 +670,15 @@ var Keyv = class extends event_manager_default {
|
|
|
618
670
|
return await store.deleteMany(keyPrefixed);
|
|
619
671
|
}
|
|
620
672
|
const promises = keyPrefixed.map(async (key) => store.delete(key));
|
|
621
|
-
const results = await Promise.
|
|
622
|
-
const returnResult = results.every(
|
|
673
|
+
const results = await Promise.all(promises);
|
|
674
|
+
const returnResult = results.every(Boolean);
|
|
623
675
|
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
|
|
624
676
|
return returnResult;
|
|
625
677
|
} catch (error) {
|
|
626
678
|
this.emit("error", error);
|
|
679
|
+
if (this._throwOnErrors) {
|
|
680
|
+
throw error;
|
|
681
|
+
}
|
|
627
682
|
return false;
|
|
628
683
|
}
|
|
629
684
|
}
|
|
@@ -638,6 +693,9 @@ var Keyv = class extends event_manager_default {
|
|
|
638
693
|
await store.clear();
|
|
639
694
|
} catch (error) {
|
|
640
695
|
this.emit("error", error);
|
|
696
|
+
if (this._throwOnErrors) {
|
|
697
|
+
throw error;
|
|
698
|
+
}
|
|
641
699
|
}
|
|
642
700
|
}
|
|
643
701
|
async has(key) {
|
|
@@ -654,6 +712,10 @@ var Keyv = class extends event_manager_default {
|
|
|
654
712
|
rawData = await store.get(keyPrefixed);
|
|
655
713
|
} catch (error) {
|
|
656
714
|
this.emit("error", error);
|
|
715
|
+
if (this._throwOnErrors) {
|
|
716
|
+
throw error;
|
|
717
|
+
}
|
|
718
|
+
return false;
|
|
657
719
|
}
|
|
658
720
|
if (rawData) {
|
|
659
721
|
const data = await this.deserializeData(rawData);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keyv",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Simple key-value storage with support for multiple backends",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -54,23 +54,23 @@
|
|
|
54
54
|
},
|
|
55
55
|
"homepage": "https://github.com/jaredwray/keyv",
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@keyv/serialize": "^1.0
|
|
57
|
+
"@keyv/serialize": "^1.1.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@faker-js/faker": "^9.
|
|
61
|
-
"@vitest/coverage-v8": "^3.
|
|
60
|
+
"@faker-js/faker": "^9.9.0",
|
|
61
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
62
62
|
"rimraf": "^6.0.1",
|
|
63
63
|
"timekeeper": "^2.3.1",
|
|
64
|
-
"tsd": "^0.
|
|
65
|
-
"vitest": "^3.
|
|
66
|
-
"xo": "^
|
|
67
|
-
"@keyv/
|
|
68
|
-
"@keyv/compress-
|
|
69
|
-
"@keyv/compress-
|
|
70
|
-
"@keyv/
|
|
71
|
-
"@keyv/
|
|
72
|
-
"@keyv/
|
|
73
|
-
"@keyv/
|
|
64
|
+
"tsd": "^0.32.0",
|
|
65
|
+
"vitest": "^3.2.4",
|
|
66
|
+
"xo": "^1.1.1",
|
|
67
|
+
"@keyv/memcache": "^2.0.2",
|
|
68
|
+
"@keyv/compress-gzip": "^2.0.3",
|
|
69
|
+
"@keyv/compress-lz4": "^1.0.1",
|
|
70
|
+
"@keyv/compress-brotli": "^2.0.5",
|
|
71
|
+
"@keyv/mongo": "^3.0.3",
|
|
72
|
+
"@keyv/test-suite": "^2.0.9",
|
|
73
|
+
"@keyv/sqlite": "^4.0.5"
|
|
74
74
|
},
|
|
75
75
|
"tsd": {
|
|
76
76
|
"directory": "test"
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"scripts": {
|
|
83
83
|
"build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
|
|
84
84
|
"test": "xo --fix && vitest run --coverage",
|
|
85
|
-
"test:ci": "xo && vitest --run --sequence.setupFiles=list",
|
|
85
|
+
"test:ci": "xo && vitest --run --sequence.setupFiles=list --coverage",
|
|
86
86
|
"clean": "rimraf ./node_modules ./coverage ./test/testdb.sqlite ./dist"
|
|
87
87
|
}
|
|
88
88
|
}
|