Files
openclaw/src/plugins/plugin-lru-cache.ts
2026-04-26 14:28:15 -07:00

73 lines
1.8 KiB
TypeScript

export type PluginLruCacheResult<T> = { hit: true; value: T } | { hit: false };
export class PluginLruCache<T> {
readonly #defaultMaxEntries: number;
#maxEntries: number;
readonly #entries = new Map<string, T>();
constructor(defaultMaxEntries: number) {
this.#defaultMaxEntries = normalizeMaxEntries(defaultMaxEntries, 1);
this.#maxEntries = this.#defaultMaxEntries;
}
get maxEntries(): number {
return this.#maxEntries;
}
get size(): number {
return this.#entries.size;
}
setMaxEntriesForTest(value?: number): void {
this.#maxEntries =
typeof value === "number"
? normalizeMaxEntries(value, this.#defaultMaxEntries)
: this.#defaultMaxEntries;
this.#evictOldestEntries();
}
clear(): void {
this.#entries.clear();
}
get(cacheKey: string): T | undefined {
const cached = this.getResult(cacheKey);
return cached.hit ? cached.value : undefined;
}
getResult(cacheKey: string): PluginLruCacheResult<T> {
if (!this.#entries.has(cacheKey)) {
return { hit: false };
}
const cached = this.#entries.get(cacheKey) as T;
this.#entries.delete(cacheKey);
this.#entries.set(cacheKey, cached);
return { hit: true, value: cached };
}
set(cacheKey: string, value: T): void {
if (this.#entries.has(cacheKey)) {
this.#entries.delete(cacheKey);
}
this.#entries.set(cacheKey, value);
this.#evictOldestEntries();
}
#evictOldestEntries(): void {
while (this.#entries.size > this.#maxEntries) {
const oldestEntry = this.#entries.keys().next();
if (oldestEntry.done) {
break;
}
this.#entries.delete(oldestEntry.value);
}
}
}
function normalizeMaxEntries(value: number, fallback: number): number {
if (!Number.isFinite(value) || value <= 0) {
return fallback;
}
return Math.max(1, Math.floor(value));
}