feat: harden analytics dashboard

This commit is contained in:
2026-05-27 15:19:31 +08:00
parent 5e0ca6a504
commit 356039d9cf
34 changed files with 1424 additions and 879 deletions

39
lib/query-cache.ts Normal file
View File

@@ -0,0 +1,39 @@
export interface QueryCacheOptions {
ttlMs: number;
maxEntries: number;
now?: () => number;
}
export function createQueryCache(options: QueryCacheOptions) {
const now = options.now ?? Date.now;
const entries = new Map<string, { data: unknown; ts: number }>();
async function cached<T>(key: string, fn: () => Promise<T>): Promise<T> {
const hit = entries.get(key);
if (hit && now() - hit.ts < options.ttlMs) {
return hit.data as T;
}
const data = await fn();
entries.set(key, { data, ts: now() });
while (entries.size > options.maxEntries) {
const oldestKey = entries.keys().next().value;
if (oldestKey === undefined) break;
entries.delete(oldestKey);
}
return data;
}
function clear() {
entries.clear();
}
return { cached, clear };
}
export const queryCache = createQueryCache({
ttlMs: 120_000,
maxEntries: 500,
});