Skip to main content

Cache Module

The Cache Module (@ever-works/agent/cache) provides a persistent caching layer backed by TypeORM. It wraps a custom Keyv-compatible adapter that stores cache entries in the database, supporting TTL expiration, namespace isolation, and batch operations.

Module Structure

packages/agent/src/cache/
├── index.ts # Barrel exports (re-exports @nestjs/cache-manager + local modules)
├── cache.factory.ts # CacheFactory with InMemory and TypeORM strategies
├── repository.ts # CacheEntryRepository injectable wrapper
└── typeorm-keyv.adapter.ts # TypeORMKeyvAdapter (core implementation)

Architecture

Key Components

CacheFactory

A static factory that creates Keyv cache instances in two modes:

import { CacheFactory } from '@ever-works/agent/cache';

// In-memory cache (default, no persistence)
const memoryCache = CacheFactory.InMemory();

// TypeORM-backed cache (persistent, uses database)
const dbCache = CacheFactory.TypeORM({
dataSource, // TypeORM DataSource
namespace: 'ai', // Optional namespace prefix
ttl: 3600000 // Default TTL in milliseconds
});
MethodDescription
InMemory()Creates a Keyv instance backed by an in-memory Map. Suitable for testing or ephemeral caches.
TypeORM(options)Creates a Keyv instance backed by the TypeORMKeyvAdapter. Data persists across restarts.

TypeORMKeyvAdapter

The core adapter class that implements Keyv's store interface using TypeORM's CacheEntry entity. It extends EventEmitter and provides:

MethodSignatureDescription
getget(key: string): Promise<string | undefined>Retrieves a value by key. Returns undefined if expired or missing.
setset(key: string, value: string, ttl?: number): Promise<void>Stores a value with optional TTL (milliseconds). Uses upsert for idempotency.
deletedelete(key: string): Promise<boolean>Deletes a single cache entry by key.
deleteManydeleteMany(keys: string[]): Promise<boolean>Batch-deletes multiple keys efficiently.
clearclear(): Promise<void>Clears all entries in the current namespace.
hashas(key: string): Promise<boolean>Checks existence without returning the value.
cleanExpiredcleanExpired(): Promise<number>Removes all expired entries. Returns the count of deleted rows.
deleteUnscopedEntriesLikedeleteUnscopedEntriesLike(pattern: string): Promise<number>Deletes entries matching a LIKE pattern (without namespace prefix).
wrapwrap<T>(key, fetcher, ttl?): Promise<T>Cache-aside pattern: returns cached value or calls fetcher, caches the result, and returns it.

Namespace isolation: All keys are prefixed with the configured namespace (e.g., ai:myKey). This prevents collisions when multiple subsystems share the same database table.

TTL handling: Expiration timestamps are stored as bigint columns. The get method checks expiration at read time and deletes stale entries lazily.

CacheEntryRepository

An @Injectable() NestJS service that wraps the TypeORMKeyvAdapter for dependency injection:

import { CacheEntryRepository } from '@ever-works/agent/cache';

@Injectable()
export class MyService {
constructor(private readonly cache: CacheEntryRepository) {}

async getCachedResult(key: string): Promise<string | undefined> {
return this.cache.get(key);
}
}

CacheEntry Entity

The database entity backing the cache (defined in entities/cache.entity.ts):

ColumnTypeDescription
keyvarchar (PK)Namespaced cache key
valuetextSerialized cache value
expiresAtbigint (nullable)Expiration timestamp in milliseconds

Usage Examples

Cache-Aside Pattern

// Automatically fetches and caches expensive computations
const result = await cache.wrap(
'expensive-computation-key',
async () => {
// This only runs on cache miss
return await performExpensiveOperation();
},
60 * 60 * 1000 // 1 hour TTL
);

Periodic Cleanup

// Clean up expired entries (e.g., in a cron job)
const deletedCount = await adapter.cleanExpired();
logger.log(`Cleaned ${deletedCount} expired cache entries`);

Pattern-Based Deletion

// Delete all cache entries matching a pattern
const deleted = await adapter.deleteUnscopedEntriesLike('work:%');

Exports

The module re-exports everything from @nestjs/cache-manager alongside its own components:

  • CacheFactory -- Static factory for creating cache instances
  • CacheEntryRepository -- Injectable repository for DI consumers
  • TypeORMKeyvAdapter -- Low-level adapter (rarely used directly)
  • All exports from @nestjs/cache-manager (CacheModule, CACHE_MANAGER, etc.)