Skip to main content

@happyvertical/cache

Unified caching interface supporting Memory, File, Redis, and S3 backends with TTL, eviction policies, batch operations, and compression. All providers implement the same CacheProvider interface, so you can swap backends without changing application code.

Installation​

pnpm add @happyvertical/cache
# Requires @happyvertical/utils as a peer
# redis and @aws-sdk/client-s3 are bundled

Quick Start​

import { getCache } from '@happyvertical/cache';

const cache = await getCache({
provider: 'memory',
maxSize: 100 * 1024 * 1024,
evictionPolicy: 'lru',
});

await cache.set('user:123', { name: 'Alice' }, 3600); // TTL in seconds
const user = await cache.get('user:123');
await cache.delete('user:123');
await cache.close();

Providers​

Memory​

In-process Map-based cache. No external dependencies. Data lost on restart.

const cache = await getCache({
provider: 'memory',
namespace: 'app',
defaultTTL: 3600, // seconds
maxSize: 100 * 1024 * 1024, // bytes (default 100MB)
maxEntries: 10000, // default 10k
evictionPolicy: 'lru', // 'lru' | 'lfu' | 'fifo'
checkPeriod: 60000, // expiration sweep interval in ms
});

File​

Stores entries as files on disk with optional gzip compression. Persists across restarts.

const cache = await getCache({
provider: 'file',
cacheDir: './cache', // required
compression: true, // gzip (default false)
maxSize: 500 * 1024 * 1024, // bytes (default 500MB)
fileExtension: '.cache',
checkPeriod: 300000, // cleanup interval in ms
});

Redis​

Distributed cache using the redis npm client. Supports optional gzip compression for large values.

const cache = await getCache({
provider: 'redis',
host: 'localhost',
port: 6379,
password: 'secret',
db: 0,
namespace: 'app',
enableCompression: true,
compressionThreshold: 1024, // bytes — only compress values larger than this
connectTimeout: 5000, // ms
});

S3​

Stores entries as S3 objects. Useful for CI caches that must persist between runs. Compression enabled by default to reduce egress costs.

const cache = await getCache({
provider: 's3',
bucket: 'my-cache-bucket',
prefix: 'cache/',
region: 'us-east-1',
compression: true, // default true
compressionThreshold: 1024, // bytes
});

API​

All providers implement CacheProvider:

interface CacheProvider {
get<T>(key: string): Promise<T | undefined>;
set<T>(key: string, value: T, ttl?: number): Promise<void>;
has(key: string): Promise<boolean>;
delete(key: string): Promise<boolean>;
clear(namespace?: string): Promise<void>;
keys(pattern?: string): Promise<string[]>;
getMany<T>(keys: string[]): Promise<Map<string, T>>;
setMany<T>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void>;
deleteMany(keys: string[]): Promise<number>;
touch(key: string, ttl: number): Promise<boolean>;
getStats(): Promise<CacheStats>;
close(): Promise<void>;
}
  • TTL is always in seconds. Omit for no expiration.
  • keys() accepts glob patterns (user:*, report:2024*).
  • touch() updates TTL without modifying the value. Returns false if the key doesn't exist.
  • Batch ops (getMany, setMany, deleteMany) reduce round-trips, especially for Redis.

Environment Variables​

Configuration can be loaded from HAVE_CACHE_* environment variables via @happyvertical/utils/loadEnvConfig. Programmatic options always take precedence.

VariableMaps toNotes
HAVE_CACHE_PROVIDERprovidermemory, file, redis, s3
HAVE_CACHE_NAMESPACEnamespace
HAVE_CACHE_DEFAULT_TTLdefaultTTLseconds
HAVE_CACHE_MAX_SIZEmaxSizebytes (memory/file)
HAVE_CACHE_MAX_ENTRIESmaxEntriesmemory only
HAVE_CACHE_EVICTION_POLICYevictionPolicymemory only
HAVE_CACHE_CACHE_DIRcacheDirfile only
HAVE_CACHE_COMPRESSIONcompressionfile/s3
HAVE_CACHE_HOSThostredis only
HAVE_CACHE_PORTportredis only
HAVE_CACHE_PASSWORDpasswordredis only
HAVE_CACHE_BUCKETbuckets3 only
HAVE_CACHE_PREFIXprefixs3 only
HAVE_CACHE_REGIONregions3 only

Error Classes​

All errors extend CacheError(message, code, provider):

  • CacheKeyError — invalid key (empty or >250 chars)
  • CacheConnectionError — backend unreachable (Redis)
  • CacheSizeError — entry would exceed maxSize
  • CacheSerializationError — JSON serialize/deserialize failure

Exported Utilities​

Low-level helpers re-exported from shared/utils:

  • isValidKey(key) — check key length constraints
  • calculateSize(value) — approximate JSON byte size
  • matchesPattern(pattern, str) — glob matching
  • formatKey(namespace, key) / extractKey(namespace, fullKey) — namespace prefixing
  • isExpired(expiresAt) / calculateExpiration(ttl) — TTL math
  • serialize(value) / deserialize(json) — JSON wrappers