npm package: @kyrasource/redis
Description: Advanced Redis client and module for NestJS applications with caching, connection management, TTL handling, and statistics tracking
Author: Kyrasource
Latest version: 1.0.2

# @kyrasource/redis

Advanced Redis client and module for NestJS applications with caching, connection management, TTL handling, and statistics tracking.

## Features

- ✅ **Connection Management**: Auto-reconnection with configurable retry strategy
- ✅ **Cache Statistics**: Built-in hit/miss tracking and performance monitoring
- ✅ **Flexible TTL**: Set indefinite persistence or custom TTL per key
- ✅ **Pattern Deletion**: Delete multiple keys matching a pattern
- ✅ **TypeScript Support**: Full type safety with generics
- ✅ **NestJS Integration**: Global module with ConfigService support
- ✅ **Error Handling**: Graceful fallbacks and comprehensive logging
- ✅ **Production Ready**: Used in Redis Cloud with enterprise-grade reliability

## Installation

```bash
npm install @kyrasource/redis
```

## Quick Start

### 1. Setup in Your Module

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { RedisModule } from '@kyrasource/redis';
import redisConfig from './config/redis.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [redisConfig],
    }),
    RedisModule,
  ],
})
export class AppModule {}
```

### 2. Configure Redis in `.env`

```env
REDIS_USERNAME=default
REDIS_PASSWORD=your-password
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DATABASE=kushi-redis
REDIS_MAX_RETRIES=3
REDIS_RETRY_DELAY=1000
```

### 3. Use RedisService

```typescript
import { Injectable } from '@nestjs/common';
import { RedisService } from '@kyrasource/redis';

@Injectable()
export class MyService {
  constructor(private readonly redis: RedisService) {}

  async example() {
    // Set with TTL (seconds)
    await this.redis.set('user:123', { name: 'John' }, 3600);

    // Set indefinitely
    await this.redis.set('config:app', { theme: 'dark' });

    // Get value
    const user = await this.redis.get<User>('user:123');

    // Check existence
    const exists = await this.redis.exists('user:123');

    // Delete key
    await this.redis.delete('user:123');

    // Delete by pattern
    await this.redis.deletePattern('user:*');

    // Get statistics
    const stats = this.redis.getStats();
    console.log(`Hit rate: ${stats.hitRate}%`);

    // Health check
    const ok = await this.redis.ping();
  }
}
```

## Configuration

Create `src/config/redis.config.ts`:

```typescript
import { registerAs } from '@nestjs/config';
import { RedisConfig } from '@kyrasource/redis';

export default registerAs('redis', (): RedisConfig => ({
  username: process.env.REDIS_USERNAME || 'default',
  password: process.env.REDIS_PASSWORD,
  host: process.env.REDIS_HOST || 'localhost',
  port: parseInt(process.env.REDIS_PORT || '6379', 10),
  database: process.env.REDIS_DATABASE || 'default',
  maxRetries: parseInt(process.env.REDIS_MAX_RETRIES || '3', 10),
  retryDelay: parseInt(process.env.REDIS_RETRY_DELAY || '1000', 10),
  ttl: process.env.REDIS_TTL ? parseInt(process.env.REDIS_TTL, 10) : undefined,
  enabled: process.env.CACHE_ENABLED !== 'false',
  maxItems: parseInt(process.env.CACHE_MAX_ITEMS || '1000', 10),
  ragTimeoutMs: parseInt(process.env.RAG_TIMEOUT_MS || '30000', 10),
}));
```

## API Reference

### RedisService Methods

#### `set(key: string, value: any, ttlSeconds?: number): Promise<boolean>`
Set a value with optional TTL. If `ttlSeconds` is omitted, the key persists indefinitely.

```typescript
await redis.set('user:1', { id: 1, name: 'John' }, 3600); // 1 hour
await redis.set('settings', { theme: 'dark' }); // Indefinite
```

#### `get<T>(key: string): Promise<T | null>`
Retrieve and deserialize a cached value.

```typescript
const user = await redis.get<User>('user:1');
if (user) {
  console.log(user.name);
}
```

#### `delete(key: string): Promise<boolean>`
Delete a single key.

```typescript
await redis.delete('user:1');
```

#### `deletePattern(pattern: string): Promise<number>`
Delete all keys matching a glob pattern.

```typescript
const deleted = await redis.deletePattern('user:*');
console.log(`Deleted ${deleted} keys`);
```

#### `exists(key: string): Promise<boolean>`
Check if a key exists.

```typescript
if (await redis.exists('user:1')) {
  console.log('User cached');
}
```

#### `ping(): Promise<boolean>`
Health check - returns true if Redis is reachable.

```typescript
const healthy = await redis.ping();
```

#### `getStats(): RedisStats`
Get cache hit/miss statistics.

```typescript
const { hits, misses, hitRate, isConnected } = redis.getStats();
```

## Advanced Usage

### Using with Other Services

```typescript
import { Injectable } from '@nestjs/common';
import { RedisService } from '@kyrasource/redis';

@Injectable()
export class UserCacheService {
  constructor(private readonly redis: RedisService) {}

  async getCachedUser(id: number): Promise<User | null> {
    const cached = await this.redis.get<User>(`user:${id}`);
    if (cached) return cached;

    // Not in cache - fetch from database
    const user = await this.database.user.findById(id);
    if (user) {
      // Cache for 1 hour
      await this.redis.set(`user:${id}`, user, 3600);
    }
    return user;
  }
}
```

## Type Safety

```typescript
interface User {
  id: number;
  name: string;
  email: string;
}

// Fully typed
const user = await redis.get<User>('user:123');
if (user) {
  console.log(user.email); // Type-safe!
}
```

## Exports

From `@kyrasource/redis` you can import:

```typescript
export { RedisService } from './redis.service';
export { RedisModule } from './redis.module';
export { RedisConfig, RedisStats } from './types';
```

## Connection Details

The service automatically handles:
- Connection pooling
- Reconnection with exponential backoff
- Error recovery
- Graceful shutdown

Connection events are logged at INFO/DEBUG level. Check your logger output for details.

## Troubleshooting

### "Redis connection failed"
- Verify Redis is running and accessible
- Check credentials in `.env`
- Ensure network connectivity to Redis host

### "Max retries exceeded"
- Redis is unreachable or crashed
- The service will log detailed error messages
- Requests will fail gracefully

### Memory Issues
- Monitor cache hit rate via `getStats()`
- Implement cache eviction policies
- Use appropriate TTL values

## License

MIT - See LICENSE file

## Support

For issues, feature requests, or documentation, visit:
- GitHub: [kyrasource/redis](https://github.com/kyrasource/redis)
- npm: [@kyrasource/redis](https://www.npmjs.com/package/@kyrasource/redis)
    await this.redisService.set('persistent-key', { data: 'value' });

    // Get value
    const data = await this.redisService.get('key');

    // Delete key
    await this.redisService.delete('key');

    // Delete pattern
    await this.redisService.deletePattern('pattern:*');

    // Check stats
    const stats = this.redisService.getStats();
    console.log(stats);
  }
}
```

## Configuration

Set the following environment variables:

```env
# Required
REDIS_HOST=your-redis-host.com
REDIS_PORT=6379
REDIS_PASSWORD=your-password

# Optional
REDIS_USERNAME=default
REDIS_DATABASE=kushi-redis
REDIS_MAX_RETRIES=3
REDIS_RETRY_DELAY=1000

# Cache TTL settings (omit for indefinite persistence)
REDIS_TTL=3600
AGENT_CACHE_TTL=7200
PROMPT_CACHE_TTL=3600
ANSWER_CACHE_TTL=1800
CHROMADB_CACHE_TTL=3600

# Other settings
CACHE_ENABLED=true
CACHE_MAX_ITEMS=1000
RAG_TIMEOUT_MS=30000
```

## API Reference

### RedisService Methods

- `set(key: string, value: any, ttlSeconds?: number): Promise<boolean>` - Set a value with optional TTL
- `get<T>(key: string): Promise<T | null>` - Get a value
- `delete(key: string): Promise<boolean>` - Delete a key
- `deletePattern(pattern: string): Promise<number>` - Delete keys matching a pattern
- `exists(key: string): Promise<boolean>` - Check if a key exists
- `getStats()` - Get cache statistics
- `ping(): Promise<boolean>` - Check Redis connection
- `flushAll(): Promise<boolean>` - Flush all data (use with caution)

### RedisConfig

The library exports a `redisConfig` function that loads configuration from environment variables.

## License

MIT