Socket
Book a DemoInstallSign in
Socket

@meistrari/fetch

Package Overview
Dependencies
Maintainers
5
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@meistrari/fetch

Reliable HTTP client built on fetch with automatic retries, timeouts, and better error handling

0.0.2
latest
npmnpm
Version published
Weekly downloads
160
Maintainers
5
Weekly downloads
 
Created
Source

@meistrari/fetch

A reliable HTTP client built on the native fetch API with automatic retries, timeouts, and better error handling. This library extends fetch rather than replacing it, making it a true drop-in replacement with superpowers.

Why @meistrari/fetch?

Most existing HTTP libraries either:

  • Create entirely new HTTP clients with different APIs
  • Don't properly handle network errors (ECONNRESET, ETIMEDOUT, etc.)
  • Leave retry logic and error handling to the developer
  • Add significant bundle size and complexity

@meistrari/fetch solves these problems by:

  • 🎯 Extending native fetch - Same API you know and love, just more reliable
  • 🔄 Smart retries - Automatically retries on network errors and configurable status codes
  • Zero-overhead when not needed - Uses native fetch directly when no extra features are configured
  • 🛡️ Network error handling - Properly detects and retries transient network failures
  • ⏱️ Built-in timeouts - Prevent requests from hanging indefinitely
  • 📦 Tiny footprint - Minimal dependencies, tree-shakeable

Installation

# Using bun
bun add @meistrari/fetch

# Using npm
npm install @meistrari/fetch

# Using yarn
yarn add @meistrari/fetch

# Using pnpm
pnpm add @meistrari/fetch

Usage

Basic Usage

import { fetch } from '@meistrari/fetch'

// Works exactly like native fetch
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// With timeout
const response = await fetch('https://api.example.com/data', {
  timeout: 5000 // 5 second timeout
})

// With retries (uses sensible defaults)
const response = await fetch('https://api.example.com/data', {
  retry: true
})

Retry Configuration

Default Retry Behavior

When you set retry: true, the library uses these defaults:

  • Retries up to 3 times
  • Retries on network errors (ECONNRESET, ETIMEDOUT, etc.)
  • Retries on status codes: 429, 500, 502, 503, 504
  • Uses exponential backoff starting at 200ms
  • Respects Retry-After headers
  • Only retries safe methods (GET, HEAD, OPTIONS)
// Enable default retry behavior
const response = await fetch('https://api.example.com/data', {
  retry: true
})

Custom Retry Configuration

const response = await fetch('https://api.example.com/data', {
  retry: {
    max: 5,                          // Maximum retry attempts
    delay: 300,                      // Initial delay in ms
    backoffFactor: 2,                // Exponential backoff multiplier
    maxDelay: 30000,                 // Maximum delay between retries
    on: [429, 500, 503],            // Status codes to retry on
    methods: ['GET', 'POST'],        // HTTP methods to retry
    respectHttpRetryHeader: true     // Respect Retry-After header
  }
})

Network Error Handling

The library automatically detects and retries these network errors:

  • ECONNRESET - Connection reset by peer
  • ETIMEDOUT - Connection timeout
  • ECONNREFUSED - Connection refused
  • EHOSTUNREACH - Host unreachable
  • ENETUNREACH - Network unreachable
  • EPIPE - Broken pipe
  • And more...

Body Replayability

For safety, the library automatically prevents retrying requests with non-replayable bodies to avoid data corruption:

Replayable bodies (safe to retry):

  • null or undefined
  • string, URLSearchParams
  • ArrayBuffer, Uint8Array, other typed arrays
  • Blob, File
  • FormData (if all entries are replayable)

Non-replayable bodies (never retried):

  • ReadableStream - Once consumed, it's gone
  • Node.js streams - Can only be read once
  • FormData containing streams
  • Response bodies that have been consumed

This behavior is always active and cannot be disabled - it's a safety feature to prevent sending corrupted or empty data on retry attempts.

import { NetworkError } from '@meistrari/fetch'

// Retry on specific network errors and status codes
const response = await fetch('https://api.example.com/data', {
  retry: {
    max: 3,
    on: [
      NetworkError.ECONNRESET,
      NetworkError.ETIMEDOUT,
      429,
      503
    ]
  }
})

Custom Retry Logic

You can provide a custom retry decision function for complete control:

const response = await fetch('https://api.example.com/data', {
  retry: (context) => {
    // Don't retry on 4xx errors (except 429)
    if (context.response?.status && context.response.status >= 400 && context.response.status < 500) {
      return context.response.status === 429 ? 1000 : false
    }
    
    // Stop after 3 attempts
    if (context.attempt >= 3) return false
    
    // Custom exponential backoff
    return Math.min(1000 * Math.pow(2, context.attempt), 10000)
  }
})

The retry context provides:

  • attempt - Current attempt number (0-indexed)
  • request - The Request object being retried
  • response - Response (if request succeeded but needs retry)
  • error - Error object (if request failed)
  • startedAt - Timestamp of first attempt
  • elapsedMs - Total time elapsed since first attempt

Creating Pre-configured Instances

Use createFetch to create a fetch instance with default options:

import { createFetch } from '@meistrari/fetch'

// Create an API client with defaults
const apiFetch = createFetch({
  timeout: 10000,
  retry: true,
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json'
  }
})

// Uses the pre-configured options
const response = await apiFetch('/api/users')

// Override specific options
const response = await apiFetch('/api/users', {
  timeout: 5000 // Override default timeout
})

Timeout Handling

import { isTimeoutError } from '@meistrari/fetch'

try {
  const response = await fetch('https://slow-api.example.com', {
    timeout: 3000 // 3 second timeout
  })
} catch (error) {
  if (isTimeoutError(error)) {
    console.log('Request timed out')
  }
}

Advanced Examples

Combining with AbortController

const controller = new AbortController()

// Abort after 5 seconds
setTimeout(() => controller.abort(), 5000)

const response = await fetch('https://api.example.com/data', {
  signal: controller.signal,
  timeout: 10000,
  retry: true
})

File Upload with Retry

const formData = new FormData()
formData.append('file', file)

const response = await fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData,
  timeout: 60000, // 1 minute timeout for uploads
  retry: {
    max: 3,
    on: [408, 429, 503] // Only retry on specific errors
  }
})

Custom Retry for Rate Limiting

const response = await fetch('https://api.example.com/data', {
  retry: (ctx) => {
    // Handle rate limiting with jitter
    if (ctx.response?.status === 429) {
      const retryAfter = ctx.response.headers.get('Retry-After')
      const delay = retryAfter ? parseInt(retryAfter) * 1000 : 60000
      // Add jitter to prevent thundering herd
      return delay + Math.random() * 1000
    }
    
    // Exponential backoff for other errors
    if (ctx.attempt < 3) {
      return 1000 * Math.pow(2, ctx.attempt)
    }
    
    return false
  }
})

API Reference

fetch(input, options?)

Main fetch function with enhanced capabilities.

  • input: string | URL | Request - The resource to fetch
  • options: FetchOptions - Extended fetch options
    • All standard fetch options (method, headers, body, etc.)
    • timeout?: number - Request timeout in milliseconds
    • retry?: true | RetryOptions | RetryDecider - Retry configuration
    • dispatcher?: unknown - Custom dispatcher for Node.js/Bun

createFetch(defaultOptions)

Creates a fetch instance with default options.

  • defaultOptions: FetchOptions - Default options applied to all requests

isTimeoutError(error)

Type guard to check if an error is a timeout error.

Types

  • FetchOptions - Extended fetch options
  • RetryOptions - Retry configuration object
  • RetryDecider - Custom retry decision function
  • RetryContext - Context passed to retry functions
  • NetworkError - Enum of retryable network errors

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/meistrari/fetch.git
cd fetch

# Install dependencies
bun install

Running Tests

# Run all tests
bun test

# Run unit tests
bun test:unit

# Run E2E tests
bun test:e2e

# Run tests in watch mode
bun test:watch

Code Quality

# Type checking
bun run typecheck

# Linting
bun run lint

# Fix linting issues
bun run lint:fix

# Check for unused dependencies
bun run unused

Building

bun run build

Credits

Built with ❤️ by Meistrari

Keywords

fetch

FAQs

Package last updated on 02 Sep 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.