keyv 6.0.0-beta.3 → 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
@@ -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,9 +508,11 @@ 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);
515
+ if (this._storeHandlesNamespace) this._store.namespace = this._namespace;
488
516
  if (typeof store.on === "function") store.on("error", (error) => this.emit("error", error));
489
517
  }
490
518
  /**
@@ -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;
@@ -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,19 +1417,32 @@ 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
1448
  this.emit("error", /* @__PURE__ */ new Error("Could not use the provided storage adapter, falling back to KeyvMemoryAdapter with Map"));
@@ -1440,13 +1500,27 @@ var Keyv = class Keyv extends Hookified {
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
1522
  await this.hookWithDeprecated("before:getMany", { keys });
1449
- const rawData = await this._store.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) => {
@@ -1505,7 +1579,7 @@ var Keyv = class Keyv extends Hookified {
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) => {
@@ -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;
@@ -1551,7 +1625,7 @@ 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
1631
  this.emit("error", error);
@@ -1568,7 +1642,7 @@ var Keyv = class Keyv extends Hookified {
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) => ({
@@ -1597,7 +1671,7 @@ 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);
@@ -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;
@@ -1632,11 +1706,12 @@ var Keyv = class Keyv extends Hookified {
1632
1706
  value
1633
1707
  };
1634
1708
  await this.hookWithDeprecated("before:setRaw", data);
1635
- const ttl = ttlFromExpires(data.value.expires);
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;
@@ -1656,7 +1731,7 @@ 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) => ({
@@ -1668,11 +1743,10 @@ var Keyv = class Keyv extends Hookified {
1668
1743
  await this.hookWithDeprecated("before:setManyRaw", { entries });
1669
1744
  try {
1670
1745
  const rawEntries = await Promise.all(entries.map(async ({ key, value }) => {
1671
- const ttl = ttlFromExpires(value.expires);
1672
1746
  return {
1673
1747
  key,
1674
1748
  value: await this.encode(value),
1675
- ttl
1749
+ expires: value.expires
1676
1750
  };
1677
1751
  }));
1678
1752
  const storeResult = await this._store.setMany(rawEntries);
@@ -1712,7 +1786,7 @@ var Keyv = class Keyv extends Hookified {
1712
1786
  /**
1713
1787
  * Delete many items from the store
1714
1788
  * @param {string[]} keys the keys to be deleted
1715
- * @returns {boolean[]} array of booleans indicating success for each key
1789
+ * @returns {Promise<boolean[]>} an array of booleans indicating success for each key.
1716
1790
  */
1717
1791
  async deleteMany(keys) {
1718
1792
  /* v8 ignore next -- @preserve */
@@ -1765,7 +1839,7 @@ var Keyv = class Keyv extends Hookified {
1765
1839
  /**
1766
1840
  * Check if many keys exist
1767
1841
  * @param {string[]} keys the keys to check
1768
- * @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.
1769
1843
  */
1770
1844
  async hasMany(keys) {
1771
1845
  keys = this._sanitize.enabled ? this._sanitize.cleanKeys(keys) : keys;
@@ -1788,8 +1862,9 @@ var Keyv = class Keyv extends Hookified {
1788
1862
  return results;
1789
1863
  }
1790
1864
  /**
1791
- * Clear the store
1792
- * @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.
1793
1868
  */
1794
1869
  async clear() {
1795
1870
  this.emit("clear");
@@ -2005,10 +2080,14 @@ var KeyvMemoryAdapter = class extends Hookified {
2005
2080
  if (options?.namespace) this._namespace = options?.namespace;
2006
2081
  }
2007
2082
  /**
2008
- * 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).
2009
2085
  */
2010
2086
  get capabilities() {
2011
- return this._capabilities;
2087
+ return {
2088
+ ...this._capabilities,
2089
+ expires: true
2090
+ };
2012
2091
  }
2013
2092
  /**
2014
2093
  * Gets the underlying store instance.
@@ -2085,24 +2164,24 @@ var KeyvMemoryAdapter = class extends Hookified {
2085
2164
  return entry.value;
2086
2165
  }
2087
2166
  /**
2088
- * Stores a value in the store with an optional TTL.
2167
+ * Stores a value in the store with an optional absolute expiry.
2089
2168
  * @param key - The key to store the value under
2090
2169
  * @param value - The value to store
2091
- * @param ttl - Optional time-to-live in milliseconds
2170
+ * @param expires - Optional absolute expiry as Unix ms since epoch
2092
2171
  * @returns Always returns true indicating success
2093
2172
  */
2094
- async set(key, value, ttl) {
2173
+ async set(key, value, expires) {
2095
2174
  const keyPrefix = this.getKeyPrefix(key, this._namespace);
2096
2175
  const entry = {
2097
2176
  value,
2098
- expires: ttl ? Date.now() + ttl : void 0
2177
+ expires: typeof expires === "number" ? expires : void 0
2099
2178
  };
2100
- this._store.set(keyPrefix, entry, ttl);
2179
+ this._store.set(keyPrefix, entry, ttlFromExpires(expires));
2101
2180
  return true;
2102
2181
  }
2103
2182
  /**
2104
2183
  * Stores multiple entries in the store at once.
2105
- * @param entries - Array of entries containing key, value, and optional TTL
2184
+ * @param entries - Array of entries containing key, value, and optional absolute `expires`
2106
2185
  */
2107
2186
  async setMany(entries) {
2108
2187
  const results = [];
@@ -2110,9 +2189,9 @@ var KeyvMemoryAdapter = class extends Hookified {
2110
2189
  const keyPrefix = this.getKeyPrefix(entry.key, this._namespace);
2111
2190
  const memEntry = {
2112
2191
  value: entry.value,
2113
- expires: entry.ttl ? Date.now() + entry.ttl : void 0
2192
+ expires: typeof entry.expires === "number" ? entry.expires : void 0
2114
2193
  };
2115
- this._store.set(keyPrefix, memEntry, entry.ttl);
2194
+ this._store.set(keyPrefix, memEntry, ttlFromExpires(entry.expires));
2116
2195
  results.push(true);
2117
2196
  }
2118
2197
  return results;
@@ -2265,4 +2344,4 @@ function createKeyv(store, options) {
2265
2344
  });
2266
2345
  }
2267
2346
  //#endregion
2268
- 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keyv",
3
- "version": "6.0.0-beta.3",
3
+ "version": "6.0.0-beta.4",
4
4
  "description": "Simple key-value storage with support for multiple backends",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",