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.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
|
-
[
|
|
406
|
-
[
|
|
407
|
-
[
|
|
408
|
-
[
|
|
409
|
-
[
|
|
410
|
-
[
|
|
411
|
-
[
|
|
412
|
-
[
|
|
413
|
-
[
|
|
414
|
-
[
|
|
415
|
-
[
|
|
416
|
-
[
|
|
417
|
-
[
|
|
418
|
-
[
|
|
419
|
-
[
|
|
420
|
-
[
|
|
421
|
-
[
|
|
422
|
-
[
|
|
423
|
-
[
|
|
424
|
-
[
|
|
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.
|
|
488
|
-
if (typeof store.on === "function") store.on(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
652
|
+
async set(key, value, expires) {
|
|
611
653
|
const keyPrefix = this.getKeyPrefix(key, this._namespace);
|
|
612
|
-
|
|
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
|
|
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
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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.
|
|
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(
|
|
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
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
|
|
1377
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
1422
|
-
this.emitTelemetry(
|
|
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(
|
|
1488
|
+
await this.hookWithDeprecated("after:get", {
|
|
1429
1489
|
key,
|
|
1430
1490
|
value: void 0
|
|
1431
1491
|
});
|
|
1432
|
-
this.emitTelemetry(
|
|
1492
|
+
this.emitTelemetry("stat:miss", key);
|
|
1433
1493
|
return;
|
|
1434
1494
|
}
|
|
1435
|
-
await this.hookWithDeprecated(
|
|
1495
|
+
await this.hookWithDeprecated("after:get", {
|
|
1436
1496
|
key,
|
|
1437
1497
|
value: data
|
|
1438
1498
|
});
|
|
1439
|
-
this.emitTelemetry(
|
|
1499
|
+
this.emitTelemetry("stat:hit", key);
|
|
1440
1500
|
return data.value;
|
|
1441
1501
|
}
|
|
1442
1502
|
/**
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
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(
|
|
1449
|
-
const rawData = await this.
|
|
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(
|
|
1458
|
-
for (let i = 0; i < result.length; i++) if (result[i] === void 0) this.emitTelemetry(
|
|
1459
|
-
else this.emitTelemetry(
|
|
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(
|
|
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(
|
|
1551
|
+
await this.hookWithDeprecated("after:getRaw", {
|
|
1478
1552
|
key,
|
|
1479
1553
|
value: void 0
|
|
1480
1554
|
});
|
|
1481
|
-
this.emitTelemetry(
|
|
1555
|
+
this.emitTelemetry("stat:miss", key);
|
|
1482
1556
|
return;
|
|
1483
1557
|
}
|
|
1484
|
-
this.emitTelemetry(
|
|
1485
|
-
await this.hookWithDeprecated(
|
|
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(
|
|
1573
|
+
await this.hookWithDeprecated("before:getManyRaw", { keys });
|
|
1500
1574
|
if (keys.length === 0) {
|
|
1501
1575
|
const result = [];
|
|
1502
|
-
await this.hookWithDeprecated(
|
|
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.
|
|
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(
|
|
1516
|
-
else this.emitTelemetry(
|
|
1517
|
-
await this.hookWithDeprecated(
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
1543
|
-
this.emitTelemetry(
|
|
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,
|
|
1628
|
+
result = await this._store.set(data.key, encodedValue, expires);
|
|
1555
1629
|
} catch (error) {
|
|
1556
1630
|
result = false;
|
|
1557
|
-
this.emit(
|
|
1558
|
-
this.emitTelemetry(
|
|
1631
|
+
this.emit("error", error);
|
|
1632
|
+
this.emitTelemetry("stat:error", key);
|
|
1559
1633
|
}
|
|
1560
|
-
await this.hookWithDeprecated(
|
|
1634
|
+
await this.hookWithDeprecated("after:set", {
|
|
1561
1635
|
key,
|
|
1562
1636
|
value: encodedValue,
|
|
1563
1637
|
ttl
|
|
1564
1638
|
});
|
|
1565
|
-
if (result) this.emitTelemetry(
|
|
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[]}
|
|
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(
|
|
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(
|
|
1590
|
-
this.emitTelemetry(
|
|
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
|
-
|
|
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(
|
|
1680
|
+
this.emitTelemetry("stat:set", entries.map((e) => e.key));
|
|
1607
1681
|
} catch (error) {
|
|
1608
|
-
this.emit(
|
|
1609
|
-
this.emitTelemetry(
|
|
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(
|
|
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
|
|
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(
|
|
1635
|
-
const
|
|
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,
|
|
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(
|
|
1644
|
-
this.emitTelemetry(
|
|
1718
|
+
this.emit("error", error);
|
|
1719
|
+
this.emitTelemetry("stat:error", key);
|
|
1645
1720
|
}
|
|
1646
|
-
await this.hookWithDeprecated(
|
|
1721
|
+
await this.hookWithDeprecated("after:setRaw", {
|
|
1647
1722
|
key,
|
|
1648
1723
|
value: data.value,
|
|
1649
1724
|
ttl
|
|
1650
1725
|
});
|
|
1651
|
-
if (result) this.emitTelemetry(
|
|
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[]}
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1754
|
+
this.emitTelemetry("stat:set", entries.map((e) => e.key));
|
|
1680
1755
|
} catch (error) {
|
|
1681
|
-
this.emit(
|
|
1682
|
-
this.emitTelemetry(
|
|
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(
|
|
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(
|
|
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(
|
|
1702
|
-
this.emitTelemetry(
|
|
1776
|
+
this.emit("error", error);
|
|
1777
|
+
this.emitTelemetry("stat:error", key);
|
|
1703
1778
|
}
|
|
1704
|
-
await this.hookWithDeprecated(
|
|
1779
|
+
await this.hookWithDeprecated("after:delete", {
|
|
1705
1780
|
key,
|
|
1706
1781
|
value: result
|
|
1707
1782
|
});
|
|
1708
|
-
this.emitTelemetry(
|
|
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(
|
|
1720
|
-
await this.hookWithDeprecated(
|
|
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(
|
|
1799
|
+
this.emitTelemetry("stat:delete", keys);
|
|
1725
1800
|
} catch (error) {
|
|
1726
|
-
this.emit(
|
|
1727
|
-
this.emitTelemetry(
|
|
1801
|
+
this.emit("error", error);
|
|
1802
|
+
this.emitTelemetry("stat:error", keys);
|
|
1728
1803
|
results = keys.map(() => false);
|
|
1729
1804
|
}
|
|
1730
|
-
await this.hookWithDeprecated(
|
|
1805
|
+
await this.hookWithDeprecated("after:deleteMany", {
|
|
1731
1806
|
keys,
|
|
1732
1807
|
values: results
|
|
1733
1808
|
});
|
|
1734
|
-
await this.hookWithDeprecated(
|
|
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(
|
|
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(
|
|
1756
|
-
this.emitTelemetry(
|
|
1830
|
+
this.emit("error", error);
|
|
1831
|
+
this.emitTelemetry("stat:error", key);
|
|
1757
1832
|
}
|
|
1758
|
-
await this.hookWithDeprecated(
|
|
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[]}
|
|
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(
|
|
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(
|
|
1780
|
-
this.emitTelemetry(
|
|
1854
|
+
this.emit("error", error);
|
|
1855
|
+
this.emitTelemetry("stat:error", keys);
|
|
1781
1856
|
results = keys.map(() => false);
|
|
1782
1857
|
}
|
|
1783
|
-
await this.hookWithDeprecated(
|
|
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
|
-
*
|
|
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(
|
|
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(
|
|
1800
|
-
this.emitTelemetry(
|
|
1875
|
+
this.emit("error", error);
|
|
1876
|
+
this.emitTelemetry("stat:error");
|
|
1801
1877
|
}
|
|
1802
|
-
await this.hook(
|
|
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(
|
|
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(
|
|
1890
|
+
this.emit("error", error);
|
|
1815
1891
|
}
|
|
1816
|
-
await this.hook(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
2173
|
+
async set(key, value, expires) {
|
|
2094
2174
|
const keyPrefix = this.getKeyPrefix(key, this._namespace);
|
|
2095
2175
|
const entry = {
|
|
2096
2176
|
value,
|
|
2097
|
-
expires:
|
|
2177
|
+
expires: typeof expires === "number" ? expires : void 0
|
|
2098
2178
|
};
|
|
2099
|
-
this._store.set(keyPrefix, entry,
|
|
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
|
|
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.
|
|
2192
|
+
expires: typeof entry.expires === "number" ? entry.expires : void 0
|
|
2113
2193
|
};
|
|
2114
|
-
this._store.set(keyPrefix, memEntry, entry.
|
|
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(
|
|
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 };
|