Reliev 🩹
Reliev is a small store library on top of observ that adds undo/redo to reactive state. You subclass Store, mark the methods that change state with @mutation, and every call records a history entry that can be undone and redone. Patches are recorded with patchdiff, so a mutation costs what it changes, not the size of your state.
from reliev import Store, mutation
class TodoStore(Store):
@mutation(context=lambda self, item: f"Add {item}")
def add_item(self, item):
self.state["items"].append(item)
store = TodoStore({"items": []})
store.add_item("apple")
assert store.state["items"] == ["apple"]
assert store.undo_context == "Add apple" # e.g. menu item "Undo Add apple"
store.undo()
assert store.state["items"] == []
store.redo()
assert store.state["items"] == ["apple"]
Because the state is an observ reactive proxy, everything composes with observ's watch and computed: watchers see exactly the keys a mutation (or an undo) touched, and the @computed decorator exposes derived state as store properties.
Where to start
- The quick start walks through a complete store.
- The guide covers mutations, undo & redo, mutation context, computed properties, nested mutations and reactivity in more detail.
- The complete public API is documented in the API reference.
- The internals page describes how everything works under the hood.