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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@aidanuno/use-fetch-event-source

v0.2.0

Published

React hook for Azure/fetch-event-source. For making Event Source requests, with all the features of fetch()

Readme

useFetchEventSource

React hook for Azure/fetch-event-source.

Features

The main aim of this library is to extend the utility of Azure/fetch-event-source, making dealing with Server-Sent Events more flexible than with the native EventSource API in React.

From Azure/fetch-event-source:

This library provides an alternate interface for consuming server-sent events, based on the Fetch API. It is fully compatible with the Event Stream format, so if you already have a server emitting these events, you can consume it just like before. However, you now have greater control over the request and response so:

  • You can use any request method/headers/body, plus all the other functionality exposed by fetch(). You can even provide an alternate fetch() implementation, if the default browser implementation doesn't work for you.
  • You have access to the response object if you want to do some custom validation/processing before parsing the event source. This is useful in case you have API gateways (like nginx) in front of your application server: if the gateway returns an error, you might want to handle it correctly.
  • If the connection gets cut or an error occurs, you have full control over the retry strategy.

In addition, this library also plugs into the browser's Page Visibility API so the connection closes if the document is hidden (e.g., the user minimizes the window), and automatically retries with the last event ID when it becomes visible again. This reduces the load on your server by not having open connections unnecessarily (but you can opt out of this behavior if you want.)

useFetchEventSource

  • Easy Integration: Simplifies the use of Server-Sent Events (SSE) in React applications.
  • Customizable: Provides hooks for handling SSE events such as onOpen, onError, onEventMessage, onClose.
  • Includes all fetch API request features: Allows you to pass custom fetch request init options, including headers, method, and body, ensuring full control over establishing a connection.
  • Retry Logic: Ability to implement custom retry logic very easily (e.g. exponential backoff, jitter).
  • Visibility Handling: Using the Page Visibility API, close connection to save server resources while your application is hidden from the user.
  • Sensible defaults: Follows the default behavior of the native EventSource API (retry on remote close or error), while still being able to customise the behaviour by providing your own callbacks.

Installation

npm i @aidanuno/use-fetch-event-source
yarn add @aidanuno/use-fetch-event-source
pnpm add @aidanuno/use-fetch-event-source

Usage

Retry strategy

  • By default, the hook follows the behavior of the EventSource API, where errors and remotely closed connections will trigger a retry.
  • If the onClose and onError callbacks aren't defined, the default retry interval is 1000ms.
  • The retry interval will be updated if any event messages provide a retry interval field.
  • You can define custom intervals and control whether to stop retrying by returning either the interval (in milliseconds) or false from the onClose and onError callbacks.

Detailed example

import React, { useState, useEffect } from "react";
import { useAuth } from "@/lib/auth";
import type { FetchEventSourceMessage } from "@aidanuno/use-fetch-event-source";
import { useFetchEventSource, FetchEventSourceOpenError } from "@aidanuno/use-fetch-event-source";

class FatalErrorExample extends Error {}

export default function App() {
    const { bearerToken } = useAuth();

    const { open, close, eventMessage, lastEventId, readyState, retryInterval } = useFetchEventSource("/api/v1/sse", {
        /**
         * Called when a response is received. Use this to validate that the response
         * actually matches what you expect (and throw if it doesn't.) If this callback is undefined,
         * will default to a basic validation to ensure the response is valid, will throw FetchEventSourceOpenError if invalid.
         */
        onOpen: async (response) => {
            return;
        },
        /**
         * Called when there is any error making the request / processing messages /
         * handling callbacks etc. Use this to control the retry strategy: Return false to stop retrying based on error.
         * If this callback is undefined, the connection will be retried using the given retry interval (default or value provided in latest event message).
         *
         * @param err - The error that occurred.
         * @param retries - The number of consecutive retries on error events that have been attempted. Resets to 0 on successful connection (open).
         * @returns {number|false} A number representing the interval (in milliseconds) after which the request will retry, or false to end retrying.
         */
        onError: (err, retries) => {
            const maxRetries = 100;
            if (retries >= maxRetries) return false; //stop retrying
            if (err instanceof FatalErrorExample) return false; //stop retrying
            if (err instanceof FetchEventSourceOpenError) {
                /**
                 * Handle invalid SSE response (according to spec https://html.spec.whatwg.org/multipage/server-sent-events.html).
                 * FetchEventSourceOpenError only thrown when onOpen callback is not defined.
                 */
                if (err.response.status === 401) {
                    //request new token...
                }
            }

            const newInterval = retryInterval * Math.pow(2, retries) + Math.random() * 1000; //Exponential backoff with jitter, easy to implement.
            return newInterval;
        },
        /**
         * Called when a message is received. NOTE: Unlike the default browser
         * EventSource.onmessage, this callback is called for _all_ events,
         * even ones with a custom `event` field.
         */
        onEventMessage: (ev) => {
            console.log(ev);
            /**
             * Example event:
             * { data: "data", id: "id", retry: 1000, event: "event" }
             */
        },
        /**
         * Called when the server terminates the connection (without error), response finished.
         * @returns {number|false} A number representing the interval (in milliseconds) after which the request will retry, or false to end retrying.
         */
        onClose: () => false,
        /** The Fetch function to use. Defaults to window.fetch */
        fetch: window.fetch,
        /**
         * If true, the event source connection will remain open even when the document is hidden. Defaults to true. Uses the Page Visibility API. https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
         */
        openWhenHidden: true,
        /**
         * Whether to open the connection immediately. Defaults to true, same as native EventSource.
         */
        initiallyOpen: true,
        /**
         * If neither onClose nor onError are defined, the connection will be retried using this interval otherwise a default interval of 1000ms will be used.
         */
        defaultRetryInterval: 1000,
        /**
         * The fetch request init options to use when making the request.
         * Whenever these are changed, the connection will be closed and reopened.
         * For example, a new Authorization header would require a new connection.
         * To have more control, use the open and close functions while changing fetchRequestInit.
         */
        fetchRequestInit: {
            headers: {
                Authorization: `Bearer ${bearerToken}`
            },
            /**
             * Note the 'Last-Event-ID' header is automatically sent on retry (just like the native EventSource API does), including when closing and then reopening the connection using the close/open functions returned.
             * This can be easily overriden by providing a 'Last-Event-ID' header.
             */
            credentials: "include" //Equivalent to EventSource API EventSourceInit withCredentials: true.
        }
    });

    const [events, setEvents] = useState<FetchEventSourceMessage[]>([]);

    useEffect(() => {
        if (eventMessage) {
            setEvents((prev) => [...prev, eventMessage]);
        }
    }, [eventMessage]);
    return (
        <div>
            <h2>useFetchEventSource</h2>
            <button onClick={open}>Open Connection</button>
            <button onClick={close}>Close Connection</button>
        </div>
    );
}

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

Commits use https://www.conventionalcommits.org/en/v1.0.0/ format.