Reference

API reference

@stateledger/core

Public surface of the core package.

defineMachine(config)

Factory that returns a MachineFactory. The config is validated at runtime and its states and transitions are narrowed at the type level.

typescript
function defineMachine<C extends MachineConfig>(config: C): MachineFactory<C>;

type MachineConfig = {
  readonly name: string;
  readonly states: readonly string[];
  readonly initialState: string;
  readonly transitions: readonly { readonly from: string; readonly to: string }[];
  readonly version?: number;
  readonly guards?: Record<string, GuardFn>;
  readonly callbacks?: Record<string, CallbackFn>;
};

type MachineFactory<C> = {
  config: C;
  for<TxHandle, Subject>(
    subjectId: string,
    opts: BindOptions<TxHandle, Subject>,
  ): Machine<C, TxHandle, Subject>;
};

factory.for(subjectId, opts)

Binds a machine definition to a specific subject. Returns a live Machine instance.

typescript
type BindOptions<TxHandle, Subject> = {
  adapter: Adapter<TxHandle>;
  tx?: TxHandle;         // Join an outer transaction (optional)
  actor?: Actor | string; // Default actor recorded on every transition
  subject?: Subject;     // Full business subject exposed to guards/callbacks
};

Machine methods

  • transitionTo(target, opts?): Promise<TransitionRow>
    Attempt the transition. Throws InvalidTransition, GuardRejected, or OptimisticConcurrencyError.
  • in(from).transitionTo(target)
    Type-only sugar. Narrows autocomplete to states reachable from from. Runtime behaviour is identical to transitionTo(target).
  • readCurrent(): Promise<TransitionRow | null>
    Latest transition row for this subject. Null if the subject has never transitioned.
  • readHistory(): Promise<TransitionRow[]>
    All transitions for this subject, oldest first. Includes state, actor, timestamp, metadata for each hop.
  • stateAt(at: Date): Promise<State | null>
    Point-in-time query. Returns the state as of the given timestamp, or null if the subject didn’t exist yet.

TransitionOptions

typescript
type TransitionOptions = {
  metadata?: Record<string, unknown>;  // Arbitrary JSON stored on the row
  actor?: Actor | string;              // Override the bind-time actor
};

Types you'll import

typescript
type Actor = { id: string; type: string } | string;

type TransitionRow<State = string> = {
  id: string;
  machine: string;
  subjectId: string;
  fromState: State | null;
  toState: State;
  actor: string | null;
  metadata: Record<string, unknown> | null;
  transitionedAt: Date;
  createdAt: Date;
};

type GuardContext<Subject> = {
  subject: Subject;
  from: string;
  to: string;
  actor: string | null;
  metadata: Record<string, unknown>;
};

type CallbackContext<TxHandle, Subject> = GuardContext<Subject> & {
  tx: TxHandle;
  subjectId: string;
};

type InferMachineState<F> = /* union of the machine's state literals */;

Errors

All errors extend StateledgerError. See the errors reference for exact field shapes and handling patterns.

  • • InvalidTransition
  • • GuardRejected
  • • OptimisticConcurrencyError
  • • StaleSubjectError
  • • AdapterError

@stateledger/prisma

typescript
function createPrismaAdapter(
  client: PrismaClient | Prisma.TransactionClient,
  options?: {
    tableName?: string;             // default "state_transitions"
    locking?: "pessimistic" | "optimistic";  // default "pessimistic"
  },
): Adapter<PrismaRawCalls>;

// Shipped schema SQL you can run at setup or paste into a migration:
const STATELEDGER_SCHEMA_SQL: string;
const STATELEDGER_SCHEMA_STATEMENTS: string[];

@stateledger/drizzle

typescript
function createDrizzleAdapter(
  db: DrizzleClient | DrizzleTx,
  options?: { tableName?: string; locking?: "pessimistic" | "optimistic" },
): Adapter<DrizzleTx>;

const STATELEDGER_SCHEMA_SQL: string;

@stateledger/memory

typescript
class InMemoryAdapter implements Adapter<InMemoryTx>;
// Use: const adapter = new InMemoryAdapter();

@stateledger/outbox

typescript
// Enqueue
function enqueue<Payload extends Record<string, unknown>>(
  tx: OutboxTx,
  input: EnqueueInput<Payload>,
): Promise<OutboxRecord<Payload>>;

function enqueueBatch<Payload extends Record<string, unknown>>(
  tx: OutboxTx,
  inputs: readonly EnqueueInput<Payload>[],
): Promise<OutboxRecord<Payload>[]>;

// Worker
function createWorker(config: WorkerConfig): WorkerHandle;
function defaultBackoffMs(attempt: number): number;

// Schema
const OUTBOX_SCHEMA_STATEMENTS: readonly string[];
const OUTBOX_SCHEMA_SQL: string;

// Errors
class OutboxError extends Error {}
class OutboxAdapterError extends OutboxError {}
class UnknownKindError extends OutboxError {
  readonly kind: string;
  readonly recordId: string;
}

// Structural tx handle | any Prisma/Drizzle/pg client satisfies this
type OutboxTx = {
  $queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Promise<T>;
  $executeRawUnsafe(query: string, ...values: any[]): Promise<unknown>;
};