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

@mrzr/api-client

v3.0.1

Published

A TypeScript API client built on fetch, focused on browser auth: coalesced token refresh, Web Worker token isolation and cross-tab session sync. Zero dependencies.

Readme

@mrzr/api-client

npm types license

A TypeScript-first API client focused on secure browser auth: coalesced token refresh, Web Worker token isolation, and cross-tab session sync. Zero runtime dependencies, works in every JS runtime.

Documentation · Live demo · Wiki · Changelog

npm install @mrzr/api-client
import { createClient } from "@mrzr/api-client";

export const api = createClient({ baseUrl: "https://api.example.com" });

// Tokens are captured, stored, refreshed and rotated across tabs for you.
await api.login({ email, password });
const { data } = await api.get<User[]>("/users");

Is this for you?

Use it if any of these are real problems for you:

  • Your access token expires and 20 concurrent requests each fire their own refresh
  • You want tokens off the main thread, where XSS can't read them
  • Logging out in one tab should log out the others
  • You use httpOnly cookies and can't tell on page load whether a session exists
  • You need refresh to work during a five-minute file upload

Use something else if not. For a small fetch wrapper with built-in retry, use ky. For the widest legacy support and ecosystem, use axios. Neither focuses on browser auth.


How it compares

| | axios | ky | @mrzr/api-client | |---|---|---|---| | Zero runtime dependencies | ✗ | ✓ | ✓ | | Built on | XHR / node:http | fetch | fetch | | Retry with backoff | via axios-retry | ✓ built in | ✗ (not yet) | | Interceptors / hooks | ✓ global | ✓ global | ✓ global, via plugins | | Coalesced token refresh | build it yourself | build it yourself | ✓ built in | | Web Worker token isolation | ✗ | ✗ | ✓ | | Cross-tab auth sync | ✗ | ✗ | ✓ | | httpOnly cookie session restore | ✗ | ✗ | ✓ | | Cancel by URL pattern / scope | ✗ | ✗ | ✓ | | CSRF double-submit | partial | ✗ | ✓ |

An honest note on that table:

  • Retry. Not implemented. It has to interact correctly with refresh-and-retry, cancellation and takeLatest, and shipping it half-right would be worse than not shipping it.

What it actually does

  • Coalesced refresh — 50 simultaneous 401s trigger exactly one refresh call. A shared promise, not a polling loop
  • Web Worker isolation — requests run in a worker by default, so tokens never enter the main-thread heap. Self-disables on the server or where Worker is missing
  • Cross-tab sync — login, logout and refresh propagate over BroadcastChannel, and tabs take turns refreshing (Web Locks), so a rotating refresh token is never spent twice
  • httpOnly cookie mode — including restoreSession(), which answers the "am I logged in?" question that cookies make unanswerable from JS
  • Opt-in cancellation — cancel by URL pattern, scope or key on page change or modal close; real aborts, worker mode included
  • Real upload support — FormData, File, Blob, typed arrays and streams, with refresh handled mid-upload
  • CSRF double-submit — built in, for cookie auth
  • Plugins — optional add-ons that cost nothing until imported, like services for several APIs on one session (guide)
  • WebSockets / socket.io — getSocketToken(url) hands a socket a server-issued ticket without exposing the access token; getAccessToken() is there behind exposeTokens: true (guide)
  • One request engine — the worker and main thread run the same compiled code, so behaviour can't drift between modes
  • Runs anywhere — React, Vue, Svelte, Angular, Next.js, Nuxt, SvelteKit, plain <script>, Node 20+, Deno, Bun, Cloudflare Workers

Works with your data library

It sits under TanStack Query, SWR or Vue Query — it doesn't replace them.

useQuery({
  queryKey: ["users"],
  queryFn: ({ signal }) => api.get<User[]>("/users", { signal }).then((r) => r.data),
});

Failures reject with a typed ApiError, which is what Query and SWR need to mark a request failed. Cancellation resolves instead, flagged with canceled: true, so a route change never looks like an error.


Quick start

// lib/api.ts
import { createClient } from "@mrzr/api-client";

export const api = createClient({
  baseUrl: "https://api.example.com",
});
import { api } from "./lib/api";
import { ApiError } from "@mrzr/api-client";

try {
  const { data } = await api.get<User[]>("/users");
  console.log(data);
} catch (e) {
  if (e instanceof ApiError) console.error(e.statusCode, e.message);
}

Worker isolation, token refresh and tab sync are on by default, and turn themselves off where the runtime doesn't support them.


📚 Documentation

api-client.mrzr.ir: short guides for every feature, and a live demo that runs the package in your browser.

For every detail, edge case and recipe, see the Wiki (Security model, Troubleshooting, Migration guide, FAQ).

Upgrading from 2.x? 3.0.0 has breaking changes — see the changelog.


Requirements

Any runtime with fetch and AbortController: all modern browsers, Node 20+, Deno, Bun, Cloudflare Workers.

License

MIT