Client Plugins
Retry, circuit breaker, timeout, batching, deduplication, and CSRF protection for the Silgi client.
Client plugins wrap the transport link to add resilience, performance, and security features. They are composable — stack them in any order.
import { } from 'silgi/client'
import { } from 'silgi/client/fetch'
import { , , } from 'silgi/client/plugins'
const = ({ : 'https://api.example.com' })
const = (((, { : 5000 }), { : 5 }), {
: 3,
})
const = <>()Retry
Automatically retry failed requests with exponential backoff and jitter.
import { } from 'silgi/client/plugins'
const = (baseLink, {
: 3, // default: 3
: 1000, // 1s → 2s → 4s (exponential)
: true, // adds 0-25% random jitter (default: true)
: [500, 502, 503, 504], // status codes to retry on
: (, ) => < 5,
: ({ , , , }) => {
.(`Retry #${} for ${.('/')} in ${}ms`)
},
})| Option | Type | Default | Description |
|---|---|---|---|
maxRetries | number | 3 | Maximum retry attempts |
baseDelay | number | (attempt) => number | 1000 | Base delay in ms. Actual: baseDelay * 2^attempt + jitter |
jitter | boolean | true | Add 0-25% random delay to prevent thundering herd |
retryOn | number[] | [408, 429, 500, 502, 503, 504] | HTTP status codes that trigger retry |
shouldRetry | (error, attempt) => boolean | — | Custom predicate to stop retrying |
onRetry | (info) => void | — | Called before each retry with attempt, delay, error, path |
Network errors (no status code) are always retried unless shouldRetry returns false.
The retry plugin respects AbortSignal — if the signal is aborted during a delay wait, the retry is cancelled
immediately.
Circuit Breaker
Prevents cascading failures by blocking requests when a service is down.
import { } from 'silgi/client/plugins'
const = (baseLink, {
: 5, // open after 5 consecutive failures
: 30000, // try again after 30s
: (, { }) => {
.(`Circuit: ${} (${} failures)`)
},
})
// Check state programmatically
.() // 'closed' | 'open' | 'half-open'
.() // manually close the circuit| Option | Type | Default | Description |
|---|---|---|---|
failureThreshold | number | 5 | Consecutive failures before opening |
resetTimeout | number | 30000 | Ms to wait before half-open test |
onStateChange | (state, info) => void | — | Called on state transitions |
State machine
CLOSED → (failures >= threshold) → OPEN
OPEN → (resetTimeout elapsed) → HALF-OPEN
HALF-OPEN → (success) → CLOSED
HALF-OPEN → (failure) → OPENWhen open, requests throw CircuitBreakerOpenError immediately — no network call is made.
Timeout
Set a per-link timeout for all requests.
import { } from 'silgi/client/plugins'
const = (baseLink, { : 5000 })| Option | Type | Default | Description |
|---|---|---|---|
timeout | number | 30000 | Timeout in ms |
The timeout signal is combined with any existing signal using AbortSignal.any() — whichever fires first wins.
Composition
Plugins are pure link wrappers — compose them in any order. The outermost plugin runs first:
// Request flow: timeout check → circuit breaker check → retry loop → actual fetch
const = withRetry(withCircuitBreaker(withTimeout(baseLink, { : 5000 })))Recommended order for production:
- withRetry (outermost) — retries the entire inner chain
- withCircuitBreaker — blocks when service is down
- withTimeout (innermost) — aborts slow individual requests
Other plugins
Batch
Combine multiple RPC calls into a single HTTP request:
import { } from 'silgi/client/plugins'
const = new ({ : '/batch', : 10 })Dedupe
Deduplicate identical in-flight requests:
import { } from 'silgi/client/plugins'
const = (baseLink)CSRF
Add CSRF token to requests:
import { } from 'silgi/client/plugins'
const = (baseLink, { : 'x-csrf-token' })