Cache API Reference
Complete reference for createCache(), the Cache class, CacheOptions, and LiveConfigService.
Cache API Reference
Import cache utilities from telaio/cache:
import { createCache, Cache, LiveConfigService } from 'telaio/cache';createCache()
function createCache(
options?: CacheOptions | Record<string, unknown>,
logger?: Logger,
): CacheCreates a Cache instance. Accepts either explicit CacheOptions or a loaded config record. When passed a config record it reads REDIS_ENABLED and REDIS_URL automatically.
If enabled is false (or REDIS_ENABLED=false in config), returns a no-op stub. All methods return null or resolve immediately without connecting to Redis. No redis peer dependency is loaded.
// From explicit options
const cache = createCache({ enabled: true, url: 'redis://localhost:6379' });
// From a loaded config (reads REDIS_ENABLED and REDIS_URL)
const cache = createCache(config);
// Disabled stub -- safe to use in tests without Redis
const cache = createCache({ enabled: false });CacheOptions
interface CacheOptions {
enabled?: boolean;
url?: string;
}| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Whether to connect to Redis. When false, a no-op stub is returned. |
url | string | undefined | Redis connection URI (e.g. redis://localhost:6379). Required when enabled is true. |
Cache
The Cache class wraps a redis (node-redis) client pool and provides a consistent interface for string and JSON operations. It requires redis as a peer dependency.
class Cache {
redis: RedisClientPool | null;
async get(key: string): Promise<string | null>
async set(key: string, value: string, ttl?: number): Promise<void>
async getRecord<T = unknown>(key: string): Promise<T | null>
async setRecord(key: string, value: unknown, ttl?: number): Promise<void>
async delete(key: string): Promise<void>
async close(): Promise<void>
}Properties
| Property | Type | Description |
|---|---|---|
redis | RedisClientPool | null | The underlying node-redis client pool. null when cache is disabled. |
Methods
.get(key)
async get(key: string): Promise<string | null>Retrieves a raw string value. Returns null if the key does not exist or if the cache is disabled.
.set(key, value, ttl?)
async set(key: string, value: string, ttl?: number): Promise<void>Stores a raw string value. If ttl is provided, the key expires after that many seconds. If the cache is disabled, this is a no-op.
.getRecord<T>(key)
async getRecord<T = unknown>(key: string): Promise<T | null>Retrieves and JSON.parse()s a stored value. Returns null if the key does not exist, if parsing fails, or if the cache is disabled.
.setRecord(key, value, ttl?)
async setRecord(key: string, value: unknown, ttl?: number): Promise<void>JSON.stringify()s value and stores it. If ttl is provided, the key expires after that many seconds. No-op when the cache is disabled.
.delete(key)
async delete(key: string): Promise<void>Deletes a key. No-op when the cache is disabled.
.close()
async close(): Promise<void>Closes the Redis connection gracefully. Called automatically by app.stop(). No-op when the cache is disabled.
Usage example
import { createCache } from 'telaio/cache';
const cache = createCache({ enabled: true, url: 'redis://localhost:6379' });
// String values
await cache.set('session:abc123', 'user-id-456', 3600); // expires in 1 hour
const raw = await cache.get('session:abc123'); // 'user-id-456'
// JSON records
await cache.setRecord('user:42', { name: 'Alice', role: 'admin' }, 600);
const user = await cache.getRecord<{ name: string; role: string }>('user:42');
// { name: 'Alice', role: 'admin' }
await cache.delete('session:abc123');
await cache.close();Disabled mode
When enabled: false, all methods silently succeed or return null:
const cache = createCache({ enabled: false });
cache.redis; // null
await cache.get('any-key'); // null -- no Redis call
await cache.set('any-key', 'value'); // no-op
await cache.setRecord('any-key', { foo: 'bar' }); // no-op
await cache.getRecord('any-key'); // null
await cache.delete('any-key'); // no-op
await cache.close(); // no-opThis is the recommended approach for tests that do not need Redis.
LiveConfigService<TModules>
class LiveConfigService<TModules extends Record<string, unknown>> {
constructor(options: LiveConfigOptions)
async get<K extends keyof TModules>(module: K): Promise<TModules[K] | null>
async set<K extends keyof TModules>(module: K, config: TModules[K]): Promise<void>
async delete<K extends keyof TModules>(module: K): Promise<void>
}
interface LiveConfigOptions {
db: Kysely<any>;
cache: Cache;
ttl?: number; // cache TTL in seconds (default: 120)
keyPrefix?: string; // cache key prefix (default: 'live-config')
logger?: Logger;
}A stale-while-revalidate (SWR) config service backed by a Postgres table and Redis cache. On cache hit, returns the cached value and refreshes in the background. On cache miss, fetches from Postgres and writes to Redis.
The expected table shape is: live_configs(module TEXT PRIMARY KEY, config JSONB).
Constructor
| Option | Type | Default | Description |
|---|---|---|---|
db | Kysely<any> | required | Kysely database instance |
cache | Cache | required | Cache instance (disabled stub is valid) |
ttl | number | 120 | Cache TTL in seconds |
keyPrefix | string | 'live-config' | Prefix for Redis cache keys |
logger | Logger | — | Pino logger for error reporting |
Methods
.get(module)
Returns the config for module. Redis first (fast path), falls back to Postgres. Returns null if not found in either store.
.set(module, config)
Persists config to Postgres and writes to Redis. Both writes happen before resolving.
.delete(module)
Removes the config from both Postgres and Redis. Both deletes happen before resolving.
Usage
import { LiveConfigService } from 'telaio/cache';
interface FeatureFlags {
newCheckout: boolean;
maxUploadSizeMb: number;
}
// Module name becomes the generic key for type safety
interface AppConfigs {
'checkout-flags': FeatureFlags;
}
const configs = new LiveConfigService<AppConfigs>({ db, cache });
await configs.set('checkout-flags', { newCheckout: true, maxUploadSizeMb: 50 });
const flags = await configs.get('checkout-flags');
// FeatureFlags | null
await configs.delete('checkout-flags');