import type { CacheProvider, ICache } from './types'; /** * A cache wrapper that automatically prefixes all keys with a namespace * Used to provide isolated cache spaces for different services */ export class NamespacedCache implements CacheProvider { private readonly prefix: string; constructor( private readonly cache: CacheProvider, private readonly namespace: string ) { this.prefix = `${namespace}:`; } async get(key: string): Promise { return this.cache.get(`${this.prefix}${key}`); } async set(key: string, value: T, options?: number | { ttl?: number }): Promise { return this.cache.set(`${this.prefix}${key}`, value, options); } async del(key: string): Promise { return this.cache.del(`${this.prefix}${key}`); } async exists(key: string): Promise { return this.cache.exists(`${this.prefix}${key}`); } async keys(pattern: string = '*'): Promise { const fullPattern = `${this.prefix}${pattern}`; const keys = await this.cache.keys(fullPattern); // Remove the prefix from returned keys for cleaner API return keys.filter(k => k.startsWith(this.prefix)).map(k => k.substring(this.prefix.length)); } async clear(): Promise { // Clear only keys with this namespace prefix const keys = await this.cache.keys(`${this.prefix}*`); if (keys.length > 0) { await Promise.all(keys.map(key => this.cache.del(key.substring(this.prefix.length)))); } } getNamespace(): string { return this.namespace; } getFullPrefix(): string { return this.prefix; } // CacheProvider methods getStats() { return this.cache.getStats(); } async health(): Promise { return this.cache.health(); } async waitForReady(timeout?: number): Promise { return this.cache.waitForReady(timeout); } isReady(): boolean { return this.cache.isReady(); } } /** * Adapter to convert ICache to CacheProvider */ export class CacheAdapter implements CacheProvider { constructor(private readonly cache: ICache) {} async get(key: string): Promise { return this.cache.get(key); } async set(key: string, value: T, options?: number | { ttl?: number }): Promise { const ttl = typeof options === 'number' ? options : options?.ttl; await this.cache.set(key, value, ttl); return null; } async del(key: string): Promise { return this.cache.del(key); } async exists(key: string): Promise { return this.cache.exists(key); } async clear(): Promise { return this.cache.clear(); } async keys(pattern: string): Promise { return this.cache.keys(pattern); } getStats() { return { hits: 0, misses: 0, errors: 0, hitRate: 0, total: 0, uptime: process.uptime(), }; } async health(): Promise { return this.cache.ping(); } async waitForReady(): Promise { // ICache doesn't have waitForReady, so just check connection if (!this.cache.isConnected()) { throw new Error('Cache not connected'); } } isReady(): boolean { return this.cache.isConnected(); } }