npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@axiomify/sdk-runtime

v7.1.0

Published

Runtime library for Axiomify-generated TypeScript SDKs — HTTP client, auth injection, retry engine, interceptors, caching, typed errors.

Readme

@axiomify/sdk-runtime

npm version codecov OpenSSF Scorecard License: MIT

The @axiomify/sdk-runtime is the foundational HTTP networking library that powers all TypeScript clients generated by the axiomify sdk generate command.

Rather than bloating every single generated SDK file with complex logic for retries, interceptors, and authentication injection, the generated code outsources those responsibilities to this zero-dependency library.

Philosophy

  • Zero Dependencies: Uses the native fetch API. It does not wrap or bundle Axios, Got, or Node-Fetch. This keeps your client bundle size incredibly small.
  • Pluggable: Exposes an InterceptorManager to tap into the request lifecycle.
  • Resilient: Features an advanced withRetry engine with exponential backoff and jitter designed specifically for server-to-server and high-latency edge environments.

Installation

Normally, you don't need to install this manually. If you used axiomify sdk generate -t typescript, this package is included as a dependency of the generated SDK.

However, if you generated only the types, you can install the runtime manually:

npm install @axiomify/sdk-runtime

Basic Usage

The runtime is initialized via the BaseClient. Your generated SDK will extend this class, but you will configure it using ClientConfig.

import { MyGeneratedSDK } from './generated-sdks';

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  timeoutMs: 10000, // optional; when omitted, no request timeout is applied
});

const users = await client.getUsers({ limit: 100 });

Interceptors

Interceptors allow you to mutate requests before they are sent, or intercept responses before they are returned to the caller.

// 1. Add a Request Interceptor
client.interceptors.useRequest(async (req) => {
  req.headers = { ...req.headers, 'X-Request-Start': Date.now().toString() };
  return req;
});

// 2. Add a Response Interceptor
client.interceptors.useResponse(async (res) => {
  if (res.status === 401) {
    console.error('Unauthorized! Redirecting to login...');
  }
  return res;
});

// 3. Add an Error Interceptor
client.interceptors.useError(async (err) => {
  console.error('Request failed:', err);
  return err;
});

A request interceptor receives a ClientRequest whose headers is a plain Record<string, string> (not a Headers instance), so mutate it as an object.

Retry Engine

Network requests fail. @axiomify/sdk-runtime handles retries automatically using exponential backoff and full jitter.

By default, the client retries 3 times. The default retryable status codes are [408, 409, 429, 500, 502, 503, 504], with a base delay of 500ms and a maximum delay of 5000ms.

You can override the retry config at initialization via retryConfig (all fields optional and merged over the defaults):

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  retryConfig: {
    maxRetries: 5, // Retry up to 5 times
    baseDelayMs: 200, // Start with a 200ms delay
    maxDelayMs: 5000, // Cap the delay at 5000ms
    retryableStatusCodes: [429, 500, 502, 503, 504],
  },
});

Authentication

Injecting tokens into every request is tedious. Use an AuthProvider to automatically manage tokens. An AuthProvider is any object with a getToken() method that returns the full Authorization header value (e.g. "Bearer eyJ..."), or null to skip auth. The client calls getToken() before every request and sets the returned value as the Authorization header.

Static Tokens

For a fixed token, use StaticTokenProvider:

import { StaticTokenProvider } from '@axiomify/sdk-runtime';

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  authProvider: new StaticTokenProvider('Bearer eyJ...'),
});

Custom Providers

For tokens sourced from memory, local storage, or a credential store, implement AuthProvider directly:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  authProvider: {
    getToken: async () => {
      const token = localStorage.getItem('access_token');
      return token ? `Bearer ${token}` : null;
    },
  },
});

OAuth2 Client Credentials

OAuth2BearerProvider performs the OAuth2 client_credentials flow for you, caching the token until it nears expiry and refreshing it automatically. It attaches the Authorization: Bearer <token> header before the request hits the network.

import { OAuth2BearerProvider } from '@axiomify/sdk-runtime';

const authProvider = new OAuth2BearerProvider(
  'https://auth.example.com/oauth/token', // token URL
  'my-client-id',
  'my-client-secret',
  'read write', // optional scope
);

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  authProvider,
});

Advanced: Custom Fetch Implementation

Because the runtime uses the native fetch API, you can supply your own fetch implementation (for example, a mock in tests or a polyfill) via the fetch option:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  fetch: myCustomFetch,
});

Static headers applied to every request can be supplied via the headers option:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  headers: { 'X-App-Version': '1.2.3' },
});

Circuit Breaker

To prevent cascading failures in high-volume microservices or distributed systems, the SDK client wraps all outgoing requests in a circuit breaker. By default, it operates with standard thresholds, but you can configure the behavior to suit your system:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  circuitBreakerConfig: {
    failureThreshold: 5, // Number of failures before tripping the circuit
    cooldownPeriodMs: 10000, // Time to wait (in ms) before attempting probe requests in HALF_OPEN state
    halfOpenMaxProbeRequests: 3, // Max probe requests allowed in HALF_OPEN to check system health
  },
});

If the breaker trips, the client throws a CircuitBreakerError directly, shielding downstream dependencies until the cooldown period expires.

LRU TTL Caching

The runtime provides an in-memory Least Recently Used (LRU) cache with Time-To-Live (TTL) expiration. If enabled, it automatically caches incoming GET responses and returns them for matching paths and query configurations:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  enableCache: true,
  cacheTtlMs: 60000, // Cache GET responses for 60 seconds
});

Additionally, the runtime performs Request Deduplication for identical in-flight GET requests, resolving multiple concurrent requests to the same endpoint with a single network round-trip.

Telemetry Hooks

Provide hooks to intercept and log request metadata, responses, or failures for auditing and APM integration:

const client = new MyGeneratedSDK({
  baseUrl: 'https://api.example.com/v1',
  telemetry: {
    onBeforeRequest: (req) => {
      console.log(`Sending ${req.method} request to ${req.path}`);
    },
    onAfterResponse: (res) => {
      console.log(`Received status ${res.status} from ${res.request.path}`);
    },
    onError: (err) => {
      console.error(`Request failed: ${err.message}`);
    },
  },
});

Server-Sent Events (SSE) Client

The client runtime provides a dedicated SseClient to consume Server-Sent Events. It implements automatic reconnection logic with exponential backoff:

import { SseClient } from '@axiomify/sdk-runtime';

const sse = new SseClient('https://api.example.com/v1/live-feed', {
  headers: {
    Authorization: 'Bearer token123',
  },
  maxRetries: 5,
  baseDelayMs: 1000,
  onOpen: () => console.log('SSE connection opened'),
  onMessage: (event, data) => console.log(`Received event: ${event}`, data),
  onError: (err) => console.error('SSE Error:', err),
});

// Start listening
sse.connect();

// Stop listening
sse.disconnect();

WebSocket Client

For full-duplex communication, use the WebSocketClient class. It manages standard browser/node WebSockets with customizable ping-pong heartbeats and auto-reconnection:

import { WebSocketClient } from '@axiomify/sdk-runtime';

const ws = new WebSocketClient('wss://api.example.com/v1/chat', {
  heartbeatIntervalMs: 30000, // Send ping every 30 seconds
  maxRetries: 10,
  onOpen: () => {
    console.log('WS connection active');
    ws.send(JSON.stringify({ event: 'join', channel: 'general' }));
  },
  onMessage: (data) => console.log('WS Message:', data),
  onClose: () => console.log('WS closed'),
});

ws.connect();

Paginators

The Paginator handles cursor-based paginated endpoints seamlessly:

import { Paginator } from '@axiomify/sdk-runtime';

const paginator = new Paginator<User, { cursor?: string }>({
  fetchPage: async (params) => {
    const response = await client.listUsers(params.cursor);
    return {
      items: response.users,
      nextCursor: response.nextCursor,
      hasMore: !!response.nextCursor,
    };
  },
  initialParams: {},
  cursorParamName: 'cursor',
});

// Fetch pages sequentially
if (paginator.hasNext()) {
  const users = await paginator.nextPage();
  console.log('Fetched users:', users);
}

Client Offline Queuing

For mobile or edge clients, the OfflineQueue caches requests during offline periods and flushes them automatically when the connection returns:

import { OfflineQueue } from '@axiomify/sdk-runtime';

const offlineQueue = new OfflineQueue();

// In offline state, queue operations
offlineQueue.enqueue({
  path: '/users',
  method: 'POST',
  body: { name: 'Jane Doe', email: '[email protected]' },
});

// Flush automatically on navigator/window online event
// or call manually with a custom processor:
await offlineQueue.flush(async (queuedRequest) => {
  await client.request({
    path: queuedRequest.path,
    method: queuedRequest.method as any,
    body: queuedRequest.body,
  });
});

Environment Switcher

Manage target environments programmatically using the EnvironmentSwitcher:

import { EnvironmentSwitcher } from '@axiomify/sdk-runtime';

const environments = {
  production: 'https://api.example.com/v1',
  staging: 'https://api-staging.example.com/v1',
  development: 'http://localhost:3000',
};

const switcher = new EnvironmentSwitcher(environments, 'development');
console.log(switcher.getUrl()); // http://localhost:3000

switcher.setEnvironment('production');
console.log(switcher.getUrl()); // https://api.example.com/v1