
Company News
Meet the Socket Team at RSAC and BSidesSF 2026
Join Socket for live demos, rooftop happy hours, and one-on-one meetings during BSidesSF and RSA 2026 in San Francisco.
@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 auth option with strategies:
// Bearer token authentication
const client = new FetchClient({
baseURL: "https://api.example.com",
auth: {
strategies: [
{
type: "bearer",
token: "your-token-here",
},
],
},
});
// Dynamic bearer token
const client = new FetchClient({
baseURL: "https://api.example.com",
auth: {
strategies: [
{
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",
auth: {
strategies: [
{
type: "basic",
username: "user",
password: "pass",
},
],
},
});
// API key in header
const client = new FetchClient({
baseURL: "https://api.example.com",
auth: {
strategies: [
{
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",
auth: {
strategies: [
{
type: "apiKey",
key: "your-api-key",
location: "query",
name: "api_key",
},
],
},
});
// Multiple authentication strategies
const client = new FetchClient({
baseURL: "https://api.example.com",
auth: {
strategies: [
{
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",
auth: {
strategies: [
{
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;
auth?: AuthConfig;
fetch?: typeof fetch;
credentials?: RequestCredentials;
}
interface AuthConfig {
strategies: AuthStrategy[];
}
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 0 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.

Company News
Join Socket for live demos, rooftop happy hours, and one-on-one meetings during BSidesSF and RSA 2026 in San Francisco.

Research
/Security News
Malicious Packagist packages disguised as Laravel utilities install an encrypted PHP RAT via Composer dependencies, enabling remote access and C2 callbacks.

Research
/Security News
OpenVSX releases of Aqua Trivy 1.8.12 and 1.8.13 contained injected natural-language prompts that abuse local AI coding agents for system inspection and potential data exfiltration.