@idempotix/core
v1.0.0
Published
Idempotency engine for HTTP APIs - ensures operations execute exactly once
Maintainers
Readme
@idempotix/core
Core idempotency library with memory storage. The foundation for all Idempotix packages.
Installation
npm install @idempotix/coreQuick Start
import { MemoryStorage, hashObject, parseTtl } from '@idempotix/core';
const storage = new MemoryStorage();
// Acquire a lock for a request
const result = await storage.acquire('request-key', hashObject(body), parseTtl('1h'));
if (result.status === 'acquired') {
// Execute the operation
const response = await processRequest(body);
// Save the response
await storage.save('request-key', {
data: response,
createdAt: Date.now(),
hash: hashObject(body),
});
}
if (result.status === 'hit') {
// Return cached response
return result.response.data;
}Storage Adapter
MemoryStorage is the default adapter, ideal for:
- Development and testing
- Single-instance deployments
- Prototyping
For production multi-instance deployments, use:
- @idempotix/redis - Standard Redis
- @idempotix/upstash - Serverless Redis
StorageAdapter Interface
interface StorageAdapter {
acquire(key: string, hash: string | null, ttl: number): Promise<AcquireResult>;
save(key: string, response: StoredResponse): Promise<void>;
release(key: string): Promise<void>;
delete(key: string): Promise<void>;
clear(): Promise<void>;
}
type AcquireResult =
| { status: 'acquired' }
| { status: 'hit'; response: StoredResponse }
| { status: 'conflict'; startedAt: number }
| { status: 'mismatch'; existingHash: string; providedHash: string };Utilities
Hash Objects
import { hashObject } from '@idempotix/core';
const hash = hashObject({ amount: 100, currency: 'USD' });
// => 'a1b2c3d4...'Parse TTL
import { parseTtl } from '@idempotix/core';
parseTtl('1h'); // 3600000
parseTtl('30m'); // 1800000
parseTtl('5s'); // 5000
parseTtl('1d'); // 86400000
parseTtl(60000); // 60000Error Classes
import {
IdempotencyError,
MissingKeyError, // 400 - Key required but missing
ConflictError, // 409 - Request in progress
MismatchError, // 422 - Key reused with different body
} from '@idempotix/core';All errors extend IdempotencyError and include:
statusCode- HTTP status codetoProblemDetails()- RFC 7807 Problem Details
Constants
import { IDEMPOTENCY_KEY_HEADER, IDEMPOTENCY_REPLAY_HEADER } from '@idempotix/core';
IDEMPOTENCY_KEY_HEADER; // 'Idempotency-Key'
IDEMPOTENCY_REPLAY_HEADER; // 'Idempotency-Replay'Testing Utilities
import { createTestStorage, MockStorage } from '@idempotix/core/testing';
// Create a test storage with optional pre-seeded data
const storage = createTestStorage({
'existing-key': { data: { id: 1 }, createdAt: Date.now(), hash: null },
});
// Or use MockStorage for fine-grained control
const mock = new MockStorage();
mock.simulateConflict('key');
mock.simulateError(new Error('Connection failed'));Related Packages
- @idempotix/express - Express middleware
- @idempotix/next - Next.js integration
- @idempotix/client - Client utilities
- @idempotix/redis - Redis adapter
- @idempotix/upstash - Upstash adapter
License
MIT
