Sign In

keyv

Package Overview
Dependencies
Maintainers
2
Versions
86
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

keyv - npm Package Compare versions

Comparing version
6.0.0-alpha.3
to
6.0.0-beta.1
+1351
dist/index.d.mts
import { Hookified, IEventEmitter } from "hookified";
//#region src/capabilities.d.ts
type MethodType = "sync" | "async" | "none";
type KeyvStorageMethod = {
exists: boolean;
methodType: MethodType;
};
declare const keyvMethodNames: readonly ["get", "set", "delete", "clear", "has", "getMany", "setMany", "deleteMany", "hasMany", "disconnect", "getRaw", "getManyRaw", "setRaw", "setManyRaw", "iterator"];
declare const keyvPropertyNames: readonly ["hooks", "stats"];
type KeyvMethods = Record<(typeof keyvMethodNames)[number], KeyvStorageMethod>;
type KeyvProperties = Record<(typeof keyvPropertyNames)[number], boolean>;
type KeyvCapability = {
compatible: boolean;
methods: KeyvMethods;
properties: KeyvProperties;
};
declare const keyvStorageMethodNames: readonly ["get", "getMany", "has", "hasMany", "set", "setMany", "delete", "deleteMany", "clear", "disconnect", "iterator"];
type KeyvStorageMethods = Record<(typeof keyvStorageMethodNames)[number], KeyvStorageMethod>;
type KeyvStorageCapability = {
compatible: boolean;
store: "mapLike" | "keyvStorage" | "asyncMap" | "none";
methods: KeyvStorageMethods;
};
declare const keyvCompressionMethodNames: readonly ["compress", "decompress"];
type KeyvCompressionMethods = Record<(typeof keyvCompressionMethodNames)[number], KeyvStorageMethod>;
type KeyvCompressionCapability = {
compatible: boolean;
methods: KeyvCompressionMethods;
};
declare const keyvSerializationMethodNames: readonly ["stringify", "parse"];
type KeyvSerializationMethods = Record<(typeof keyvSerializationMethodNames)[number], KeyvStorageMethod>;
type KeyvSerializationCapability = {
compatible: boolean;
methods: KeyvSerializationMethods;
};
declare const keyvEncryptionMethodNames: readonly ["encrypt", "decrypt"];
type KeyvEncryptionMethods = Record<(typeof keyvEncryptionMethodNames)[number], KeyvStorageMethod>;
type KeyvEncryptionCapability = {
compatible: boolean;
methods: KeyvEncryptionMethods;
};
/**
* Detect whether an object implements the full Keyv interface
* @param obj - The object to check
* @returns A {@link KeyvCapability} where `compatible` is `true` only when all required capabilities are present
* @example
* ```typescript
* import Keyv, { detectKeyv } from 'keyv';
*
* const result = detectKeyv(new Keyv());
* result.compatible; // true — all capabilities present
* result.methods.get.exists; // true
* result.methods.get.methodType; // "async"
*
* const partial = detectKeyv(new Map());
* partial.compatible; // false — missing getMany, setMany, hooks, stats, etc.
* partial.methods.get.exists; // true
* ```
*/
declare function detectKeyv(obj: unknown): KeyvCapability;
/**
* Detect whether an object implements the Keyv storage adapter interface
* @param obj - The object to check
* @returns A {@link KeyvStorageCapability} where:
* - `compatible` is `true` when the object is a valid storage adapter (`"keyvStorage"`, `"mapLike"`, or `"asyncMap"`)
* - `store` indicates the detected store type: `"keyvStorage"`, `"mapLike"`, `"asyncMap"`, or `"none"`
* - `methods` maps each method name to `{ exists, methodType }`
* @example
* ```typescript
* import { detectKeyvStorage } from 'keyv';
*
* const map = detectKeyvStorage(new Map());
* map.compatible; // true
* map.store; // "mapLike"
* map.methods.get.exists; // true
* map.methods.get.methodType; // "sync"
*
* const adapter = detectKeyvStorage(asyncAdapter);
* adapter.compatible; // true
* adapter.store; // "keyvStorage"
* adapter.methods.get.methodType; // "async"
* ```
*/
declare function detectKeyvStorage(obj: unknown): KeyvStorageCapability;
/**
* Detect whether an object implements the Keyv compression adapter interface
* @param obj - The object to check
* @returns A {@link KeyvCompressionCapability} where `compatible` is `true` when both `compress` and `decompress` methods are present
* @example
* ```typescript
* import { detectKeyvCompression } from 'keyv';
*
* detectKeyvCompression({ compress: (d) => d, decompress: (d) => d });
* // { compatible: true, methods: { compress: { exists: true, methodType: "sync" }, decompress: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvCompression(obj: unknown): KeyvCompressionCapability;
/**
* Detect whether an object implements the Keyv serialization adapter interface
* @param obj - The object to check
* @returns A {@link KeyvSerializationCapability} where `compatible` is `true` when both `stringify` and `parse` methods are present
* @example
* ```typescript
* import { detectKeyvSerialization } from 'keyv';
*
* detectKeyvSerialization(JSON);
* // { compatible: true, methods: { stringify: { exists: true, methodType: "sync" }, parse: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvSerialization(obj: unknown): KeyvSerializationCapability;
/**
* Detect whether an object implements the Keyv encryption adapter interface
* @param obj - The object to check
* @returns A {@link KeyvEncryptionCapability} where `compatible` is `true` when both `encrypt` and `decrypt` methods are present
* @example
* ```typescript
* import { detectKeyvEncryption } from 'keyv';
*
* detectKeyvEncryption({ encrypt: (d) => d, decrypt: (d) => d });
* // { compatible: true, methods: { encrypt: { exists: true, methodType: "sync" }, decrypt: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvEncryption(obj: unknown): KeyvEncryptionCapability;
//#endregion
//#region src/sanitize.d.ts
/**
* Which dangerous-pattern categories to detect and strip.
* Each defaults to `true` when the parent scope is enabled.
*/
type KeyvSanitizePatterns = {
/**
* Detect and strip SQL injection patterns: semicolons (`;`), SQL comments (`--` and `/*`).
* @default false
*/
sql: boolean;
/**
* Detect and strip MongoDB operator patterns: leading `$`, `{$` sequences.
* @default false
*/
mongo: boolean;
/**
* Detect and strip dangerous control sequences: null bytes (`\0`), carriage returns (`\r`), newlines (`\n`).
* @default false
*/
escape: boolean;
/**
* Detect and strip path traversal patterns: `../` and `..\\` sequences.
* @default false
*/
path: boolean;
};
/**
* Options for configuring sanitization pattern categories.
* All categories default to `true` when the parent scope is enabled.
*/
type KeyvSanitizePatternsOptions = {
/**
* Detect and strip SQL injection patterns: semicolons (`;`), SQL comments (`--` and `/*`).
* @default true
*/
sql?: boolean;
/**
* Detect and strip MongoDB operator patterns: leading `$`, `{$` sequences.
* @default true
*/
mongo?: boolean;
/**
* Detect and strip dangerous control sequences: null bytes (`\0`), carriage returns (`\r`), newlines (`\n`).
* @default true
*/
escape?: boolean;
/**
* Detect and strip path traversal patterns: `../` and `..\\` sequences.
* @default true
*/
path?: boolean;
};
/**
* Controls what gets sanitized and with which patterns.
*/
type KeyvSanitizeOptions = {
/**
* Sanitize keys. Pass `true` for all pattern categories, `false` to skip,
* or a `KeyvSanitizePatternOptions` object for granular control.
* @default false
*/
keys?: boolean | KeyvSanitizePatternsOptions;
/**
* Sanitize namespace strings. Pass `true` for all pattern categories, `false` to skip,
* or a `KeyvSanitizePatternOptions` object for granular control.
* @default false
*/
namespace?: boolean | KeyvSanitizePatternsOptions;
};
/**
* Adapter interface for key and namespace sanitization.
* Implement this to provide custom sanitization logic to Keyv.
*/
type KeyvSanitizeAdapter = {
/** Whether any sanitization is currently enabled. */readonly enabled: boolean; /** The key sanitization pattern configuration. */
readonly keys: KeyvSanitizePatterns; /** The namespace sanitization pattern configuration. */
readonly namespace: KeyvSanitizePatterns; /** Sanitize a single key. */
cleanKey(key: string): string; /** Sanitize an array of keys. */
cleanKeys(keys: string[]): string[]; /** Sanitize a namespace string. */
cleanNamespace(ns: string): string;
};
/**
* Encapsulates key and namespace sanitization with an LRU result cache.
*/
declare class KeyvSanitize implements KeyvSanitizeAdapter {
private _keys;
private _namespace;
private _keyPatterns;
private _namespacePatterns;
private _enabled;
private _cacheKeys;
private _cacheNamespaces;
private _cacheMax;
constructor(options?: KeyvSanitizeOptions);
/**
* The key sanitization pattern configuration.
*/
get keys(): KeyvSanitizePatterns;
/**
* Whether any sanitization pattern (keys or namespace) is enabled.
*/
get enabled(): boolean;
/**
* The namespace sanitization pattern configuration.
*/
get namespace(): KeyvSanitizePatterns;
/**
* Update the sanitization configuration. Recompiles patterns and clears the cache.
*/
updateOptions(options: KeyvSanitizeOptions): void;
/**
* Sanitize a single key. Uses an LRU cache for repeated lookups.
*/
cleanKey(key: string): string;
/**
* Sanitize an array of keys.
*/
cleanKeys(keys: string[]): string[];
/**
* Sanitize a namespace string. Uses an LRU cache for repeated lookups.
*/
cleanNamespace(ns: string): string;
/**
* Clear the LRU caches.
*/
clearCache(): void;
private resolvePatterns;
}
//#endregion
//#region src/stats.d.ts
/**
* Structure of a telemetry event emitted by Keyv.
*/
type KeyvTelemetryEvent = {
/** The event type (e.g. "hit", "miss", "set", "delete", "error"). */event: string; /** The cache key involved, if applicable. */
key?: string; /** The namespace of the Keyv instance. */
namespace?: string; /** Unix timestamp in milliseconds when the event occurred. */
timestamp: number;
};
type KeyvStatsOptions = {
/**
* Enable or disable stats tracking.
* @default false
*/
enabled?: boolean;
/**
* Maximum number of entries per event-type LRU map.
* @default 1000
*/
maxEntries?: number;
/**
* The event emitter (e.g. a Keyv instance) to subscribe to for telemetry events.
* If provided, KeyvStats will automatically subscribe on construction.
*/
emitter?: IEventEmitter;
};
declare class KeyvStats {
private _hits;
private _misses;
private _sets;
private _deletes;
private _errors;
private _maxEntries;
private _enabled;
private readonly hitKeysMap;
private readonly missKeysMap;
private readonly setKeysMap;
private readonly deleteKeysMap;
private readonly errorKeysMap;
private _emitter?;
private readonly _listeners;
constructor(options?: KeyvStatsOptions);
/**
* Total number of cache hits.
*/
get hits(): number;
/**
* Total number of cache misses.
*/
get misses(): number;
/**
* Total number of cache sets.
*/
get sets(): number;
/**
* Total number of cache deletes.
*/
get deletes(): number;
/**
* Total number of cache errors.
*/
get errors(): number;
/**
* LRU-bounded map of key to hit count.
*/
get hitKeys(): Map<string, number>;
/**
* LRU-bounded map of key to miss count.
*/
get missKeys(): Map<string, number>;
/**
* LRU-bounded map of key to set count.
*/
get setKeys(): Map<string, number>;
/**
* LRU-bounded map of key to delete count.
*/
get deleteKeys(): Map<string, number>;
/**
* LRU-bounded map of key to error count.
*/
get errorKeys(): Map<string, number>;
/**
* Maximum number of entries per event-type LRU map.
* @default 1000
*/
get maxEntries(): number;
/**
* Set the maximum number of entries per event-type LRU map.
* @param {number} value the new maximum entries
*/
set maxEntries(value: number);
/**
* Whether stats tracking is enabled.
* @default false
*/
get enabled(): boolean;
/**
* Enable or disable stats tracking. If false it will unsubscribe from the events
* @param {boolean} value true to enable, false to disable
*/
set enabled(value: boolean);
/**
* Build a composite key from a telemetry event.
* Format: "namespace:key" if namespace is present, otherwise just "key".
*/
buildKeyEventName(event: KeyvTelemetryEvent): string;
/**
* Increment the count for a key in an LRU-bounded map.
* Deletes and re-inserts to maintain LRU order, evicts the oldest entry when full.
*/
incrementKeys(map: Map<string, number>, compositeKey: string): void;
/**
* Subscribe to telemetry events from an emitter (e.g. a Keyv instance).
* Automatically increments the corresponding stat counters and LRU key maps on each event.
* @param {IEventEmitter} emitter the event emitter to subscribe to
*/
subscribe(emitter: IEventEmitter): void;
/**
* Unsubscribe from the currently subscribed emitter, removing all telemetry event listeners.
*/
unsubscribe(): void;
/**
* Reset all counters and LRU key maps to their initial state.
*/
reset(): void;
}
//#endregion
//#region src/types/keyv.d.ts
/**
* A Map or any Map-like object. Used as a flexible input type for stores.
*/
type KeyvMapAny = Map<any, any> | any;
/**
* The envelope structure used to store values in Keyv.
* Wraps the actual value with an optional expiration timestamp.
*/
type KeyvValue<Value> = {
/** The stored value. */value?: Value; /** Absolute expiration timestamp in milliseconds since epoch, or `undefined` for no expiry. */
expires?: number | undefined;
};
/** @deprecated Use `KeyvValue` instead. */
type DeserializedData<Value> = KeyvValue<Value>;
/**
* Events emitted by Keyv for error handling and telemetry.
*/
declare enum KeyvEvents {
/** Emitted when an error occurs in a store operation. */
ERROR = "error",
/** Emitted for informational messages. */
INFO = "info",
/** Emitted for warning messages. */
WARN = "warn",
/** Telemetry: cache hit. */
STAT_HIT = "stat:hit",
/** Telemetry: cache miss. */
STAT_MISS = "stat:miss",
/** Telemetry: value set. */
STAT_SET = "stat:set",
/** Telemetry: value deleted. */
STAT_DELETE = "stat:delete",
/** Telemetry: operation error. */
STAT_ERROR = "stat:error"
}
/**
* Hook names for intercepting Keyv operations.
* Register hooks via `keyv.on(KeyvHooks.BEFORE_SET, callback)` to run logic before/after operations.
*/
declare enum KeyvHooks {
/** @deprecated Use BEFORE_SET instead */
PRE_SET = "preSet",
/** @deprecated Use AFTER_SET instead */
POST_SET = "postSet",
/** @deprecated Use BEFORE_GET instead */
PRE_GET = "preGet",
/** @deprecated Use AFTER_GET instead */
POST_GET = "postGet",
/** @deprecated Use BEFORE_GET_MANY instead */
PRE_GET_MANY = "preGetMany",
/** @deprecated Use AFTER_GET_MANY instead */
POST_GET_MANY = "postGetMany",
/** @deprecated Use BEFORE_GET_RAW instead */
PRE_GET_RAW = "preGetRaw",
/** @deprecated Use AFTER_GET_RAW instead */
POST_GET_RAW = "postGetRaw",
/** @deprecated Use BEFORE_GET_MANY_RAW instead */
PRE_GET_MANY_RAW = "preGetManyRaw",
/** @deprecated Use AFTER_GET_MANY_RAW instead */
POST_GET_MANY_RAW = "postGetManyRaw",
/** @deprecated Use BEFORE_SET_RAW instead */
PRE_SET_RAW = "preSetRaw",
/** @deprecated Use AFTER_SET_RAW instead */
POST_SET_RAW = "postSetRaw",
/** @deprecated Use BEFORE_SET_MANY_RAW instead */
PRE_SET_MANY_RAW = "preSetManyRaw",
/** @deprecated Use AFTER_SET_MANY_RAW instead */
POST_SET_MANY_RAW = "postSetManyRaw",
/** @deprecated Use BEFORE_SET_MANY instead */
PRE_SET_MANY = "preSetMany",
/** @deprecated Use AFTER_SET_MANY instead */
POST_SET_MANY = "postSetMany",
/** @deprecated Use BEFORE_DELETE instead */
PRE_DELETE = "preDelete",
/** @deprecated Use AFTER_DELETE instead */
POST_DELETE = "postDelete",
/** @deprecated Use BEFORE_DELETE_MANY instead */
PRE_DELETE_MANY = "preDeleteMany",
/** @deprecated Use AFTER_DELETE_MANY instead */
POST_DELETE_MANY = "postDeleteMany",
BEFORE_SET = "before:set",
AFTER_SET = "after:set",
BEFORE_GET = "before:get",
AFTER_GET = "after:get",
BEFORE_GET_MANY = "before:getMany",
AFTER_GET_MANY = "after:getMany",
BEFORE_GET_RAW = "before:getRaw",
AFTER_GET_RAW = "after:getRaw",
BEFORE_GET_MANY_RAW = "before:getManyRaw",
AFTER_GET_MANY_RAW = "after:getManyRaw",
BEFORE_SET_RAW = "before:setRaw",
AFTER_SET_RAW = "after:setRaw",
BEFORE_SET_MANY = "before:setMany",
AFTER_SET_MANY = "after:setMany",
BEFORE_SET_MANY_RAW = "before:setManyRaw",
AFTER_SET_MANY_RAW = "after:setManyRaw",
BEFORE_DELETE = "before:delete",
AFTER_DELETE = "after:delete",
BEFORE_DELETE_MANY = "before:deleteMany",
AFTER_DELETE_MANY = "after:deleteMany",
BEFORE_HAS = "before:has",
AFTER_HAS = "after:has",
BEFORE_HAS_MANY = "before:hasMany",
AFTER_HAS_MANY = "after:hasMany",
BEFORE_CLEAR = "before:clear",
AFTER_CLEAR = "after:clear",
BEFORE_DISCONNECT = "before:disconnect",
AFTER_DISCONNECT = "after:disconnect"
}
/**
* Represents a key-value entry with an optional TTL, used for batch operations like `setMany`.
*/
type KeyvEntry<Value = any> = {
/**
* Key to set.
*/
key: string;
/**
* Value to set.
*/
value: Value;
/**
* Time to live in milliseconds.
*/
ttl?: number;
};
/**
* Configuration options for the Keyv constructor.
*/
type KeyvOptions = {
/**
* Namespace for the current instance.
* @default undefined
*/
namespace?: string;
/**
* A custom serialization adapter with stringify and parse methods.
* @default KeyvJsonSerializer (built-in)
*/
serialization?: KeyvSerializationAdapter | false;
/**
* The storage adapter instance to be used by Keyv.
* @default new Map() - in-memory store
*/
store?: KeyvStorageAdapter | Map<any, any> | any;
/**
* Default TTL in milliseconds. Can be overridden by specifying a TTL on `.set()`.
* @default undefined
*/
ttl?: number;
/**
* Enable compression option
* @default undefined
*/
compression?: KeyvCompressionAdapter | any;
/**
* Enable or disable statistics (default is false)
* @default false
*/
stats?: boolean;
/**
* Will throw on all errors if this is enabled to true. By default, errors
* will only throw if there are no listeners to the error event.
* This maps to hookified's `throwOnEmitError` under the hood.
* @default false
*/
throwOnErrors?: boolean;
/**
* Enable sanitization of keys and namespaces by detecting dangerous patterns
* for SQL, MongoDB, or filesystem-based storage backends. Pass a `KeyvSanitizeOptions`
* object for granular control over targets and patterns.
* @default undefined
*/
sanitize?: KeyvSanitizeOptions;
/**
* Enable encryption of stored values. Pass a `KeyvEncryptionAdapter` with
* `encrypt` and `decrypt` methods.
* @default undefined
*/
encryption?: KeyvEncryptionAdapter;
/**
* When true, Keyv checks expiry on get/getMany/has/hasMany at its layer.
* When false (default), trusts the storage adapter to handle expiry.
* @default false
*/
checkExpired?: boolean;
};
//#endregion
//#region src/types/adapters.d.ts
/**
* Adapter interface for custom serialization.
* Implement `stringify` and `parse` to control how values are serialized to/from strings.
*/
type KeyvSerializationAdapter = {
/** Converts a value to a string representation. */stringify: (object: unknown) => string | Promise<string>; /** Parses a string back into its original value. */
parse: <T>(data: string) => T | Promise<T>;
};
/**
* Adapter interface for compression.
* Implement `compress` and `decompress` to add compression to stored values.
*/
type KeyvCompressionAdapter = {
/** Compresses a string value. */compress(value: string): Promise<string>; /** Decompresses a string value back to its original form. */
decompress(value: string): Promise<string>;
};
/**
* Adapter interface for encryption.
* Implement `encrypt` and `decrypt` to add encryption to stored values.
*/
type KeyvEncryptionAdapter = {
/** Encrypts a string value. */encrypt: (data: string) => string | Promise<string>; /** Decrypts a string value back to its original form. */
decrypt: (data: string) => string | Promise<string>;
};
type KeyvStorageGetResult<Value> = KeyvValue<Value> | string | undefined;
/**
* Interface that all Keyv storage adapters must implement.
* Adapters handle the actual persistence of key-value pairs.
*/
type KeyvStorageAdapter = {
/** Optional namespace for key isolation. */namespace?: string | undefined; /** Detected capabilities of the underlying store. */
capabilities?: KeyvStorageCapability; /** Retrieves a value by key. */
get<Value>(key: string): Promise<KeyvStorageGetResult<Value>>; /** Stores a value with a key and optional TTL in milliseconds. */
set(key: string, value: unknown, ttl?: number): Promise<boolean>; /** Stores multiple entries at once. */
setMany<Value>(values: KeyvEntry<Value>[]): Promise<boolean[] | undefined>; /** Deletes a key from the store. */
delete(key: string): Promise<boolean>; /** Clears all entries from the store (respects namespace if set). */
clear(): Promise<void>; /** Checks if a key exists in the store. */
has(key: string): Promise<boolean>; /** Checks if multiple keys exist in the store. */
hasMany(keys: string[]): Promise<boolean[]>; /** Retrieves multiple values by keys. */
getMany<Value>(keys: string[]): Promise<Array<KeyvStorageGetResult<Value | undefined>>>; /** Disconnects from the store and releases resources. */
disconnect?(): Promise<void>; /** Deletes multiple keys from the store. */
deleteMany(key: string[]): Promise<boolean[]>; /** Returns an async iterator over all key-value pairs. */
iterator?<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
} & IEventEmitter;
/**
* @deprecated Use `KeyvStorageAdapter` instead.
*/
type KeyvStoreAdapter = KeyvStorageAdapter;
/**
* @deprecated Use `KeyvCompressionAdapter` instead.
*/
type KeyvCompression = KeyvCompressionAdapter;
//#endregion
//#region src/adapters/bridge.d.ts
/**
* Configuration options for KeyvBridgeAdapter.
*/
type KeyvBridgeAdapterOptions = {
/**
* The namespace to use for keys.
* When set, all keys will be prefixed with the namespace followed by the key separator.
*/
namespace?: string;
/**
* The separator used between namespace and key. Defaults to ":".
*/
keySeparator?: string;
};
/**
* Interface for a promise-based store that can be used with KeyvBridgeAdapter.
* The store must implement get, set, delete, and clear as async operations.
* Optional methods (has, hasMany, getMany, setMany, deleteMany, iterator, disconnect)
* will be delegated to the store if present, otherwise fallback implementations are used.
*/
type KeyvBridgeStore = {
/** Store configuration/options (e.g. dialect, url) */opts?: any; /** Retrieves a value by key */
get(key: string): Promise<any>; /** Sets a value with a key and optional TTL */
set(key: string, value: any, ttl?: number): Promise<any>; /** Deletes a key from the store */
delete(key: string): Promise<boolean>; /** Clears all entries from the store */
clear(): Promise<void>; /** Checks if a key exists in the store */
has?(key: string): Promise<boolean>; /** Checks if multiple keys exist in the store */
hasMany?(keys: string[]): Promise<boolean[]>; /** Retrieves multiple values by keys */
getMany?(keys: string[]): Promise<any[]>; /** Sets multiple entries at once */
setMany?(entries: any[]): Promise<any>; /** Deletes multiple keys at once */
deleteMany?(keys: string[]): Promise<boolean | boolean[]>; /** Iterates over all entries, optionally filtered by namespace */
iterator?(namespace?: string): AsyncGenerator<any>; /** Disconnects from the store */
disconnect?(): Promise<void>; /** Subscribe to events (e.g. error events from v5 adapters) */
on?(event: string, listener: (...args: any[]) => void): any;
};
/**
* Data structure returned when parsing a prefixed key.
*/
type KeyPrefixData = {
/** The namespace extracted from the key, if present */namespace?: string; /** The key without the namespace prefix */
key: string;
};
/**
* A bridge storage adapter for Keyv that wraps any promise-based store.
*
* This class provides a unified interface for using various async stores
* with Keyv, handling namespace prefixing, TTL-based expiration, and batch operations.
* If the underlying store implements optional methods (has, hasMany, getMany, etc.),
* the bridge will delegate to them. Otherwise, it falls back to using primitives.
*
* @example
* ```typescript
* // Using with a promise-based store
* const bridge = new KeyvBridgeAdapter(myAsyncStore, { namespace: 'cache' });
*
* // Using with Keyv
* const keyv = new Keyv({ store: new KeyvBridgeAdapter(myAsyncStore) });
* ```
*/
declare class KeyvBridgeAdapter extends Hookified implements KeyvStorageAdapter {
private _store;
private _namespace?;
private _keySeparator;
private readonly _capabilities;
/**
* Creates a new KeyvBridgeAdapter instance.
* @param store - The underlying promise-based store to bridge
* @param options - Configuration options for the adapter
*/
constructor(store: KeyvBridgeStore, options?: KeyvBridgeAdapterOptions);
/**
* Gets the underlying store instance.
*/
get store(): KeyvBridgeStore;
/**
* Sets the underlying store instance.
*/
set store(store: KeyvBridgeStore);
/**
* Gets the detected capabilities of the underlying store.
*/
get capabilities(): KeyvStorageCapability;
/**
* Gets the current key separator used between namespace and key.
*/
get keySeparator(): string;
/**
* Sets the key separator used between namespace and key.
*/
set keySeparator(separator: string);
/**
* Gets the current namespace.
*/
get namespace(): string | undefined;
/**
* Sets the namespace.
*/
set namespace(namespace: string | undefined);
/**
* Creates a prefixed key by combining the namespace and key with the separator.
* @param key - The base key
* @param namespace - Optional namespace to prefix the key with
* @returns The prefixed key if namespace is provided, otherwise the original key
*/
getKeyPrefix(key: string, namespace?: string): string;
/**
* Parses a prefixed key to extract the namespace and original key.
* @param key - The prefixed key to parse
* @returns An object containing the namespace (if present) and the original key
*/
getKeyPrefixData(key: string): KeyPrefixData;
/**
* Retrieves a value from the store by key.
* Automatically handles namespace prefixing and TTL expiration.
* @param key - The key to retrieve
* @returns The stored data, or undefined if not found or expired
*/
get<T>(key: string): Promise<KeyvStorageGetResult<T>>;
/**
* Retrieves multiple values from the store by their keys.
* Delegates to the store's native getMany if available.
* @param keys - Array of keys to retrieve
* @returns Array of stored data in the same order as the input keys
*/
getMany<T>(keys: string[]): Promise<Array<KeyvStorageGetResult<T | undefined>>>;
/**
* Stores a value in the store with an optional TTL.
* @param key - The key to store the value under
* @param value - The value to store
* @param ttl - Optional time-to-live in milliseconds
* @returns Always returns true indicating success
*/
set(key: string, value: any, ttl?: number): Promise<boolean>;
/**
* Stores multiple entries in the store at once.
* Delegates to the store's native setMany if available, otherwise loops over set.
* @param entries - Array of entries containing key, value, and optional TTL
*/
setMany<Value>(entries: KeyvEntry<Value>[]): Promise<boolean[] | undefined>;
/**
* Checks if a key exists in the store and is not expired.
* Delegates to the store's native has if available.
* @param key - The key to check
* @returns True if the key exists and is not expired, false otherwise
*/
has(key: string): Promise<boolean>;
/**
* Checks if multiple keys exist in the store and are not expired.
* Delegates to the store's native hasMany if available.
* @param keys - Array of keys to check
* @returns Array of booleans indicating existence for each key
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Deletes a value from the store by key.
* @param key - The key to delete
* @returns True if the key was deleted, false otherwise
*/
delete(key: string): Promise<boolean>;
/**
* Deletes multiple keys from the store at once.
* Delegates to the store's native deleteMany if available.
* @param keys - Array of keys to delete
* @returns Array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Clears entries from the store. If a namespace is set and the store supports
* iteration, only entries within that namespace are removed. Otherwise, the
* entire store is cleared.
*/
clear(): Promise<void>;
/**
* Creates an async iterator for iterating over store entries.
* If the underlying store does not support iteration, returns an empty generator.
* @returns An async generator yielding [key, value] pairs
*/
iterator<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
/**
* Disconnects from the underlying store.
* No-op if the store does not support disconnect.
*/
disconnect(): Promise<void>;
}
//#endregion
//#region src/keyv.d.ts
declare class Keyv<GenericValue = any> extends Hookified {
/**
* Stats manager for tracking cache operation metrics (hits, misses, sets, deletes, errors).
* @default this is disabled.
*/
private _stats;
/**
* Default time to live in milliseconds. Can be overridden per-key via {@link set}.
*/
private _ttl?;
/**
* Key prefix namespace used to isolate keys across different Keyv instances sharing the same store.
*/
private _namespace?;
/**
* The underlying storage adapter. Defaults to an in-memory {@link Map}.
*/
private _store;
/**
* Pluggable serialization adapter with `stringify` and `parse` methods.
* When `undefined`, the built-in {@link KeyvJsonSerializer} is used.
*/
private _serialization;
/**
* Pluggable compression adapter with `compress` and `decompress` methods.
*/
private _compression;
/**
* Pluggable encryption adapter with `encrypt` and `decrypt` methods.
*/
private _encryption;
/**
* Sanitization handler for keys and namespaces. By default it is disabled.
*/
private _sanitize;
/**
* When true, Keyv checks expiry at its layer on get/getMany/has/hasMany.
*/
private _checkExpired;
/**
* Keyv Constructor
* @param {KeyvStorageAdapter | KeyvOptions | Map<any, any> | any} store to be provided or just the options
* @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
*/
constructor(store?: KeyvStorageAdapter | KeyvOptions | KeyvMapAny, options?: Omit<KeyvOptions, "store">);
/**
* Keyv Constructor
* @param {KeyvOptions} options to be provided
*/
constructor(options?: KeyvOptions);
/**
* Get the current storage adapter.
* @returns {KeyvStorageAdapter} The current storage adapter.
*/
get store(): KeyvStorageAdapter;
/**
* Set the storage adapter.
* @param {KeyvStorageAdapter | Map<any, any> | any} store The storage adapter to set.
*/
set store(store: KeyvStorageAdapter | KeyvMapAny);
/**
* Get the current compression adapter.
* @returns {KeyvCompressionAdapter | undefined} The current compression adapter.
*/
get compression(): KeyvCompressionAdapter | undefined;
/**
* Set the compression adapter.
* @param {KeyvCompressionAdapter | undefined} compress The compression adapter to set.
*/
set compression(compress: KeyvCompressionAdapter | undefined);
/**
* Get the current encryption adapter.
* @returns {KeyvEncryptionAdapter | undefined} The current encryption adapter.
*/
get encryption(): KeyvEncryptionAdapter | undefined;
/**
* Set the encryption adapter.
* @param {KeyvEncryptionAdapter | undefined} encryption The encryption adapter to set.
*/
set encryption(encryption: KeyvEncryptionAdapter | undefined);
/**
* Get the current namespace.
* @returns {string | undefined} The current namespace.
*/
get namespace(): string | undefined;
/**
* Set the current namespace.
* @param {string | undefined} namespace The namespace to set.
*/
set namespace(namespace: string | undefined);
/**
* Get the current TTL.
* @returns {number} The current TTL in milliseconds.
*/
get ttl(): number | undefined;
/**
* Set the current TTL.
* @param {number} ttl The TTL to set in milliseconds.
*/
set ttl(ttl: number | undefined);
/**
* Get the current serialization adapter. If `undefined`, serialization is not enabled.
* @returns {KeyvSerializationAdapter | undefined} The current serialization adapter.
*/
get serialization(): KeyvSerializationAdapter | undefined;
/**
* Set the current serialization adapter. Pass a `KeyvSerializationAdapter` to enable
* custom serialization, or `undefined` to disable serialization entirely.
* @param {KeyvSerializationAdapter | undefined} serialization The serialization adapter to set.
*/
set serialization(serialization: KeyvSerializationAdapter | false | undefined);
/**
* Get the current throwOnErrors value. When enabled, all errors with throw. By default, errors
* will only throw if there are no listeners to the error event.
* @return {boolean} The current throwOnErrors value.
*/
get throwOnErrors(): boolean;
/**
* Set the current throwOnErrors value. When enabled, all errors will throw. By default, errors
* will only throw if there are no listeners to the error event.
* @param {boolean} value The throwOnErrors value to set.
*/
set throwOnErrors(value: boolean);
/**
* Get the current sanitize adapter. Sanitization is disabled by default. To
* enable it `sanitize.keys` or `sanitize.namespace` to true or set KeyvSanitizePatterns
* to each.
* @returns {KeyvSanitizeAdapter} The current sanitize adapter.
*/
get sanitize(): KeyvSanitizeAdapter;
/**
* Set the sanitize adapter directly and will run sanitization on namespace.
* @param {KeyvSanitizeAdapter} value The sanitize adapter to use.
*/
set sanitize(value: KeyvSanitizeAdapter);
/**
* Get the stats. This is just for this instance
* @returns {KeyvStats} The current stats.
*/
get stats(): KeyvStats;
/**
* When true, Keyv checks expiry at its layer on get/getMany/has/hasMany.
* When false (default), trusts the storage adapter.
*/
get checkExpired(): boolean;
/**
* Set the stats. When setting a new instance it will unsubscribe the old listeners
* and subscribe the new instance.
* @param {KeyvStats} stats The stats instance to set.
*/
set stats(stats: KeyvStats);
/**
* Resolves a store to a fully-compliant KeyvStorageAdapter using a 3-tier detection chain:
* 1. If the store already implements the full KeyvStorageAdapter interface, use it directly.
* 2. If the store is map-like (synchronous get/set/delete/has), wrap it in KeyvMemoryAdapter.
* 3. If the store has async get/set/delete/clear, wrap it in KeyvBridgeAdapter.
* 4. Otherwise, emit an error and fall back to a default in-memory KeyvMemoryAdapter.
*
* NOTE: this is used for internal but provided public for custom adapter testing
* @param {unknown} store The store to resolve.
* @returns {KeyvStorageAdapter} A fully-compliant storage adapter.
*/
resolveStore(store: any): KeyvStorageAdapter;
/**
* Sets the storage adapter by resolving it via {@link resolveStore}, then wires up
* error forwarding and namespace propagation.
* @param {KeyvStorageAdapter | Map<any, any> | any} store The storage adapter to set.
*/
setStore(store: KeyvStorageAdapter | KeyvMapAny): void;
/**
* Sets the TTL, treating zero and negative values as undefined (no TTL).
* @param {number | undefined} ttl The TTL to set in milliseconds.
*/
setTtl(ttl?: number): void;
/**
* Get the Value of a Key
* @param {string | string[]} key passing in a single key or multiple as an array
*/
get<Value = GenericValue>(key: string): Promise<Value | undefined>;
get<Value = GenericValue>(key: string[]): Promise<Array<Value | undefined>>;
/**
* Get many values of keys
* @param {string[]} keys passing in a single key or multiple as an array
*/
getMany<Value = GenericValue>(keys: string[]): Promise<Array<Value | undefined>>;
/**
* Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
* @param {string} key the key to get
* @returns {Promise<KeyvStorageGetResult<Value>>} will return a KeyvStorageGetResult<Value> or undefined
* if the key does not exist or is expired.
*/
getRaw<Value = GenericValue>(key: string): Promise<KeyvStorageGetResult<Value>>;
/**
* Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
* @param {string[]} keys the keys to get
* @returns {Promise<Array<KeyvStorageGetResult<Value>>>} will return an array of KeyvStorageGetResult<Value> or undefined if the key does not exist or is expired.
*/
getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<KeyvStorageGetResult<Value>>>;
/**
* Set an item to the store
* @param {string | Array<KeyvEntry<Value>>} key the key to use. If you pass in an array of KeyvEntry it will set many items
* @param {Value} value the value of the key
* @param {number} [ttl] time to live in milliseconds
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
set<Value = GenericValue>(key: string, value: Value, ttl?: number): Promise<boolean>;
/**
* Set many items to the store
* @param {Array<KeyvEntry<Value>>} entries the entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setMany<Value = GenericValue>(entries: KeyvEntry<Value>[]): Promise<boolean[]>;
/**
* Set a raw value to the store without wrapping or serialization. This is the write-side counterpart to getRaw().
* The value should be a KeyvValue object with { value, expires? }. 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`.
* @param {string} key the key to set
* @param {KeyvValue<Value>} value the raw value envelope to store
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
setRaw<Value = GenericValue>(key: string, value: KeyvValue<Value>): Promise<boolean>;
/**
* Set many raw values to the store without wrapping or serialization. This is the write-side counterpart to getManyRaw().
* Each entry's value should be a KeyvValue object with { value, expires? }. If you need TTL-based expiration,
* set `expires` on each value directly. The store-level TTL is derived automatically from `value.expires`.
* @param {KeyvEntry<KeyvValue<Value>>[]} entries the raw entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setManyRaw<Value = GenericValue>(entries: KeyvEntry<KeyvValue<Value>>[]): Promise<boolean[]>;
/**
* Delete an Entry
* @param {string} key the key to be deleted
* @returns {boolean} will return true if item is deleted. false if there is an error
*/
delete(key: string): Promise<boolean>;
/**
* Delete multiple Entries
* @param {string[]} keys the keys to be deleted
* @returns {boolean[]} will return array of booleans for each key
*/
delete(keys: string[]): Promise<boolean[]>;
/**
* Delete many items from the store
* @param {string[]} keys the keys to be deleted
* @returns {boolean[]} array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Has a key.
* @param {string} key the key to check
* @returns {boolean} will return true if the key exists
*/
has(key: string[]): Promise<boolean[]>;
has(key: string): Promise<boolean>;
/**
* Check if many keys exist
* @param {string[]} keys the keys to check
* @returns {boolean[]} will return an array of booleans if the keys exist
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Clear the store
* @returns {void}
*/
clear(): Promise<void>;
/**
* Will disconnect the store. This is only available if the store has a disconnect method
* @returns {Promise<void>}
*/
disconnect(): Promise<void>;
/**
* Iterate over all key-value pairs in the store. Automatically deserializes values,
* filters out expired entries, and deletes them from the store.
* @returns {AsyncGenerator<Array<string | unknown>, void>} An async generator yielding `[key, value]` pairs.
*/
iterator(): AsyncGenerator<[string, any], void>;
/**
* Encodes a value for storage. Pipeline: serialize → compress → encrypt.
* If serialization is not configured, returns the data as-is.
* @param {KeyvValue<T>} data The value envelope to encode.
* @returns {Promise<unknown>} The encoded value, or the original data on failure.
*/
encode<T>(data: KeyvValue<T>): Promise<unknown>;
/**
* Decodes a stored value. Pipeline: decrypt → decompress → deserialize (reverse of encode).
* If serialization is not configured, returns the data as a KeyvValue or undefined for strings.
* @param {unknown} data The raw data from the store.
* @returns {Promise<KeyvValue<T> | undefined>} The decoded value envelope, or undefined on failure.
*/
decode<T>(data: unknown): Promise<KeyvValue<T> | undefined>;
/**
* Deserializes raw data from the store, checks for expiry, and deletes expired keys.
* Accepts a single key/value or arrays. Returns an array of decoded KeyvValue objects
* (undefined for missing or expired entries).
* @param {string | string[]} keys the key(s) to process
* @param {unknown | unknown[]} rawData the raw data from the store
* @returns {Promise<Array<KeyvValue<Value> | undefined>>} decoded values with expired entries removed
*/
decodeWithExpire<Value>(keys: string | string[], rawData: unknown | unknown[]): Promise<Array<KeyvValue<Value> | undefined>>;
/**
* Fires a hook under its new name and also under the deprecated alias (if any),
* so that integrations still subscribing to the old PRE_/POST_ names keep working.
*/
private hookWithDeprecated;
/**
* Emit a telemetry event for cache operations.
* @param {KeyvEvents} event the telemetry event type
* @param {string | string[]} [key] the cache key or keys (emits one event per key)
*/
private emitTelemetry;
/**
* Merges the overloaded constructor arguments into a single KeyvOptions object.
*/
private static resolveOptions;
/**
* Initializes the serialization adapter from options.
*/
private initSerialization;
/**
* Initializes the sanitization handler from options.
*/
private initSanitize;
/**
* Initializes the stats manager from options.
*/
private initStats;
/**
* Initializes the namespace, applying sanitization if enabled.
*/
private initNamespace;
}
//#endregion
//#region src/adapters/memory.d.ts
/**
* Configuration options for KeyvMemoryAdapter.
*/
type KeyvMemoryAdapterOptions = {
/**
* The namespace to use for keys.
* When set, all keys will be prefixed with the namespace followed by the key separator.
*/
namespace?: string;
/**
* The separator used between namespace and key. Defaults to ":".
*/
keySeparator?: string;
};
/**
* Interface for a Map-like store that can be used with KeyvMemoryAdapter.
* This allows any object implementing these methods to be used as the underlying storage.
* Compatible with Map, QuickLRU, lru.min, and other LRU cache implementations.
*/
type KeyvMapType = {
/** Retrieves a value by key */get: (key: string) => any; /** Sets a value with a key. Additional parameters (like TTL) vary by implementation. */
set: (key: string, value: any, ...args: any[]) => any; /** Deletes a key from the store */
delete: (key: string) => boolean; /** Clears all entries from the store */
clear: () => void; /** Checks if a key exists in the store */
has: (key: string) => boolean;
};
/**
* An in-memory storage adapter for Keyv that wraps any Map-like object.
*
* This class provides a unified interface for using various Map-like stores
* with Keyv, handling namespace prefixing, TTL-based expiration, and batch operations.
*
* @example
* ```typescript
* // Using with a standard Map
* const store = new KeyvMemoryAdapter(new Map(), { namespace: 'cache' });
*
* // Using with a custom store
* const customStore = new KeyvMemoryAdapter(myCustomMapLikeStore, {
* namespace: 'tenant-123',
* keySeparator: ':'
* });
* ```
*/
declare class KeyvMemoryAdapter extends Hookified implements KeyvStorageAdapter {
private _store;
private _namespace?;
private _keySeparator;
private readonly _capabilities;
/**
* Creates a new KeyvMemoryAdapter instance.
* @param store - The underlying Map or Map-like object to use for storage
* @param options - Configuration options for the store
*/
constructor(store: KeyvMapType, options?: KeyvMemoryAdapterOptions);
/**
* Gets the detected capabilities of the underlying store.
*/
get capabilities(): KeyvStorageCapability;
/**
* Gets the underlying store instance.
*/
get store(): KeyvMapType;
/**
* Sets the underlying store instance.
*/
set store(store: KeyvMapType);
/**
* Gets the current key separator used between namespace and key.
*/
get keySeparator(): string;
/**
* Sets the key separator used between namespace and key.
*/
set keySeparator(separator: string);
/**
* Gets the current namespace.
*/
get namespace(): string | undefined;
/**
* Sets the namespace.
*/
set namespace(namespace: string | undefined);
/**
* Creates a prefixed key by combining the namespace and key with the separator.
* @param key - The base key
* @param namespace - Optional namespace to prefix the key with
* @returns The prefixed key if namespace is provided, otherwise the original key
*/
getKeyPrefix(key: string, namespace?: string): string;
/**
* Parses a prefixed key to extract the namespace and original key.
* @param key - The prefixed key to parse
* @returns An object containing the namespace (if present) and the original key
*/
getKeyPrefixData(key: string): {
namespace: string;
key: string;
} | {
key: string;
namespace?: undefined;
};
/**
* Retrieves a value from the store by key.
* Automatically handles namespace prefixing and TTL expiration.
* @param key - The key to retrieve
* @returns The stored data, or undefined if not found or expired
*/
get<T>(key: string): Promise<KeyvStorageGetResult<T>>;
/**
* Stores a value in the store with an optional TTL.
* @param key - The key to store the value under
* @param value - The value to store
* @param ttl - Optional time-to-live in milliseconds
* @returns Always returns true indicating success
*/
set(key: string, value: any, ttl?: number): Promise<boolean>;
/**
* Stores multiple entries in the store at once.
* @param entries - Array of entries containing key, value, and optional TTL
*/
setMany<Value>(entries: KeyvEntry<Value>[]): Promise<boolean[] | undefined>;
/**
* Deletes a value from the store by key.
* @param key - The key to delete
* @returns True if the key was deleted, false otherwise
*/
delete(key: string): Promise<boolean>;
/**
* Clears entries from the store. If a namespace is set, only entries
* within that namespace are removed. Otherwise, the entire store is cleared.
* NOTE: if there is no `keys()` then we just do a full clear.
*/
clear(): Promise<void>;
/**
* Checks if a key exists in the store and is not expired.
* @param key - The key to check
* @returns True if the key exists and is not expired, false otherwise
*/
has(key: string): Promise<boolean>;
/**
* Checks if multiple keys exist in the store and are not expired.
* @param keys - Array of keys to check
* @returns Array of booleans indicating existence for each key
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Retrieves multiple values from the store by their keys.
* @param keys - Array of keys to retrieve
* @returns Array of stored data in the same order as the input keys
*/
getMany<T>(keys: string[]): Promise<Array<KeyvStorageGetResult<T | undefined>>>;
/**
* Deletes multiple keys from the store at once.
* @param keys - Array of keys to delete
* @returns Array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Creates an async iterator for iterating over store entries.
* If the underlying store does not support iteration, returns an empty generator.
* @returns {AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>} An async generator yielding [key, value] pairs
*/
iterator<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
/**
* No-op disconnect for in-memory stores.
*/
disconnect(): Promise<void>;
}
/**
* Creates a Keyv instance with a memory adapter optimized for in-memory storage.
*
* This factory function configures Keyv to bypass serialization/deserialization
* and key prefixing, resulting in faster performance for in-memory use cases
* where data doesn't need to be persisted or transmitted.
*
* @param store - The underlying Map or Map-like object to use for storage
* @param options - Configuration options for the memory adapter
* @returns A configured Keyv instance with optimized settings for in-memory storage
*
* @example
* ```typescript
* // Create a simple in-memory cache
* const cache = createKeyv(new Map());
* await cache.set('user:1', { name: 'John' });
*
* // Create with namespace for multi-tenant scenarios
* const tenantCache = createKeyv(new Map(), {
* namespace: 'tenant-123',
* keySeparator: ':'
* });
* ```
*/
declare function createKeyv(store: KeyvMapType, options?: KeyvMemoryAdapterOptions): Keyv<any>;
//#endregion
//#region src/json-serializer.d.ts
declare class KeyvJsonSerializer implements KeyvSerializationAdapter {
stringify(object: unknown): string;
parse<T>(data: string): T;
}
declare const jsonSerializer: KeyvJsonSerializer;
//#endregion
export { type DeserializedData, Keyv, Keyv as default, KeyvBridgeAdapter, type KeyvBridgeAdapterOptions, type KeyvBridgeStore, type KeyvCapability, type KeyvCompression, type KeyvCompressionAdapter, type KeyvCompressionCapability, type KeyvCompressionMethods, type KeyvEncryptionAdapter, type KeyvEncryptionCapability, type KeyvEncryptionMethods, type KeyvEntry, KeyvEvents, KeyvHooks, KeyvJsonSerializer, type KeyvMapAny, type KeyvMapType, KeyvMemoryAdapter, type KeyvMemoryAdapterOptions, type KeyvMethods, type KeyvOptions, type KeyvProperties, KeyvSanitize, type KeyvSanitizeAdapter, type KeyvSanitizeOptions, type KeyvSanitizePatterns, type KeyvSerializationAdapter, type KeyvSerializationCapability, type KeyvSerializationMethods, KeyvStats, type KeyvStatsOptions, type KeyvStorageAdapter, type KeyvStorageCapability, type KeyvStorageGetResult, type KeyvStorageMethod, type KeyvStorageMethods, type KeyvStoreAdapter, type KeyvTelemetryEvent, type KeyvValue, type MethodType, createKeyv, detectKeyv, detectKeyvCompression, detectKeyvEncryption, detectKeyvSerialization, detectKeyvStorage, jsonSerializer };

Sorry, the diff of this file is too big to display

+1329
-367

@@ -1,155 +0,619 @@

type EventListener = (...arguments_: any[]) => void;
declare class EventManager {
_eventListeners: Map<string, EventListener[]>;
_maxListeners: number;
constructor();
maxListeners(): number;
addListener(event: string, listener: EventListener): void;
on(event: string, listener: EventListener): this;
removeListener(event: string, listener: EventListener): void;
off(event: string, listener: EventListener): void;
once(event: string, listener: EventListener): void;
emit(event: string, ...arguments_: any[]): void;
listeners(event: string): EventListener[];
removeAllListeners(event?: string): void;
setMaxListeners(n: number): void;
}
import { Hookified, IEventEmitter } from "hookified";
type HookHandler = (...arguments_: any[]) => void;
declare class HooksManager extends EventManager {
_hookHandlers: Map<string, HookHandler[]>;
constructor();
addHandler(event: string, handler: HookHandler): void;
removeHandler(event: string, handler: HookHandler): void;
trigger(event: string, data: any): void;
get handlers(): Map<string, HookHandler[]>;
//#region src/capabilities.d.ts
type MethodType = "sync" | "async" | "none";
type KeyvStorageMethod = {
exists: boolean;
methodType: MethodType;
};
declare const keyvMethodNames: readonly ["get", "set", "delete", "clear", "has", "getMany", "setMany", "deleteMany", "hasMany", "disconnect", "getRaw", "getManyRaw", "setRaw", "setManyRaw", "iterator"];
declare const keyvPropertyNames: readonly ["hooks", "stats"];
type KeyvMethods = Record<(typeof keyvMethodNames)[number], KeyvStorageMethod>;
type KeyvProperties = Record<(typeof keyvPropertyNames)[number], boolean>;
type KeyvCapability = {
compatible: boolean;
methods: KeyvMethods;
properties: KeyvProperties;
};
declare const keyvStorageMethodNames: readonly ["get", "getMany", "has", "hasMany", "set", "setMany", "delete", "deleteMany", "clear", "disconnect", "iterator"];
type KeyvStorageMethods = Record<(typeof keyvStorageMethodNames)[number], KeyvStorageMethod>;
type KeyvStorageCapability = {
compatible: boolean;
store: "mapLike" | "keyvStorage" | "asyncMap" | "none";
methods: KeyvStorageMethods;
};
declare const keyvCompressionMethodNames: readonly ["compress", "decompress"];
type KeyvCompressionMethods = Record<(typeof keyvCompressionMethodNames)[number], KeyvStorageMethod>;
type KeyvCompressionCapability = {
compatible: boolean;
methods: KeyvCompressionMethods;
};
declare const keyvSerializationMethodNames: readonly ["stringify", "parse"];
type KeyvSerializationMethods = Record<(typeof keyvSerializationMethodNames)[number], KeyvStorageMethod>;
type KeyvSerializationCapability = {
compatible: boolean;
methods: KeyvSerializationMethods;
};
declare const keyvEncryptionMethodNames: readonly ["encrypt", "decrypt"];
type KeyvEncryptionMethods = Record<(typeof keyvEncryptionMethodNames)[number], KeyvStorageMethod>;
type KeyvEncryptionCapability = {
compatible: boolean;
methods: KeyvEncryptionMethods;
};
/**
* Detect whether an object implements the full Keyv interface
* @param obj - The object to check
* @returns A {@link KeyvCapability} where `compatible` is `true` only when all required capabilities are present
* @example
* ```typescript
* import Keyv, { detectKeyv } from 'keyv';
*
* const result = detectKeyv(new Keyv());
* result.compatible; // true — all capabilities present
* result.methods.get.exists; // true
* result.methods.get.methodType; // "async"
*
* const partial = detectKeyv(new Map());
* partial.compatible; // false — missing getMany, setMany, hooks, stats, etc.
* partial.methods.get.exists; // true
* ```
*/
declare function detectKeyv(obj: unknown): KeyvCapability;
/**
* Detect whether an object implements the Keyv storage adapter interface
* @param obj - The object to check
* @returns A {@link KeyvStorageCapability} where:
* - `compatible` is `true` when the object is a valid storage adapter (`"keyvStorage"`, `"mapLike"`, or `"asyncMap"`)
* - `store` indicates the detected store type: `"keyvStorage"`, `"mapLike"`, `"asyncMap"`, or `"none"`
* - `methods` maps each method name to `{ exists, methodType }`
* @example
* ```typescript
* import { detectKeyvStorage } from 'keyv';
*
* const map = detectKeyvStorage(new Map());
* map.compatible; // true
* map.store; // "mapLike"
* map.methods.get.exists; // true
* map.methods.get.methodType; // "sync"
*
* const adapter = detectKeyvStorage(asyncAdapter);
* adapter.compatible; // true
* adapter.store; // "keyvStorage"
* adapter.methods.get.methodType; // "async"
* ```
*/
declare function detectKeyvStorage(obj: unknown): KeyvStorageCapability;
/**
* Detect whether an object implements the Keyv compression adapter interface
* @param obj - The object to check
* @returns A {@link KeyvCompressionCapability} where `compatible` is `true` when both `compress` and `decompress` methods are present
* @example
* ```typescript
* import { detectKeyvCompression } from 'keyv';
*
* detectKeyvCompression({ compress: (d) => d, decompress: (d) => d });
* // { compatible: true, methods: { compress: { exists: true, methodType: "sync" }, decompress: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvCompression(obj: unknown): KeyvCompressionCapability;
/**
* Detect whether an object implements the Keyv serialization adapter interface
* @param obj - The object to check
* @returns A {@link KeyvSerializationCapability} where `compatible` is `true` when both `stringify` and `parse` methods are present
* @example
* ```typescript
* import { detectKeyvSerialization } from 'keyv';
*
* detectKeyvSerialization(JSON);
* // { compatible: true, methods: { stringify: { exists: true, methodType: "sync" }, parse: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvSerialization(obj: unknown): KeyvSerializationCapability;
/**
* Detect whether an object implements the Keyv encryption adapter interface
* @param obj - The object to check
* @returns A {@link KeyvEncryptionCapability} where `compatible` is `true` when both `encrypt` and `decrypt` methods are present
* @example
* ```typescript
* import { detectKeyvEncryption } from 'keyv';
*
* detectKeyvEncryption({ encrypt: (d) => d, decrypt: (d) => d });
* // { compatible: true, methods: { encrypt: { exists: true, methodType: "sync" }, decrypt: { exists: true, methodType: "sync" } } }
* ```
*/
declare function detectKeyvEncryption(obj: unknown): KeyvEncryptionCapability;
//#endregion
//#region src/sanitize.d.ts
/**
* Which dangerous-pattern categories to detect and strip.
* Each defaults to `true` when the parent scope is enabled.
*/
type KeyvSanitizePatterns = {
/**
* Detect and strip SQL injection patterns: semicolons (`;`), SQL comments (`--` and `/*`).
* @default false
*/
sql: boolean;
/**
* Detect and strip MongoDB operator patterns: leading `$`, `{$` sequences.
* @default false
*/
mongo: boolean;
/**
* Detect and strip dangerous control sequences: null bytes (`\0`), carriage returns (`\r`), newlines (`\n`).
* @default false
*/
escape: boolean;
/**
* Detect and strip path traversal patterns: `../` and `..\\` sequences.
* @default false
*/
path: boolean;
};
/**
* Options for configuring sanitization pattern categories.
* All categories default to `true` when the parent scope is enabled.
*/
type KeyvSanitizePatternsOptions = {
/**
* Detect and strip SQL injection patterns: semicolons (`;`), SQL comments (`--` and `/*`).
* @default true
*/
sql?: boolean;
/**
* Detect and strip MongoDB operator patterns: leading `$`, `{$` sequences.
* @default true
*/
mongo?: boolean;
/**
* Detect and strip dangerous control sequences: null bytes (`\0`), carriage returns (`\r`), newlines (`\n`).
* @default true
*/
escape?: boolean;
/**
* Detect and strip path traversal patterns: `../` and `..\\` sequences.
* @default true
*/
path?: boolean;
};
/**
* Controls what gets sanitized and with which patterns.
*/
type KeyvSanitizeOptions = {
/**
* Sanitize keys. Pass `true` for all pattern categories, `false` to skip,
* or a `KeyvSanitizePatternOptions` object for granular control.
* @default false
*/
keys?: boolean | KeyvSanitizePatternsOptions;
/**
* Sanitize namespace strings. Pass `true` for all pattern categories, `false` to skip,
* or a `KeyvSanitizePatternOptions` object for granular control.
* @default false
*/
namespace?: boolean | KeyvSanitizePatternsOptions;
};
/**
* Adapter interface for key and namespace sanitization.
* Implement this to provide custom sanitization logic to Keyv.
*/
type KeyvSanitizeAdapter = {
/** Whether any sanitization is currently enabled. */readonly enabled: boolean; /** The key sanitization pattern configuration. */
readonly keys: KeyvSanitizePatterns; /** The namespace sanitization pattern configuration. */
readonly namespace: KeyvSanitizePatterns; /** Sanitize a single key. */
cleanKey(key: string): string; /** Sanitize an array of keys. */
cleanKeys(keys: string[]): string[]; /** Sanitize a namespace string. */
cleanNamespace(ns: string): string;
};
/**
* Encapsulates key and namespace sanitization with an LRU result cache.
*/
declare class KeyvSanitize implements KeyvSanitizeAdapter {
private _keys;
private _namespace;
private _keyPatterns;
private _namespacePatterns;
private _enabled;
private _cacheKeys;
private _cacheNamespaces;
private _cacheMax;
constructor(options?: KeyvSanitizeOptions);
/**
* The key sanitization pattern configuration.
*/
get keys(): KeyvSanitizePatterns;
/**
* Whether any sanitization pattern (keys or namespace) is enabled.
*/
get enabled(): boolean;
/**
* The namespace sanitization pattern configuration.
*/
get namespace(): KeyvSanitizePatterns;
/**
* Update the sanitization configuration. Recompiles patterns and clears the cache.
*/
updateOptions(options: KeyvSanitizeOptions): void;
/**
* Sanitize a single key. Uses an LRU cache for repeated lookups.
*/
cleanKey(key: string): string;
/**
* Sanitize an array of keys.
*/
cleanKeys(keys: string[]): string[];
/**
* Sanitize a namespace string. Uses an LRU cache for repeated lookups.
*/
cleanNamespace(ns: string): string;
/**
* Clear the LRU caches.
*/
clearCache(): void;
private resolvePatterns;
}
declare class StatsManager extends EventManager {
enabled: boolean;
hits: number;
misses: number;
sets: number;
deletes: number;
errors: number;
constructor(enabled?: boolean);
hit(): void;
miss(): void;
set(): void;
delete(): void;
hitsOrMisses<T>(array: Array<T | undefined>): void;
reset(): void;
}
type KeyvSerializationAdapter = {
stringify: (object: unknown) => string | Promise<string>;
parse: <T>(data: string) => T | Promise<T>;
//#endregion
//#region src/stats.d.ts
/**
* Structure of a telemetry event emitted by Keyv.
*/
type KeyvTelemetryEvent = {
/** The event type (e.g. "hit", "miss", "set", "delete", "error"). */event: string; /** The cache key involved, if applicable. */
key?: string; /** The namespace of the Keyv instance. */
namespace?: string; /** Unix timestamp in milliseconds when the event occurred. */
timestamp: number;
};
type KeyvCompressionAdapter = {
compress(value: any, options?: any): Promise<any>;
decompress(value: any, options?: any): Promise<any>;
type KeyvStatsOptions = {
/**
* Enable or disable stats tracking.
* @default false
*/
enabled?: boolean;
/**
* Maximum number of entries per event-type LRU map.
* @default 1000
*/
maxEntries?: number;
/**
* The event emitter (e.g. a Keyv instance) to subscribe to for telemetry events.
* If provided, KeyvStats will automatically subscribe on construction.
*/
emitter?: IEventEmitter;
};
type DeserializedData<Value> = {
value?: Value;
expires?: number | undefined;
declare class KeyvStats {
private _hits;
private _misses;
private _sets;
private _deletes;
private _errors;
private _maxEntries;
private _enabled;
private readonly hitKeysMap;
private readonly missKeysMap;
private readonly setKeysMap;
private readonly deleteKeysMap;
private readonly errorKeysMap;
private _emitter?;
private readonly _listeners;
constructor(options?: KeyvStatsOptions);
/**
* Total number of cache hits.
*/
get hits(): number;
/**
* Total number of cache misses.
*/
get misses(): number;
/**
* Total number of cache sets.
*/
get sets(): number;
/**
* Total number of cache deletes.
*/
get deletes(): number;
/**
* Total number of cache errors.
*/
get errors(): number;
/**
* LRU-bounded map of key to hit count.
*/
get hitKeys(): Map<string, number>;
/**
* LRU-bounded map of key to miss count.
*/
get missKeys(): Map<string, number>;
/**
* LRU-bounded map of key to set count.
*/
get setKeys(): Map<string, number>;
/**
* LRU-bounded map of key to delete count.
*/
get deleteKeys(): Map<string, number>;
/**
* LRU-bounded map of key to error count.
*/
get errorKeys(): Map<string, number>;
/**
* Maximum number of entries per event-type LRU map.
* @default 1000
*/
get maxEntries(): number;
/**
* Set the maximum number of entries per event-type LRU map.
* @param {number} value the new maximum entries
*/
set maxEntries(value: number);
/**
* Whether stats tracking is enabled.
* @default false
*/
get enabled(): boolean;
/**
* Enable or disable stats tracking. If false it will unsubscribe from the events
* @param {boolean} value true to enable, false to disable
*/
set enabled(value: boolean);
/**
* Build a composite key from a telemetry event.
* Format: "namespace:key" if namespace is present, otherwise just "key".
*/
buildKeyEventName(event: KeyvTelemetryEvent): string;
/**
* Increment the count for a key in an LRU-bounded map.
* Deletes and re-inserts to maintain LRU order, evicts the oldest entry when full.
*/
incrementKeys(map: Map<string, number>, compositeKey: string): void;
/**
* Subscribe to telemetry events from an emitter (e.g. a Keyv instance).
* Automatically increments the corresponding stat counters and LRU key maps on each event.
* @param {IEventEmitter} emitter the event emitter to subscribe to
*/
subscribe(emitter: IEventEmitter): void;
/**
* Unsubscribe from the currently subscribed emitter, removing all telemetry event listeners.
*/
unsubscribe(): void;
/**
* Reset all counters and LRU key maps to their initial state.
*/
reset(): void;
}
//#endregion
//#region src/types/keyv.d.ts
/**
* A Map or any Map-like object. Used as a flexible input type for stores.
*/
type KeyvMapAny = Map<any, any> | any;
/**
* The envelope structure used to store values in Keyv.
* Wraps the actual value with an optional expiration timestamp.
*/
type KeyvValue<Value> = {
/** The stored value. */value?: Value; /** Absolute expiration timestamp in milliseconds since epoch, or `undefined` for no expiry. */
expires?: number | undefined;
};
/** @deprecated Use `KeyvValue` instead. */
type DeserializedData<Value> = KeyvValue<Value>;
/**
* Events emitted by Keyv for error handling and telemetry.
*/
declare enum KeyvEvents {
/** Emitted when an error occurs in a store operation. */
ERROR = "error",
/** Emitted for informational messages. */
INFO = "info",
/** Emitted for warning messages. */
WARN = "warn",
/** Telemetry: cache hit. */
STAT_HIT = "stat:hit",
/** Telemetry: cache miss. */
STAT_MISS = "stat:miss",
/** Telemetry: value set. */
STAT_SET = "stat:set",
/** Telemetry: value deleted. */
STAT_DELETE = "stat:delete",
/** Telemetry: operation error. */
STAT_ERROR = "stat:error"
}
/**
* Hook names for intercepting Keyv operations.
* Register hooks via `keyv.on(KeyvHooks.BEFORE_SET, callback)` to run logic before/after operations.
*/
declare enum KeyvHooks {
PRE_SET = "preSet",
POST_SET = "postSet",
PRE_GET = "preGet",
POST_GET = "postGet",
PRE_GET_MANY = "preGetMany",
POST_GET_MANY = "postGetMany",
PRE_GET_RAW = "preGetRaw",
POST_GET_RAW = "postGetRaw",
PRE_GET_MANY_RAW = "preGetManyRaw",
POST_GET_MANY_RAW = "postGetManyRaw",
PRE_SET_RAW = "preSetRaw",
POST_SET_RAW = "postSetRaw",
PRE_SET_MANY_RAW = "preSetManyRaw",
POST_SET_MANY_RAW = "postSetManyRaw",
PRE_DELETE = "preDelete",
POST_DELETE = "postDelete"
/** @deprecated Use BEFORE_SET instead */
PRE_SET = "preSet",
/** @deprecated Use AFTER_SET instead */
POST_SET = "postSet",
/** @deprecated Use BEFORE_GET instead */
PRE_GET = "preGet",
/** @deprecated Use AFTER_GET instead */
POST_GET = "postGet",
/** @deprecated Use BEFORE_GET_MANY instead */
PRE_GET_MANY = "preGetMany",
/** @deprecated Use AFTER_GET_MANY instead */
POST_GET_MANY = "postGetMany",
/** @deprecated Use BEFORE_GET_RAW instead */
PRE_GET_RAW = "preGetRaw",
/** @deprecated Use AFTER_GET_RAW instead */
POST_GET_RAW = "postGetRaw",
/** @deprecated Use BEFORE_GET_MANY_RAW instead */
PRE_GET_MANY_RAW = "preGetManyRaw",
/** @deprecated Use AFTER_GET_MANY_RAW instead */
POST_GET_MANY_RAW = "postGetManyRaw",
/** @deprecated Use BEFORE_SET_RAW instead */
PRE_SET_RAW = "preSetRaw",
/** @deprecated Use AFTER_SET_RAW instead */
POST_SET_RAW = "postSetRaw",
/** @deprecated Use BEFORE_SET_MANY_RAW instead */
PRE_SET_MANY_RAW = "preSetManyRaw",
/** @deprecated Use AFTER_SET_MANY_RAW instead */
POST_SET_MANY_RAW = "postSetManyRaw",
/** @deprecated Use BEFORE_SET_MANY instead */
PRE_SET_MANY = "preSetMany",
/** @deprecated Use AFTER_SET_MANY instead */
POST_SET_MANY = "postSetMany",
/** @deprecated Use BEFORE_DELETE instead */
PRE_DELETE = "preDelete",
/** @deprecated Use AFTER_DELETE instead */
POST_DELETE = "postDelete",
/** @deprecated Use BEFORE_DELETE_MANY instead */
PRE_DELETE_MANY = "preDeleteMany",
/** @deprecated Use AFTER_DELETE_MANY instead */
POST_DELETE_MANY = "postDeleteMany",
BEFORE_SET = "before:set",
AFTER_SET = "after:set",
BEFORE_GET = "before:get",
AFTER_GET = "after:get",
BEFORE_GET_MANY = "before:getMany",
AFTER_GET_MANY = "after:getMany",
BEFORE_GET_RAW = "before:getRaw",
AFTER_GET_RAW = "after:getRaw",
BEFORE_GET_MANY_RAW = "before:getManyRaw",
AFTER_GET_MANY_RAW = "after:getManyRaw",
BEFORE_SET_RAW = "before:setRaw",
AFTER_SET_RAW = "after:setRaw",
BEFORE_SET_MANY = "before:setMany",
AFTER_SET_MANY = "after:setMany",
BEFORE_SET_MANY_RAW = "before:setManyRaw",
AFTER_SET_MANY_RAW = "after:setManyRaw",
BEFORE_DELETE = "before:delete",
AFTER_DELETE = "after:delete",
BEFORE_DELETE_MANY = "before:deleteMany",
AFTER_DELETE_MANY = "after:deleteMany",
BEFORE_HAS = "before:has",
AFTER_HAS = "after:has",
BEFORE_HAS_MANY = "before:hasMany",
AFTER_HAS_MANY = "after:hasMany",
BEFORE_CLEAR = "before:clear",
AFTER_CLEAR = "after:clear",
BEFORE_DISCONNECT = "before:disconnect",
AFTER_DISCONNECT = "after:disconnect"
}
type KeyvEntry = {
/**
* Key to set.
*/
key: string;
/**
* Value to set.
*/
value: any;
/**
* Time to live in milliseconds.
*/
ttl?: number;
/**
* Represents a key-value entry with an optional TTL, used for batch operations like `setMany`.
*/
type KeyvEntry<Value = any> = {
/**
* Key to set.
*/
key: string;
/**
* Value to set.
*/
value: Value;
/**
* Time to live in milliseconds.
*/
ttl?: number;
};
type StoredDataNoRaw<Value> = Value | undefined;
type StoredDataRaw<Value> = DeserializedData<Value> | undefined;
type StoredData<Value> = StoredDataNoRaw<Value> | StoredDataRaw<Value>;
type IEventEmitter = {
on(event: string, listener: (...arguments_: any[]) => void): IEventEmitter;
/**
* Configuration options for the Keyv constructor.
*/
type KeyvOptions = {
/**
* Namespace for the current instance.
* @default undefined
*/
namespace?: string;
/**
* A custom serialization adapter with stringify and parse methods.
* @default KeyvJsonSerializer (built-in)
*/
serialization?: KeyvSerializationAdapter | false;
/**
* The storage adapter instance to be used by Keyv.
* @default new Map() - in-memory store
*/
store?: KeyvStorageAdapter | Map<any, any> | any;
/**
* Default TTL in milliseconds. Can be overridden by specifying a TTL on `.set()`.
* @default undefined
*/
ttl?: number;
/**
* Enable compression option
* @default undefined
*/
compression?: KeyvCompressionAdapter | any;
/**
* Enable or disable statistics (default is false)
* @default false
*/
stats?: boolean;
/**
* Will throw on all errors if this is enabled to true. By default, errors
* will only throw if there are no listeners to the error event.
* This maps to hookified's `throwOnEmitError` under the hood.
* @default false
*/
throwOnErrors?: boolean;
/**
* Enable sanitization of keys and namespaces by detecting dangerous patterns
* for SQL, MongoDB, or filesystem-based storage backends. Pass a `KeyvSanitizeOptions`
* object for granular control over targets and patterns.
* @default undefined
*/
sanitize?: KeyvSanitizeOptions;
/**
* Enable encryption of stored values. Pass a `KeyvEncryptionAdapter` with
* `encrypt` and `decrypt` methods.
* @default undefined
*/
encryption?: KeyvEncryptionAdapter;
/**
* When true, Keyv checks expiry on get/getMany/has/hasMany at its layer.
* When false (default), trusts the storage adapter to handle expiry.
* @default false
*/
checkExpired?: boolean;
};
//#endregion
//#region src/types/adapters.d.ts
/**
* Adapter interface for custom serialization.
* Implement `stringify` and `parse` to control how values are serialized to/from strings.
*/
type KeyvSerializationAdapter = {
/** Converts a value to a string representation. */stringify: (object: unknown) => string | Promise<string>; /** Parses a string back into its original value. */
parse: <T>(data: string) => T | Promise<T>;
};
/**
* Adapter interface for compression.
* Implement `compress` and `decompress` to add compression to stored values.
*/
type KeyvCompressionAdapter = {
/** Compresses a string value. */compress(value: string): Promise<string>; /** Decompresses a string value back to its original form. */
decompress(value: string): Promise<string>;
};
/**
* Adapter interface for encryption.
* Implement `encrypt` and `decrypt` to add encryption to stored values.
*/
type KeyvEncryptionAdapter = {
/** Encrypts a string value. */encrypt: (data: string) => string | Promise<string>; /** Decrypts a string value back to its original form. */
decrypt: (data: string) => string | Promise<string>;
};
type KeyvStorageGetResult<Value> = KeyvValue<Value> | string | undefined;
/**
* Interface that all Keyv storage adapters must implement.
* Adapters handle the actual persistence of key-value pairs.
*/
type KeyvStorageAdapter = {
opts: any;
namespace?: string | undefined;
get<Value>(key: string): Promise<StoredData<Value> | undefined>;
set(key: string, value: any, ttl?: number): any;
setMany?(values: Array<{
key: string;
value: any;
ttl?: number;
}>): Promise<void>;
delete(key: string): Promise<boolean>;
clear(): Promise<void>;
has?(key: string): Promise<boolean>;
hasMany?(keys: string[]): Promise<boolean[]>;
getMany?<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
disconnect?(): Promise<void>;
deleteMany?(key: string[]): Promise<boolean>;
iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
/** Optional namespace for key isolation. */namespace?: string | undefined; /** Detected capabilities of the underlying store. */
capabilities?: KeyvStorageCapability; /** Retrieves a value by key. */
get<Value>(key: string): Promise<KeyvStorageGetResult<Value>>; /** Stores a value with a key and optional TTL in milliseconds. */
set(key: string, value: unknown, ttl?: number): Promise<boolean>; /** Stores multiple entries at once. */
setMany<Value>(values: KeyvEntry<Value>[]): Promise<boolean[] | undefined>; /** Deletes a key from the store. */
delete(key: string): Promise<boolean>; /** Clears all entries from the store (respects namespace if set). */
clear(): Promise<void>; /** Checks if a key exists in the store. */
has(key: string): Promise<boolean>; /** Checks if multiple keys exist in the store. */
hasMany(keys: string[]): Promise<boolean[]>; /** Retrieves multiple values by keys. */
getMany<Value>(keys: string[]): Promise<Array<KeyvStorageGetResult<Value | undefined>>>; /** Disconnects from the store and releases resources. */
disconnect?(): Promise<void>; /** Deletes multiple keys from the store. */
deleteMany(key: string[]): Promise<boolean[]>; /** Returns an async iterator over all key-value pairs. */
iterator?<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
} & IEventEmitter;
type KeyvOptions = {
/**
* Emit errors
* @default true
*/
emitErrors?: boolean;
/**
* Namespace for the current instance.
* @default 'keyv'
*/
namespace?: string;
/**
* A custom serialization adapter with stringify and parse methods.
* @default KeyvJsonSerializer (built-in)
*/
serialization?: KeyvSerializationAdapter | false;
/**
* The storage adapter instance to be used by Keyv.
* @default new Map() - in-memory store
*/
store?: KeyvStorageAdapter | Map<any, any> | any;
/**
* Default TTL in milliseconds. Can be overridden by specifying a TTL on `.set()`.
* @default undefined
*/
ttl?: number;
/**
* Enable compression option
* @default false
*/
compression?: KeyvCompressionAdapter | any;
/**
* Enable or disable statistics (default is false)
* @default false
*/
stats?: boolean;
/**
* Will enable throwing errors on methods in addition to emitting them.
* @default false
*/
throwOnErrors?: boolean;
};
/**

@@ -163,228 +627,726 @@ * @deprecated Use `KeyvStorageAdapter` instead.

type KeyvCompression = KeyvCompressionAdapter;
//#endregion
//#region src/adapters/bridge.d.ts
/**
* Configuration options for KeyvBridgeAdapter.
*/
type KeyvBridgeAdapterOptions = {
/**
* The namespace to use for keys.
* When set, all keys will be prefixed with the namespace followed by the key separator.
*/
namespace?: string;
/**
* The separator used between namespace and key. Defaults to ":".
*/
keySeparator?: string;
};
/**
* Interface for a promise-based store that can be used with KeyvBridgeAdapter.
* The store must implement get, set, delete, and clear as async operations.
* Optional methods (has, hasMany, getMany, setMany, deleteMany, iterator, disconnect)
* will be delegated to the store if present, otherwise fallback implementations are used.
*/
type KeyvBridgeStore = {
/** Store configuration/options (e.g. dialect, url) */opts?: any; /** Retrieves a value by key */
get(key: string): Promise<any>; /** Sets a value with a key and optional TTL */
set(key: string, value: any, ttl?: number): Promise<any>; /** Deletes a key from the store */
delete(key: string): Promise<boolean>; /** Clears all entries from the store */
clear(): Promise<void>; /** Checks if a key exists in the store */
has?(key: string): Promise<boolean>; /** Checks if multiple keys exist in the store */
hasMany?(keys: string[]): Promise<boolean[]>; /** Retrieves multiple values by keys */
getMany?(keys: string[]): Promise<any[]>; /** Sets multiple entries at once */
setMany?(entries: any[]): Promise<any>; /** Deletes multiple keys at once */
deleteMany?(keys: string[]): Promise<boolean | boolean[]>; /** Iterates over all entries, optionally filtered by namespace */
iterator?(namespace?: string): AsyncGenerator<any>; /** Disconnects from the store */
disconnect?(): Promise<void>; /** Subscribe to events (e.g. error events from v5 adapters) */
on?(event: string, listener: (...args: any[]) => void): any;
};
/**
* Data structure returned when parsing a prefixed key.
*/
type KeyPrefixData = {
/** The namespace extracted from the key, if present */namespace?: string; /** The key without the namespace prefix */
key: string;
};
/**
* A bridge storage adapter for Keyv that wraps any promise-based store.
*
* This class provides a unified interface for using various async stores
* with Keyv, handling namespace prefixing, TTL-based expiration, and batch operations.
* If the underlying store implements optional methods (has, hasMany, getMany, etc.),
* the bridge will delegate to them. Otherwise, it falls back to using primitives.
*
* @example
* ```typescript
* // Using with a promise-based store
* const bridge = new KeyvBridgeAdapter(myAsyncStore, { namespace: 'cache' });
*
* // Using with Keyv
* const keyv = new Keyv({ store: new KeyvBridgeAdapter(myAsyncStore) });
* ```
*/
declare class KeyvBridgeAdapter extends Hookified implements KeyvStorageAdapter {
private _store;
private _namespace?;
private _keySeparator;
private readonly _capabilities;
/**
* Creates a new KeyvBridgeAdapter instance.
* @param store - The underlying promise-based store to bridge
* @param options - Configuration options for the adapter
*/
constructor(store: KeyvBridgeStore, options?: KeyvBridgeAdapterOptions);
/**
* Gets the underlying store instance.
*/
get store(): KeyvBridgeStore;
/**
* Sets the underlying store instance.
*/
set store(store: KeyvBridgeStore);
/**
* Gets the detected capabilities of the underlying store.
*/
get capabilities(): KeyvStorageCapability;
/**
* Gets the current key separator used between namespace and key.
*/
get keySeparator(): string;
/**
* Sets the key separator used between namespace and key.
*/
set keySeparator(separator: string);
/**
* Gets the current namespace.
*/
get namespace(): string | undefined;
/**
* Sets the namespace.
*/
set namespace(namespace: string | undefined);
/**
* Creates a prefixed key by combining the namespace and key with the separator.
* @param key - The base key
* @param namespace - Optional namespace to prefix the key with
* @returns The prefixed key if namespace is provided, otherwise the original key
*/
getKeyPrefix(key: string, namespace?: string): string;
/**
* Parses a prefixed key to extract the namespace and original key.
* @param key - The prefixed key to parse
* @returns An object containing the namespace (if present) and the original key
*/
getKeyPrefixData(key: string): KeyPrefixData;
/**
* Retrieves a value from the store by key.
* Automatically handles namespace prefixing and TTL expiration.
* @param key - The key to retrieve
* @returns The stored data, or undefined if not found or expired
*/
get<T>(key: string): Promise<KeyvStorageGetResult<T>>;
/**
* Retrieves multiple values from the store by their keys.
* Delegates to the store's native getMany if available.
* @param keys - Array of keys to retrieve
* @returns Array of stored data in the same order as the input keys
*/
getMany<T>(keys: string[]): Promise<Array<KeyvStorageGetResult<T | undefined>>>;
/**
* Stores a value in the store with an optional TTL.
* @param key - The key to store the value under
* @param value - The value to store
* @param ttl - Optional time-to-live in milliseconds
* @returns Always returns true indicating success
*/
set(key: string, value: any, ttl?: number): Promise<boolean>;
/**
* Stores multiple entries in the store at once.
* Delegates to the store's native setMany if available, otherwise loops over set.
* @param entries - Array of entries containing key, value, and optional TTL
*/
setMany<Value>(entries: KeyvEntry<Value>[]): Promise<boolean[] | undefined>;
/**
* Checks if a key exists in the store and is not expired.
* Delegates to the store's native has if available.
* @param key - The key to check
* @returns True if the key exists and is not expired, false otherwise
*/
has(key: string): Promise<boolean>;
/**
* Checks if multiple keys exist in the store and are not expired.
* Delegates to the store's native hasMany if available.
* @param keys - Array of keys to check
* @returns Array of booleans indicating existence for each key
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Deletes a value from the store by key.
* @param key - The key to delete
* @returns True if the key was deleted, false otherwise
*/
delete(key: string): Promise<boolean>;
/**
* Deletes multiple keys from the store at once.
* Delegates to the store's native deleteMany if available.
* @param keys - Array of keys to delete
* @returns Array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Clears entries from the store. If a namespace is set and the store supports
* iteration, only entries within that namespace are removed. Otherwise, the
* entire store is cleared.
*/
clear(): Promise<void>;
/**
* Creates an async iterator for iterating over store entries.
* If the underlying store does not support iteration, returns an empty generator.
* @returns An async generator yielding [key, value] pairs
*/
iterator<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
/**
* Disconnects from the underlying store.
* No-op if the store does not support disconnect.
*/
disconnect(): Promise<void>;
}
//#endregion
//#region src/keyv.d.ts
declare class Keyv<GenericValue = any> extends Hookified {
/**
* Stats manager for tracking cache operation metrics (hits, misses, sets, deletes, errors).
* @default this is disabled.
*/
private _stats;
/**
* Default time to live in milliseconds. Can be overridden per-key via {@link set}.
*/
private _ttl?;
/**
* Key prefix namespace used to isolate keys across different Keyv instances sharing the same store.
*/
private _namespace?;
/**
* The underlying storage adapter. Defaults to an in-memory {@link Map}.
*/
private _store;
/**
* Pluggable serialization adapter with `stringify` and `parse` methods.
* When `undefined`, the built-in {@link KeyvJsonSerializer} is used.
*/
private _serialization;
/**
* Pluggable compression adapter with `compress` and `decompress` methods.
*/
private _compression;
/**
* Pluggable encryption adapter with `encrypt` and `decrypt` methods.
*/
private _encryption;
/**
* Sanitization handler for keys and namespaces. By default it is disabled.
*/
private _sanitize;
/**
* When true, Keyv checks expiry at its layer on get/getMany/has/hasMany.
*/
private _checkExpired;
/**
* Keyv Constructor
* @param {KeyvStorageAdapter | KeyvOptions | Map<any, any> | any} store to be provided or just the options
* @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
*/
constructor(store?: KeyvStorageAdapter | KeyvOptions | KeyvMapAny, options?: Omit<KeyvOptions, "store">);
/**
* Keyv Constructor
* @param {KeyvOptions} options to be provided
*/
constructor(options?: KeyvOptions);
/**
* Get the current storage adapter.
* @returns {KeyvStorageAdapter} The current storage adapter.
*/
get store(): KeyvStorageAdapter;
/**
* Set the storage adapter.
* @param {KeyvStorageAdapter | Map<any, any> | any} store The storage adapter to set.
*/
set store(store: KeyvStorageAdapter | KeyvMapAny);
/**
* Get the current compression adapter.
* @returns {KeyvCompressionAdapter | undefined} The current compression adapter.
*/
get compression(): KeyvCompressionAdapter | undefined;
/**
* Set the compression adapter.
* @param {KeyvCompressionAdapter | undefined} compress The compression adapter to set.
*/
set compression(compress: KeyvCompressionAdapter | undefined);
/**
* Get the current encryption adapter.
* @returns {KeyvEncryptionAdapter | undefined} The current encryption adapter.
*/
get encryption(): KeyvEncryptionAdapter | undefined;
/**
* Set the encryption adapter.
* @param {KeyvEncryptionAdapter | undefined} encryption The encryption adapter to set.
*/
set encryption(encryption: KeyvEncryptionAdapter | undefined);
/**
* Get the current namespace.
* @returns {string | undefined} The current namespace.
*/
get namespace(): string | undefined;
/**
* Set the current namespace.
* @param {string | undefined} namespace The namespace to set.
*/
set namespace(namespace: string | undefined);
/**
* Get the current TTL.
* @returns {number} The current TTL in milliseconds.
*/
get ttl(): number | undefined;
/**
* Set the current TTL.
* @param {number} ttl The TTL to set in milliseconds.
*/
set ttl(ttl: number | undefined);
/**
* Get the current serialization adapter. If `undefined`, serialization is not enabled.
* @returns {KeyvSerializationAdapter | undefined} The current serialization adapter.
*/
get serialization(): KeyvSerializationAdapter | undefined;
/**
* Set the current serialization adapter. Pass a `KeyvSerializationAdapter` to enable
* custom serialization, or `undefined` to disable serialization entirely.
* @param {KeyvSerializationAdapter | undefined} serialization The serialization adapter to set.
*/
set serialization(serialization: KeyvSerializationAdapter | false | undefined);
/**
* Get the current throwOnErrors value. When enabled, all errors with throw. By default, errors
* will only throw if there are no listeners to the error event.
* @return {boolean} The current throwOnErrors value.
*/
get throwOnErrors(): boolean;
/**
* Set the current throwOnErrors value. When enabled, all errors will throw. By default, errors
* will only throw if there are no listeners to the error event.
* @param {boolean} value The throwOnErrors value to set.
*/
set throwOnErrors(value: boolean);
/**
* Get the current sanitize adapter. Sanitization is disabled by default. To
* enable it `sanitize.keys` or `sanitize.namespace` to true or set KeyvSanitizePatterns
* to each.
* @returns {KeyvSanitizeAdapter} The current sanitize adapter.
*/
get sanitize(): KeyvSanitizeAdapter;
/**
* Set the sanitize adapter directly and will run sanitization on namespace.
* @param {KeyvSanitizeAdapter} value The sanitize adapter to use.
*/
set sanitize(value: KeyvSanitizeAdapter);
/**
* Get the stats. This is just for this instance
* @returns {KeyvStats} The current stats.
*/
get stats(): KeyvStats;
/**
* When true, Keyv checks expiry at its layer on get/getMany/has/hasMany.
* When false (default), trusts the storage adapter.
*/
get checkExpired(): boolean;
/**
* Set the stats. When setting a new instance it will unsubscribe the old listeners
* and subscribe the new instance.
* @param {KeyvStats} stats The stats instance to set.
*/
set stats(stats: KeyvStats);
/**
* Resolves a store to a fully-compliant KeyvStorageAdapter using a 3-tier detection chain:
* 1. If the store already implements the full KeyvStorageAdapter interface, use it directly.
* 2. If the store is map-like (synchronous get/set/delete/has), wrap it in KeyvMemoryAdapter.
* 3. If the store has async get/set/delete/clear, wrap it in KeyvBridgeAdapter.
* 4. Otherwise, emit an error and fall back to a default in-memory KeyvMemoryAdapter.
*
* NOTE: this is used for internal but provided public for custom adapter testing
* @param {unknown} store The store to resolve.
* @returns {KeyvStorageAdapter} A fully-compliant storage adapter.
*/
resolveStore(store: any): KeyvStorageAdapter;
/**
* Sets the storage adapter by resolving it via {@link resolveStore}, then wires up
* error forwarding and namespace propagation.
* @param {KeyvStorageAdapter | Map<any, any> | any} store The storage adapter to set.
*/
setStore(store: KeyvStorageAdapter | KeyvMapAny): void;
/**
* Sets the TTL, treating zero and negative values as undefined (no TTL).
* @param {number | undefined} ttl The TTL to set in milliseconds.
*/
setTtl(ttl?: number): void;
/**
* Get the Value of a Key
* @param {string | string[]} key passing in a single key or multiple as an array
*/
get<Value = GenericValue>(key: string): Promise<Value | undefined>;
get<Value = GenericValue>(key: string[]): Promise<Array<Value | undefined>>;
/**
* Get many values of keys
* @param {string[]} keys passing in a single key or multiple as an array
*/
getMany<Value = GenericValue>(keys: string[]): Promise<Array<Value | undefined>>;
/**
* Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
* @param {string} key the key to get
* @returns {Promise<KeyvStorageGetResult<Value>>} will return a KeyvStorageGetResult<Value> or undefined
* if the key does not exist or is expired.
*/
getRaw<Value = GenericValue>(key: string): Promise<KeyvStorageGetResult<Value>>;
/**
* Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
* @param {string[]} keys the keys to get
* @returns {Promise<Array<KeyvStorageGetResult<Value>>>} will return an array of KeyvStorageGetResult<Value> or undefined if the key does not exist or is expired.
*/
getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<KeyvStorageGetResult<Value>>>;
/**
* Set an item to the store
* @param {string | Array<KeyvEntry<Value>>} key the key to use. If you pass in an array of KeyvEntry it will set many items
* @param {Value} value the value of the key
* @param {number} [ttl] time to live in milliseconds
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
set<Value = GenericValue>(key: string, value: Value, ttl?: number): Promise<boolean>;
/**
* Set many items to the store
* @param {Array<KeyvEntry<Value>>} entries the entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setMany<Value = GenericValue>(entries: KeyvEntry<Value>[]): Promise<boolean[]>;
/**
* Set a raw value to the store without wrapping or serialization. This is the write-side counterpart to getRaw().
* The value should be a KeyvValue object with { value, expires? }. 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`.
* @param {string} key the key to set
* @param {KeyvValue<Value>} value the raw value envelope to store
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
setRaw<Value = GenericValue>(key: string, value: KeyvValue<Value>): Promise<boolean>;
/**
* Set many raw values to the store without wrapping or serialization. This is the write-side counterpart to getManyRaw().
* Each entry's value should be a KeyvValue object with { value, expires? }. If you need TTL-based expiration,
* set `expires` on each value directly. The store-level TTL is derived automatically from `value.expires`.
* @param {KeyvEntry<KeyvValue<Value>>[]} entries the raw entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setManyRaw<Value = GenericValue>(entries: KeyvEntry<KeyvValue<Value>>[]): Promise<boolean[]>;
/**
* Delete an Entry
* @param {string} key the key to be deleted
* @returns {boolean} will return true if item is deleted. false if there is an error
*/
delete(key: string): Promise<boolean>;
/**
* Delete multiple Entries
* @param {string[]} keys the keys to be deleted
* @returns {boolean[]} will return array of booleans for each key
*/
delete(keys: string[]): Promise<boolean[]>;
/**
* Delete many items from the store
* @param {string[]} keys the keys to be deleted
* @returns {boolean[]} array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Has a key.
* @param {string} key the key to check
* @returns {boolean} will return true if the key exists
*/
has(key: string[]): Promise<boolean[]>;
has(key: string): Promise<boolean>;
/**
* Check if many keys exist
* @param {string[]} keys the keys to check
* @returns {boolean[]} will return an array of booleans if the keys exist
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Clear the store
* @returns {void}
*/
clear(): Promise<void>;
/**
* Will disconnect the store. This is only available if the store has a disconnect method
* @returns {Promise<void>}
*/
disconnect(): Promise<void>;
/**
* Iterate over all key-value pairs in the store. Automatically deserializes values,
* filters out expired entries, and deletes them from the store.
* @returns {AsyncGenerator<Array<string | unknown>, void>} An async generator yielding `[key, value]` pairs.
*/
iterator(): AsyncGenerator<[string, any], void>;
/**
* Encodes a value for storage. Pipeline: serialize → compress → encrypt.
* If serialization is not configured, returns the data as-is.
* @param {KeyvValue<T>} data The value envelope to encode.
* @returns {Promise<unknown>} The encoded value, or the original data on failure.
*/
encode<T>(data: KeyvValue<T>): Promise<unknown>;
/**
* Decodes a stored value. Pipeline: decrypt → decompress → deserialize (reverse of encode).
* If serialization is not configured, returns the data as a KeyvValue or undefined for strings.
* @param {unknown} data The raw data from the store.
* @returns {Promise<KeyvValue<T> | undefined>} The decoded value envelope, or undefined on failure.
*/
decode<T>(data: unknown): Promise<KeyvValue<T> | undefined>;
/**
* Deserializes raw data from the store, checks for expiry, and deletes expired keys.
* Accepts a single key/value or arrays. Returns an array of decoded KeyvValue objects
* (undefined for missing or expired entries).
* @param {string | string[]} keys the key(s) to process
* @param {unknown | unknown[]} rawData the raw data from the store
* @returns {Promise<Array<KeyvValue<Value> | undefined>>} decoded values with expired entries removed
*/
decodeWithExpire<Value>(keys: string | string[], rawData: unknown | unknown[]): Promise<Array<KeyvValue<Value> | undefined>>;
/**
* Fires a hook under its new name and also under the deprecated alias (if any),
* so that integrations still subscribing to the old PRE_/POST_ names keep working.
*/
private hookWithDeprecated;
/**
* Emit a telemetry event for cache operations.
* @param {KeyvEvents} event the telemetry event type
* @param {string | string[]} [key] the cache key or keys (emits one event per key)
*/
private emitTelemetry;
/**
* Merges the overloaded constructor arguments into a single KeyvOptions object.
*/
private static resolveOptions;
/**
* Initializes the serialization adapter from options.
*/
private initSerialization;
/**
* Initializes the sanitization handler from options.
*/
private initSanitize;
/**
* Initializes the stats manager from options.
*/
private initStats;
/**
* Initializes the namespace, applying sanitization if enabled.
*/
private initNamespace;
}
//#endregion
//#region src/adapters/memory.d.ts
/**
* Configuration options for KeyvMemoryAdapter.
*/
type KeyvMemoryAdapterOptions = {
/**
* The namespace to use for keys.
* When set, all keys will be prefixed with the namespace followed by the key separator.
*/
namespace?: string;
/**
* The separator used between namespace and key. Defaults to ":".
*/
keySeparator?: string;
};
/**
* Interface for a Map-like store that can be used with KeyvMemoryAdapter.
* This allows any object implementing these methods to be used as the underlying storage.
* Compatible with Map, QuickLRU, lru.min, and other LRU cache implementations.
*/
type KeyvMapType = {
/** Retrieves a value by key */get: (key: string) => any; /** Sets a value with a key. Additional parameters (like TTL) vary by implementation. */
set: (key: string, value: any, ...args: any[]) => any; /** Deletes a key from the store */
delete: (key: string) => boolean; /** Clears all entries from the store */
clear: () => void; /** Checks if a key exists in the store */
has: (key: string) => boolean;
};
/**
* An in-memory storage adapter for Keyv that wraps any Map-like object.
*
* This class provides a unified interface for using various Map-like stores
* with Keyv, handling namespace prefixing, TTL-based expiration, and batch operations.
*
* @example
* ```typescript
* // Using with a standard Map
* const store = new KeyvMemoryAdapter(new Map(), { namespace: 'cache' });
*
* // Using with a custom store
* const customStore = new KeyvMemoryAdapter(myCustomMapLikeStore, {
* namespace: 'tenant-123',
* keySeparator: ':'
* });
* ```
*/
declare class KeyvMemoryAdapter extends Hookified implements KeyvStorageAdapter {
private _store;
private _namespace?;
private _keySeparator;
private readonly _capabilities;
/**
* Creates a new KeyvMemoryAdapter instance.
* @param store - The underlying Map or Map-like object to use for storage
* @param options - Configuration options for the store
*/
constructor(store: KeyvMapType, options?: KeyvMemoryAdapterOptions);
/**
* Gets the detected capabilities of the underlying store.
*/
get capabilities(): KeyvStorageCapability;
/**
* Gets the underlying store instance.
*/
get store(): KeyvMapType;
/**
* Sets the underlying store instance.
*/
set store(store: KeyvMapType);
/**
* Gets the current key separator used between namespace and key.
*/
get keySeparator(): string;
/**
* Sets the key separator used between namespace and key.
*/
set keySeparator(separator: string);
/**
* Gets the current namespace.
*/
get namespace(): string | undefined;
/**
* Sets the namespace.
*/
set namespace(namespace: string | undefined);
/**
* Creates a prefixed key by combining the namespace and key with the separator.
* @param key - The base key
* @param namespace - Optional namespace to prefix the key with
* @returns The prefixed key if namespace is provided, otherwise the original key
*/
getKeyPrefix(key: string, namespace?: string): string;
/**
* Parses a prefixed key to extract the namespace and original key.
* @param key - The prefixed key to parse
* @returns An object containing the namespace (if present) and the original key
*/
getKeyPrefixData(key: string): {
namespace: string;
key: string;
} | {
key: string;
namespace?: undefined;
};
/**
* Retrieves a value from the store by key.
* Automatically handles namespace prefixing and TTL expiration.
* @param key - The key to retrieve
* @returns The stored data, or undefined if not found or expired
*/
get<T>(key: string): Promise<KeyvStorageGetResult<T>>;
/**
* Stores a value in the store with an optional TTL.
* @param key - The key to store the value under
* @param value - The value to store
* @param ttl - Optional time-to-live in milliseconds
* @returns Always returns true indicating success
*/
set(key: string, value: any, ttl?: number): Promise<boolean>;
/**
* Stores multiple entries in the store at once.
* @param entries - Array of entries containing key, value, and optional TTL
*/
setMany<Value>(entries: KeyvEntry<Value>[]): Promise<boolean[] | undefined>;
/**
* Deletes a value from the store by key.
* @param key - The key to delete
* @returns True if the key was deleted, false otherwise
*/
delete(key: string): Promise<boolean>;
/**
* Clears entries from the store. If a namespace is set, only entries
* within that namespace are removed. Otherwise, the entire store is cleared.
* NOTE: if there is no `keys()` then we just do a full clear.
*/
clear(): Promise<void>;
/**
* Checks if a key exists in the store and is not expired.
* @param key - The key to check
* @returns True if the key exists and is not expired, false otherwise
*/
has(key: string): Promise<boolean>;
/**
* Checks if multiple keys exist in the store and are not expired.
* @param keys - Array of keys to check
* @returns Array of booleans indicating existence for each key
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Retrieves multiple values from the store by their keys.
* @param keys - Array of keys to retrieve
* @returns Array of stored data in the same order as the input keys
*/
getMany<T>(keys: string[]): Promise<Array<KeyvStorageGetResult<T | undefined>>>;
/**
* Deletes multiple keys from the store at once.
* @param keys - Array of keys to delete
* @returns Array of booleans indicating success for each key
*/
deleteMany(keys: string[]): Promise<boolean[]>;
/**
* Creates an async iterator for iterating over store entries.
* If the underlying store does not support iteration, returns an empty generator.
* @returns {AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>} An async generator yielding [key, value] pairs
*/
iterator<Value>(): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
/**
* No-op disconnect for in-memory stores.
*/
disconnect(): Promise<void>;
}
/**
* Creates a Keyv instance with a memory adapter optimized for in-memory storage.
*
* This factory function configures Keyv to bypass serialization/deserialization
* and key prefixing, resulting in faster performance for in-memory use cases
* where data doesn't need to be persisted or transmitted.
*
* @param store - The underlying Map or Map-like object to use for storage
* @param options - Configuration options for the memory adapter
* @returns A configured Keyv instance with optimized settings for in-memory storage
*
* @example
* ```typescript
* // Create a simple in-memory cache
* const cache = createKeyv(new Map());
* await cache.set('user:1', { name: 'John' });
*
* // Create with namespace for multi-tenant scenarios
* const tenantCache = createKeyv(new Map(), {
* namespace: 'tenant-123',
* keySeparator: ':'
* });
* ```
*/
declare function createKeyv(store: KeyvMapType, options?: KeyvMemoryAdapterOptions): Keyv<any>;
//#endregion
//#region src/json-serializer.d.ts
declare class KeyvJsonSerializer implements KeyvSerializationAdapter {
stringify(object: unknown): string;
parse<T>(data: string): T;
stringify(object: unknown): string;
parse<T>(data: string): T;
}
declare const jsonSerializer: KeyvJsonSerializer;
type IteratorFunction = (argument: any) => AsyncGenerator<any, void>;
declare class Keyv<GenericValue = any> extends EventManager {
iterator?: IteratorFunction;
hooks: HooksManager;
stats: StatsManager;
/**
* Time to live in milliseconds
*/
private _ttl?;
/**
* Namespace
*/
private _namespace?;
/**
* Store
*/
private _store;
private _serialization;
private _compression;
private _throwOnErrors;
private _emitErrors;
/**
* Keyv Constructor
* @param {KeyvStorageAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
* @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
*/
constructor(store?: KeyvStorageAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, "store">);
/**
* Keyv Constructor
* @param {KeyvOptions} options to be provided
*/
constructor(options?: KeyvOptions);
/**
* Get the current store
*/
get store(): KeyvStorageAdapter | Map<any, any> | any;
/**
* Set the current store. This will also set the namespace, event error handler, and generate the iterator. If the store is not valid it will throw an error.
* @param {KeyvStorageAdapter | Map<any, any> | any} store the store to set
*/
set store(store: KeyvStorageAdapter | Map<any, any> | any);
/**
* Get the current compression function
* @returns {KeyvCompressionAdapter} The current compression function
*/
get compression(): KeyvCompressionAdapter | undefined;
/**
* Set the current compression function
* @param {KeyvCompressionAdapter} compress The compression function to set
*/
set compression(compress: KeyvCompressionAdapter | undefined);
/**
* Get the current namespace.
* @returns {string | undefined} The current namespace.
*/
get namespace(): string | undefined;
/**
* Set the current namespace.
* @param {string | undefined} namespace The namespace to set.
*/
set namespace(namespace: string | undefined);
/**
* Get the current TTL.
* @returns {number} The current TTL in milliseconds.
*/
get ttl(): number | undefined;
/**
* Set the current TTL.
* @param {number} ttl The TTL to set in milliseconds.
*/
set ttl(ttl: number | undefined);
/**
* Get the current serialization adapter.
* @returns {KeyvSerializationAdapter | undefined} The current serialization adapter.
*/
get serialization(): KeyvSerializationAdapter | undefined;
/**
* Set the current serialization adapter.
* @param {KeyvSerializationAdapter | undefined} serialization The serialization adapter to set.
*/
set serialization(serialization: KeyvSerializationAdapter | false | undefined);
/**
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @return {boolean} The current throwOnErrors value.
*/
get throwOnErrors(): boolean;
/**
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @param {boolean} value The throwOnErrors value to set.
*/
set throwOnErrors(value: boolean);
/**
* Get the current emitErrors value. This will enable or disable emitting errors on methods.
* @return {boolean} The current emitErrors value.
* @default true
*/
get emitErrors(): boolean;
/**
* Set the current emitErrors value. This will enable or disable emitting errors on methods.
* @param {boolean} value The emitErrors value to set.
*/
set emitErrors(value: boolean);
generateIterator(iterator: IteratorFunction): IteratorFunction;
_checkIterableAdapter(): boolean;
_isValidStorageAdapter(store: KeyvStorageAdapter | any): boolean;
/**
* Get the Value of a Key
* @param {string | string[]} key passing in a single key or multiple as an array
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true }
*/
get<Value = GenericValue>(key: string, options?: {
raw: false;
}): Promise<StoredDataNoRaw<Value>>;
get<Value = GenericValue>(key: string, options?: {
raw: true;
}): Promise<StoredDataRaw<Value>>;
get<Value = GenericValue>(key: string[], options?: {
raw: false;
}): Promise<Array<StoredDataNoRaw<Value>>>;
get<Value = GenericValue>(key: string[], options?: {
raw: true;
}): Promise<Array<StoredDataRaw<Value>>>;
/**
* Get many values of keys
* @param {string[]} keys passing in a single key or multiple as an array
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true }
*/
getMany<Value = GenericValue>(keys: string[], options?: {
raw: false;
}): Promise<Array<StoredDataNoRaw<Value>>>;
getMany<Value = GenericValue>(keys: string[], options?: {
raw: true;
}): Promise<Array<StoredDataRaw<Value>>>;
/**
* Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
* @param {string} key the key to get
* @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
getRaw<Value = GenericValue>(key: string): Promise<StoredDataRaw<Value> | undefined>;
/**
* Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
* @param {string[]} keys the keys to get
* @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<StoredDataRaw<Value>>>;
/**
* Set an item to the store
* @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
* @param {Value} value the value of the key
* @param {number} [ttl] time to live in milliseconds
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
set<Value = GenericValue>(key: string, value: Value, ttl?: number): Promise<boolean>;
/**
* Set a raw value to the store without wrapping or serialization. This is the write-side counterpart to getRaw().
* The value should be a DeserializedData object with { value, expires? }.
* @param {string} key the key to set
* @param {DeserializedData<Value>} value the raw value envelope to store
* @param {number} [ttl] time to live in milliseconds. If the raw value does not already have an expires field, it will be computed from ttl.
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
setRaw<Value = GenericValue>(key: string, value: DeserializedData<Value>, ttl?: number): Promise<boolean>;
/**
* Set many items to the store
* @param {Array<KeyvEntry>} entries the entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setMany<Value = GenericValue>(entries: KeyvEntry[]): Promise<boolean[]>;
/**
* Set many raw values to the store without wrapping or serialization. This is the write-side counterpart to getManyRaw().
* Each entry's value should be a DeserializedData object with { value, expires? }.
* @param {Array<{key: string, value: DeserializedData<Value>, ttl?: number}>} entries the raw entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setManyRaw<Value = GenericValue>(entries: Array<{
key: string;
value: DeserializedData<Value>;
ttl?: number;
}>): Promise<boolean[]>;
/**
* Delete an Entry
* @param {string | string[]} key the key to be deleted. if an array it will delete many items
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
delete(key: string | string[]): Promise<boolean>;
/**
* Delete many items from the store
* @param {string[]} keys the keys to be deleted
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
deleteMany(keys: string[]): Promise<boolean>;
/**
* Clear the store
* @returns {void}
*/
clear(): Promise<void>;
/**
* Has a key
* @param {string} key the key to check
* @returns {boolean} will return true if the key exists
*/
has(key: string[]): Promise<boolean[]>;
has(key: string): Promise<boolean>;
/**
* Check if many keys exist
* @param {string[]} keys the keys to check
* @returns {boolean[]} will return an array of booleans if the keys exist
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Will disconnect the store. This is only available if the store has a disconnect method
* @returns {Promise<void>}
*/
disconnect(): Promise<void>;
emit(event: string, ...arguments_: any[]): void;
serializeData<T>(data: DeserializedData<T>): Promise<string | DeserializedData<T>>;
deserializeData<T>(data: string | DeserializedData<T>): Promise<DeserializedData<T> | undefined>;
}
export { type DeserializedData, type IEventEmitter, Keyv, type KeyvCompression, type KeyvCompressionAdapter, type KeyvEntry, KeyvHooks, KeyvJsonSerializer, type KeyvOptions, type KeyvSerializationAdapter, type KeyvStorageAdapter, type KeyvStoreAdapter, type StoredData, type StoredDataNoRaw, type StoredDataRaw, Keyv as default, jsonSerializer };
//#endregion
export { type DeserializedData, Keyv, Keyv as default, KeyvBridgeAdapter, type KeyvBridgeAdapterOptions, type KeyvBridgeStore, type KeyvCapability, type KeyvCompression, type KeyvCompressionAdapter, type KeyvCompressionCapability, type KeyvCompressionMethods, type KeyvEncryptionAdapter, type KeyvEncryptionCapability, type KeyvEncryptionMethods, type KeyvEntry, KeyvEvents, KeyvHooks, KeyvJsonSerializer, type KeyvMapAny, type KeyvMapType, KeyvMemoryAdapter, type KeyvMemoryAdapterOptions, type KeyvMethods, type KeyvOptions, type KeyvProperties, KeyvSanitize, type KeyvSanitizeAdapter, type KeyvSanitizeOptions, type KeyvSanitizePatterns, type KeyvSerializationAdapter, type KeyvSerializationCapability, type KeyvSerializationMethods, KeyvStats, type KeyvStatsOptions, type KeyvStorageAdapter, type KeyvStorageCapability, type KeyvStorageGetResult, type KeyvStorageMethod, type KeyvStorageMethods, type KeyvStoreAdapter, type KeyvTelemetryEvent, type KeyvValue, type MethodType, createKeyv, detectKeyv, detectKeyvCompression, detectKeyvEncryption, detectKeyvSerialization, detectKeyvStorage, jsonSerializer };
MIT License
Copyright (c) 2017-2021 Luke Childs
Copyright (c) 2021-2022 Jared Wray
Copyright (c) 2021-2026 Jared Wray

@@ -6,0 +6,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "keyv",
"version": "6.0.0-alpha.3",
"version": "6.0.0-beta.1",
"description": "Simple key-value storage with support for multiple backends",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {

@@ -16,4 +16,4 @@ ".": {

"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}

@@ -53,2 +53,5 @@ }

"homepage": "https://github.com/jaredwray/keyv",
"dependencies": {
"hookified": "^2.0.1"
},
"devDependencies": {

@@ -58,2 +61,5 @@ "@biomejs/biome": "^2.3.13",

"@vitest/coverage-v8": "^4.0.18",
"happy-dom": "^20.8.7",
"keyv-anyredis": "^3.3.0",
"keyv-file": "^5.3.3",
"lru.min": "^1.1.1",

@@ -71,6 +77,6 @@ "quick-lru": "^7.0.0",

"dist",
"LISCENCE"
"LICENSE"
],
"scripts": {
"build": "rimraf ./dist && tsup src/index.ts --format cjs,esm --dts --clean",
"build": "tsdown",
"lint": "biome check --write --error-on-warnings",

@@ -77,0 +83,0 @@ "lint:ci": "biome check --error-on-warnings",

+270
-56

@@ -7,2 +7,3 @@ <h1 align="center"><img width="250" src="https://jaredwray.com/images/keyv.svg" alt="keyv"></h1>

[![bun](https://github.com/jaredwray/keyv/actions/workflows/bun-test.yaml/badge.svg)](https://github.com/jaredwray/keyv/actions/workflows/bun-test.yaml)
[![browser](https://github.com/jaredwray/keyv/actions/workflows/browser-compat.yaml/badge.svg)](https://github.com/jaredwray/keyv/actions/workflows/browser-compat.yaml)
[![codecov](https://codecov.io/gh/jaredwray/keyv/branch/main/graph/badge.svg?token=bRzR3RyOXZ)](https://codecov.io/gh/jaredwray/keyv)

@@ -41,2 +42,3 @@ [![npm](https://img.shields.io/npm/dm/keyv.svg)](https://www.npmjs.com/package/keyv)

- [Compression](#compression)
- [Capability Detection](#capability-detection)
- [API](#api)

@@ -53,2 +55,3 @@ - [new Keyv([storage-adapter], [options]) or new Keyv([options])](#new-keyvstorage-adapter-options-or-new-keyvoptions)

- [.stats](#stats)
- [.sanitize](#sanitize)
- [Keyv Instance](#keyv-instance)

@@ -61,3 +64,3 @@ - [.set(key, value, [ttl])](#setkey-value-ttl)

- [.getManyRaw(keys)](#getmanyrawkeys)
- [.setRaw(key, value, [ttl])](#setrawkey-value-ttl)
- [.setRaw(key, value)](#setrawkey-value)
- [.setManyRaw(entries)](#setmanyrawentries)

@@ -309,34 +312,39 @@ - [.delete(key)](#deletekey)

## Custom Serializers
## Official Serializers
You can provide your own serializer by implementing the `KeyvSerializationAdapter` interface:
In addition to the built-in serializer, Keyv offers two official serialization packages:
```typescript
interface KeyvSerializationAdapter {
stringify: (object: unknown) => string | Promise<string>;
parse: <T>(data: string) => T | Promise<T>;
}
```
### SuperJSON
For example, using the built-in `JSON` object:
[`@keyv/serialize-superjson`](https://github.com/jaredwray/keyv/tree/main/serialization/superjson) supports `Date`, `RegExp`, `Map`, `Set`, `BigInt`, `undefined`, `Error`, and `URL` types.
```js
const keyv = new Keyv({
serialization: { stringify: JSON.stringify, parse: JSON.parse },
});
import Keyv from 'keyv';
import { superJsonSerializer } from '@keyv/serialize-superjson'; // using the helper function that does new KeyvSuperJsonSerializer()
const keyv = new Keyv({ serialization: superJsonSerializer });
```
Or a custom async serializer:
### MessagePack (msgpackr)
[`@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.
```js
const keyv = new Keyv({
serialization: {
stringify: async (value) => JSON.stringify(value),
parse: async (data) => JSON.parse(data),
},
});
import Keyv from 'keyv';
import { KeyvMsgpackrSerializer } from '@keyv/serialize-msgpackr';
const keyv = new Keyv({ serialization: new KeyvMsgpackrSerializer() });
```
**Warning:** Using custom serializers means you lose any guarantee of data consistency. You should do extensive testing with your serialization functions and chosen storage engine.
## Custom Serializers
You can provide your own serializer by implementing the `KeyvSerializationAdapter` interface with `stringify` and `parse` methods:
```typescript
interface KeyvSerializationAdapter {
stringify: (object: unknown) => string | Promise<string>;
parse: <T>(data: string) => T | Promise<T>;
}
```
## Disabling Serialization

@@ -366,11 +374,11 @@

---|---|---
Redis | [@keyv/redis](https://github.com/jaredwray/keyv/tree/master/storage/redis) | Yes
Valkey | [@keyv/valkey](https://github.com/jaredwray/keyv/tree/master/storage/valkey) | Yes
MongoDB | [@keyv/mongo](https://github.com/jaredwray/keyv/tree/master/storage/mongo) | Yes
SQLite | [@keyv/sqlite](https://github.com/jaredwray/keyv/tree/master/storage/sqlite) | No
PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/master/storage/postgres) | No
MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/master/storage/mysql) | No
Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/master/storage/etcd) | Yes
Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/master/storage/memcache) | Yes
DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/master/storage/dynamo) | Yes
Redis | [@keyv/redis](https://github.com/jaredwray/keyv/tree/main/storage/redis) | Yes
Valkey | [@keyv/valkey](https://github.com/jaredwray/keyv/tree/main/storage/valkey) | Yes
MongoDB | [@keyv/mongo](https://github.com/jaredwray/keyv/tree/main/storage/mongo) | Yes
SQLite | [@keyv/sqlite](https://github.com/jaredwray/keyv/tree/main/storage/sqlite) | No
PostgreSQL | [@keyv/postgres](https://github.com/jaredwray/keyv/tree/main/storage/postgres) | No
MySQL | [@keyv/mysql](https://github.com/jaredwray/keyv/tree/main/storage/mysql) | No
Etcd | [@keyv/etcd](https://github.com/jaredwray/keyv/tree/main/storage/etcd) | Yes
Memcache | [@keyv/memcache](https://github.com/jaredwray/keyv/tree/main/storage/memcache) | Yes
DynamoDB | [@keyv/dynamo](https://github.com/jaredwray/keyv/tree/main/storage/dynamo) | Yes

@@ -510,6 +518,6 @@ # Third-party Storage Adapters

```js
import { keyvCompresstionTests } from '@keyv/test-suite';
import { keyvCompressionTests } from '@keyv/test-suite';
import KeyvGzip from '@keyv/compress-gzip';
keyvCompresstionTests(test, new KeyvGzip());
keyvCompressionTests(test, new KeyvGzip());
```

@@ -528,2 +536,112 @@

# Capability Detection
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.
```ts
import {
detectKeyv,
detectKeyvStorage,
detectKeyvCompression,
detectKeyvSerialization,
detectKeyvEncryption,
detectCapabilities,
} from 'keyv';
```
## detectKeyv(obj)
Returns a `KeyvCapability` with a boolean for each Keyv method/property. The `keyv` flag is `true` only when **all** capabilities are present.
```ts
import Keyv, { detectKeyv } from 'keyv';
detectKeyv(new Keyv());
// { keyv: true, get: true, set: true, delete: true, clear: true, has: true,
// getMany: true, setMany: true, deleteMany: true, hasMany: true,
// disconnect: true, getRaw: true, getManyRaw: true, setRaw: true,
// setManyRaw: true, hooks: true, stats: true, iterator: true }
detectKeyv(new Map());
// { keyv: false, get: true, set: true, ... }
```
## detectKeyvStorage(obj)
Returns a `KeyvStorageCapability`. The `keyvStorage` flag is `true` when the object has `get`, `set`, `delete`, `clear`, `has`, `setMany`, `deleteMany`, and `hasMany`.
The result also includes:
- **`mapLike`** — `true` when the object has synchronous `get`, `set`, `delete`, `has`, `entries`, and `keys` methods (i.e. it behaves like a `Map`)
- **`methodTypes`** — a record mapping each method name to `"sync"`, `"async"`, or `"none"` (not present)
```ts
import { detectKeyvStorage } from 'keyv';
// Map-like object
const result = detectKeyvStorage(new Map());
result.mapLike; // true
result.methodTypes.get; // "sync"
result.methodTypes.set; // "sync"
// Async storage adapter
const adapter = {
get: async () => {}, set: async () => {}, delete: async () => {},
clear: async () => {}, has: async () => {}, setMany: async () => {},
deleteMany: async () => {}, hasMany: async () => {},
};
const adapterResult = detectKeyvStorage(adapter);
adapterResult.keyvStorage; // true
adapterResult.mapLike; // false
adapterResult.methodTypes.get; // "async"
```
## detectKeyvCompression(obj)
Returns a `KeyvCompressionCapability`. The `keyvCompression` flag is `true` when both `compress` and `decompress` methods are present.
```ts
import { detectKeyvCompression } from 'keyv';
detectKeyvCompression({ compress: (d) => d, decompress: (d) => d });
// { keyvCompression: true, compress: true, decompress: true }
```
## detectKeyvSerialization(obj)
Returns a `KeyvSerializationCapability`. The `keyvSerialization` flag is `true` when both `stringify` and `parse` methods are present.
```ts
import { detectKeyvSerialization } from 'keyv';
detectKeyvSerialization(JSON);
// { keyvSerialization: true, stringify: true, parse: true }
```
## detectKeyvEncryption(obj)
Returns a `KeyvEncryptionCapability`. The `keyvEncryption` flag is `true` when both `encrypt` and `decrypt` methods are present.
```ts
import { detectKeyvEncryption } from 'keyv';
detectKeyvEncryption({ encrypt: (d) => d, decrypt: (d) => d });
// { keyvEncryption: true, encrypt: true, decrypt: true }
```
## detectCapabilities(obj, spec)
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.
```ts
import { detectCapabilities } from 'keyv';
const result = detectCapabilities(myObject, {
methods: ['read', 'write'],
properties: ['name'],
requiredKeys: ['read', 'write', 'name'],
compositeKey: 'isValid',
});
// { isValid: true/false, read: true/false, write: true/false, name: true/false }
```
# API

@@ -547,5 +665,5 @@

Type: `String`
Default: `'keyv'`
Default: `undefined`
This is the namespace for the current instance. When you set it it will set it also on the storage adapter. This is the preferred way to set the namespace over `.opts.namespace`.
This is the namespace for the current instance. When you set it it will set it also on the storage adapter.

@@ -561,3 +679,3 @@ ## options

Type: `String`<br />
Default: `'keyv'`
Default: `undefined`

@@ -608,3 +726,3 @@ Namespace for the current instance.

Set multiple values using KeyvEntrys `{ key: string, value: any, ttl?: number }`.
Set multiple values using `KeyvEntry<Value>` objects (`{ key: string, value: Value, ttl?: number }`). The `Value` type is inferred from the entries provided.

@@ -627,5 +745,5 @@ ## .get(key, [options])

## .setRaw(key, value, [ttl])
## .setRaw(key, value)
Sets a raw value in the store without wrapping. This is the write-side counterpart to `.getRaw()`. The caller provides the `DeserializedData` 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 `expires` is not set in the value and `ttl` is provided, `expires` will be computed from `ttl`.
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`.

@@ -637,12 +755,14 @@ Returns a promise which resolves to `true`.

// Set a raw value directly
// Set a raw value with expiration
await keyv.setRaw('foo', { value: 'bar', expires: Date.now() + 60000 });
// Set a raw value without expiration
await keyv.setRaw('foo', { value: 'bar' });
// Round-trip: get raw, modify, set raw
const raw = await keyv.getRaw('foo');
raw.value = 'updated';
await keyv.setRaw('foo', raw);
// TTL computes expires automatically if not set
await keyv.setRaw('foo', { value: 'bar' }, 60000);
if (raw) {
raw.value = 'updated';
await keyv.setRaw('foo', raw);
}
```

@@ -652,3 +772,3 @@

Sets many raw values in the store without wrapping. Each entry should have a `key`, a `value` (`DeserializedData` envelope), and an optional `ttl`. Like `setRaw()`, the envelopes are serialized before storing.
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`.

@@ -716,13 +836,17 @@ Returns a promise which resolves to an array of booleans.

Iterate over all entries of the current namespace.
Iterate over all key-value pairs in the store. Automatically deserializes values, filters out expired entries, and deletes them.
Returns a iterable that can be iterated by for-of loops. For example:
Returns an async generator that yields `[key, value]` pairs. Use with `for await...of`:
```js
// please note that the "await" keyword should be used here
for await (const [key, value] of this.keyv.iterator()) {
for await (const [key, value] of keyv.iterator()) {
console.log(key, value);
};
}
```
The iterator works with any storage backend:
- **Map stores**: iterates using the built-in `Symbol.iterator`
- **Storage adapters**: delegates to the adapter's `iterator()` method (e.g., Redis SCAN, SQL cursor)
- **Unsupported stores**: emits an `error` event if the store does not support iteration
# API - Properties

@@ -745,3 +869,3 @@

const keyv = new Keyv();
console.log(keyv.namespace); // 'keyv' which is default
console.log(keyv.namespace); // undefined which is default
keyv.namespace = undefined;

@@ -883,6 +1007,6 @@ console.log(keyv.namespace); // undefined

## .stats
Type: `StatsManager`<br />
Default: `StatsManager` instance with `enabled: false`
Type: `KeyvStats`<br />
Default: `KeyvStats` instance with `enabled: false`
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.
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.

@@ -896,2 +1020,4 @@ ### Enabling Stats:

### Available Statistics:
**Aggregate counters:**
- `hits`: Number of successful cache retrievals

@@ -903,2 +1029,9 @@ - `misses`: Number of failed cache retrievals

**Per-key LRU frequency maps** (each capped at `maxEntries`, default 1000):
- `hitKeys`: `Map<string, number>` — key to hit count
- `missKeys`: `Map<string, number>` — key to miss count
- `setKeys`: `Map<string, number>` — key to set count
- `deleteKeys`: `Map<string, number>` — key to delete count
- `errorKeys`: `Map<string, number>` — key to error count
### Accessing Stats:

@@ -917,2 +1050,6 @@ ```js

console.log(keyv.stats.deletes); // 1
// Per-key frequency maps
console.log(keyv.stats.hitKeys.get('foo')); // 1
console.log(keyv.stats.missKeys.get('nonexistent')); // 1
```

@@ -924,6 +1061,7 @@

console.log(keyv.stats.hits); // 0
console.log(keyv.stats.hitKeys.size); // 0
```
### Manual Control:
You can also manually enable/disable stats tracking at runtime:
You can also manually enable/disable stats tracking at runtime. Disabling stats will automatically unsubscribe from events:
```js

@@ -933,5 +1071,81 @@ const keyv = new Keyv({ stats: false });

// ... perform operations ...
keyv.stats.enabled = false; // Disable stats tracking
keyv.stats.enabled = false; // Disable stats tracking and unsubscribe
```
### Standalone Usage:
You can create a `KeyvStats` instance independently and subscribe it to a Keyv instance:
```js
import { KeyvStats } from 'keyv';
const stats = new KeyvStats({ enabled: true, maxEntries: 500, emitter: keyv });
```
## .sanitize
Type: `boolean | KeyvSanitizeOptions`<br />
Default: `false`
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.
Results are cached in an LRU cache (10,000 entries) for fast repeated lookups.
### Pattern Categories
| Category | Patterns Stripped | Purpose |
|----------|------------------|---------|
| `sql` | `;` `--` `/*` | Prevents SQL injection |
| `mongo` | leading `$`, `{$` sequences | Prevents MongoDB operator injection |
| `escape` | `\0` `\r` `\n` | Strips null bytes, CRLF injection |
| `path` | `../` `..\` | Prevents path traversal |
### Targets
| Target | Default | Description |
|--------|---------|-------------|
| `keys` | `true` (when enabled) | Sanitize keys on all operations |
| `namespace` | `true` (when enabled) | Sanitize namespace on construction and setter |
### Usage
Enable all sanitization:
```js
const keyv = new Keyv({ sanitize: true });
await keyv.set("test; DROP TABLE", "value");
// Key is stored as "test DROP TABLE"
// Harmless characters pass through
await keyv.set("user's-data", "value");
// Key is stored as "user's-data" (unchanged)
```
Disable all sanitization (default):
```js
const keyv = new Keyv({ sanitize: false });
```
Granular control per target and category:
```js
const keyv = new Keyv({
sanitize: {
keys: { sql: true, mongo: false }, // only SQL patterns on keys
namespace: { path: true, sql: false }, // only path patterns on namespace
}
});
```
Disable namespace sanitization only:
```js
const keyv = new Keyv({
sanitize: { keys: true, namespace: false }
});
```
Change at runtime:
```js
keyv.sanitize = false; // disable
keyv.sanitize = true; // enable all
keyv.sanitize = { keys: { sql: true, mongo: false } }; // granular
```
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.
# Bun Support

@@ -938,0 +1152,0 @@

type EventListener = (...arguments_: any[]) => void;
declare class EventManager {
_eventListeners: Map<string, EventListener[]>;
_maxListeners: number;
constructor();
maxListeners(): number;
addListener(event: string, listener: EventListener): void;
on(event: string, listener: EventListener): this;
removeListener(event: string, listener: EventListener): void;
off(event: string, listener: EventListener): void;
once(event: string, listener: EventListener): void;
emit(event: string, ...arguments_: any[]): void;
listeners(event: string): EventListener[];
removeAllListeners(event?: string): void;
setMaxListeners(n: number): void;
}
type HookHandler = (...arguments_: any[]) => void;
declare class HooksManager extends EventManager {
_hookHandlers: Map<string, HookHandler[]>;
constructor();
addHandler(event: string, handler: HookHandler): void;
removeHandler(event: string, handler: HookHandler): void;
trigger(event: string, data: any): void;
get handlers(): Map<string, HookHandler[]>;
}
declare class StatsManager extends EventManager {
enabled: boolean;
hits: number;
misses: number;
sets: number;
deletes: number;
errors: number;
constructor(enabled?: boolean);
hit(): void;
miss(): void;
set(): void;
delete(): void;
hitsOrMisses<T>(array: Array<T | undefined>): void;
reset(): void;
}
type KeyvSerializationAdapter = {
stringify: (object: unknown) => string | Promise<string>;
parse: <T>(data: string) => T | Promise<T>;
};
type KeyvCompressionAdapter = {
compress(value: any, options?: any): Promise<any>;
decompress(value: any, options?: any): Promise<any>;
};
type DeserializedData<Value> = {
value?: Value;
expires?: number | undefined;
};
declare enum KeyvHooks {
PRE_SET = "preSet",
POST_SET = "postSet",
PRE_GET = "preGet",
POST_GET = "postGet",
PRE_GET_MANY = "preGetMany",
POST_GET_MANY = "postGetMany",
PRE_GET_RAW = "preGetRaw",
POST_GET_RAW = "postGetRaw",
PRE_GET_MANY_RAW = "preGetManyRaw",
POST_GET_MANY_RAW = "postGetManyRaw",
PRE_SET_RAW = "preSetRaw",
POST_SET_RAW = "postSetRaw",
PRE_SET_MANY_RAW = "preSetManyRaw",
POST_SET_MANY_RAW = "postSetManyRaw",
PRE_DELETE = "preDelete",
POST_DELETE = "postDelete"
}
type KeyvEntry = {
/**
* Key to set.
*/
key: string;
/**
* Value to set.
*/
value: any;
/**
* Time to live in milliseconds.
*/
ttl?: number;
};
type StoredDataNoRaw<Value> = Value | undefined;
type StoredDataRaw<Value> = DeserializedData<Value> | undefined;
type StoredData<Value> = StoredDataNoRaw<Value> | StoredDataRaw<Value>;
type IEventEmitter = {
on(event: string, listener: (...arguments_: any[]) => void): IEventEmitter;
};
type KeyvStorageAdapter = {
opts: any;
namespace?: string | undefined;
get<Value>(key: string): Promise<StoredData<Value> | undefined>;
set(key: string, value: any, ttl?: number): any;
setMany?(values: Array<{
key: string;
value: any;
ttl?: number;
}>): Promise<void>;
delete(key: string): Promise<boolean>;
clear(): Promise<void>;
has?(key: string): Promise<boolean>;
hasMany?(keys: string[]): Promise<boolean[]>;
getMany?<Value>(keys: string[]): Promise<Array<StoredData<Value | undefined>>>;
disconnect?(): Promise<void>;
deleteMany?(key: string[]): Promise<boolean>;
iterator?<Value>(namespace?: string): AsyncGenerator<Array<string | Awaited<Value> | undefined>, void>;
} & IEventEmitter;
type KeyvOptions = {
/**
* Emit errors
* @default true
*/
emitErrors?: boolean;
/**
* Namespace for the current instance.
* @default 'keyv'
*/
namespace?: string;
/**
* A custom serialization adapter with stringify and parse methods.
* @default KeyvJsonSerializer (built-in)
*/
serialization?: KeyvSerializationAdapter | false;
/**
* The storage adapter instance to be used by Keyv.
* @default new Map() - in-memory store
*/
store?: KeyvStorageAdapter | Map<any, any> | any;
/**
* Default TTL in milliseconds. Can be overridden by specifying a TTL on `.set()`.
* @default undefined
*/
ttl?: number;
/**
* Enable compression option
* @default false
*/
compression?: KeyvCompressionAdapter | any;
/**
* Enable or disable statistics (default is false)
* @default false
*/
stats?: boolean;
/**
* Will enable throwing errors on methods in addition to emitting them.
* @default false
*/
throwOnErrors?: boolean;
};
/**
* @deprecated Use `KeyvStorageAdapter` instead.
*/
type KeyvStoreAdapter = KeyvStorageAdapter;
/**
* @deprecated Use `KeyvCompressionAdapter` instead.
*/
type KeyvCompression = KeyvCompressionAdapter;
declare class KeyvJsonSerializer implements KeyvSerializationAdapter {
stringify(object: unknown): string;
parse<T>(data: string): T;
}
declare const jsonSerializer: KeyvJsonSerializer;
type IteratorFunction = (argument: any) => AsyncGenerator<any, void>;
declare class Keyv<GenericValue = any> extends EventManager {
iterator?: IteratorFunction;
hooks: HooksManager;
stats: StatsManager;
/**
* Time to live in milliseconds
*/
private _ttl?;
/**
* Namespace
*/
private _namespace?;
/**
* Store
*/
private _store;
private _serialization;
private _compression;
private _throwOnErrors;
private _emitErrors;
/**
* Keyv Constructor
* @param {KeyvStorageAdapter | KeyvOptions | Map<any, any>} store to be provided or just the options
* @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
*/
constructor(store?: KeyvStorageAdapter | KeyvOptions | Map<any, any>, options?: Omit<KeyvOptions, "store">);
/**
* Keyv Constructor
* @param {KeyvOptions} options to be provided
*/
constructor(options?: KeyvOptions);
/**
* Get the current store
*/
get store(): KeyvStorageAdapter | Map<any, any> | any;
/**
* Set the current store. This will also set the namespace, event error handler, and generate the iterator. If the store is not valid it will throw an error.
* @param {KeyvStorageAdapter | Map<any, any> | any} store the store to set
*/
set store(store: KeyvStorageAdapter | Map<any, any> | any);
/**
* Get the current compression function
* @returns {KeyvCompressionAdapter} The current compression function
*/
get compression(): KeyvCompressionAdapter | undefined;
/**
* Set the current compression function
* @param {KeyvCompressionAdapter} compress The compression function to set
*/
set compression(compress: KeyvCompressionAdapter | undefined);
/**
* Get the current namespace.
* @returns {string | undefined} The current namespace.
*/
get namespace(): string | undefined;
/**
* Set the current namespace.
* @param {string | undefined} namespace The namespace to set.
*/
set namespace(namespace: string | undefined);
/**
* Get the current TTL.
* @returns {number} The current TTL in milliseconds.
*/
get ttl(): number | undefined;
/**
* Set the current TTL.
* @param {number} ttl The TTL to set in milliseconds.
*/
set ttl(ttl: number | undefined);
/**
* Get the current serialization adapter.
* @returns {KeyvSerializationAdapter | undefined} The current serialization adapter.
*/
get serialization(): KeyvSerializationAdapter | undefined;
/**
* Set the current serialization adapter.
* @param {KeyvSerializationAdapter | undefined} serialization The serialization adapter to set.
*/
set serialization(serialization: KeyvSerializationAdapter | false | undefined);
/**
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @return {boolean} The current throwOnErrors value.
*/
get throwOnErrors(): boolean;
/**
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @param {boolean} value The throwOnErrors value to set.
*/
set throwOnErrors(value: boolean);
/**
* Get the current emitErrors value. This will enable or disable emitting errors on methods.
* @return {boolean} The current emitErrors value.
* @default true
*/
get emitErrors(): boolean;
/**
* Set the current emitErrors value. This will enable or disable emitting errors on methods.
* @param {boolean} value The emitErrors value to set.
*/
set emitErrors(value: boolean);
generateIterator(iterator: IteratorFunction): IteratorFunction;
_checkIterableAdapter(): boolean;
_isValidStorageAdapter(store: KeyvStorageAdapter | any): boolean;
/**
* Get the Value of a Key
* @param {string | string[]} key passing in a single key or multiple as an array
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true }
*/
get<Value = GenericValue>(key: string, options?: {
raw: false;
}): Promise<StoredDataNoRaw<Value>>;
get<Value = GenericValue>(key: string, options?: {
raw: true;
}): Promise<StoredDataRaw<Value>>;
get<Value = GenericValue>(key: string[], options?: {
raw: false;
}): Promise<Array<StoredDataNoRaw<Value>>>;
get<Value = GenericValue>(key: string[], options?: {
raw: true;
}): Promise<Array<StoredDataRaw<Value>>>;
/**
* Get many values of keys
* @param {string[]} keys passing in a single key or multiple as an array
* @param {{raw: boolean} | undefined} options can pass in to return the raw value by setting { raw: true }
*/
getMany<Value = GenericValue>(keys: string[], options?: {
raw: false;
}): Promise<Array<StoredDataNoRaw<Value>>>;
getMany<Value = GenericValue>(keys: string[], options?: {
raw: true;
}): Promise<Array<StoredDataRaw<Value>>>;
/**
* Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
* @param {string} key the key to get
* @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
getRaw<Value = GenericValue>(key: string): Promise<StoredDataRaw<Value> | undefined>;
/**
* Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
* @param {string[]} keys the keys to get
* @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<StoredDataRaw<Value>>>;
/**
* Set an item to the store
* @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
* @param {Value} value the value of the key
* @param {number} [ttl] time to live in milliseconds
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
set<Value = GenericValue>(key: string, value: Value, ttl?: number): Promise<boolean>;
/**
* Set a raw value to the store without wrapping or serialization. This is the write-side counterpart to getRaw().
* The value should be a DeserializedData object with { value, expires? }.
* @param {string} key the key to set
* @param {DeserializedData<Value>} value the raw value envelope to store
* @param {number} [ttl] time to live in milliseconds. If the raw value does not already have an expires field, it will be computed from ttl.
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
setRaw<Value = GenericValue>(key: string, value: DeserializedData<Value>, ttl?: number): Promise<boolean>;
/**
* Set many items to the store
* @param {Array<KeyvEntry>} entries the entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setMany<Value = GenericValue>(entries: KeyvEntry[]): Promise<boolean[]>;
/**
* Set many raw values to the store without wrapping or serialization. This is the write-side counterpart to getManyRaw().
* Each entry's value should be a DeserializedData object with { value, expires? }.
* @param {Array<{key: string, value: DeserializedData<Value>, ttl?: number}>} entries the raw entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
setManyRaw<Value = GenericValue>(entries: Array<{
key: string;
value: DeserializedData<Value>;
ttl?: number;
}>): Promise<boolean[]>;
/**
* Delete an Entry
* @param {string | string[]} key the key to be deleted. if an array it will delete many items
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
delete(key: string | string[]): Promise<boolean>;
/**
* Delete many items from the store
* @param {string[]} keys the keys to be deleted
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
deleteMany(keys: string[]): Promise<boolean>;
/**
* Clear the store
* @returns {void}
*/
clear(): Promise<void>;
/**
* Has a key
* @param {string} key the key to check
* @returns {boolean} will return true if the key exists
*/
has(key: string[]): Promise<boolean[]>;
has(key: string): Promise<boolean>;
/**
* Check if many keys exist
* @param {string[]} keys the keys to check
* @returns {boolean[]} will return an array of booleans if the keys exist
*/
hasMany(keys: string[]): Promise<boolean[]>;
/**
* Will disconnect the store. This is only available if the store has a disconnect method
* @returns {Promise<void>}
*/
disconnect(): Promise<void>;
emit(event: string, ...arguments_: any[]): void;
serializeData<T>(data: DeserializedData<T>): Promise<string | DeserializedData<T>>;
deserializeData<T>(data: string | DeserializedData<T>): Promise<DeserializedData<T> | undefined>;
}
export { type DeserializedData, type IEventEmitter, Keyv, type KeyvCompression, type KeyvCompressionAdapter, type KeyvEntry, KeyvHooks, KeyvJsonSerializer, type KeyvOptions, type KeyvSerializationAdapter, type KeyvStorageAdapter, type KeyvStoreAdapter, type StoredData, type StoredDataNoRaw, type StoredDataRaw, Keyv as default, jsonSerializer };
// src/event-manager.ts
var EventManager = class {
_eventListeners;
_maxListeners;
constructor() {
this._eventListeners = /* @__PURE__ */ new Map();
this._maxListeners = 100;
}
maxListeners() {
return this._maxListeners;
}
// Add an event listener
addListener(event, listener) {
this.on(event, listener);
}
on(event, listener) {
if (!this._eventListeners.has(event)) {
this._eventListeners.set(event, []);
}
const listeners = this._eventListeners.get(event);
if (listeners) {
if (listeners.length >= this._maxListeners) {
console.warn(
`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
);
}
listeners.push(listener);
}
return this;
}
// Remove an event listener
removeListener(event, listener) {
this.off(event, listener);
}
off(event, listener) {
const listeners = this._eventListeners.get(event) ?? [];
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
if (listeners.length === 0) {
this._eventListeners.delete(event);
}
}
once(event, listener) {
const onceListener = (...arguments_) => {
listener(...arguments_);
this.off(event, onceListener);
};
this.on(event, onceListener);
}
// Emit an event
// biome-ignore lint/suspicious/noExplicitAny: type format
emit(event, ...arguments_) {
const listeners = this._eventListeners.get(event);
if (listeners && listeners.length > 0) {
for (const listener of listeners) {
listener(...arguments_);
}
}
}
// Get all listeners for a specific event
listeners(event) {
return this._eventListeners.get(event) ?? [];
}
// Remove all listeners for a specific event
removeAllListeners(event) {
if (event) {
this._eventListeners.delete(event);
} else {
this._eventListeners.clear();
}
}
// Set the maximum number of listeners for a single event
setMaxListeners(n) {
this._maxListeners = n;
}
};
var event_manager_default = EventManager;
// src/hooks-manager.ts
var HooksManager = class extends event_manager_default {
_hookHandlers;
constructor() {
super();
this._hookHandlers = /* @__PURE__ */ new Map();
}
// Adds a handler function for a specific event
addHandler(event, handler) {
const eventHandlers = this._hookHandlers.get(event);
if (eventHandlers) {
eventHandlers.push(handler);
} else {
this._hookHandlers.set(event, [handler]);
}
}
// Removes a specific handler function for a specific event
removeHandler(event, handler) {
const eventHandlers = this._hookHandlers.get(event);
if (eventHandlers) {
const index = eventHandlers.indexOf(handler);
if (index !== -1) {
eventHandlers.splice(index, 1);
}
}
}
// Triggers all handlers for a specific event with provided data
// biome-ignore lint/suspicious/noExplicitAny: type format
trigger(event, data) {
const eventHandlers = this._hookHandlers.get(event);
if (eventHandlers) {
for (const handler of eventHandlers) {
try {
handler(data);
} catch (error) {
this.emit(
"error",
new Error(
`Error in hook handler for event "${event}": ${error.message}`
)
);
}
}
}
}
// Provides read-only access to the current handlers
get handlers() {
return new Map(this._hookHandlers);
}
};
var hooks_manager_default = HooksManager;
// src/json-serializer.ts
function getGlobalBuffer() {
return globalThis.Buffer;
}
function bytesToBase64(bytes) {
const buffer = getGlobalBuffer();
if (buffer) {
return buffer.from(bytes).toString("base64");
}
let binary = "";
for (const byte of bytes) {
binary += String.fromCharCode(byte);
}
return btoa(binary);
}
function base64ToBytes(value) {
const buffer = getGlobalBuffer();
if (buffer) {
return buffer.from(value, "base64");
}
const binary = atob(value);
const bytes = new Uint8Array(binary.length);
for (let index = 0; index < binary.length; index++) {
bytes[index] = binary.charCodeAt(index);
}
return bytes;
}
function isBinaryValue(value) {
const buffer = getGlobalBuffer();
if (buffer?.isBuffer(value)) {
return true;
}
return value instanceof Uint8Array;
}
function prepare(value) {
if (value === null || value === void 0) {
return value;
}
if (isBinaryValue(value)) {
return `:base64:${bytesToBase64(value)}`;
}
if (typeof value === "bigint") {
return `:bigint:${value.toString()}`;
}
if (typeof value === "string") {
return value.startsWith(":") ? `:${value}` : value;
}
if (Array.isArray(value)) {
return value.map((item) => prepare(item));
}
if (typeof value === "object") {
if (typeof value.toJSON === "function") {
return prepare(value.toJSON());
}
const result = {};
for (const key of Object.keys(value)) {
if (value[key] !== void 0) {
result[key] = prepare(value[key]);
}
}
return result;
}
return value;
}
var KeyvJsonSerializer = class {
stringify(object) {
return JSON.stringify(prepare(object));
}
parse(data) {
return JSON.parse(data, (_, value) => {
if (typeof value === "string") {
if (value.startsWith(":bigint:")) {
return BigInt(value.slice(8));
}
if (value.startsWith(":base64:")) {
return base64ToBytes(value.slice(8));
}
return value.startsWith(":") ? value.slice(1) : value;
}
return value;
});
}
};
var jsonSerializer = new KeyvJsonSerializer();
// src/stats-manager.ts
var StatsManager = class extends event_manager_default {
enabled = true;
hits = 0;
misses = 0;
sets = 0;
deletes = 0;
errors = 0;
constructor(enabled) {
super();
if (enabled !== void 0) {
this.enabled = enabled;
}
this.reset();
}
hit() {
if (this.enabled) {
this.hits++;
}
}
miss() {
if (this.enabled) {
this.misses++;
}
}
set() {
if (this.enabled) {
this.sets++;
}
}
delete() {
if (this.enabled) {
this.deletes++;
}
}
hitsOrMisses(array) {
for (const item of array) {
if (item === void 0) {
this.miss();
} else {
this.hit();
}
}
}
reset() {
this.hits = 0;
this.misses = 0;
this.sets = 0;
this.deletes = 0;
this.errors = 0;
}
};
var stats_manager_default = StatsManager;
// src/types.ts
var KeyvHooks = /* @__PURE__ */ ((KeyvHooks2) => {
KeyvHooks2["PRE_SET"] = "preSet";
KeyvHooks2["POST_SET"] = "postSet";
KeyvHooks2["PRE_GET"] = "preGet";
KeyvHooks2["POST_GET"] = "postGet";
KeyvHooks2["PRE_GET_MANY"] = "preGetMany";
KeyvHooks2["POST_GET_MANY"] = "postGetMany";
KeyvHooks2["PRE_GET_RAW"] = "preGetRaw";
KeyvHooks2["POST_GET_RAW"] = "postGetRaw";
KeyvHooks2["PRE_GET_MANY_RAW"] = "preGetManyRaw";
KeyvHooks2["POST_GET_MANY_RAW"] = "postGetManyRaw";
KeyvHooks2["PRE_SET_RAW"] = "preSetRaw";
KeyvHooks2["POST_SET_RAW"] = "postSetRaw";
KeyvHooks2["PRE_SET_MANY_RAW"] = "preSetManyRaw";
KeyvHooks2["POST_SET_MANY_RAW"] = "postSetManyRaw";
KeyvHooks2["PRE_DELETE"] = "preDelete";
KeyvHooks2["POST_DELETE"] = "postDelete";
return KeyvHooks2;
})(KeyvHooks || {});
// src/index.ts
var iterableAdapters = [
"sqlite",
"postgres",
"mysql",
"mongo",
"redis",
"valkey",
"etcd"
];
var Keyv = class extends event_manager_default {
iterator;
hooks = new hooks_manager_default();
stats = new stats_manager_default(false);
/**
* Time to live in milliseconds
*/
_ttl;
/**
* Namespace
*/
_namespace;
/**
* Store
*/
// biome-ignore lint/suspicious/noExplicitAny: type format
_store = /* @__PURE__ */ new Map();
_serialization;
_compression;
_throwOnErrors = false;
_emitErrors = true;
/**
* Keyv Constructor
* @param {KeyvStorageAdapter | KeyvOptions} store
* @param {Omit<KeyvOptions, 'store'>} [options] if you provide the store you can then provide the Keyv Options
*/
constructor(store, options) {
super();
options ??= {};
store ??= {};
const mergedOptions = {
namespace: "keyv",
emitErrors: true,
...options
};
if (store && store.get) {
mergedOptions.store = store;
} else {
Object.assign(mergedOptions, store);
}
this._store = mergedOptions.store ?? /* @__PURE__ */ new Map();
this._compression = mergedOptions.compression;
if (mergedOptions.serialization === false) {
this._serialization = void 0;
} else {
this._serialization = mergedOptions.serialization ?? new KeyvJsonSerializer();
}
if (mergedOptions.namespace) {
this._namespace = mergedOptions.namespace;
}
if (this._store) {
if (!this._isValidStorageAdapter(this._store)) {
throw new Error("Invalid storage adapter");
}
if (typeof this._store.on === "function") {
this._store.on("error", (error) => this.emit("error", error));
}
this._store.namespace = this._namespace;
if (
// biome-ignore lint/suspicious/noExplicitAny: need to check Map iterator
typeof this._store[Symbol.iterator] === "function" && this._store instanceof Map
) {
this.iterator = this.generateIterator(
this._store
);
} else if ("iterator" in this._store && this._store.opts && this._checkIterableAdapter()) {
this.iterator = this.generateIterator(
// biome-ignore lint/style/noNonNullAssertion: need to fix
this._store.iterator.bind(this._store)
);
}
}
if (mergedOptions.stats) {
this.stats.enabled = mergedOptions.stats;
}
if (mergedOptions.ttl) {
this._ttl = mergedOptions.ttl;
}
if (mergedOptions.emitErrors !== void 0) {
this._emitErrors = mergedOptions.emitErrors;
}
if (mergedOptions.throwOnErrors !== void 0) {
this._throwOnErrors = mergedOptions.throwOnErrors;
}
}
/**
* Get the current store
*/
// biome-ignore lint/suspicious/noExplicitAny: type format
get store() {
return this._store;
}
/**
* Set the current store. This will also set the namespace, event error handler, and generate the iterator. If the store is not valid it will throw an error.
* @param {KeyvStorageAdapter | Map<any, any> | any} store the store to set
*/
// biome-ignore lint/suspicious/noExplicitAny: type format
set store(store) {
if (this._isValidStorageAdapter(store)) {
this._store = store;
if (typeof store.on === "function") {
store.on("error", (error) => this.emit("error", error));
}
if (this._namespace) {
this._store.namespace = this._namespace;
}
if (typeof store[Symbol.iterator] === "function" && store instanceof Map) {
this.iterator = this.generateIterator(
store
);
} else if ("iterator" in store && store.opts && this._checkIterableAdapter()) {
this.iterator = this.generateIterator(store.iterator?.bind(store));
}
} else {
throw new Error("Invalid storage adapter");
}
}
/**
* Get the current compression function
* @returns {KeyvCompressionAdapter} The current compression function
*/
get compression() {
return this._compression;
}
/**
* Set the current compression function
* @param {KeyvCompressionAdapter} compress The compression function to set
*/
set compression(compress) {
this._compression = compress;
}
/**
* Get the current namespace.
* @returns {string | undefined} The current namespace.
*/
get namespace() {
return this._namespace;
}
/**
* Set the current namespace.
* @param {string | undefined} namespace The namespace to set.
*/
set namespace(namespace) {
this._namespace = namespace;
this._store.namespace = namespace;
}
/**
* Get the current TTL.
* @returns {number} The current TTL in milliseconds.
*/
get ttl() {
return this._ttl;
}
/**
* Set the current TTL.
* @param {number} ttl The TTL to set in milliseconds.
*/
set ttl(ttl) {
this._ttl = ttl;
}
/**
* Get the current serialization adapter.
* @returns {KeyvSerializationAdapter | undefined} The current serialization adapter.
*/
get serialization() {
return this._serialization;
}
/**
* Set the current serialization adapter.
* @param {KeyvSerializationAdapter | undefined} serialization The serialization adapter to set.
*/
set serialization(serialization) {
this._serialization = serialization === false ? void 0 : serialization;
}
/**
* Get the current throwErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @return {boolean} The current throwOnErrors value.
*/
get throwOnErrors() {
return this._throwOnErrors;
}
/**
* Set the current throwOnErrors value. This will enable or disable throwing errors on methods in addition to emitting them.
* @param {boolean} value The throwOnErrors value to set.
*/
set throwOnErrors(value) {
this._throwOnErrors = value;
}
/**
* Get the current emitErrors value. This will enable or disable emitting errors on methods.
* @return {boolean} The current emitErrors value.
* @default true
*/
get emitErrors() {
return this._emitErrors;
}
/**
* Set the current emitErrors value. This will enable or disable emitting errors on methods.
* @param {boolean} value The emitErrors value to set.
*/
set emitErrors(value) {
this._emitErrors = value;
}
generateIterator(iterator) {
const function_ = async function* () {
for await (const [key, raw] of typeof iterator === "function" ? iterator(this._store.namespace) : iterator) {
const data = await this.deserializeData(raw);
if (typeof data.expires === "number" && Date.now() > data.expires) {
await this.delete(key);
continue;
}
yield [key, data.value];
}
};
return function_.bind(this);
}
_checkIterableAdapter() {
return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some(
(element) => this._store.opts.url.includes(element)
);
}
// biome-ignore lint/suspicious/noExplicitAny: type format
_isValidStorageAdapter(store) {
return store instanceof Map || typeof store.get === "function" && typeof store.set === "function" && typeof store.delete === "function" && typeof store.clear === "function";
}
// eslint-disable-next-line @stylistic/max-len
async get(key, options) {
const store = this._store;
const isArray = Array.isArray(key);
const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
if (isArray) {
if (options?.raw === true) {
return this.getMany(key, { raw: true });
}
return this.getMany(key, { raw: false });
}
this.hooks.trigger("preGet" /* PRE_GET */, { key });
let rawData;
try {
rawData = await store.get(key);
} catch (error) {
if (this.throwOnErrors) {
throw error;
}
}
const deserializedData = typeof rawData === "string" || this._compression ? await this.deserializeData(rawData) : rawData;
if (deserializedData === void 0 || deserializedData === null) {
this.hooks.trigger("postGet" /* POST_GET */, {
key,
value: void 0
});
this.stats.miss();
return void 0;
}
if (isDataExpired(deserializedData)) {
await this.delete(key);
this.hooks.trigger("postGet" /* POST_GET */, {
key,
value: void 0
});
this.stats.miss();
return void 0;
}
this.hooks.trigger("postGet" /* POST_GET */, {
key,
value: deserializedData
});
this.stats.hit();
return options?.raw ? deserializedData : deserializedData.value;
}
async getMany(keys, options) {
const store = this._store;
const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
this.hooks.trigger("preGetMany" /* PRE_GET_MANY */, { keys });
if (store.getMany === void 0) {
const promises = keys.map(async (key) => {
const rawData2 = await store.get(key);
const deserializedRow = typeof rawData2 === "string" || this._compression ? await this.deserializeData(rawData2) : rawData2;
if (deserializedRow === void 0 || deserializedRow === null) {
return void 0;
}
if (isDataExpired(deserializedRow)) {
await this.delete(key);
return void 0;
}
return options?.raw ? deserializedRow : deserializedRow.value;
});
const deserializedRows = await Promise.allSettled(promises);
const result2 = deserializedRows.map(
// biome-ignore lint/suspicious/noExplicitAny: type format
(row) => row.value
);
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result2);
if (result2.length > 0) {
this.stats.hit();
}
return result2;
}
const rawData = await store.getMany(keys);
const result = [];
const expiredKeys = [];
for (const index in rawData) {
let row = rawData[index];
if (typeof row === "string") {
row = await this.deserializeData(row);
}
if (row === void 0 || row === null) {
result.push(void 0);
continue;
}
if (isDataExpired(row)) {
expiredKeys.push(keys[index]);
result.push(void 0);
continue;
}
const value = options?.raw ? row : row.value;
result.push(value);
}
if (expiredKeys.length > 0) {
await this.deleteMany(expiredKeys);
}
this.hooks.trigger("postGetMany" /* POST_GET_MANY */, result);
if (result.length > 0) {
this.stats.hit();
}
return result;
}
/**
* Get the raw value of a key. This is the replacement for setting raw to true in the get() method.
* @param {string} key the key to get
* @returns {Promise<StoredDataRaw<Value> | undefined>} will return a StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
async getRaw(key) {
const store = this._store;
this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key });
const rawData = await store.get(key);
if (rawData === void 0 || rawData === null) {
this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, {
key,
value: void 0
});
this.stats.miss();
return void 0;
}
const deserializedData = typeof rawData === "string" || this._compression ? await this.deserializeData(rawData) : rawData;
if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && // biome-ignore lint/style/noNonNullAssertion: need to fix
deserializedData.expires < Date.now()) {
this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, {
key,
value: void 0
});
this.stats.miss();
await this.delete(key);
return void 0;
}
this.stats.hit();
this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, {
key,
value: deserializedData
});
return deserializedData;
}
/**
* Get the raw values of many keys. This is the replacement for setting raw to true in the getMany() method.
* @param {string[]} keys the keys to get
* @returns {Promise<Array<StoredDataRaw<Value>>>} will return an array of StoredDataRaw<Value> or undefined if the key does not exist or is expired.
*/
async getManyRaw(keys) {
const store = this._store;
if (keys.length === 0) {
const result2 = Array.from({ length: keys.length }).fill(
void 0
);
this.stats.misses += keys.length;
this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
keys,
values: result2
});
return result2;
}
let result = [];
if (store.getMany === void 0) {
const promises = keys.map(async (key) => {
const rawData = await store.get(key);
if (rawData !== void 0 && rawData !== null) {
return this.deserializeData(rawData);
}
return void 0;
});
const deserializedRows = await Promise.allSettled(promises);
result = deserializedRows.map(
(row) => (
// biome-ignore lint/suspicious/noExplicitAny: type format
row.value
)
);
} else {
const rawData = await store.getMany(keys);
for (const row of rawData) {
if (row !== void 0 && row !== null) {
result.push(await this.deserializeData(row));
} else {
result.push(void 0);
}
}
}
const expiredKeys = [];
const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
for (const [index, row] of result.entries()) {
if (row !== void 0 && isDataExpired(row)) {
expiredKeys.push(keys[index]);
result[index] = void 0;
}
}
if (expiredKeys.length > 0) {
await this.deleteMany(expiredKeys);
}
this.stats.hitsOrMisses(result);
this.hooks.trigger("postGetManyRaw" /* POST_GET_MANY_RAW */, {
keys,
values: result
});
return result;
}
/**
* Set an item to the store
* @param {string | Array<KeyvEntry>} key the key to use. If you pass in an array of KeyvEntry it will set many items
* @param {Value} value the value of the key
* @param {number} [ttl] time to live in milliseconds
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
async set(key, value, ttl) {
const data = { key, value, ttl };
this.hooks.trigger("preSet" /* PRE_SET */, data);
data.ttl ??= this._ttl;
if (data.ttl === 0) {
data.ttl = void 0;
}
const store = this._store;
const expires = typeof data.ttl === "number" ? Date.now() + data.ttl : void 0;
if (typeof data.value === "symbol") {
this.emit("error", "symbol cannot be serialized");
throw new Error("symbol cannot be serialized");
}
const formattedValue = { value: data.value, expires };
const serializedValue = await this.serializeData(formattedValue);
let result = true;
try {
const value2 = await store.set(data.key, serializedValue, data.ttl);
if (typeof value2 === "boolean") {
result = value2;
}
} catch (error) {
result = false;
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
}
this.hooks.trigger("postSet" /* POST_SET */, {
key,
value: serializedValue,
ttl
});
this.stats.set();
return result;
}
/**
* Set a raw value to the store without wrapping or serialization. This is the write-side counterpart to getRaw().
* The value should be a DeserializedData object with { value, expires? }.
* @param {string} key the key to set
* @param {DeserializedData<Value>} value the raw value envelope to store
* @param {number} [ttl] time to live in milliseconds. If the raw value does not already have an expires field, it will be computed from ttl.
* @returns {boolean} if it sets then it will return a true. On failure will return false.
*/
async setRaw(key, value, ttl) {
const data = { key, value, ttl };
this.hooks.trigger("preSetRaw" /* PRE_SET_RAW */, data);
data.ttl ??= this._ttl;
if (data.ttl === 0) {
data.ttl = void 0;
}
if (data.value.expires === void 0 && typeof data.ttl === "number") {
data.value.expires = Date.now() + data.ttl;
}
const store = this._store;
let result = true;
try {
const serializedValue = await this.serializeData(data.value);
const storeResult = await store.set(data.key, serializedValue, data.ttl);
if (typeof storeResult === "boolean") {
result = storeResult;
}
} catch (error) {
result = false;
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
}
this.hooks.trigger("postSetRaw" /* POST_SET_RAW */, {
key,
value: data.value,
ttl: data.ttl
});
this.stats.set();
return result;
}
/**
* Set many items to the store
* @param {Array<KeyvEntry>} entries the entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
// biome-ignore lint/correctness/noUnusedVariables: type format
async setMany(entries) {
let results = [];
try {
if (this._store.setMany === void 0) {
const promises = [];
for (const entry of entries) {
promises.push(this.set(entry.key, entry.value, entry.ttl));
}
const promiseResults = await Promise.all(promises);
results = promiseResults;
} else {
const serializedEntries = await Promise.all(
entries.map(async ({ key, value, ttl }) => {
ttl ??= this._ttl;
if (ttl === 0) {
ttl = void 0;
}
const expires = typeof ttl === "number" ? Date.now() + ttl : void 0;
if (typeof value === "symbol") {
this.emit("error", "symbol cannot be serialized");
throw new Error("symbol cannot be serialized");
}
const formattedValue = { value, expires };
const serializedValue = await this.serializeData(formattedValue);
return { key, value: serializedValue, ttl };
})
);
const storeResult = await this._store.setMany(serializedEntries);
results = Array.isArray(storeResult) ? storeResult : entries.map(() => true);
}
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
results = entries.map(() => false);
}
return results;
}
/**
* Set many raw values to the store without wrapping or serialization. This is the write-side counterpart to getManyRaw().
* Each entry's value should be a DeserializedData object with { value, expires? }.
* @param {Array<{key: string, value: DeserializedData<Value>, ttl?: number}>} entries the raw entries to set
* @returns {boolean[]} will return an array of booleans if it sets then it will return a true. On failure will return false.
*/
async setManyRaw(entries) {
let results = [];
this.hooks.trigger("preSetManyRaw" /* PRE_SET_MANY_RAW */, { entries });
try {
if (this._store.setMany === void 0) {
const promises = [];
for (const entry of entries) {
promises.push(this.setRaw(entry.key, entry.value, entry.ttl));
}
results = await Promise.all(promises);
} else {
const rawEntries = await Promise.all(
entries.map(async ({ key, value, ttl }) => {
ttl ??= this._ttl;
if (ttl === 0) {
ttl = void 0;
}
if (value.expires === void 0 && typeof ttl === "number") {
value.expires = Date.now() + ttl;
}
const serializedValue = await this.serializeData(value);
return { key, value: serializedValue, ttl };
})
);
const storeResult = await this._store.setMany(rawEntries);
results = Array.isArray(storeResult) ? storeResult : entries.map(() => true);
}
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
results = entries.map(() => false);
}
this.hooks.trigger("postSetManyRaw" /* POST_SET_MANY_RAW */, { entries, results });
return results;
}
/**
* Delete an Entry
* @param {string | string[]} key the key to be deleted. if an array it will delete many items
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
async delete(key) {
const store = this._store;
if (Array.isArray(key)) {
return this.deleteMany(key);
}
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key });
let result = true;
try {
const value = await store.delete(key);
if (typeof value === "boolean") {
result = value;
}
} catch (error) {
result = false;
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
}
this.hooks.trigger("postDelete" /* POST_DELETE */, {
key,
value: result
});
this.stats.delete();
return result;
}
/**
* Delete many items from the store
* @param {string[]} keys the keys to be deleted
* @returns {boolean} will return true if item or items are deleted. false if there is an error
*/
async deleteMany(keys) {
try {
const store = this._store;
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key: keys });
if (store.deleteMany !== void 0) {
return await store.deleteMany(keys);
}
const promises = keys.map(async (key) => store.delete(key));
const results = await Promise.all(promises);
const returnResult = results.every(Boolean);
this.hooks.trigger("postDelete" /* POST_DELETE */, {
key: keys,
value: returnResult
});
return returnResult;
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
return false;
}
}
/**
* Clear the store
* @returns {void}
*/
async clear() {
this.emit("clear");
const store = this._store;
try {
await store.clear();
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
}
}
async has(key) {
if (Array.isArray(key)) {
return this.hasMany(key);
}
const store = this._store;
if (store.has !== void 0 && !(store instanceof Map)) {
return store.has(key);
}
let rawData;
try {
rawData = await store.get(key);
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
return false;
}
if (rawData) {
const data = await this.deserializeData(rawData);
if (data) {
if (data.expires === void 0 || data.expires === null) {
return true;
}
return data.expires > Date.now();
}
}
return false;
}
/**
* Check if many keys exist
* @param {string[]} keys the keys to check
* @returns {boolean[]} will return an array of booleans if the keys exist
*/
async hasMany(keys) {
const store = this._store;
if (store.hasMany !== void 0) {
return store.hasMany(keys);
}
const results = [];
for (const key of keys) {
results.push(await this.has(key));
}
return results;
}
/**
* Will disconnect the store. This is only available if the store has a disconnect method
* @returns {Promise<void>}
*/
async disconnect() {
const store = this._store;
this.emit("disconnect");
if (typeof store.disconnect === "function") {
return store.disconnect();
}
}
// biome-ignore lint/suspicious/noExplicitAny: type format
emit(event, ...arguments_) {
if (event === "error" && !this._emitErrors) {
return;
}
super.emit(event, ...arguments_);
}
async serializeData(data) {
if (!this._serialization && !this._compression) {
return data;
}
let result = data;
if (this._serialization) {
result = await this._serialization.stringify(data);
} else if (this._compression) {
result = JSON.stringify(data);
}
if (this._compression?.compress) {
result = await this._compression.compress(result);
}
return result;
}
async deserializeData(data) {
if (data === void 0 || data === null) {
return void 0;
}
if (!this._serialization && !this._compression) {
if (typeof data === "string") {
return void 0;
}
return data;
}
let result = data;
if (this._compression?.decompress) {
result = await this._compression.decompress(result);
}
if (this._serialization && typeof result === "string") {
return await this._serialization.parse(result);
}
if (typeof result === "string") {
try {
return JSON.parse(result);
} catch {
return void 0;
}
}
return result;
}
};
var index_default = Keyv;
export {
Keyv,
KeyvHooks,
KeyvJsonSerializer,
index_default as default,
jsonSerializer
};
/* v8 ignore next -- @preserve */

Sorry, the diff of this file is too big to display