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

@fluxninja/graceful-js

v0.2.6

Published

Library for handling rate limits from FluxNinja Aperture and other backends

Readme

graceful-js

graceful-js is a robust React library that enhances API communication by intelligently handling retries and understanding rate limiting headers and bodies. It allows your application to recover gracefully from transient failures.

Installation

Install using npm or yarn:

#npm
npm i @fluxninja/graceful-js
#yarn
yarn add @fluxninja/graceful-js

Configuration

Configure graceful-js to suit your needs. If using axios, pass the axios instance to the config:

export declare type Config = {
  axios?: AxiosInstance
  urlList?: string[]
  theme?: GracefulTheme
  errorComponentMap?: Map<number, JSX.Element>
  DefaultErrorComponent?: JSX.Element
  WaitingRoomErrorComponent?: JSX.Element
  maxBackOffTime?: number
  maxRequestResolveTime?: number
  exponentialBackOffFn?: ExponentialBackOffFn
}

Apply this config object to the GracefulProvider:

import { GracefulProvider } from 'graceful-js'

const App: FC = () => (
  <ThemeProvider>
    <GracefulProvider config={yourConfigObject}>
      <AppComponent />
    </GracefulProvider>
  </ThemeProvider>
)

Usage

Use gracefulRequest for support with rate limit headers and body. You can also config according to your needs at request level using configOptions argument. This function will retry requests based on the provided parameters:

import { gracefulRequest } from 'graceful-js'

// gracefulRequest with Axios
gracefulRequest <
  'Axios' >
  ('Axios',
  () => api.get('yourEndpoint'),
  (err, success) => {
    if (err) {
      // action on error
      return
    }
    // action on success
  })
import { gracefulRequest } from 'graceful-js'

// gracefulRequest with Fetch
gracefulRequest <
  'Fetch' >
  ('Fetch',
  () => fetch('yourEndpoint'),
  (err, success) => {
    if (err) {
      // action on error
      return
    }
    // action on success
  })

The gracefulRequest callback emits an error or success response at each retry, resolving with a promise when retries complete. It allows immediate user notification of errors without waiting for function resolution.

Hooks

Use the useGracefulRequest hook:

const { isError, refetch, data, isLoading, isRetry, error } =
  useGracefulRequest <
  'Axios' >
  {
    typeOfRequest: 'Axios',
    requestFnc: () => api.get('api/rate-limit'),
  }

The useGraceful hook can also be utilized to obtain the context of the last request response, in addition to a Map of application errors.

Error Components

Use error components as follows:

<GracefulError
  {...{
    url: 'http://localhost:3009/api/ping', // endpoint for which this error component is rendering
    method: 'GET', // method for the request
    requestBody: {}, // request body in request, omit it if no request body
  }}
/>
;<GracefulErrorByStatus status={errorStatus} />
const { errorInfo } = useGraceful()
errorInfo.get('http://localhost:3009/api/rate-limit-get-{}') // create key with url + lowercase method + requestBody (if no request body add {})

Scenarios

For rate limiting scenarios, send the following inside the error response body:

export declare type RateLimitResponseBody = {
  message: string // message in the response
  retryAfter: number // time in seconds after which retry will happen
  retryLimit: number // max number of retries if not resolved
  global: boolean // if true, full app is rate limited. ie. app is down
  rateLimitRemaining: number // Remaining rate limit
  rateLimitReset: number // delta seconds after which rate-limit will reset
}

For rate limiting scenarios using headers, add the following headers:

Note: Rate limit headers are inspired by IETF draft. For more information, visit IETF website

// Generic rate limit headers
export declare type RateLimitHeaders = {
  // The number of requests that can be made.
  'x-ratelimit-limit': string
  // The number of remaining requests that can be made.
  'x-ratelimit-remaining': string
  // The number of seconds(delta-seconds) until the rate limit resets.
  'x-ratelimit-reset': string
  // Returned only on HTTP 429 responses if the rate limit encountered is the global rate limit (not per-route).
  'x-ratelimit-global': string
  // The scope of the rate limit upto which it is valid. For example, "user" or "bot".
  'x-ratelimit-scope': string
  // The number of seconds after which the rate limit resets.
  'retry-after': string
}

NOTE: Retry will occur regardless of the error status code if a retry-after time is provided in headers or body.