refactor(plugin-sdk): unify channel dedupe primitives

This commit is contained in:
Peter Steinberger
2026-02-22 10:46:00 +01:00
parent edaa5ef7a5
commit 59807efa31
10 changed files with 339 additions and 70 deletions

View File

@@ -2,6 +2,7 @@ import { pruneMapToMaxSize } from "./map-size.js";
export type DedupeCache = {
check: (key: string | undefined | null, now?: number) => boolean;
peek: (key: string | undefined | null, now?: number) => boolean;
clear: () => void;
size: () => number;
};
@@ -37,20 +38,39 @@ export function createDedupeCache(options: DedupeCacheOptions): DedupeCache {
pruneMapToMaxSize(cache, maxSize);
};
const hasUnexpired = (key: string, now: number, touchOnRead: boolean): boolean => {
const existing = cache.get(key);
if (existing === undefined) {
return false;
}
if (ttlMs > 0 && now - existing >= ttlMs) {
cache.delete(key);
return false;
}
if (touchOnRead) {
touch(key, now);
}
return true;
};
return {
check: (key, now = Date.now()) => {
if (!key) {
return false;
}
const existing = cache.get(key);
if (existing !== undefined && (ttlMs <= 0 || now - existing < ttlMs)) {
touch(key, now);
if (hasUnexpired(key, now, true)) {
return true;
}
touch(key, now);
prune(now);
return false;
},
peek: (key, now = Date.now()) => {
if (!key) {
return false;
}
return hasUnexpired(key, now, false);
},
clear: () => {
cache.clear();
},

View File

@@ -227,5 +227,13 @@ describe("infra store", () => {
expect(cache.check("c", 200)).toBe(false);
expect(cache.size()).toBe(2);
});
it("supports non-mutating existence checks via peek()", () => {
const cache = createDedupeCache({ ttlMs: 1000, maxSize: 10 });
expect(cache.peek("a", 100)).toBe(false);
expect(cache.check("a", 100)).toBe(false);
expect(cache.peek("a", 200)).toBe(true);
expect(cache.peek("a", 1201)).toBe(false);
});
});
});