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

idempotency-kit

v0.1.1

Published

Idempotency toolkit for Node.js and TypeScript with in-flight request deduplication and TTL response caching.

Readme

idempotency-kit

npm version npm downloads CI license

Traffic Dashboard

GitHub traffic snapshot (rolling window reported by GitHub API).

Totals since 2026-02-12: 0 views and 0 clones.

| Date | Views | Clones | |---|---:|---:| | pending first workflow run | 0 | 0 |

Updated automatically: 2026-02-13T22:10:59.514Z

Local-only idempotency for Node.js/TypeScript.

  • Dedup concurrent executions by key (single in-flight promise).
  • Return the same result on retries while TTL is valid.
  • Optional failed-result memoization (cacheFailures).
  • Abort one caller without canceling shared execution.
  • Zero infra (in-memory only).

Why this library

  • Webhook duplicates.
  • Client retries.
  • Double-submit and double-click actions.
  • Accidental job reprocessing.

Install

npm install idempotency-kit

Quick Start

import { IdempotencyLocal } from "idempotency-kit";

const idem = new IdempotencyLocal({ ttlMs: 30_000 });

const charge = await idem.run("charge:order-123", async () => {
  return { ok: true, chargeId: "ch_1" };
});

API

new IdempotencyLocal(options?)
createIdempotencyLocal(options?)

Main methods

| Method | Return | Description | |---|---|---| | run(key, fn, options?) | Promise<T> | Executes once per key and memoizes result by TTL. | | runWithMeta(key, fn, options?) | Promise<{ value: T; meta: RunMeta }> | Same as run, with resolution metadata. | | delete(key) | boolean | Deletes one cached result key. | | clear() | void | Clears all cached results. | | prune() | number | Removes expired entries and returns removed count. | | getStats() | IdempotencyStats | Read runtime counters and sizes. | | dispose() | void | Disposes internal cache resources. | | size | number | Current result-cache size. |

Constructor options

| Option | Type | Default | Description | |---|---|---|---| | ttlMs | number | 30000 | Success TTL in milliseconds. | | cacheFailures | boolean | false | Cache failed results for dedup/retry behavior. | | failureTtlMs | number | ttlMs | TTL for cached failures. | | maxSize | number | undefined | Max result entries (LRU evicts old entries). | | cleanupIntervalMs | number \\| false | false | Periodic cleanup interval. | | keyPrefix | string | "" | Prefix applied as prefix:key. |

Per-run options

| Option | Type | Description | |---|---|---| | ttlMs | number | Override success TTL for this call. | | cacheFailures | boolean | Override failure caching behavior for this call. | | failureTtlMs | number | Override failure TTL for this call. | | signal | AbortSignal | Cancel only this caller wait. |

runWithMeta statuses

  • hit_completed
  • hit_failed
  • inflight_hit
  • miss_executed
  • miss_executed_failed

Behavior and semantics

run(key, fn) rules:

  1. If completed result is valid, returns it (hit_completed).
  2. If failed result is valid and cacheFailures=true, throws same error (hit_failed).
  3. If key is in-flight, waits on the same promise (inflight_hit).
  4. Otherwise executes fn:
    • success: caches completed result (miss_executed)
    • error: caches failed result only if enabled (miss_executed_failed)

Key normalization:

const finalKey = keyPrefix ? `${keyPrefix}:${key}` : key;

Abort behavior

import { AbortError, IdempotencyLocal, isAbortError } from "idempotency-kit";

const idem = new IdempotencyLocal();
const controller = new AbortController();

const promise = idem.run("job:1", doWork, { signal: controller.signal });
controller.abort();

try {
  await promise;
} catch (error) {
  if (isAbortError(error)) {
    // this caller stopped waiting
  }
}

Aborting one caller does not cancel the shared loader for other callers.

Errors

  • AbortError: thrown when caller signal is aborted.
  • isAbortError(error): type-safe helper.

Stats

getStats() returns:

  • runs
  • hitsCompleted
  • hitsFailed
  • inflightHits
  • missesExecuted
  • missesExecutedFailed
  • abortedWaits
  • size
  • inFlight

Benchmarks

Run:

npm run bench

Included scenarios:

  • Miss path (run with unique key).
  • Hit path (run with warm key).
  • 100 concurrent calls same key (dedup).
  • LRU pressure under maxSize.
  • Expiration cleanup with prune().

See BENCHMARK.md for details.

Latest local run

Date: February 13, 2026
Environment: Windows + Node v22.19.0 + Vitest 3.2.4

| Scenario | Throughput (hz) | |---|---:| | run miss (new key each call) | 672,647.73 | | run hit (same key) | 707,083.15 | | inflight dedup (100 concurrent same key) | 120.37 | | lru pressure (maxSize=1_000, 2_000 inserts) | 544.62 | | prune expired (5_000 keys) | 40.83 |

Quality checks

npm run typecheck
npm test
npm run build

Gotchas

  • Cache is per process; no cross-instance guarantees.
  • undefined return values are cached normally.
  • Default cacheFailures is false.

License

MIT (LICENSE)