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

nekobasu

v1.0.0

Published

Configurable and type safe event bus that can buffer and reduce events

Downloads

7

Readme

nekobasu

Auto completion friendly library for configurable and type safe event buses with emitters that can buffer and reduce events!

This library lets you construct event buses. An event bus consists of a number of "nekos". A neko can receive an event of some type. It will then feed this event to each of its event buffers, which listeners can subscribe to. A buffer can dispatch, buffer, and reduce events.

You can build your own event buffers and nekos. The library also comes with some built in.

Basic usage

Lets look at an example:

import * as nbus from 'nekobasu';

let neko = nbus.builtin.event<number>();

neko.immediate.sub((n) => console.log(`immediate ${n}`));
neko.last.sub((n) => console.log(`last ${n}`));
neko.list.sub((n) => console.log(`list ${n}`));

neko.send(1); // prints "immediate 1"
neko.send(2); // prints "immediate 2"
neko.send(3); // prints "immediate 3"

neko.flush(); // prints "last 3" and "list [ 1, 2, 3 ]", in undefined order

TypeScript can infer all types used, so you get complete auto completion and the assurance that your event handlers know which arguments to expect. The list handler above knows it's getting a list of numbers, and the last handler knows it'll get a single number.

The event buffers all extend SimpleEventDispatcher from the Strongly-Typed-Events-for-TypeScript library.

You can use only plain nekos if you want, they work fine by themselves. This is how you would create an event bus:

let event_bus = nbus.event_bus.create({
  cool_numbers: nbus.builtin.event<number>(),
  boring_strings: nbus.builtin.event<string>(),
});

// Nekos can be used as you saw above
event_bus.cool_numbers.list.sub((n) => console.log(`list ${n}`));
event_bus.cool_numbers.immediate.sub((n) => console.log(`imm ${n}`));

event_bus.cool_numbers.send(2333); // imm 2333

// Clearing removes all buffered events
event_bus._meta.clear();

event_bus.cool_numbers.flush(); // no "list [2333]", since we cleared

// You can also flush all nekos using the event bus
event_bus._meta.flush();

// And clear individual nekos
event_bus.cool_numbers._meta.clear();

So in essence, using the event bus simply gives you the clear and flush convenience functions. You can also combine multiple event buses if you want to namespace your app's events:

let event_bus = nbus.event_bus.categorized({

  cool: nbus.event_bus.create({
    numbers: nbus.builtin.event<number>(),
    strings: nbus.builtin.event<string>(),
  }),

  bad: nbus.event_bus.create({
    errors: nbus.builtin.event<Error>(),
    feels: nbus.builtin.event<Feel>(),
  }),

});

// Just like event buses let you call clear/flush on all their
// nekos, the categorized event bus container will let you call
// flush and clear on all event buses.

event_bus._meta.clear();

In addition to the builtin event neko, there's a built in signal neko. This is basically a builtin.event<undefined> neko, but with a patched send function so that you can just call send() instead of send({}). It comes with the immediate and count event buffers.

import * as nbus from 'nekobasu';

let neko = nbus.builtin.signal();

neko.immediate.sub(() => console.log(`immediate`));
neko.count.sub((n) => console.log(`count ${n}`));

neko.send(); // immediate
neko.send(); // immediate
neko.send(); // immediate

neko.flush(); // count 3

Public Bus

Want to create a reference to your bus that will only allow listening for but not sending events? Sadly, it doesn't seem like TypeScript's type system will let us create a general function to do this. You'll need to do it manually for each event bus you create. If you're using the builtin nekos, some convenience is provided. Otherwise, you'll need to do some manual work. See the util file to see how it's done.

Here's how to do it with builtin nekos:

  const event_bus = nbus.event_bus.categorized({

    system: nbus.event_bus.create({
      error: nbus.builtin.event<Catastrophe>(),
    }),

    runtime: nbus.event_bus.create({
      we_get: nbus.builtin.signal(),
    }),
    
    data: nbus.event_bus.create({
      parse_result: nbus.builtin.event<ParseResult>(),
    }),

  });

  function get_public_bus() {
    const pub_ev = nbus.util.builtin_event_as_public;
    const pub_sig = nbus.util.builtin_signal_as_public;

    return {

      system: {
        error: pub_sv(event_bus.system.error),
      },

      runtime: {
        we_get: pub_sig(event_bus.runtime.we_get),
      },

      data: {
        parse_result: pub_ev(event_bus.data.parse_result),
      },

    };
  }

  const public_bus = get_public_bus();
  // Note that only the types have changed. We didn't actually create
  // any new objects with fewer properties. If your public bus consumer
  // is JS, not TS, you'll want to write your own functions to strip
  // away all mutating functions. However, since you don't need to care
  // about the type system at that point, it should be easy.

Advanced usage

In addition to the builtin event buffers shown here, there's instrumented_last, which will save the last event but also keep count of how many events have fired.

Please see the custom_buffer test in src/test/basic.test.ts to learn how to create your own event buffer and neko. It'll also show you how you can merge event buffer dictionaries, which lets you easily keep using the builtin event buffers along with your own.

Want to specify the type of your event bus? This is often handy when doing dependency injection, where we often want one component to store a reference to the bus which it gets through its constructor. See the file example/how_to_export_type_for_dep_injection.ts.

Performance

A neko will only pass on events to an event buffer that has subscribers.

You can also ensure that a neko will only send events to a single event buffer using the neko._meta.use_single_buffer('buffer_name') function. These buffer names are type safe, so don't worry about spelling. Call ._meta.use_all_buffers() to reset.

Future

Hope to work on:

  • A method for logging/tracking events, to mitigate the difficulties that event spaghetti often causes in large apps.
  • A non-typesafe convenience function for creating public event buses for non-TS consumers.

Meta

  • Requires TypeScript 2.3 or higher (uses generic parameter defaults and keyof)
  • I mean you technically can use this lib even if you're just writing JS but without the auto completion it's not much better than the stringly typed Event Emitter stuff that's popular these days. Though if you do misspell an event name, you'll get a nice undefined value exception with nekobasu, instead of a hard to debug missing event.
  • See LICENSE file for license (Apache 2.0. You may also ask Oliver Uvman for a GPLv2 compatible license.)
  • See CONTRIBUTING for contributor's agreement (You grant Apache 2.0 and you allow Oliver Uvman to redistribute under any GPLv2 compatible license)
  • I'd like to thank my mom & dad and whatever type inference algorithm TS uses. Love you forever.