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