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

@setu-ts/cache-plugin

v0.11.0

Published

Cache over memory (LRU), Redis, or noop, with transparent response caching

Readme

@setu-ts/cache-plugin

Caching with pluggable stores. Registers an ICacheStore under CAPABILITIES.CACHE ('cache').

Three stores ship: MemoryStore (LRU with per-entry TTL, zero-dependency default), RedisStore (over ioredis, lazily imported or injected), and NoopStore.

Installation

import { CachePlugin } from '@setu-ts/cache-plugin';

Usage

import { createApplication } from '@setu-ts/kernel';
import { RuntimePlugin } from '@setu-ts/runtime';
import { cacheMiddleware, CachePlugin, CacheService } from '@setu-ts/cache-plugin';
import { CAPABILITIES, type ICacheStore } from '@setu-ts/common';

const app = createApplication({
  plugins: [
    RuntimePlugin(),
    CachePlugin({ store: 'redis', options: { url: 'redis://localhost:6379' } }),
  ],
});
await app.start({ port: 3000 });

const cache = app.services.get<ICacheStore>(CAPABILITIES.CACHE);
await cache.set('user:1', { name: 'Ada' }, 60);
const user = await cache.get<{ name: string }>('user:1');

// CacheService adds coalesced read-through for one cache key.
const readThroughCache = app.services.get<CacheService>(CAPABILITIES.CACHE);
const profile = await readThroughCache.getOrSet(
  'profile:1',
  async () => {
    return await loadProfile('1');
  },
  60,
);

Options

| Option | Type | Default | Description | | ------------- | ------------------------------- | ----------- | ------------------------------------- | | store | 'memory' \| 'redis' \| 'noop' | 'memory' | Backend implementation. | | name | string | 'default' | Instance name for multi-cache setups. | | options | CacheStoreOptions | — | Store-specific configuration. | | diagnostics | CacheDiagnosticsOptions | — | Opt-in operation counters (M98i). |

With store: 'redis', connection errors of the ioredis client the store builds go to the application logger — the first error of an outage at warn, identical repeats at debug, the recovery at info — instead of ioredis printing every reconnect failure to console.error. An injected client gets no listener: it belongs to the caller.

node-redis. To use node-redis instead of ioredis, pass options: { client: fromNodeRedis(createClient({ url })) } (fromNodeRedis from @setu-ts/common, createClient from redis, installed in your application). The adapter bounds its own commands (fromNodeRedis(client, { commandTimeoutMs })); this store's commandTimeoutMs applies only to the client it builds. See Using node-redis.

options.commandTimeoutMs (Redis only, default 15000, 0 disables) bounds each command on the client the store builds. A paused or partitioned server keeps its socket open, so without the bound a cache call waits forever; with it the call rejects and the diagnostics count it failed. (The cache health indicator reports such a server down on its own, independent of this option: its ping() probe has a fixed 2-second bound.) It is not applied to an injected client, and a value outside 0–2147483647 throws RangeError when CachePlugin(...) is called.

A name other than 'default' derives the capability token as cache.<name>, so several caches can coexist in one application.

Diagnostics (M98i)

CachePlugin({ diagnostics: { enabled: true, alias: 'primary' } }) counts every backend call this instance's own CacheService makes (get, set, delete, has, clear; getOrSet counts as its internal get/set) — succeeded, failed, hits, misses, present/absent and removed/notRemoved — for the local diagnostics connector's GET /v1/cache (@setu-ts/diagnostics-plugin). Keys, prefixes, values, Redis URLs, factory results and errors are never captured, and no eviction is inferred. Without the option the instance registers an inert disabled source and its cache calls are not touched. Results, errors, TTL, prefix and getOrSet coalescing are identical either way; enabled calls add one clock read (two on the timed one-in-eight sample) and one derived promise each (which re-rejects with the original reason, so an unhandled rejection stays unhandled), measured at about 5% of throughput against a real Redis at 50 concurrent calls. Direct store calls and a replacement service are outside coverage. Enable only on an approved development dataset: counts aggregate every tenant using the instance.

Response caching

cacheMiddleware(options) transparently caches responses. Streaming responses are skipped — a live ReadableStream cannot be replayed from a cache, so those requests are marked X-Cache: MISS and pass straight through.

Concurrent misses for the same key are coalesced within one process: one request reaches a cacheable, buffered origin response and waiters replay it with X-Cache: COALESCED. A failed, streaming, or otherwise uncacheable leader is not replayed; every waiter runs the origin itself. Separate processes do not coordinate, so one overlapping successful batch can produce at most one origin call per process. CacheService.getOrSet() applies the same per-store coalescing to programmatic read-through calls.

Exports

| Export | Kind | | ---------------------------- | --------- | | cacheMiddleware | function | | CachePlugin | function | | CacheService | class | | CacheStoreUnavailableError | class | | MemoryStore | class | | NoopStore | class | | RedisStore | class | | CacheDiagnosticsOptions | interface | | CachedResponsePayload | interface | | CacheMiddlewareOptions | interface | | CachePluginOptions | interface | | CacheStoreOptions | interface | | ICacheStore | interface | | IRedisClient | interface | | CacheStoreType | type |

Generated from the package barrel by pnpm run docs:exports; pnpm run check:docs fails when it drifts.

Full API

Every export and option is documented in PUBLIC_API.md.

Readiness and dependency outages (M113b)

RedisStore.get/set/delete/has/clear wrap recognised connection faults in CacheStoreUnavailableError, preserving the original as cause. With the exceptions errorHandler, this returns 503 and the fixed detail The cache is temporarily unavailable. Other errors propagate unchanged. Inspect cause for driver diagnostics.