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

reqkit

v1.0.5

Published

Fast cross-platform request engine with caching, background execution, streaming, and React hooks.

Readme

Reqkit

Reqkit — a fast, cross-platform API engine for React, React Native (including Expo), and web apps. It unifies networking, caching, background execution, streaming/polling, offline queueing, and typed React hooks into a single, composable developer experience.

Built for performance-critical apps (banking, trading, AI, dashboards) where UI responsiveness and predictable network behavior matter.


Quick facts

  • ✅ Cross-platform: Web + React Native + Expo
  • ⚡ Background execution: react-native-worklets (RN) + Web Workers (Web) with safe main-thread fallback
  • 🧠 Hooks: useReqkitQuery, useReqkitMutation, useReqkitStream, plus createQueryHook / createMutationHook / createStreamHook
  • 🗂️ Caching: in-memory with tag-based invalidation and dedupe for in-flight requests
  • 🔁 Offline queue: persist-and-retry for non-GET requests (pluggable storage)
  • 📡 Streaming & polling: append/replace modes and configurable intervals
  • 🔧 TypeScript-first API and DI-friendly (inject executor, fetch, storage)

Installation

# npm
npm install reqkit

# pnpm
pnpm add reqkit

# react-native-worklets for better RN background performance (optional but recommended)
npm install react-native-worklets

If you don't install react-native-worklets, Reqkit will still work — heavy transforms run on the main JS thread as a fallback.


Table of contents


Quick start

// src/reqkit.ts
import { createReqkit } from "reqkit";
import AsyncStorage from "@react-native-async-storage/async-storage"; // RN/Expo

const storageAdapter = {
  getItem: (k: string) => AsyncStorage.getItem(k),
  setItem: (k: string, v: string) => AsyncStorage.setItem(k, v),
  removeItem: (k: string) => AsyncStorage.removeItem(k),
};

export const {
  ReqkitProvider,
  useReqkitQuery,
  useReqkitMutation,
  useReqkitStream,
  createQueryHook,
  createMutationHook,
  createStreamHook,
  useReqkitGlobal,
  invalidateTag,
  invalidateKey,
  setOnline,
  flushOfflineQueue,
  client,
} = createReqkit({
  baseUrl: "https://api.example.com",
  defaultTimeoutMs: 12_000,
  offlineQueue: { enabled: true, storage: storageAdapter },
});

Wrap your app:

// App.tsx
import React from "react";
import { ReqkitProvider } from "./reqkit";

export default function App() {
  return (
    <ReqkitProvider>
      {/* your app */}
    </ReqkitProvider>
  );
}

Core concepts

ApiClient — the core HTTP client. Handles fetch, timeouts, retry/backoff, caching, dedupe, and optional offline enqueue.

Background Executor — executes heavy transforms off the main thread. On RN, uses react-native-worklets if available; in Web, uses a Web Worker. Fallback runs on main thread.

Cache — in-memory cache with TTLs and tag indices. It also stores inflight promises to dedupe concurrent requests.

OfflineQueue — persistent queue for non-GET requests while offline. Flushable when connectivity returns.

HooksuseReqkitQuery / useReqkitMutation / useReqkitStream provide typed, declarative access to ApiClient functionality and global state.

Named hooks — factory helpers (createQueryHook, createMutationHook, createStreamHook) to create business-level hooks like useGetUserProfile().


API reference

createReqkit(config)

Creates Reqkit instance bound to a client configuration.

Config (selected fields):

  • baseUrl: string — base URL used for requests
  • defaultHeaders?: Record<string, string>
  • getAuthToken?: () => Promise<string | undefined> — attach tokens to outgoing requests
  • defaultTimeoutMs?: number
  • offlineQueue?: { enabled: boolean; storage: StorageAdapter }
  • fetchImpl?: typeof fetch — inject custom fetch (useful for tests)
  • backgroundExecutor?: BackgroundExecutor — inject custom executor (useful in tests)

Returns an object with:

  • ReqkitProvider — React provider
  • useReqkitQuery / useReqkitMutation / useReqkitStream
  • createQueryHook, createMutationHook, createStreamHook
  • Cache invalidation helpers and offline utilities
  • client — the underlying ApiClient

Hooks

useReqkitQuery(options)

Options (common):

  • path: string
  • method?: "GET" | ... (defaults to GET)
  • params?: Record<string, any>
  • cache?: { key?: string; tags?: string[]; cacheTimeMs?: number; staleTimeMs?: number }
  • transformResponse?: (raw) => any — can be run in background if isHeavy: true
  • isHeavy?: boolean — opt into background execution
  • enabled?: boolean — control whether it runs
  • refetchOnMount?: boolean
  • refetchIntervalMs?: number — for polling

Returns:

{ data, error, status, isLoading, isFetching, refetch }

useReqkitMutation(options)

Options:

  • path: string
  • method?: "POST" | "PATCH" | "PUT" | "DELETE" (default POST)
  • offline?: { enqueueIfNetworkError?: boolean }
  • cache?: { tags?: string[] } — tags to invalidate / refresh
  • transformResponse? / isHeavy? / backgroundStrategy?

Returns:

{ mutate, data, error, status, isLoading }

mutate(vars) executes the request and returns the ApiResponse.

useReqkitStream(options)

Options:

  • path: string
  • intervalMs: number — poll frequency
  • append?: boolean — append results into array
  • maxItems?: number — for rolling windows
  • enabled?: boolean
  • autoStart?: boolean — set false in tests and call start() manually

Returns:

{ data, error, isStreaming, start, stop, restart }

useReqkitGlobal()

Returns global request state:

{ activeRequests: number, lastError?: ApiError, extras: Record<string, unknown> }

Use it for global indicators and centralized error toasts.


Examples

Query example (GET)

function Profile() {
  const { data, isLoading, error, refetch } = useReqkitQuery({
    path: "/me",
    cache: { key: "me", tags: ["user:me"], cacheTimeMs: 60_000 }
  });

  if (isLoading) return <div>Loading…</div>;
  if (error) return <div>Error: {error.message}</div>;
  return <div>Hello {data?.name}</div>;
}

Mutation example (POST/PATCH)

function EditProfile() {
  const { mutate, isLoading } = useReqkitMutation({
    path: "/me",
    method: "PATCH",
    cache: { tags: ["user:me"] }
  });

  const save = async (payload) => {
    try {
      await mutate(payload);
      // optimistic UI or success actions
    } catch (err) {
      // handle error
    }
  };
}

Streaming / Polling example

function PriceTicker() {
  const { data, isStreaming } = useReqkitStream({
    path: "/ticker/BTC-USD",
    intervalMs: 1000,
    append: true,
    maxItems: 100,
  });

  return <div>{isStreaming ? "Live" : "Stopped"} — {JSON.stringify(data)}</div>;
}

React Native / Expo

  • Add react-native-worklets for best background execution performance.
  • Use AsyncStorage as the default storage adapter for offline queueing.
  • For Expo-managed apps: react-native-worklets works in most managed builds; otherwise Reqkit falls back to main-thread execution.

Example storage adapter for createReqkit in RN:

import AsyncStorage from '@react-native-async-storage/async-storage';

const storageAdapter = {
  getItem: (k: string) => AsyncStorage.getItem(k),
  setItem: (k: string, v: string) => AsyncStorage.setItem(k, v),
  removeItem: (k: string) => AsyncStorage.removeItem(k),
};

Web

  • Reqkit uses a Web Worker for background transforms if available.
  • No extra dependency required for workers — Reqkit auto-generates a worker blob to run pure transform functions.
  • Use localStorage or IndexedDB as a storage adapter for offline queues.

Example storage adapter for Web:

const storageAdapter = {
  getItem: (k) => Promise.resolve(localStorage.getItem(k)),
  setItem: (k, v) => Promise.resolve(localStorage.setItem(k, v)),
  removeItem: (k) => Promise.resolve(localStorage.removeItem(k)),
};

Background execution

Reqkit will attempt to offload heavy JSON transforms and parsing off the main thread.

  • RN: uses react-native-worklets runOnUIAsync when available (mark heavy functions with "worklet" where applicable).
  • Web: uses a generated Web Worker (Blob) to eval and run the transform function (pure functions only).
  • Fallback: main-thread execution when neither is available.

Important: transformResponse must be a pure function without closure over React component state — this allows safe serialization / execution in the background.


Caching & invalidation

  • Cache keys are derived from method + path + params by default, but you can specify cache.key.

  • cache.tags lets you group resources (e.g. user:me).

  • Helpers:

    • invalidateTag(tag) — invalidates all cache entries that were indexed under tag.
    • invalidateKey(key) — remove a single key.
    • invalidatePrefix(prefix) — invalidates keys with a prefix.

Dedupe: concurrent identical GET requests share the same in-flight promise so you only execute the network call once.


Offline queue

  • Off-line queue persists non-GET requests when offline and retries them when connectivity returns.
  • Queue uses a pluggable storage adapter (AsyncStorage or localStorage) and is flushable via flushOfflineQueue().
  • Config example in createReqkit:
createReqkit({
  baseUrl: "https://api.example.com",
  offlineQueue: { enabled: true, storage: storageAdapter }
});

To mark a mutation for offline enqueue:

useReqkitMutation({
  path: "/transfer",
  method: "POST",
  offline: { enqueueIfNetworkError: true }
});

Error handling & retries

  • Retry is automatic for transient failures (configurable backoff and retry count).
  • Errors surfaced by hooks are ApiError objects with code and message.
  • Global error surface: useReqkitGlobal() exposes lastError for centralized toasts.

Contributing

Contributions welcome! Suggested workflow:

  1. Fork repo and create a branch.
  2. Add tests for new features or bug fixes.
  3. Keep PRs focused and small.
  4. Update README and CHANGELOG.

Please follow conventional commits for release automation.


License

MIT © Ebubechi Ihediwa