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

@forgedevstack/forge-query

v1.0.0

Published

Powerful data fetching and caching library for React with DevTools support

Readme

Forge Query


Why Forge Query?

| Feature | Forge Query | Others | |---------|-------------|--------| | Bundle Size | ~12KB | 30KB+ | | DevTools | Built-in + Chrome Extension | Separate package | | Setup | 2 lines | 10+ lines | | Learning Curve | Minimal | Steep | | TypeScript | First-class | Added later |

Features

  • Simple API — Just useQuery and useMutation
  • Smart Caching — Automatic with configurable stale/cache times
  • Background Sync — Auto-refetch on focus, reconnect, and intervals
  • Optimistic Updates — Instant UI feedback
  • DevTools — In-app panel + Chrome extension
  • Tiny — ~12KB gzipped
  • Flexible — Works with fetch, axios, graphql, or any async function

Quick Start

1. Install

npm install @forgedevstack/forge-query

2. Setup

import { QueryClient, QueryClientContext } from '@forgedevstack/forge-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientContext.Provider value={queryClient}>
      <YourApp />
    </QueryClientContext.Provider>
  );
}

3. Fetch Data

import { useQuery } from '@forgedevstack/forge-query';

function UserProfile({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  });

  if (isLoading) return <Spinner />;
  if (error) return <Error message={error.message} />;
  
  return <Profile user={data} />;
}

4. Mutate Data

import { useMutation, useQueryClient } from '@forgedevstack/forge-query';

function CreateTodo() {
  const queryClient = useQueryClient();
  
  const { mutate, isLoading } = useMutation({
    mutationFn: (todo) => fetch('/api/todos', {
      method: 'POST',
      body: JSON.stringify(todo),
    }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] });
    },
  });

  return (
    <button onClick={() => mutate({ title: 'New Todo' })} disabled={isLoading}>
      Add Todo
    </button>
  );
}

DevTools

In-App Panel

Add the DevTools component to see all queries, logs, and cache in real-time:

import { ForgeQueryDevTools } from '@forgedevstack/forge-query/devtools';

function App() {
  return (
    <QueryClientContext.Provider value={queryClient}>
      <YourApp />
      <ForgeQueryDevTools />
    </QueryClientContext.Provider>
  );
}

Chrome Extension

Get a dedicated DevTools panel in Chrome:

  1. Download from Chrome Web Store (coming soon)
  2. Or build from source:
    cd devtools-extension
    npm install
    npm run build
  3. Load in Chrome: Extensions → Developer Mode → Load Unpacked

Features:

  • View all queries and their status
  • Activity logs with timestamps
  • Cache statistics and data preview
  • Refetch, invalidate, or remove queries

API Reference

useQuery

const {
  data,         // The fetched data
  error,        // Error if failed
  isLoading,    // Initial loading state
  isFetching,   // Any fetching (including background)
  isError,      // Error state
  isSuccess,    // Success state
  refetch,      // Manual refetch function
} = useQuery({
  queryKey: ['users'],        // Unique cache key
  queryFn: fetchUsers,        // Async function
  staleTime: 60000,           // Time until stale (ms)
  cacheTime: 300000,          // Cache retention (ms)
  retry: 3,                   // Retry attempts
  enabled: true,              // Enable/disable
  refetchOnMount: true,       // Refetch on mount
  refetchOnWindowFocus: true, // Refetch on focus
  refetchInterval: false,     // Auto-refetch interval
});

useMutation

const {
  mutate,       // Trigger mutation
  mutateAsync,  // Returns promise
  data,         // Result data
  error,        // Error if failed
  isLoading,    // Loading state
  reset,        // Reset state
} = useMutation({
  mutationFn: (data) => createItem(data),
  onMutate: (variables) => { /* Before mutation */ },
  onSuccess: (data) => { /* On success */ },
  onError: (error) => { /* On error */ },
  onSettled: () => { /* Always runs */ },
});

QueryClient

const queryClient = new QueryClient({
  defaultOptions: {
    staleTime: 0,
    cacheTime: 5 * 60 * 1000,
    retry: 3,
  },
});

// Methods
queryClient.getQueryData(['users']);           // Get cached data
queryClient.setQueryData(['users'], newData);  // Set cache
queryClient.invalidateQueries(['users']);      // Mark stale & refetch
queryClient.refetchQueries(['users']);         // Force refetch
queryClient.removeQueries(['users']);          // Remove from cache
queryClient.clear();                           // Clear all

Examples

Dependent Queries

const { data: user } = useQuery({
  queryKey: ['user', userId],
  queryFn: fetchUser,
});

const { data: posts } = useQuery({
  queryKey: ['posts', user?.id],
  queryFn: () => fetchPosts(user.id),
  enabled: !!user, // Wait for user
});

Optimistic Updates

const { mutate } = useMutation({
  mutationFn: updateTodo,
  onMutate: async (newTodo) => {
    await queryClient.cancelQueries(['todos']);
    const previous = queryClient.getQueryData(['todos']);
    queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
    return { previous };
  },
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(['todos'], context.previous);
  },
});

With TypeScript

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

const { data } = useQuery<User, Error>({
  queryKey: ['user', id],
  queryFn: () => fetchUser(id),
});
// data is User | undefined

Configuration

const queryClient = new QueryClient({
  defaultOptions: {
    staleTime: 0,              // Data is stale immediately
    cacheTime: 5 * 60 * 1000,  // 5 minutes
    retry: 3,
    retryDelay: 1000,
    refetchOnMount: true,
    refetchOnWindowFocus: true,
    refetchOnReconnect: true,
  },
  devtools: {
    enabled: process.env.NODE_ENV === 'development',
    maxLogs: 100,
  },
});

Browser Support

| Browser | Version | |---------|---------| | Chrome | 90+ | | Firefox | 90+ | | Safari | 14+ | | Edge | 90+ |


Contributing

We welcome contributions! See CONTRIBUTING.md.

License

MIT © ForgeDevStack