Files
skills/docs/media/audio/audio-controllers/src/base/connection-fsm.md
2026-05-29 08:20:56 +01:00

2.2 KiB

connection-fsm

Purpose

Builds the controller connection-state machine consumed by every MidiControllerPlugin. The FSM models the lifecycle of a hardware controller's MIDI access: a fresh controller starts disconnected, moves through connecting, settles in connected, and falls into error on any access failure or rejected transition. Because the FSM is driven from both the adapter (real connect/disconnect) and from handleStateChange (hot-plug events from navigator.requestMIDIAccess().onstatechange-shaped sources), centralising the rules here keeps every device subclass ignorant of state-machine details.

Features

  • createConnectionMachine() returns an @suaveplan/fsm interpreter with the four canonical states pre-wired.
  • sendOrThrow(machine, event) converts the FSM's underlying INVALID_TRANSITION into a domain-stable AudioControllersError("AUDIO_CONTROLLERS.INVALID_STATE") with the offending from and event carried in context.
  • Transition table mirrors the spec exactly: DISCONNECT, CONNECT, CONNECTED, ERROR, RESET.

Usage: Basic

import { createConnectionMachine, sendOrThrow } from "@suaveplan/audio-controllers";

const m = createConnectionMachine();
sendOrThrow(m, "CONNECT");
sendOrThrow(m, "CONNECTED");

Usage: Advanced

const m = createConnectionMachine();
m.onTransition((state) => log.debug({ value: state.value }, "controller-fsm"));
try {
  sendOrThrow(m, "CONNECTED"); // illegal from `disconnected`
} catch (err) {
  if (err instanceof AudioControllersError) {
    expect(err.code).toBe(AUDIO_CONTROLLERS_CODES.INVALID_STATE);
  }
}

API Reference

  • createConnectionMachine() → FSMInterpreter<{ lastError?: string }>.
  • sendOrThrow(machine, event) → void.
  • ConnectionMachine — re-exported interpreter type alias.

Implementation Notes

A local TRANSITIONS table is consulted before delegating to the FSM's own dispatcher so the package surface throws an AUDIO_CONTROLLERS.* error rather than the raw FSM.INVALID_TRANSITION code. The state graph deliberately omits transitions out of error other than RESET to force callers to explicitly acknowledge recovery — accidental re-CONNECT from error would mask the original failure.