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

@fehnomenal/emit-typed-server-sent-events

v3.0.0

Published

This library contains helpers to convert events from a node.js event emitter to a event stream for [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) and handle them on the client side with type safety (via `@microso

Readme

@fehnomenal/emit-typed-server-sent-events

This library contains helpers to convert events from a node.js event emitter to a event stream for server-sent events and handle them on the client side with type safety (via @microsoft/fetch-event-source).

Installation

Choose the one for your package manager.

npm install '@fehnomenal/emit-typed-server-sent-events
yarn install '@fehnomenal/emit-typed-server-sent-events
pnpm install '@fehnomenal/emit-typed-server-sent-events
bun add '@fehnomenal/emit-typed-server-sent-events

Server side

  1. Create an event emitter (optionally with typed events which I recommend).
  2. Configure an event streamer that filters events and optionally maps the data to send. The filter functions can optionally access a context argument.
  3. Respond to requests.
import { defineMapFor } from '@fehnomenal/emit-typed-server-sent-events';
import EventEmitter from 'node:events';

// 1. Create an event emitter (optionally with typed events which I recommend).
const jobEmitter = new EventEmitter<{
  start: [id: string];
  progress: [id: string, current: number, total: number];
  finish: [id: string];
}>();

// 2. Configure an event streamer.
const jobStreamer = defineMapFor(jobEmitter)
  // You have to specify which events to handle.
  .switchEvents({
    // We do not care about the `start` event and omit it here.

    // We want to throttle the rate of `progress` events.
    progress(id, current, total) {
      const percent = current / total;
      if (percent % 5 === 0) {
        // Needs either a const assertion or a specific return type. Otherwise the type at the
        // frontend would be (string | number)[].
        return [id, percent] as const;
      }

      // Skip this event.
      return false;
    },

    // Pass the data of the `finish` event unaltered.
    finish: true,
  });

// 3. Respond to requests. This is a sveltekit server endpoint but the library should work
// everywhere you can return a web response.
export const GET = (event) => {
  // Optionally check authentication.

  return jobStreamer.streamEvents();
};

// Now emit events into your emitter to pass them to listening clients.
jobEmitter.emit('start', 'job-1');
jobEmitter.emit('progress', 'job-1', 1, 100);
jobEmitter.emit('finish', 'job-1');

// Export for the frontend.
export type { jobStreamer };

You can also call defineMapFor(..).withContext<{ ... }>() to get access to a context value inside the event forwarding functions. In this example from a chat application only message events shall be streamed that belong to the current chat window:

const messageEmitter = new EventEmitter<{
  msg: [chatId: string, message: string];
}>();

const messageStreamer = defineMapFor(messageEmitter)
  .withContext<{ chatId: string }>()
  .switchEvents({
    msg(chatId, _message, ctx) {
      return chatId === ctx.chatId;
    },
  });

export const GET = (event) => {
  return messageStreamer.streamEvents({ chatId: event.params.chat_id });
};

export type { messageStreamer };

Client side

Call listenToEvents with the url to your endpoint, a map of event handlers and optionally config that is passed to @microsoft/fetch-event-source. The event handler arguments are typed from the sse emitter.

import { listenToEvents } from '@fehnomenal/emit-typed-server-sent-events';
import type { jobStreamer } from './server.js';

const sse = listenToEvents<typeof jobStreamer>(
  '/endpoint/url',
  {
    progress(id, percent) {
      if (percent === 0) {
        console.log('started job', id);
      } else {
        console.log('job progress', id, percent.toLocaleString(undefined, { style: 'percent' }));
      }
    },
    finish(id) {
      console.log('finished job', id);
    },
  },
  {
    // @microsoft/fetch-event-source config
    // signal: ...
  },
);

// You can abort the event source. This is only available if you didn't pass a `signal` to the `listenToEvents` call.
sse.abort();

// You can await the closing of the connection.
await sse.promise;

Development and publishing

Dev

> bun i
> git switch -c ...
> # work work work and commit stuff
> # add a changeset if it is an user-visible change
> bun changeset
> git add .changeset
> git commit -m "changeset"
> git push

Publish

Publishing is done through the changesets bot and action.