keyv 5.4.0 → 5.5.1

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,6 +49,8 @@ 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)
@@ -469,7 +471,7 @@ Returns a promise which resolves to the retrieved value.
469
471
 
470
472
  Returns a promise which resolves to an array of retrieved values.
471
473
 
472
- ### options.raw
474
+ ### options.raw - (Will be deprecated in v6)
473
475
 
474
476
  Type: `Boolean`<br />
475
477
  Default: `false`
@@ -478,6 +480,16 @@ If set to true the raw DB object Keyv stores internally will be returned instead
478
480
 
479
481
  This contains the TTL timestamp.
480
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
+
481
493
  ## .delete(key)
482
494
 
483
495
  Deletes an entry.
package/dist/index.cjs CHANGED
@@ -49,7 +49,9 @@ var EventManager = class {
49
49
  const listeners = this._eventListeners.get(event);
50
50
  if (listeners) {
51
51
  if (listeners.length >= this._maxListeners) {
52
- console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`);
52
+ console.warn(
53
+ `MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
54
+ );
53
55
  }
54
56
  listeners.push(listener);
55
57
  }
@@ -77,6 +79,7 @@ var EventManager = class {
77
79
  this.on(event, onceListener);
78
80
  }
79
81
  // Emit an event
82
+ // biome-ignore lint/suspicious/noExplicitAny: type format
80
83
  emit(event, ...arguments_) {
81
84
  const listeners = this._eventListeners.get(event);
82
85
  if (listeners && listeners.length > 0) {
@@ -131,6 +134,7 @@ var HooksManager = class extends event_manager_default {
131
134
  }
132
135
  }
133
136
  // Triggers all handlers for a specific event with provided data
137
+ // biome-ignore lint/suspicious/noExplicitAny: type format
134
138
  trigger(event, data) {
135
139
  const eventHandlers = this._hookHandlers.get(event);
136
140
  if (eventHandlers) {
@@ -138,7 +142,12 @@ var HooksManager = class extends event_manager_default {
138
142
  try {
139
143
  handler(data);
140
144
  } catch (error) {
141
- this.emit("error", new Error(`Error in hook handler for event "${event}": ${error.message}`));
145
+ this.emit(
146
+ "error",
147
+ new Error(
148
+ `Error in hook handler for event "${event}": ${error.message}`
149
+ )
150
+ );
142
151
  }
143
152
  }
144
153
  }
@@ -185,6 +194,15 @@ var StatsManager = class extends event_manager_default {
185
194
  this.deletes++;
186
195
  }
187
196
  }
197
+ hitsOrMisses(array) {
198
+ for (const item of array) {
199
+ if (item === void 0) {
200
+ this.miss();
201
+ } else {
202
+ this.hit();
203
+ }
204
+ }
205
+ }
188
206
  reset() {
189
207
  this.hits = 0;
190
208
  this.misses = 0;
@@ -203,6 +221,10 @@ var KeyvHooks = /* @__PURE__ */ ((KeyvHooks2) => {
203
221
  KeyvHooks2["POST_GET"] = "postGet";
204
222
  KeyvHooks2["PRE_GET_MANY"] = "preGetMany";
205
223
  KeyvHooks2["POST_GET_MANY"] = "postGetMany";
224
+ KeyvHooks2["PRE_GET_RAW"] = "preGetRaw";
225
+ KeyvHooks2["POST_GET_RAW"] = "postGetRaw";
226
+ KeyvHooks2["PRE_GET_MANY_RAW"] = "preGetManyRaw";
227
+ KeyvHooks2["POST_GET_MANY_RAW"] = "postGetManyRaw";
206
228
  KeyvHooks2["PRE_DELETE"] = "preDelete";
207
229
  KeyvHooks2["POST_DELETE"] = "postDelete";
208
230
  return KeyvHooks2;
@@ -232,6 +254,7 @@ var Keyv = class extends event_manager_default {
232
254
  /**
233
255
  * Store
234
256
  */
257
+ // biome-ignore lint/suspicious/noExplicitAny: type format
235
258
  _store = /* @__PURE__ */ new Map();
236
259
  _serialize = import_serialize.defaultSerialize;
237
260
  _deserialize = import_serialize.defaultDeserialize;
@@ -280,9 +303,14 @@ var Keyv = class extends event_manager_default {
280
303
  }
281
304
  this._store.namespace = this._namespace;
282
305
  if (typeof this._store[Symbol.iterator] === "function" && this._store instanceof Map) {
283
- this.iterator = this.generateIterator(this._store);
306
+ this.iterator = this.generateIterator(
307
+ this._store
308
+ );
284
309
  } else if ("iterator" in this._store && this._store.opts && this._checkIterableAdapter()) {
285
- this.iterator = this.generateIterator(this._store.iterator.bind(this._store));
310
+ this.iterator = this.generateIterator(
311
+ // biome-ignore lint/style/noNonNullAssertion: need to fix
312
+ this._store.iterator.bind(this._store)
313
+ );
286
314
  }
287
315
  }
288
316
  if (this.opts.stats) {
@@ -301,6 +329,7 @@ var Keyv = class extends event_manager_default {
301
329
  /**
302
330
  * Get the current store
303
331
  */
332
+ // biome-ignore lint/suspicious/noExplicitAny: type format
304
333
  get store() {
305
334
  return this._store;
306
335
  }
@@ -308,6 +337,7 @@ var Keyv = class extends event_manager_default {
308
337
  * Set the current store. This will also set the namespace, event error handler, and generate the iterator. If the store is not valid it will throw an error.
309
338
  * @param {KeyvStoreAdapter | Map<any, any> | any} store the store to set
310
339
  */
340
+ // biome-ignore lint/suspicious/noExplicitAny: type format
311
341
  set store(store) {
312
342
  if (this._isValidStorageAdapter(store)) {
313
343
  this._store = store;
@@ -319,9 +349,11 @@ var Keyv = class extends event_manager_default {
319
349
  this._store.namespace = this._namespace;
320
350
  }
321
351
  if (typeof store[Symbol.iterator] === "function" && store instanceof Map) {
322
- this.iterator = this.generateIterator(store);
352
+ this.iterator = this.generateIterator(
353
+ store
354
+ );
323
355
  } else if ("iterator" in store && store.opts && this._checkIterableAdapter()) {
324
- this.iterator = this.generateIterator(store.iterator.bind(store));
356
+ this.iterator = this.generateIterator(store.iterator?.bind(store));
325
357
  }
326
358
  } else {
327
359
  throw new Error("Invalid storage adapter");
@@ -453,7 +485,9 @@ var Keyv = class extends event_manager_default {
453
485
  return function_.bind(this);
454
486
  }
455
487
  _checkIterableAdapter() {
456
- return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some((element) => this._store.opts.url.includes(element));
488
+ return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some(
489
+ (element) => this._store.opts.url.includes(element)
490
+ );
457
491
  }
458
492
  _getKeyPrefix(key) {
459
493
  if (!this._useKeyPrefix) {
@@ -479,6 +513,7 @@ var Keyv = class extends event_manager_default {
479
513
  }
480
514
  return key.split(":").splice(1).join(":");
481
515
  }
516
+ // biome-ignore lint/suspicious/noExplicitAny: type format
482
517
  _isValidStorageAdapter(store) {
483
518
  return store instanceof Map || typeof store.get === "function" && typeof store.set === "function" && typeof store.delete === "function" && typeof store.clear === "function";
484
519
  }
@@ -513,7 +548,10 @@ var Keyv = class extends event_manager_default {
513
548
  this.stats.miss();
514
549
  return void 0;
515
550
  }
516
- this.hooks.trigger("postGet" /* POST_GET */, { key: keyPrefixed, value: deserializedData });
551
+ this.hooks.trigger("postGet" /* POST_GET */, {
552
+ key: keyPrefixed,
553
+ value: deserializedData
554
+ });
517
555
  this.stats.hit();
518
556
  return options?.raw ? deserializedData : deserializedData.value;
519
557
  }
@@ -536,7 +574,10 @@ var Keyv = class extends event_manager_default {
536
574
  return options?.raw ? deserializedRow : deserializedRow.value;
537
575
  });
538
576
  const deserializedRows = await Promise.allSettled(promises);
539
- const result2 = deserializedRows.map((row) => row.value);
577
+ const result2 = deserializedRows.map(
578
+ // biome-ignore lint/suspicious/noExplicitAny: type format
579
+ (row) => row.value
580
+ );
540
581
  this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result2);
541
582
  if (result2.length > 0) {
542
583
  this.stats.hit();
@@ -572,6 +613,95 @@ var Keyv = class extends event_manager_default {
572
613
  }
573
614
  return result;
574
615
  }
616
+ /**
617
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
618
+ * @param {string} key the key to get
619
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
620
+ */
621
+ async getRaw(key) {
622
+ const { store } = this.opts;
623
+ const keyPrefixed = this._getKeyPrefix(key);
624
+ this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key: keyPrefixed });
625
+ const rawData = await store.get(keyPrefixed);
626
+ if (rawData === void 0 || rawData === null) {
627
+ this.stats.miss();
628
+ return void 0;
629
+ }
630
+ const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
631
+ if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && // biome-ignore lint/style/noNonNullAssertion: need to fix
632
+ deserializedData.expires < Date.now()) {
633
+ this.stats.miss();
634
+ await this.delete(key);
635
+ return void 0;
636
+ }
637
+ this.stats.hit();
638
+ this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, {
639
+ key: keyPrefixed,
640
+ value: deserializedData
641
+ });
642
+ return deserializedData;
643
+ }
644
+ /**
645
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
646
+ * @param {string[]} keys the keys to get
647
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
648
+ */
649
+ async getManyRaw(keys) {
650
+ const { store } = this.opts;
651
+ const keyPrefixed = this._getKeyPrefixArray(keys);
652
+ if (keys.length === 0) {
653
+ const result2 = Array.from({ length: keys.length }).fill(
654
+ void 0
655
+ );
656
+ this.stats.misses += keys.length;
657
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
658
+ keys: keyPrefixed,
659
+ values: result2
660
+ });
661
+ return result2;
662
+ }
663
+ let result = [];
664
+ if (store.getMany === void 0) {
665
+ const promises = keyPrefixed.map(async (key) => {
666
+ const rawData = await store.get(key);
667
+ if (rawData !== void 0 && rawData !== null) {
668
+ return this.deserializeData(rawData);
669
+ }
670
+ return void 0;
671
+ });
672
+ const deserializedRows = await Promise.allSettled(promises);
673
+ result = deserializedRows.map(
674
+ // biome-ignore lint/suspicious/noExplicitAny: type format
675
+ (row) => row.value
676
+ );
677
+ } else {
678
+ const rawData = await store.getMany(keyPrefixed);
679
+ for (const row of rawData) {
680
+ if (row !== void 0 && row !== null) {
681
+ result.push(await this.deserializeData(row));
682
+ } else {
683
+ result.push(void 0);
684
+ }
685
+ }
686
+ }
687
+ const expiredKeys = [];
688
+ const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
689
+ for (const [index, row] of result.entries()) {
690
+ if (row !== void 0 && isDataExpired(row)) {
691
+ expiredKeys.push(keyPrefixed[index]);
692
+ result[index] = void 0;
693
+ }
694
+ }
695
+ if (expiredKeys.length > 0) {
696
+ await this.deleteMany(expiredKeys);
697
+ }
698
+ this.stats.hitsOrMisses(result);
699
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
700
+ keys: keyPrefixed,
701
+ values: result
702
+ });
703
+ return result;
704
+ }
575
705
  /**
576
706
  * Set an item to the store
577
707
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
@@ -608,7 +738,11 @@ var Keyv = class extends event_manager_default {
608
738
  throw error;
609
739
  }
610
740
  }
611
- this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
741
+ this.hooks.trigger("postSet" /* POST_SET */, {
742
+ key: keyPrefixed,
743
+ value: serializedValue,
744
+ ttl
745
+ });
612
746
  this.stats.set();
613
747
  return result;
614
748
  }
@@ -617,6 +751,7 @@ var Keyv = class extends event_manager_default {
617
751
  * @param {Array<KeyvEntry>} entries the entries to set
618
752
  * @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
619
753
  */
754
+ // biome-ignore lint/correctness/noUnusedVariables: type format
620
755
  async setMany(entries) {
621
756
  let results = [];
622
757
  try {
@@ -628,20 +763,22 @@ var Keyv = class extends event_manager_default {
628
763
  const promiseResults = await Promise.all(promises);
629
764
  results = promiseResults;
630
765
  } 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
- }));
766
+ const serializedEntries = await Promise.all(
767
+ entries.map(async ({ key, value, ttl }) => {
768
+ ttl ??= this._ttl;
769
+ if (ttl === 0) {
770
+ ttl = void 0;
771
+ }
772
+ const expires = typeof ttl === "number" ? Date.now() + ttl : void 0;
773
+ if (typeof value === "symbol") {
774
+ this.emit("error", "symbol cannot be serialized");
775
+ throw new Error("symbol cannot be serialized");
776
+ }
777
+ const formattedValue = { value, expires };
778
+ const serializedValue = await this.serializeData(formattedValue);
779
+ return { key, value: serializedValue, ttl };
780
+ })
781
+ );
645
782
  results = await this._store.setMany(serializedEntries);
646
783
  }
647
784
  } catch (error) {
@@ -678,7 +815,10 @@ var Keyv = class extends event_manager_default {
678
815
  throw error;
679
816
  }
680
817
  }
681
- this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
818
+ this.hooks.trigger("postDelete" /* POST_DELETE */, {
819
+ key: keyPrefixed,
820
+ value: result
821
+ });
682
822
  this.stats.delete();
683
823
  return result;
684
824
  }
@@ -698,7 +838,10 @@ var Keyv = class extends event_manager_default {
698
838
  const promises = keyPrefixed.map(async (key) => store.delete(key));
699
839
  const results = await Promise.all(promises);
700
840
  const returnResult = results.every(Boolean);
701
- this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
841
+ this.hooks.trigger("postDelete" /* POST_DELETE */, {
842
+ key: keyPrefixed,
843
+ value: returnResult
844
+ });
702
845
  return returnResult;
703
846
  } catch (error) {
704
847
  this.emit("error", error);
@@ -782,6 +925,7 @@ var Keyv = class extends event_manager_default {
782
925
  return store.disconnect();
783
926
  }
784
927
  }
928
+ // biome-ignore lint/suspicious/noExplicitAny: type format
785
929
  emit(event, ...arguments_) {
786
930
  if (event === "error" && !this.opts.emitErrors) {
787
931
  return;
@@ -793,7 +937,10 @@ var Keyv = class extends event_manager_default {
793
937
  return data;
794
938
  }
795
939
  if (this._compression?.compress) {
796
- return this._serialize({ value: await this._compression.compress(data.value), expires: data.expires });
940
+ return this._serialize({
941
+ value: await this._compression.compress(data.value),
942
+ expires: data.expires
943
+ });
797
944
  }
798
945
  return this._serialize(data);
799
946
  }
@@ -803,7 +950,10 @@ var Keyv = class extends event_manager_default {
803
950
  }
804
951
  if (this._compression?.decompress && typeof data === "string") {
805
952
  const result = await this._deserialize(data);
806
- return { value: await this._compression.decompress(result?.value), expires: result?.expires };
953
+ return {
954
+ value: await this._compression.decompress(result?.value),
955
+ expires: result?.expires
956
+ };
807
957
  }
808
958
  if (typeof data === "string") {
809
959
  return this._deserialize(data);
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
  }
@@ -105,12 +110,12 @@ type KeyvOptions = {
105
110
  /**
106
111
  * Emit errors
107
112
  * @default true
108
- */
113
+ */
109
114
  emitErrors?: boolean;
110
115
  /**
111
116
  * Namespace for the current instance.
112
117
  * @default 'keyv'
113
- */
118
+ */
114
119
  namespace?: string;
115
120
  /**
116
121
  * A custom serialization function.
@@ -120,7 +125,7 @@ type KeyvOptions = {
120
125
  /**
121
126
  * A custom deserialization function.
122
127
  * @default defaultDeserialize using JSON.parse
123
- */
128
+ */
124
129
  deserialize?: Deserialize;
125
130
  /**
126
131
  * The storage adapter instance to be used by Keyv.
@@ -153,8 +158,8 @@ type KeyvOptions = {
153
158
  */
154
159
  throwOnErrors?: boolean;
155
160
  };
156
- type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
157
- store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
161
+ type KeyvOptions_ = Omit<KeyvOptions, "store"> & {
162
+ store: KeyvStoreAdapter | (Map<any, any> & KeyvStoreAdapter);
158
163
  };
159
164
  type IteratorFunction = (argument: any) => AsyncGenerator<any, void>;
160
165
  declare class Keyv<GenericValue = any> extends EventManager {
@@ -184,7 +189,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
184
189
  * @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
185
190
  * @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
186
191
  */
187
- constructor(store?: KeyvStoreAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, 'store'>);
192
+ constructor(store?: KeyvStoreAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, "store">);
188
193
  /**
189
194
  * Keyv Constructor
190
195
  * @param {KeyvOptions} options to be provided
@@ -304,6 +309,18 @@ declare class Keyv<GenericValue = any> extends EventManager {
304
309
  getMany<Value = GenericValue>(keys: string[], options?: {
305
310
  raw: true;
306
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>>>;
307
324
  /**
308
325
  * Set an item to the store
309
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
  }
@@ -105,12 +110,12 @@ type KeyvOptions = {
105
110
  /**
106
111
  * Emit errors
107
112
  * @default true
108
- */
113
+ */
109
114
  emitErrors?: boolean;
110
115
  /**
111
116
  * Namespace for the current instance.
112
117
  * @default 'keyv'
113
- */
118
+ */
114
119
  namespace?: string;
115
120
  /**
116
121
  * A custom serialization function.
@@ -120,7 +125,7 @@ type KeyvOptions = {
120
125
  /**
121
126
  * A custom deserialization function.
122
127
  * @default defaultDeserialize using JSON.parse
123
- */
128
+ */
124
129
  deserialize?: Deserialize;
125
130
  /**
126
131
  * The storage adapter instance to be used by Keyv.
@@ -153,8 +158,8 @@ type KeyvOptions = {
153
158
  */
154
159
  throwOnErrors?: boolean;
155
160
  };
156
- type KeyvOptions_ = Omit<KeyvOptions, 'store'> & {
157
- store: KeyvStoreAdapter | Map<any, any> & KeyvStoreAdapter;
161
+ type KeyvOptions_ = Omit<KeyvOptions, "store"> & {
162
+ store: KeyvStoreAdapter | (Map<any, any> & KeyvStoreAdapter);
158
163
  };
159
164
  type IteratorFunction = (argument: any) => AsyncGenerator<any, void>;
160
165
  declare class Keyv<GenericValue = any> extends EventManager {
@@ -184,7 +189,7 @@ declare class Keyv<GenericValue = any> extends EventManager {
184
189
  * @param {KeyvStoreAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
185
190
  * @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
186
191
  */
187
- constructor(store?: KeyvStoreAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, 'store'>);
192
+ constructor(store?: KeyvStoreAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, "store">);
188
193
  /**
189
194
  * Keyv Constructor
190
195
  * @param {KeyvOptions} options to be provided
@@ -304,6 +309,18 @@ declare class Keyv<GenericValue = any> extends EventManager {
304
309
  getMany<Value = GenericValue>(keys: string[], options?: {
305
310
  raw: true;
306
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>>>;
307
324
  /**
308
325
  * Set an item to the store
309
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
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { defaultSerialize, defaultDeserialize } from "@keyv/serialize";
2
+ import { defaultDeserialize, defaultSerialize } from "@keyv/serialize";
3
3
 
4
4
  // src/event-manager.ts
5
5
  var EventManager = class {
@@ -23,7 +23,9 @@ var EventManager = class {
23
23
  const listeners = this._eventListeners.get(event);
24
24
  if (listeners) {
25
25
  if (listeners.length >= this._maxListeners) {
26
- console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`);
26
+ console.warn(
27
+ `MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
28
+ );
27
29
  }
28
30
  listeners.push(listener);
29
31
  }
@@ -51,6 +53,7 @@ var EventManager = class {
51
53
  this.on(event, onceListener);
52
54
  }
53
55
  // Emit an event
56
+ // biome-ignore lint/suspicious/noExplicitAny: type format
54
57
  emit(event, ...arguments_) {
55
58
  const listeners = this._eventListeners.get(event);
56
59
  if (listeners && listeners.length > 0) {
@@ -105,6 +108,7 @@ var HooksManager = class extends event_manager_default {
105
108
  }
106
109
  }
107
110
  // Triggers all handlers for a specific event with provided data
111
+ // biome-ignore lint/suspicious/noExplicitAny: type format
108
112
  trigger(event, data) {
109
113
  const eventHandlers = this._hookHandlers.get(event);
110
114
  if (eventHandlers) {
@@ -112,7 +116,12 @@ var HooksManager = class extends event_manager_default {
112
116
  try {
113
117
  handler(data);
114
118
  } catch (error) {
115
- this.emit("error", new Error(`Error in hook handler for event "${event}": ${error.message}`));
119
+ this.emit(
120
+ "error",
121
+ new Error(
122
+ `Error in hook handler for event "${event}": ${error.message}`
123
+ )
124
+ );
116
125
  }
117
126
  }
118
127
  }
@@ -159,6 +168,15 @@ var StatsManager = class extends event_manager_default {
159
168
  this.deletes++;
160
169
  }
161
170
  }
171
+ hitsOrMisses(array) {
172
+ for (const item of array) {
173
+ if (item === void 0) {
174
+ this.miss();
175
+ } else {
176
+ this.hit();
177
+ }
178
+ }
179
+ }
162
180
  reset() {
163
181
  this.hits = 0;
164
182
  this.misses = 0;
@@ -177,6 +195,10 @@ var KeyvHooks = /* @__PURE__ */ ((KeyvHooks2) => {
177
195
  KeyvHooks2["POST_GET"] = "postGet";
178
196
  KeyvHooks2["PRE_GET_MANY"] = "preGetMany";
179
197
  KeyvHooks2["POST_GET_MANY"] = "postGetMany";
198
+ KeyvHooks2["PRE_GET_RAW"] = "preGetRaw";
199
+ KeyvHooks2["POST_GET_RAW"] = "postGetRaw";
200
+ KeyvHooks2["PRE_GET_MANY_RAW"] = "preGetManyRaw";
201
+ KeyvHooks2["POST_GET_MANY_RAW"] = "postGetManyRaw";
180
202
  KeyvHooks2["PRE_DELETE"] = "preDelete";
181
203
  KeyvHooks2["POST_DELETE"] = "postDelete";
182
204
  return KeyvHooks2;
@@ -206,6 +228,7 @@ var Keyv = class extends event_manager_default {
206
228
  /**
207
229
  * Store
208
230
  */
231
+ // biome-ignore lint/suspicious/noExplicitAny: type format
209
232
  _store = /* @__PURE__ */ new Map();
210
233
  _serialize = defaultSerialize;
211
234
  _deserialize = defaultDeserialize;
@@ -254,9 +277,14 @@ var Keyv = class extends event_manager_default {
254
277
  }
255
278
  this._store.namespace = this._namespace;
256
279
  if (typeof this._store[Symbol.iterator] === "function" && this._store instanceof Map) {
257
- this.iterator = this.generateIterator(this._store);
280
+ this.iterator = this.generateIterator(
281
+ this._store
282
+ );
258
283
  } else if ("iterator" in this._store && this._store.opts && this._checkIterableAdapter()) {
259
- this.iterator = this.generateIterator(this._store.iterator.bind(this._store));
284
+ this.iterator = this.generateIterator(
285
+ // biome-ignore lint/style/noNonNullAssertion: need to fix
286
+ this._store.iterator.bind(this._store)
287
+ );
260
288
  }
261
289
  }
262
290
  if (this.opts.stats) {
@@ -275,6 +303,7 @@ var Keyv = class extends event_manager_default {
275
303
  /**
276
304
  * Get the current store
277
305
  */
306
+ // biome-ignore lint/suspicious/noExplicitAny: type format
278
307
  get store() {
279
308
  return this._store;
280
309
  }
@@ -282,6 +311,7 @@ var Keyv = class extends event_manager_default {
282
311
  * Set the current store. This will also set the namespace, event error handler, and generate the iterator. If the store is not valid it will throw an error.
283
312
  * @param {KeyvStoreAdapter | Map<any, any> | any} store the store to set
284
313
  */
314
+ // biome-ignore lint/suspicious/noExplicitAny: type format
285
315
  set store(store) {
286
316
  if (this._isValidStorageAdapter(store)) {
287
317
  this._store = store;
@@ -293,9 +323,11 @@ var Keyv = class extends event_manager_default {
293
323
  this._store.namespace = this._namespace;
294
324
  }
295
325
  if (typeof store[Symbol.iterator] === "function" && store instanceof Map) {
296
- this.iterator = this.generateIterator(store);
326
+ this.iterator = this.generateIterator(
327
+ store
328
+ );
297
329
  } else if ("iterator" in store && store.opts && this._checkIterableAdapter()) {
298
- this.iterator = this.generateIterator(store.iterator.bind(store));
330
+ this.iterator = this.generateIterator(store.iterator?.bind(store));
299
331
  }
300
332
  } else {
301
333
  throw new Error("Invalid storage adapter");
@@ -427,7 +459,9 @@ var Keyv = class extends event_manager_default {
427
459
  return function_.bind(this);
428
460
  }
429
461
  _checkIterableAdapter() {
430
- return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some((element) => this._store.opts.url.includes(element));
462
+ return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some(
463
+ (element) => this._store.opts.url.includes(element)
464
+ );
431
465
  }
432
466
  _getKeyPrefix(key) {
433
467
  if (!this._useKeyPrefix) {
@@ -453,6 +487,7 @@ var Keyv = class extends event_manager_default {
453
487
  }
454
488
  return key.split(":").splice(1).join(":");
455
489
  }
490
+ // biome-ignore lint/suspicious/noExplicitAny: type format
456
491
  _isValidStorageAdapter(store) {
457
492
  return store instanceof Map || typeof store.get === "function" && typeof store.set === "function" && typeof store.delete === "function" && typeof store.clear === "function";
458
493
  }
@@ -487,7 +522,10 @@ var Keyv = class extends event_manager_default {
487
522
  this.stats.miss();
488
523
  return void 0;
489
524
  }
490
- this.hooks.trigger("postGet" /* POST_GET */, { key: keyPrefixed, value: deserializedData });
525
+ this.hooks.trigger("postGet" /* POST_GET */, {
526
+ key: keyPrefixed,
527
+ value: deserializedData
528
+ });
491
529
  this.stats.hit();
492
530
  return options?.raw ? deserializedData : deserializedData.value;
493
531
  }
@@ -510,7 +548,10 @@ var Keyv = class extends event_manager_default {
510
548
  return options?.raw ? deserializedRow : deserializedRow.value;
511
549
  });
512
550
  const deserializedRows = await Promise.allSettled(promises);
513
- const result2 = deserializedRows.map((row) => row.value);
551
+ const result2 = deserializedRows.map(
552
+ // biome-ignore lint/suspicious/noExplicitAny: type format
553
+ (row) => row.value
554
+ );
514
555
  this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result2);
515
556
  if (result2.length > 0) {
516
557
  this.stats.hit();
@@ -546,6 +587,95 @@ var Keyv = class extends event_manager_default {
546
587
  }
547
588
  return result;
548
589
  }
590
+ /**
591
+ * Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
592
+ * @param {string} key the key to get
593
+ * @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
594
+ */
595
+ async getRaw(key) {
596
+ const { store } = this.opts;
597
+ const keyPrefixed = this._getKeyPrefix(key);
598
+ this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key: keyPrefixed });
599
+ const rawData = await store.get(keyPrefixed);
600
+ if (rawData === void 0 || rawData === null) {
601
+ this.stats.miss();
602
+ return void 0;
603
+ }
604
+ const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
605
+ if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && // biome-ignore lint/style/noNonNullAssertion: need to fix
606
+ deserializedData.expires < Date.now()) {
607
+ this.stats.miss();
608
+ await this.delete(key);
609
+ return void 0;
610
+ }
611
+ this.stats.hit();
612
+ this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, {
613
+ key: keyPrefixed,
614
+ value: deserializedData
615
+ });
616
+ return deserializedData;
617
+ }
618
+ /**
619
+ * Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
620
+ * @param {string[]} keys the keys to get
621
+ * @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
622
+ */
623
+ async getManyRaw(keys) {
624
+ const { store } = this.opts;
625
+ const keyPrefixed = this._getKeyPrefixArray(keys);
626
+ if (keys.length === 0) {
627
+ const result2 = Array.from({ length: keys.length }).fill(
628
+ void 0
629
+ );
630
+ this.stats.misses += keys.length;
631
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
632
+ keys: keyPrefixed,
633
+ values: result2
634
+ });
635
+ return result2;
636
+ }
637
+ let result = [];
638
+ if (store.getMany === void 0) {
639
+ const promises = keyPrefixed.map(async (key) => {
640
+ const rawData = await store.get(key);
641
+ if (rawData !== void 0 && rawData !== null) {
642
+ return this.deserializeData(rawData);
643
+ }
644
+ return void 0;
645
+ });
646
+ const deserializedRows = await Promise.allSettled(promises);
647
+ result = deserializedRows.map(
648
+ // biome-ignore lint/suspicious/noExplicitAny: type format
649
+ (row) => row.value
650
+ );
651
+ } else {
652
+ const rawData = await store.getMany(keyPrefixed);
653
+ for (const row of rawData) {
654
+ if (row !== void 0 && row !== null) {
655
+ result.push(await this.deserializeData(row));
656
+ } else {
657
+ result.push(void 0);
658
+ }
659
+ }
660
+ }
661
+ const expiredKeys = [];
662
+ const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
663
+ for (const [index, row] of result.entries()) {
664
+ if (row !== void 0 && isDataExpired(row)) {
665
+ expiredKeys.push(keyPrefixed[index]);
666
+ result[index] = void 0;
667
+ }
668
+ }
669
+ if (expiredKeys.length > 0) {
670
+ await this.deleteMany(expiredKeys);
671
+ }
672
+ this.stats.hitsOrMisses(result);
673
+ this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
674
+ keys: keyPrefixed,
675
+ values: result
676
+ });
677
+ return result;
678
+ }
549
679
  /**
550
680
  * Set an item to the store
551
681
  * @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
@@ -582,7 +712,11 @@ var Keyv = class extends event_manager_default {
582
712
  throw error;
583
713
  }
584
714
  }
585
- this.hooks.trigger("postSet" /* POST_SET */, { key: keyPrefixed, value: serializedValue, ttl });
715
+ this.hooks.trigger("postSet" /* POST_SET */, {
716
+ key: keyPrefixed,
717
+ value: serializedValue,
718
+ ttl
719
+ });
586
720
  this.stats.set();
587
721
  return result;
588
722
  }
@@ -591,6 +725,7 @@ var Keyv = class extends event_manager_default {
591
725
  * @param {Array<KeyvEntry>} entries the entries to set
592
726
  * @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
593
727
  */
728
+ // biome-ignore lint/correctness/noUnusedVariables: type format
594
729
  async setMany(entries) {
595
730
  let results = [];
596
731
  try {
@@ -602,20 +737,22 @@ var Keyv = class extends event_manager_default {
602
737
  const promiseResults = await Promise.all(promises);
603
738
  results = promiseResults;
604
739
  } 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
- }));
740
+ const serializedEntries = await Promise.all(
741
+ entries.map(async ({ key, value, ttl }) => {
742
+ ttl ??= this._ttl;
743
+ if (ttl === 0) {
744
+ ttl = void 0;
745
+ }
746
+ const expires = typeof ttl === "number" ? Date.now() + ttl : void 0;
747
+ if (typeof value === "symbol") {
748
+ this.emit("error", "symbol cannot be serialized");
749
+ throw new Error("symbol cannot be serialized");
750
+ }
751
+ const formattedValue = { value, expires };
752
+ const serializedValue = await this.serializeData(formattedValue);
753
+ return { key, value: serializedValue, ttl };
754
+ })
755
+ );
619
756
  results = await this._store.setMany(serializedEntries);
620
757
  }
621
758
  } catch (error) {
@@ -652,7 +789,10 @@ var Keyv = class extends event_manager_default {
652
789
  throw error;
653
790
  }
654
791
  }
655
- this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: result });
792
+ this.hooks.trigger("postDelete" /* POST_DELETE */, {
793
+ key: keyPrefixed,
794
+ value: result
795
+ });
656
796
  this.stats.delete();
657
797
  return result;
658
798
  }
@@ -672,7 +812,10 @@ var Keyv = class extends event_manager_default {
672
812
  const promises = keyPrefixed.map(async (key) => store.delete(key));
673
813
  const results = await Promise.all(promises);
674
814
  const returnResult = results.every(Boolean);
675
- this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, value: returnResult });
815
+ this.hooks.trigger("postDelete" /* POST_DELETE */, {
816
+ key: keyPrefixed,
817
+ value: returnResult
818
+ });
676
819
  return returnResult;
677
820
  } catch (error) {
678
821
  this.emit("error", error);
@@ -756,6 +899,7 @@ var Keyv = class extends event_manager_default {
756
899
  return store.disconnect();
757
900
  }
758
901
  }
902
+ // biome-ignore lint/suspicious/noExplicitAny: type format
759
903
  emit(event, ...arguments_) {
760
904
  if (event === "error" && !this.opts.emitErrors) {
761
905
  return;
@@ -767,7 +911,10 @@ var Keyv = class extends event_manager_default {
767
911
  return data;
768
912
  }
769
913
  if (this._compression?.compress) {
770
- return this._serialize({ value: await this._compression.compress(data.value), expires: data.expires });
914
+ return this._serialize({
915
+ value: await this._compression.compress(data.value),
916
+ expires: data.expires
917
+ });
771
918
  }
772
919
  return this._serialize(data);
773
920
  }
@@ -777,7 +924,10 @@ var Keyv = class extends event_manager_default {
777
924
  }
778
925
  if (this._compression?.decompress && typeof data === "string") {
779
926
  const result = await this._deserialize(data);
780
- return { value: await this._compression.decompress(result?.value), expires: result?.expires };
927
+ return {
928
+ value: await this._compression.decompress(result?.value),
929
+ expires: result?.expires
930
+ };
781
931
  }
782
932
  if (typeof data === "string") {
783
933
  return this._deserialize(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keyv",
3
- "version": "5.4.0",
3
+ "version": "5.5.1",
4
4
  "description": "Simple key-value storage with support for multiple backends",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -12,16 +12,6 @@
12
12
  "import": "./dist/index.js"
13
13
  }
14
14
  },
15
- "xo": {
16
- "rules": {
17
- "@typescript-eslint/ban-ts-comment": "off",
18
- "@typescript-eslint/no-unsafe-call": "off",
19
- "@typescript-eslint/no-unsafe-return": "off",
20
- "@typescript-eslint/no-unsafe-assignment": "off",
21
- "@typescript-eslint/no-unsafe-argument": "off",
22
- "@typescript-eslint/no-confusing-void-expression": "off"
23
- }
24
- },
25
15
  "repository": {
26
16
  "type": "git",
27
17
  "url": "git+https://github.com/jaredwray/keyv.git"
@@ -54,23 +44,23 @@
54
44
  },
55
45
  "homepage": "https://github.com/jaredwray/keyv",
56
46
  "dependencies": {
57
- "@keyv/serialize": "^1.1.0"
47
+ "@keyv/serialize": "^1.1.1"
58
48
  },
59
49
  "devDependencies": {
60
- "@faker-js/faker": "^9.9.0",
50
+ "@biomejs/biome": "^2.2.3",
51
+ "@faker-js/faker": "^10.0.0",
61
52
  "@vitest/coverage-v8": "^3.2.4",
62
53
  "rimraf": "^6.0.1",
63
54
  "timekeeper": "^2.3.1",
64
- "tsd": "^0.32.0",
55
+ "tsd": "^0.33.0",
65
56
  "vitest": "^3.2.4",
66
- "xo": "^1.1.1",
67
- "@keyv/memcache": "^2.0.2",
68
- "@keyv/compress-gzip": "^2.0.3",
57
+ "@keyv/mongo": "^3.0.3",
69
58
  "@keyv/compress-lz4": "^1.0.1",
59
+ "@keyv/memcache": "^2.0.2",
60
+ "@keyv/sqlite": "^4.0.5",
61
+ "@keyv/test-suite": "^2.1.1",
70
62
  "@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"
63
+ "@keyv/compress-gzip": "^2.0.3"
74
64
  },
75
65
  "tsd": {
76
66
  "directory": "test"
@@ -81,8 +71,8 @@
81
71
  ],
82
72
  "scripts": {
83
73
  "build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
84
- "test": "xo --fix && vitest run --coverage",
85
- "test:ci": "xo && vitest --run --sequence.setupFiles=list --coverage",
74
+ "test": "biome check --write && vitest run --coverage",
75
+ "test:ci": "biome check && vitest --run --sequence.setupFiles=list --coverage",
86
76
  "clean": "rimraf ./node_modules ./coverage ./test/testdb.sqlite ./dist"
87
77
  }
88
78
  }