cache
The cache utility creates a generic key-value cache with automatic garbage collection, metadata tracking, and observer support. It's designed to efficiently store temporary data with time-based expiration.
Implementation
View Source Code
ts
/**
* Creates a generic key-value cache with automatic garbage collection and observer support.
*
* @example
* ```ts
* const myCache = cache<string>();
* myCache.set(['user', 1], 'John Doe');
* const value = myCache.get(['user', 1]); // 'John Doe'
* myCache.scheduleGc(['user', 1], 5000); // Auto-delete after 5s
* ```
*
* @template T - The type of values stored in the cache.
*
* @returns A cache instance with get, set, delete, clear, and GC methods.
*/
export function cache<T>() {
const store = new Map<string, T>();
const gcTimers = new Map<string, ReturnType<typeof setTimeout>>();
const metadata = new Map<string, { lastUsedAt: number }>();
const hash = (key: readonly unknown[]) => JSON.stringify(key);
function get(key: readonly unknown[]): T | undefined {
return store.get(hash(key));
}
function set(key: readonly unknown[], value: T): void {
store.set(hash(key), value);
}
function del(key: readonly unknown[]): boolean {
const h = hash(key);
clearGc(h);
metadata.delete(h);
return store.delete(h);
}
function clear(): void {
gcTimers.forEach((timer) => {
clearTimeout(timer);
});
store.clear();
gcTimers.clear();
metadata.clear();
}
function size(): number {
return store.size;
}
function scheduleGc(key: readonly unknown[], delayMs: number): void {
const h = hash(key);
clearGc(h);
gcTimers.set(
h,
setTimeout(() => {
store.delete(h);
gcTimers.delete(h);
metadata.delete(h);
}, delayMs),
);
}
function setMeta(key: readonly unknown[], meta: Record<string, unknown>): void {
metadata.set(hash(key), { lastUsedAt: Date.now(), ...meta });
}
function getMeta(key: readonly unknown[]): Record<string, unknown> | undefined {
return metadata.get(hash(key));
}
function getMetaByHash(keyHash: string): Record<string, unknown> | undefined {
return metadata.get(keyHash);
}
function listMetaHashes(): string[] {
return Array.from(metadata.keys());
}
function clearGc(keyHash: string): void {
const timer = gcTimers.get(keyHash);
if (timer) {
clearTimeout(timer);
gcTimers.delete(keyHash);
}
}
return {
clear,
delete: del,
get,
getMeta,
getMetaByHash,
hash,
listMetaHashes,
scheduleGc,
set,
setMeta,
size,
};
}Features
- Isomorphic: Works in both Browser and Node.js.
- Type-safe: Generic typing for cache values.
- Automatic GC: Schedule automatic garbage collection for cache entries.
- Metadata Support: Store additional metadata alongside cache entries.
- Flexible Keys: Use arrays of any values as cache keys.
API
ts
function cache<T>(): {
get: (key: readonly unknown[]) => T | undefined;
set: (key: readonly unknown[], value: T) => void;
delete: (key: readonly unknown[]) => boolean;
clear: () => void;
size: () => number;
scheduleGc: (key: readonly unknown[], delayMs: number) => void;
setMeta: (key: readonly unknown[], meta: Record<string, unknown>) => void;
getMeta: (key: readonly unknown[]) => Record<string, unknown> | undefined;
getMetaByHash: (keyHash: string) => Record<string, unknown> | undefined;
listMetaHashes: () => string[];
hash: (key: readonly unknown[]) => string;
};Parameters
None. The function returns a cache instance.
Returns
A cache instance with the following methods:
- get(key): Retrieve a value from the cache.
- set(key, value): Store a value in the cache.
- delete(key): Remove a value from the cache. Returns
trueif deleted,falseif not found. - clear(): Remove all values from the cache.
- size(): Get the current number of entries in the cache.
- scheduleGc(key, delayMs): Schedule automatic deletion of a cache entry after the specified delay.
- setMeta(key, meta): Store metadata for a cache entry (automatically includes
lastUsedAttimestamp). - getMeta(key): Retrieve metadata for a cache entry.
- getMetaByHash(keyHash): Retrieve metadata using the hash string directly.
- listMetaHashes(): Get a list of all metadata hash keys.
- hash(key): Generate the hash string for a given key.
Examples
Basic Cache Usage
ts
import { cache } from '@vielzeug/toolkit';
const userCache = cache<{ name: string; email: string }>();
// Store user data
userCache.set(['user', 123], { name: 'Alice', email: 'alice@example.com' });
// Retrieve user data
const user = userCache.get(['user', 123]);
console.log(user?.name); // 'Alice'
// Check cache size
console.log(userCache.size()); // 1Automatic Garbage Collection
ts
import { cache } from '@vielzeug/toolkit';
const sessionCache = cache<string>();
// Store session with 5-minute expiration
sessionCache.set(['session', 'abc123'], 'user-data');
sessionCache.scheduleGc(['session', 'abc123'], 5 * 60 * 1000);
// Session will be automatically deleted after 5 minutesUsing Metadata
ts
import { cache } from '@vielzeug/toolkit';
const apiCache = cache<any>();
// Store API response with metadata
apiCache.set(['api', '/users'], { data: [...] });
apiCache.setMeta(['api', '/users'], {
staleTime: 60000,
cacheTime: 300000,
enabled: true
});
// Retrieve metadata
const meta = apiCache.getMeta(['api', '/users']);
console.log(meta?.staleTime); // 60000
console.log(meta?.lastUsedAt); // timestampComplex Cache Keys
ts
import { cache } from '@vielzeug/toolkit';
const queryCache = cache<any>();
// Use complex objects as part of the key
const key = ['query', { page: 1, filter: 'active' }, ['name', 'email']];
queryCache.set(key, { results: [...] });
// Same key structure retrieves the value
const results = queryCache.get(['query', { page: 1, filter: 'active' }, ['name', 'email']]);Listing and Cleaning Up
ts
import { cache } from '@vielzeug/toolkit';
const myCache = cache<string>();
myCache.set(['a'], 'A');
myCache.set(['b'], 'B');
myCache.setMeta(['a'], { priority: 'high' });
myCache.setMeta(['b'], { priority: 'low' });
// List all metadata keys
const hashes = myCache.listMetaHashes();
// Inspect metadata for each
hashes.forEach((hash) => {
const meta = myCache.getMetaByHash(hash);
console.log(meta);
});
// Clear everything
myCache.clear();
console.log(myCache.size()); // 0Implementation Notes
- Keys are hashed using
JSON.stringify, so key order and structure must match exactly for retrieval. - Garbage collection timers are automatically cleared when entries are deleted or the cache is cleared.
- Metadata always includes a
lastUsedAttimestamp automatically. - The cache is purely in-memory and will be lost on page refresh or process restart.