UNPKG

@digicroz/node-backend-utils

Version:

Backend utilities for Node.js applications - Redis client wrappers and more utilities for TypeScript/JavaScript projects

120 lines (116 loc) 4.92 kB
import { RedisClientType } from 'redis'; /** * Extract all possible cache key types from a cache key definition object * Recursively extracts string literals and function return types * * @example * ```typescript * const CACHE_KEYS = { * users: { * profile: (userId: number) => `user:${userId}:profile` as const, * }, * } as const; * * type CacheKey = ExtractCacheKeyType<typeof CACHE_KEYS>; * // Result: "user:${number}:profile" * ``` */ type ExtractCacheKeyType<T> = T extends string ? T : T extends (...args: any[]) => infer R ? R extends string ? R : never : T extends Record<string, any> ? { [K in keyof T]: ExtractCacheKeyType<T[K]>; }[keyof T] : never; interface RedisGenericClientConfig { prefix: string; isEnabled: boolean; } /** * Generic Redis client with optional type-safe cache keys * @template TCacheKeys - Optional type for cache keys (defaults to string) */ declare class RedisGenericClient<TCacheKeys = string> { private readonly keyPrefix; private readonly isEnabled; constructor(config: RedisGenericClientConfig); private addPrefix; private removePrefix; isClientEnabled(): boolean; isClientConnected(): boolean; getStatus(): { isEnabled: boolean; prefix: string; isConnected: boolean; isConnecting: boolean; initializationAttempted: boolean; }; set(key: TCacheKeys, value: string): Promise<string | null>; setObj<T>(key: TCacheKeys, value: T): Promise<string | null>; setEx(key: TCacheKeys, seconds: number, value: string): Promise<string | null>; setObjEx<T>(key: TCacheKeys, seconds: number, value: T): Promise<string | null>; get(key: TCacheKeys): Promise<string | null>; getObj<T>(key: TCacheKeys): Promise<T | null>; del(key: TCacheKeys): Promise<number | null>; delMultiple(keys: TCacheKeys[]): Promise<number | null>; /** * Delete all keys matching a pattern (Production-safe using SCAN) * @param pattern - Pattern to match (e.g., "games:*" to delete all keys starting with "games:") * @param batchSize - Number of keys to scan per iteration (default: 100) * @returns Number of keys deleted, or null if client is disabled * * @example * ```typescript * // Delete all game-related keys * await cache.delByPattern("games:*"); * * // With type-safe patterns * await cache.delByPattern(CACHE_KEYS.games._pattern); * ``` */ delByPattern(pattern: TCacheKeys | string, batchSize?: number): Promise<number | null>; exists(key: TCacheKeys): Promise<number | null>; expire(key: TCacheKeys, seconds: number): Promise<number | null>; ttl(key: TCacheKeys): Promise<number | null>; incr(key: TCacheKeys): Promise<number | null>; incrBy(key: TCacheKeys, increment: number): Promise<number | null>; decr(key: TCacheKeys): Promise<number | null>; keys(pattern: string): Promise<string[] | null>; hSet(key: TCacheKeys, field: string, value: string): Promise<number | null>; hGet(key: TCacheKeys, field: string): Promise<string | null>; hGetAll(key: TCacheKeys): Promise<Record<string, string> | null>; hDel(key: TCacheKeys, fields: string | string[]): Promise<number | null>; lPush(key: TCacheKeys, ...elements: string[]): Promise<number | null>; rPush(key: TCacheKeys, ...elements: string[]): Promise<number | null>; lPop(key: TCacheKeys): Promise<string | null>; rPop(key: TCacheKeys): Promise<string | null>; lRange(key: TCacheKeys, start: number, stop: number): Promise<string[] | null>; sAdd(key: TCacheKeys, ...members: string[]): Promise<number | null>; sMembers(key: TCacheKeys): Promise<string[] | null>; sRem(key: TCacheKeys, ...members: string[]): Promise<number | null>; safeExecute<T>(operation: (client: RedisClientType, addPrefix: (key: string) => string) => Promise<T>): Promise<T | null>; } type TCreateRedisClient = { prefix: string; isEnabled?: boolean; }; /** * Create a Redis client instance * * @example * ```typescript * // Without type safety (accepts any string) * const cache = createRedisGenericClient({ prefix: "myapp" }); * await cache.set("any:key", "value"); * * // With type safety (only accepts defined cache keys) * const CACHE_KEYS = { * users: { * profile: (userId: number) => `user:${userId}:profile` as const, * }, * } as const; * * type CacheKey = ExtractCacheKeyType<typeof CACHE_KEYS>; * const cache = createRedisGenericClient<CacheKey>({ prefix: "myapp" }); * await cache.set(CACHE_KEYS.users.profile(123), "value"); // ✅ Valid * await cache.set("random:key", "value"); // ❌ Type error * ``` */ declare const createRedisGenericClient: <TCacheKeys = string>({ prefix, isEnabled, }: TCreateRedisClient) => RedisGenericClient<TCacheKeys>; export { type ExtractCacheKeyType, RedisGenericClient, createRedisGenericClient };