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

@siggn/core

v0.2.0

Published

A lightweight message bus system for Typescript

Downloads

845

Readme

npm version

@siggn/core

A lightweight and type-safe event bus system for TypeScript projects.

Features

  • Type-Safe: Leverages TypeScript to ensure that message payloads are correct at compile and runtime.
  • Lightweight: Zero dependencies and a minimal API surface.
  • Simple API: Easy to learn and use, with a clear and concise API.

Installation

You can install the package using your favorite package manager:

npm install @siggn/core
yarn add @siggn/core
pnpm add @siggn/core

Usage

Here's a basic example of how to use Siggn:

import { Siggn } from '@siggn/core';

// 1. Define your message types
type Message =
  | { type: 'user_created'; userId: string; name: string }
  | { type: 'user_deleted'; userId: string };

// 2. Create a new Siggn instance
const siggn = new Siggn<Message>();

// 3. Subscribe to events
// Use a unique ID for each subscriber to manage subscriptions
const subscriberId = 'analytics-service';

siggn.subscribe(subscriberId, 'user_created', (msg) => {
  console.log(`[Analytics] New user created: ${msg.name} (ID: ${msg.userId})`);
});

// 4. Publish events
siggn.publish({ type: 'user_created', userId: '123', name: 'John Doe' });
// Output: [Analytics] New user created: John Doe (ID: 123)

// 5. Unsubscribe from all events for a given ID
siggn.unsubscribe(subscriberId);

siggn.publish({ type: 'user_created', userId: '456', name: 'Jane Doe' });
// No output, because the subscriber was removed.

Using the make helper

The make method simplifies managing subscriptions for a specific component or service.

const userComponent = siggn.make('user-component');

userComponent.subscribe('user_deleted', (msg) => {
  console.log(`[UI] User ${msg.userId} was deleted. Updating view...`);
});

siggn.publish({ type: 'user_deleted', userId: '123' });
// Output: [UI] User 123 was deleted. Updating view...

// Unsubscribe from all subscriptions made by 'user-component'
userComponent.unsubscribe();

Subscribing to multiple events

You can use subscribeMany to group subscriptions for a single subscriber.

const auditService = siggn.make('audit-service');

auditService.subscribeMany((subscribe) => {
  subscribe('user_created', (msg) => {
    console.log(`[Audit] User created: ${msg.name}`);
  });
  subscribe('user_deleted', (msg) => {
    console.log(`[Audit] User deleted: ${msg.userId}`);
  });
});

siggn.publish({ type: 'user_created', userId: '789', name: 'Peter Pan' });
siggn.publish({ type: 'user_deleted', userId: '123' });

// Unsubscribe from all audit-service events
auditService.unsubscribe();

Subscribing to all events

If you need to listen to every message that passes through the bus, regardless of its type, you can use subscribeAll. This is useful for cross-cutting concerns like logging or debugging.

const logger = siggn.make('logger-service');

logger.subscribeAll((msg) => {
  console.log(`[Logger] Received event of type: ${msg.type}`);
});

siggn.publish({ type: 'user_created', userId: '789', name: 'Peter Pan' });
// Output: [Logger] Received event of type: user_created

siggn.publish({ type: 'user_deleted', userId: '123' });
// Output: [Logger] Received event of type: user_deleted

// Unsubscribe from all logger-service events
logger.unsubscribe();

Extending message types with createClone

The createClone method allows you to create a new, independent Siggn instance that inherits the message types of its parent. This is useful for creating specialized message buses that extend a base set of events without affecting the parent bus.

// Continuing with the previous `Message` type...
const baseSiggn = new Siggn<Message>();

// 1. Define a new set of messages for a specialized module
type AdminMessage = { type: 'admin_login'; adminId: string };

// 2. Create a child bus that understands both `Message` and `AdminMessage`
const adminSiggn = baseSiggn.createClone<AdminMessage>();

// 3. Subscribe to events on the child bus
adminSiggn.subscribe('audit-log', 'user_created', (msg) => {
  console.log(`[Admin Audit] User created: ${msg.name}`);
});

adminSiggn.subscribe('auth-service', 'admin_login', (msg) => {
  console.log(`[Admin Auth] Admin logged in: ${msg.adminId}`);
});

// 4. Publish events on the child bus
adminSiggn.publish({ type: 'user_created', userId: 'abc', name: 'Alice' });
// Output: [Admin Audit] User created: Alice

adminSiggn.publish({ type: 'admin_login', adminId: 'xyz' });
// Output: [Admin Auth] Admin logged in: xyz

// Note: The parent and child buses are independent.
// Publishing on the parent does not affect the child's subscribers.
baseSiggn.publish({ type: 'user_created', userId: 'def', name: 'Bob' });
// No output, because the subscription is on `adminSiggn`.

Automatic Garbage Collection

Siggn is designed to prevent memory leaks even if subscriptions are not explicitly unsubscribed. It achieves this through the use of WeakRef and FinalizationRegistry:

While explicit unsubscribe calls are still good practice for immediate cleanup and control, Siggn provides a robust safety net against common memory leak scenarios.

Middleware

You can use middleware to intercept messages before they are delivered to subscribers. This is useful for logging, validation, or modifying messages.

const siggn = new Siggn<Message>();

// Register a middleware
const unsubscribeMiddleware = siggn.use(async (msg, next) => {
  console.log('Middleware received:', msg);
  
  // You can perform async operations
  await someAsyncCheck(msg);
  
  // Call next() to proceed to the next middleware or deliver the message
  next();
});

// Unregister the middleware when no longer needed
unsubscribeMiddleware();

API

new Siggn<T>()

Creates a new message bus instance.

  • T: A union type representing all possible messages.

publish(msg)

Publishes a message to all relevant subscribers.

  • msg: The message object to be published. It must conform to the Msg type.

subscribe(id, type, callback)

Subscribes a callback to a specific message type.

  • id: A unique SiggnId (string) to identify the subscriber.
  • type: The type of the message to subscribe to.
  • callback: A function that executes when a message of the specified type is published. It receives the message as its only argument.

subscribeAll(id, callback)

Subscribes a callback to all message types.

  • id: A unique SiggnId to identify the subscriber.
  • callback: A function that executes for every message published. It receives the message as its only argument.

unsubscribe(id)

Removes all subscriptions (specific and global) associated with a subscriber ID.

  • id: The SiggnId of the subscriber to remove.

unsubscribeGlobal(id)

Removes a global subscription for a given subscriber ID.

  • id: The SiggnId of the global subscriber to remove.

make(id)

Returns a helper object with subscribe, subscribeMany, subscribeAll, and unsubscribe methods pre-bound to the provided ID.

  • id: A SiggnId to pre-bind to the subscription methods.

subscribeMany(id, setup)

Subscribes to multiple message types for a single ID.

  • id: A SiggnId to identify the subscriber.
  • setup: A function that receives a subscribe helper to register multiple subscriptions under the same id.

createClone<C>()

Creates a new, independent Siggn instance that inherits the parent's message types and adds new ones.

  • C: A union type of additional message types for the new instance.

use(middleware)

Registers a middleware function.

  • middleware: A function (msg, next) => void | Promise<void>.
  • Returns: A function to unregister the middleware.

subscriptionsCount()

Returns the total number of subscriptions.

License

This project is licensed under the MIT License.