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

hot-press

v2.1.5

Published

Event lifecycle management

Downloads

30

Readme

Hot Press

Coverage Status Build Status NPM Version Greenkeeper badge License

Hot Press is an event lifecycle management library for Node.js.

Installation

npm i hot-press

Examples

Standard PubSub

Basic PubSub architecture we're mostly familiar with. Using the on() function, you can add subscribers to events that are published using the emit() function.

import HotPress from 'hot-press';

const {emit, on} = new HotPress();
on('event', (eventName, ...data) => console.log(...data));
emit('event', 'some', 'variables');
// 'some' 'variables'

Subscribing to multiple events

Using the all function you can trigger a subscriber only once all the events have been emitted.

import HotPress from 'hot-press';

const {all, emit} = new HotPress();
all({on: ['event1', 'event2']}, () => console.log('Triggered!'));
emit('event1');
emit('event2');
// 'Triggered!'

Subscription hierarchy

Dots symbolize subscription hierarchy. Using the * operator, you can subscribe to all events under that hierarchy.

import HotPress from 'hot-press';

const {emit, on} = new HotPress();
on('*', e => console.log(2, e));
on('e.*', e => console.log(1, e));
emit('e.f');
// 1 e.f
// 2 e.f

Unsubscribe

Remove all or specific subscribers from events using the off() function.

import HotPress from 'hot-press';

const {emit, off, on} = new HotPress();
const fn = () => console.log('blah');

on('event', fn);
on('event', fn);
on('event', fn);

emit('event');
// blah
// blah
// blah

off('event', fn);
emit('event');
// blah
// blah

off('event');
emit('event');
// <nothing happens>

Subscribing to the beginning and end of events

There are 3 parts to an event lifecycle.

  1. "Before" the event
  2. "On" the event
  3. "After" the event

You can subscribe to any part of the event lifecycle using the appropriate function.

import HotPress from 'hot-press';

const {after, before, emit, off, on} = new HotPress();
before('event', () => console.log(1));
on('event', () => console.log(2));
after('event', () => console.log(3));
emit('event');
// 1
// 2
// 3
off('event');

after('event', () => console.log(3));
before('event', () => console.log(1));
on('event', () => console.log(2));
emit('event');
// 1
// 2
// 3

Asynchronous subscriptions

If your subscription returns a Promise then the next part of the event lifecycle will not be published until the promise has resolved.

Note: It will not delay subscriptions within the same part of the lifecycle, only those that are to be published next. For example, all subscriptions implemented with the on() function will wait until all subscriptions implemented with the before() function have been resolved.

And finally the emit function will return a promise that will resolve once the "after" part of the lifecycle has resolved.

import HotPress from 'hot-press';

const {after, before, emit, on} = new HotPress();
before('event', eventuallyLog(1));
on('event', eventuallyLog(2));
after('event', eventuallyLog(3));
emit('event').then(() => console.log(4));
// 1
// 2
// 3
// 4

function eventuallyLog(num) {
  return () => new Promise(resolve => {
    const log = () => {
      console.log(num);
      resolve();
    };
    setTimeout(log, random());
  });
}

function random(from=0, to=1000) {
  return Math.floor(Math.random() * to) + from;
}

Timeouts

There is a configurable timeout for these asynchronous events. By default it's 300ms, but it can be configured like so:

import HotPress from 'hot-press';

const emitter = new HotPress();
emitter.timeout = 1000; // global
emitter.ns('myNamespace').timeout = 600; // specific to a namespace

If the timeout is exceeded by a listener within any part of event lifecycle, the listener is terminated and an error event is published; it will not kill the event.

Namespacing

You can create a version of hot-press prefixing all messages with a namespace.

import HotPress from 'hot-press';
import {strictEqual} from 'assert';

const {ns} = new HotPress();
const foo = ns('foo');

foo.on('event', eventName => console.log(eventName));
foo.emit('event');
// foo.event

Namespaces can be retrieved uses the dot syntax, or chained ns() calls.

import HotPress from 'hot-press';
import {strictEqual} from 'assert';

const {ns} = new HotPress();
strictEqual(
  ns('nested').ns('namespaces'),
  ns('nested.namespaces'),
  'Namespaces can be retrieved using dots as hierarchy, or chained calls to `ns`'
);

Namespaces also cascade their settings.

import HotPress from 'hot-press';
import {equal} from 'assert';

const {ns} = new HotPress();
const foo = ns('foo');
foo.timeout = 1000;

equal(
  foo.timeout,
  foo.ns('bar').timeout,
  'Namespaces cascade their settings'
);

Error handling

Errors thrown within listeners/subscribers are swallowed but can be captured in error events:

import HotPress from 'hot-press';

const {emit, on} = new HotPress();
on('error.event', error => console.log(error.message));
on('event', () => throw new Error('Something went wrong'));
emit('event');
// "Something went wrong"

Procedures

Procedures are essentially functions, referenced by a string. There are a few reasons you may want to use procedures:

  • Whether the procedure exists or not, you can call it without anything failing. This is useful when using procedures in a plugable interface, when you're unsure whether the procedure is going to be there or not.
  • Hooking in to the function call. Every call to a procedure emits an event with the same name as the procedure. The event lifecycle will exist, which also means you can pause the call with the before() method.
  • If you've decided to use HotPress as a basis to your framework/application it can mean your API is more consistent.

To register a procedure, use the reg() function. To cal your registered procedure, use the call() method.

If the procedure returns a promise, it will wait for the promise to resolve before passing the resolved data back to the caller.

The call() function always returns a promise.

import User from '../lib/user';
import HotPress from 'hot-press';

const {reg, call, on} = new HotPress();

reg('users.get', query => User.all(query));

on('error.users.get', error => console.error(error));

on('users.get', query => console.log('Querying users table', query));

call('users.get', {type: 'admin'}).then(users => {
  // Do something with users
});

Custom Lifecycles

The before(), on() & after() methods don't suffice everyone's needs. Luckily enough, for those people, the lifecycle is configurable.

Note you must still include an on method. Procedures rely on it.

import HotPress from 'hot-press';

const emitter = new HotPress();
emitter.lifecycle = ['foo', 'bar', 'on', 'after'];
const {foo, bar, on, after, emit} = emitter;

foo('event', console.log);
bar('event', console.log);
on('event', console.log);
after('event', console.log);

emit('event');
// foo
// bar
// on
// after

The lifecycle is configurable per namespace too.

import HotPress from 'hot-press';

const {ns} = new HotPress();
const foo = ns('foo');
foo.lifecycle = ['prior', 'on', 'end'];

foo.prior('event', console.log);
foo.on('event', console.log);
foo.end('event', console.log);
foo.emit('event');
// prior
// on
// end

Why the weird name?

Mostly because the good ones were already taken and there's arguably a relation between publishing/subscribing to magazines and papers.

API

after(String eventName, Function subscriber)

Register a subscribing function to the end of the event.

all(Object<[lifecycleName]: String[]> eventNames, Function subscriber)

Register a subscriber for when all events have been published

call(String procedureName, [...Any]) ==> Promise

Call a procedure with the given arguments.

dereg(String procedureName) ==> Number

Deregisters a procedure.

deregAll() ==> Number

Removes all registered procedures.

emit(String eventName, [Any ...data]) ==> Promise

Publishes the event and passes all data arguments directly to the subscribers.

[lifecycleName](String eventName, Function subscriber)

Register a subscribing function to that part of the event lifecycle.

ns(String namespace) ==> HotPress

Creates an object containing the entire API of which all messages/event names will be prefixed with a namespace.

off(String eventName, [Function subscriber]) ==> Number

Removes a given subscriber from an event. If none is specified, it will remove all subscribers from the event.

on(String eventName, Function subscriber)

Register a subscribing function to the event

once(String eventName, Function subscriber)

Registers a subscriber for just one event before it's removed.

once[LifecycleName](String eventName, Function subscriber)

Registers a subscriber, to that part of the event lifecycle, for just one event before it is removed.

triggers(String eventName, Array eventNames)

When the event has been published, publish an array of of other events.

triggers[lifecycleName](String eventName, Function subscriber)

When the event's lifecycle part has been published, publish an array of other events.

reg(String procedureName, Function procedure)

Registers a procedure.