UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

107 lines (106 loc) 3.57 kB
//#region src/plugins/plugin-cache-primitives.ts /** Small process-local LRU cache used for stable plugin metadata and loader artifacts. */ var PluginLruCache = class { #defaultMaxEntries; #maxEntries; #entries = /* @__PURE__ */ new Map(); constructor(defaultMaxEntries) { this.#defaultMaxEntries = normalizeMaxEntries(defaultMaxEntries, 1); this.#maxEntries = this.#defaultMaxEntries; } get maxEntries() { return this.#maxEntries; } get size() { return this.#entries.size; } setMaxEntriesForTest(value) { this.#maxEntries = typeof value === "number" ? normalizeMaxEntries(value, this.#defaultMaxEntries) : this.#defaultMaxEntries; this.#evictOldestEntries(); } clear() { this.#entries.clear(); } /** Returns a cached value and refreshes its recency when present. */ get(cacheKey) { const cached = this.getResult(cacheKey); return cached.hit ? cached.value : void 0; } /** Returns a hit/miss result and promotes hits to the newest LRU position. */ getResult(cacheKey) { if (!this.#entries.has(cacheKey)) return { hit: false }; const cached = this.#entries.get(cacheKey); this.#entries.delete(cacheKey); this.#entries.set(cacheKey, cached); return { hit: true, value: cached }; } /** Stores a value as the newest entry and evicts oldest entries past capacity. */ set(cacheKey, value) { if (this.#entries.has(cacheKey)) this.#entries.delete(cacheKey); this.#entries.set(cacheKey, value); this.#evictOldestEntries(); } #evictOldestEntries() { while (this.#entries.size > this.#maxEntries) { const oldestEntry = this.#entries.keys().next(); if (oldestEntry.done) break; this.#entries.delete(oldestEntry.value); } } }; /** Resolves a config-scoped cached value; calls without config intentionally bypass caching. */ function resolveConfigScopedRuntimeCacheValue(params) { if (!params.config) return params.load(); let configCache = params.cache.get(params.config); if (!configCache) { configCache = /* @__PURE__ */ new Map(); params.cache.set(params.config, configCache); } if (configCache.has(params.key)) return configCache.get(params.key); const loaded = params.load(); configCache.set(params.key, loaded); return loaded; } /** Encodes structured cache dimensions without separator ambiguity. */ function createPluginCacheKey(parts) { return JSON.stringify(parts); } /** Creates a config-scoped promise cache that drops rejected loads so callers can retry. */ function createConfigScopedPromiseLoader(load) { let defaultPromise; let promisesByConfig = /* @__PURE__ */ new WeakMap(); const createPromise = (config) => { const promise = Promise.resolve().then(() => load(config)); promise.catch(() => { if (config) promisesByConfig.delete(config); else if (defaultPromise === promise) defaultPromise = void 0; }); return promise; }; return { async load(config) { if (!config) { defaultPromise ??= createPromise(); return await defaultPromise; } const cached = promisesByConfig.get(config); if (cached) return await cached; const promise = createPromise(config); promisesByConfig.set(config, promise); return await promise; }, clear() { defaultPromise = void 0; promisesByConfig = /* @__PURE__ */ new WeakMap(); } }; } function normalizeMaxEntries(value, fallback) { if (!Number.isFinite(value) || value <= 0) return fallback; return Math.max(1, Math.floor(value)); } //#endregion export { resolveConfigScopedRuntimeCacheValue as i, createConfigScopedPromiseLoader as n, createPluginCacheKey as r, PluginLruCache as t };