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

@pehotin/fsm

v1.0.7

Published

Simple Fine State Machine

Readme

fsm

Simple finite state machine (FSM) library for Node.js, built around explicit State and Transition objects with optional entry/exit and transition actions.

The package exposes a single StateMachine class from src/index.js.

Installation

npm install fsm

Or, if you are working in this repo directly:

npm install

Basic Usage

const StateMachine = require('fsm')

// Optional shared context passed to actions
const context = { count: 0 }

const machine = new StateMachine(
  'counter',
  (state, ctx) => console.log('Global entry:', state.id, ctx),
  (state, ctx) => console.log('Global exit:', state.id, ctx),
  context
)

// Create states
const idle = machine.createState(
  'idle',
  (state, ctx) => console.log('Enter idle'),
  (state, ctx) => console.log('Exit idle')
)

const active = machine.createState(
  'active',
  (state, ctx) => console.log('Enter active'),
  (state, ctx) => console.log('Exit active')
)

// Register start state
machine.addState(idle, true)
machine.addState(active)

// Add transitions
// Trigger IDs are local to each state: internally they are stored as `${state.id}:${triggerId}`
idle.addTransition(
  'start',
  active,
  () => console.log('Transition idle -> active')
)

active.addTransition(
  'stop',
  idle,
  () => console.log('Transition active -> idle')
)

// Start the machine and trigger transitions
machine.start()
machine.trigger('start') // idle -> active
machine.trigger('stop')  // active -> idle

Core Concepts

  • StateMachine

    • Constructed as new StateMachine(name, globalEntryAction, globalExitAction, context).
    • name: string used in error messages.
    • globalEntryAction(state, context): called whenever any state is entered.
    • globalExitAction(state, context): called whenever any state is exited.
    • context: arbitrary object passed to all actions.

    Key methods:

    • createState(name, entryAction, exitAction)State
    • addState(state, isStart) – registers a state, optionally marking it as the start state.
    • start() – starts the machine in the configured start state (or the first added state).
    • reset(restart = false) – clears current/previous state, and optionally restarts.
    • trigger(triggerId) – performs a transition based on the current state and trigger.
    • gotoPrevious() – moves back to the previous state if it exists.
    • getCurrentState() – returns the current State instance.
    • isStarted() – returns true if the machine has been started.
  • State

    • Created via state = machine.createState(name, entryAction, exitAction) or directly via new State(...) and then machine.addState(state, isStart).
    • id: read‑only string identifier (the name passed in).
    • entryAction(state, context): optional function called on entry.
    • exitAction(state, context): optional function called on exit.

    Key methods:

    • addTransition(triggerId, targetState, transitionAction)
      • Internally, transitions use IDs of the form ${state.id}:${triggerId}.
    • getTransition(triggerId) – returns the Transition registered for the given local trigger ID.
  • Transition

    • Created internally when you call state.addTransition(...).
    • Holds:
      • An ID (local trigger ID, e.g. idle:start).
      • A targetState.
      • An optional transitionAction() function, called during the transition.

    Key methods:

    • getTriggerId() – returns the transition ID.
    • getTargetState() – returns the target State instance.

Trigger IDs and Transitions

When you call:

idle.addTransition('start', active, () => { /* ... */ })

the State converts the provided trigger id to a local ID:

`${state.id}:${triggerId}` // e.g. "idle:start"

When you later call:

machine.trigger('start')

the state machine builds the same local ID based on the current state's id:

`${currentState.id}:${triggerId}`

and uses that to find the correct Transition. This ensures trigger IDs are namespaced per state.

Error Handling

The StateMachine performs several runtime checks and throws descriptive errors:

  • Starting twice: "The state machine has already started."
  • Starting without any states: "No states have been defined. The state machine cannot be started."
  • Transitioning when not started: "State machine <name> not started."
  • Invalid transitions (no matching transition for the trigger): "Invalid Transition - triggerId: <id>."
  • Attempting to add a duplicate state ID.

All errors are thrown as standard Error instances with messages of the form:

State Machine (<name>) - <message>

Development

  • Main entry point: src/index.js (exports the StateMachine class).
  • Core classes:
    • src/stateMachine.js
    • src/State.js
    • src/Transition.js

To run the example entry script defined in package.json:

npm start

This will execute node ./src/index.js.