"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, { KeyvAdapter: () => KeyvAdapter, createCache: () => createCache }); module.exports = __toCommonJS(src_exports); var import_node_events = __toESM(require("events"), 1); var import_keyv = require("keyv"); // src/coalesce-async.ts var callbacks = /* @__PURE__ */ new Map(); function hasKey(key) { return callbacks.has(key); } function addKey(key) { callbacks.set(key, []); } function removeKey(key) { callbacks.delete(key); } function addCallbackToKey(key, callback) { const stash = getCallbacksByKey(key); stash.push(callback); callbacks.set(key, stash); } function getCallbacksByKey(key) { return callbacks.get(key) ?? []; } async function enqueue(key) { return new Promise((resolve, reject) => { const callback = { resolve, reject }; addCallbackToKey(key, callback); }); } function dequeue(key) { const stash = getCallbacksByKey(key); removeKey(key); return stash; } function coalesce(options) { const { key, error, result } = options; for (const callback of dequeue(key)) { if (error) { callback.reject(error); } else { callback.resolve(result); } } } async function coalesceAsync(key, fnc) { if (!hasKey(key)) { addKey(key); try { const result = await Promise.resolve(fnc()); coalesce({ key, result }); return result; } catch (error) { coalesce({ key, error }); throw error; } } return enqueue(key); } // src/run-if-fn.ts function runIfFn(valueOrFunction, ...arguments_) { return typeof valueOrFunction === "function" ? valueOrFunction(...arguments_) : valueOrFunction; } // src/lt.ts function lt(number1, number2) { return typeof number1 === "number" && typeof number2 === "number" ? number1 < number2 : false; } // src/keyv-adapter.ts var KeyvAdapter = class { opts; namespace; _cache; constructor(store) { this._cache = store; } async get(key) { const value = await this._cache.get(key); if (value !== void 0 && value !== null) { return value; } return void 0; } async set(key, value, ttl) { return this._cache.set(key, value, ttl).then(() => true); } async delete(key) { await this._cache.del(key); return true; } async clear() { return this._cache.reset?.(); } async has(key) { const result = await this._cache.get(key); if (result) { return true; } return false; } async getMany(keys) { return this._cache.mget(...keys).then((values) => values.map((value) => value)); } async deleteMany(key) { await this._cache.mdel(...key); return true; } /* c8 ignore next 5 */ on(event, listener) { this._cache.on?.(event, listener); return this; } }; // src/index.ts var createCache = (options) => { const eventEmitter = new import_node_events.default(); const stores = options?.stores?.length ? options.stores : [new import_keyv.Keyv()]; const nonBlocking = options?.nonBlocking ?? false; const get = async (key) => { let result = null; if (nonBlocking) { try { result = await Promise.race(stores.map(async (store) => store.get(key))); if (result === void 0) { return null; } } catch (error) { eventEmitter.emit("get", { key, error }); } } else { for (const store of stores) { try { const cacheValue = await store.get(key); if (cacheValue !== void 0) { result = cacheValue; eventEmitter.emit("get", { key, value: result }); break; } } catch (error) { eventEmitter.emit("get", { key, error }); } } } return result; }; const mget = async (keys) => { const result = []; for (const key of keys) { const data = await get(key); result.push(data); } return result; }; const set = async (stores2, key, value, ttl) => { try { if (nonBlocking) { Promise.all(stores2.map(async (store) => store.set(key, value, ttl ?? options?.ttl))); eventEmitter.emit("set", { key, value }); return value; } await Promise.all(stores2.map(async (store) => store.set(key, value, ttl ?? options?.ttl))); eventEmitter.emit("set", { key, value }); return value; } catch (error) { eventEmitter.emit("set", { key, value, error }); return Promise.reject(error); } }; const mset = async (stores2, list) => { const items = list.map(({ key, value, ttl }) => ({ key, value, ttl })); try { const promises = []; for (const item of list) { promises.push(stores2.map(async (store) => store.set(item.key, item.value, item.ttl))); } await Promise.all(promises); eventEmitter.emit("mset", { list }); return list; } catch (error) { eventEmitter.emit("mset", { list, error }); return Promise.reject(error); } }; const del = async (key) => { try { if (nonBlocking) { Promise.all(stores.map(async (store) => store.delete(key))); eventEmitter.emit("del", { key }); return true; } await Promise.all(stores.map(async (store) => store.delete(key))); eventEmitter.emit("del", { key }); return true; } catch (error) { eventEmitter.emit("del", { key, error }); return Promise.reject(error); } }; const mdel = async (keys) => { try { const promises = []; for (const key of keys) { promises.push(stores.map(async (store) => store.delete(key))); } if (nonBlocking) { Promise.all(promises); eventEmitter.emit("mdel", { keys }); return true; } await Promise.all(promises); eventEmitter.emit("mdel", { keys }); return true; } catch (error) { eventEmitter.emit("mdel", { keys, error }); return Promise.reject(error); } }; const clear = async () => { try { if (nonBlocking) { Promise.all(stores.map(async (store) => store.clear())); eventEmitter.emit("clear"); return true; } await Promise.all(stores.map(async (store) => store.clear())); eventEmitter.emit("clear"); return true; } catch (error) { eventEmitter.emit("clear", error); return Promise.reject(error); } }; const wrap = async (key, fnc, ttl, refreshThreshold) => coalesceAsync(key, async () => { let value; let i = 0; let remainingTtl; for (; i < stores.length; i++) { try { const data = await stores[i].get(key, { raw: true }); if (data !== void 0) { value = data.value; if (typeof data.expires === "number") { remainingTtl = Math.max(0, data.expires - Date.now()); } break; } } catch { } } if (value === void 0) { const result = await fnc(); await set(stores, key, result, runIfFn(ttl, result) ?? options?.ttl); return result; } const ms = runIfFn(ttl, value) ?? options?.ttl; const shouldRefresh = lt(remainingTtl, refreshThreshold ?? options?.refreshThreshold); if (shouldRefresh) { coalesceAsync(`+++${key}`, fnc).then(async (result) => { try { await set(stores.slice(0, i + 1), key, result, ms); eventEmitter.emit("refresh", { key, value: result }); } catch (error) { eventEmitter.emit("refresh", { key, value, error }); } }).catch((error) => { eventEmitter.emit("refresh", { key, value, error }); }); } if (!shouldRefresh && i > 0) { await set(stores.slice(0, i), key, value, ms); } return value; }); const on = (event, listener) => eventEmitter.addListener(event, listener); const off = (event, listener) => eventEmitter.removeListener(event, listener); return { get, mget, set: async (key, value, ttl) => set(stores, key, value, ttl), mset: async (list) => mset(stores, list), del, mdel, clear, wrap, on, off }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { KeyvAdapter, createCache });