keyv 5.3.4 → 5.5.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
@@ -49,18 +49,12 @@ There are a few existing modules similar to Keyv, however Keyv is different beca
49
49
  - [.setMany(entries)](#setmanyentries)
50
50
  - [.get(key, [options])](#getkey-options)
51
51
  - [.getMany(keys, [options])](#getmanykeys-options)
52
+ - [.getRaw(key)](#getrawkey)
53
+ - [.getManyRaw(keys)](#getmanyrawkeys)
52
54
  - [.delete(key)](#deletekey)
53
55
  - [.deleteMany(keys)](#deletemanykeys)
54
56
  - [.clear()](#clear)
55
57
  - [.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
58
  - [How to Contribute](#how-to-contribute)
65
59
  - [License](#license)
66
60
 
@@ -83,6 +77,7 @@ npm install --save @keyv/postgres
83
77
  npm install --save @keyv/mysql
84
78
  npm install --save @keyv/etcd
85
79
  npm install --save @keyv/memcache
80
+ npm install --save @keyv/dynamo
86
81
  ```
87
82
 
88
83
  First, create a new Keyv instance.
@@ -233,7 +228,7 @@ keyv.hooks.addHandler(KeyvHooks.PRE_SET, (data) => console.log(`Setting key ${da
233
228
 
234
229
  //POST_SET hook
235
230
  const keyv = new Keyv();
236
- keyv.hooks.addHandler(KeyvHooks.POST_SET, (key, value) => console.log(`Set key ${key} to ${value}`));
231
+ keyv.hooks.addHandler(KeyvHooks.POST_SET, ({key, value}) => console.log(`Set key ${key} to ${value}`));
237
232
  ```
238
233
 
239
234
  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 +281,7 @@ PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/master/pack
286
281
  MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/master/packages/mysql) | No
287
282
  Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/master/packages/etcd) | Yes
288
283
  Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/master/packages/memcache) | Yes
284
+ DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/master/packages/dynamo) | Yes
289
285
 
290
286
  # Third-party Storage Adapters
291
287
 
@@ -318,7 +314,6 @@ The following are third-party storage adapters compatible with Keyv:
318
314
 
319
315
  - [quick-lru](https://github.com/sindresorhus/quick-lru) - Simple "Least Recently Used" (LRU) cache
320
316
  - [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
317
  - [keyv-lru](https://www.npmjs.com/package/keyv-lru) - LRU storage adapter for Keyv
323
318
  - [keyv-null](https://www.npmjs.com/package/keyv-null) - Null storage adapter for Keyv
324
319
  - [keyv-firestore ](https://github.com/goto-bus-stop/keyv-firestore) – Firebase Cloud Firestore adapter for Keyv
@@ -476,7 +471,7 @@ Returns a promise which resolves to the retrieved value.
476
471
 
477
472
  Returns a promise which resolves to an array of retrieved values.
478
473
 
479
- ### options.raw
474
+ ### options.raw - (Will be deprecated in v6)
480
475
 
481
476
  Type: `Boolean`<br />
482
477
  Default: `false`
@@ -485,6 +480,16 @@ If set to true the raw DB object Keyv stores internally will be returned instead
485
480
 
486
481
  This contains the TTL timestamp.
487
482
 
483
+ NOTE: This option will be deprecated in v6 and replaced with `.getRaw()` and `.getManyRaw()` methods.
484
+
485
+ ## .getRaw(key)
486
+
487
+ Returns a promise which resolves to the raw stored data for the key or `undefined` if the key does not exist or is expired.
488
+
489
+ ## .getManyRaw(keys)
490
+
491
+ Returns a promise which resolves to an array of raw stored data for the keys or `undefined` if the key does not exist or is expired.
492
+
488
493
  ## .delete(key)
489
494
 
490
495
  Deletes an entry.
@@ -623,6 +628,50 @@ keyv.useKeyPrefix = true;
623
628
  console.log(keyv.useKeyPrefix); // true
624
629
  ```
625
630
 
631
+ 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`:
632
+
633
+ ```js
634
+ import Keyv from 'keyv';
635
+ import KeyvSqlite from '@keyv/sqlite';
636
+
637
+ const store = new KeyvSqlite('sqlite://path/to/database.sqlite');
638
+ const keyv = new Keyv({ store });
639
+ keyv.useKeyPrefix = false; // disable key prefixing
640
+ store.namespace = undefined; // disable namespacing in the storage adapter
641
+
642
+ await keyv.set('foo', 'bar'); // true
643
+ await keyv.get('foo'); // 'bar'
644
+ await keyv.clear();
645
+ ```
646
+
647
+ ## .throwOnErrors
648
+
649
+ Type: `Boolean`<br />
650
+ Default: `false`
651
+
652
+ 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.
653
+
654
+ ```js
655
+ const keyv = new Keyv({ throwOnErrors: true });
656
+ console.log(keyv.throwOnErrors); // true
657
+ keyv.throwOnErrors = false;
658
+ console.log(keyv.throwOnErrors); // false
659
+ ```
660
+
661
+ 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:
662
+
663
+ ```js
664
+ import Keyv from 'keyv';
665
+ import KeyvRedis from '@keyv/redis';
666
+
667
+ // create redis instance that will throw on connection error
668
+ const keyvRedis = new KeyvRedis('redis://user:pass@localhost:6379', { throwOnConnectErrors: true });
669
+
670
+ const keyv = new Keyv({ store: keyvRedis, throwOnErrors: true });
671
+ ```
672
+
673
+ What this does is it only throw on connection errors with the Redis client.
674
+
626
675
  # How to Contribute
627
676
 
628
677
  We welcome contributions to Keyv! 🎉 Here are some guides to get you started with contributing:
package/dist/index.cjs CHANGED
@@ -185,6 +185,15 @@ var StatsManager = class extends event_manager_default {
185
185
  this.deletes++;
186
186
  }
187
187
  }
188
+ hitsOrMisses(array) {
189
+ for (const item of array) {
190
+ if (item === void 0) {
191
+ this.miss();
192
+ } else {
193
+ this.hit();
194
+ }
195
+ }
196
+ }
188
197
  reset() {
189
198
  this.hits = 0;
190
199
  this.misses = 0;
@@ -203,6 +212,10 @@ var KeyvHooks = /* @__PURE__ */ ((KeyvHooks2) => {
203
212
  KeyvHooks2["POST_GET"] = "postGet";
204
213
  KeyvHooks2["PRE_GET_MANY"] = "preGetMany";
205
214
  KeyvHooks2["POST_GET_MANY"] = "postGetMany";
215
+ KeyvHooks2["PRE_GET_RAW"] = "preGetRaw";
216
+ KeyvHooks2["POST_GET_RAW"] = "postGetRaw";
217
+ KeyvHooks2["PRE_GET_MANY_RAW"] = "preGetManyRaw";
218
+ KeyvHooks2["POST_GET_MANY_RAW"] = "postGetManyRaw";
206
219
  KeyvHooks2["PRE_DELETE"] = "preDelete";
207
220
  KeyvHooks2["POST_DELETE"] = "postDelete";
208
221
  return KeyvHooks2;
@@ -237,6 +250,7 @@ var Keyv = class extends event_manager_default {
237
250
  _deserialize = import_serialize.defaultDeserialize;
238
251
  _compression;
239
252
  _useKeyPrefix = true;
253
+ _throwOnErrors = false;
240
254
  /**
241
255
  * Keyv Constructor
242
256
  * @param {KeyvStoreAdapter | KeyvOptions} store
@@ -293,6 +307,9 @@ var Keyv = class extends event_manager_default {
293
307
  if (this.opts.useKeyPrefix !== void 0) {
294
308
  this._useKeyPrefix = this.opts.useKeyPrefix;
295
309
  }
310
+ if (this.opts.throwOnErrors !== void 0) {
311
+ this._throwOnErrors = this.opts.throwOnErrors;
312
+ }
296
313
  }
297
314
  /**
298
315
  * Get the current store
@@ -417,6 +434,21 @@ var Keyv = class extends event_manager_default {
417
434
  this._useKeyPrefix = value;
418
435
  this.opts.useKeyPrefix = value;
419
436
  }
437
+ /**
438
+ * Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
439
+ * @return {boolean} The current throwOnErrors value.
440
+ */
441
+ get throwOnErrors() {
442
+ return this._throwOnErrors;
443
+ }
444
+ /**
445
+ * Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
446
+ * @param {boolean} value The throwOnErrors value to set.
447
+ */
448
+ set throwOnErrors(value) {
449
+ this._throwOnErrors = value;
450
+ this.opts.throwOnErrors = value;
451
+ }
420
452
  generateIterator(iterator) {
421
453
  const function_ = async function* () {
422
454
  for await (const [key, raw] of typeof iterator === "function" ? iterator(this._store.namespace) : iterator) {
@@ -476,7 +508,14 @@ var Keyv = class extends event_manager_default {
476
508
  return this.getMany(key, { raw: false });
477
509
  }
478
510
  this.hooks.trigger("preGet" /* PRE_GET */, { key: keyPrefixed });
479
- const rawData = await store.get(keyPrefixed);
511
+ let rawData;
512
+ try {
513
+ rawData = await store.get(keyPrefixed);
514
+ } catch (error) {
515
+ if (this.throwOnErrors) {
516
+ throw error;
517
+ }
518
+ }
480
519
  const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
481
520
  if (deserializedData === void 0 || deserializedData === null) {
482
521
  this.stats.miss();
@@ -519,6 +558,7 @@ var Keyv = class extends event_manager_default {
519
558
  }
520
559
  const rawData = await store.getMany(keyPrefixed);
521
560
  const result = [];
561
+ const expiredKeys = [];
522
562
  for (const index in rawData) {
523
563
  let row = rawData[index];
524
564
  if (typeof row === "string") {
@@ -529,19 +569,96 @@ var Keyv = class extends event_manager_default {
529
569
  continue;
530
570
  }
531
571
  if (isDataExpired(row)) {
532
- await this.delete(keys[index]);
572
+ expiredKeys.push(keys[index]);
533
573
  result.push(void 0);
534
574
  continue;
535
575
  }
536
576
  const value = options?.raw ? row : row.value;
537
577
  result.push(value);
538
578
  }
579
+ if (expiredKeys.length > 0) {
580
+ await this.deleteMany(expiredKeys);
581
+ }
539
582
  this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result);
540
583
  if (result.length > 0) {
541
584
  this.stats.hit();
542
585
  }
543
586
  return result;
544
587
  }
588
+ /**
589
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
590
+ * @param {string} key the key to get
591
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
592
+ */
593
+ async getRaw(key) {
594
+ const { store } = this.opts;
595
+ const keyPrefixed = this._getKeyPrefix(key);
596
+ this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key: keyPrefixed });
597
+ const rawData = await store.get(keyPrefixed);
598
+ if (rawData === void 0 || rawData === null) {
599
+ this.stats.miss();
600
+ return void 0;
601
+ }
602
+ const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
603
+ if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && deserializedData.expires < Date.now()) {
604
+ this.stats.miss();
605
+ await this.delete(key);
606
+ return void 0;
607
+ }
608
+ this.stats.hit();
609
+ this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, { key: keyPrefixed, value: deserializedData });
610
+ return deserializedData;
611
+ }
612
+ /**
613
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
614
+ * @param {string[]} keys the keys to get
615
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
616
+ */
617
+ async getManyRaw(keys) {
618
+ const { store } = this.opts;
619
+ const keyPrefixed = this._getKeyPrefixArray(keys);
620
+ if (keys.length === 0) {
621
+ const result2 = Array.from({ length: keys.length }).fill(void 0);
622
+ this.stats.misses += keys.length;
623
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, { keys: keyPrefixed, values: result2 });
624
+ return result2;
625
+ }
626
+ let result = [];
627
+ if (store.getMany === void 0) {
628
+ const promises = keyPrefixed.map(async (key) => {
629
+ const rawData = await store.get(key);
630
+ if (rawData !== void 0 && rawData !== null) {
631
+ return this.deserializeData(rawData);
632
+ }
633
+ return void 0;
634
+ });
635
+ const deserializedRows = await Promise.allSettled(promises);
636
+ result = deserializedRows.map((row) => row.value);
637
+ } else {
638
+ const rawData = await store.getMany(keyPrefixed);
639
+ for (const row of rawData) {
640
+ if (row !== void 0 && row !== null) {
641
+ result.push(await this.deserializeData(row));
642
+ } else {
643
+ result.push(void 0);
644
+ }
645
+ }
646
+ }
647
+ const expiredKeys = [];
648
+ const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
649
+ for (const [index, row] of result.entries()) {
650
+ if (row !== void 0 && isDataExpired(row)) {
651
+ expiredKeys.push(keyPrefixed[index]);
652
+ result[index] = void 0;
653
+ }
654
+ }
655
+ if (expiredKeys.length > 0) {
656
+ await this.deleteMany(expiredKeys);
657
+ }
658
+ this.stats.hitsOrMisses(result);
659
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, { keys: keyPrefixed, values: result });
660
+ return result;
661
+ }
545
662
  /**
546
663
  * Set an item to the store
547
664
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
@@ -574,6 +691,9 @@ var Keyv = class extends event_manager_default {
574
691
  } catch (error) {
575
692
  result = false;
576
693
  this.emit("error", error);
694
+ if (this._throwOnErrors) {
695
+ throw error;
696
+ }
577
697
  }
578
698
  this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
579
699
  this.stats.set();
@@ -587,7 +707,14 @@ var Keyv = class extends event_manager_default {
587
707
  async setMany(entries) {
588
708
  let results = [];
589
709
  try {
590
- if (this._store.setMany !== void 0) {
710
+ if (this._store.setMany === void 0) {
711
+ const promises = [];
712
+ for (const entry of entries) {
713
+ promises.push(this.set(entry.key, entry.value, entry.ttl));
714
+ }
715
+ const promiseResults = await Promise.all(promises);
716
+ results = promiseResults;
717
+ } else {
591
718
  const serializedEntries = await Promise.all(entries.map(async ({ key, value, ttl }) => {
592
719
  ttl ??= this._ttl;
593
720
  if (ttl === 0) {
@@ -604,14 +731,11 @@ var Keyv = class extends event_manager_default {
604
731
  }));
605
732
  results = await this._store.setMany(serializedEntries);
606
733
  }
607
- const promises = [];
608
- for (const entry of entries) {
609
- promises.push(this.set(entry.key, entry.value, entry.ttl));
610
- }
611
- const promiseResults = await Promise.allSettled(promises);
612
- results = promiseResults.map((result) => result.value);
613
734
  } catch (error) {
614
735
  this.emit("error", error);
736
+ if (this._throwOnErrors) {
737
+ throw error;
738
+ }
615
739
  results = entries.map(() => false);
616
740
  }
617
741
  return results;
@@ -637,6 +761,9 @@ var Keyv = class extends event_manager_default {
637
761
  } catch (error) {
638
762
  result = false;
639
763
  this.emit("error", error);
764
+ if (this._throwOnErrors) {
765
+ throw error;
766
+ }
640
767
  }
641
768
  this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
642
769
  this.stats.delete();
@@ -656,12 +783,15 @@ var Keyv = class extends event_manager_default {
656
783
  return await store.deleteMany(keyPrefixed);
657
784
  }
658
785
  const promises = keyPrefixed.map(async (key) => store.delete(key));
659
- const results = await Promise.allSettled(promises);
660
- const returnResult = results.every((x) => x.value === true);
786
+ const results = await Promise.all(promises);
787
+ const returnResult = results.every(Boolean);
661
788
  this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
662
789
  return returnResult;
663
790
  } catch (error) {
664
791
  this.emit("error", error);
792
+ if (this._throwOnErrors) {
793
+ throw error;
794
+ }
665
795
  return false;
666
796
  }
667
797
  }
@@ -676,6 +806,9 @@ var Keyv = class extends event_manager_default {
676
806
  await store.clear();
677
807
  } catch (error) {
678
808
  this.emit("error", error);
809
+ if (this._throwOnErrors) {
810
+ throw error;
811
+ }
679
812
  }
680
813
  }
681
814
  async has(key) {
@@ -692,6 +825,10 @@ var Keyv = class extends event_manager_default {
692
825
  rawData = await store.get(keyPrefixed);
693
826
  } catch (error) {
694
827
  this.emit("error", error);
828
+ if (this._throwOnErrors) {
829
+ throw error;
830
+ }
831
+ return false;
695
832
  }
696
833
  if (rawData) {
697
834
  const data = await this.deserializeData(rawData);
package/dist/index.d.cts CHANGED
@@ -37,6 +37,7 @@ declare class StatsManager extends EventManager {
37
37
  miss(): void;
38
38
  set(): void;
39
39
  delete(): void;
40
+ hitsOrMisses<T>(array: Array<T | undefined>): void;
40
41
  reset(): void;
41
42
  }
42
43
 
@@ -59,6 +60,10 @@ declare enum KeyvHooks {
59
60
  POST_GET = "postGet",
60
61
  PRE_GET_MANY = "preGetMany",
61
62
  POST_GET_MANY = "postGetMany",
63
+ PRE_GET_RAW = "preGetRaw",
64
+ POST_GET_RAW = "postGetRaw",
65
+ PRE_GET_MANY_RAW = "preGetManyRaw",
66
+ POST_GET_MANY_RAW = "postGetManyRaw",
62
67
  PRE_DELETE = "preDelete",
63
68
  POST_DELETE = "postDelete"
64
69
  }
@@ -102,24 +107,56 @@ type KeyvStoreAdapter = {
102
107
  iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
103
108
  } & IEventEmitter;
104
109
  type KeyvOptions = {
105
- /** Emit errors */
110
+ /**
111
+ * Emit errors
112
+ * @default true
113
+ */
106
114
  emitErrors?: boolean;
107
- /** Namespace for the current instance. */
115
+ /**
116
+ * Namespace for the current instance.
117
+ * @default 'keyv'
118
+ */
108
119
  namespace?: string;
109
- /** A custom serialization function. */
120
+ /**
121
+ * A custom serialization function.
122
+ * @default defaultSerialize using JSON.stringify
123
+ */
110
124
  serialize?: Serialize;
111
- /** A custom deserialization function. */
125
+ /**
126
+ * A custom deserialization function.
127
+ * @default defaultDeserialize using JSON.parse
128
+ */
112
129
  deserialize?: Deserialize;
113
- /** The storage adapter instance to be used by Keyv. */
130
+ /**
131
+ * The storage adapter instance to be used by Keyv.
132
+ * @default new Map() - in-memory store
133
+ */
114
134
  store?: KeyvStoreAdapter | Map<any, any> | any;
115
- /** Default TTL. Can be overridden by specifying a TTL on `.set()`. */
135
+ /**
136
+ * Default TTL. Can be overridden by specifying a TTL on `.set()`.
137
+ * @default undefined
138
+ */
116
139
  ttl?: number;
117
- /** Enable compression option **/
140
+ /**
141
+ * Enable compression option
142
+ * @default false
143
+ */
118
144
  compression?: CompressionAdapter | any;
119
- /** Enable or disable statistics (default is false) */
145
+ /**
146
+ * Enable or disable statistics (default is false)
147
+ * @default false
148
+ */
120
149
  stats?: boolean;
121
- /** Enable or disable key prefixing (default is true) */
150
+ /**
151
+ * Enable or disable key prefixing (default is true)
152
+ * @default true
153
+ */
122
154
  useKeyPrefix?: boolean;
155
+ /**
156
+ * Will enable throwing errors on methods in addition to emitting them.
157
+ * @default false
158
+ */
159
+ throwOnErrors?: boolean;
123
160
  };
124
161
  type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
125
162
  store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
@@ -146,6 +183,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
146
183
  private _deserialize;
147
184
  private _compression;
148
185
  private _useKeyPrefix;
186
+ private _throwOnErrors;
149
187
  /**
150
188
  * Keyv Constructor
151
189
  * @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
@@ -227,6 +265,16 @@ declare class Keyv<GenericValue = any> extends EventManager {
227
265
  * @param {boolean} value The useKeyPrefix value to set.
228
266
  */
229
267
  set useKeyPrefix(value: boolean);
268
+ /**
269
+ * Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
270
+ * @return {boolean} The current throwOnErrors value.
271
+ */
272
+ get throwOnErrors(): boolean;
273
+ /**
274
+ * Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
275
+ * @param {boolean} value The throwOnErrors value to set.
276
+ */
277
+ set throwOnErrors(value: boolean);
230
278
  generateIterator(iterator: IteratorFunction): IteratorFunction;
231
279
  _checkIterableAdapter(): boolean;
232
280
  _getKeyPrefix(key: string): string;
@@ -261,6 +309,18 @@ declare class Keyv<GenericValue = any> extends EventManager {
261
309
  getMany<Value = GenericValue>(keys: string[], options?: {
262
310
  raw: true;
263
311
  }): Promise<Array<StoredDataRaw<Value>>>;
312
+ /**
313
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
314
+ * @param {string} key the key to get
315
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
316
+ */
317
+ getRaw<Value = GenericValue>(key: string): Promise<StoredDataRaw<Value> | undefined>;
318
+ /**
319
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
320
+ * @param {string[]} keys the keys to get
321
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
322
+ */
323
+ getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<StoredDataRaw<Value>>>;
264
324
  /**
265
325
  * Set an item to the store
266
326
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
package/dist/index.d.ts CHANGED
@@ -37,6 +37,7 @@ declare class StatsManager extends EventManager {
37
37
  miss(): void;
38
38
  set(): void;
39
39
  delete(): void;
40
+ hitsOrMisses<T>(array: Array<T | undefined>): void;
40
41
  reset(): void;
41
42
  }
42
43
 
@@ -59,6 +60,10 @@ declare enum KeyvHooks {
59
60
  POST_GET = "postGet",
60
61
  PRE_GET_MANY = "preGetMany",
61
62
  POST_GET_MANY = "postGetMany",
63
+ PRE_GET_RAW = "preGetRaw",
64
+ POST_GET_RAW = "postGetRaw",
65
+ PRE_GET_MANY_RAW = "preGetManyRaw",
66
+ POST_GET_MANY_RAW = "postGetManyRaw",
62
67
  PRE_DELETE = "preDelete",
63
68
  POST_DELETE = "postDelete"
64
69
  }
@@ -102,24 +107,56 @@ type KeyvStoreAdapter = {
102
107
  iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
103
108
  } & IEventEmitter;
104
109
  type KeyvOptions = {
105
- /** Emit errors */
110
+ /**
111
+ * Emit errors
112
+ * @default true
113
+ */
106
114
  emitErrors?: boolean;
107
- /** Namespace for the current instance. */
115
+ /**
116
+ * Namespace for the current instance.
117
+ * @default 'keyv'
118
+ */
108
119
  namespace?: string;
109
- /** A custom serialization function. */
120
+ /**
121
+ * A custom serialization function.
122
+ * @default defaultSerialize using JSON.stringify
123
+ */
110
124
  serialize?: Serialize;
111
- /** A custom deserialization function. */
125
+ /**
126
+ * A custom deserialization function.
127
+ * @default defaultDeserialize using JSON.parse
128
+ */
112
129
  deserialize?: Deserialize;
113
- /** The storage adapter instance to be used by Keyv. */
130
+ /**
131
+ * The storage adapter instance to be used by Keyv.
132
+ * @default new Map() - in-memory store
133
+ */
114
134
  store?: KeyvStoreAdapter | Map<any, any> | any;
115
- /** Default TTL. Can be overridden by specifying a TTL on `.set()`. */
135
+ /**
136
+ * Default TTL. Can be overridden by specifying a TTL on `.set()`.
137
+ * @default undefined
138
+ */
116
139
  ttl?: number;
117
- /** Enable compression option **/
140
+ /**
141
+ * Enable compression option
142
+ * @default false
143
+ */
118
144
  compression?: CompressionAdapter | any;
119
- /** Enable or disable statistics (default is false) */
145
+ /**
146
+ * Enable or disable statistics (default is false)
147
+ * @default false
148
+ */
120
149
  stats?: boolean;
121
- /** Enable or disable key prefixing (default is true) */
150
+ /**
151
+ * Enable or disable key prefixing (default is true)
152
+ * @default true
153
+ */
122
154
  useKeyPrefix?: boolean;
155
+ /**
156
+ * Will enable throwing errors on methods in addition to emitting them.
157
+ * @default false
158
+ */
159
+ throwOnErrors?: boolean;
123
160
  };
124
161
  type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
125
162
  store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
@@ -146,6 +183,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
146
183
  private _deserialize;
147
184
  private _compression;
148
185
  private _useKeyPrefix;
186
+ private _throwOnErrors;
149
187
  /**
150
188
  * Keyv Constructor
151
189
  * @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
@@ -227,6 +265,16 @@ declare class Keyv<GenericValue = any> extends EventManager {
227
265
  * @param {boolean} value The useKeyPrefix value to set.
228
266
  */
229
267
  set useKeyPrefix(value: boolean);
268
+ /**
269
+ * Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
270
+ * @return {boolean} The current throwOnErrors value.
271
+ */
272
+ get throwOnErrors(): boolean;
273
+ /**
274
+ * Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
275
+ * @param {boolean} value The throwOnErrors value to set.
276
+ */
277
+ set throwOnErrors(value: boolean);
230
278
  generateIterator(iterator: IteratorFunction): IteratorFunction;
231
279
  _checkIterableAdapter(): boolean;
232
280
  _getKeyPrefix(key: string): string;
@@ -261,6 +309,18 @@ declare class Keyv<GenericValue = any> extends EventManager {
261
309
  getMany<Value = GenericValue>(keys: string[], options?: {
262
310
  raw: true;
263
311
  }): Promise<Array<StoredDataRaw<Value>>>;
312
+ /**
313
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
314
+ * @param {string} key the key to get
315
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
316
+ */
317
+ getRaw<Value = GenericValue>(key: string): Promise<StoredDataRaw<Value> | undefined>;
318
+ /**
319
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
320
+ * @param {string[]} keys the keys to get
321
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
322
+ */
323
+ getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<StoredDataRaw<Value>>>;
264
324
  /**
265
325
  * Set an item to the store
266
326
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
package/dist/index.js CHANGED
@@ -159,6 +159,15 @@ var StatsManager = class extends event_manager_default {
159
159
  this.deletes++;
160
160
  }
161
161
  }
162
+ hitsOrMisses(array) {
163
+ for (const item of array) {
164
+ if (item === void 0) {
165
+ this.miss();
166
+ } else {
167
+ this.hit();
168
+ }
169
+ }
170
+ }
162
171
  reset() {
163
172
  this.hits = 0;
164
173
  this.misses = 0;
@@ -177,6 +186,10 @@ var KeyvHooks = /* @__PURE__ */ ((KeyvHooks2) => {
177
186
  KeyvHooks2["POST_GET"] = "postGet";
178
187
  KeyvHooks2["PRE_GET_MANY"] = "preGetMany";
179
188
  KeyvHooks2["POST_GET_MANY"] = "postGetMany";
189
+ KeyvHooks2["PRE_GET_RAW"] = "preGetRaw";
190
+ KeyvHooks2["POST_GET_RAW"] = "postGetRaw";
191
+ KeyvHooks2["PRE_GET_MANY_RAW"] = "preGetManyRaw";
192
+ KeyvHooks2["POST_GET_MANY_RAW"] = "postGetManyRaw";
180
193
  KeyvHooks2["PRE_DELETE"] = "preDelete";
181
194
  KeyvHooks2["POST_DELETE"] = "postDelete";
182
195
  return KeyvHooks2;
@@ -211,6 +224,7 @@ var Keyv = class extends event_manager_default {
211
224
  _deserialize = defaultDeserialize;
212
225
  _compression;
213
226
  _useKeyPrefix = true;
227
+ _throwOnErrors = false;
214
228
  /**
215
229
  * Keyv Constructor
216
230
  * @param {KeyvStoreAdapter | KeyvOptions} store
@@ -267,6 +281,9 @@ var Keyv = class extends event_manager_default {
267
281
  if (this.opts.useKeyPrefix !== void 0) {
268
282
  this._useKeyPrefix = this.opts.useKeyPrefix;
269
283
  }
284
+ if (this.opts.throwOnErrors !== void 0) {
285
+ this._throwOnErrors = this.opts.throwOnErrors;
286
+ }
270
287
  }
271
288
  /**
272
289
  * Get the current store
@@ -391,6 +408,21 @@ var Keyv = class extends event_manager_default {
391
408
  this._useKeyPrefix = value;
392
409
  this.opts.useKeyPrefix = value;
393
410
  }
411
+ /**
412
+ * Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
413
+ * @return {boolean} The current throwOnErrors value.
414
+ */
415
+ get throwOnErrors() {
416
+ return this._throwOnErrors;
417
+ }
418
+ /**
419
+ * Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
420
+ * @param {boolean} value The throwOnErrors value to set.
421
+ */
422
+ set throwOnErrors(value) {
423
+ this._throwOnErrors = value;
424
+ this.opts.throwOnErrors = value;
425
+ }
394
426
  generateIterator(iterator) {
395
427
  const function_ = async function* () {
396
428
  for await (const [key, raw] of typeof iterator === "function" ? iterator(this._store.namespace) : iterator) {
@@ -450,7 +482,14 @@ var Keyv = class extends event_manager_default {
450
482
  return this.getMany(key, { raw: false });
451
483
  }
452
484
  this.hooks.trigger("preGet" /* PRE_GET */, { key: keyPrefixed });
453
- const rawData = await store.get(keyPrefixed);
485
+ let rawData;
486
+ try {
487
+ rawData = await store.get(keyPrefixed);
488
+ } catch (error) {
489
+ if (this.throwOnErrors) {
490
+ throw error;
491
+ }
492
+ }
454
493
  const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
455
494
  if (deserializedData === void 0 || deserializedData === null) {
456
495
  this.stats.miss();
@@ -493,6 +532,7 @@ var Keyv = class extends event_manager_default {
493
532
  }
494
533
  const rawData = await store.getMany(keyPrefixed);
495
534
  const result = [];
535
+ const expiredKeys = [];
496
536
  for (const index in rawData) {
497
537
  let row = rawData[index];
498
538
  if (typeof row === "string") {
@@ -503,19 +543,96 @@ var Keyv = class extends event_manager_default {
503
543
  continue;
504
544
  }
505
545
  if (isDataExpired(row)) {
506
- await this.delete(keys[index]);
546
+ expiredKeys.push(keys[index]);
507
547
  result.push(void 0);
508
548
  continue;
509
549
  }
510
550
  const value = options?.raw ? row : row.value;
511
551
  result.push(value);
512
552
  }
553
+ if (expiredKeys.length > 0) {
554
+ await this.deleteMany(expiredKeys);
555
+ }
513
556
  this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result);
514
557
  if (result.length > 0) {
515
558
  this.stats.hit();
516
559
  }
517
560
  return result;
518
561
  }
562
+ /**
563
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
564
+ * @param {string} key the key to get
565
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
566
+ */
567
+ async getRaw(key) {
568
+ const { store } = this.opts;
569
+ const keyPrefixed = this._getKeyPrefix(key);
570
+ this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key: keyPrefixed });
571
+ const rawData = await store.get(keyPrefixed);
572
+ if (rawData === void 0 || rawData === null) {
573
+ this.stats.miss();
574
+ return void 0;
575
+ }
576
+ const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
577
+ if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && deserializedData.expires < Date.now()) {
578
+ this.stats.miss();
579
+ await this.delete(key);
580
+ return void 0;
581
+ }
582
+ this.stats.hit();
583
+ this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, { key: keyPrefixed, value: deserializedData });
584
+ return deserializedData;
585
+ }
586
+ /**
587
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
588
+ * @param {string[]} keys the keys to get
589
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
590
+ */
591
+ async getManyRaw(keys) {
592
+ const { store } = this.opts;
593
+ const keyPrefixed = this._getKeyPrefixArray(keys);
594
+ if (keys.length === 0) {
595
+ const result2 = Array.from({ length: keys.length }).fill(void 0);
596
+ this.stats.misses += keys.length;
597
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, { keys: keyPrefixed, values: result2 });
598
+ return result2;
599
+ }
600
+ let result = [];
601
+ if (store.getMany === void 0) {
602
+ const promises = keyPrefixed.map(async (key) => {
603
+ const rawData = await store.get(key);
604
+ if (rawData !== void 0 && rawData !== null) {
605
+ return this.deserializeData(rawData);
606
+ }
607
+ return void 0;
608
+ });
609
+ const deserializedRows = await Promise.allSettled(promises);
610
+ result = deserializedRows.map((row) => row.value);
611
+ } else {
612
+ const rawData = await store.getMany(keyPrefixed);
613
+ for (const row of rawData) {
614
+ if (row !== void 0 && row !== null) {
615
+ result.push(await this.deserializeData(row));
616
+ } else {
617
+ result.push(void 0);
618
+ }
619
+ }
620
+ }
621
+ const expiredKeys = [];
622
+ const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
623
+ for (const [index, row] of result.entries()) {
624
+ if (row !== void 0 && isDataExpired(row)) {
625
+ expiredKeys.push(keyPrefixed[index]);
626
+ result[index] = void 0;
627
+ }
628
+ }
629
+ if (expiredKeys.length > 0) {
630
+ await this.deleteMany(expiredKeys);
631
+ }
632
+ this.stats.hitsOrMisses(result);
633
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, { keys: keyPrefixed, values: result });
634
+ return result;
635
+ }
519
636
  /**
520
637
  * Set an item to the store
521
638
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
@@ -548,6 +665,9 @@ var Keyv = class extends event_manager_default {
548
665
  } catch (error) {
549
666
  result = false;
550
667
  this.emit("error", error);
668
+ if (this._throwOnErrors) {
669
+ throw error;
670
+ }
551
671
  }
552
672
  this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
553
673
  this.stats.set();
@@ -561,7 +681,14 @@ var Keyv = class extends event_manager_default {
561
681
  async setMany(entries) {
562
682
  let results = [];
563
683
  try {
564
- if (this._store.setMany !== void 0) {
684
+ if (this._store.setMany === void 0) {
685
+ const promises = [];
686
+ for (const entry of entries) {
687
+ promises.push(this.set(entry.key, entry.value, entry.ttl));
688
+ }
689
+ const promiseResults = await Promise.all(promises);
690
+ results = promiseResults;
691
+ } else {
565
692
  const serializedEntries = await Promise.all(entries.map(async ({ key, value, ttl }) => {
566
693
  ttl ??= this._ttl;
567
694
  if (ttl === 0) {
@@ -578,14 +705,11 @@ var Keyv = class extends event_manager_default {
578
705
  }));
579
706
  results = await this._store.setMany(serializedEntries);
580
707
  }
581
- const promises = [];
582
- for (const entry of entries) {
583
- promises.push(this.set(entry.key, entry.value, entry.ttl));
584
- }
585
- const promiseResults = await Promise.allSettled(promises);
586
- results = promiseResults.map((result) => result.value);
587
708
  } catch (error) {
588
709
  this.emit("error", error);
710
+ if (this._throwOnErrors) {
711
+ throw error;
712
+ }
589
713
  results = entries.map(() => false);
590
714
  }
591
715
  return results;
@@ -611,6 +735,9 @@ var Keyv = class extends event_manager_default {
611
735
  } catch (error) {
612
736
  result = false;
613
737
  this.emit("error", error);
738
+ if (this._throwOnErrors) {
739
+ throw error;
740
+ }
614
741
  }
615
742
  this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
616
743
  this.stats.delete();
@@ -630,12 +757,15 @@ var Keyv = class extends event_manager_default {
630
757
  return await store.deleteMany(keyPrefixed);
631
758
  }
632
759
  const promises = keyPrefixed.map(async (key) => store.delete(key));
633
- const results = await Promise.allSettled(promises);
634
- const returnResult = results.every((x) => x.value === true);
760
+ const results = await Promise.all(promises);
761
+ const returnResult = results.every(Boolean);
635
762
  this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
636
763
  return returnResult;
637
764
  } catch (error) {
638
765
  this.emit("error", error);
766
+ if (this._throwOnErrors) {
767
+ throw error;
768
+ }
639
769
  return false;
640
770
  }
641
771
  }
@@ -650,6 +780,9 @@ var Keyv = class extends event_manager_default {
650
780
  await store.clear();
651
781
  } catch (error) {
652
782
  this.emit("error", error);
783
+ if (this._throwOnErrors) {
784
+ throw error;
785
+ }
653
786
  }
654
787
  }
655
788
  async has(key) {
@@ -666,6 +799,10 @@ var Keyv = class extends event_manager_default {
666
799
  rawData = await store.get(keyPrefixed);
667
800
  } catch (error) {
668
801
  this.emit("error", error);
802
+ if (this._throwOnErrors) {
803
+ throw error;
804
+ }
805
+ return false;
669
806
  }
670
807
  if (rawData) {
671
808
  const data = await this.deserializeData(rawData);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keyv",
3
- "version": "5.3.4",
3
+ "version": "5.5.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.8.0",
61
- "@vitest/coverage-v8": "^3.2.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
64
  "tsd": "^0.32.0",
65
- "vitest": "^3.2.3",
66
- "xo": "^1.1.0",
67
- "@keyv/compress-brotli": "^2.0.4",
65
+ "vitest": "^3.2.4",
66
+ "xo": "^1.2.0",
67
+ "@keyv/compress-brotli": "^2.0.5",
68
68
  "@keyv/compress-gzip": "^2.0.3",
69
- "@keyv/sqlite": "^4.0.4",
70
- "@keyv/memcache": "^2.0.1",
71
- "@keyv/test-suite": "^2.0.7",
72
- "@keyv/mongo": "^3.0.2",
73
- "@keyv/compress-lz4": "^1.0.0"
69
+ "@keyv/memcache": "^2.0.2",
70
+ "@keyv/compress-lz4": "^1.0.1",
71
+ "@keyv/mongo": "^3.0.3",
72
+ "@keyv/sqlite": "^4.0.5",
73
+ "@keyv/test-suite": "^2.1.0"
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
  }