| title | ICacheService Contract |
|---|---|
| description | Reference for the Cache Service contract — key-value caching with TTL support |
The Cache Service provides a key-value caching layer used throughout ObjectStack for metadata caching, query result caching, session storage, and rate limiting. Implementations can range from in-memory Maps to Redis clusters.
**Source:** `packages/spec/src/contracts/cache-service.ts` **Service name:** `cache` — resolve with `kernel.getService('cache')`export interface ICacheService {
// Core Operations
get<T = unknown>(key: string): Promise<T | undefined>;
set<T = unknown>(key: string, value: T, ttl?: number): Promise<void>;
delete(key: string): Promise<boolean>;
has(key: string): Promise<boolean>;
clear(): Promise<void>;
// Observability
stats(): Promise<CacheStats>;
}CacheStats is returned by stats() for monitoring:
export interface CacheStats {
hits: number; // Total number of cache hits
misses: number; // Total number of cache misses
keyCount: number; // Number of keys currently stored
memoryUsage?: number; // Memory usage in bytes (if available)
}Retrieves a cached value by key. Returns undefined if the key does not exist or has expired.
const user = await cacheService.get<AuthUser>('user:usr_01HQ3V5K8N');
if (user) {
console.log(user.name); // "Jane Smith"
}Stores a value with an optional TTL (time-to-live), passed as a positional argument in seconds.
// Cache for 5 minutes
await cacheService.set('user:usr_01HQ3V5K8N', userData, 300);
// Cache indefinitely (omit the ttl argument)
await cacheService.set('config:feature_flags', flags);Removes a key from the cache. Returns true if the key existed.
const deleted = await cacheService.delete('user:usr_01HQ3V5K8N');
// true if the key was found and removedChecks if a key exists without retrieving the value.
const exists = await cacheService.has('user:usr_01HQ3V5K8N');
// true or falseRemoves all entries from the cache. clear() takes no arguments — it flushes the entire store.
// Clear every key in the cache
await cacheService.clear();Returns counters for monitoring cache effectiveness.
const { hits, misses, keyCount } = await cacheService.stats();
const hitRate = hits / (hits + misses || 1);
console.log(`Cache hit rate: ${(hitRate * 100).toFixed(1)}% (${keyCount} keys)`);async function getObjectDefinition(name: string): Promise<ObjectDefinition> {
const cacheKey = `meta:object:${name}`;
// Try cache first
const cached = await cacheService.get<ObjectDefinition>(cacheKey);
if (cached) return cached;
// Load from source
const definition = await metadataService.getObject(name);
if (!definition) throw new Error(`Object not found: ${name}`);
// Store in cache
await cacheService.set(cacheKey, definition, 3600);
return definition;
}async function updateObjectDefinition(
name: string,
changes: Partial<ObjectDefinition>
): Promise<ObjectDefinition> {
// Update source of truth — register() saves the full definition
const current = await metadataService.getObject(name);
const updated = { ...(current as ObjectDefinition), ...changes };
await metadataService.register('object', name, updated);
// Update cache immediately
await cacheService.set(`meta:object:${name}`, updated, 3600);
return updated;
}// watch() is optional on IMetadataService — check before subscribing
const handle = metadataService.watch?.('object', (event) => {
// Invalidate the affected key when metadata changes.
// The contract deletes individual keys — track related keys
// (e.g. cached queries) yourself to invalidate them.
cacheService.delete(`meta:object:${event.name}`);
});Two adapters ship in @objectstack/service-cache, both implementing ICacheService:
MemoryCacheAdapter— Map-backed in-process store with TTL expiry and optional LRU-style eviction (maxSize). Suitable for development, testing, and single-process deployments.RedisCacheAdapter— a skeleton placeholder for future Redis integration; its methods currently throwRedisCacheAdapter not yet implemented.