keyv 6.0.0-beta.1 → 6.0.0-beta.4

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/dist/index.mjs CHANGED
@@ -173,6 +173,26 @@ function detectKeyvStorage(obj) {
173
173
  };
174
174
  }
175
175
  /**
176
+ * Build the capability descriptor for a v6 storage adapter: the structurally detected
177
+ * methods plus `expires: true`, declaring that the adapter accepts an absolute `expires`
178
+ * timestamp on `set`/`setMany`. First-party adapters expose this from their `capabilities`
179
+ * getter so Keyv uses them directly instead of bridging.
180
+ * @param adapter - The storage adapter to describe (typically `this`).
181
+ * @returns A {@link KeyvStorageCapability} with `expires` set to `true`.
182
+ * @example
183
+ * ```typescript
184
+ * public get capabilities(): KeyvStorageCapability {
185
+ * return keyvStorageCapability(this);
186
+ * }
187
+ * ```
188
+ */
189
+ function keyvStorageCapability(adapter) {
190
+ return {
191
+ ...detectKeyvStorage(adapter),
192
+ expires: true
193
+ };
194
+ }
195
+ /**
176
196
  * Detect whether an object implements the Keyv compression adapter interface
177
197
  * @param obj - The object to check
178
198
  * @returns A {@link KeyvCompressionCapability} where `compatible` is `true` when both `compress` and `decompress` methods are present
@@ -402,26 +422,26 @@ async function deleteExpiredKeys(keys, data, keyv) {
402
422
  * Maps new hook names to their deprecated equivalents so both fire during migration.
403
423
  */
404
424
  const deprecatedHookAliases = new Map([
405
- [KeyvHooks.BEFORE_SET, KeyvHooks.PRE_SET],
406
- [KeyvHooks.AFTER_SET, KeyvHooks.POST_SET],
407
- [KeyvHooks.BEFORE_GET, KeyvHooks.PRE_GET],
408
- [KeyvHooks.AFTER_GET, KeyvHooks.POST_GET],
409
- [KeyvHooks.BEFORE_GET_MANY, KeyvHooks.PRE_GET_MANY],
410
- [KeyvHooks.AFTER_GET_MANY, KeyvHooks.POST_GET_MANY],
411
- [KeyvHooks.BEFORE_GET_RAW, KeyvHooks.PRE_GET_RAW],
412
- [KeyvHooks.AFTER_GET_RAW, KeyvHooks.POST_GET_RAW],
413
- [KeyvHooks.BEFORE_GET_MANY_RAW, KeyvHooks.PRE_GET_MANY_RAW],
414
- [KeyvHooks.AFTER_GET_MANY_RAW, KeyvHooks.POST_GET_MANY_RAW],
415
- [KeyvHooks.BEFORE_SET_RAW, KeyvHooks.PRE_SET_RAW],
416
- [KeyvHooks.AFTER_SET_RAW, KeyvHooks.POST_SET_RAW],
417
- [KeyvHooks.BEFORE_SET_MANY, KeyvHooks.PRE_SET_MANY],
418
- [KeyvHooks.AFTER_SET_MANY, KeyvHooks.POST_SET_MANY],
419
- [KeyvHooks.BEFORE_SET_MANY_RAW, KeyvHooks.PRE_SET_MANY_RAW],
420
- [KeyvHooks.AFTER_SET_MANY_RAW, KeyvHooks.POST_SET_MANY_RAW],
421
- [KeyvHooks.BEFORE_DELETE, KeyvHooks.PRE_DELETE],
422
- [KeyvHooks.AFTER_DELETE, KeyvHooks.POST_DELETE],
423
- [KeyvHooks.BEFORE_DELETE_MANY, KeyvHooks.PRE_DELETE_MANY],
424
- [KeyvHooks.AFTER_DELETE_MANY, KeyvHooks.POST_DELETE_MANY]
425
+ ["before:set", "preSet"],
426
+ ["after:set", "postSet"],
427
+ ["before:get", "preGet"],
428
+ ["after:get", "postGet"],
429
+ ["before:getMany", "preGetMany"],
430
+ ["after:getMany", "postGetMany"],
431
+ ["before:getRaw", "preGetRaw"],
432
+ ["after:getRaw", "postGetRaw"],
433
+ ["before:getManyRaw", "preGetManyRaw"],
434
+ ["after:getManyRaw", "postGetManyRaw"],
435
+ ["before:setRaw", "preSetRaw"],
436
+ ["after:setRaw", "postSetRaw"],
437
+ ["before:setMany", "preSetMany"],
438
+ ["after:setMany", "postSetMany"],
439
+ ["before:setManyRaw", "preSetManyRaw"],
440
+ ["after:setManyRaw", "postSetManyRaw"],
441
+ ["before:delete", "preDelete"],
442
+ ["after:delete", "postDelete"],
443
+ ["before:deleteMany", "preDeleteMany"],
444
+ ["after:deleteMany", "postDeleteMany"]
425
445
  ]);
426
446
  /**
427
447
  * Build the deprecated-hooks map used by Hookified to warn when old PRE_/POST_ hook names are registered.
@@ -475,6 +495,12 @@ var KeyvBridgeAdapter = class extends Hookified {
475
495
  _keySeparator = ":";
476
496
  _capabilities;
477
497
  /**
498
+ * Whether the wrapped store manages its own namespace (exposes a `namespace` property).
499
+ * When true the bridge propagates its namespace to the store and does not prefix keys,
500
+ * so the store's native, namespace-scoped operations (notably `clear()`) are used directly.
501
+ */
502
+ _storeHandlesNamespace;
503
+ /**
478
504
  * Creates a new KeyvBridgeAdapter instance.
479
505
  * @param store - The underlying promise-based store to bridge
480
506
  * @param options - Configuration options for the adapter
@@ -482,10 +508,12 @@ var KeyvBridgeAdapter = class extends Hookified {
482
508
  constructor(store, options) {
483
509
  super({ throwOnHookError: false });
484
510
  this._store = store;
511
+ this._capabilities = detectKeyvStorage(store);
512
+ this._storeHandlesNamespace = this._capabilities.store === "keyvStorage" && "namespace" in store;
485
513
  if (options?.keySeparator) this._keySeparator = options.keySeparator;
486
514
  if (options?.namespace) this._namespace = options.namespace;
487
- this._capabilities = detectKeyvStorage(store);
488
- if (typeof store.on === "function") store.on(KeyvEvents.ERROR, (error) => this.emit(KeyvEvents.ERROR, error));
515
+ if (this._storeHandlesNamespace) this._store.namespace = this._namespace;
516
+ if (typeof store.on === "function") store.on("error", (error) => this.emit("error", error));
489
517
  }
490
518
  /**
491
519
  * Gets the underlying store instance.
@@ -500,10 +528,15 @@ var KeyvBridgeAdapter = class extends Hookified {
500
528
  this._store = store;
501
529
  }
502
530
  /**
503
- * Gets the detected capabilities of the underlying store.
531
+ * Gets the capabilities of the underlying store, with `expires: true` to declare that
532
+ * the bridge accepts an absolute `expires` timestamp (which it converts to a ttl for the
533
+ * wrapped legacy store).
504
534
  */
505
535
  get capabilities() {
506
- return this._capabilities;
536
+ return {
537
+ ...this._capabilities,
538
+ expires: true
539
+ };
507
540
  }
508
541
  /**
509
542
  * Gets the current key separator used between namespace and key.
@@ -524,10 +557,12 @@ var KeyvBridgeAdapter = class extends Hookified {
524
557
  return this._namespace;
525
558
  }
526
559
  /**
527
- * Sets the namespace.
560
+ * Sets the namespace. When the wrapped store manages its own namespace, the value is
561
+ * propagated to it so its native scoped operations stay in sync.
528
562
  */
529
563
  set namespace(namespace) {
530
564
  this._namespace = namespace;
565
+ if (this._storeHandlesNamespace) this._store.namespace = namespace;
531
566
  }
532
567
  /**
533
568
  * Creates a prefixed key by combining the namespace and key with the separator.
@@ -536,6 +571,7 @@ var KeyvBridgeAdapter = class extends Hookified {
536
571
  * @returns The prefixed key if namespace is provided, otherwise the original key
537
572
  */
538
573
  getKeyPrefix(key, namespace) {
574
+ if (this._storeHandlesNamespace) return key;
539
575
  if (namespace) return `${namespace}${this._keySeparator}${key}`;
540
576
  return key;
541
577
  }
@@ -601,35 +637,49 @@ var KeyvBridgeAdapter = class extends Hookified {
601
637
  return values;
602
638
  }
603
639
  /**
604
- * Stores a value in the store with an optional TTL.
640
+ * Stores a value in the store with an optional absolute expiry.
641
+ * The wrapped store's `set(key, value, ttl?)` expects a relative duration, so the absolute
642
+ * `expires` is converted to a remaining ttl (`undefined` when already expired or absent).
643
+ * The value is passed through unchanged — the bridge does not wrap it in an envelope — so
644
+ * expiry is enforced by the wrapped legacy store's own ttl handling. (The read-side
645
+ * {@link isDataExpired} check only fires when a caller stores a raw `{ value, expires }`
646
+ * object directly; when Keyv core drives the bridge the value arrives already encoded.)
605
647
  * @param key - The key to store the value under
606
648
  * @param value - The value to store
607
- * @param ttl - Optional time-to-live in milliseconds
649
+ * @param expires - Optional absolute expiry as Unix ms since epoch
608
650
  * @returns Always returns true indicating success
609
651
  */
610
- async set(key, value, ttl) {
652
+ async set(key, value, expires) {
611
653
  const keyPrefix = this.getKeyPrefix(key, this._namespace);
612
- const result = await this._store.set(keyPrefix, value, ttl);
654
+ if (typeof expires === "number" && expires <= Date.now()) {
655
+ await this._store.delete(keyPrefix);
656
+ return true;
657
+ }
658
+ const result = await this._store.set(keyPrefix, value, ttlFromExpires(expires));
613
659
  if (typeof result === "boolean") return result;
614
660
  return true;
615
661
  }
616
662
  /**
617
663
  * Stores multiple entries in the store at once.
618
664
  * Delegates to the store's native setMany if available, otherwise loops over set.
619
- * @param entries - Array of entries containing key, value, and optional TTL
665
+ * @param entries - Array of entries containing key, value, and optional absolute `expires`
620
666
  */
621
667
  async setMany(entries) {
622
668
  if (this._capabilities.methods.setMany.exists) {
623
- const prefixedEntries = entries.map((entry) => ({
624
- ...entry,
625
- key: this.getKeyPrefix(entry.key, this._namespace)
626
- }));
627
- await this._store.setMany?.(prefixedEntries);
669
+ const now = Date.now();
670
+ const isExpired = (entry) => typeof entry.expires === "number" && entry.expires <= now;
671
+ const live = entries.filter((entry) => !isExpired(entry));
672
+ if (live.length > 0) await this._store.setMany?.(live.map((entry) => ({
673
+ key: this.getKeyPrefix(entry.key, this._namespace),
674
+ value: entry.value,
675
+ ttl: ttlFromExpires(entry.expires)
676
+ })));
677
+ for (const entry of entries) if (isExpired(entry)) await this._store.delete(this.getKeyPrefix(entry.key, this._namespace));
628
678
  return entries.map(() => true);
629
679
  }
630
680
  const results = [];
631
681
  for (const entry of entries) {
632
- await this.set(entry.key, entry.value, entry.ttl);
682
+ await this.set(entry.key, entry.value, entry.expires);
633
683
  results.push(true);
634
684
  }
635
685
  return results;
@@ -692,7 +742,7 @@ var KeyvBridgeAdapter = class extends Hookified {
692
742
  const result = await this._store.delete(keyPrefix);
693
743
  results.push(result);
694
744
  } catch (error) {
695
- this.emit(KeyvEvents.ERROR, error);
745
+ this.emit("error", error);
696
746
  results.push(false);
697
747
  }
698
748
  return results;
@@ -703,6 +753,10 @@ var KeyvBridgeAdapter = class extends Hookified {
703
753
  * entire store is cleared.
704
754
  */
705
755
  async clear() {
756
+ if (this._namespace && this._storeHandlesNamespace) {
757
+ await this._store.clear();
758
+ return;
759
+ }
706
760
  if (!this._namespace || !this._capabilities.methods.iterator.exists) {
707
761
  await this._store.clear();
708
762
  return;
@@ -724,7 +778,7 @@ var KeyvBridgeAdapter = class extends Hookified {
724
778
  async *iterator() {
725
779
  if (!this._capabilities.methods.iterator.exists) return;
726
780
  const namespace = this._namespace;
727
- const prefix = namespace ? `${namespace}${this._keySeparator}` : void 0;
781
+ const prefix = namespace && !this._storeHandlesNamespace ? `${namespace}${this._keySeparator}` : void 0;
728
782
  /* v8 ignore next -- @preserve */
729
783
  for await (const entry of this._store.iterator?.(this._namespace) ?? []) {
730
784
  const [key, data] = Array.isArray(entry) ? entry : [entry];
@@ -1164,6 +1218,29 @@ var KeyvStats = class {
1164
1218
  //#endregion
1165
1219
  //#region src/keyv.ts
1166
1220
  var Keyv = class Keyv extends Hookified {
1221
+ /**
1222
+ * Keyv Constructor
1223
+ * @param {KeyvStorageAdapter | KeyvOptions} store
1224
+ * @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
1225
+ */
1226
+ constructor(store, options) {
1227
+ const mergedOptions = Keyv.resolveOptions(store, options);
1228
+ super({
1229
+ throwOnHookError: false,
1230
+ throwOnEmptyListeners: true,
1231
+ throwOnEmitError: mergedOptions.throwOnErrors ?? false
1232
+ });
1233
+ this.deprecatedHooks = buildDeprecatedHooks();
1234
+ this._compression = mergedOptions.compression;
1235
+ this._encryption = mergedOptions.encryption;
1236
+ this.initSerialization(mergedOptions);
1237
+ this.initSanitize(mergedOptions);
1238
+ this.initNamespace(mergedOptions.namespace);
1239
+ this.initStats(mergedOptions);
1240
+ if (mergedOptions.store) this.setStore(mergedOptions.store);
1241
+ this.setTtl(mergedOptions.ttl);
1242
+ this._checkExpired = mergedOptions.checkExpired ?? false;
1243
+ }
1167
1244
  /**
1168
1245
  * Stats manager for tracking cache operation metrics (hits, misses, sets, deletes, errors).
1169
1246
  * @default this is disabled.
@@ -1203,29 +1280,6 @@ var Keyv = class Keyv extends Hookified {
1203
1280
  */
1204
1281
  _checkExpired = false;
1205
1282
  /**
1206
- * Keyv Constructor
1207
- * @param {KeyvStorageAdapter | KeyvOptions} store
1208
- * @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
1209
- */
1210
- constructor(store, options) {
1211
- const mergedOptions = Keyv.resolveOptions(store, options);
1212
- super({
1213
- throwOnHookError: false,
1214
- throwOnEmptyListeners: true,
1215
- throwOnEmitError: mergedOptions.throwOnErrors ?? false
1216
- });
1217
- this.deprecatedHooks = buildDeprecatedHooks();
1218
- this._compression = mergedOptions.compression;
1219
- this._encryption = mergedOptions.encryption;
1220
- this.initSerialization(mergedOptions);
1221
- this.initSanitize(mergedOptions);
1222
- this.initNamespace(mergedOptions.namespace);
1223
- this.initStats(mergedOptions);
1224
- if (mergedOptions.store) this.setStore(mergedOptions.store);
1225
- this.setTtl(mergedOptions.ttl);
1226
- this._checkExpired = mergedOptions.checkExpired ?? false;
1227
- }
1228
- /**
1229
1283
  * Get the current storage adapter.
1230
1284
  * @returns {KeyvStorageAdapter} The current storage adapter.
1231
1285
  */
@@ -1353,13 +1407,6 @@ var Keyv = class Keyv extends Hookified {
1353
1407
  return this._stats;
1354
1408
  }
1355
1409
  /**
1356
- * When true, Keyv checks expiry at its layer on get/getMany/has/hasMany.
1357
- * When false (default), trusts the storage adapter.
1358
- */
1359
- get checkExpired() {
1360
- return this._checkExpired;
1361
- }
1362
- /**
1363
1410
  * Set the stats. When setting a new instance it will unsubscribe the old listeners
1364
1411
  * and subscribe the new instance.
1365
1412
  * @param {KeyvStats} stats The stats instance to set.
@@ -1370,22 +1417,35 @@ var Keyv = class Keyv extends Hookified {
1370
1417
  this._stats.subscribe(this);
1371
1418
  }
1372
1419
  /**
1373
- * Resolves a store to a fully-compliant KeyvStorageAdapter using a 3-tier detection chain:
1374
- * 1. If the store already implements the full KeyvStorageAdapter interface, use it directly.
1375
- * 2. If the store is map-like (synchronous get/set/delete/has), wrap it in KeyvMemoryAdapter.
1376
- * 3. If the store has async get/set/delete/clear, wrap it in KeyvBridgeAdapter.
1377
- * 4. Otherwise, emit an error and fall back to a default in-memory KeyvMemoryAdapter.
1420
+ * Get whether Keyv checks expiry at its own layer on get/getMany/has/hasMany.
1421
+ * When false (default), it trusts the storage adapter to handle expiry.
1422
+ * @returns {boolean} `true` if Keyv checks expiry at its layer.
1423
+ */
1424
+ get checkExpired() {
1425
+ return this._checkExpired;
1426
+ }
1427
+ /**
1428
+ * Resolves a store to a fully-compliant KeyvStorageAdapter:
1429
+ * 1. If the store declares the v6 `capabilities.expires` contract, use it directly (this takes
1430
+ * precedence over structural detection, so a full adapter whose async methods aren't written
1431
+ * with the `async` keyword is not mis-bridged).
1432
+ * 2. If the store implements the full async storage interface (but doesn't declare `expires`),
1433
+ * treat it as a legacy relative-`ttl` adapter and wrap it in KeyvBridgeAdapter.
1434
+ * 3. If the store is map-like (synchronous get/set/delete/has), wrap it in KeyvMemoryAdapter.
1435
+ * 4. If the store has async get/set/delete/clear, wrap it in KeyvBridgeAdapter.
1436
+ * 5. Otherwise, emit an error and fall back to a default in-memory KeyvMemoryAdapter.
1378
1437
  *
1379
1438
  * NOTE: this is used for internal but provided public for custom adapter testing
1380
1439
  * @param {unknown} store The store to resolve.
1381
1440
  * @returns {KeyvStorageAdapter} A fully-compliant storage adapter.
1382
1441
  */
1383
1442
  resolveStore(store) {
1443
+ if (store?.capabilities?.expires === true) return store;
1384
1444
  const cap = detectKeyvStorage(store);
1385
- if (cap.store === "keyvStorage") return store;
1445
+ if (cap.store === "keyvStorage") return new KeyvBridgeAdapter(store);
1386
1446
  if (cap.store === "mapLike") return new KeyvMemoryAdapter(store);
1387
1447
  if (cap.store === "asyncMap") return new KeyvBridgeAdapter(store);
1388
- this.emit(KeyvEvents.ERROR, /* @__PURE__ */ new Error("Could not use the provided storage adapter, falling back to KeyvMemoryAdapter with Map"));
1448
+ this.emit("error", /* @__PURE__ */ new Error("Could not use the provided storage adapter, falling back to KeyvMemoryAdapter with Map"));
1389
1449
  return new KeyvMemoryAdapter(/* @__PURE__ */ new Map());
1390
1450
  }
1391
1451
  /**
@@ -1395,7 +1455,7 @@ var Keyv = class Keyv extends Hookified {
1395
1455
  */
1396
1456
  setStore(store) {
1397
1457
  this._store = this.resolveStore(store);
1398
- if (typeof this._store.on === "function") this._store.on(KeyvEvents.ERROR, (error) => this.emit(KeyvEvents.ERROR, error));
1458
+ if (typeof this._store.on === "function") this._store.on("error", (error) => this.emit("error", error));
1399
1459
  this._store.namespace = this._namespace;
1400
1460
  }
1401
1461
  /**
@@ -1413,40 +1473,54 @@ var Keyv = class Keyv extends Hookified {
1413
1473
  if (Array.isArray(key)) return this.getMany(key);
1414
1474
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
1415
1475
  if (key === "") return;
1416
- await this.hookWithDeprecated(KeyvHooks.BEFORE_GET, { key });
1476
+ await this.hookWithDeprecated("before:get", { key });
1417
1477
  let rawData;
1418
1478
  try {
1419
1479
  rawData = await this._store.get(key);
1420
1480
  } catch (error) {
1421
- this.emit(KeyvEvents.ERROR, error);
1422
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1481
+ this.emit("error", error);
1482
+ this.emitTelemetry("stat:error", key);
1423
1483
  }
1424
1484
  let data;
1425
1485
  if (this._checkExpired) [data] = await this.decodeWithExpire(key, rawData);
1426
1486
  else data = rawData === void 0 || rawData === null ? void 0 : typeof rawData === "string" ? await this.decode(rawData) : rawData;
1427
1487
  if (data === void 0) {
1428
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET, {
1488
+ await this.hookWithDeprecated("after:get", {
1429
1489
  key,
1430
1490
  value: void 0
1431
1491
  });
1432
- this.emitTelemetry(KeyvEvents.STAT_MISS, key);
1492
+ this.emitTelemetry("stat:miss", key);
1433
1493
  return;
1434
1494
  }
1435
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET, {
1495
+ await this.hookWithDeprecated("after:get", {
1436
1496
  key,
1437
1497
  value: data
1438
1498
  });
1439
- this.emitTelemetry(KeyvEvents.STAT_HIT, key);
1499
+ this.emitTelemetry("stat:hit", key);
1440
1500
  return data.value;
1441
1501
  }
1442
1502
  /**
1443
- * Get many values of keys
1444
- * @param {string[]} keys passing in a single key or multiple as an array
1503
+ * Reads many keys from the store, preferring its native `getMany` and falling back to parallel
1504
+ * single `get`s when an adapter does not implement it. A directly-used v6 adapter is not
1505
+ * structurally required to provide `getMany` (the bridge and memory adapters always do), so
1506
+ * this keeps `getMany`/`getManyRaw` working regardless of the resolved adapter.
1507
+ * @param keys - the keys to read
1508
+ * @returns the raw store results in the same order as `keys`
1509
+ */
1510
+ async storeGetMany(keys) {
1511
+ if (typeof this._store.getMany === "function") return this._store.getMany(keys);
1512
+ return Promise.all(keys.map(async (key) => this._store.get(key)));
1513
+ }
1514
+ /**
1515
+ * Get many values for an array of keys.
1516
+ * @param {string[]} keys the keys to get
1517
+ * @returns {Promise<Array<Value | undefined>>} an array of values in the same order as the
1518
+ * keys, with `undefined` for keys that do not exist or are expired.
1445
1519
  */
1446
1520
  async getMany(keys) {
1447
1521
  keys = this._sanitize.enabled ? this._sanitize.cleanKeys(keys) : keys;
1448
- await this.hookWithDeprecated(KeyvHooks.BEFORE_GET_MANY, { keys });
1449
- const rawData = await this._store.getMany(keys);
1522
+ await this.hookWithDeprecated("before:getMany", { keys });
1523
+ const rawData = await this.storeGetMany(keys);
1450
1524
  let deserialized;
1451
1525
  if (this._checkExpired) deserialized = await this.decodeWithExpire(keys, rawData);
1452
1526
  else deserialized = await Promise.all(rawData.map(async (row) => {
@@ -1454,9 +1528,9 @@ var Keyv = class Keyv extends Hookified {
1454
1528
  return typeof row === "string" ? this.decode(row) : row;
1455
1529
  }));
1456
1530
  const result = deserialized.map((row) => row !== void 0 ? row.value : void 0);
1457
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET_MANY, result);
1458
- for (let i = 0; i < result.length; i++) if (result[i] === void 0) this.emitTelemetry(KeyvEvents.STAT_MISS, keys[i]);
1459
- else this.emitTelemetry(KeyvEvents.STAT_HIT, keys[i]);
1531
+ await this.hookWithDeprecated("after:getMany", result);
1532
+ for (let i = 0; i < result.length; i++) if (result[i] === void 0) this.emitTelemetry("stat:miss", keys[i]);
1533
+ else this.emitTelemetry("stat:hit", keys[i]);
1460
1534
  return result;
1461
1535
  }
1462
1536
  /**
@@ -1468,21 +1542,21 @@ var Keyv = class Keyv extends Hookified {
1468
1542
  async getRaw(key) {
1469
1543
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
1470
1544
  if (key === "") return;
1471
- await this.hookWithDeprecated(KeyvHooks.BEFORE_GET_RAW, { key });
1545
+ await this.hookWithDeprecated("before:getRaw", { key });
1472
1546
  const rawData = await this._store.get(key);
1473
1547
  let data;
1474
1548
  if (this._checkExpired) [data] = await this.decodeWithExpire(key, rawData);
1475
1549
  else data = rawData === void 0 || rawData === null ? void 0 : typeof rawData === "string" ? await this.decode(rawData) : rawData;
1476
1550
  if (data === void 0) {
1477
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET_RAW, {
1551
+ await this.hookWithDeprecated("after:getRaw", {
1478
1552
  key,
1479
1553
  value: void 0
1480
1554
  });
1481
- this.emitTelemetry(KeyvEvents.STAT_MISS, key);
1555
+ this.emitTelemetry("stat:miss", key);
1482
1556
  return;
1483
1557
  }
1484
- this.emitTelemetry(KeyvEvents.STAT_HIT, key);
1485
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET_RAW, {
1558
+ this.emitTelemetry("stat:hit", key);
1559
+ await this.hookWithDeprecated("after:getRaw", {
1486
1560
  key,
1487
1561
  value: data
1488
1562
  });
@@ -1496,25 +1570,25 @@ var Keyv = class Keyv extends Hookified {
1496
1570
  async getManyRaw(keys) {
1497
1571
  /* v8 ignore next -- @preserve */
1498
1572
  keys = this._sanitize.enabled ? this._sanitize.cleanKeys(keys) : keys;
1499
- await this.hookWithDeprecated(KeyvHooks.BEFORE_GET_MANY_RAW, { keys });
1573
+ await this.hookWithDeprecated("before:getManyRaw", { keys });
1500
1574
  if (keys.length === 0) {
1501
1575
  const result = [];
1502
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET_MANY_RAW, {
1576
+ await this.hookWithDeprecated("after:getManyRaw", {
1503
1577
  keys,
1504
1578
  values: result
1505
1579
  });
1506
1580
  return result;
1507
1581
  }
1508
- const rawData = await this._store.getMany(keys);
1582
+ const rawData = await this.storeGetMany(keys);
1509
1583
  let result;
1510
1584
  if (this._checkExpired) result = await this.decodeWithExpire(keys, rawData);
1511
1585
  else result = await Promise.all(rawData.map(async (row) => {
1512
1586
  if (row === void 0 || row === null) return;
1513
1587
  return typeof row === "string" ? this.decode(row) : row;
1514
1588
  }));
1515
- for (let i = 0; i < result.length; i++) if (result[i] === void 0) this.emitTelemetry(KeyvEvents.STAT_MISS, keys[i]);
1516
- else this.emitTelemetry(KeyvEvents.STAT_HIT, keys[i]);
1517
- await this.hookWithDeprecated(KeyvHooks.AFTER_GET_MANY_RAW, {
1589
+ for (let i = 0; i < result.length; i++) if (result[i] === void 0) this.emitTelemetry("stat:miss", keys[i]);
1590
+ else this.emitTelemetry("stat:hit", keys[i]);
1591
+ await this.hookWithDeprecated("after:getManyRaw", {
1518
1592
  keys,
1519
1593
  values: result
1520
1594
  });
@@ -1522,10 +1596,10 @@ var Keyv = class Keyv extends Hookified {
1522
1596
  }
1523
1597
  /**
1524
1598
  * Set an item to the store
1525
- * @param {string | Array<KeyvEntry<Value>>} key the key to use. If you pass in an array of KeyvEntry it will set many items
1599
+ * @param {string} key the key to use
1526
1600
  * @param {Value} value the value of the key
1527
- * @param {number} [ttl] time to live in milliseconds
1528
- * @returns {boolean} if it sets then it will return a true. On failure will return false.
1601
+ * @param {number} [ttl] time to live in milliseconds. Overrides the instance-level `ttl`.
1602
+ * @returns {Promise<boolean>} `true` if it was set successfully, `false` on failure.
1529
1603
  */
1530
1604
  async set(key, value, ttl) {
1531
1605
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
@@ -1535,12 +1609,12 @@ var Keyv = class Keyv extends Hookified {
1535
1609
  value,
1536
1610
  ttl
1537
1611
  };
1538
- await this.hookWithDeprecated(KeyvHooks.BEFORE_SET, data);
1612
+ await this.hookWithDeprecated("before:set", data);
1539
1613
  data.ttl = resolveTtl(data.ttl, this._ttl);
1540
1614
  const expires = calculateExpires(data.ttl);
1541
1615
  if (typeof data.value === "symbol") {
1542
- this.emit(KeyvEvents.ERROR, "symbol cannot be serialized");
1543
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1616
+ this.emit("error", "symbol cannot be serialized");
1617
+ this.emitTelemetry("stat:error", key);
1544
1618
  return false;
1545
1619
  }
1546
1620
  const formattedValue = {
@@ -1551,24 +1625,24 @@ var Keyv = class Keyv extends Hookified {
1551
1625
  let encodedValue = formattedValue;
1552
1626
  try {
1553
1627
  encodedValue = await this.encode(formattedValue);
1554
- result = await this._store.set(data.key, encodedValue, data.ttl);
1628
+ result = await this._store.set(data.key, encodedValue, expires);
1555
1629
  } catch (error) {
1556
1630
  result = false;
1557
- this.emit(KeyvEvents.ERROR, error);
1558
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1631
+ this.emit("error", error);
1632
+ this.emitTelemetry("stat:error", key);
1559
1633
  }
1560
- await this.hookWithDeprecated(KeyvHooks.AFTER_SET, {
1634
+ await this.hookWithDeprecated("after:set", {
1561
1635
  key,
1562
1636
  value: encodedValue,
1563
1637
  ttl
1564
1638
  });
1565
- if (result) this.emitTelemetry(KeyvEvents.STAT_SET, key);
1639
+ if (result) this.emitTelemetry("stat:set", key);
1566
1640
  return result;
1567
1641
  }
1568
1642
  /**
1569
1643
  * Set many items to the store
1570
1644
  * @param {Array<KeyvEntry<Value>>} entries the entries to set
1571
- * @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
1645
+ * @returns {Promise<boolean[]>} an array of booleans, one per entry: `true` if set successfully, `false` on failure.
1572
1646
  */
1573
1647
  async setMany(entries) {
1574
1648
  entries = entries.map((e) => ({
@@ -1576,7 +1650,7 @@ var Keyv = class Keyv extends Hookified {
1576
1650
  key: this._sanitize.enabled ? this._sanitize.cleanKey(e.key) : e.key
1577
1651
  }));
1578
1652
  const data = { entries };
1579
- await this.hookWithDeprecated(KeyvHooks.BEFORE_SET_MANY, data);
1653
+ await this.hookWithDeprecated("before:setMany", data);
1580
1654
  entries = data.entries;
1581
1655
  let results = [];
1582
1656
  try {
@@ -1586,8 +1660,8 @@ var Keyv = class Keyv extends Hookified {
1586
1660
  const expires = calculateExpires(ttl);
1587
1661
  /* v8 ignore next -- @preserve */
1588
1662
  if (typeof value === "symbol") {
1589
- this.emit(KeyvEvents.ERROR, "symbol cannot be serialized");
1590
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1663
+ this.emit("error", "symbol cannot be serialized");
1664
+ this.emitTelemetry("stat:error", key);
1591
1665
  throw new Error("symbol cannot be serialized");
1592
1666
  }
1593
1667
  const formattedValue = {
@@ -1597,19 +1671,19 @@ var Keyv = class Keyv extends Hookified {
1597
1671
  return {
1598
1672
  key,
1599
1673
  value: await this.encode(formattedValue),
1600
- ttl
1674
+ expires
1601
1675
  };
1602
1676
  }));
1603
1677
  const storeResult = await this._store.setMany(serializedEntries);
1604
1678
  /* v8 ignore next -- @preserve */
1605
1679
  results = Array.isArray(storeResult) ? storeResult : entries.map(() => true);
1606
- this.emitTelemetry(KeyvEvents.STAT_SET, entries.map((e) => e.key));
1680
+ this.emitTelemetry("stat:set", entries.map((e) => e.key));
1607
1681
  } catch (error) {
1608
- this.emit(KeyvEvents.ERROR, error);
1609
- this.emitTelemetry(KeyvEvents.STAT_ERROR, entries.map((e) => e.key));
1682
+ this.emit("error", error);
1683
+ this.emitTelemetry("stat:error", entries.map((e) => e.key));
1610
1684
  results = entries.map(() => false);
1611
1685
  }
1612
- await this.hookWithDeprecated(KeyvHooks.AFTER_SET_MANY, {
1686
+ await this.hookWithDeprecated("after:setMany", {
1613
1687
  entries,
1614
1688
  values: results
1615
1689
  });
@@ -1622,7 +1696,7 @@ var Keyv = class Keyv extends Hookified {
1622
1696
  * The store-level TTL is derived automatically from `value.expires`.
1623
1697
  * @param {string} key the key to set
1624
1698
  * @param {KeyvValue<Value>} value the raw value envelope to store
1625
- * @returns {boolean} if it sets then it will return a true. On failure will return false.
1699
+ * @returns {Promise<boolean>} `true` if it was set successfully, `false` on failure.
1626
1700
  */
1627
1701
  async setRaw(key, value) {
1628
1702
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
@@ -1631,24 +1705,25 @@ var Keyv = class Keyv extends Hookified {
1631
1705
  key,
1632
1706
  value
1633
1707
  };
1634
- await this.hookWithDeprecated(KeyvHooks.BEFORE_SET_RAW, data);
1635
- const ttl = ttlFromExpires(data.value.expires);
1708
+ await this.hookWithDeprecated("before:setRaw", data);
1709
+ const expires = data.value.expires;
1710
+ const ttl = ttlFromExpires(expires);
1636
1711
  let result = true;
1637
1712
  try {
1638
1713
  const encodedValue = await this.encode(data.value);
1639
- const storeResult = await this._store.set(data.key, encodedValue, ttl);
1714
+ const storeResult = await this._store.set(data.key, encodedValue, expires);
1640
1715
  if (typeof storeResult === "boolean") result = storeResult;
1641
1716
  } catch (error) {
1642
1717
  result = false;
1643
- this.emit(KeyvEvents.ERROR, error);
1644
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1718
+ this.emit("error", error);
1719
+ this.emitTelemetry("stat:error", key);
1645
1720
  }
1646
- await this.hookWithDeprecated(KeyvHooks.AFTER_SET_RAW, {
1721
+ await this.hookWithDeprecated("after:setRaw", {
1647
1722
  key,
1648
1723
  value: data.value,
1649
1724
  ttl
1650
1725
  });
1651
- if (result) this.emitTelemetry(KeyvEvents.STAT_SET, key);
1726
+ if (result) this.emitTelemetry("stat:set", key);
1652
1727
  return result;
1653
1728
  }
1654
1729
  /**
@@ -1656,33 +1731,33 @@ var Keyv = class Keyv extends Hookified {
1656
1731
  * Each entry's value should be a KeyvValue object with { value, expires? }. If you need TTL-based expiration,
1657
1732
  * set `expires` on each value directly. The store-level TTL is derived automatically from `value.expires`.
1658
1733
  * @param {KeyvEntry<KeyvValue<Value>>[]} entries the raw entries to set
1659
- * @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
1734
+ * @returns {Promise<boolean[]>} an array of booleans, one per entry: `true` if set successfully, `false` on failure.
1660
1735
  */
1661
1736
  async setManyRaw(entries) {
1662
1737
  entries = entries.map((e) => ({
1663
1738
  ...e,
1739
+ /* v8 ignore next -- @preserve */
1664
1740
  key: this._sanitize.enabled ? this._sanitize.cleanKey(e.key) : e.key
1665
1741
  }));
1666
1742
  let results = [];
1667
- await this.hookWithDeprecated(KeyvHooks.BEFORE_SET_MANY_RAW, { entries });
1743
+ await this.hookWithDeprecated("before:setManyRaw", { entries });
1668
1744
  try {
1669
1745
  const rawEntries = await Promise.all(entries.map(async ({ key, value }) => {
1670
- const ttl = ttlFromExpires(value.expires);
1671
1746
  return {
1672
1747
  key,
1673
1748
  value: await this.encode(value),
1674
- ttl
1749
+ expires: value.expires
1675
1750
  };
1676
1751
  }));
1677
1752
  const storeResult = await this._store.setMany(rawEntries);
1678
1753
  results = Array.isArray(storeResult) ? storeResult : entries.map(() => true);
1679
- this.emitTelemetry(KeyvEvents.STAT_SET, entries.map((e) => e.key));
1754
+ this.emitTelemetry("stat:set", entries.map((e) => e.key));
1680
1755
  } catch (error) {
1681
- this.emit(KeyvEvents.ERROR, error);
1682
- this.emitTelemetry(KeyvEvents.STAT_ERROR, entries.map((e) => e.key));
1756
+ this.emit("error", error);
1757
+ this.emitTelemetry("stat:error", entries.map((e) => e.key));
1683
1758
  results = entries.map(() => false);
1684
1759
  }
1685
- await this.hookWithDeprecated(KeyvHooks.AFTER_SET_MANY_RAW, {
1760
+ await this.hookWithDeprecated("after:setManyRaw", {
1686
1761
  entries,
1687
1762
  results
1688
1763
  });
@@ -1692,46 +1767,46 @@ var Keyv = class Keyv extends Hookified {
1692
1767
  if (Array.isArray(key)) return this.deleteMany(key);
1693
1768
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
1694
1769
  if (key === "") return false;
1695
- await this.hookWithDeprecated(KeyvHooks.BEFORE_DELETE, { key });
1770
+ await this.hookWithDeprecated("before:delete", { key });
1696
1771
  let result = true;
1697
1772
  try {
1698
1773
  result = await this._store.delete(key);
1699
1774
  } catch (error) {
1700
1775
  result = false;
1701
- this.emit(KeyvEvents.ERROR, error);
1702
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1776
+ this.emit("error", error);
1777
+ this.emitTelemetry("stat:error", key);
1703
1778
  }
1704
- await this.hookWithDeprecated(KeyvHooks.AFTER_DELETE, {
1779
+ await this.hookWithDeprecated("after:delete", {
1705
1780
  key,
1706
1781
  value: result
1707
1782
  });
1708
- this.emitTelemetry(KeyvEvents.STAT_DELETE, key);
1783
+ this.emitTelemetry("stat:delete", key);
1709
1784
  return result;
1710
1785
  }
1711
1786
  /**
1712
1787
  * Delete many items from the store
1713
1788
  * @param {string[]} keys the keys to be deleted
1714
- * @returns {boolean[]} array of booleans indicating success for each key
1789
+ * @returns {Promise<boolean[]>} an array of booleans indicating success for each key.
1715
1790
  */
1716
1791
  async deleteMany(keys) {
1717
1792
  /* v8 ignore next -- @preserve */
1718
1793
  keys = this._sanitize.enabled ? this._sanitize.cleanKeys(keys) : keys;
1719
- await this.hookWithDeprecated(KeyvHooks.BEFORE_DELETE_MANY, { keys });
1720
- await this.hookWithDeprecated(KeyvHooks.BEFORE_DELETE, { key: keys });
1794
+ await this.hookWithDeprecated("before:deleteMany", { keys });
1795
+ await this.hookWithDeprecated("before:delete", { key: keys });
1721
1796
  let results;
1722
1797
  try {
1723
1798
  results = await this._store.deleteMany(keys);
1724
- this.emitTelemetry(KeyvEvents.STAT_DELETE, keys);
1799
+ this.emitTelemetry("stat:delete", keys);
1725
1800
  } catch (error) {
1726
- this.emit(KeyvEvents.ERROR, error);
1727
- this.emitTelemetry(KeyvEvents.STAT_ERROR, keys);
1801
+ this.emit("error", error);
1802
+ this.emitTelemetry("stat:error", keys);
1728
1803
  results = keys.map(() => false);
1729
1804
  }
1730
- await this.hookWithDeprecated(KeyvHooks.AFTER_DELETE_MANY, {
1805
+ await this.hookWithDeprecated("after:deleteMany", {
1731
1806
  keys,
1732
1807
  values: results
1733
1808
  });
1734
- await this.hookWithDeprecated(KeyvHooks.AFTER_DELETE, {
1809
+ await this.hookWithDeprecated("after:delete", {
1735
1810
  key: keys,
1736
1811
  value: results
1737
1812
  });
@@ -1741,7 +1816,7 @@ var Keyv = class Keyv extends Hookified {
1741
1816
  if (Array.isArray(key)) return this.hasMany(key);
1742
1817
  key = this._sanitize.enabled ? this._sanitize.cleanKey(key) : key;
1743
1818
  if (key === "") return false;
1744
- await this.hookWithDeprecated(KeyvHooks.BEFORE_HAS, { key });
1819
+ await this.hookWithDeprecated("before:has", { key });
1745
1820
  let result = false;
1746
1821
  try {
1747
1822
  if (this._checkExpired) {
@@ -1752,10 +1827,10 @@ var Keyv = class Keyv extends Hookified {
1752
1827
  }
1753
1828
  } else result = await this._store.has(key);
1754
1829
  } catch (error) {
1755
- this.emit(KeyvEvents.ERROR, error);
1756
- this.emitTelemetry(KeyvEvents.STAT_ERROR, key);
1830
+ this.emit("error", error);
1831
+ this.emitTelemetry("stat:error", key);
1757
1832
  }
1758
- await this.hookWithDeprecated(KeyvHooks.AFTER_HAS, {
1833
+ await this.hookWithDeprecated("after:has", {
1759
1834
  key,
1760
1835
  value: result
1761
1836
  });
@@ -1764,11 +1839,11 @@ var Keyv = class Keyv extends Hookified {
1764
1839
  /**
1765
1840
  * Check if many keys exist
1766
1841
  * @param {string[]} keys the keys to check
1767
- * @returns {boolean[]} will return an array of booleans if the keys exist
1842
+ * @returns {Promise<boolean[]>} an array of booleans in the same order as the keys, `true` if the key exists.
1768
1843
  */
1769
1844
  async hasMany(keys) {
1770
1845
  keys = this._sanitize.enabled ? this._sanitize.cleanKeys(keys) : keys;
1771
- await this.hookWithDeprecated(KeyvHooks.BEFORE_HAS_MANY, { keys });
1846
+ await this.hookWithDeprecated("before:hasMany", { keys });
1772
1847
  let results = [];
1773
1848
  try {
1774
1849
  if (this._checkExpired) {
@@ -1776,30 +1851,31 @@ var Keyv = class Keyv extends Hookified {
1776
1851
  results = (await this.decodeWithExpire(keys, rawData)).map((row) => row !== void 0);
1777
1852
  } else results = await this._store.hasMany(keys);
1778
1853
  } catch (error) {
1779
- this.emit(KeyvEvents.ERROR, error);
1780
- this.emitTelemetry(KeyvEvents.STAT_ERROR, keys);
1854
+ this.emit("error", error);
1855
+ this.emitTelemetry("stat:error", keys);
1781
1856
  results = keys.map(() => false);
1782
1857
  }
1783
- await this.hookWithDeprecated(KeyvHooks.AFTER_HAS_MANY, {
1858
+ await this.hookWithDeprecated("after:hasMany", {
1784
1859
  keys,
1785
1860
  values: results
1786
1861
  });
1787
1862
  return results;
1788
1863
  }
1789
1864
  /**
1790
- * Clear the store
1791
- * @returns {void}
1865
+ * Clear the store. If a namespace is set only entries in that namespace are removed.
1866
+ * Emits a `clear` event.
1867
+ * @returns {Promise<void>} resolves once the entries have been cleared.
1792
1868
  */
1793
1869
  async clear() {
1794
1870
  this.emit("clear");
1795
- await this.hook(KeyvHooks.BEFORE_CLEAR, { namespace: this._namespace });
1871
+ await this.hook("before:clear", { namespace: this._namespace });
1796
1872
  try {
1797
1873
  await this._store.clear();
1798
1874
  } catch (error) {
1799
- this.emit(KeyvEvents.ERROR, error);
1800
- this.emitTelemetry(KeyvEvents.STAT_ERROR);
1875
+ this.emit("error", error);
1876
+ this.emitTelemetry("stat:error");
1801
1877
  }
1802
- await this.hook(KeyvHooks.AFTER_CLEAR, { namespace: this._namespace });
1878
+ await this.hook("after:clear", { namespace: this._namespace });
1803
1879
  }
1804
1880
  /**
1805
1881
  * Will disconnect the store. This is only available if the store has a disconnect method
@@ -1807,13 +1883,13 @@ var Keyv = class Keyv extends Hookified {
1807
1883
  */
1808
1884
  async disconnect() {
1809
1885
  this.emit("disconnect");
1810
- await this.hook(KeyvHooks.BEFORE_DISCONNECT, { namespace: this._namespace });
1886
+ await this.hook("before:disconnect", { namespace: this._namespace });
1811
1887
  try {
1812
1888
  if (this._store.disconnect) await this._store.disconnect();
1813
1889
  } catch (error) {
1814
- this.emit(KeyvEvents.ERROR, error);
1890
+ this.emit("error", error);
1815
1891
  }
1816
- await this.hook(KeyvHooks.AFTER_DISCONNECT, { namespace: this._namespace });
1892
+ await this.hook("after:disconnect", { namespace: this._namespace });
1817
1893
  }
1818
1894
  /**
1819
1895
  * Iterate over all key-value pairs in the store. Automatically deserializes values,
@@ -1861,7 +1937,7 @@ var Keyv = class Keyv extends Hookified {
1861
1937
  if (typeof result === "string") return await this._serialization.parse(result);
1862
1938
  return result;
1863
1939
  } catch (error) {
1864
- this.emit(KeyvEvents.ERROR, error);
1940
+ this.emit("error", error);
1865
1941
  return;
1866
1942
  }
1867
1943
  }
@@ -2004,10 +2080,14 @@ var KeyvMemoryAdapter = class extends Hookified {
2004
2080
  if (options?.namespace) this._namespace = options?.namespace;
2005
2081
  }
2006
2082
  /**
2007
- * Gets the detected capabilities of the underlying store.
2083
+ * Gets the capabilities of the underlying store, with `expires: true` to declare that
2084
+ * this adapter accepts an absolute `expires` timestamp (the v6 storage contract).
2008
2085
  */
2009
2086
  get capabilities() {
2010
- return this._capabilities;
2087
+ return {
2088
+ ...this._capabilities,
2089
+ expires: true
2090
+ };
2011
2091
  }
2012
2092
  /**
2013
2093
  * Gets the underlying store instance.
@@ -2084,24 +2164,24 @@ var KeyvMemoryAdapter = class extends Hookified {
2084
2164
  return entry.value;
2085
2165
  }
2086
2166
  /**
2087
- * Stores a value in the store with an optional TTL.
2167
+ * Stores a value in the store with an optional absolute expiry.
2088
2168
  * @param key - The key to store the value under
2089
2169
  * @param value - The value to store
2090
- * @param ttl - Optional time-to-live in milliseconds
2170
+ * @param expires - Optional absolute expiry as Unix ms since epoch
2091
2171
  * @returns Always returns true indicating success
2092
2172
  */
2093
- async set(key, value, ttl) {
2173
+ async set(key, value, expires) {
2094
2174
  const keyPrefix = this.getKeyPrefix(key, this._namespace);
2095
2175
  const entry = {
2096
2176
  value,
2097
- expires: ttl ? Date.now() + ttl : void 0
2177
+ expires: typeof expires === "number" ? expires : void 0
2098
2178
  };
2099
- this._store.set(keyPrefix, entry, ttl);
2179
+ this._store.set(keyPrefix, entry, ttlFromExpires(expires));
2100
2180
  return true;
2101
2181
  }
2102
2182
  /**
2103
2183
  * Stores multiple entries in the store at once.
2104
- * @param entries - Array of entries containing key, value, and optional TTL
2184
+ * @param entries - Array of entries containing key, value, and optional absolute `expires`
2105
2185
  */
2106
2186
  async setMany(entries) {
2107
2187
  const results = [];
@@ -2109,9 +2189,9 @@ var KeyvMemoryAdapter = class extends Hookified {
2109
2189
  const keyPrefix = this.getKeyPrefix(entry.key, this._namespace);
2110
2190
  const memEntry = {
2111
2191
  value: entry.value,
2112
- expires: entry.ttl ? Date.now() + entry.ttl : void 0
2192
+ expires: typeof entry.expires === "number" ? entry.expires : void 0
2113
2193
  };
2114
- this._store.set(keyPrefix, memEntry, entry.ttl);
2194
+ this._store.set(keyPrefix, memEntry, ttlFromExpires(entry.expires));
2115
2195
  results.push(true);
2116
2196
  }
2117
2197
  return results;
@@ -2201,7 +2281,7 @@ var KeyvMemoryAdapter = class extends Hookified {
2201
2281
  this._store.delete(keyPrefix);
2202
2282
  results.push(existed);
2203
2283
  } catch (error) {
2204
- this.emit(KeyvEvents.ERROR, error);
2284
+ this.emit("error", error);
2205
2285
  results.push(false);
2206
2286
  }
2207
2287
  return results;
@@ -2264,4 +2344,4 @@ function createKeyv(store, options) {
2264
2344
  });
2265
2345
  }
2266
2346
  //#endregion
2267
- export { Keyv, Keyv as default, KeyvBridgeAdapter, KeyvEvents, KeyvHooks, KeyvJsonSerializer, KeyvMemoryAdapter, KeyvSanitize, KeyvStats, createKeyv, detectKeyv, detectKeyvCompression, detectKeyvEncryption, detectKeyvSerialization, detectKeyvStorage, jsonSerializer };
2347
+ export { Keyv, Keyv as default, KeyvBridgeAdapter, KeyvEvents, KeyvHooks, KeyvJsonSerializer, KeyvMemoryAdapter, KeyvSanitize, KeyvStats, createKeyv, detectKeyv, detectKeyvCompression, detectKeyvEncryption, detectKeyvSerialization, detectKeyvStorage, jsonSerializer, keyvStorageCapability };