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

fatcher

v3.0.2

Published

Send fetch request gracefully in browsers and nodeJS

Readme

Fatcher

Send fetch requests gracefully in browsers and Node.js

Introduction

Fatcher is a lightweight HTTP request library based on the native fetch API. It works seamlessly in both browsers and Node.js environments.

Features

  • Fully compatible with the Fetch API
  • Zero dependencies
  • Less than 1kb
  • Works in Node.js and all modern browsers
  • Composable middleware
  • Streaming API support

Compatibility

| Platform | Version | | ----------------- | ------------- | | Chrome | >= 66 | | Firefox | >= 65 | | Safari | >= 12.1 | | Edge | >= 16 | | Opera | >= 53 | | Internet Explorer | Not Supported | | Node.js | >= 18.0.0 |

Installation

NPM

npm install fatcher

CDN

<script src="https://cdn.jsdelivr.net/npm/fatcher/dist/fatcher.min.js"></script>
<script>
  Fatcher.fatcher('xxx', {}).then(response => {
    console.log(response);
  });
</script>

Quick Start

import { fatcher } from 'fatcher';

const init: RequestInit = {};
fatcher('https://foo.bar', init);

// equivalent to native fetch
fetch('https://foo.bar', init);

Middlewares

Fatcher uses a middleware system similar to Koa.

export interface FatcherOptions extends RequestInit {
  middlewares?: FatcherMiddlewares | FatcherMiddlewares[];
}

export interface FatcherContext extends Omit<FatcherOptions, 'middlewares'> {
  request: Request;
}

export type FatcherFunctionalMiddleware = (
  request: FatcherContext,
  next: (context?: Partial<FatcherContext>) => Promise<FatcherResponse> | FatcherResponse,
) => Promise<FatcherResponse> | FatcherResponse;

export type FatcherMiddleware = {
  name: string;
  use: FatcherFunctionalMiddleware;
};
  • FunctionalMiddleware runs every time it is used.
  • ObjectMiddleware is registered only once, respecting the registration order.

Custom Middleware

// fatcher.d.ts
import 'fatcher';

declare module 'fatcher' {
  // expand fatcher options for custom options
  interface FatcherOptions {
    baseUrl?: number;
  }
}

// middleware.ts
import { defineMiddleware } from 'fatcher';
const baseUrlMiddleware = defineMiddleware({
  name: 'base-url',
  use: async (context, next) => {
    const target = `${context.baseUrl}/${context.url}`;
    return next({ request: new Request(target, context.request), url: target });
  },
});

// api.ts
fatcher('/foo.bar', {
  baseUrl: 'https://api.example.com',
}).then(response => {
  // do something
});

Examples

Logger Middleware

import { defineMiddleware } from 'fatcher';

const logs = defineMiddleware(async (request, next) => {
  const startTime = Date.now();

  const response = await next();

  console.log(`Request spent ${Date.now() - startTime}ms`);
  return response;
});

fatcher('https://foo.bar', { middlewares: [logs] }); // Request spent 20 ms

Custom Request

import { defineMiddleware } from 'fatcher';

const request = defineMiddleware({
  name: 'my-custom-request',
  use: async context => {
    const response = await myFetch(context.url);
    return response;
  },
});
// custom request should register at last
fatcher('https://foo.bar', { middlewares: [request] });

Request Interceptor

import { defineMiddleware } from 'fatcher';

const requestInterceptor = defineMiddleware({
  name: 'request-interceptor',
  use: async (context, next) => {
    const accessToken = localStorage.get('AccessToken');

    if (accessToken) {
      context.request.headers.set('Authorization', accessToken);
    }

    return next();
  },
});

Response Interceptor

import { defineMiddleware, fatcher } from 'fatcher';

const responseInterceptor = defineMiddleware({
  name: 'response-interceptor',
  use: async (context, next) => {
    const response = await next();

    // rewrite response body
    return new Response('success', response);
  },
});

fatcher('https://foo.bar', {
  middlewares: [responseInterceptor],
}).then(response => {
  const text = await response.text();
  console.log(text); // 'success'2
});

Video Transformer

// fatcher.d.ts
import 'fatcher';

declare module 'fatcher' {
  interface FatcherResponse {
    getMp4: () => Promise<File>;
  }
}

// middleware.ts
import { defineMiddleware, fatcher } from 'fatcher';

const videoTransformer = defineMiddleware({
  name: 'video-transformer',
  use: async (context, next) => {
    const response = await next();

    const videoResponse = response.clone();

    response.getMp4 = () => {
      return new Promise((resolve, reject) => {
        // video transform
        console.log(videoResponse);
      });
    };

    return response;
  },
});

// api.ts
const response = await fatcher('https://video.examples.com/foo.avi', {
  middlewares: [videoTransformer],
});

const mediaSource = new MediaSource();
const url = URL.createObjectURL(mediaSource);
mediaSource.onsourceopen = async () => {
  // read response readableStream for data;
};
const video = document.querySelector('#video');
video.src = url;

const transformedFile = await response.getMp4();
// download mp4 file

Packages

License

MIT