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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@opuscapita/fsm-core

v0.0.1-beta.5

Published

FSM workflow (for Node.js)

Readme

FSM core

Machine and its definition.

How To Use

Install package

Run npm install @opuscapita/fsm-core to get up and running.

Use in code

import { MachineDefinition, Machine } from '@opuscapita/fsm-core';

Machine definition

Machine definition consist of:

Example

const machineDefinition = new MachineDefinition({
  schema: {
    name: "invoice approval",               
    initialState: "open",                   
    finalStates: ["approved"],
    objectStateFieldName: "status",         
    transitions: [
      {
          from: "open",                    
          event: "approve",                 
          guards: [                       
            {                               
              "name": "validate",
              "arguments": {
                "argument1": "value1",
                "argument2": "value2"
              }
            }
          ],
          to: "approved",                   
          actions: [                       
            {                                
              "name": "archive",
              "arguments": {
                "argument1": "value1",
                "argument2": "value2"
              }
            }
          ],
          automatic: [                          
            {                                
                "name": "lastlyUpdatedMoreThan24hAgo",
                "arguments": {
                  "argument1": "value1",
                  "argument2": "value2"
                }
            }
          ]
      }
    ]
  },
  actions: {
    archive: function({argument1, argument1}) {}
  },
  conditions: {
    validate: function({argument1, argument1}) {},
    lastlyUpdatedMoreThan24hAgo: function({argument1, argument1}) {}
  }
});

Schema

Defines machine transitions and initialization options. Could be presented as oriented graph, where each node represents state and directed edges are used to represent transition from one state to another.

Transitions

In schema you needs to define an array of available machine transitions. Typically a transition is triggered by an event and happens between from and to states. Optionally each transition can have actions, guards and/or automatic (conditions).

Initial state

You can define the initial state by setting the initialState property:

var machineDefinition = new MachineDefinition({
  schema: {
    initial: 'start'
    transitions: [
      {from: 'start', event: 'run', to: 'finish'}
    ]
  }
});

const object = {status: 'none'};
const machine = new Machine(machineDefinition);
machine.start(object).then(({object}) => {
  console.log(machine.currentState({object}));
  // start  
});

if initial state is not specified, then 'none' will be used (TBD)

Final states

You can define the final states (one or many) by setting the finalStates property:

var machineDefinition = new MachineDefinition({
  schema: {
    initial: 'start',
    finalStates: ['finish'],
    transitions: [
      {from: 'start', event: 'run', to: 'finish'}
    ]
  }
});

Code (Actions and Conditions(guards/automatic))

Ideas & thoughts

Action

Actions (action = function) are executed during transition (not during existing or entering states). Action references specific function by name. Action implemented separately from schema. Each action accepts named arguments explicitly defined in transition and implicit arguments like object, from, to, etc. During transition machine executes each action in defined order. Each action gets actionExecutionResutls argument which serves as an accumulator from perviously called actions, where each property is an action name and value is value returned by action.

Guard (conditions)

Guards are used to protect transitions. Guard works as 'if' condition. Technically guard is defined the same way like as action, it is a function. The difference is that it should always return boolean value (true or false).

Note: similar to Spring State Machine Guards

Automatic (conditions)

Transition could be marked as automatic using corresponding property. It could be:

  • true (boolean value) - e.g. this transition is always automatic
  • array of conditions(functions, each return true or false) Check for whether object in current state has (at least one) automatic transition needs to be done by external task manager (inside the application). Basing on evaluated results task manager will be able to take a decision to send event without user interaction.

Stateful object as a process

Machine does not have own state, all the transitions are performed over object which state is changed by machine. Object is used by Machine as a mutable parameter passed to guards and actions.

var machineDefinition = new MachineDefinition({
  schema: {
    initial: 'start'
    finalStates: ['finish'],
    transitions: [
      {from: 'start', event: 'run', to: 'finish'}
    ]
  }
});

const object = {status: 'none'};
const machine = new Machine(machineDefinition);
machine.start(object).then(({object}) => {
  console.log(machine.currentState({object}));
  // start
  return machine.sendEvent({object, event: 'start'})
}).then(({object}) => {
  console.log(machine.currentState({object}));
  // finish
});

Machine

API

var machineDefinition = new MachineDefinition({schema, guards, actions})
// register workflow
var machine = new Machine(machineDefinition, context);

// start/initialize machine/workflow
machine.start({object})

// returns a list of available transitions: {event, from, to, request..}, e.g. event
// request is used to pass parameters to guards for some dynamic calculation, e.g. when event availability depends 
// on current user information as roles and etc. 
machine.availableTransitions({object})
// returns a list of available automatic transitions: {event, from, to, ..}, e.g. event
// if machine schema is adequate then there should be not more than 1 such transition
machine.availableAutomaticTransitions({})

// send 'event' and pass addition 'request' data that is posted by user/app
// returns promise, in case of successful transition then function will be called
// with one parameter that is an JSON with the following structure:
// - object - object in new state (the same reference that is passed as parameter)
machine.sendEvent({object, event, request})

machine.currentState({ object })     // gets current state
machine.is({ object, state})         // is object in state
machine.isInFinalState({ object })   // returns true iff object is in one of final states
machine.can({ object, event })       // whether event is available
machine.cannot({ object, event })    // whether event is not available

// hooks (tbd)
machine.onStartTransition()   // returns promise
machine.onFinishTransition()  // returns promise