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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@siddharth-karna/kangaroo

v1.0.5

Published

A smart, type-safe, and hassle-free Redis caching wrapper for Node.js applications.

Readme

🦘 Kangaroo

Fast like the Kangaroo way, easy like the Kangaroo jump.

A smart, type-safe, and hassle-free Redis caching wrapper for Node.js / TypeScript.

Stop writing the same Redis boilerplate over and over. Kangaroo provides a strictly typed CacheBucket that magically handles object-key hashing, JSON serialization, and read-through caching so you can focus on building your app.

Why use Kangaroo?

  • 🛡️ End-to-End Type Safety: Define exact types for your cache keys AND values. No more any or JSON.parse(string) guesswork.
  • 🗂️ Bucket Namespacing: Pass a prefix to your buckets (e.g. createCacheBucket("users")). Kangaroo isolates your keys behind the scenes so an {id: 1} key in the users bucket doesn't collide with an {id: 1} key in your products bucket!
  • 🔑 Smart Object Hashing: Uses fast-json-stable-stringify under the hood. You can use full Javascript objects as cache keys (e.g. bucket.get({ id: 1, type: "user" })), and Kangaroo will securely and deterministically hash them so key order doesn't matter!
  • 🔄 Read-Through Caching: The magical .wrap() method automatically checks the cache. If it misses, it automatically runs your fallback database query, saves the result to Redis for you, and returns the data.
  • Lightweight: Built on top of the battle-tested ioredis library.

Installation

npm i @siddharth-karna/kangaroo
pnpm i @siddharth-karna/kangaroo
yarn add @siddharth-karna/kangaroo
bun add @siddharth-karna/kangaroo

Real-Life Quick Start: E-Commerce Product Caching

Instead of limiting yourself to string keys, Kangaroo lets you use complex query objects as cache keys, and caches back the exact response type. Here is how you can cache an e-commerce search with multiple filters!

import { Kangaroo } from "kangaroo";
import Redis from "ioredis";

// 1. Initialize standard ioredis connection
const redis = new Redis("redis://localhost:6379");

// 2. Pass it to Kangaroo
const cache = new Kangaroo(redis);

// Types for our real-world use case
type ProductSearchFilters = { category: string; minPrice: number; maxPrice: number; inStockOnly: boolean };
type ProductSearchResult = { products: { id: string; name: string; price: number }[]; totalFound: number };

// 3. Create a bucket. Give it a namespace ("product-search"), and fully type the Key and Value!
const productSearchBucket = cache.createCacheBucket<ProductSearchFilters, ProductSearchResult>("product-search");

async function searchProducts(filters: ProductSearchFilters) {
    // 4. Wrap automatically checks Redis using the object key!
    return await productSearchBucket.wrap({
        key: filters,
        timePeriod: 300, // Cache for 5 minutes
        whatIf: async () => {
            console.log("⚠️ Cache miss! Querying expensive database operation...");
            
            // Simulating an expensive DB query using the filters object
            // const dbResults = await db.query('...', filters);
            
            return {
                products: [
                    { id: "p_1", name: "Wireless Headphones", price: 99.99 },
                    { id: "p_2", name: "Bluetooth Speaker", price: 59.99 }
                ],
                totalFound: 2
            };
        }
    });
}

async function run() {
    const userFilters = { category: "audio", minPrice: 50, maxPrice: 150, inStockOnly: true };

    // First call: Runs the `whatIf` database query
    const results1 = await searchProducts(userFilters);

    // Second call: Instantly returns from Redis! It hashes the object deterministically.
    const results2 = await searchProducts({ 
        inStockOnly: true, 
        maxPrice: 150, 
        category: "audio", 
        minPrice: 50 
    }); // Property order doesn't matter!

    console.log(`Found ${results2.totalFound} products.`);
}

run();

Ready for more? Check out the Examples Guide to see how to use complex objects as keys and leverage .wrap() in real-world scenarios.