Skip to content

@connectum/interceptors

Production-ready ConnectRPC interceptors providing resilience patterns, error handling, validation, and serialization. Includes a fixed-order default interceptor chain and a method-filter interceptor for per-method configuration.

Layer: 1 (Protocol)

Related Guides

Full API Reference

Complete TypeScript API documentation: API Reference

Installation

bash
pnpm add @connectum/interceptors

Requires: Node.js 18+

Quick Start

typescript
import { createDefaultInterceptors } from '@connectum/interceptors';

// All defaults (fallback disabled)
const interceptors = createDefaultInterceptors();

// Custom configuration
const interceptors = createDefaultInterceptors({
  retry: false,
  timeout: { duration: 10_000 },
  circuitBreaker: { threshold: 3 },
});

When using @connectum/core, pass the result of createDefaultInterceptors() to the interceptors option:

typescript
import { createServer } from '@connectum/core';
import { createDefaultInterceptors } from '@connectum/interceptors';

const server = createServer({
  services: [routes],
  interceptors: createDefaultInterceptors({
    errorHandler: { logErrors: true },
    timeout: { duration: 15_000 },
    retry: false,
  }),
});

Default Interceptor Chain

The interceptor order is fixed and intentional:

errorHandler -> timeout -> bulkhead -> circuitBreaker -> retry -> fallback -> validation -> serializer
#InterceptorPurposeDefault
1errorHandlerCatch-all error normalization (outermost)Enabled
2timeoutEnforce request deadlineEnabled (30s)
3bulkheadLimit concurrent requestsEnabled (10/10)
4circuitBreakerPrevent cascading failuresEnabled (5 failures)
5retryRetry transient failures with backoffEnabled (3 retries)
6fallbackGraceful degradationDisabled
7validationValidate request messages (@connectrpc/validate)Enabled
8serializerJSON serialization (innermost)Enabled

API Reference

createDefaultInterceptors(options?)

Creates the full interceptor chain with configurable options.

typescript
function createDefaultInterceptors(options?: DefaultInterceptorOptions): Interceptor[];

Each interceptor can be set to true (defaults), false (disabled), or an options object.

DefaultInterceptorOptions

typescript
interface DefaultInterceptorOptions {
  errorHandler?: boolean | ErrorHandlerOptions;      // default: true
  timeout?: boolean | TimeoutOptions;                // default: true
  bulkhead?: boolean | BulkheadOptions;              // default: true
  circuitBreaker?: boolean | CircuitBreakerOptions;  // default: true
  retry?: boolean | RetryOptions;                    // default: true
  fallback?: boolean | FallbackOptions;              // default: false
  validation?: boolean;                              // default: true
  serializer?: boolean | SerializerOptions;          // default: true
}

Individual Interceptors

Error Handler

Transforms errors into ConnectError with proper gRPC status codes. Recognizes the SanitizableError protocol from @connectum/core: preserves server-side details for logging while exposing only a safe clientMessage to the client.

typescript
import { createErrorHandlerInterceptor } from '@connectum/interceptors';

const interceptor = createErrorHandlerInterceptor({
  logErrors: true,           // default: NODE_ENV !== "production"
  includeStackTrace: false,  // default: NODE_ENV !== "production"
});
OptionTypeDefaultDescription
logErrorsbooleanNODE_ENV !== "production"Log errors to console. Deprecated: use onError instead.
includeStackTracebooleanNODE_ENV !== "production"Include stack trace in logs
onError(info: { error: Error; code: number; serverDetails?: Record<string, unknown>; stack?: string }) => void--Error callback. Replaces console.error when provided. Receives rich error info including serverDetails from SanitizableError.

Timeout

Enforces a request deadline before any processing begins.

typescript
import { createTimeoutInterceptor } from '@connectum/interceptors';

const interceptor = createTimeoutInterceptor({
  duration: 15_000,      // 15 seconds
  skipStreaming: true,   // skip for streaming calls
});
OptionTypeDefaultDescription
durationnumber30000Request timeout in milliseconds
skipStreamingbooleantrueSkip for streaming calls

Bulkhead

Limits concurrent requests to prevent resource exhaustion.

typescript
import { createBulkheadInterceptor } from '@connectum/interceptors';

const interceptor = createBulkheadInterceptor({
  capacity: 20,       // max concurrent requests
  queueSize: 50,      // max queued requests
  skipStreaming: true,
});
OptionTypeDefaultDescription
capacitynumber10Maximum concurrent requests
queueSizenumber10Maximum queued requests
skipStreamingbooleantrueSkip for streaming calls

Circuit Breaker

Prevents cascading failures by breaking the circuit on consecutive errors.

typescript
import { createCircuitBreakerInterceptor } from '@connectum/interceptors';

const interceptor = createCircuitBreakerInterceptor({
  threshold: 5,          // failures before opening
  halfOpenAfter: 30_000, // wait before retrying
  skipStreaming: true,
});
OptionTypeDefaultDescription
thresholdnumber5Consecutive failures before opening
halfOpenAfternumber30000Milliseconds before half-open attempt
skipStreamingbooleantrueSkip for streaming calls

Retry

Retries transient failures with exponential backoff. Uses the cockatiel library.

typescript
import { createRetryInterceptor } from '@connectum/interceptors';

const interceptor = createRetryInterceptor({
  maxRetries: 3,
  initialDelay: 200,
  maxDelay: 5_000,
  retryableCodes: [Code.Unavailable, Code.ResourceExhausted],
  skipStreaming: true,
});
OptionTypeDefaultDescription
maxRetriesnumber3Maximum retry attempts
initialDelaynumber200Initial backoff delay (ms)
maxDelaynumber5000Maximum backoff delay (ms)
retryableCodesCode[][Unavailable, ResourceExhausted]Error codes that trigger retry
skipStreamingbooleantrueSkip for streaming calls

Fallback

Provides graceful degradation when the service fails. Disabled by default because it requires a handler function.

typescript
import { createFallbackInterceptor } from '@connectum/interceptors';

const interceptor = createFallbackInterceptor({
  handler: (error) => ({ items: [], error: error.message }),
  skipStreaming: true,
});
OptionTypeDefaultDescription
handler(error: Error) => T | Promise<T>(required)Fallback function
skipStreamingbooleantrueSkip for streaming calls

Validation

Validates request messages using @connectrpc/validate (protovalidate). No configuration options; toggled on/off.

typescript
// Enabled by default in createDefaultInterceptors()
// To use standalone:
import { createValidateInterceptor } from '@connectrpc/validate';
const interceptor = createValidateInterceptor();

Serializer

Auto-serializes ConnectRPC responses to JSON format.

typescript
import { createSerializerInterceptor } from '@connectum/interceptors';

const interceptor = createSerializerInterceptor({
  skipGrpcServices: true,
  alwaysEmitImplicit: true,
  ignoreUnknownFields: true,
});
OptionTypeDefaultDescription
skipGrpcServicesbooleantrueSkip for gRPC services
alwaysEmitImplicitbooleantrueAlways emit implicit fields in JSON
ignoreUnknownFieldsbooleantrueIgnore unknown fields when deserializing

Method Filter Interceptor

Routes interceptors to specific methods based on wildcard pattern matching.

typescript
import { createMethodFilterInterceptor } from '@connectum/interceptors';

const perMethodInterceptor = createMethodFilterInterceptor({
  '*': [logRequest],                                      // all methods
  'admin.v1.AdminService/*': [requireAdmin],              // all service methods
  'user.v1.UserService/DeleteUser': [requireAdmin, auditLog], // exact method
});

Pattern Resolution Order

All matching patterns execute in order:

  1. Global wildcard "*" (first)
  2. Service wildcard "Service/*" (second)
  3. Exact match "Service/Method" (last)

Within each pattern, interceptors execute in array order.

MethodFilterMap

typescript
type MethodFilterMap = Record<string, Interceptor[]>;

Exports Summary

ExportDescription
createDefaultInterceptorsFactory for the default interceptor chain
createErrorHandlerInterceptorError normalization
createLoggerInterceptorRequest logging
createSerializerInterceptorJSON serialization
createRetryInterceptorRetry with backoff
createCircuitBreakerInterceptorCircuit breaker
createTimeoutInterceptorRequest timeout
createBulkheadInterceptorConcurrency limiter
createFallbackInterceptorGraceful degradation
createMethodFilterInterceptorPer-method interceptor routing