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 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
- const rawData = await store.get(keyPrefixed);
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
- await this.delete(keys[index]);
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
- if (data.ttl === void 0) {
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 : null;
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 !== void 0) {
592
- results = await this._store.setMany(entries);
593
- return results;
594
- }
595
- const promises = [];
596
- for (const entry of entries) {
597
- promises.push(this.set(entry.key, entry.value, entry.ttl));
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.allSettled(promises);
648
- const returnResult = results.every((x) => x.value === true);
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 | null;
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
- /** Emit errors */
105
+ /**
106
+ * Emit errors
107
+ * @default true
108
+ */
106
109
  emitErrors?: boolean;
107
- /** Namespace for the current instance. */
110
+ /**
111
+ * Namespace for the current instance.
112
+ * @default 'keyv'
113
+ */
108
114
  namespace?: string;
109
- /** A custom serialization function. */
115
+ /**
116
+ * A custom serialization function.
117
+ * @default defaultSerialize using JSON.stringify
118
+ */
110
119
  serialize?: Serialize;
111
- /** A custom deserialization function. */
120
+ /**
121
+ * A custom deserialization function.
122
+ * @default defaultDeserialize using JSON.parse
123
+ */
112
124
  deserialize?: Deserialize;
113
- /** The storage adapter instance to be used by Keyv. */
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
- /** Default TTL. Can be overridden by specifying a TTL on `.set()`. */
130
+ /**
131
+ * Default TTL. Can be overridden by specifying a TTL on `.set()`.
132
+ * @default undefined
133
+ */
116
134
  ttl?: number;
117
- /** Enable compression option **/
135
+ /**
136
+ * Enable compression option
137
+ * @default false
138
+ */
118
139
  compression?: CompressionAdapter | any;
119
- /** Enable or disable statistics (default is false) */
140
+ /**
141
+ * Enable or disable statistics (default is false)
142
+ * @default false
143
+ */
120
144
  stats?: boolean;
121
- /** Enable or disable key prefixing (default is true) */
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 | null;
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
- /** Emit errors */
105
+ /**
106
+ * Emit errors
107
+ * @default true
108
+ */
106
109
  emitErrors?: boolean;
107
- /** Namespace for the current instance. */
110
+ /**
111
+ * Namespace for the current instance.
112
+ * @default 'keyv'
113
+ */
108
114
  namespace?: string;
109
- /** A custom serialization function. */
115
+ /**
116
+ * A custom serialization function.
117
+ * @default defaultSerialize using JSON.stringify
118
+ */
110
119
  serialize?: Serialize;
111
- /** A custom deserialization function. */
120
+ /**
121
+ * A custom deserialization function.
122
+ * @default defaultDeserialize using JSON.parse
123
+ */
112
124
  deserialize?: Deserialize;
113
- /** The storage adapter instance to be used by Keyv. */
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
- /** Default TTL. Can be overridden by specifying a TTL on `.set()`. */
130
+ /**
131
+ * Default TTL. Can be overridden by specifying a TTL on `.set()`.
132
+ * @default undefined
133
+ */
116
134
  ttl?: number;
117
- /** Enable compression option **/
135
+ /**
136
+ * Enable compression option
137
+ * @default false
138
+ */
118
139
  compression?: CompressionAdapter | any;
119
- /** Enable or disable statistics (default is false) */
140
+ /**
141
+ * Enable or disable statistics (default is false)
142
+ * @default false
143
+ */
120
144
  stats?: boolean;
121
- /** Enable or disable key prefixing (default is true) */
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
- const rawData = await store.get(keyPrefixed);
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
- await this.delete(keys[index]);
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
- if (data.ttl === void 0) {
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 : null;
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 !== void 0) {
566
- results = await this._store.setMany(entries);
567
- return results;
568
- }
569
- const promises = [];
570
- for (const entry of entries) {
571
- promises.push(this.set(entry.key, entry.value, entry.ttl));
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.allSettled(promises);
622
- const returnResult = results.every((x) => x.value === true);
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.3",
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.3"
57
+ "@keyv/serialize": "^1.1.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@faker-js/faker": "^9.6.0",
61
- "@vitest/coverage-v8": "^3.1.1",
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.31.2",
65
- "vitest": "^3.1.1",
66
- "xo": "^0.60.0",
67
- "@keyv/compress-gzip": "^2.0.2",
68
- "@keyv/compress-lz4": "^1.0.0",
69
- "@keyv/compress-brotli": "^2.0.3",
70
- "@keyv/memcache": "^2.0.1",
71
- "@keyv/sqlite": "^4.0.2",
72
- "@keyv/mongo": "^3.0.1",
73
- "@keyv/test-suite": "^2.0.6"
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
  }