CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xstate

Actor-based state management & orchestration for complex app logic.

Overview
Eval results
Files

actors.mddocs/

Actors

Actor system for creating, managing, and communicating with stateful actors that run state machines and other logic. Actors encapsulate state and behavior, communicating through message passing in a predictable and isolated manner.

Capabilities

Actor Creation

Creates and manages actor instances from various types of actor logic including state machines and specialized actor types.

/**
 * Creates an actor instance from actor logic
 * @param logic - Actor logic (state machine or other actor logic)
 * @param options - Optional configuration for the actor
 * @returns Actor instance that can be started, stopped, and communicated with
 */
function createActor<TLogic extends AnyActorLogic>(
  logic: TLogic,
  options?: ActorOptions<TLogic>
): Actor<TLogic>;

/**
 * Legacy alias for createActor
 * @deprecated Use createActor instead
 */
function interpret<TLogic extends AnyActorLogic>(
  logic: TLogic,
  options?: ActorOptions<TLogic>
): Actor<TLogic>;

interface ActorOptions<TLogic extends AnyActorLogic> {
  /** Unique identifier for the actor */
  id?: string;
  /** System identifier for the actor */
  systemId?: string;
  /** Input data for the actor */
  input?: InputFrom<TLogic>;
  /** Parent actor reference */
  parent?: AnyActorRef;
  /** Synchronize snapshot with parent */
  syncSnapshot?: boolean;
  /** Actor system reference */
  system?: AnyActorSystem;
  /** Logger for the actor */
  logger?: (msg: string) => void;
  /** Inspection observer */
  inspect?: Observer<InspectionEvent>;
  /** DevTools adapter */
  devTools?: DevToolsAdapter;
}

Usage Examples:

import { createMachine, createActor } from "xstate";

// Create actor from state machine
const machine = createMachine({
  initial: "idle",
  states: {
    idle: {
      on: { START: "running" }
    },
    running: {
      on: { STOP: "idle" }
    }
  }
});

const actor = createActor(machine, {
  id: "my-actor",
  input: { count: 0 }
});

// Start the actor
actor.start();

// Send events
actor.send({ type: "START" });

Actor Class

Main actor implementation providing state management, event handling, and lifecycle control.

class Actor<TLogic extends AnyActorLogic> implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>> {
  /** Unique actor identifier */
  readonly id: string;
  /** Actor logic */
  readonly logic: TLogic;
  /** Actor options */
  readonly options: ActorOptions<TLogic>;
  /** Actor status */
  readonly status: "not-started" | "running" | "stopped" | "error";

  /**
   * Starts the actor and begins processing
   */
  start(): this;

  /**
   * Stops the actor and cleans up resources
   */
  stop(): this;

  /**
   * Sends an event to the actor
   * @param event - Event to send
   */
  send(event: EventFromLogic<TLogic>): void;

  /**
   * Gets the current snapshot
   * @returns Current actor snapshot
   */
  getSnapshot(): SnapshotFrom<TLogic>;

  /**
   * Gets persisted snapshot data
   * @returns Persisted snapshot
   */
  getPersistedSnapshot(): Snapshot<unknown>;

  /**
   * Subscribes to actor state changes
   * @param observer - Observer function or object
   * @returns Subscription object
   */
  subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;

  /**
   * Subscribes to actor state changes with next/error/complete callbacks
   * @param nextListener - Called on state changes
   * @param errorListener - Called on errors
   * @param completeListener - Called on completion
   * @returns Subscription object
   */
  subscribe(
    nextListener: (snapshot: SnapshotFrom<TLogic>) => void,
    errorListener?: (error: any) => void,
    completeListener?: () => void
  ): Subscription;
}

Actor References

Interface for communicating with actors, providing a stable API for message passing and observation.

interface ActorRef<
  TSnapshot extends Snapshot<unknown>,
  TEvent extends EventObject
> {
  /** Unique actor identifier */
  readonly id: string;

  /**
   * Sends an event to the actor
   * @param event - Event to send
   */
  send(event: TEvent): void;

  /**
   * Subscribes to actor state changes
   * @param observer - Observer function or object
   * @returns Subscription object
   */
  subscribe(observer: Observer<TSnapshot>): Subscription;

  /**
   * Gets the current snapshot
   * @returns Current actor snapshot
   */
  getSnapshot(): TSnapshot;

  /**
   * Gets persisted snapshot data
   * @returns Persisted snapshot
   */
  getPersistedSnapshot(): Snapshot<unknown>;

  /** Symbol.observable implementation */
  [Symbol.observable](): InteropObservable<TSnapshot>;
}

interface BaseActorRef<TEvent extends EventObject> {
  readonly id: string;
  send(event: TEvent): void;
}

type AnyActorRef = ActorRef<any, any>;
type AnyActor = Actor<any>;

Callback Actors

Creates actors from callback functions for subscription-based or free-form logic with bidirectional communication.

/**
 * Creates callback actor logic for subscription-based or free-form logic
 * @param callback - Function defining the actor's behavior with access to input, system, self, sendBack, receive, emit
 * @returns CallbackActorLogic that can be used to create actors
 */
function fromCallback<
  TEvent extends EventObject,
  TSentEvent extends EventObject = AnyEventObject,
  TInput = any,
  TEmitted = any
>(
  callback: CallbackLogicFunction<TEvent, TSentEvent, TInput, TEmitted>
): CallbackActorLogic<TEvent, TInput, TEmitted>;

type CallbackLogicFunction<
  TEvent extends EventObject,
  TSentEvent extends EventObject,
  TInput,
  TEmitted
> = (params: {
  /** Input data provided to the actor */
  input: TInput;
  /** Actor system reference */
  system: AnyActorSystem;
  /** Reference to this actor */
  self: CallbackActorRef<TEvent, TInput>;
  /** Function to send events back to parent */
  sendBack: (event: TSentEvent) => void;
  /** Function to register event handler */
  receive: (listener: (event: TEvent) => void) => void;
  /** Function to emit events to external handlers */
  emit: (event: TEmitted) => void;
}) => (() => void) | void;

type CallbackActorLogic<TEvent extends EventObject, TInput, TEmitted> = 
  ActorLogic<CallbackSnapshot<TInput>, TEvent, TInput, AnyEventObject, TEmitted>;

interface CallbackSnapshot<TInput> extends Snapshot<undefined> {
  input: TInput;
}

type CallbackActorRef<TEvent extends EventObject, TInput> = 
  ActorRef<CallbackSnapshot<TInput>, TEvent>;

Usage Examples:

import { fromCallback, createActor } from "xstate/actors";

// WebSocket callback actor
const websocketLogic = fromCallback(({ input, sendBack, receive, emit }) => {
  const ws = new WebSocket(input.url);
  
  ws.onopen = () => emit({ type: "connected" });
  ws.onmessage = (event) => sendBack({ type: "MESSAGE", data: event.data });
  ws.onerror = (error) => sendBack({ type: "ERROR", error });
  
  receive((event) => {
    if (event.type === "SEND") {
      ws.send(event.data);
    }
  });
  
  return () => ws.close();
});

const actor = createActor(websocketLogic, {
  input: { url: "ws://localhost:8080" }
});

Promise Actors

Creates actors from async functions that resolve to a single value.

/**
 * Creates promise actor logic from an async process
 * @param promiseCreator - Async function that returns a promise
 * @returns PromiseActorLogic that resolves/rejects and emits the result
 */
function fromPromise<TOutput, TInput = any, TEmitted = any>(
  promiseCreator: (params: {
    input: TInput;
    system: AnyActorSystem;
    self: PromiseActorRef<TOutput>;
    signal: AbortSignal;
    emit: (event: TEmitted) => void;
  }) => PromiseLike<TOutput>
): PromiseActorLogic<TOutput, TInput, TEmitted>;

type PromiseActorLogic<TOutput, TInput, TEmitted> = 
  ActorLogic<PromiseSnapshot<TOutput, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;

interface PromiseSnapshot<TOutput, TInput> extends Snapshot<TOutput> {
  input: TInput;
}

type PromiseActorRef<TOutput> = ActorRef<PromiseSnapshot<TOutput, any>, AnyEventObject>;

Usage Examples:

import { fromPromise, createActor } from "xstate/actors";

// Fetch data promise actor
const fetchUserLogic = fromPromise(async ({ input, signal, emit }) => {
  emit({ type: "FETCH_START" });
  
  const response = await fetch(`/api/users/${input.userId}`, {
    signal
  });
  
  if (!response.ok) {
    throw new Error(`Failed to fetch user: ${response.status}`);
  }
  
  const user = await response.json();
  emit({ type: "FETCH_SUCCESS", user });
  
  return user;
});

const actor = createActor(fetchUserLogic, {
  input: { userId: "123" }
});

Observable Actors

Creates actors from observable streams for reactive programming patterns.

/**
 * Creates observable actor logic from an observable stream
 * @param observableCreator - Function that creates a subscribable stream
 * @returns ObservableActorLogic that emits values from the stream
 */
function fromObservable<TContext, TInput = any, TEmitted = any>(
  observableCreator: (params: {
    input: TInput;
    system: AnyActorSystem;
    self: ObservableActorRef<TContext>;
    emit: (event: TEmitted) => void;
  }) => Subscribable<TContext>
): ObservableActorLogic<TContext, TInput, TEmitted>;

/**
 * Creates event observable actor logic that sends events to parent
 * @param lazyObservable - Function that creates a subscribable event stream
 * @returns ObservableActorLogic that forwards events to parent
 */
function fromEventObservable<TEvent extends EventObject, TInput = any, TEmitted = any>(
  lazyObservable: (params: {
    input: TInput;
    system: AnyActorSystem;
    self: ObservableActorRef<TEvent>;
    emit: (event: TEmitted) => void;
  }) => Subscribable<TEvent>
): ObservableActorLogic<TEvent, TInput, TEmitted>;

type ObservableActorLogic<TContext, TInput, TEmitted> = 
  ActorLogic<ObservableSnapshot<TContext, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;

interface ObservableSnapshot<TContext, TInput> extends Snapshot<undefined> {
  context: TContext;
  input: TInput;
}

type ObservableActorRef<TContext> = ActorRef<ObservableSnapshot<TContext, any>, AnyEventObject>;

Transition Actors

Creates actors from transition functions for reducer-like state management.

/**
 * Creates transition actor logic from a transition function and initial state
 * @param transition - Function that computes next state given current state and event
 * @param initialContext - Initial state value or factory function
 * @returns TransitionActorLogic for reducer-like state management
 */
function fromTransition<TContext, TEvent extends EventObject, TInput = any, TEmitted = any>(
  transition: (
    state: TContext,
    event: TEvent,
    actorScope: ActorScope<TContext, TEvent, TEmitted>
  ) => TContext,
  initialContext: TContext | ((input: TInput) => TContext)
): TransitionActorLogic<TContext, TEvent, TInput, TEmitted>;

type TransitionActorLogic<TContext, TEvent extends EventObject, TInput, TEmitted> = 
  ActorLogic<TransitionSnapshot<TContext>, TEvent, TInput, AnyEventObject, TEmitted>;

interface TransitionSnapshot<TContext> extends Snapshot<undefined> {
  context: TContext;
}

type TransitionActorRef<TContext, TEvent extends EventObject> = 
  ActorRef<TransitionSnapshot<TContext>, TEvent>;

Actor Utilities

Utility functions and types for working with actors and actor systems.

/**
 * Creates an empty actor with undefined context
 * @returns Empty actor reference
 */
function createEmptyActor(): ActorRef<Snapshot<undefined>, AnyEventObject, AnyEventObject>;

/**
 * Converts actor to a promise that resolves when actor reaches final state
 * @param actor - Actor to convert
 * @returns Promise that resolves with actor output
 */
function toPromise<TActor extends AnyActorRef>(
  actor: TActor
): Promise<OutputFrom<TActor>>;

/**
 * Waits for actor to reach specific conditions
 * @param actor - Actor to observe
 * @param predicate - Condition to wait for
 * @param options - Optional timeout and other options
 * @returns Promise that resolves when condition is met
 */
function waitFor<TActor extends AnyActorRef, T>(
  actor: TActor,
  predicate: (snapshot: SnapshotFrom<TActor>) => T | undefined,
  options?: { timeout?: number }
): Promise<T>;

Actor System Types

interface ActorSystem<T extends Record<string, AnyActorLogic>> {
  /** Get actor by ID */
  get<K extends keyof T>(id: K): ActorRefFrom<T[K]>;
  /** Register actor logic */
  register<TActorLogic extends AnyActorLogic>(
    id: string,
    actorLogic: TActorLogic
  ): ActorRefFrom<TActorLogic>;
}

interface ActorScope<TContext, TEvent extends EventObject, TEmitted> {
  /** Reference to this actor */
  self: ActorRef<any, TEvent>;
  /** Function to emit events */
  emit: (event: TEmitted) => void;
  /** Actor system reference */
  system: AnyActorSystem;
}

interface Observer<T> {
  next?: (value: T) => void;
  error?: (error: any) => void;
  complete?: () => void;
}

interface Subscription {
  unsubscribe(): void;
}

interface Subscribable<T> {
  subscribe(observer: Observer<T>): Subscription;
  subscribe(
    next: (value: T) => void,
    error?: (error: any) => void,
    complete?: () => void
  ): Subscription;
}

Install with Tessl CLI

npx tessl i tessl/npm-xstate

docs

actions.md

actors.md

graph-utilities.md

guards.md

index.md

state-machines.md

tile.json