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

@ferrow/cache-strategies

v2.0.0

Published

LRU, LFU, and TTL in-memory cache implementations sharing one interface, each tracking hits/misses/evictions. LRU correctly refreshes recency on get(). Zero runtime dependencies.

Readme

cache-strategies

CI

Three in-memory cache implementations for TypeScript/Node — LRUCache, LFUCache, TTLCache — sharing one Cache<T> interface, each tracking hits/misses/evictions. Zero runtime dependencies, no Redis or other backing store.

An earlier version of LRUCache in this repo had a real bug: get() never refreshed an entry's recency, so eviction was actually by insertion order, not access order. This version fixes it — get() and set() both move a key to the most-recently-used end via the Map delete+re-insert pattern (Map iterates in insertion order, so re-inserting moves a key to the end).

Install

Copy src/index.ts into your project, or build this repo (npm run build) and depend on the compiled dist/.

Quickstart

import { LRUCache, LFUCache, TTLCache } from 'cache-strategies';

const lru = new LRUCache<string>({ maxSize: 100 });
lru.set('key', 'value');
lru.get('key'); // refreshes recency — 'key' won't be the next eviction target

const lfu = new LFUCache<string>({ maxSize: 100 });
// evicts the least-frequently-accessed entry when full

const ttl = new TTLCache<string>({ ttlMs: 60_000, sweepIntervalMs: 30_000 });
// entries expire lazily on get()/has(); sweepIntervalMs is optional
// proactive cleanup for entries that are set and never read again

API

All three implement:

interface Cache<T> {
  get(key: string): T | undefined;
  set(key: string, value: T): void;
  has(key: string): boolean;
  delete(key: string): boolean;
  clear(): void;
  readonly size: number;
  stats(): { hits: number; misses: number; evictions: number; size: number };
}
  • LRUCache<T>({ maxSize }) — evicts the least-recently-used entry (by both get and set) once size > maxSize.
  • LFUCache<T>({ maxSize }) — evicts the least-frequently-accessed entry once full, using O(1) frequency buckets (no full scan per eviction). Ties within the lowest frequency bucket evict in insertion order.
  • TTLCache<T>({ ttlMs, sweepIntervalMs? }) — every entry expires ttlMs after being set (or pass a per-key set(key, value, ttlMs) to override). Expiry is checked lazily on get()/has(), so a TTLCache with no sweep interval never leaks memory as long as you eventually read every key. sweepIntervalMs adds a background timer (created with .unref(), so it never keeps a Node process alive by itself) that proactively removes expired entries even if they're never read again; call .stopSweep() to cancel it.

Scope and limits

  • In-memory only — no persistence, no distributed/Redis backing.
  • LFUCache breaks ties within a frequency by insertion order, not by recency — it is not an LFU+LRU hybrid.
  • TTLCache expiry is wall-clock (Date.now()), not monotonic — system clock changes affect it.
  • No max-memory-bytes bound on any cache; maxSize/no bound is by entry count only.

Sponsored by Ferrow


Part of the ferrow-toolkit collection · Sponsored by Ferrow