Skip to content

Subhajit1993/turbocache-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

TurboCache-JS πŸš€

High-performance, intelligent caching library for TypeScript/NestJS microservices

npm version License: MIT TypeScript

TurboCache-JS is a production-ready caching abstraction layer that brings Spring Cache-like decorators to the TypeScript/NestJS ecosystem. Built on top of battle-tested libraries like Keyv and Cacheable, it provides intelligent caching strategies, multi-tier support, and seamless microservices integration.


✨ Features

  • 🎯 Decorator-Based API - Clean, declarative caching with @TurboCache, @TurboCacheEvict, @TurboCachePut
  • 🏭️ NestJS First - Deep integration with dependency injection and module system
  • πŸ”Œ Multiple Adapters - Redis, Memory, MongoDB, PostgreSQL, or custom backends
  • 🌐 Microservices Ready - Distributed cache coordination and cross-service invalidation
  • πŸ“Š Multi-Tier Caching - L1 (memory) + L2 (distributed) for optimal performance
  • πŸ”₯ Cache Warming - Pre-load hot data on startup, scheduled refresh, predictive warming
  • πŸ” Type-Safe - Full TypeScript support with strict typing
  • πŸ“ˆ Observable - Built-in metrics, logging, and health checks
  • ⚑ High Performance - <5ms read latency, 100k+ ops/sec
  • πŸ›‘οΈ Production Ready - Stampede prevention, compression, encryption
  • 🎨 Flexible - Works standalone or with NestJS

πŸ“¦ Installation

npm i @brewedbytes/turbocache-js

πŸš€ Quick Start

Basic Usage

import { TurboCache } from 'turbocache-js';

class UserService {
  @TurboCache({ key: 'user:#{id}', ttl: 3600 })
  async getUser(id: string) {
    return await db.users.findOne({ id });
  }
}

NestJS Integration

// app.module.ts
import { TurboCacheModule } from 'turbocache-js';

@Module({
  imports: [
    TurboCacheModule.register({
      stores: [
        {
          name: 'default',
          type: 'redis',
          primary: {
            type: 'redis',
            uri: 'redis://localhost:6379'
          },
          ttl: 3600
        }
      ],
      namespace: 'myapp'
    })
  ]
})
export class AppModule {}

// user.service.ts
@Injectable()
export class UserService {
  constructor(
    @InjectCache() private cache: CacheManager,
    private userRepo: UserRepository
  ) {}
  
  @TurboCache({ key: 'user:#{id}' })
  async findById(id: string): Promise<User> {
    return this.userRepo.findById(id);
  }
  
  @TurboCacheEvict({ key: 'user:#{id}' })
  async update(id: string, data: UpdateUserDto) {
    return this.userRepo.update(id, data);
  }
}

πŸ“š Core Concepts

Decorators

@TurboCache

Automatically cache method results:

@TurboCache({
  key: 'product:#{id}',
  ttl: 3600,
  condition: (result) => result !== null
})
async getProduct(id: string): Promise<Product> {
  return await this.productRepo.findById(id);
}

@TurboCacheEvict

Invalidate cache on mutations:

@TurboCacheEvict({ 
  key: 'user:#{id}',
  allEntries: false 
})
async deleteUser(id: string): Promise<void> {
  await this.userRepo.delete(id);
}

@TurboCachePut

Update cache without preventing execution:

@TurboCachePut({ key: 'user:#{result.id}' })
async createUser(data: CreateUserDto): Promise<User> {
  return await this.userRepo.create(data);
}

Multi-Tier Caching

Combine local memory with distributed cache:

TurboCacheModule.register({
  stores: [
    {
      name: 'multi-tier',
      type: 'multi-tier',
      primary: {
        type: 'memory',
        options: { max: 1000 },
        ttl: 300
      },
      secondary: {
        type: 'redis',
        uri: 'redis://localhost:6379',
        ttl: 3600
      }
    }
  ]
})

Key Expressions

Dynamic key generation with expressions:

// Simple parameter
@TurboCache({ key: 'user:#{id}' })

// Object property
@TurboCache({ key: 'order:#{order.id}:#{order.status}' })

// Multiple parameters
@TurboCache({ key: 'search:#{category}:#{page}' })

🎯 Use Cases

API Response Caching

@Controller('products')
export class ProductController {
  @Get(':id')
  @TurboCache({ key: 'product:#{params.id}', ttl: 3600 })
  async getProduct(@Param('id') id: string) {
    return this.productService.findById(id);
  }
}

Database Query Caching

@TurboCache({ key: 'users:active', ttl: 600 })
async getActiveUsers(): Promise<User[]> {
  return this.db.users.find({ status: 'active' });
}

Expensive Computation

@TurboCache({ 
  key: 'report:#{month}',
  ttl: 86400, // 24 hours
  stampedeLock: true 
})
async generateMonthlyReport(month: string) {
  return this.heavyComputation(month);
}

Microservices Cache Sync

// Service A
@TurboCacheEvict({ key: 'inventory:#{productId}' })
async updateInventory(productId: string, quantity: number) {
  await this.repo.update(productId, quantity);
  await this.eventBus.emit('inventory.updated', { productId });
}

// Service B listens and invalidates its cache
this.eventBus.on('inventory.updated', async ({ productId }) => {
  await this.cache.delete(`inventory:${productId}`);
});

πŸ“– Documentation


πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚        Application Layer                β”‚
β”‚    (Controllers, Services, Resolvers)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Decorator Layer                    β”‚
β”‚  @Cacheable  @CacheEvict  @CachePut    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Cache Manager (Core)               β”‚
β”‚  Strategy | Keys | TTL | Serialization  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Adapter Layer                      β”‚
β”‚   Keyv | Cacheable | Multi-Tier        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Storage Backends                   β”‚
β”‚  Redis | Memory | MongoDB | PostgreSQL  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚑ Performance

  • Read Latency: <5ms (memory), <10ms (Redis)
  • Throughput: 100,000+ operations/sec
  • Memory Overhead: <100MB for typical workloads
  • Cache Hit Rate: 85-95% in production

πŸ› οΈ Configuration

Environment-Based Config

TurboCacheModule.registerAsync({
  imports: [ConfigModule],
  useFactory: (config: ConfigService) => ({
    stores: [{
      name: 'default',
      type: 'redis',
      primary: {
        type: 'redis',
        uri: config.get('REDIS_URL')
      },
      ttl: config.get('CACHE_TTL', 3600)
    }],
    namespace: config.get('APP_NAME'),
    enableMetrics: config.get('ENABLE_METRICS', true),
    compression: {
      enabled: config.get('CACHE_COMPRESSION', false),
      threshold: 1024
    }
  }),
  inject: [ConfigService]
})

πŸ§ͺ Testing

describe('UserService', () => {
  let service: UserService;
  let cache: CacheManager;
  
  beforeEach(async () => {
    const module = await Test.createTestingModule({
      imports: [
        TurboCacheModule.register({
          stores: [{ 
            name: 'default', 
            type: 'memory',
            primary: { type: 'memory' }
          }]
        })
      ],
      providers: [UserService]
    }).compile();
    
    service = module.get(UserService);
    cache = module.get('CACHE_MANAGER');
  });
  
  it('should cache user data', async () => {
    const user = await service.findById('123');
    const cached = await cache.get('user:123');
    expect(cached).toEqual(user);
  });
});

πŸ“ž Support


Made with ❀️ by the platform engineering team

About

Next level caching for TS and NestJS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published