@suaveplan/idempotency - Idempotency key guard and dedup: store adapters (memory, database, redis), distributed locking, middleware, key generation, metrics, OTel instrumentation.
Summary
Idempotency key guard and deduplication for async operations. The package provides a complete pending → completed | failed state machine, three store backends (memory, database, Redis), distributed locking across multiple processes, request middleware, key generation with payload fingerprinting, version history management, and OTel metrics instrumentation. It is designed to protect any operation that must not execute more than once per request — payment charges, email sends, record creation — regardless of retries or race conditions.
Documentation tree
- distributed-guard — Provides distributed idempotency protection via a pluggable
LockProviderthat serializes concurrent access across mul… - redis-lock-provider — Provides a Redis-backed implementation of the
LockProviderinterface using atomicSET NX(set-if-not-exists) operat… - error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev…- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev…
- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
- errors — (no submodules)
- idempotency-error — (no submodules)
- guard — (no submodules)
- idempotency-guard — (no submodules)
- key — (no submodules)
- key-generator — (no submodules)
- metrics — (no submodules)
- idempotency-metrics — (no submodules)
- middleware — (no submodules)
- idempotency-middleware — (no submodules)
- database-store — Provides a persistent
IdempotencyStoreAdapter<T>backed by any relational database via the `IdempotencyDatabaseAdapte… - memory-store — Provides an in-memory implementation of
IdempotencyStoreAdapter<T>backed by aMap. It is the default store for uni… - redis-store — Provides a Redis-backed
IdempotencyStoreAdapter<T>with automatic key expiration using Redis native TTL. By accepting… - versioning — (no submodules)
- key-versioning — (no submodules)
- memory-store — Provides an in-memory implementation of
IdempotencyStoreAdapter<T>backed by aMap. It is the default store for uni… - redis-store — Provides a Redis-backed
IdempotencyStoreAdapter<T>with automatic key expiration using Redis native TTL. By accepting… - versioning — (no submodules)- key-versioning — (no submodules)- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev… - idempotency-error — (no submodules)- guard — (no submodules)- idempotency-guard — (no submodules)- key — (no submodules)- key-generator — (no submodules)- metrics — (no submodules)- idempotency-metrics — (no submodules)- middleware — (no submodules)- idempotency-middleware — (no submodules)- database-store — Provides a persistent
IdempotencyStoreAdapter<T>backed by any relational database via the `IdempotencyDatabaseAdapte… - memory-store — Provides an in-memory implementation of
IdempotencyStoreAdapter<T>backed by aMap. It is the default store for uni… - redis-store — Provides a Redis-backed
IdempotencyStoreAdapter<T>with automatic key expiration using Redis native TTL. By accepting… - versioning — (no submodules)- key-versioning — (no submodules)- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev… - idempotency-error — (no submodules)- guard — (no submodules)- idempotency-guard — (no submodules)- key — (no submodules)- key-generator — (no submodules)- metrics — (no submodules)- idempotency-metrics — (no submodules)- middleware — (no submodules)- idempotency-middleware — (no submodules)- database-store — Provides a persistent
IdempotencyStoreAdapter<T>backed by any relational database via the `IdempotencyDatabaseAdapte… - memory-store — Provides an in-memory implementation of
IdempotencyStoreAdapter<T>backed by aMap. It is the default store for uni… - redis-store — Provides a Redis-backed
IdempotencyStoreAdapter<T>with automatic key expiration using Redis native TTL. By accepting… - versioning — (no submodules)- key-versioning — (no submodules)- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev… - idempotency-error — (no submodules)- guard — (no submodules) - idempotency-guard — (no submodules)- key — (no submodules) - key-generator — (no submodules)- metrics — (no submodules) - idempotency-metrics — (no submodules)- middleware — (no submodules) - idempotency-middleware — (no submodules)- database-store — Provides a persistent
IdempotencyStoreAdapter<T>backed by any relational database via the `IdempotencyDatabaseAdapte… - memory-store — Provides an in-memory implementation of
IdempotencyStoreAdapter<T>backed by aMap. It is the default store for uni… - redis-store — Provides a Redis-backed
IdempotencyStoreAdapter<T>with automatic key expiration using Redis native TTL. By accepting… - versioning — (no submodules) - key-versioning — (no submodules)- error-codes — Defines and registers all stable error codes and their HTTP/retry metadata for the
@suaveplan/idempotencypackage. Ev…
Install
bun add @suaveplan/idempotency
Quick start
import { IdempotencyGuard } from "@suaveplan/idempotency/guard";
import { MemoryIdempotencyStore } from "@suaveplan/idempotency/store";
const guard = new IdempotencyGuard({
store: new MemoryIdempotencyStore(),
ttlMs: 3_600_000, // 1 hour
});
// First call: executes the handler and caches the result
const result = await guard.execute("order-42", () => createOrder(payload));
// Subsequent calls with the same key: return the cached result immediately
const again = await guard.execute("order-42", () => createOrder(payload));
// result === again — handler was not called again
// With payload fingerprinting and AbortSignal
const controller = new AbortController();
const safe = await guard.execute(
"charge-99",
() => chargeCard(payload),
{ input: payload, signal: controller.signal }
);
Modules
| Module | Description |
|---|---|
| src/guard/idempotency-guard.md | IdempotencyGuard — single-node idempotency guard with full state machine, injectable clock, AbortSignal support, and OTel instrumentation |
| src/distributed/distributed-guard.md | DistributedIdempotencyGuard — multi-node guard backed by a pluggable LockProvider; MemoryLockProvider for tests; RedisLockProvider for production |
| src/distributed/redis-lock-provider.md | RedisLockProvider — Redis-backed distributed lock provider with TTL and exponential back-off |
| src/store/memory-store.md | MemoryIdempotencyStore — in-memory store for tests and single-process deployments; lazy TTL expiration |
| src/store/database-store.md | DatabaseIdempotencyStore — SQL-backed store via a generic IdempotencyDatabaseAdapter; auto-creates table; supports upsert |
| src/store/redis-store.md | RedisIdempotencyStore — Redis-backed store with native key TTL and configurable namespace prefix |
| src/key/key-generator.md | Key generation utilities: generateIdempotencyKey, compositeKey, fingerprintPayload, fingerprintPayloadAsync |
| src/middleware/idempotency-middleware.md | createIdempotencyMiddleware — framework-agnostic middleware factory for Express, Fastify, Hono, or custom request types |
| src/metrics/idempotency-metrics.md | IdempotencyMetrics — aggregate and rolling-window counters, OTel counter/histogram instruments, periodic reporter |
| src/versioning/key-versioning.md | KeyVersioning — multi-version record management with reject, overwrite, and version conflict strategies |
| src/errors/idempotency-error.md | Structured error hierarchy: IdempotencyConflictError, IdempotencyMismatchError, LockAcquisitionError, VersionConflictError |
| src/error-codes.md | Stable IDEMPOTENCY.* error code registry |