Build resilient Node.js and LLM applications. One composable TypeScript API.
Compose retry, timeout, circuit breaking, bulkheads, rate limiting, fallback, cache, deduplication, and hedging into one predictable pipeline — then put that same pipeline in front of LLM generation and streaming, with provider adapters, budget protection, typed events, and metrics.
Public Beta 1 — APIs may still change before the stable release.
SIMPLIFIED REQUEST PATH
Response
Why developers choose Resili
Resili brings reliability controls, request optimization, cancellation, and observability into one typed execution model.
One composable API
A policy wraps an async function, not a request object — so the same configuration protects an HTTP call, a database query, an SDK call, or an LLM generation.
TypeScript-first
Operation arguments and result types flow through the client. Invalid configuration throws at build time rather than degrading silently.
Predictable policy ordering
Built-in policies execute through a defined canonical pipeline, and ordering is configurable with relative anchors.
Native cancellation primitives
Cancellation is a standard AbortSignal. In a core execution the caller signal and per-attempt timeouts compose into the one signal your operation receives.
Observable and private
Typed events and metric instruments expose policy and LLM behaviour. No outbound telemetry, and no prompts, generated text, or credentials in any payload.
Lightweight core
@resili/core has zero runtime dependencies. Transport and vendor code stays in adapter packages you opt into.
Production failures are the ones you didn't plan for.
Every service reimplements retry logic. Every team learns the hard way about cascade failures, thundering herds, and cascading timeouts. LLM providers add rate limits, long tail latency, and a bill that grows with every retry. The result is inconsistency, incidents, and engineering hours spent on undifferentiated work.
Scattered retry logic
Copy-pasted across every service, with subtle differences that cause production incidents.
Cascade failures
One slow dependency brings down the entire system when there's no circuit breaker.
Thundering herds
Retries overwhelm a recovering service. No bulkheads, no rate limits, no deduplication.
Zero observability
You find out about resilience issues — and about what a retry loop cost you — through user reports, not typed events or metrics.
Fluent. Typed.
Predictable.
Resili applies policies through a predictable canonical pipeline. Every execution is typed, every event is observable, and every policy boundary is explicit.
- Full TypeScript generics — result types flow through the entire pipeline
- Core executions compose a caller signal with each attempt timeout
- Typed lifecycle events for retries, circuit state changes, and cache hits
- Thin wrappers for Fetch, Axios, and Undici — caller AbortSignal composes with timeout and retry
- Custom policies and plugins through definePolicy and definePlugin
Caller AbortSignal cancellation composes with Resili timeout and retry behavior across Fetch, Axios, and Undici. LLM provider adapters also forward a caller signal to the SDK.
import { resili } from "@resili/core";
const payments = resili(async (paymentId: string) => {
const response = await fetch(
`https://api.example.com/payments/${paymentId}`
);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json() as Promise<{
id: string;
status: string;
}>;
})
.cache({
key: (paymentId) => paymentId,
ttl: 5_000,
})
.retry({
maxAttempts: 3,
backoff: "exponential",
jitter: "none",
})
.circuitBreaker({
minimumThroughput: 10,
})
.timeout({
perAttemptMs: 1_000,
})
.dedupe({
key: (paymentId) => paymentId,
})
.hedge({
delay: 150,
})
.build();
const payment = await payments.call("payment-42");
Predictable Order of Execution
Resili executes policies in a deterministic order across all client wrappers to protect local and downstream resources safely. Only the policies you configure are installed. With @resili/llm, Budget Guard registers just before retry, so one reservation covers the whole logical request.
Built for asynchronous Node.js workloads
Every resilience pattern, ready to compose.
Nine policies that compose into a single deterministic execution pipeline. A policy is installed only when you configure it, and the same nine protect a fetch call, an SDK call, a queue publish, or an LLM generation. No magic, no surprises.
Retry
Retry transient failures with bounded attempts and configurable backoff.
Timeout
Give each attempt a strict time budget through AbortSignal-aware cancellation.
Circuit Breaker
Stop repeatedly calling an unhealthy dependency and probe its recovery.
Bulkhead
Limit concurrent executions and queue depth to protect local resources.
Rate Limiter
Control request throughput using token-bucket or sliding-window strategies.
Fallback
Return an alternative result when configured failures reach the fallback boundary.
Hedged Requests
Start one delayed backup execution to reduce long-tail latency for safe operations.
Request Deduplication
Share one in-flight execution across concurrent callers with the same key.
Memory Cache
Store successful results in a bounded per-client cache with configurable TTL.
Resilience for LLM workloads.
Bring retries, timeouts, streaming, usage tracking, and budget control to OpenAI, Anthropic, and Google Gemini through the same Resili execution model. Public Beta — @resili/llm performs no network I/O and never constructs a vendor client. You own the SDK and the credentials.
LLM REQUEST PATH
Your client
Streaming
Pull-through streaming with consumer-driven backpressure. Retry is allowed before the first delivered non-empty text delta. After visible text has committed, Resili does not start another provider generation.
Safe retries
Provider SDK retries are disabled so Resili owns retry behaviour. OpenAI and Anthropic use maxRetries: 0. Gemini uses HTTP attempts: 1.
Budget Guard
Estimated cost is reserved before execution and settled against provider-reported usage. Pricing is caller-supplied. Accounting is process-local — not distributed.
Usage & cost
Provider token counts are normalized to input, output, and total. Cost is calculated in integer micro-USD when you supply a price table. Resili hard-codes no vendor prices.
Timeouts & cancellation
A per-attempt timeout covers the full streaming attempt, including time between pulls. Before commit, a timeout may retry. After commit, no second generation is started — the error is classification: "timeout", retryable: false. A caller AbortSignal reaches the provider SDK; cancellation never retries.
Observability
Typed LlmStreamStarted, LlmStreamCompleted, and LlmStreamFailed events. Prompts, completions, and raw chunks are never placed on the event bus or in metrics.
Three adapters. You construct the client.
Each adapter maps a vendor SDK you already own onto generate() and stream(). No Responses API, tools, multimodal APIs, or distributed budgets in this beta.
OpenAI
@resili/llm-openai · 0.1.0-beta.1. Chat Completions, generate() and stream(), usage mapping, and AbortSignal into the SDK. maxRetries: 0.
Anthropic
@resili/llm-anthropic · 0.1.0-beta.1. Messages API, generate() and stream(), partial streaming usage merge, and AbortSignal into the SDK. maxRetries: 0.
Google Gemini
@resili/llm-gemini · 0.1.0-beta.1. generateContent and generateContentStream via @google/genai, usage mapping, abortSignal, and cumulative snapshot de-duplication. HTTP attempts: 1.
One stream,
one generation.
Retries may occur before the first non-empty text delta is delivered to your loop. Once visible text has been committed to the consumer, Resili will not start another provider generation for a retryable failure or a timeout — so a stream is never two answers concatenated into one.
- Retries only before the first non-empty text delta is delivered
- After delivery, no second provider generation is started
- A post-commit timeout surfaces as a non-retryable LLM timeout error
- Cancellation never retries, before or after that point
- One budget reservation per request, settled against actual usage
Behaviour shipped in @resili/llm 0.1.0-beta.1. Read the streaming guide for the full retry and timeout matrix.
import OpenAI from "openai";
import { createLlmClient } from "@resili/llm";
import { createOpenAiProvider } from "@resili/llm-openai";
const llm = createLlmClient({
provider: createOpenAiProvider({
client: new OpenAI(),
}),
model: "gpt-4.1-mini",
timeout: { perAttemptMs: 60_000 },
retry: {
maxAttempts: 3,
backoff: "exponential",
baseDelayMs: 500,
jitter: "none",
},
});
const stream = llm.stream({
input: "Explain backpressure in one sentence.",
});
for await (const event of stream) {
if (event.type === "text-delta") {
process.stdout.write(event.text);
}
}
// Usage after the stream closes. Cost is present if a price table was configured.
const { usage, cost } = await stream.result();
Built as a monorepo.
Ship only what you need.
Eight npm packages across two independently versioned lines. Core and HTTP are at 0.2.0-beta.1; the LLM line is at 0.1.0-beta.1. Plain npm install resolves to Beta 1 on latest; the @beta tag is also available. Historical @alpha builds remain published.
Quality is the foundation, not an afterthought.
Releases are cut from main only after linting, formatting, strict TypeScript checks, the full test suite, workspace builds, and the API report check pass — then verified against the public npm registry in a clean consumer project.
Where the project is today
Two independently versioned lines. Public Alpha is historical; Beta 1 is current on latest and beta. Stable is not scheduled — no date.
Public Beta 1
- Nine core policies and HTTP adapters with caller cancellation
- LLM foundation, OpenAI, Anthropic, Gemini
- Pull-through streaming and Budget Guard
- 641 tests, Node 20 & 22, ESM and CommonJS
- Primary APIs reviewed for Beta freeze — still may change before stable
Toward stable
- Further beta hardening
- Real-world feedback and interaction testing
- Documentation and compatibility review
- TTFB / idle timeout exploration
- Under consideration — none committed
Stable v1.0
- Stable public API
- Compatibility guarantees
- Production-readiness criteria
- No date, and no version between here and there is scheduled
Stop rewriting resilience logic. Start shipping.
Install the public beta for Node.js services or LLM workloads, try it on a non-critical path, and help shape what comes next.
npm install @resili/core
Building with LLMs? Install npm install @resili/core @resili/llm @resili/llm-openai openai — installation guide →
Public Beta 1 — APIs may still change before the stable release. Plain npm install resolves to Beta 1; @beta is also available.