
Security News
minimatch Patches 3 High-Severity ReDoS Vulnerabilities
minimatch patched three high-severity ReDoS vulnerabilities that can stall the Node.js event loop, and Socket has released free certified patches.
@blimu/fetch
Advanced tools
Universal HTTP fetch client with hooks, retries, and streaming support for browser and Node.js
Universal HTTP fetch client with hooks, retries, and streaming support for browser and Node.js.
npm install @blimu/fetch
# or
yarn add @blimu/fetch
# or
pnpm add @blimu/fetch
import { FetchClient } from '@blimu/fetch';
const client = new FetchClient({
baseURL: 'https://api.example.com',
headers: {
'Content-Type': 'application/json',
},
});
// Make a request
const data = await client.request({
path: '/users',
method: 'GET',
});
const client = new FetchClient({
baseURL: 'https://api.example.com',
headers: {
'X-Custom-Header': 'value',
},
timeoutMs: 5000,
credentials: 'include',
});
Authentication is configured using the authStrategies option:
// Bearer token authentication
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'bearer',
token: 'your-token-here',
},
],
});
// Dynamic bearer token
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'bearer',
token: async () => {
// Fetch or refresh token
return await getToken();
},
headerName: 'Authorization', // Optional, defaults to "Authorization"
},
],
});
// Basic authentication
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'basic',
username: 'user',
password: 'pass',
},
],
});
// API key in header
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'apiKey',
key: 'your-api-key',
location: 'header',
name: 'X-API-Key',
},
],
});
// API key in query parameter
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'apiKey',
key: 'your-api-key',
location: 'query',
name: 'api_key',
},
],
});
// Multiple authentication strategies
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'bearer',
token: 'token',
},
{
type: 'apiKey',
key: 'api-key',
location: 'header',
name: 'X-API-Key',
},
],
});
// Custom authentication strategy
const client = new FetchClient({
baseURL: 'https://api.example.com',
authStrategies: [
{
type: 'custom',
apply: async (headers, url) => {
// Custom authentication logic
const token = await getCustomToken();
headers.set('X-Custom-Auth', token);
},
},
],
});
The hooks system allows you to intercept and modify requests at different lifecycle stages.
beforeRequest: Before the request is made (can modify request)afterRequest: After response is received, before parsingafterResponse: After response is parsedonError: When an error occursbeforeRetry: Before a retry attemptafterRetry: After a retry attemptonTimeout: When a timeout occursonStreamStart: When streaming startsonStreamChunk: For each stream chunk (can transform)onStreamEnd: When streaming endsconst client = new FetchClient({
baseURL: 'https://api.example.com',
hooks: {
beforeRequest: [
(ctx) => {
// Add custom header
ctx.init.headers.set('X-Request-ID', generateId());
},
async (ctx) => {
// Refresh token if needed
const token = await refreshToken();
ctx.init.headers.set('Authorization', `Bearer ${token}`);
},
],
afterResponse: [
(ctx) => {
// Log response
console.log('Response:', ctx.data);
},
],
onError: [
(ctx) => {
// Log errors
console.error('Request failed:', ctx.error);
},
],
},
});
const client = new FetchClient({ baseURL: 'https://api.example.com' });
// Register a hook
client.useHook('beforeRequest', (ctx) => {
console.log('Making request to:', ctx.url);
});
// Remove a hook
const hook = (ctx) => console.log(ctx);
client.useHook('beforeRequest', hook);
client.removeHook('beforeRequest', hook);
// Clear all hooks for a stage
client.clearHooks('beforeRequest');
// Clear all hooks
client.clearHooks();
const client = new FetchClient({
baseURL: 'https://api.example.com',
retry: {
retries: 3,
strategy: 'exponential',
backoffMs: 100,
retryOn: [429, 500, 502, 503, 504],
},
});
const client = new FetchClient({
baseURL: 'https://api.example.com',
retry: {
retries: 3,
strategy: 'linear',
backoffMs: 200,
retryOn: [500, 502, 503],
},
});
const client = new FetchClient({
baseURL: 'https://api.example.com',
retry: {
retries: 3,
strategy: (attempt, baseBackoff) => {
// Custom delay calculation
return baseBackoff * (attempt + 1) * 2;
},
retryOn: [500],
retryOnError: (error) => {
// Custom retry condition
return error instanceof NetworkError;
},
},
});
for await (const chunk of client.requestStream({
path: '/events',
method: 'GET',
contentType: 'text/event-stream',
streamingFormat: 'sse',
})) {
console.log('Event:', chunk);
}
for await (const item of client.requestStream({
path: '/items',
method: 'GET',
contentType: 'application/x-ndjson',
streamingFormat: 'ndjson',
})) {
console.log('Item:', item);
}
for await (const chunk of client.requestStream({
path: '/stream',
method: 'GET',
contentType: 'application/octet-stream',
streamingFormat: 'chunked',
})) {
console.log('Chunk:', chunk);
}
The package provides specific error classes for different HTTP status codes, enabling instanceof checks in catch blocks.
4xx Client Errors:
BadRequestError (400)UnauthorizedError (401)ForbiddenError (403)NotFoundError (404)MethodNotAllowedError (405)ConflictError (409)UnprocessableEntityError (422)TooManyRequestsError (429)ClientError (generic 4xx)5xx Server Errors:
InternalServerError (500)BadGatewayError (502)ServiceUnavailableError (503)GatewayTimeoutError (504)ServerError (generic 5xx)import {
FetchClient,
NotFoundError,
UnauthorizedError,
ServerError,
} from '@blimu/fetch';
try {
await client.request({ path: '/users/123', method: 'GET' });
} catch (error) {
if (error instanceof NotFoundError) {
// Handle 404
console.log('User not found');
} else if (error instanceof UnauthorizedError) {
// Handle 401
console.log('Unauthorized - refresh token');
} else if (error instanceof ServerError) {
// Handle any 5xx
console.log('Server error:', error.status);
} else {
// Handle other errors
console.error('Unexpected error:', error);
}
}
Works out of the box in modern browsers (Chrome 42+, Firefox 39+, Safari 10.1+, Edge 14+):
import { FetchClient } from '@blimu/fetch';
const client = new FetchClient({
baseURL: 'https://api.example.com',
});
Node.js 22+: Native fetch is available, works out of the box.
Node.js < 22: Provide a custom fetch implementation:
import { FetchClient } from '@blimu/fetch';
import { fetch } from 'undici'; // or "node-fetch"
const client = new FetchClient({
baseURL: 'https://api.example.com',
fetch, // Provide custom fetch
});
new FetchClient(config?: FetchClientConfig)
request<T>(options: RequestOptions): Promise<T> - Make an HTTP requestrequestStream<T>(options: StreamingRequestOptions): AsyncGenerator<T> - Make a streaming requestaddAuthStrategy(strategy: AuthStrategy): void - Add an authentication strategyclearAuthStrategies(): void - Remove all authentication strategiesuseHook(stage: string, hook: Hook): void - Register a hookremoveHook(stage: string, hook: Hook): boolean - Remove a hookclearHooks(stage?: string): void - Clear hooksinterface FetchClientConfig {
baseURL?: string;
headers?: Record<string, string>;
timeoutMs?: number;
retry?: RetryConfig;
hooks?: HooksConfig;
authStrategies?: AuthStrategy[];
fetch?: typeof fetch;
credentials?: RequestCredentials;
}
type AuthStrategy =
| BearerAuthStrategy
| BasicAuthStrategy
| ApiKeyAuthStrategy
| CustomAuthStrategy;
interface RequestOptions extends RequestInit {
path: string;
method: string;
query?: Record<string, any>;
}
interface StreamingRequestOptions extends RequestOptions {
contentType: string;
streamingFormat?: 'sse' | 'ndjson' | 'chunked';
}
MIT
FAQs
Universal HTTP fetch client with hooks, retries, and streaming support for browser and Node.js
The npm package @blimu/fetch receives a total of 1 weekly downloads. As such, @blimu/fetch popularity was classified as not popular.
We found that @blimu/fetch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer 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.

Security News
minimatch patched three high-severity ReDoS vulnerabilities that can stall the Node.js event loop, and Socket has released free certified patches.

Research
/Security News
Socket uncovered 26 malicious npm packages tied to North Korea's Contagious Interview campaign, retrieving a live 9-module infostealer and RAT from the adversary's C2.

Research
An impersonated golang.org/x/crypto clone exfiltrates passwords, executes a remote shell stager, and delivers a Rekoobe backdoor on Linux.