keyv
Version:
Simple key-value storage with support for multiple backends
907 lines (901 loc) • 28.3 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Keyv: () => Keyv,
KeyvHooks: () => KeyvHooks,
default: () => index_default
});
module.exports = __toCommonJS(index_exports);
var import_serialize = require("@keyv/serialize");
// 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
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
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/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/index.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_DELETE"] = "preDelete";
KeyvHooks2["POST_DELETE"] = "postDelete";
return KeyvHooks2;
})(KeyvHooks || {});
var iterableAdapters = [
"sqlite",
"postgres",
"mysql",
"mongo",
"redis",
"valkey",
"etcd"
];
var Keyv = class extends event_manager_default {
opts;
iterator;
hooks = new hooks_manager_default();
stats = new stats_manager_default(false);
/**
* Time to live in milliseconds
*/
_ttl;
/**
* Namespace
*/
_namespace;
/**
* Store
*/
_store = /* @__PURE__ */ new Map();
_serialize = import_serialize.defaultSerialize;
_deserialize = import_serialize.defaultDeserialize;
_compression;
_useKeyPrefix = true;
_throwOnErrors = false;
/**
* Keyv Constructor
* @param {KeyvStoreAdapter | 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 ??= {};
this.opts = {
namespace: "keyv",
serialize: import_serialize.defaultSerialize,
deserialize: import_serialize.defaultDeserialize,
emitErrors: true,
// @ts-expect-error - Map is not a KeyvStoreAdapter
store: /* @__PURE__ */ new Map(),
...options
};
if (store && store.get) {
this.opts.store = store;
} else {
this.opts = {
...this.opts,
...store
};
}
this._store = this.opts.store ?? /* @__PURE__ */ new Map();
this._compression = this.opts.compression;
this._serialize = this.opts.serialize;
this._deserialize = this.opts.deserialize;
if (this.opts.namespace) {
this._namespace = this.opts.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 (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(this._store.iterator.bind(this._store));
}
}
if (this.opts.stats) {
this.stats.enabled = this.opts.stats;
}
if (this.opts.ttl) {
this._ttl = this.opts.ttl;
}
if (this.opts.useKeyPrefix !== void 0) {
this._useKeyPrefix = this.opts.useKeyPrefix;
}
if (this.opts.throwOnErrors !== void 0) {
this._throwOnErrors = this.opts.throwOnErrors;
}
}
/**
* Get the current store
*/
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 {KeyvStoreAdapter | Map<any, any> | any} store the store to set
*/
set store(store) {
if (this._isValidStorageAdapter(store)) {
this._store = store;
this.opts.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 {CompressionAdapter} The current compression function
*/
get compression() {
return this._compression;
}
/**
* Set the current compression function
* @param {CompressionAdapter} 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.opts.namespace = namespace;
this._store.namespace = namespace;
if (this.opts.store) {
this.opts.store.namespace = namespace;
}
}
/**
* Get the current TTL.
* @returns {number} The current TTL.
*/
get ttl() {
return this._ttl;
}
/**
* Set the current TTL.
* @param {number} ttl The TTL to set.
*/
set ttl(ttl) {
this.opts.ttl = ttl;
this._ttl = ttl;
}
/**
* Get the current serialize function.
* @returns {Serialize} The current serialize function.
*/
get serialize() {
return this._serialize;
}
/**
* Set the current serialize function.
* @param {Serialize} serialize The serialize function to set.
*/
set serialize(serialize) {
this.opts.serialize = serialize;
this._serialize = serialize;
}
/**
* Get the current deserialize function.
* @returns {Deserialize} The current deserialize function.
*/
get deserialize() {
return this._deserialize;
}
/**
* Set the current deserialize function.
* @param {Deserialize} deserialize The deserialize function to set.
*/
set deserialize(deserialize) {
this.opts.deserialize = deserialize;
this._deserialize = deserialize;
}
/**
* Get the current useKeyPrefix value. This will enable or disable key prefixing.
* @returns {boolean} The current useKeyPrefix value.
* @default true
*/
get useKeyPrefix() {
return this._useKeyPrefix;
}
/**
* Set the current useKeyPrefix value. This will enable or disable key prefixing.
* @param {boolean} value The useKeyPrefix value to set.
*/
set useKeyPrefix(value) {
this._useKeyPrefix = value;
this.opts.useKeyPrefix = value;
}
/**
* 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;
this.opts.throwOnErrors = 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 (this._useKeyPrefix && this._store.namespace && !key.includes(this._store.namespace)) {
continue;
}
if (typeof data.expires === "number" && Date.now() > data.expires) {
this.delete(key);
continue;
}
yield [this._getKeyUnprefix(key), data.value];
}
};
return function_.bind(this);
}
_checkIterableAdapter() {
return iterableAdapters.includes(this._store.opts.dialect) || iterableAdapters.some((element) => this._store.opts.url.includes(element));
}
_getKeyPrefix(key) {
if (!this._useKeyPrefix) {
return key;
}
if (!this._namespace) {
return key;
}
return `${this._namespace}:${key}`;
}
_getKeyPrefixArray(keys) {
if (!this._useKeyPrefix) {
return keys;
}
if (!this._namespace) {
return keys;
}
return keys.map((key) => `${this._namespace}:${key}`);
}
_getKeyUnprefix(key) {
if (!this._useKeyPrefix) {
return key;
}
return key.split(":").splice(1).join(":");
}
_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.opts;
const isArray = Array.isArray(key);
const keyPrefixed = isArray ? this._getKeyPrefixArray(key) : this._getKeyPrefix(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: keyPrefixed });
let rawData;
try {
rawData = await store.get(keyPrefixed);
} catch (error) {
if (this.throwOnErrors) {
throw error;
}
}
const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
if (deserializedData === void 0 || deserializedData === null) {
this.stats.miss();
return void 0;
}
if (isDataExpired(deserializedData)) {
await this.delete(key);
this.stats.miss();
return void 0;
}
this.hooks.trigger("postGet" /* POST_GET */, { key: keyPrefixed, value: deserializedData });
this.stats.hit();
return options?.raw ? deserializedData : deserializedData.value;
}
async getMany(keys, options) {
const { store } = this.opts;
const keyPrefixed = this._getKeyPrefixArray(keys);
const isDataExpired = (data) => typeof data.expires === "number" && Date.now() > data.expires;
this.hooks.trigger("preGetMany" /* PRE_GET_MANY */, { keys: keyPrefixed });
if (store.getMany === void 0) {
const promises = keyPrefixed.map(async (key) => {
const rawData2 = await store.get(key);
const deserializedRow = typeof rawData2 === "string" || this.opts.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((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(keyPrefixed);
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.opts;
const keyPrefixed = this._getKeyPrefix(key);
this.hooks.trigger("preGetRaw" /* PRE_GET_RAW */, { key: keyPrefixed });
const rawData = await store.get(keyPrefixed);
if (rawData === void 0 || rawData === null) {
this.stats.miss();
return void 0;
}
const deserializedData = typeof rawData === "string" || this.opts.compression ? await this.deserializeData(rawData) : rawData;
if (deserializedData !== void 0 && deserializedData.expires !== void 0 && deserializedData.expires !== null && deserializedData.expires < Date.now()) {
this.stats.miss();
await this.delete(key);
return void 0;
}
this.stats.hit();
this.hooks.trigger("postGetRaw" /* POST_GET_RAW */, { key: keyPrefixed, 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.opts;
const keyPrefixed = this._getKeyPrefixArray(keys);
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: keyPrefixed, values: result2 });
return result2;
}
let result = [];
if (store.getMany === void 0) {
const promises = keyPrefixed.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) => row.value);
} else {
const rawData = await store.getMany(keyPrefixed);
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(keyPrefixed[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: keyPrefixed, 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);
const keyPrefixed = this._getKeyPrefix(data.key);
data.ttl ??= this._ttl;
if (data.ttl === 0) {
data.ttl = void 0;
}
const { store } = this.opts;
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(keyPrefixed, 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: keyPrefixed, value: serializedValue, 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.
*/
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 };
}));
results = await this._store.setMany(serializedEntries);
}
} catch (error) {
this.emit("error", error);
if (this._throwOnErrors) {
throw error;
}
results = entries.map(() => false);
}
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.opts;
if (Array.isArray(key)) {
return this.deleteMany(key);
}
const keyPrefixed = this._getKeyPrefix(key);
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key: keyPrefixed });
let result = true;
try {
const value = await store.delete(keyPrefixed);
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: keyPrefixed, 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.opts;
const keyPrefixed = this._getKeyPrefixArray(keys);
this.hooks.trigger("preDelete" /* PRE_DELETE */, { key: keyPrefixed });
if (store.deleteMany !== void 0) {
return await store.deleteMany(keyPrefixed);
}
const promises = keyPrefixed.map(async (key) => store.delete(key));
const results = await Promise.all(promises);
const returnResult = results.every(Boolean);
this.hooks.trigger("postDelete" /* POST_DELETE */, { key: keyPrefixed, 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.opts;
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 keyPrefixed = this._getKeyPrefix(key);
const { store } = this.opts;
if (store.has !== void 0 && !(store instanceof Map)) {
return store.has(keyPrefixed);
}
let rawData;
try {
rawData = await store.get(keyPrefixed);
} 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 keyPrefixed = this._getKeyPrefixArray(keys);
const { store } = this.opts;
if (store.hasMany !== void 0) {
return store.hasMany(keyPrefixed);
}
const results = [];
for (const key of keyPrefixed) {
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.opts;
this.emit("disconnect");
if (typeof store.disconnect === "function") {
return store.disconnect();
}
}
emit(event, ...arguments_) {
if (event === "error" && !this.opts.emitErrors) {
return;
}
super.emit(event, ...arguments_);
}
async serializeData(data) {
if (!this._serialize) {
return data;
}
if (this._compression?.compress) {
return this._serialize({ value: await this._compression.compress(data.value), expires: data.expires });
}
return this._serialize(data);
}
async deserializeData(data) {
if (!this._deserialize) {
return data;
}
if (this._compression?.decompress && typeof data === "string") {
const result = await this._deserialize(data);
return { value: await this._compression.decompress(result?.value), expires: result?.expires };
}
if (typeof data === "string") {
return this._deserialize(data);
}
return void 0;
}
};
var index_default = Keyv;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Keyv,
KeyvHooks
});