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

machina.postal

v0.4.0

Published

A plugin for machina.js that auto-wires finite state machines into the postal.js local message bus.

Downloads

101

Readme

machina.postal

##v0.4.0

What is this thing?!

So - machina.js is a JavaScript library for building flexible finite state machines, and postal.js is a JavaScript message bus library. "machina.postal" is two things:

  1. A very unoriginal name. I was going to go for something like mail.machine, but seriously, who wants to include <script src="mail.machine.js"><script> in their project?
  2. It's a BRIDGE between machina and postal. Aw, shoot, did the unoriginal name give that away?

But How?

When you include machina.postal.js in your project, it hooks into the "newFsm" event that gets fired anytime a new FSM is created. In the handler for the "newFsm" event, the machina.postal plugin subscribes to postal, using the FSM's namespace as a channel name, and a wildcard "#" as the topic (will match ANY topic on that channel). From that point on, if anyone publishes a message on the FSM's channel, with a topic that matches the name of a handler, the FSM will call handle, routing the message payload to the handler name (assuming one exists under the current state) which matches the message topic. Voila! Your application components can now interact with the FSM over the message bus, and not require a direct reference to it.

But wait, there's more.

The machina.postal plugin also publishes any events generated by the FSM to the message bus, using the FSM's namespace as the channel name (concatenated with ".events" - which you can change if you want). Again, your components don't need a direct reference to the FSM to subscribe to events, instead they can listen over postal.

FSMs that are wired up this way will have a _bus property added which contains the postal channels that are used for publishing events and subscribing to the bus. machina.postal also adds three methods to the machina.Fsm.prototype: removeBusPublishing, removeBusSubscriptions, and removeAllBusIntegration. You can remove all interactions with postal.js by calling removeAllBusIntegration on an FSM instance.

Really, there's not much....let's have a looksee:

The plugin consists of an object literal with the following members:

  • config - object literal containing default "suffixes" for the handler and event channels. The handlerChannelSuffix defaults to an empty string, while the eventChannelSuffix defaults to ".events". While it's certainly possible to let the FSM publish event messages and listen for handler messages on the same channel, it's recommended to separate them, in case you happen to name an event identical to a handler name (and thus get double triggering, or, God forbid, a message loop).
  • wireHandlersToBus - set up function which handles subscribing an FSM to postal.js, using the channel name provided.
  • wireEventsToBus - set up function which handles subscribing to the FSM "event firehose" (the "*" event) and publishing those to postal.js.
  • wireUp - handler called anytime a newFsm event is raised, which in turn calls wireHandlersToBus and wireEventsToBus, passing the newly created FSM to each.

Using It

Including the plugin wires it into both postal.js and machina.js - just be sure to include it after you include the other two (if you're not going AMD). Here's a contrived snippet of how it could work:

	// Let's set up a subscription that will write to the console
	postal.subscribe({
		channel: "hunger.machine.events",
		topic: "ShoutIt",
		callback: function(data, envelope) {
			console.log(data.msg);
		}
	});
	
	var myFsm = new machina.Fsm({
		initialState: "hungry",
	
		namespace: "hunger.machine",
	
		states: {
			hungry: {
				_onEnter: function() {
					this.emit("ShoutIt", { msg: "OH MY GOSH, I'm starving" });
				},
	
				"go.get.food": function() {
					this.transition("eating");
				}
			},
	
			eating: {
			    _onEnter: function() {
	                this.emit("ShoutIt", { msg: "NOM NOM NOM NOM NOM!" });
	            },
	
	            "stop.eating.pig": function() {
	                this.transition("satisfied");
	            }
			},
	
			satisfied: {
			    _onEnter: function() {
	                this.emit("ShoutIt", { msg: "NAP TIME!" });
	            }
			}
		}
	});
	// when the above FSM instantiates, it will transition into "hungry", and our console subscription
	// will print out "OH MY GOSH, I'm starving!"
	
	// Now that we have our FSM instance and a subscription listening for events (above)
	// Let's get a channel and publish to it:
	var channel = postal.channel("hunger.machine");
	channel.publish({
	    topic: "go.get.food",
	    data: {
	        datums: "stuff you might want to send to the FSM handler"
	    }
	});
	
	// When the "eating" state is entered, the _onEnter handler will fire and publish an event which
	// our console subscriber will catch and then print: "NOM NOM NOM NOM NOM!"
	// Then we can publish
	channel.publish({
	    topic: "stop.eating.pig",
	    data: {
	        datums: "other stuff you might want to send to the FSM"
	    }
	});
	
	// When the "satisfied" state is entered, the _onEnter handler will fire and publish an event which
	// our console subscriber will catch and then print: "NAP TIME!"

###Opting Out You might not want every FSM you stand up to be wired into the bus. My assumption is that if you've included machina.postal in your project, then FSMs will be wired into the bus by default, but you can opt out by passing the _noBus: true member on your FSMs constructor options:

	var fsm = new machina.Fsm( {
		_noBus: true, // <-- keeps FSM from being wired into bus
		initialState : "uninitialized",
		namespace : "myFsm",
		states : {
			"uninitialized" : {
				"event1" : function () {
					this.transition( "initialized" );
				},
				"event2" : function () {
					this.deferUntilTransition();
				}
			},
			"initialized" : {
				_onEnter : function () {
					this.emit( "OnEnter" );
				},
				"event2" : function () {
					this.emit( "CustomEvent" );
				}
			}
		}
	} );

Compatibility Notes

machina.postal v0.4.0 is compatibale with machina >= v0.3.x and >= postal v0.8.x. You want to use the latest versions, trust me.

If you must, here's the older info: machina.postal v0.2.3 is compatible with machina v0.2.x. If you need to use this project with an earlier version of machina.js, then download a version tagged v0.2.2 or earlier.