fixed format issues

This commit is contained in:
Boki 2025-06-26 16:12:27 -04:00
parent a700818a06
commit 08f713d98b
55 changed files with 5680 additions and 5533 deletions

View file

@ -44,11 +44,13 @@ export function createNamespacedCache(
* Type guard to check if cache is available
*/
export function isCacheAvailable(cache: unknown): cache is CacheProvider {
return cache !== null &&
cache !== undefined &&
typeof cache === 'object' &&
'get' in cache &&
typeof (cache as CacheProvider).get === 'function';
return (
cache !== null &&
cache !== undefined &&
typeof cache === 'object' &&
'get' in cache &&
typeof (cache as CacheProvider).get === 'function'
);
}
/**

View file

@ -1,6 +1,6 @@
import Redis from 'ioredis';
import type { RedisConfig } from './types';
import { REDIS_DEFAULTS } from './constants';
import type { RedisConfig } from './types';
interface ConnectionConfig {
name: string;
@ -29,7 +29,7 @@ export class RedisConnectionManager {
*/
getConnection(config: ConnectionConfig): Redis {
const { name, singleton = true, redisConfig } = config;
if (singleton) {
const existing = RedisConnectionManager.connections.get(name);
if (existing) {
@ -38,11 +38,11 @@ export class RedisConnectionManager {
}
const connection = this.createConnection(redisConfig);
if (singleton) {
RedisConnectionManager.connections.set(name, connection);
}
return connection;
}
@ -68,10 +68,8 @@ export class RedisConnectionManager {
* Close all connections
*/
static async closeAll(): Promise<void> {
const promises = Array.from(this.connections.values()).map(conn =>
conn.quit().catch(() => {})
);
const promises = Array.from(this.connections.values()).map(conn => conn.quit().catch(() => {}));
await Promise.all(promises);
this.connections.clear();
}
}
}

View file

@ -1,16 +1,16 @@
// Cache constants
export const CACHE_DEFAULTS = {
TTL: 3600, // 1 hour in seconds
KEY_PREFIX: 'cache:',
SCAN_COUNT: 100,
} as const;
// Redis connection constants
export const REDIS_DEFAULTS = {
DB: 0,
MAX_RETRIES: 3,
RETRY_DELAY: 100,
CONNECT_TIMEOUT: 10000,
COMMAND_TIMEOUT: 5000,
KEEP_ALIVE: 0,
} as const;
// Cache constants
export const CACHE_DEFAULTS = {
TTL: 3600, // 1 hour in seconds
KEY_PREFIX: 'cache:',
SCAN_COUNT: 100,
} as const;
// Redis connection constants
export const REDIS_DEFAULTS = {
DB: 0,
MAX_RETRIES: 3,
RETRY_DELAY: 100,
CONNECT_TIMEOUT: 10000,
COMMAND_TIMEOUT: 5000,
KEEP_ALIVE: 0,
} as const;

View file

@ -40,4 +40,4 @@ export function createCache(options: CacheOptions): CacheProvider {
// Export only what's actually used
export type { CacheProvider, CacheStats } from './types';
export { NamespacedCache } from './namespaced-cache';
export { createNamespacedCache } from './cache-factory';
export { createNamespacedCache } from './cache-factory';

View file

@ -8,7 +8,8 @@ import type { CacheOptions, CacheProvider, CacheStats } from './types';
*/
export class RedisCache implements CacheProvider {
private redis: Redis;
private logger: { info?: (...args: unknown[]) => void; error?: (...args: unknown[]) => void } = console;
private logger: { info?: (...args: unknown[]) => void; error?: (...args: unknown[]) => void } =
console;
private defaultTTL: number;
private keyPrefix: string;
private stats: CacheStats = {
@ -28,7 +29,7 @@ export class RedisCache implements CacheProvider {
const manager = RedisConnectionManager.getInstance();
const name = options.name || 'CACHE';
this.redis = manager.getConnection({
name: `${name}-SERVICE`,
singleton: options.shared ?? true,
@ -72,19 +73,21 @@ export class RedisCache implements CacheProvider {
async set<T>(
key: string,
value: T,
options?: number | {
ttl?: number;
preserveTTL?: boolean;
onlyIfExists?: boolean;
onlyIfNotExists?: boolean;
getOldValue?: boolean;
}
options?:
| number
| {
ttl?: number;
preserveTTL?: boolean;
onlyIfExists?: boolean;
onlyIfNotExists?: boolean;
getOldValue?: boolean;
}
): Promise<T | null> {
try {
const fullKey = this.getKey(key);
const serialized = JSON.stringify(value);
const opts = typeof options === 'number' ? { ttl: options } : options || {};
let oldValue: T | null = null;
if (opts.getOldValue) {
const existing = await this.redis.get(fullKey);
@ -92,9 +95,9 @@ export class RedisCache implements CacheProvider {
oldValue = JSON.parse(existing);
}
}
const ttl = opts.ttl ?? this.defaultTTL;
if (opts.onlyIfExists) {
const result = await this.redis.set(fullKey, serialized, 'EX', ttl, 'XX');
if (!result) {
@ -115,7 +118,7 @@ export class RedisCache implements CacheProvider {
} else {
await this.redis.setex(fullKey, ttl, serialized);
}
return oldValue;
} catch (error) {
this.updateStats(false, true);
@ -145,21 +148,21 @@ export class RedisCache implements CacheProvider {
try {
const stream = this.redis.scanStream({
match: `${this.keyPrefix}*`,
count: CACHE_DEFAULTS.SCAN_COUNT
count: CACHE_DEFAULTS.SCAN_COUNT,
});
const pipeline = this.redis.pipeline();
stream.on('data', (keys: string[]) => {
if (keys.length) {
keys.forEach(key => pipeline.del(key));
}
});
await new Promise((resolve, reject) => {
stream.on('end', resolve);
stream.on('error', reject);
});
await pipeline.exec();
} catch (error) {
this.updateStats(false, true);
@ -172,9 +175,9 @@ export class RedisCache implements CacheProvider {
const keys: string[] = [];
const stream = this.redis.scanStream({
match: `${this.keyPrefix}${pattern}`,
count: CACHE_DEFAULTS.SCAN_COUNT
count: CACHE_DEFAULTS.SCAN_COUNT,
});
await new Promise((resolve, reject) => {
stream.on('data', (resultKeys: string[]) => {
keys.push(...resultKeys.map(k => k.replace(this.keyPrefix, '')));
@ -182,7 +185,7 @@ export class RedisCache implements CacheProvider {
stream.on('end', resolve);
stream.on('error', reject);
});
return keys;
} catch {
this.updateStats(false, true);
@ -206,8 +209,10 @@ export class RedisCache implements CacheProvider {
}
async waitForReady(timeout = 5000): Promise<void> {
if (this.redis.status === 'ready') {return;}
if (this.redis.status === 'ready') {
return;
}
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Redis connection timeout after ${timeout}ms`));
@ -223,4 +228,4 @@ export class RedisCache implements CacheProvider {
isReady(): boolean {
return this.redis.status === 'ready';
}
}
}

View file

@ -113,7 +113,12 @@ export interface CacheOptions {
name?: string; // Name for connection identification
shared?: boolean; // Whether to use shared connection
redisConfig: RedisConfig;
logger?: { info?: (...args: unknown[]) => void; error?: (...args: unknown[]) => void; warn?: (...args: unknown[]) => void; debug?: (...args: unknown[]) => void };
logger?: {
info?: (...args: unknown[]) => void;
error?: (...args: unknown[]) => void;
warn?: (...args: unknown[]) => void;
debug?: (...args: unknown[]) => void;
};
}
export interface CacheStats {