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

@qfetch/middleware-retry-status

v0.0.0-reserved.0

Published

Fetch middleware for RFC 9110-compliant status code retry handling.

Readme

@qfetch/middleware-retry-status

Fetch middleware that automatically retries requests based on response status codes with configurable backoff strategies.

Overview

Implements automatic retry logic following RFC 9110 semantics for transient error responses. When a request fails with a retryable status code (by default 408, 429, 500, 502, 503, 504), this middleware automatically retries using configurable backoff strategies from @proventuslabs/retry-strategies.

Intended for use with the composable middleware system provided by @qfetch/core.

Important Limitations

Replayable vs. Non-Replayable Bodies Most request bodies — such as strings, Blob, ArrayBuffer, Uint8Array, FormData, and URLSearchParams — are replayable. Fetch recreates their internal body stream for each retry attempt, so these requests can be retried safely without any special handling.

Non-Replayable Bodies (Streaming Bodies) Requests whose body is a non-replayable type — such as ReadableStreamcannot be retried according to the Fetch specification. Attempting to retry such requests results in a TypeError because the body stream has already been consumed.

To support retries for streaming bodies, you must provide a body factory using a middleware downstream that creates a fresh stream for each retry.

Installation

npm install @qfetch/middleware-retry-status @proventuslabs/retry-strategies

API

withRetryStatus(options)

Creates a middleware that retries failed requests based on response status codes.

Options

  • strategy: () => BackoffStrategy (required) - Factory function that creates a backoff strategy for retry delays
    • The strategy determines how long to wait between retry attempts
    • Controls when to stop retrying by returning NaN
    • A new strategy instance is created for each request chain
    • Use upto() wrapper from @proventuslabs/retry-strategies to limit retry attempts
    • Common strategies: linear(), exponential(), fullJitter()
  • retryableStatuses?: ReadonlySet<number> - Set of HTTP status codes that trigger automatic retries (default: new Set([408, 429, 500, 502, 503, 504]))
    • Only responses with these status codes will be retried
    • Override to customize which status codes should trigger retry behavior
    • Common codes: 408 (Request Timeout), 429 (Too Many Requests), 500 (Internal Server Error), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout)
    • Use an empty set (new Set()) to disable all automatic retries

Behavior

  • Successful responses (status 2xx) are returned immediately without retrying
  • Retryable statuses - By default, only 408, 429, 500, 502, 503, and 504 status codes trigger retry logic. This can be customized using the retryableStatuses option
  • Non-retryable statuses - Client errors (4xx except 408 and 429) and other status codes are returned immediately without retrying
  • Backoff strategy:
    • The strategy determines how long to wait between retry attempts
    • Strategy controls when to stop retrying by returning NaN
    • Use upto() wrapper to limit the number of retry attempts
    • Common strategies include linear(), exponential(), and fullJitter()
  • Request body cleanup:
    • Automatically cancels the response body stream before retrying to prevent memory leaks
    • This is a best-effort operation that won't block retries if cancellation fails
  • Error handling:
    • Exceeding INT32_MAX (2,147,483,647 milliseconds or ~24.8 days) for delay throws a RangeError
    • When the strategy returns NaN, retrying stops and the last response is returned (no error thrown)
  • Cancellation support:
    • Respects AbortSignal passed via request options or Request object
    • Cancellation during retry wait period immediately aborts and throws the abort reason
    • Cancellation during retry request execution propagates the abort signal to the fetch call

Usage

Basic usage with linear backoff

import { withRetryStatus } from '@qfetch/middleware-retry-status';
import { linear, upto } from '@proventuslabs/retry-strategies';

const qfetch = withRetryStatus({
  strategy: () => upto(3, linear(1000, 10_000)) // Maximum 3 retries
})(fetch);

const response = await qfetch('https://api.example.com/data');

With exponential backoff

import { withRetryStatus } from '@qfetch/middleware-retry-status';
import { exponential, upto } from '@proventuslabs/retry-strategies';

const qfetch = withRetryStatus({
  strategy: () => upto(5, exponential(500, 30_000, 2)) // Maximum 5 retries, doubling delay
})(fetch);

const response = await qfetch('https://api.example.com/data');

With jitter (recommended to prevent thundering herd)

import { withRetryStatus } from '@qfetch/middleware-retry-status';
import { fullJitter, upto } from '@proventuslabs/retry-strategies';

const qfetch = withRetryStatus({
  strategy: () => upto(3, fullJitter(100, 10_000))
})(fetch);

const response = await qfetch('https://api.example.com/data');

With custom retryable status codes

import { withRetryStatus } from '@qfetch/middleware-retry-status';
import { linear, upto } from '@proventuslabs/retry-strategies';

// Only retry on rate limits and gateway errors
const qfetch = withRetryStatus({
  strategy: () => upto(3, linear(1000, 10_000)),
  retryableStatuses: new Set([429, 502, 503])
})(fetch);

const response = await qfetch('https://api.example.com/data');

Notes

  • Requests are retried with the exact same parameters (URL, method, headers, body, etc.)
  • Response bodies are automatically cancelled before retrying to prevent memory leaks
  • By default, the middleware retries on 408, 429, 500, 502, 503, and 504 status codes (customizable via retryableStatuses option)
  • Use the upto() wrapper to limit the number of retry attempts
  • This middleware does not automatically respect Retry-After headers - use @qfetch/middleware-retry-after for that behavior
  • See @proventuslabs/retry-strategies for available backoff strategies