1.0.16 • Published 5 months ago

machiner v1.0.16

Weekly downloads
-
License
-
Repository
-
Last release
5 months ago

Machiner Documentation

Overview

The machiner library is a TypeScript implementation of a typed state machine designed to handle complex workflows, time-based actions, service orchestration, debugging, and persistence. It provides a robust framework for managing state transitions with guards, actions, delayed executions, intervals, and cron jobs.

Getting Started

Installation

To install the library using npm:

npm install machiner

Importing

In your TypeScript project, import the necessary modules:

import { TypedStateMachine } from 'machiner';

Example Usage

Here's a simple example of creating and running a state machine:

import { TypedStateMachine } from 'machiner';

interface Context {
  count: number;
}

type Events = 'increment' | 'reset';

interface Payloads {
  increment: { amount: number };
  reset: {};
}

const config = {
  id: 'counter',
  initial: 'active' as const,
  context: { count: 0 } as Context,
  states: {
    active: {
      id: 'active',
      on: {
        increment: {
          actions: [
            (context, event) => ({
              count: context.count + event.data.amount
            })
          ],
          target: 'active'
        },
        reset: {
          actions: [
            () => ({
              count: 0
            })
          ],
          target: 'active'
        }
      },
      entry: [
        (context, event) => {
          console.log('Entering active state. Current count:', context.count);
        }
      ]
    }
  }
};

const machine = TypedStateMachine.create<Events, Context, Payloads>(config);

machine.send({ type: 'increment', data: { amount: 5 } });
// Current state stays active, count becomes 5

machine.waitForState(['active']).then(({ state, context }) => {
  console.log('Machine is in state:', state);
  console.log('Current count:', context.count);
});

Core Concepts

States

A state defines the current situation of the machine. Each state can have:

  • Transitions (on): Defined for events, which may include guards and actions.
  • Entry/Exit Actions: Actions triggered when entering or exiting the state.
  • Delayed Transitions (after): Execute after a delay.
  • Intervals: Actions executed periodically.
  • Cron Jobs: Actions executed based on a cron schedule.
  • Services/Machines (invoke): Invoking external services or other state machines.

TypedEvents

Each event has a type and optional data, timestamp, and metadata.

Actions and Guards

  • Actions: Functions that modify the context or send events.
  • Guards: Functions that determine if a transition can occur based on the current state and event.

Advanced Features

Persistence

  • Events are saved using a PersistenceAdapter, with LocalStorage as the default.
  • Customize persistence by implementing your own adapter.

Concurrency Handling

  • Use an expected version when sending events to prevent race conditions.

Debugging and Monitoring

  • debugSubject provides real-time debug events.
  • machineInfoSubject streams state and context changes.

Error Handling

  • Define an error handler in the configuration to handle exceptions during actions or state transitions.

Services and Machines

ServiceInvocation

Define a function that performs an async task, with optional transitions on success or failure.

{
  src: async (context, emit) => {
    // Service logic here
    return result;
  },
  onDone: {
    target: 'doneState',
    actions: [/* ... */]
  },
  onError: {
    target: 'errorState',
    actions: [/* ... */]
  }
}

MachineInvocation

Embed another state machine, with optional input mapping, updates, and transitions on completion.

{
  machine: childMachine,
  input: (parentContext) => ({ /* child context */ }),
  onUpdate: (childState, send) => {
    // Handle updates from the child machine
  },
  onDone: { /* transition */ },
  onError: { /* transition */ }
}

Managing Subscriptions

  • Track subscriptions created during invoke operations.
  • Clean up resources on disposal to prevent memory leaks.

Real-World Integration

Best Practices

  • Keep state definitions modular.
  • Use version control for complex state machines.
  • Test thoroughly, especially concurrency and error handling.

Performance Considerations

  • Optimize loops and avoid heavy computations in actions.
  • Monitor RxJS stream performance under high load.

Troubleshooting

Common issues and solutions:

  1. Concurrency Errors: Ensure expected versions match when sending events in concurrent environments.
  2. State Transitions Not Firing: Verify guards return true and actions don't throw errors blocking transitions.
  3. Persistence Issues: Check adapter implementations for correct event saving and loading.

Conclusion

The machiner library offers a powerful, flexible solution for managing stateful workflows in TypeScript. By leveraging its advanced features and following best practices, developers can build robust, maintainable applications with complex state management requirements.

1.0.16

5 months ago

1.0.15-l

5 months ago

1.0.15-k

5 months ago

1.0.15-j

5 months ago

1.0.15-i

5 months ago

1.0.15-h

5 months ago

1.0.15-g

5 months ago

1.0.15-f

5 months ago

1.0.15-e

5 months ago

1.0.15-d

5 months ago

1.0.15-c

5 months ago

1.0.15-b

5 months ago

1.0.15-a

5 months ago

1.0.15

5 months ago

1.0.14

5 months ago

1.0.13

5 months ago

1.0.12

5 months ago

1.0.11

5 months ago

1.0.10

5 months ago

1.0.9

5 months ago

1.0.8

5 months ago

1.0.7

5 months ago

1.0.6

5 months ago

1.0.5

5 months ago

1.0.4

5 months ago

1.0.3

5 months ago

1.0.2

5 months ago

0.0.2

5 months ago

0.0.1

5 months ago

1.0.0

5 months ago