New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

airbag

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

airbag

Execution Orchestration Layer for JavaScript/TypeScript — declarative async function wrapping with retries, timeouts, and circuit breaking

latest
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

Airbag

Execution Orchestration Layer for JavaScript/TypeScript.

Replace imperative try/catch/finally blocks with declarative async function wrappers. Airbag handles loading states, error catching, retries with exponential backoff, timeouts, and circuit breaking — fully type-safe with zero runtime dependencies.

Install

npm install airbag

Quick Start

import { airbag } from 'airbag';

interface User {
  id: string;
  name: string;
}

const fetchUser = async (id: string): Promise<User> => {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json() as Promise<User>;
};

const safeFetchUser = airbag(fetchUser, {
  timeout: 5000,
  retries: 3,
  onLoading: (loading) => spinner.toggle(loading),
  onSuccess: (user) => toast.success(`Loaded ${user.name}`),
  onError: (err) => toast.error(err.message),
});

// Fully type-safe — same signature as fetchUser
const user = await safeFetchUser('user-123');

Configuration Hierarchy

Three levels of configuration merged in order of specificity:

Global → Instance → Execution

import { createAirbagInstance } from 'airbag';

// Level 1: Global defaults
const { wrap } = createAirbagInstance({
  retries: 3,
  timeout: 10000,
  onError: (err) => logger.error(err),
});

// Level 2: Instance options (merged over global)
const safeFetch = wrap(fetchUser, {
  name: 'fetchUser',
  timeout: 5000,
});

// Level 3: Execution overrides (merged over instance)
const user = await safeFetch.with({ timeout: 15000 })('user-123');

API

airbag(fn, options?)

Wraps an async function with execution orchestration.

const wrapped = airbag(myAsyncFn, { timeout: 5000, retries: 3 });
const result = await wrapped(...originalArgs);

createAirbagInstance(options?)

Creates a factory with shared global defaults.

const { wrap, configure, getDefaults } = createAirbagInstance({ retries: 2 });

wrapped.with(overrides)

Creates a new wrapped function with execution-level overrides while sharing the same circuit breaker state.

const urgent = wrapped.with({ timeout: 2000 });
const result = await urgent(...args);

wrapped.reset()

Resets the circuit breaker state back to closed.

Options

OptionTypeDefaultDescription
namestring'anonymous'Identifier for logging and error messages
timeoutnumber30000Timeout in ms (0 disables)
retriesnumber0Shorthand for retry.count
retry.countnumber0Number of retries after initial failure
retry.backoff'exponential' | 'linear' | 'fixed''exponential'Backoff strategy between retries
retry.baseDelaynumber1000Base delay in ms
retry.maxDelaynumber30000Maximum delay cap in ms
retry.jitterbooleantrueRandomize delays to avoid thundering herd
circuitBreaker.enabledbooleanfalseEnable the circuit breaker
circuitBreaker.thresholdnumber5Consecutive failures before opening
circuitBreaker.resetTimeoutnumber60000Ms before probing with a half-open attempt
signalAbortSignalCancel execution via AbortController

Callbacks

Lifecycle callbacks can be passed flat at the top level — no nesting required:

airbag(fetchUser, {
  retries: 3,
  onSuccess: (user) => toast.success(user.name),
  onError: (err) => toast.error(err.message),
});

For reusable callback sets, group them in an adapter object instead:

const logger: AirbagAdapter = {
  onError: (err, ctx) => log.error(ctx.functionName, err),
  onFinish: (ctx) => log.info(`Done in ${ctx.duration}ms`),
};

airbag(fetchUser, { retries: 3, adapter: logger });

If both flat callbacks and an adapter are provided, the adapter takes precedence.

Every callback receives an ExecutionContext:

interface ExecutionContext {
  functionName: string;
  duration: number;
  timestamp: number;
  attempt: number;
  maxAttempts: number;
}

Error Types

All errors extend AirbagError with a code and context property:

ErrorCodeWhen
TimeoutErrorTIMEOUTPromise exceeded the configured timeout
RetryExhaustedErrorRETRY_EXHAUSTEDAll retry attempts failed
CircuitOpenErrorCIRCUIT_OPENCircuit breaker blocked execution
AbortErrorABORTEDExecution cancelled via AbortSignal
import { TimeoutError, RetryExhaustedError } from 'airbag';

const result = await safeFetch('id').catch((err) => {
  if (err instanceof TimeoutError) {
    // err.timeout — the configured timeout in ms
    // err.context — execution metadata
  }
  if (err instanceof RetryExhaustedError) {
    // err.cause — the last error that caused the final failure
  }
});

License

MIT

Keywords

error-handling

FAQs

Package last updated on 10 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts