
Security News
November CVEs Fell 25% YoY, Driven by Slowdowns at Major CNAs
November CVE publications fell 25% YoY even as 2025 totals rose, showing how a few major CNAs can swing “global” counts and skew perceived risk.
@evanshortiss/tstate-machine
Advanced tools
StateMachine implementation in TypeScript. This is an updated fork of the excellent SoEasy/tstate-machine.
Class-based, declarative, strongly typed state machine with hard declared transitions and without autocomplete problems.
npm install reflect-metadata @evanshortiss/tstate-machine --save
A complete example can be found in example/traffic.ts.
Run it by issuing an npm run example command.
// A Reflect.defineMetata polyfill is required by tstate-machine
import 'reflect-metadata';
import { StateMachine, PartialProperties } from '@evanshortiss/tstate-machine';
enum Colours {
Red = 'Red',
Orange = 'Orange',
Green = 'Green'
};
// Properties of the TrafficLightStateMachine
type TrafficLightProps = {
safe: boolean
message: string
}
// Can be used to represent partial state changes
type PartialTrafficLightProps = PartialProperties<TrafficLightProps>
// A union type that defines valid states for the machine
type TrafficLightStates = Colours.Red|Colours.Orange|Colours.Green
class TrafficLightStateMachine extends StateMachine<TrafficLightProps, TrafficLightStates> {
/**
* Define the Red state:
* - Inherits the initial properties (passed in constructor)
* - Overwrites the initial "message" property value with "STOP"
* - Can only transition to the Green state
*/
@StateMachine.extend(StateMachine.INITIAL, [Colours.Green])
[Colours.Red]: PartialTrafficLightProps = { message: 'STOP' }
@StateMachine.extend(StateMachine.INITIAL, [Colours.Green, Colours.Red])
[Colours.Orange]: PartialTrafficLightProps = { message: 'CAUTION' }
@StateMachine.extend(StateMachine.INITIAL, [Colours.Orange])
[Colours.Green]: PartialTrafficLightProps = { message: 'GO', safe: true }
constructor () {
super({
// Tells the state machine what state(s) it can initially transition to
initialTransitions: [Colours.Green],
// Define the initial state values for the machine
props: {
message: 'OFF',
safe: false
}
})
}
}
const machine = new TrafficLightStateMachine()
machine.transitTo(Colours.Green)
console.log(`Light is ${machine.currentState}. Message is ${machine.props.message}.`)
machine.transitTo(Colours.Orange)
console.log(`Light is ${machine.currentState}. Message is ${machine.props.message}.`)
machine.transitTo(Colours.Red)
console.log(`Light is ${machine.currentState}. Message is ${machine.props.message}.`)
StateMachine<ValidProps, ValidStates> and calls the super constructor.@StateMachine.extend(parent, transitions)To create your own state machine you must create class and inherit it from
StateMachine class.
All instances of StateMachine start in the default StateMachine.INITIAL
state. You must pass initialTransitions and initialProps to the
super constructor to correctly initialise the machine.
enum Colours {
Red = 'Red',
Orange = 'Orange',
Green = 'Green'
}
type TrafficLightProps = {
safe: boolean
message: string
}
type PartialTrafficLightProps = PartialProperties<TrafficLightProps>
type TrafficLightStates = Colours.Red|Colours.Orange|Colours.Green
class TrafficLightStateMachine extends StateMachine<TrafficLightProps, TrafficLightStates> {
constructor() {
super({
// What state(s) the machine can initially transition to
initialTransitions: [Colours.Green],
// Define the initial property values for the machine
initialProps: {
message: 'OFF',
safe: false
}
})
}
}
@StateMachine.extend to define a state. It accepts two arguments:
State.INITIAL or another state.The following snippet defines the Green state on this
TrafficLightStateMachine.
enum Colours {
Red = 'Red',
Orange = 'Orange',
Green = 'Green'
}
type TrafficLightProps = {
safe: boolean
message: string
}
type PartialTrafficLightProps = PartialProperties<TrafficLightProps>
type TrafficLightStates = Colours.Red|Colours.Orange|Colours.Green
class TrafficLightStateMachine extends StateMachine<TrafficLightProps, TrafficLightStates> {
/**
* Define the "Green" state (Colours.Green).
*
* Extends the initial state, but we override both properties:
* - Property "safe=true", because false is overwritten
* - Property "message="GO", because "OFF" is overwritten
*
* This state can transition to the "Orange" state.
*/
@StateMachine.extend(StateMachine.INITIAL, [Colours.Orange])
[Colours.Green]: PartialTrafficLightProps = {
message: 'GO',
safe: true
}
constructor() {
super({
// Tells the state machine what state(s) it can initially transition to
initialTransitions: [Colours.Green],
// Define the initial state values for the machine
initialProps: {
message: 'OFF',
safe: false
}
})
}
}
The Red state could be defined as shown below. Only the message property is
defined, since this state is uses the inherited false value for safe.
/**
* Define the "Red" state (Colours.Red).
*
* Extends the initial state:
* - Property "safe=false", because it's inherited from the initial state
* - Property "message="STOP", because it's overwritten
*
* This state can transition to the "Green" state.
*/
@StateMachine.extend(StateMachine.INITIAL, [Colours.Green])
[Colours.Red]: PartialTrafficLightProps = {
message: 'STOP'
}
Call transitTo(targetState: string, ...args: Array<any>) to transition
between states. Arguments passed to transitTo() are passed to the onEnter
transition callback(s).
const machine = TrafficLightStateMachine()
const ORANGE_TIMEOUT = 4 * 1000 // 4000 milliseconds
machine.transitTo(Colors.Green)
machine.transitTo(Colors.Orange, ORANGE_TIMEOUT)
machine.transitTo(Colors.Red)
Attempting to transition to an invalid state will fail. This can be detected by
checking the return value of transitTo.
const machine = new TrafficLightStateMachine()
// Will return undefined, since this is a valid transition
machine.transitTo(Colors.Green)
// Result is "InvalidTransition" since Green => Red is not a valid path
const greenToRedError = machine.transitTo(Colors.Red)
if (greenToRedError) {
console.log(`Failed to transition due to error: ${greenToRedError}`)
}
Multiple callbacks can be registered for onLeave and onEnter phases of a
state transition.
The onLeave callbacks are called before the transition has occurred. This
means that the machine properties have not been updated when the callback is
invoked.
The onEnter callbacks are called after the transition has occurred. This
means that the machine properties have been updated when the callback is
invoked.
const machine = new TrafficLightStateMachine();
const ORANGE_TIMEOUT = 4 * 1000; // 4000 milliseconds
const removeOrangeEnterCb = machine.onEnter(Colours.Orange, (timeout: number) => {
// Change to Red state after the given timeout
setTimeout(() => machine.transitTo(Colous.Red), timeout);
});
machine.onLeave(Colours.Orange, () => console.log('Leaving Orange state'));
// Transition to green, then orange (this will trigger a callback)
machine.transitTo(Colors.Green);
machine.transitTo(Colors.Orange, ORANGE_TIMEOUT);
// Remove a registered callback
removeOrangeEnterCb();
@StateMachine.hide() - decorator for wrapping fields/methods that are not related to the state@StateMachine.extend(parentState: string, toStates: Array<string>) - Declares new state. Inherit class properties from parentState. Possible transitions are to states.transitTo(targetState, ...args) - Transition to targetState. Supports optional variadic arguments that will be passedcurrentState: string - Get the current state the machine is in.is(stateName: string): boolean - Check if current state is stateName.can(stateNameL string): boolean - Check if it's possible to transition to stateName.transitions(): Array<string> - Returns a list possible transitions from the current state.onEnter(stateName: string, cb: (...args: Array<any>) => void): () => void - add onEnter callbackonLeave(stateName: string, cb: () => void): () => void - add onLeave callbackThe interface is peeked here: JS FSM.
FAQs
TypeScript implementation of StateMachine
We found that @evanshortiss/tstate-machine demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
November CVE publications fell 25% YoY even as 2025 totals rose, showing how a few major CNAs can swing “global” counts and skew perceived risk.

Security News
React disclosed a CVSS 10.0 RCE in React Server Components and is advising users to upgrade affected packages and frameworks to patched versions now.

Research
/Security News
We spotted a wave of auto-generated “elf-*” npm packages published every two minutes from new accounts, with simple malware variants and early takedowns underway.