StateKeeper Svelte Themes

Statekeeper

StateKeeper is a powerful and flexible history management library that provides undo/redo functionality for any JavaScript application. Built on a micro-kernel architecture with zero runtime dependencies.

StateKeeper

Zero-dependency undo/redo history manager with micro-kernel plugin architecture

StateKeeper is a powerful and flexible history management library that provides undo/redo functionality for any JavaScript application. Built on a micro-kernel architecture with zero runtime dependencies.

🎯 Features

  • Zero Dependencies - No external runtime dependencies
  • Multiple Strategies - Choose between Snapshot, Command, or Patch strategies
  • Micro-Kernel Architecture - Extend with plugins
  • Framework Agnostic - Works with vanilla JS, React, Vue, Svelte, or any framework
  • Full TypeScript Support - Written in TypeScript with strict mode
  • Branching Support - Git-like branching for alternative timelines (via plugin)
  • Persistence - Save/restore history to any storage (via plugin)
  • Time Travel Debugging - Visual timeline UI (via plugin)
  • Tree-Shakeable - Only bundle what you use

📦 Installation

npm install @oxog/statekeeper
yarn add @oxog/statekeeper
pnpm add @oxog/statekeeper

🚀 Quick Start

Basic Usage

import { createHistory } from '@oxog/statekeeper'

// Create a history manager
const history = createHistory({
  initialState: { count: 0 },
  limit: 100, // Maximum 100 history entries
})

// Make changes
history.push({ count: 1 })
history.push({ count: 2 })
history.push({ count: 3 })

console.log(history.getState()) // { count: 3 }

// Undo
history.undo()
console.log(history.getState()) // { count: 2 }

// Redo
history.redo()
console.log(history.getState()) // { count: 3 }

React Integration

import { createHistory } from '@oxog/statekeeper'
import { useState, useEffect } from 'react'

function Counter() {
  const [history] = useState(() =>
    createHistory({ initialState: { count: 0 } })
  )
  const [state, setState] = useState(history.getState())

  useEffect(() => {
    return history.on('state-change', (event) => {
      setState(event.state)
    })
  }, [history])

  const increment = () => {
    history.push({ count: state.count + 1 })
  }

  return (
    <div>
      <h1>{state.count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={() => history.undo()} disabled={!history.canUndo()}>
        Undo
      </button>
      <button onClick={() => history.redo()} disabled={!history.canRedo()}>
        Redo
      </button>
    </div>
  )
}

📖 Strategies

StateKeeper supports three different strategies for managing history:

Snapshot Strategy (Default)

Stores complete state copies. Simple and fast for small to medium state.

const history = createHistory({
  initialState: { count: 0 },
  strategy: 'snapshot' // or omit (default)
})

Pros:

  • Simple to understand
  • Fast undo/redo
  • Works with any state structure

Cons:

  • Higher memory usage for large states

Command Strategy

Stores executable commands with undo/redo logic. Most memory efficient.

import { createHistory, defineCommand } from '@oxog/statekeeper'

// Define commands
const incrementCommand = defineCommand({
  name: 'increment',
  execute: (state, amount: number) => ({
    ...state,
    count: state.count + amount
  }),
  undo: (state, amount: number) => ({
    ...state,
    count: state.count - amount
  })
})

const history = createHistory({
  initialState: { count: 0 },
  strategy: 'command'
})

const commandStrategy = history.getStrategy()
commandStrategy.registerCommand(incrementCommand)

// Execute command
const newState = commandStrategy.execute(incrementCommand, 5, history.getState())
history.push(newState)

Pros:

  • Memory efficient
  • Explicit intent
  • Easy to debug

Cons:

  • Requires command definitions
  • More setup code

Patch Strategy

Stores diffs using RFC 6902 JSON Patch. Efficient for large states with small changes.

const history = createHistory({
  initialState: { count: 0, name: 'John', items: [] },
  strategy: 'patch'
})

Pros:

  • Memory efficient for large states
  • Automatic diff calculation
  • Small payload size

Cons:

  • Slower than snapshot for small states
  • Complex for debugging

🎨 API Reference

Core API

createHistory(options)

Creates a history manager instance.

const history = createHistory({
  initialState: T,        // Required: Initial state
  strategy?: StrategyName, // Optional: 'snapshot' | 'command' | 'patch'
  limit?: number,         // Optional: Max entries (default: 100)
  plugins?: Plugin[]      // Optional: Plugins to register
})

State Management

history.getState()           // Get current state
history.setState(state)      // Set state directly (bypasses history)
history.getInitialState()    // Get initial state

History Operations

history.push(state, metadata?)  // Push new state
history.undo()                  // Undo to previous state
history.redo()                  // Redo to next state
history.canUndo()               // Check if undo is possible
history.canRedo()               // Check if redo is possible
history.clear()                 // Clear all history
history.goTo(position)          // Jump to specific position

History Access

history.getHistory()     // Get complete history stack
history.getPosition()    // Get current position
history.getLength()      // Get number of entries

Events

// Subscribe to events
const unsubscribe = history.on('state-change', (event) => {
  console.log('State changed:', event.state)
})

// Unsubscribe
unsubscribe()

// Available events:
// - 'push'
// - 'undo'
// - 'redo'
// - 'state-change'
// - 'clear'
// - 'destroy'

Lifecycle

history.destroy()         // Clean up and destroy instance
history.isDestroyed()     // Check if destroyed

🔌 Plugins

StateKeeper can be extended with plugins. Full plugin system with branching, persistence, keyboard shortcuts, compression, and time-travel UI will be available soon.

import { createHistory } from '@oxog/statekeeper'
// Plugins coming soon:
// import { branching, persistence, keyboardShortcuts } from '@oxog/statekeeper/plugins'

const history = createHistory({
  initialState: { count: 0 },
  // plugins: [branching(), persistence({ key: 'my-app' }), keyboardShortcuts()]
})

📚 Documentation

Full documentation website coming soon at statekeeper.oxog.dev

🤝 Contributing

Contributions are welcome! Please read our contributing guidelines first.

📄 License

MIT © 2025 Ersin KOÇ


Made with ❤️ by Ersin KOÇ

Top categories

Loading Svelte Themes