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

staleness

v0.1.0

Published

Wrap an async function with stale-while-revalidate caching — serve fresh instantly, serve stale while refreshing once in the background, block only when truly expired. Single-flight, per key.

Readme

staleness

npm version License: MIT

Wrap async functions with stale-while-revalidate caching — serve fresh instantly, serve stale while refreshing once in the background, block only when truly expired. Single-flight, per-key cache for servers and CLIs.

The problem

When cached data expires, every concurrent caller waits for a slow recompute, causing cache stampedes and latency spikes. You want to serve slightly-stale data immediately while refreshing in the background, but only trigger one refresh operation. Existing solutions like swr and react-query focus on React, while lru-cache provides storage without SWR semantics.

Install

npm install staleness
# or
pnpm add staleness
# or
yarn add staleness

Use

import staleness from "staleness";

const cached = staleness(fetchData, {
  ttlMs: 60_000,
  staleMs: 600_000
});

API

staleness(fn, options): Cached

Wrap an async function with stale-while-revalidate caching.

import { staleness } from "staleness";

const cached = staleness(fetchData, {
  ttlMs: 60_000,     // Required: fresh window
  staleMs: 600_000,  // Optional: stale-while-revalidate window (default: Infinity)
  key: (...args) => args[0],  // Optional: custom cache key function
  clock: () => Date.now(),  // Optional: time provider for testing
  onError: (error, key) => console.error(error),  // Optional: background refresh failure handler
  max: 1000,  // Optional: max distinct cache keys with LRU eviction
});

Behavior: Fresh (≤ ttlMs) returns cached immediately; Stale (ttlMs < age ≤ staleMs) returns stale value and triggers background refresh; Expired (> staleMs) blocks and fetches fresh value. Single-flight prevents stampedes.

Cached interface

const result = await cached(arg1, arg2);
cached.invalidate(arg1, arg2);
cached.clear();
console.log(cached.size);

Non-goals

Focuses on core SWR semantics, explicitly avoiding persistence, React bindings, size-based eviction, and distributed caching.

Composition with persistent storage:

import { LRUCache } from "lru-cache";
import staleness from "staleness";

const persistentCache = new LRUCache({ max: 500 });
const cached = staleness(fetchFromAPI, { ttlMs: 60000, staleMs: 600000 });

async function fetch(key: string) {
  if (persistentCache.has(key)) return persistentCache.get(key);
  const value = await cached(key);
  persistentCache.set(key, value);
  return value;
}

TypeScript

Full TypeScript support with strict mode enabled. Type inference works for function arguments:

import staleness from "staleness";

// Types inferred from function signature
const cachedFetch = staleness(async (userId: number, resource: string): Promise<UserData> => {
  return fetch(`/users/${userId}/${resource}`).then(r => r.json());
});

// Fully typed: userId and resource are validated
const data = await cachedFetch(123, "profile");

Related Packages

Caching & Concurrency:

Text Processing:

  • @azghr/shorn — Truncate strings by byte budget without breaking graphemes
  • seriatim — Sequential processing utilities

HTTP & Network:

  • forbear — Read server rate-limit instructions from HTTP responses
  • forestall — Delay execution until a condition is met
  • obviate — Render operations unnecessary through caching

System & Process:

  • quiesce — Ordered, timeboxed graceful shutdown for Node
  • sortition — Deterministic percentage rollouts and A/B bucketing
  • stanch — Stop flows or operations based on conditions

Utilities:

  • expunge — Remove or exclude items from collections
  • occlude — Hide or mask data and functionality
  • placemark — Geographic location and mapping utilities
  • specie — Currency and financial calculations

License

MIT