"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { createKeyv: () => createKeyv, default: () => src_default }); module.exports = __toCommonJS(src_exports); var import_events = __toESM(require("events"), 1); var import_iovalkey = __toESM(require("iovalkey"), 1); // ../../node_modules/.pnpm/@keyv+serialize@1.0.1/node_modules/@keyv/serialize/dist/index.js var import_buffer = require("buffer"); var defaultSerialize = (data) => { if (data === void 0 || data === null) { return "null"; } if (typeof data === "string") { return JSON.stringify(data.startsWith(":") ? ":" + data : data); } if (import_buffer.Buffer.isBuffer(data)) { return JSON.stringify(":base64:" + data.toString("base64")); } if (data?.toJSON) { data = data.toJSON(); } if (typeof data === "object") { let s = ""; const array = Array.isArray(data); s = array ? "[" : "{"; let first = true; for (const k in data) { const ignore = typeof data[k] === "function" || !array && data[k] === void 0; if (!data.hasOwnProperty(k) || ignore) { continue; } if (!first) { s += ","; } first = false; if (array) { s += defaultSerialize(data[k]); } else if (data[k] !== void 0) { s += defaultSerialize(k) + ":" + defaultSerialize(data[k]); } } s += array ? "]" : "}"; return s; } return JSON.stringify(data); }; var defaultDeserialize = (data) => JSON.parse(data, (_, value) => { if (typeof value === "string") { if (value.startsWith(":base64:")) { return import_buffer.Buffer.from(value.slice(8), "base64"); } return value.startsWith(":") ? value.slice(1) : value; } return value; }); // ../../node_modules/.pnpm/keyv@5.2.1/node_modules/keyv/dist/index.js 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_); } } else if (event === "error") { if (arguments_[0] instanceof Error) { throw arguments_[0]; } else { const error = new CustomError(arguments_[0]); error.context = arguments_[0]; throw error; } } } // 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 CustomError = class _CustomError extends Error { context; constructor(message, context) { super(message); this.context = context; if (Error.captureStackTrace) { Error.captureStackTrace(this, _CustomError); } this.name = this.constructor.name; } }; var event_manager_default = EventManager; 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; 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++; } } reset() { this.hits = 0; this.misses = 0; this.sets = 0; this.deletes = 0; this.errors = 0; } }; var stats_manager_default = StatsManager; var iterableAdapters = [ "sqlite", "postgres", "mysql", "mongo", "redis" ]; 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 = defaultSerialize; _deserialize = defaultDeserialize; _compression; _useKeyPrefix = true; /** * Keyv Constructor * @param {KeyvStoreAdapter | KeyvOptions} store * @param {Omit} [options] if you provide the store you can then provide the Keyv Options */ constructor(store, options) { super(); options ??= {}; store ??= {}; this.opts = { namespace: "keyv", serialize: defaultSerialize, deserialize: 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; 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.opts.emitErrors) { 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; } } /** * 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} store the store to set */ set store(store) { if (this._isValidStorageAdapter(store)) { this._store = store; this.opts.store = store; if (typeof store.on === "function" && this.opts.emitErrors) { 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; } 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"; } 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) { this.hooks.trigger("preGetMany", { keys: keyPrefixed }); if (store.getMany === void 0) { const promises = keyPrefixed.map(async (key2) => { const rawData3 = await store.get(key2); const deserializedRow = typeof rawData3 === "string" || this.opts.compression ? await this.deserializeData(rawData3) : rawData3; if (deserializedRow === void 0 || deserializedRow === null) { return void 0; } if (isDataExpired(deserializedRow)) { await this.delete(key2); 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", result2); if (result2.length > 0) { this.stats.hit(); } return result2; } const rawData2 = await store.getMany(keyPrefixed); const result = []; for (const index in rawData2) { let row = rawData2[index]; if (typeof row === "string") { row = await this.deserializeData(row); } if (row === void 0 || row === null) { result.push(void 0); continue; } if (isDataExpired(row)) { await this.delete(key[index]); result.push(void 0); continue; } const value = options?.raw ? row : row.value; result.push(value); } this.hooks.trigger("postGetMany", result); if (result.length > 0) { this.stats.hit(); } return result; } this.hooks.trigger("preGet", { key: keyPrefixed }); const rawData = await store.get(keyPrefixed); 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", { key: keyPrefixed, value: deserializedData }); this.stats.hit(); return options?.raw ? deserializedData : deserializedData.value; } /** * Set an item to the store * @param {string} key the key to use * @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) { this.hooks.trigger("preSet", { key, value, ttl }); const keyPrefixed = this._getKeyPrefix(key); if (typeof ttl === "undefined") { ttl = this._ttl; } if (ttl === 0) { ttl = void 0; } const { store } = this.opts; const expires = typeof ttl === "number" ? Date.now() + ttl : null; if (typeof value === "symbol") { this.emit("error", "symbol cannot be serialized"); } const formattedValue = { value, expires }; const serializedValue = await this.serializeData(formattedValue); await store.set(keyPrefixed, serializedValue, ttl); this.hooks.trigger("postSet", { key: keyPrefixed, value: serializedValue, ttl }); this.stats.set(); return true; } /** * 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)) { const keyPrefixed2 = this._getKeyPrefixArray(key); this.hooks.trigger("preDelete", { key: keyPrefixed2 }); if (store.deleteMany !== void 0) { return store.deleteMany(keyPrefixed2); } const promises = keyPrefixed2.map(async (key2) => store.delete(key2)); const results = await Promise.allSettled(promises); const returnResult = results.every((x) => x.value === true); this.hooks.trigger("postDelete", { key: keyPrefixed2, value: returnResult }); return returnResult; } const keyPrefixed = this._getKeyPrefix(key); this.hooks.trigger("preDelete", { key: keyPrefixed }); const result = await store.delete(keyPrefixed); this.hooks.trigger("postDelete", { key: keyPrefixed, value: result }); this.stats.delete(); return result; } /** * Clear the store * @returns {void} */ async clear() { this.emit("clear"); const { store } = this.opts; await store.clear(); } /** * Has a key * @param {string} key the key to check * @returns {boolean} will return true if the key exists */ async has(key) { const keyPrefixed = this._getKeyPrefix(key); const { store } = this.opts; if (store.has !== void 0 && !(store instanceof Map)) { return store.has(keyPrefixed); } const rawData = await store.get(keyPrefixed); 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; } /** * Will disconnect the store. This is only available if the store has a disconnect method * @returns {Promise} */ async disconnect() { const { store } = this.opts; this.emit("disconnect"); if (typeof store.disconnect === "function") { return store.disconnect(); } } 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; } }; // src/index.ts var createKeyv = (uri, options) => new Keyv({ store: new KeyvValkey(uri, options) }); var KeyvValkey = class extends import_events.default { ttlSupport = true; namespace; opts; redis; constructor(uri, options) { super(); this.opts = {}; this.opts.useRedisSets = true; this.opts.dialect = "redis"; if (typeof uri !== "string" && uri.options && ("family" in uri.options || uri.isCluster)) { this.redis = uri; } else { options = { ...typeof uri === "string" ? { uri } : uri, ...options }; this.redis = new import_iovalkey.default(options.uri, options); } if (options !== void 0 && options.useRedisSets === false) { this.opts.useRedisSets = false; } this.redis.on("error", (error) => this.emit("error", error)); } _getNamespace() { return `namespace:${this.namespace}`; } _getKeyName = (key) => { if (!this.opts.useRedisSets) { return `sets:${this._getNamespace()}:${key}`; } return key; }; async get(key) { key = this._getKeyName(key); const value = await this.redis.get(key); if (value === null) { return void 0; } return value; } async getMany(keys) { keys = keys.map(this._getKeyName); return this.redis.mget(keys); } async set(key, value, ttl) { if (value === void 0) { return void 0; } key = this._getKeyName(key); const set = async (redis) => { if (typeof ttl === "number") { await redis.set(key, value, "PX", ttl); } else { await redis.set(key, value); } }; if (this.opts.useRedisSets) { const trx = await this.redis.multi(); await set(trx); await trx.sadd(this._getNamespace(), key); await trx.exec(); } else { await set(this.redis); } } async delete(key) { key = this._getKeyName(key); let items = 0; const unlink = async (redis) => redis.unlink(key); if (this.opts.useRedisSets) { const trx = this.redis.multi(); await unlink(trx); await trx.srem(this._getNamespace(), key); const r = await trx.exec(); items = r[0][1]; } else { items = await unlink(this.redis); } return items > 0; } async deleteMany(keys) { const deletePromises = keys.map(async (key) => this.delete(key)); const results = await Promise.allSettled(deletePromises); return results.every((result) => result.value); } async clear() { if (this.opts.useRedisSets) { const keys = await this.redis.smembers(this._getNamespace()); if (keys.length > 0) { await Promise.all([ this.redis.unlink([...keys]), this.redis.srem(this._getNamespace(), [...keys]) ]); } } else { const pattern = `sets:${this._getNamespace()}:*`; const keys = await this.redis.keys(pattern); if (keys.length > 0) { await this.redis.unlink(keys); } } } async *iterator(namespace) { const scan = this.redis.scan.bind(this.redis); const get = this.redis.mget.bind(this.redis); let cursor = "0"; do { const [curs, keys] = await scan(cursor, "MATCH", `${namespace}:*`); cursor = curs; if (keys.length > 0) { const values = await get(keys); for (const [i] of keys.entries()) { const key = keys[i]; const value = values[i]; yield [key, value]; } } } while (cursor !== "0"); } async has(key) { const value = await this.redis.exists(key); return value !== 0; } async disconnect() { return this.redis.disconnect(); } }; var src_default = KeyvValkey; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createKeyv });