
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@meistrari/fetch
Advanced tools
Reliable HTTP client built on fetch with automatic retries, timeouts, and better error handling
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.
Most existing HTTP libraries either:
@meistrari/fetch solves these problems by:
# Using bun
bun add @meistrari/fetch
# Using npm
npm install @meistrari/fetch
# Using yarn
yarn add @meistrari/fetch
# Using pnpm
pnpm add @meistrari/fetch
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
})
When you set retry: true
, the library uses these defaults:
Retry-After
headers// Enable default retry behavior
const response = await fetch('https://api.example.com/data', {
retry: true
})
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
}
})
The library automatically detects and retries these network errors:
ECONNRESET
- Connection reset by peerETIMEDOUT
- Connection timeoutECONNREFUSED
- Connection refusedEHOSTUNREACH
- Host unreachableENETUNREACH
- Network unreachableEPIPE
- Broken pipeFor 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 arraysBlob
, File
FormData
(if all entries are replayable)Non-replayable bodies (never retried):
ReadableStream
- Once consumed, it's goneFormData
containing streamsThis 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
]
}
})
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 retriedresponse
- Response (if request succeeded but needs retry)error
- Error object (if request failed)startedAt
- Timestamp of first attemptelapsedMs
- Total time elapsed since first attemptUse 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
})
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')
}
}
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
})
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
}
})
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
}
})
fetch(input, options?)
Main fetch function with enhanced capabilities.
input
: string | URL | Request
- The resource to fetchoptions
: FetchOptions
- Extended fetch options
fetch
options (method, headers, body, etc.)timeout?: number
- Request timeout in millisecondsretry?: true | RetryOptions | RetryDecider
- Retry configurationdispatcher?: unknown
- Custom dispatcher for Node.js/BuncreateFetch(defaultOptions)
Creates a fetch instance with default options.
defaultOptions
: FetchOptions
- Default options applied to all requestsisTimeoutError(error)
Type guard to check if an error is a timeout error.
FetchOptions
- Extended fetch optionsRetryOptions
- Retry configuration objectRetryDecider
- Custom retry decision functionRetryContext
- Context passed to retry functionsNetworkError
- Enum of retryable network errorsWe welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/meistrari/fetch.git
cd fetch
# Install dependencies
bun install
# 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
# Type checking
bun run typecheck
# Linting
bun run lint
# Fix linting issues
bun run lint:fix
# Check for unused dependencies
bun run unused
bun run build
Built with ❤️ by Meistrari
FAQs
Reliable HTTP client built on fetch with automatic retries, timeouts, and better error handling
The npm package @meistrari/fetch receives a total of 160 weekly downloads. As such, @meistrari/fetch popularity was classified as not popular.
We found that @meistrari/fetch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
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.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.