@lacspace/machine
A tiny, fully type-safe finite state machine — declare states, events, guarded transitions, entry/exit/transition actions and a typed context. A pure transition() function plus an interpret() actor with send/subscribe/matches. Context updates are immutable via assign(). A lightweight xstate alternative for the 90% case. Zero-dependency, isomorphic.
npm i @lacspace/machineUsage
import { createMachine, assign, interpret } from "@lacspace/machine";
const toggle = createMachine<{ count: number }, { type: "TOGGLE" }>({
initial: "inactive",
context: { count: 0 },
states: {
inactive: { on: { TOGGLE: { target: "active", actions: assign((c) => ({ count: c.count + 1 })) } } },
active: { on: { TOGGLE: "inactive" } },
},
});
// pure — great for reducers/tests
const next = toggle.transition(toggle.initialState, { type: "TOGGLE" });
next.value; // "active"
next.context.count; // 1
// or run it as a live actor
const actor = interpret(toggle).start();
actor.subscribe((s) => console.log(s.value));
actor.send({ type: "TOGGLE" });Exports 4
createMachineassigninterpretcreateActorKeywords
More in Core Runtime Kit
A tiny structured logger for Node and the browser — leveled JSON logging, child loggers, field redaction and pluggable transports (JSON, pretty, in-memory). A log below the active level costs almost nothing: the record is never even built. Errors serialise automatically; secrets get redacted before they leave the logger. Zero-dependency, isomorphic.
@lacspace/resultTyped, functional error handling — Result<T,E> (Ok/Err) and Option<T> (Some/None) so functions return errors as values instead of throwing. Constructors, guards, map/andThen/match, unwrap variants, trySync/tryAsync to wrap throwing code, and an all() combinator that short-circuits on the first error. Tree-shakeable, zero-dependency, isomorphic.
@lacspace/eventsA fully type-safe event emitter / tiny pub-sub for Node and the browser. Declare an events map (name → payload type) and get compile-time-checked on/emit. A throwing listener never blocks the others (errors are isolated), adding or removing listeners mid-emit is safe, and once/waitFor/onAny round it out. Comparable to mitt or nanoevents but strongly typed. Zero-dependency, isomorphic.
@lacspace/queueAn in-memory async task queue with a concurrency limit — run up to N async tasks at once and await individual results or the whole drain. Priority ordering, pause/start, clear, onIdle/onEmpty draining, and per-task abort via AbortSignal. A rejected task never stalls the queue. Comparable to p-queue/p-limit but tiny and dependency-free. Isomorphic.
@lacspace/schedulerAn in-process job scheduler that actually runs your callbacks — on a recurring interval, a standard 5-field cron schedule, or at a specific time. A self-rescheduling, drift-corrected timer (never setInterval), overlap protection so an async job never runs over itself, jitter, maxRuns and error isolation. Clock and timers are injectable, so it's fully testable without real time. Zero-dependency, isomorphic.