npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@origins-digital/cacheable

v2.2.0

Published

cacheable package

Downloads

417

Readme

@origins-digital/cacheable

A powerful caching package for NestJS applications that provides decorators for Redis-based caching with automatic cache invalidation and key management.

Installation

npm install @origins-digital/cacheable

Features

  • Redis-based caching with decorators
  • Automatic cache key generation
  • Cache invalidation support
  • TTL (Time To Live) configuration
  • Raw and formatted cache responses
  • Context-aware caching
  • Cache hit/miss tracking
  • Automatic cache status headers
  • Response transformation

Usage

Basic Setup

First, configure the Redis connection and response transformation in your module:

import { Module } from '@nestjs/common';
import { CacheableModule } from '@origins-digital/cacheable';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { ResponseTransformInterceptor } from '@origins-digital/cacheable';

@Module({
  imports: [
    CacheableModule.forRoot({
      host: 'localhost',
      port: 6379,
      // Optional Redis configuration
      // password: 'your-password',
      // db: 0,
    }),
  ],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseTransformInterceptor,
    },
  ],
})
export class AppModule {}

Using ResponseTransformInterceptor

The ResponseTransformInterceptor automatically transforms responses and adds cache headers:

import { Controller, Get } from '@nestjs/common';
import { Cacheable } from '@origins-digital/cacheable';
import { GenericOutput } from '@origins-digital/cacheable';

@Controller('users')
export class UserController {
  @Get(':id')
  @Cacheable({
    key: 'user:{id}',
    raw: false,
  })
  async getUser(@Param('id') id: string) {
    const user = await this.userService.findById(id);
    return new GenericOutput(user);
  }

  @Get()
  @Cacheable({
    key: 'users:active',
    ttlSeconds: 300,
    raw: false,
  })
  async getActiveUsers() {
    const users = await this.userService.findActive();
    return new GenericOutput(users);
  }
}

With the interceptor in place, responses will be automatically transformed:

// Example response for GET /users/123
{
  "data": {
    "id": "123",
    "name": "John Doe",
    "email": "[email protected]"
  },
  "metadata": {
    "cache": "hit" // or "miss", "set", "no-cache"
  }
}

// Example response for GET /users
{
  "data": [
    {
      "id": "123",
      "name": "John Doe",
      "email": "[email protected]"
    },
    {
      "id": "124",
      "name": "Jane Doe",
      "email": "[email protected]"
    }
  ],
  "metadata": {
    "cache": "miss",
    "count": 2
  }
}

The interceptor will also add the X-Redis-Cache header to all responses.

Using Cacheable Decorator

The @Cacheable decorator checks for cached results and sets cache if not found:

import { Injectable } from '@nestjs/common';
import { Cacheable } from '@origins-digital/cacheable';

@Injectable()
export class UserService {
  @Cacheable({
    key: 'user:{id}',
    ttlSeconds: 3600, // Cache for 1 hour
  })
  async getUser(id: string) {
    // This will only execute if the cache miss
    return this.userRepository.findById(id);
  }
}

Using CacheGet Decorator

The @CacheGet decorator only checks for cached results without setting cache:

import { Injectable } from '@nestjs/common';
import { CacheGet } from '@origins-digital/cacheable';

@Injectable()
export class ProductService {
  @CacheGet({
    key: 'product:{id}',
  })
  async getProduct(id: string) {
    // This will execute on cache miss
    return this.productRepository.findById(id);
  }
}

Using CacheClear Decorator

The @CacheClear decorator invalidates cache entries:

import { Injectable } from '@nestjs/common';
import { CacheClear } from '@origins-digital/cacheable';

@Injectable()
export class UserService {
  @CacheClear({
    key: 'user:{id}',
  })
  async updateUser(id: string, data: any) {
    // This will clear the cache for this user
    return this.userRepository.update(id, data);
  }
}

Cache Options

All decorators accept options for fine-tuning cache behavior:

interface CacheOptions {
  key?: string; // Cache key pattern
  ttlSeconds?: number; // Time to live in seconds
  excludeContext?: boolean; // Exclude method context from key
  forceOne?: boolean; // Force single item from array
  raw?: boolean; // Return raw data without metadata
}

Cache Response Format

By default, cache responses include metadata:

interface CacheResult {
  $fromCache: 'hit' | 'miss' | 'set';
  $responseBody: any;
}

Using GenericOutput

To get a properly typed response, you can use the GenericOutput utility:

import { Injectable } from '@nestjs/common';
import { Cacheable, GenericOutput } from '@origins-digital/cacheable';

interface User {
  id: string;
  name: string;
  email: string;
}

@Injectable()
export class UserService {
  @Cacheable({
    key: 'user:{id}',
    ttlSeconds: 3600,
  })
  async getUser(id: string): Promise<GenericOutput<User>> {
    const user = await this.userRepository.findById(id);
  }
}

// Usage
const result = await userService.getUser('123');
const userData = GenericOutput.data(user); // Get the actual user data
const isFromCache = GenericOutput.fromCache(user); // Check if data came from cache
const isCacheable = GenericOutput.cacheable(user); // Check the cache status: hit, miss, no-cache, set

Raw vs Non-Raw Usage Patterns

The raw option should be used differently depending on where the decorator is applied:

Service Level (raw: true)

When using @Cacheable at the service level, set raw: true to get the data directly:

@Injectable()
export class UserService {
  @Cacheable({
    key: 'user:{id}',
    raw: true, // Get data directly at service level
  })
  async getUser(id: string): Promise<User> {
    return this.userRepository.findById(id);
  }
}

Controller Level (raw: false)

When using @Cacheable at the controller level, keep raw: false to enable cache status headers:

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get(':id')
  @Cacheable({
    key: 'user:{id}',
    raw: false, // Keep metadata for headers
  })
  async getUser(@Param('id') id: string): Promise<CacheResult<User>> {
    return this.userService.getUser(id);
  }
}

The cache status will be automatically added to the response headers:

  • X-Redis-Cache: hit - Data was found in cache
  • X-Redis-Cache: miss - Data was not in cache
  • X-Redis-Cache: set - Data was set in cache
  • X-Redis-Cache: no-cache - Cache was not used

Advanced Examples

Using forceOne and raw options

import { Injectable } from '@nestjs/common';
import { Cacheable } from '@origins-digital/cacheable';

@Injectable()
export class UserService {
  // This will return a single user from cache or database
  @Cacheable({
    key: 'user:{id}',
    forceOne: true, // If the result is an array, return only the first item
    raw: true, // Return only the data without metadata
  })
  async getUser(id: string): Promise<User> {
    return this.userRepository.findById(id);
  }

  // This will return a list of users with metadata
  @Cacheable({
    key: 'users:active',
    ttlSeconds: 300,
  })
  async getActiveUsers(): Promise<CacheResult<User[]>> {
    return this.userRepository.findActive();
  }
}

// Usage
const user = await userService.getUser('123'); // Returns User directly
const activeUsers = await userService.getActiveUsers(); // Returns CacheResult<User[]>

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.