keyv 6.0.0-alpha.2 → 6.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +410 -95
- package/dist/index.cjs +2280 -992
- package/dist/index.d.cts +1340 -375
- package/dist/index.d.mts +1351 -0
- package/dist/index.mjs +2267 -0
- package/package.json +12 -9
- package/dist/index.d.ts +0 -386
- package/dist/index.js +0 -972
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/jaredwray/keyv/actions/workflows/tests.yaml)
|
|
6
6
|
[](https://github.com/jaredwray/keyv/actions/workflows/bun-test.yaml)
|
|
7
|
+
[](https://github.com/jaredwray/keyv/actions/workflows/browser-compat.yaml)
|
|
7
8
|
[](https://codecov.io/gh/jaredwray/keyv)
|
|
8
9
|
[](https://www.npmjs.com/package/keyv)
|
|
9
10
|
[](https://www.npmjs.com/package/keyv)
|
|
@@ -19,7 +20,7 @@ There are a few existing modules similar to Keyv, however Keyv is different beca
|
|
|
19
20
|
- Suitable as a TTL based cache or persistent key-value store
|
|
20
21
|
- [Easily embeddable](#add-cache-support-to-your-module) inside another module
|
|
21
22
|
- Works with any storage that implements the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) API
|
|
22
|
-
- Handles all JSON types plus `Buffer`
|
|
23
|
+
- Handles all JSON types plus `Buffer` and `BigInt` via the built-in `KeyvJsonSerializer`
|
|
23
24
|
- Supports namespaces
|
|
24
25
|
- Wide range of [**efficient, well tested**](#official-storage-adapters) storage adapters
|
|
25
26
|
- Connection errors are passed through (db failures won't kill your app)
|
|
@@ -32,21 +33,24 @@ There are a few existing modules similar to Keyv, however Keyv is different beca
|
|
|
32
33
|
- [Namespaces](#namespaces)
|
|
33
34
|
- [Events](#events)
|
|
34
35
|
- [Hooks](#hooks)
|
|
35
|
-
- [
|
|
36
|
+
- [Serialization](#serialization)
|
|
36
37
|
- [Official Storage Adapters](#official-storage-adapters)
|
|
37
38
|
- [Third-party Storage Adapters](#third-party-storage-adapters)
|
|
38
39
|
- [Using BigMap to Scale](#using-bigmap-to-scale)
|
|
39
40
|
- [Compression](#compression)
|
|
41
|
+
- [Capability Detection](#capability-detection)
|
|
40
42
|
- [API](#api)
|
|
41
43
|
- [new Keyv([storage-adapter], [options]) or new Keyv([options])](#new-keyvstorage-adapter-options-or-new-keyvoptions)
|
|
42
44
|
- [.namespace](#namespace)
|
|
43
45
|
- [.ttl](#ttl)
|
|
44
46
|
- [.store](#store)
|
|
45
|
-
- [.
|
|
46
|
-
- [.deserialize](#deserialize)
|
|
47
|
+
- [.serialization](#serialization-1)
|
|
47
48
|
- [.compression](#compression)
|
|
48
49
|
- [.useKeyPrefix](#usekeyprefix)
|
|
50
|
+
- [.emitErrors](#emiterrors)
|
|
51
|
+
- [.throwOnErrors](#throwonerrors)
|
|
49
52
|
- [.stats](#stats)
|
|
53
|
+
- [.sanitize](#sanitize)
|
|
50
54
|
- [Keyv Instance](#keyv-instance)
|
|
51
55
|
- [.set(key, value, [ttl])](#setkey-value-ttl)
|
|
52
56
|
- [.setMany(entries)](#setmanyentries)
|
|
@@ -54,9 +58,14 @@ There are a few existing modules similar to Keyv, however Keyv is different beca
|
|
|
54
58
|
- [.getMany(keys, [options])](#getmanykeys-options)
|
|
55
59
|
- [.getRaw(key)](#getrawkey)
|
|
56
60
|
- [.getManyRaw(keys)](#getmanyrawkeys)
|
|
61
|
+
- [.setRaw(key, value)](#setrawkey-value)
|
|
62
|
+
- [.setManyRaw(entries)](#setmanyrawentries)
|
|
57
63
|
- [.delete(key)](#deletekey)
|
|
58
64
|
- [.deleteMany(keys)](#deletemanykeys)
|
|
59
65
|
- [.clear()](#clear)
|
|
66
|
+
- [.has(key)](#haskey)
|
|
67
|
+
- [.hasMany(keys)](#hasmanykeys)
|
|
68
|
+
- [.disconnect()](#disconnect)
|
|
60
69
|
- [.iterator()](#iterator)
|
|
61
70
|
- [Bun Support](#bun-support)
|
|
62
71
|
- [How to Contribute](#how-to-contribute)
|
|
@@ -219,6 +228,10 @@ PRE_GET_MANY_RAW
|
|
|
219
228
|
POST_GET_MANY_RAW
|
|
220
229
|
PRE_SET
|
|
221
230
|
POST_SET
|
|
231
|
+
PRE_SET_RAW
|
|
232
|
+
POST_SET_RAW
|
|
233
|
+
PRE_SET_MANY_RAW
|
|
234
|
+
POST_SET_MANY_RAW
|
|
222
235
|
PRE_DELETE
|
|
223
236
|
POST_DELETE
|
|
224
237
|
```
|
|
@@ -288,41 +301,80 @@ Now this key will have prefix- added to it before it is set.
|
|
|
288
301
|
In `PRE_DELETE` and `POST_DELETE` hooks, the value could be a single item or an `Array`. This is based on the fact that `delete` can accept a single key or an `Array` of keys.
|
|
289
302
|
|
|
290
303
|
|
|
291
|
-
#
|
|
304
|
+
# Serialization
|
|
292
305
|
|
|
293
|
-
Keyv uses
|
|
306
|
+
By default, Keyv uses its built-in `KeyvJsonSerializer` — a JSON-based serializer with support for `Buffer` and `BigInt` types. This works out of the box with all storage adapters.
|
|
294
307
|
|
|
295
|
-
|
|
308
|
+
## Official Serializers
|
|
309
|
+
|
|
310
|
+
In addition to the built-in serializer, Keyv offers two official serialization packages:
|
|
311
|
+
|
|
312
|
+
### SuperJSON
|
|
313
|
+
|
|
314
|
+
[`@keyv/serialize-superjson`](https://github.com/jaredwray/keyv/tree/main/serialization/superjson) supports `Date`, `RegExp`, `Map`, `Set`, `BigInt`, `undefined`, `Error`, and `URL` types.
|
|
296
315
|
|
|
297
316
|
```js
|
|
298
|
-
|
|
317
|
+
import Keyv from 'keyv';
|
|
318
|
+
import { superJsonSerializer } from '@keyv/serialize-superjson'; // using the helper function that does new KeyvSuperJsonSerializer()
|
|
319
|
+
|
|
320
|
+
const keyv = new Keyv({ serialization: superJsonSerializer });
|
|
299
321
|
```
|
|
300
322
|
|
|
301
|
-
|
|
323
|
+
### MessagePack (msgpackr)
|
|
302
324
|
|
|
303
|
-
|
|
325
|
+
[`@keyv/serialize-msgpackr`](https://github.com/jaredwray/keyv/tree/main/serialization/msgpackr) is a binary serializer that supports `Date`, `RegExp`, `Map`, `Set`, `Error`, `undefined`, `NaN`, and `Infinity` types.
|
|
304
326
|
|
|
305
327
|
```js
|
|
306
|
-
|
|
307
|
-
keyv
|
|
308
|
-
|
|
328
|
+
import Keyv from 'keyv';
|
|
329
|
+
import { KeyvMsgpackrSerializer } from '@keyv/serialize-msgpackr';
|
|
330
|
+
|
|
331
|
+
const keyv = new Keyv({ serialization: new KeyvMsgpackrSerializer() });
|
|
309
332
|
```
|
|
310
333
|
|
|
334
|
+
## Custom Serializers
|
|
335
|
+
|
|
336
|
+
You can provide your own serializer by implementing the `KeyvSerializationAdapter` interface with `stringify` and `parse` methods:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
interface KeyvSerializationAdapter {
|
|
340
|
+
stringify: (object: unknown) => string | Promise<string>;
|
|
341
|
+
parse: <T>(data: string) => T | Promise<T>;
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Disabling Serialization
|
|
346
|
+
|
|
347
|
+
You can disable serialization entirely by passing `false`. This stores data as raw objects, which works for in-memory `Map` storage where string conversion is not needed:
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
const keyv = new Keyv({ serialization: false });
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Pipeline
|
|
354
|
+
|
|
355
|
+
When serialization and/or compression are configured, Keyv applies them in this order:
|
|
356
|
+
|
|
357
|
+
**On set:** serialize (optional) → compress (optional) → store
|
|
358
|
+
|
|
359
|
+
**On get:** store → decompress (optional) → parse (optional) → value
|
|
360
|
+
|
|
361
|
+
If compression is configured without a serializer, Keyv will use `JSON.stringify`/`JSON.parse` as a minimum fallback since compression adapters require string input.
|
|
362
|
+
|
|
311
363
|
# Official Storage Adapters
|
|
312
364
|
|
|
313
365
|
The official storage adapters are covered by [over 150 integration tests](https://github.com/jaredwray/keyv/actions/workflows/tests.yaml) to guarantee consistent behaviour. They are lightweight, efficient wrappers over the DB clients making use of indexes and native TTLs where available.
|
|
314
366
|
|
|
315
367
|
Database | Adapter | Native TTL
|
|
316
368
|
---|---|---
|
|
317
|
-
Redis | [@keyv/redis](https://github.com/jaredwray/keyv/tree/
|
|
318
|
-
Valkey | [@keyv/valkey](https://github.com/jaredwray/keyv/tree/
|
|
319
|
-
MongoDB | [@keyv/mongo](https://github.com/jaredwray/keyv/tree/
|
|
320
|
-
SQLite | [@keyv/sqlite](https://github.com/jaredwray/keyv/tree/
|
|
321
|
-
PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/
|
|
322
|
-
MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/
|
|
323
|
-
Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/
|
|
324
|
-
Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/
|
|
325
|
-
DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/
|
|
369
|
+
Redis | [@keyv/redis](https://github.com/jaredwray/keyv/tree/main/storage/redis) | Yes
|
|
370
|
+
Valkey | [@keyv/valkey](https://github.com/jaredwray/keyv/tree/main/storage/valkey) | Yes
|
|
371
|
+
MongoDB | [@keyv/mongo](https://github.com/jaredwray/keyv/tree/main/storage/mongo) | Yes
|
|
372
|
+
SQLite | [@keyv/sqlite](https://github.com/jaredwray/keyv/tree/main/storage/sqlite) | No
|
|
373
|
+
PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/main/storage/postgres) | No
|
|
374
|
+
MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/main/storage/mysql) | No
|
|
375
|
+
Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/main/storage/etcd) | Yes
|
|
376
|
+
Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/main/storage/memcache) | Yes
|
|
377
|
+
DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/main/storage/dynamo) | Yes
|
|
326
378
|
|
|
327
379
|
# Third-party Storage Adapters
|
|
328
380
|
|
|
@@ -411,7 +463,7 @@ await keyv.delete('user:1');
|
|
|
411
463
|
await keyv.clear();
|
|
412
464
|
```
|
|
413
465
|
|
|
414
|
-
For more details about BigMap, see the [@keyv/bigmap documentation](https://github.com/jaredwray/keyv/tree/main/
|
|
466
|
+
For more details about BigMap, see the [@keyv/bigmap documentation](https://github.com/jaredwray/keyv/tree/main/core/bigmap).
|
|
415
467
|
|
|
416
468
|
# Compression
|
|
417
469
|
|
|
@@ -443,26 +495,145 @@ const keyv = new Keyv({ compression: keyvLz4 });
|
|
|
443
495
|
|
|
444
496
|
You can also pass a custom compression function to the `compression` option. Following the pattern of the official compression adapters.
|
|
445
497
|
|
|
446
|
-
## Want to build your own
|
|
498
|
+
## Want to build your own KeyvCompressionAdapter?
|
|
447
499
|
|
|
448
500
|
Great! Keyv is designed to be easily extended. You can build your own compression adapter by following the pattern of the official compression adapters based on this interface:
|
|
449
501
|
|
|
450
502
|
```typescript
|
|
451
|
-
interface
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
async serialize(value: any);
|
|
455
|
-
async deserialize(value: any);
|
|
503
|
+
interface KeyvCompressionAdapter {
|
|
504
|
+
compress(value: any, options?: any): Promise<any>;
|
|
505
|
+
decompress(value: any, options?: any): Promise<any>;
|
|
456
506
|
}
|
|
457
507
|
```
|
|
458
508
|
|
|
459
509
|
In addition to the interface, you can test it with our compression test suite using @keyv/test-suite:
|
|
460
510
|
|
|
461
511
|
```js
|
|
462
|
-
import {
|
|
512
|
+
import { keyvCompressionTests } from '@keyv/test-suite';
|
|
463
513
|
import KeyvGzip from '@keyv/compress-gzip';
|
|
464
514
|
|
|
465
|
-
|
|
515
|
+
keyvCompressionTests(test, new KeyvGzip());
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
# Encryption
|
|
519
|
+
|
|
520
|
+
Keyv provides a `KeyvEncryptionAdapter` interface for encryption support. This interface is available for custom implementations but is not yet wired into the core pipeline.
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
interface KeyvEncryptionAdapter {
|
|
524
|
+
encrypt: (data: string) => string | Promise<string>;
|
|
525
|
+
decrypt: (data: string) => string | Promise<string>;
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
# Capability Detection
|
|
530
|
+
|
|
531
|
+
Keyv exports helper functions to check whether an object implements the expected interface for a Keyv instance, storage adapter, compression adapter, serialization adapter, or encryption adapter. Each function returns an object with boolean flags for every capability, plus a top-level boolean indicating whether the object fully satisfies the interface.
|
|
532
|
+
|
|
533
|
+
```ts
|
|
534
|
+
import {
|
|
535
|
+
detectKeyv,
|
|
536
|
+
detectKeyvStorage,
|
|
537
|
+
detectKeyvCompression,
|
|
538
|
+
detectKeyvSerialization,
|
|
539
|
+
detectKeyvEncryption,
|
|
540
|
+
detectCapabilities,
|
|
541
|
+
} from 'keyv';
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## detectKeyv(obj)
|
|
545
|
+
|
|
546
|
+
Returns a `KeyvCapability` with a boolean for each Keyv method/property. The `keyv` flag is `true` only when **all** capabilities are present.
|
|
547
|
+
|
|
548
|
+
```ts
|
|
549
|
+
import Keyv, { detectKeyv } from 'keyv';
|
|
550
|
+
|
|
551
|
+
detectKeyv(new Keyv());
|
|
552
|
+
// { keyv: true, get: true, set: true, delete: true, clear: true, has: true,
|
|
553
|
+
// getMany: true, setMany: true, deleteMany: true, hasMany: true,
|
|
554
|
+
// disconnect: true, getRaw: true, getManyRaw: true, setRaw: true,
|
|
555
|
+
// setManyRaw: true, hooks: true, stats: true, iterator: true }
|
|
556
|
+
|
|
557
|
+
detectKeyv(new Map());
|
|
558
|
+
// { keyv: false, get: true, set: true, ... }
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## detectKeyvStorage(obj)
|
|
562
|
+
|
|
563
|
+
Returns a `KeyvStorageCapability`. The `keyvStorage` flag is `true` when the object has `get`, `set`, `delete`, `clear`, `has`, `setMany`, `deleteMany`, and `hasMany`.
|
|
564
|
+
|
|
565
|
+
The result also includes:
|
|
566
|
+
- **`mapLike`** — `true` when the object has synchronous `get`, `set`, `delete`, `has`, `entries`, and `keys` methods (i.e. it behaves like a `Map`)
|
|
567
|
+
- **`methodTypes`** — a record mapping each method name to `"sync"`, `"async"`, or `"none"` (not present)
|
|
568
|
+
|
|
569
|
+
```ts
|
|
570
|
+
import { detectKeyvStorage } from 'keyv';
|
|
571
|
+
|
|
572
|
+
// Map-like object
|
|
573
|
+
const result = detectKeyvStorage(new Map());
|
|
574
|
+
result.mapLike; // true
|
|
575
|
+
result.methodTypes.get; // "sync"
|
|
576
|
+
result.methodTypes.set; // "sync"
|
|
577
|
+
|
|
578
|
+
// Async storage adapter
|
|
579
|
+
const adapter = {
|
|
580
|
+
get: async () => {}, set: async () => {}, delete: async () => {},
|
|
581
|
+
clear: async () => {}, has: async () => {}, setMany: async () => {},
|
|
582
|
+
deleteMany: async () => {}, hasMany: async () => {},
|
|
583
|
+
};
|
|
584
|
+
const adapterResult = detectKeyvStorage(adapter);
|
|
585
|
+
adapterResult.keyvStorage; // true
|
|
586
|
+
adapterResult.mapLike; // false
|
|
587
|
+
adapterResult.methodTypes.get; // "async"
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
## detectKeyvCompression(obj)
|
|
591
|
+
|
|
592
|
+
Returns a `KeyvCompressionCapability`. The `keyvCompression` flag is `true` when both `compress` and `decompress` methods are present.
|
|
593
|
+
|
|
594
|
+
```ts
|
|
595
|
+
import { detectKeyvCompression } from 'keyv';
|
|
596
|
+
|
|
597
|
+
detectKeyvCompression({ compress: (d) => d, decompress: (d) => d });
|
|
598
|
+
// { keyvCompression: true, compress: true, decompress: true }
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## detectKeyvSerialization(obj)
|
|
602
|
+
|
|
603
|
+
Returns a `KeyvSerializationCapability`. The `keyvSerialization` flag is `true` when both `stringify` and `parse` methods are present.
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
import { detectKeyvSerialization } from 'keyv';
|
|
607
|
+
|
|
608
|
+
detectKeyvSerialization(JSON);
|
|
609
|
+
// { keyvSerialization: true, stringify: true, parse: true }
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
## detectKeyvEncryption(obj)
|
|
613
|
+
|
|
614
|
+
Returns a `KeyvEncryptionCapability`. The `keyvEncryption` flag is `true` when both `encrypt` and `decrypt` methods are present.
|
|
615
|
+
|
|
616
|
+
```ts
|
|
617
|
+
import { detectKeyvEncryption } from 'keyv';
|
|
618
|
+
|
|
619
|
+
detectKeyvEncryption({ encrypt: (d) => d, decrypt: (d) => d });
|
|
620
|
+
// { keyvEncryption: true, encrypt: true, decrypt: true }
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
## detectCapabilities(obj, spec)
|
|
624
|
+
|
|
625
|
+
A generic helper for building your own capability checks. Accepts a `CapabilitySpec` describing which methods and properties to look for, which are required, and the name of the composite boolean key.
|
|
626
|
+
|
|
627
|
+
```ts
|
|
628
|
+
import { detectCapabilities } from 'keyv';
|
|
629
|
+
|
|
630
|
+
const result = detectCapabilities(myObject, {
|
|
631
|
+
methods: ['read', 'write'],
|
|
632
|
+
properties: ['name'],
|
|
633
|
+
requiredKeys: ['read', 'write', 'name'],
|
|
634
|
+
compositeKey: 'isValid',
|
|
635
|
+
});
|
|
636
|
+
// { isValid: true/false, read: true/false, write: true/false, name: true/false }
|
|
466
637
|
```
|
|
467
638
|
|
|
468
639
|
# API
|
|
@@ -478,16 +649,14 @@ The Keyv instance is also an `EventEmitter` that will emit an `'error'` event if
|
|
|
478
649
|
Type: `KeyvStorageAdapter`<br />
|
|
479
650
|
Default: `undefined`
|
|
480
651
|
|
|
481
|
-
The
|
|
482
|
-
|
|
483
|
-
Merged into the options object as options.uri.
|
|
652
|
+
The storage adapter instance to be used by Keyv.
|
|
484
653
|
|
|
485
654
|
## .namespace
|
|
486
655
|
|
|
487
656
|
Type: `String`
|
|
488
|
-
Default: `
|
|
657
|
+
Default: `undefined`
|
|
489
658
|
|
|
490
|
-
This is the namespace for the current instance. When you set it it will set it also on the storage adapter.
|
|
659
|
+
This is the namespace for the current instance. When you set it it will set it also on the storage adapter.
|
|
491
660
|
|
|
492
661
|
## options
|
|
493
662
|
|
|
@@ -498,7 +667,7 @@ The options object is also passed through to the storage adapter. Check your sto
|
|
|
498
667
|
## options.namespace
|
|
499
668
|
|
|
500
669
|
Type: `String`<br />
|
|
501
|
-
Default: `
|
|
670
|
+
Default: `undefined`
|
|
502
671
|
|
|
503
672
|
Namespace for the current instance.
|
|
504
673
|
|
|
@@ -511,24 +680,17 @@ Default TTL. Can be overridden by specififying a TTL on `.set()`.
|
|
|
511
680
|
|
|
512
681
|
## options.compression
|
|
513
682
|
|
|
514
|
-
Type:
|
|
683
|
+
Type: `KeyvCompressionAdapter`<br />
|
|
515
684
|
Default: `undefined`
|
|
516
685
|
|
|
517
686
|
Compression package to use. See [Compression](#compression) for more details.
|
|
518
687
|
|
|
519
|
-
## options.
|
|
520
|
-
|
|
521
|
-
Type: `Function`<br />
|
|
522
|
-
Default: `JSON.stringify`
|
|
688
|
+
## options.serialization
|
|
523
689
|
|
|
524
|
-
|
|
690
|
+
Type: `KeyvSerializationAdapter | false`<br />
|
|
691
|
+
Default: `KeyvJsonSerializer` (built-in)
|
|
525
692
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
Type: `Function`<br />
|
|
529
|
-
Default: `JSON.parse`
|
|
530
|
-
|
|
531
|
-
A custom deserialization function.
|
|
693
|
+
A serialization object with `stringify` and `parse` methods. Set to `false` to disable serialization and store raw objects. See [Serialization](#serialization) for more details.
|
|
532
694
|
|
|
533
695
|
## options.store
|
|
534
696
|
|
|
@@ -551,7 +713,7 @@ Returns a promise which resolves to `true`.
|
|
|
551
713
|
|
|
552
714
|
## .setMany(entries)
|
|
553
715
|
|
|
554
|
-
Set multiple values using
|
|
716
|
+
Set multiple values using `KeyvEntry<Value>` objects (`{ key: string, value: Value, ttl?: number }`). The `Value` type is inferred from the entries provided.
|
|
555
717
|
|
|
556
718
|
## .get(key, [options])
|
|
557
719
|
|
|
@@ -561,24 +723,50 @@ Returns a promise which resolves to the retrieved value.
|
|
|
561
723
|
|
|
562
724
|
Returns a promise which resolves to an array of retrieved values.
|
|
563
725
|
|
|
564
|
-
|
|
726
|
+
## .getRaw(key)
|
|
565
727
|
|
|
566
|
-
|
|
567
|
-
Default: `false`
|
|
728
|
+
Returns a promise which resolves to the raw stored data for the key or `undefined` if the key does not exist or is expired.
|
|
568
729
|
|
|
569
|
-
|
|
730
|
+
## .getManyRaw(keys)
|
|
570
731
|
|
|
571
|
-
|
|
732
|
+
Returns a promise which resolves to an array of raw stored data for the keys or `undefined` if the key does not exist or is expired.
|
|
572
733
|
|
|
573
|
-
|
|
734
|
+
## .setRaw(key, value)
|
|
574
735
|
|
|
575
|
-
|
|
736
|
+
Sets a raw value in the store without wrapping. This is the write-side counterpart to `.getRaw()`. The caller provides the `KeyvValue` envelope directly (`{ value, expires? }`) instead of having Keyv wrap it. The envelope is still serialized before storing so that all read paths (`get()`, `getRaw()`, `has()`, `getManyRaw()`) work consistently. If you need TTL-based expiration, set `expires` on the value directly (e.g. `{ value: 'bar', expires: Date.now() + 60000 }`). The store-level TTL is derived automatically from `value.expires`.
|
|
576
737
|
|
|
577
|
-
Returns a promise which resolves to
|
|
738
|
+
Returns a promise which resolves to `true`.
|
|
578
739
|
|
|
579
|
-
|
|
740
|
+
```js
|
|
741
|
+
const keyv = new Keyv();
|
|
580
742
|
|
|
581
|
-
|
|
743
|
+
// Set a raw value with expiration
|
|
744
|
+
await keyv.setRaw('foo', { value: 'bar', expires: Date.now() + 60000 });
|
|
745
|
+
|
|
746
|
+
// Set a raw value without expiration
|
|
747
|
+
await keyv.setRaw('foo', { value: 'bar' });
|
|
748
|
+
|
|
749
|
+
// Round-trip: get raw, modify, set raw
|
|
750
|
+
const raw = await keyv.getRaw('foo');
|
|
751
|
+
if (raw) {
|
|
752
|
+
raw.value = 'updated';
|
|
753
|
+
await keyv.setRaw('foo', raw);
|
|
754
|
+
}
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
## .setManyRaw(entries)
|
|
758
|
+
|
|
759
|
+
Sets many raw values in the store without wrapping. Each entry should have a `key` and a `value` (`KeyvValue` envelope). Like `setRaw()`, the envelopes are serialized before storing and the store-level TTL is derived from each entry's `value.expires`.
|
|
760
|
+
|
|
761
|
+
Returns a promise which resolves to an array of booleans.
|
|
762
|
+
|
|
763
|
+
```js
|
|
764
|
+
const keyv = new Keyv();
|
|
765
|
+
await keyv.setManyRaw([
|
|
766
|
+
{ key: 'foo', value: { value: 'bar' } },
|
|
767
|
+
{ key: 'baz', value: { value: 'qux', expires: Date.now() + 60000 } },
|
|
768
|
+
]);
|
|
769
|
+
```
|
|
582
770
|
|
|
583
771
|
## .delete(key)
|
|
584
772
|
|
|
@@ -588,7 +776,7 @@ Returns a promise which resolves to `true` if the key existed, `false` if not.
|
|
|
588
776
|
|
|
589
777
|
## .deleteMany(keys)
|
|
590
778
|
Deletes multiple entries.
|
|
591
|
-
Returns a promise which resolves to
|
|
779
|
+
Returns a promise which resolves to `true` if all keys were deleted successfully, `false` otherwise.
|
|
592
780
|
|
|
593
781
|
## .clear()
|
|
594
782
|
|
|
@@ -596,19 +784,56 @@ Delete all entries in the current namespace.
|
|
|
596
784
|
|
|
597
785
|
Returns a promise which is resolved when the entries have been cleared.
|
|
598
786
|
|
|
787
|
+
## .has(key)
|
|
788
|
+
|
|
789
|
+
Check if a key exists in the store.
|
|
790
|
+
|
|
791
|
+
Returns a promise which resolves to `true` if the key exists, `false` if not.
|
|
792
|
+
|
|
793
|
+
```js
|
|
794
|
+
await keyv.set('foo', 'bar');
|
|
795
|
+
await keyv.has('foo'); // true
|
|
796
|
+
await keyv.has('unknown'); // false
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
## .hasMany(keys)
|
|
800
|
+
|
|
801
|
+
Check if multiple keys exist in the store.
|
|
802
|
+
|
|
803
|
+
Returns a promise which resolves to an array of booleans indicating if each key exists.
|
|
804
|
+
|
|
805
|
+
```js
|
|
806
|
+
await keyv.set('foo', 'bar');
|
|
807
|
+
await keyv.hasMany(['foo', 'unknown']); // [true, false]
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
## .disconnect()
|
|
811
|
+
|
|
812
|
+
Disconnect from the storage adapter. Emits a `'disconnect'` event.
|
|
813
|
+
|
|
814
|
+
Returns a promise which is resolved when the connection has been closed.
|
|
815
|
+
|
|
816
|
+
```js
|
|
817
|
+
await keyv.disconnect();
|
|
818
|
+
```
|
|
819
|
+
|
|
599
820
|
## .iterator()
|
|
600
821
|
|
|
601
|
-
Iterate over all
|
|
822
|
+
Iterate over all key-value pairs in the store. Automatically deserializes values, filters out expired entries, and deletes them.
|
|
602
823
|
|
|
603
|
-
Returns
|
|
824
|
+
Returns an async generator that yields `[key, value]` pairs. Use with `for await...of`:
|
|
604
825
|
|
|
605
826
|
```js
|
|
606
|
-
|
|
607
|
-
for await (const [key, value] of this.keyv.iterator()) {
|
|
827
|
+
for await (const [key, value] of keyv.iterator()) {
|
|
608
828
|
console.log(key, value);
|
|
609
|
-
}
|
|
829
|
+
}
|
|
610
830
|
```
|
|
611
831
|
|
|
832
|
+
The iterator works with any storage backend:
|
|
833
|
+
- **Map stores**: iterates using the built-in `Symbol.iterator`
|
|
834
|
+
- **Storage adapters**: delegates to the adapter's `iterator()` method (e.g., Redis SCAN, SQL cursor)
|
|
835
|
+
- **Unsupported stores**: emits an `error` event if the store does not support iteration
|
|
836
|
+
|
|
612
837
|
# API - Properties
|
|
613
838
|
|
|
614
839
|
## .namespace
|
|
@@ -626,7 +851,7 @@ here is an example of setting the namespace to `undefined`:
|
|
|
626
851
|
|
|
627
852
|
```js
|
|
628
853
|
const keyv = new Keyv();
|
|
629
|
-
console.log(keyv.namespace); //
|
|
854
|
+
console.log(keyv.namespace); // undefined which is default
|
|
630
855
|
keyv.namespace = undefined;
|
|
631
856
|
console.log(keyv.namespace); // undefined
|
|
632
857
|
```
|
|
@@ -660,40 +885,26 @@ keyv.store = new KeyvSqlite('sqlite://path/to/database.sqlite');
|
|
|
660
885
|
console.log(keyv.store instanceof KeyvSqlite); // true
|
|
661
886
|
```
|
|
662
887
|
|
|
663
|
-
## .
|
|
664
|
-
|
|
665
|
-
Type: `Function`<br />
|
|
666
|
-
Default: `JSON.stringify`
|
|
667
|
-
|
|
668
|
-
A custom serialization function used for any value.
|
|
669
|
-
|
|
670
|
-
```js
|
|
671
|
-
const keyv = new Keyv();
|
|
672
|
-
console.log(keyv.serialize); // JSON.stringify
|
|
673
|
-
keyv.serialize = value => value.toString();
|
|
674
|
-
console.log(keyv.serialize); // value => value.toString()
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
## .deserialize
|
|
888
|
+
## .serialization
|
|
678
889
|
|
|
679
|
-
Type: `
|
|
680
|
-
Default: `
|
|
890
|
+
Type: `KeyvSerializationAdapter | false | undefined`<br />
|
|
891
|
+
Default: `KeyvJsonSerializer` (built-in)
|
|
681
892
|
|
|
682
|
-
|
|
893
|
+
The serialization object used for storing and retrieving values. Set to `false` or `undefined` to disable serialization and use raw object pass-through. See [Serialization](#serialization) for more details.
|
|
683
894
|
|
|
684
895
|
```js
|
|
685
896
|
const keyv = new Keyv();
|
|
686
|
-
console.log(keyv.
|
|
687
|
-
keyv.
|
|
688
|
-
console.log(keyv.
|
|
897
|
+
console.log(keyv.serialization); // KeyvJsonSerializer (default)
|
|
898
|
+
keyv.serialization = false; // disable serialization
|
|
899
|
+
console.log(keyv.serialization); // undefined
|
|
689
900
|
```
|
|
690
901
|
|
|
691
902
|
## .compression
|
|
692
903
|
|
|
693
|
-
Type: `
|
|
904
|
+
Type: `KeyvCompressionAdapter`<br />
|
|
694
905
|
Default: `undefined`
|
|
695
906
|
|
|
696
|
-
|
|
907
|
+
This is the compression package to use. See [Compression](#compression) for more details. If it is undefined it will not compress (default).
|
|
697
908
|
|
|
698
909
|
```js
|
|
699
910
|
import KeyvGzip from '@keyv/compress-gzip';
|
|
@@ -734,6 +945,20 @@ await keyv.get('foo'); // 'bar'
|
|
|
734
945
|
await keyv.clear();
|
|
735
946
|
```
|
|
736
947
|
|
|
948
|
+
## .emitErrors
|
|
949
|
+
|
|
950
|
+
Type: `Boolean`<br />
|
|
951
|
+
Default: `true`
|
|
952
|
+
|
|
953
|
+
If set to `true`, Keyv will emit an `'error'` event when an error occurs. Set to `false` to suppress error events.
|
|
954
|
+
|
|
955
|
+
```js
|
|
956
|
+
const keyv = new Keyv({ emitErrors: false });
|
|
957
|
+
console.log(keyv.emitErrors); // false
|
|
958
|
+
keyv.emitErrors = true;
|
|
959
|
+
console.log(keyv.emitErrors); // true
|
|
960
|
+
```
|
|
961
|
+
|
|
737
962
|
## .throwOnErrors
|
|
738
963
|
|
|
739
964
|
Type: `Boolean`<br />
|
|
@@ -763,10 +988,10 @@ const keyv = new Keyv({ store: keyvRedis, throwOnErrors: true });
|
|
|
763
988
|
What this does is it only throw on connection errors with the Redis client.
|
|
764
989
|
|
|
765
990
|
## .stats
|
|
766
|
-
Type: `
|
|
767
|
-
Default: `
|
|
991
|
+
Type: `KeyvStats`<br />
|
|
992
|
+
Default: `KeyvStats` instance with `enabled: false`
|
|
768
993
|
|
|
769
|
-
The stats property provides access to statistics tracking for cache operations. When enabled via the `stats` option during initialization, it tracks hits, misses, sets, deletes, and errors.
|
|
994
|
+
The stats property provides access to statistics tracking for cache operations. When enabled via the `stats` option during initialization, it tracks hits, misses, sets, deletes, and errors. It also maintains LRU-bounded per-key frequency maps for each event type, allowing you to see which keys are accessed most.
|
|
770
995
|
|
|
771
996
|
### Enabling Stats:
|
|
772
997
|
```js
|
|
@@ -775,12 +1000,21 @@ console.log(keyv.stats.enabled); // true
|
|
|
775
1000
|
```
|
|
776
1001
|
|
|
777
1002
|
### Available Statistics:
|
|
1003
|
+
|
|
1004
|
+
**Aggregate counters:**
|
|
778
1005
|
- `hits`: Number of successful cache retrievals
|
|
779
1006
|
- `misses`: Number of failed cache retrievals
|
|
780
1007
|
- `sets`: Number of set operations
|
|
781
1008
|
- `deletes`: Number of delete operations
|
|
782
1009
|
- `errors`: Number of errors encountered
|
|
783
1010
|
|
|
1011
|
+
**Per-key LRU frequency maps** (each capped at `maxEntries`, default 1000):
|
|
1012
|
+
- `hitKeys`: `Map<string, number>` — key to hit count
|
|
1013
|
+
- `missKeys`: `Map<string, number>` — key to miss count
|
|
1014
|
+
- `setKeys`: `Map<string, number>` — key to set count
|
|
1015
|
+
- `deleteKeys`: `Map<string, number>` — key to delete count
|
|
1016
|
+
- `errorKeys`: `Map<string, number>` — key to error count
|
|
1017
|
+
|
|
784
1018
|
### Accessing Stats:
|
|
785
1019
|
```js
|
|
786
1020
|
const keyv = new Keyv({ stats: true });
|
|
@@ -794,23 +1028,104 @@ console.log(keyv.stats.hits); // 1
|
|
|
794
1028
|
console.log(keyv.stats.misses); // 1
|
|
795
1029
|
console.log(keyv.stats.sets); // 1
|
|
796
1030
|
console.log(keyv.stats.deletes); // 1
|
|
1031
|
+
|
|
1032
|
+
// Per-key frequency maps
|
|
1033
|
+
console.log(keyv.stats.hitKeys.get('foo')); // 1
|
|
1034
|
+
console.log(keyv.stats.missKeys.get('nonexistent')); // 1
|
|
797
1035
|
```
|
|
798
1036
|
|
|
799
1037
|
### Resetting Stats:
|
|
800
1038
|
```js
|
|
801
1039
|
keyv.stats.reset();
|
|
802
1040
|
console.log(keyv.stats.hits); // 0
|
|
1041
|
+
console.log(keyv.stats.hitKeys.size); // 0
|
|
803
1042
|
```
|
|
804
1043
|
|
|
805
1044
|
### Manual Control:
|
|
806
|
-
You can also manually enable/disable stats tracking at runtime:
|
|
1045
|
+
You can also manually enable/disable stats tracking at runtime. Disabling stats will automatically unsubscribe from events:
|
|
807
1046
|
```js
|
|
808
1047
|
const keyv = new Keyv({ stats: false });
|
|
809
1048
|
keyv.stats.enabled = true; // Enable stats tracking
|
|
810
1049
|
// ... perform operations ...
|
|
811
|
-
keyv.stats.enabled = false; // Disable stats tracking
|
|
1050
|
+
keyv.stats.enabled = false; // Disable stats tracking and unsubscribe
|
|
812
1051
|
```
|
|
813
1052
|
|
|
1053
|
+
### Standalone Usage:
|
|
1054
|
+
You can create a `KeyvStats` instance independently and subscribe it to a Keyv instance:
|
|
1055
|
+
```js
|
|
1056
|
+
import { KeyvStats } from 'keyv';
|
|
1057
|
+
|
|
1058
|
+
const stats = new KeyvStats({ enabled: true, maxEntries: 500, emitter: keyv });
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
## .sanitize
|
|
1062
|
+
Type: `boolean | KeyvSanitizeOptions`<br />
|
|
1063
|
+
Default: `false`
|
|
1064
|
+
|
|
1065
|
+
Detects and strips dangerous patterns from keys and namespaces to protect against SQL injection, MongoDB operator injection, path traversal, and control character attacks. Harmless characters like quotes, slashes, and dollar signs pass through unchanged — only dangerous *patterns* are stripped.
|
|
1066
|
+
|
|
1067
|
+
Results are cached in an LRU cache (10,000 entries) for fast repeated lookups.
|
|
1068
|
+
|
|
1069
|
+
### Pattern Categories
|
|
1070
|
+
|
|
1071
|
+
| Category | Patterns Stripped | Purpose |
|
|
1072
|
+
|----------|------------------|---------|
|
|
1073
|
+
| `sql` | `;` `--` `/*` | Prevents SQL injection |
|
|
1074
|
+
| `mongo` | leading `$`, `{$` sequences | Prevents MongoDB operator injection |
|
|
1075
|
+
| `escape` | `\0` `\r` `\n` | Strips null bytes, CRLF injection |
|
|
1076
|
+
| `path` | `../` `..\` | Prevents path traversal |
|
|
1077
|
+
|
|
1078
|
+
### Targets
|
|
1079
|
+
|
|
1080
|
+
| Target | Default | Description |
|
|
1081
|
+
|--------|---------|-------------|
|
|
1082
|
+
| `keys` | `true` (when enabled) | Sanitize keys on all operations |
|
|
1083
|
+
| `namespace` | `true` (when enabled) | Sanitize namespace on construction and setter |
|
|
1084
|
+
|
|
1085
|
+
### Usage
|
|
1086
|
+
|
|
1087
|
+
Enable all sanitization:
|
|
1088
|
+
```js
|
|
1089
|
+
const keyv = new Keyv({ sanitize: true });
|
|
1090
|
+
await keyv.set("test; DROP TABLE", "value");
|
|
1091
|
+
// Key is stored as "test DROP TABLE"
|
|
1092
|
+
|
|
1093
|
+
// Harmless characters pass through
|
|
1094
|
+
await keyv.set("user's-data", "value");
|
|
1095
|
+
// Key is stored as "user's-data" (unchanged)
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
Disable all sanitization (default):
|
|
1099
|
+
```js
|
|
1100
|
+
const keyv = new Keyv({ sanitize: false });
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
Granular control per target and category:
|
|
1104
|
+
```js
|
|
1105
|
+
const keyv = new Keyv({
|
|
1106
|
+
sanitize: {
|
|
1107
|
+
keys: { sql: true, mongo: false }, // only SQL patterns on keys
|
|
1108
|
+
namespace: { path: true, sql: false }, // only path patterns on namespace
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
Disable namespace sanitization only:
|
|
1114
|
+
```js
|
|
1115
|
+
const keyv = new Keyv({
|
|
1116
|
+
sanitize: { keys: true, namespace: false }
|
|
1117
|
+
});
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
Change at runtime:
|
|
1121
|
+
```js
|
|
1122
|
+
keyv.sanitize = false; // disable
|
|
1123
|
+
keyv.sanitize = true; // enable all
|
|
1124
|
+
keyv.sanitize = { keys: { sql: true, mongo: false } }; // granular
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
Sanitization is applied to all key-accepting methods: `get`, `set`, `delete`, `has`, `getMany`, `setMany`, `deleteMany`, `hasMany`, `getRaw`, `getManyRaw`, `setRaw`, and `setManyRaw`. Namespace sanitization is applied at construction and when the `namespace` setter is used.
|
|
1128
|
+
|
|
814
1129
|
# Bun Support
|
|
815
1130
|
|
|
816
1131
|
We make a best effort to support [Bun](https://bun.sh/) as a runtime. Our default and primary target is Node.js, but we run tests against Bun to ensure compatibility. If you encounter any issues while using Keyv with Bun, please report them at our [GitHub issues](https://github.com/jaredwray/keyv/issues).
|