huge refactor to remove depenencie hell and add typesafe container

This commit is contained in:
Boki 2025-06-24 09:37:51 -04:00
parent 28b9822d55
commit 843a7b9b9b
148 changed files with 3603 additions and 2378 deletions

View file

@ -1,23 +1,23 @@
import { NamespacedCache } from './namespaced-cache';
import type { CacheProvider } from './types';
/**
* Factory function to create namespaced caches
* Provides a clean API for services to get their own namespaced cache
*/
export function createNamespacedCache(
cache: CacheProvider | null | undefined,
namespace: string
): CacheProvider | null {
if (!cache) {
return null;
}
return new NamespacedCache(cache, namespace);
}
/**
* Type guard to check if cache is available
*/
export function isCacheAvailable(cache: any): cache is CacheProvider {
return cache !== null && cache !== undefined && typeof cache.get === 'function';
}
import { NamespacedCache } from './namespaced-cache';
import type { CacheProvider } from './types';
/**
* Factory function to create namespaced caches
* Provides a clean API for services to get their own namespaced cache
*/
export function createNamespacedCache(
cache: CacheProvider | null | undefined,
namespace: string
): CacheProvider | null {
if (!cache) {
return null;
}
return new NamespacedCache(cache, namespace);
}
/**
* Type guard to check if cache is available
*/
export function isCacheAvailable(cache: any): cache is CacheProvider {
return cache !== null && cache !== undefined && typeof cache.get === 'function';
}

View file

@ -88,7 +88,7 @@ export class RedisConnectionManager {
};
const redis = new Redis(redisOptions);
// Use the provided logger or fall back to instance logger
const log = logger || this.logger;

View file

@ -1,101 +1,100 @@
import type { CacheProvider } 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 = `cache:${namespace}:`;
}
async get<T = any>(key: string): Promise<T | null> {
return this.cache.get(`${this.prefix}${key}`);
}
async set<T>(
key: string,
value: T,
options?:
| number
| {
ttl?: number;
preserveTTL?: boolean;
onlyIfExists?: boolean;
onlyIfNotExists?: boolean;
getOldValue?: boolean;
}
): Promise<T | null> {
return this.cache.set(`${this.prefix}${key}`, value, options);
}
async del(key: string): Promise<void> {
return this.cache.del(`${this.prefix}${key}`);
}
async exists(key: string): Promise<boolean> {
return this.cache.exists(`${this.prefix}${key}`);
}
async keys(pattern: string = '*'): Promise<string[]> {
const fullPattern = `${this.prefix}${pattern}`;
const keys = await this.cache.keys(fullPattern);
// Remove the prefix from returned keys for cleaner API
return keys.map(k => k.substring(this.prefix.length));
}
async clear(): Promise<void> {
// 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)));
}
}
getStats() {
return this.cache.getStats();
}
async health(): Promise<boolean> {
return this.cache.health();
}
isReady(): boolean {
return this.cache.isReady();
}
async waitForReady(timeout?: number): Promise<void> {
return this.cache.waitForReady(timeout);
}
async close(): Promise<void> {
// Namespaced cache doesn't own the connection, so we don't close it
// The underlying cache instance should be closed by its owner
}
getNamespace(): string {
return this.namespace;
}
getFullPrefix(): string {
return this.prefix;
}
/**
* Get a value using a raw Redis key (bypassing the namespace prefix)
* Delegates to the underlying cache's getRaw method if available
*/
async getRaw<T = unknown>(key: string): Promise<T | null> {
if (this.cache.getRaw) {
return this.cache.getRaw<T>(key);
}
// Fallback for caches that don't implement getRaw
return null;
}
}
import type { CacheProvider } 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 = `cache:${namespace}:`;
}
async get<T = any>(key: string): Promise<T | null> {
return this.cache.get(`${this.prefix}${key}`);
}
async set<T>(
key: string,
value: T,
options?:
| number
| {
ttl?: number;
preserveTTL?: boolean;
onlyIfExists?: boolean;
onlyIfNotExists?: boolean;
getOldValue?: boolean;
}
): Promise<T | null> {
return this.cache.set(`${this.prefix}${key}`, value, options);
}
async del(key: string): Promise<void> {
return this.cache.del(`${this.prefix}${key}`);
}
async exists(key: string): Promise<boolean> {
return this.cache.exists(`${this.prefix}${key}`);
}
async keys(pattern: string = '*'): Promise<string[]> {
const fullPattern = `${this.prefix}${pattern}`;
const keys = await this.cache.keys(fullPattern);
// Remove the prefix from returned keys for cleaner API
return keys.map(k => k.substring(this.prefix.length));
}
async clear(): Promise<void> {
// 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)));
}
}
getStats() {
return this.cache.getStats();
}
async health(): Promise<boolean> {
return this.cache.health();
}
isReady(): boolean {
return this.cache.isReady();
}
async waitForReady(timeout?: number): Promise<void> {
return this.cache.waitForReady(timeout);
}
async close(): Promise<void> {
// Namespaced cache doesn't own the connection, so we don't close it
// The underlying cache instance should be closed by its owner
}
getNamespace(): string {
return this.namespace;
}
getFullPrefix(): string {
return this.prefix;
}
/**
* Get a value using a raw Redis key (bypassing the namespace prefix)
* Delegates to the underlying cache's getRaw method if available
*/
async getRaw<T = unknown>(key: string): Promise<T | null> {
if (this.cache.getRaw) {
return this.cache.getRaw<T>(key);
}
// Fallback for caches that don't implement getRaw
return null;
}
}