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

@devraj-labs/api-kit

v1.0.4

Published

Production-grade API client with automatic token lifecycle management, race-condition-safe refresh handling, and platform-agnostic storage adapters.

Downloads

81

Readme

Devraj Labs · API Kit

The API client that handles auth so you don't have to.

Token attachment. Silent refresh. Race-condition safety. Works everywhere.

npm TypeScript License: MIT Platform


You've written the interceptor. You've debugged the race condition where five requests all tried to refresh at once. You've added the retry logic, the logger, the storage adapter. You've done it on every project.

API Kit does all of it — once, correctly.


What it does

ApiClient.getInstance({
  baseURL: "https://api.example.com",
  storage: myStorage,
  hooks: {
    onAuthFailure: () => router.push("/login"),
  },
});

// That's it. Every request from here automatically:
// - attaches Bearer token
// - refreshes silently when it expires
// - retries if the server hiccups
// - routes exactly ONE refresh call even if 10 requests fire at once
const { data } = await client.get<User>("/api/me");

Features

Token lifecycle — fully automatic

  • Attaches Authorization: Bearer <token> to every request
  • Detects 401s and transparently refreshes + replays the failed request
  • Pre-emptive refresh — renews the token before it expires, configurable via preemptiveRefreshSeconds

Race-condition safe

  • Concurrent 401s collapse into exactly one refresh call
  • All queued requests drain together the moment refresh completes
  • Pre-emptive refresh shares the same single-flight promise — no double-refresh under load

Platform agnostic

  • Works in browser, React Native, and Node.js
  • Bring your own storage — any object implementing getAccessToken / setTokens / clearTokens
  • Ships with MemoryTokenStorage, LocalStorageTokenStorage, and AsyncStorageTokenStorage
  • First-class support for @devraj-labs/rn-storage-kit (encrypted keychain on mobile)

Production grade

  • Exponential backoff with full jitter on transient errors (408, 429, 5xx)
  • Auth event hooks — onTokenRefreshed · onAuthFailure · onLogout
  • Bring-your-own logger — any { debug, info, warn, error } object (console, @devraj-labs/logger, etc.)
  • Singleton pattern — initialise once, use everywhere, no prop drilling

TypeScript first

  • Full generics on every method: client.get<User>("/api/me")
  • Exported interfaces for every extension point

Install

npm install @devraj-labs/api-kit axios

Quick start

// bootstrap.ts — run this once at app entry (index.ts / App.tsx)
import { ApiClient, LocalStorageTokenStorage } from "@devraj-labs/api-kit";

ApiClient.getInstance({
  baseURL: "https://api.example.com",
  storage: new LocalStorageTokenStorage(),
  hooks: {
    onAuthFailure() {
      window.location.href = "/login";
    },
  },
});
// anywhere in your app — no config needed
import { ApiClient } from "@devraj-labs/api-kit";

const client = ApiClient.getInstance();

const { data: user }    = await client.get<User>("/api/me");
const { data: post }    = await client.post<Post>("/api/posts", { title });
const { data: updated } = await client.patch<Post>("/api/posts/1", { title });

After login, store the tokens and every subsequent request is handled:

import { ApiClient } from "@devraj-labs/api-kit";

async function login(username: string, password: string) {
  const res = await fetch("/auth/login", {
    method: "POST",
    body: JSON.stringify({ username, password }),
  });
  const tokens = await res.json();

  // hand tokens to api-kit — it takes it from here
  const client = ApiClient.getInstance();
  await client.storage.setTokens(tokens);
}

Storage

| Adapter | Environment | Security | |---|---|---| | MemoryTokenStorage | Any | Cleared on page reload | | LocalStorageTokenStorage | Browser | Vulnerable to XSS — dev/demo only | | AsyncStorageTokenStorage | React Native | Unencrypted — dev/demo only | | @devraj-labs/rn-storage-kit | React Native | Encrypted keychain — recommended for prod |

Implement your own with three methods:

import type { TokenStorage } from "@devraj-labs/api-kit";

const myStorage: TokenStorage = {
  getAccessToken:  () => secureGet("access_token"),
  getRefreshToken: () => secureGet("refresh_token"),
  setTokens:       (t) => secureSet(t),
  clearTokens:     ()  => secureClear(),
};

Full guide → docs/storage.md


Logger

Pass any object with debug / info / warn / error — no adapter needed:

// console
ApiClient.getInstance({ ..., logger: console });

// @devraj-labs/logger
import { logger } from "@devraj-labs/logger";
ApiClient.getInstance({ ..., logger: logger.child({ module: "api-kit" }) });

// silent (default)
ApiClient.getInstance({ ...config }); // omit logger entirely

Full guide → docs/logger.md


Documentation

| | | |---|---| | Getting Started | Install, minimal setup, platform examples | | Configuration | All config options, types, and defaults | | Token Storage | Built-in adapters, custom storage, rn-storage-kit | | Logger Integration | Using @devraj-labs/logger or any compatible logger | | Race Condition Guard | How concurrent 401s are handled | | Pre-emptive Refresh | Proactive token renewal before expiry | | Examples | Node.js · Browser · React Native · custom storage | | Demo | Running the interactive demo app locally |


Run the demo

Hosted demo — no setup needed: https://web-self-delta-77.vercel.app/

See token refresh, race-condition guard, and live expiry countdown in action. Login with alice / password123.

Or run it locally:

npm run demo

Opens a Vite + React app at http://localhost:5173 backed by a local Express server. Full guide → docs/demo.md


License

MIT © Devraj Labs