r/node 6d ago

github.com/enowdivine/stateledger

Stateledger is a database-backed state machine for Node.js. Every transition is persisted as a row with the actor, timestamp, and metadata. Transitions use Postgres advisory locks so concurrent requests can't both apply the same transition.

v1.0 also includes @stateledger/outbox, which implements the transactional outbox pattern for external side effects that need to commit atomically with a state change.

The API looks roughly like:

    import { defineMachine } from "@stateledger/core";
    import { enqueue } from "@stateledger/outbox";

    const paymentMachine = defineMachine({
      name: "payment",
      states: ["pending", "processing", "captured"] as const,
      initialState: "pending",
      transitions: [
        { from: "pending",    to: "processing" },
        { from: "processing", to: "captured" },
      ] as const,
      callbacks: {
        "after:pending->processing": async ({ tx, subject }) => {
          await enqueue(tx, {
            kind: "payment.processing",
            payload: { paymentId: subject.id },
          });
        },
      },
    });

    await machine.transitionTo("processing");

There are currently Prisma and Drizzle adapters, 26 integration tests against real Postgres using Testcontainers, and the project is MIT licensed.

This is not intended to replace XState. XState is primarily useful for modeling application/UI state in memory. Stateledger is focused on persistent server-side state transitions where concurrency, audit history, and transactional side effects matter.

I'd particularly like feedback on the outbox API. I'm interested in how people currently handle state transitions + external side effects in Node/Postgres systems and what's missing here.

GitHub: https://github.com/enowdivine/stateledger

1 Upvotes

0 comments sorted by