@statedelta-apex/derived-states
v3.0.0
Published
...
Readme
@statedelta-apex/derived-states
Três tipos derivados de domínio que compõem sobre primitivos via DerivedState:
| Tipo | Domínio | Composição interna |
| ----------------------- | ---------------------------------------------- | -------------------- |
| CounterState | número com bounds, step e clamping automático | wrappa RecordState |
| FlagsState | set de strings com whitelist opcional e toggle | wrappa RecordState |
| StateMachineState | FSM com grafo pré-compilado de transições | wrappa RecordState |
Cada um expõe apenas actions de domínio (hp.increment(), status.add(), phase.transition()) — a API do RecordState interno é invisível. Toda a mecânica de transaction, snapshot, middleware, observação dual, lock e checkpoints é herdada automaticamente via DerivedState.
Mecânica compartilhada e contratos: veja o README do
@statedelta-apex/store. Este pacote só adiciona semântica de domínio.
Instalação
pnpm add @statedelta-apex/derived-statesRequer @statedelta-apex/store e @statedelta-apex/record-state como peer dependencies.
Exports
import {
CounterState,
createCounter,
counterPlugin,
FlagsState,
createFlags,
flagsPlugin,
StateMachineState,
createStateMachine,
statemachinePlugin,
} from "@statedelta-apex/derived-states";
import type {
CounterData,
CounterConfig,
FlagsData,
FlagsConfig,
StateMachineData,
StateMachineConfig,
TransitionRule,
} from "@statedelta-apex/derived-states";Os três *Plugin são manifestos declarativos para o @statedelta-apex/router.
CounterState
Valor numérico com min/max/step e clamping automático. Cobre HP/MP, ammo, cooldowns, XP, scores, progress bars, budgets, turn counters.
const hp = createCounter("hp", { value: 100, min: 0, max: 100 });
const xp = createCounter("xp", { value: 0, min: 0 }); // sem maxActions
hp.increment(); // +step (default 1)
hp.increment(30); // +30
hp.decrement(50); // clampa em min se passar
hp.set(75); // direto (clampa aos bounds)
hp.fill(); // value = max
hp.empty(); // value = min
hp.reset(); // volta ao valor de criação
// Runtime bounds (level up, debuff, etc.)
hp.setMax(150);
hp.setMin(10);
hp.setStep(5);Getters
hp.value; // 100
hp.initial; // 100
hp.min; // 0
hp.max; // 100
hp.step; // 1
hp.percentage; // 1.0 (0–1)
hp.isMin; // false
hp.isMax; // true
hp.canIncrement; // false (em max)
hp.canDecrement; // trueFlagsState
Set de flags (strings) com whitelist opcional e batch atômico. Cada flag é uma key — operações são O(1). Cobre status effects, feature flags, permissions, pipeline stages.
const status = createFlags("status", {
initial: ["alive"],
allowed: ["alive", "poisoned", "stunned", "shielded", "burning"],
});
const features = createFlags("features"); // sem whitelist — qualquer flagActions
status.add("poisoned"); // no-op se já existe
status.remove("poisoned");
status.toggle("shielded");
// Batch atômico — uma mutação, um notify
status.addMany("strength", "haste");
status.removeMany("strength", "haste");
status.set(["alive", "shielded"]); // replace all
status.clear();
status.reset();Getters
status.has("poisoned"); // O(1)
status.hasAll("alive", "poisoned"); // todos presentes
status.hasAny("stunned", "frozen"); // pelo menos um
status.hasNone("stunned", "frozen"); // nenhum
status.all; // ["alive", "poisoned"] (novo array)
status.size;
status.isEmpty;
status.allowed; // readonly string[] | nullStateMachineState
Máquina de estados finita com grafo de transições pré-compilado em Map<string, Set<string>>. Checagens de transição são O(1). Suporta wildcards ("*"), arrays e bypass.
const phase = createStateMachine("phase", {
initial: "menu",
states: ["menu", "playing", "paused", "gameover"],
transitions: [
{ from: "menu", to: "playing" },
{ from: "playing", to: ["paused", "gameover"] },
{ from: "paused", to: ["playing", "menu"] },
{ from: "*", to: "gameover" }, // wildcard: qualquer → gameover
],
});TransitionRule
// Arrays — múltiplos destinos ou origens
{ from: "playing", to: ["paused", "gameover"] }
{ from: ["a", "b"], to: "c" }
// Wildcards
{ from: "*", to: "error" } // qualquer → error
{ from: "admin", to: "*" } // admin → qualquerActions
phase.transition("playing"); // validada pelo grafo
phase.transition("gameover"); // throws se não permitida
phase.force("gameover"); // bypass do grafo (admin/debug)
phase.reset();Getters
phase.current; // "menu"
phase.initial; // "menu"
phase.is("menu"); // true
phase.can("playing"); // true
phase.available; // ["playing"] — destinos permitidos a partir de current
phase.states; // readonly all statesFeatures herdadas (todos os três tipos)
Como derivam de State<T> via DerivedState, automaticamente suportam:
- Transaction —
state.transaction(fn),state.simulate(fn), manualbeginTransaction/commit/rollback - Subscribe —
state.subscribe(fn, { internal?: boolean }) - Meta —
state.meta(),state.subscribeMeta() - Middleware —
state.use(fn) - Lock —
state.lock(),state.unlock(),state.isLocked - Persistence —
state.snapshot(),state.restore() - Strict mode — via
stateConfig: { strict: true } - Integration com Store —
store.register(derivedState), participa de transactions cross-state, registry transacional, checkpoints
Documentação completa de cada uma dessas em store/README.md.
Plugins para Router
Os três tipos têm plugins declarativos para o @statedelta-apex/router, permitindo dispatch untyped via DSL:
import { createRouter } from "@statedelta-apex/router";
import {
counterPlugin,
flagsPlugin,
statemachinePlugin,
} from "@statedelta-apex/derived-states";
const router = createRouter(store);
router.register(counterPlugin);
router.register(flagsPlugin);
router.register(statemachinePlugin);
router.dispatch("hp", "dec", { value: 30 });
router.dispatch("status", "add", { value: "poisoned" });
router.dispatch("phase", "transition", { to: "playing" });License
MIT
