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

taskhubjs

v0.0.6

Published

PubSubHub over websockets, with a task lifecycle

Downloads

11

Readme

TaskHub

Send it tasks, watch as they happen.

Important:

  • This project is in early development and not all features are implemented yet.
  • Backwards compatibility not guaranteed until version 1.x.x

Node.js CI

Vocabulary

  • server: The taskhub server.
  • client: Both "clients" and "services" (that respond to clients) are referred to as clients here. A connection is an instance of a client.
  • action: A category of tasks. Example of actions can be: "email:send", "geo:geocode", "email/address:validate". Actions are composed of: <noun>:<verb> or <noun>/<sub.noun>:<verb>
  • task: An instance of an action, like a job.
  • event: An event that updates the state of a task. See task lifecycle for complete event reference
  • command: Messages sent to the hub. Either "pub" or "sub". Kind of like requests. Internal, not exposed in APIs.
  • message: Messages sent from the hub to the clients. Kind of like responses. Internal, not exposed in APIs.

Task lifecycle

  • init: A client asks to start this task.
  • start: A task has been received by the hub and has been sent to subbing services. Event is triggered when one has started work on the task.
    • update: A service updates all other subbing services about an update.
    • drop: A service is done working on it without returning a result.
    • return: A service has returned a result, and thereby completed the task globally.
  • success: A service has completed and returned a result. Task is considered complete and hub sends complete event to all subbing services.
  • fail: A service failed or been cancelled.
  • end: All subbing services have either timedout, succeeded or dropped, or the hub has cancelled/failed the task.

Examples

Server

const { Server } = require('taskhub');

const hub = new Server({
  port: 8080,
  // If hub waits longer than this for subscribing clients
  // the task has failed. Default value. Can be overridden per task.
  // NOT IMPLEMENTED YET.
  taskStartTimeout: 100,
  // IF a task takes longer than this to finish (either success or error)
  // hub will consider the task has failed and emit fail message.
  // Can be overridden per task.
  // NOT IMPLEMENTED YET.
  taskEndTimeout: 1000 * 60
});

hub.addCredentials('emailer', {
  // The client's authentication key
  key: '---super-secret-key---',
  // The actions the client is allowed to subscribe to.
  // NOT IMPLEMENTED YET.
  subPermissions: [ 'email/bulk:send' ],
  // The actions it is allowed to publish/start tasks for.
  // Here is can mail:send, and it can do everything under geocode,
  // such as weather:forecast, weather/metno:forecast
  // NOT IMPLEMENTED YET.
  pubPermissions: [ 'email:send', 'weather' ],
  // Specify how many connections of this client is allowed.
  // NOT IMPLEMENTED YET.
  maxConnections: 1
});

hub.start(); // Open for business

Client

import { Client } from 'taskhub';

const client = new Client({
  url: 'ws:server:port', // server url
  clientName: 'emailer', // unique name
  key: '---super-secret-key---'
});

client.sub('email/bulk:send', async (task) => {
  // Tell the hub this service will begin work on this task, so that it knows to wait.
  // Otherwise, the hub will assume a task is complete when all listening services has seen it, or timedout. (The timeout is short.)
  task.start();

  // Get payload (async because it could be large)
  const data = await task.getPayload();

  // Update the caller on current progress
  task.update(data);

  // Triggers when another client updates the task
  task.on('update', (task) => { task.getLastUpdate() });

  // When another client returns and thereby completes the task globally.
  task.on('success', () => {});

  // Done and the data is sent to the caller/publisher.
  return data; // or task.success(result);

  // This client has completed but doesn't want to return a result to pub.
  task.drop();
});

// Calling
try {
  let result = await client.pub('email/bulk:send', emails).getResult();
} catch(err) { }

// Call it with value if error, to avoid the exceptions, and wait 30 min
let result = await client.pub('email/bulk:send', emails, 1000 * 60 * 30 /* 30 min */)
  .getResult(valueIfError);

// Call it with progress updates
let finalResult = await client.pub('email/bulk:send', emails)
  .on('update', (task) => { console.log(task.getLastUpdate()); })
  .getResult(valueIfError);