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

@numaris-microfront/event-bus

v0.2.1

Published

Event Bus pub/sub con retencion del ultimo valor por tipo de evento, agnostico de framework y de dominio.

Readme

@numaris-microfront/event-bus

Event Bus pub/sub agnostico de framework y de dominio: no sabe que es React, no sabe que es un trackable ni un comando. Su unico trabajo es entregar eventos entre partes de una aplicacion que no se importan entre si — el caso tipico es una arquitectura de micro-frontends, donde el host y cada remoto son bundles separados y nunca deberian importarse en el codigo.

Si estas construyendo un widget para la plataforma Numaris, probablemente no instales este paquete directo: usa @numaris-microfront/contracts, que expone numarisBus — la misma instancia de este bus, ya tipada con los eventos de dominio de la plataforma (trackable.selected, trackable.list.updated, etc.). Instala este paquete directo solo si necesitas el bus crudo, sin esos tipos.

Por que "retiene el ultimo valor"

La diferencia con un EventEmitter comun: cuando alguien se suscribe a un tipo de evento, recibe inmediatamente el ultimo valor emitido de ese tipo, si existe — no solo los que se emitan a partir de ahora. Eso resuelve un problema concreto de micro-frontends: si el widget A emite trackable.selected y el widget B se monta un segundo despues, B igual tiene que saber cual esta seleccionado. Sin retencion, el orden de montaje de los widgets cambiaria lo que cada uno ve — un bug dificil de reproducir porque depende de timing de red, no de codigo.

Instalacion

npm install @numaris-microfront/event-bus

Sin dependencias de runtime. type: module — es ESM puro.

Uso basico

import { createEventBus } from '@numaris-microfront/event-bus';

interface MyEvents {
  'user.selected': { userId: string | null };
  'cart.updated': { itemCount: number };
}

const bus = createEventBus<MyEvents>({ label: 'my-app' });

// Suscribirse. Por default, si ya hay un valor emitido de este tipo, se entrega de inmediato.
const unsubscribe = bus.on('user.selected', (payload, meta) => {
  console.log(payload.userId, meta.retained); // meta.retained: true si vino por replay
});

// Emitir. Todo suscriptor activo (y futuro, mientras dure el valor) lo recibe.
bus.emit('user.selected', { userId: 'u-123' });

// Cortar la suscripcion.
unsubscribe();

API

createEventBus<TMap>(options?)

Crea una instancia. TMap es un Record<string, unknown> — el mapa de tipo de evento a forma del payload. Cada instancia es independiente: dos createEventBus() no comparten estado.

interface EventBusOptions {
  /** Se invoca si un handler lanza una excepcion. El bus nunca la deja escapar
   *  hacia quien emitio: un suscriptor que falla no puede tumbar a los demas. */
  onHandlerError?: (error: unknown, meta: EventMeta) => void;
  /** Etiqueta para diagnostico, aparece en `instanceId`. */
  label?: string;
}

Metodos de la instancia

| Metodo | Que hace | |---|---| | emit(type, payload) | Publica un valor. Se guarda como "ultimo valor" del tipo y se entrega a los suscriptores activos. | | on(type, handler, options?) | Se suscribe. Devuelve una funcion para desuscribirse. Por default entrega el ultimo valor retenido de inmediato (options.replayLast, default true). | | once(type, handler, options?) | Como on, pero se desuscribe solo despues de la primera entrega. | | onAny(handler) | Observa TODOS los eventos, sin replay. Pensado para diagnostico/logging, no para logica de negocio. | | getLast(type) | Lee el ultimo valor sin suscribirse. Devuelve { payload, emittedAt } o undefined. | | snapshot() | Devuelve todos los valores retenidos, de todos los tipos. Para paneles de diagnostico. | | clearRetained(type?) | Olvida el ultimo valor de un tipo (o de todos, sin argumento). No cancela suscripciones. Util al cerrar sesion o cambiar de tenant, para que el proximo widget que monte no reciba por replay datos de un contexto anterior. | | listenerCount(type) | Cantidad de suscriptores activos de un tipo. Para tests/diagnostico. | | reset() | Borra suscripciones y valores retenidos. Para tests. | | instanceId | Identifica la instancia en memoria. Si dos partes de tu app ven un instanceId distinto para lo que debia ser el mismo bus compartido, tu bundler esta duplicando el paquete en vez de compartirlo (ver seccion siguiente). |

EventMeta (segundo argumento de cada handler)

interface EventMeta {
  type: string;
  emittedAt: number;  // epoch ms de la emision original, no de la entrega
  retained: boolean;  // true si llego por replay al suscribirse, no por una emision en vivo
}

El punto critico si lo usas en Module Federation (o cualquier arquitectura multi-bundle)

Este bus solo funciona como mecanismo de comunicacion entre widgets si todos comparten la misma instancia en memoria. Si tu host y cada remoto cargan su propia copia del paquete (porque no esta declarado como dependencia compartida singleton en tu configuracion de Module Federation, Webpack o Vite), vas a tener N instancias distintas que nunca se hablan entre si — y el sintoma no es un error: la app carga, cada widget renderiza, y simplemente nunca reciben los eventos del otro. Nada rompe visiblemente.

Para detectarlo en desarrollo, compara instanceId entre dos partes que deberian compartir bus: si difiere, hay una copia duplicada del paquete en el bundle.

Si usas Vite + @originjs/vite-plugin-federation (u otro plugin de Module Federation), declara este paquete como singleton: true en el bloque shared de cada remoto y del host.