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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pawsaw/subscription-manager

v1.0.1

Published

Subscription Manager - Lightweight Utility for managing Subscriptions

Downloads

7

Readme

Subscription Manager

https://github.com/pawsaw/subscription-manager

What is it?

Subscription Manager - Lightweight JavaScript and TypeScript Utility for managing Subscriptions.

Why Subscription Manager?

  • Designed with one goal in mind: managing subscriptions.
  • No dependencies and an incredibly small footprint.
  • Developed in TypeScript, usable in TypeScript and JavaScript.
  • Elegant and easy to use.

The best way to describe a situation is often by Example.

Setup

npm i @pawsaw/subscription-manager

Subscription Manager API

Obtain an instance of Subscription Manager

At the beginning it is necessary to get an instance of the Subscription Manager.

import {
    createSubscriptionManager,
    SubscriptionManager,
    Subscription,
} from '@pawsaw/subscription-manager';

const sm: SubscriptionManager<string> = createSubscriptionManager();

Here string is the data type of the channel, as default. Other data types are acceptable, but less usual.

Here a Subscription Manager is created, where the channels are of the datatype number:

const sm: SubscriptionManager<number> = createSubscriptionManager<number>();

subscribe

We subscribe to a certain channel and define a callback function that takes any parameters. The parameters must be the same as in the counterpart, the publish method.

function onChatMessageReceived(msg: string): void {
    // ...
}

const sub = sm.subscribe('chatMessages', onChatMessageReceived);

The result of the subscribe method is a Subscription.

publish

To broadcast data, we use the publish method.

sm.publish('chatMessages', 'Hello World');

For all Subscribers on this channel the stored callback is called.

Typesafe publish and subscribe

In TypeScript it makes sense to get as much as possible out of static type checking.

interface OnChatMessageReceived {
    (msg: string): void;
}

const onChatMessageReceived: OnChatMessageReceived = (msg: string) => {
    // ...
};

const sub = sm.subscribe<OnChatMessageReceived>('chatMessages', onChatMessageReceived);

When publishing we can ensure the integrity of the parameters with respect to the type by explicitly specifying the type of the callback.

sm.publish<OnChatMessageReceived>('chatMessages', 'Hello World');

Note: The Subscription Manager may handle different types of callbacks on different channels.

free

If a subscription is no longer needed, be sure to free it.

sub.free();

Example (TypeScript): ChatService

We want to implement a ChatService that looks like this:

export interface OnChatMessageReceived {
    (msg: string): void;
}

export interface ChatService {
    onChatMessageReceived(listener: OnChatMessageReceived): Subscription;
}

... and a Client using it:

const chatService = ChatService.instance(); // ... access the instance somehow

const onChatMessageReceived: OnChatMessageReceived = (msg: string) => {
    console.log(`Got new message: ${msg}`);
};

// start listening for incomming messages
const sub = chatService.onChatMessageReceived(onChatMessageReceived);

// and if we're not longer interested in receiving messages ...
sub.free();

As you can see here, the ChatService may be a singleton (not mandatory), where several (!) clients may want to register to receive messages.

If a client is no longer interested in receiving the messages, he wants to free the Subscription.

Maybe you want to offer another method in the ChatService to get information about new ChatUsers, as the following example shows:

export interface OnChatMessageReceived {
    (msg: string): void;
}

export interface OnNewChatUser {
    (user: string): void;
}

export interface ChatService {
    onChatMessageReceived(listener: OnChatMessageReceived): Subscription;
    onNewChatUser(listener: OnNewChatUser): Subscription;
}

It is easy to see that the implementation of subscription management is quite complex and potentially repetitive.

Wouldn't it be nice to have a utility here that would make our work easier?

How to use the Subscription Manager?

import {
    createSubscriptionManager,
    SubscriptionManager,
    Subscription,
} from '@pawsaw/subscription-manager';

// [ ... ]

export interface OnChatMessageReceived {
    (msg: string): void;
}

export interface OnNewChatUser {
    (user: string): void;
}

export class ChatService {
    // Usually one SubscriptionManager per service
    private sm = createSubscriptionManager();

    private anyAsyncDatasource = any; // any async data source

    onChatMessageReceived(listener: OnChatMessageReceived): Subscription {
        return this.sm.subscribe('onChatMessageReceived', listener);
    }

    onNewChatUser(listener: OnNewChatUser): Subscription {
        return this.sm.subscribe('onNewChatUser', listener);
    }

    private initDataSource(): void {
        this.anyAsyncDatasource.receive((type: string, data: string) => {
            if (type === 'message') {
                this.sm.publish<OnChatMessageReceived>('onChatMessageReceived', data);
            } else if (type === 'user') {
                this.sm.publish<OnNewChatUser>('onNewChatUser', data);
            }
        });
    }
}

That's it folks!

Stay tuned and keep on coding.