# @suaveplan/undo - Enterprise-grade undo/redo engine with branching history, async commands, history compression, selective undo, and command merging ## Summary Enterprise-grade undo/redo engine with branching history, async commands, history compression, selective undo, and command merging. Built for collaborative editors, document tools, and any application requiring robust, reversible state management. ## Documentation tree - [async-command](./src/async/async-command.md) — Provides factory functions and execution helpers for asynchronous commands in `@suaveplan/undo`. Async commands follow… - [async-stack](./src/async/async-stack.md) — Implements `AsyncUndoStack`, the asynchronous counterpart to `UndoStack`. All mutation methods (`push`, `undo`, `… - [branch](./src/branch/branch.md) — _(no submodules)_ - [branch](./src/branch/branch.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_ - [compression](./src/compression/history-compressor.md) — _(no submodules)_ - [history-compressor](./src/compression/history-compressor.md) — _(no submodules)_ - [errors](./src/errors/undo-error.md) — _(no submodules)_ - [undo-error](./src/errors/undo-error.md) — _(no submodules)_ - [merge](./src/merge/command-merger.md) — _(no submodules)_ - [command-merger](./src/merge/command-merger.md) — _(no submodules)_ - [schemas](./src/schemas/undo.schemas.md) — _(no submodules)_ - [undo.schemas](./src/schemas/undo.schemas.md) — _(no submodules)_ - [selective](./src/selective/selective-undo.md) — _(no submodules)_ - [selective-undo](./src/selective/selective-undo.md) — _(no submodules)_ - [stack](./src/stack/stack.md) — _(no submodules)_ - [stack](./src/stack/stack.md) — _(no submodules)_ - [branch](./src/branch/branch.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [compression](./src/compression/history-compressor.md) — _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — _(no submodules)_- [errors](./src/errors/undo-error.md) — _(no submodules)_- [undo-error](./src/errors/undo-error.md) — _(no submodules)_- [merge](./src/merge/command-merger.md) — _(no submodules)_- [command-merger](./src/merge/command-merger.md) — _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [selective](./src/selective/selective-undo.md) — _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [branch](./src/branch/branch.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [compression](./src/compression/history-compressor.md) — _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — _(no submodules)_- [errors](./src/errors/undo-error.md) — _(no submodules)_- [undo-error](./src/errors/undo-error.md) — _(no submodules)_- [merge](./src/merge/command-merger.md) — _(no submodules)_- [command-merger](./src/merge/command-merger.md) — _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [selective](./src/selective/selective-undo.md) — _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [branch](./src/branch/branch.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [compression](./src/compression/history-compressor.md) — _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — _(no submodules)_- [errors](./src/errors/undo-error.md) — _(no submodules)_- [undo-error](./src/errors/undo-error.md) — _(no submodules)_- [merge](./src/merge/command-merger.md) — _(no submodules)_- [command-merger](./src/merge/command-merger.md) — _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [selective](./src/selective/selective-undo.md) — _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_- [branch](./src/branch/branch.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_- [compression](./src/compression/history-compressor.md) — _(no submodules)_ - [history-compressor](./src/compression/history-compressor.md) — _(no submodules)_- [errors](./src/errors/undo-error.md) — _(no submodules)_ - [undo-error](./src/errors/undo-error.md) — _(no submodules)_- [merge](./src/merge/command-merger.md) — _(no submodules)_ - [command-merger](./src/merge/command-merger.md) — _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — _(no submodules)_ - [undo.schemas](./src/schemas/undo.schemas.md) — _(no submodules)_- [selective](./src/selective/selective-undo.md) — _(no submodules)_ - [selective-undo](./src/selective/selective-undo.md) — _(no submodules)_- [stack](./src/stack/stack.md) — _(no submodules)_ - [stack](./src/stack/stack.md) — _(no submodules)_ ## Install ```bash bun add @suaveplan/undo ``` ## Quick Start ```ts import { UndoStack, createCommand } from "@suaveplan/undo"; interface Counter { value: number } const stack = new UndoStack({ value: 0 }); const inc = createCommand( "Increment", (s) => ({ value: s.value + 1 }), (s) => ({ value: s.value - 1 }), ); stack.push(inc); console.log(stack.current.value); // 1 stack.undo(); console.log(stack.current.value); // 0 stack.redo(); console.log(stack.current.value); // 1 ``` ### Branching History ```ts import { BranchingHistory, createCommand } from "@suaveplan/undo"; const h = new BranchingHistory({ value: 0 }); h.push(createCommand("A", (s) => ({ value: s.value + 1 }), (s) => ({ value: s.value - 1 }))); h.undo(); h.push(createCommand("B", (s) => ({ value: s.value + 2 }), (s) => ({ value: s.value - 2 }))); // forks console.log(h.branches.length); // 2 ``` ## Modules | Module | Description | |--------|-------------| | [`src/command/command.md`](src/command/command.md) | Command factories and execution helpers | | [`src/stack/stack.md`](src/stack/stack.md) | Synchronous linear undo/redo stack | | [`src/branch/branch.md`](src/branch/branch.md) | Branching history manager | | [`src/async/async-command.md`](src/async/async-command.md) | Async command factories | | [`src/async/async-stack.md`](src/async/async-stack.md) | Async undo/redo stack | | [`src/compression/history-compressor.md`](src/compression/history-compressor.md) | History compression | | [`src/selective/selective-undo.md`](src/selective/selective-undo.md) | Selective undo by command ID | | [`src/merge/command-merger.md`](src/merge/command-merger.md) | Command merging / coalescing | | [`src/types/undo.types.md`](src/types/undo.types.md) | All types and type guards | | [`src/schemas/undo.schemas.md`](src/schemas/undo.schemas.md) | Zod option schemas | | [`src/errors/undo-error.md`](src/errors/undo-error.md) | Structured errors and codes | ## Benchmarks Measured on an AMD Ryzen 5 (WSL2), 1000 iterations: | Operation | Throughput | |-----------|-----------| | UndoStack push/undo/redo (closure) | ~250k ops/s | | UndoStack push/undo (patch, 50 fields) | ~15k ops/s | | compressHistory (1000 entries, depth 100) | ~2k ops/s | > A >10% regression from baseline fails the CI performance gate.