Skip to content

Changelog

1.0.0

Initial stable release.

StateMesh is a TypeScript-first, transaction-first state orchestration library for React. This is the first public release with a stable API, 603 tests across 19 files, and production-grade guarantees.

What's included

  • Core mesh store. External store with getState, setState, setPath, reset, subscribe with selector/equality support, and optimized path-based subscriptions.
  • Named actions. mesh.action(name, handler) and mesh.runAction(name, payload) with error wrapping.
  • Batch operations. mesh.batch(fn) groups multiple state updates into a single notification flush.
  • Computed state. mesh.computed(name, deps, compute) with automatic dirty tracking, dependency intersection, and value caching.
  • Async transactions. Full lifecycle: validation, snapshot, optimistic update, effect, commit, rollback, retry with exponential backoff, timeout, cancellation, status tracking, and logging.
  • Resource cache. mesh.resource(name, fetcher) with request deduplication, invalidation tags, pagination, prefetch, focus/reconnect refetch, polling, LRU cache eviction, dehydration/hydration, and offline support.
  • Mutations. mesh.mutation(name, mutator) with optimistic rollback, queueing, and persistence.
  • Persistence. mesh.persist(options) with localStorage, sessionStorage, IndexedDB, and memory adapters. Version migration and TTL expiration.
  • URL state. mesh.urlState(options) with browser history adapter, custom query param names, and serialization.
  • Forms. mesh.form(name, options) with async field validation, server errors, autosave, dirty tracking, field arrays, and schema adapters.
  • Tab sync. tabSyncPlugin with BroadcastChannel and localStorage fallback.
  • Router. defineRoutes + mesh.router(routes, options) with nested routes, lazy loading, loaders, guards, middleware pipeline, rollback on error, keep-alive pools, predictive prefetch, route analytics, shared element transitions, and SEO meta management.
  • Middleware. mesh.middleware(handler) with Express-style (event, mesh) signature.
  • Guards. mesh.guard(target, handler) for protective side-effect barriers.
  • Plugins. mesh.use(plugin) with setup/cleanup lifecycle.
  • DevTools. Timeline component with dark theme, search, category filters, failed-only view, and export/copy.
  • Error handling. 16 typed error classes with cause chaining, metadata, and codes.
  • Testing utilities. createTestMesh, createMockMesh, mockActions, assertStatePath, assertResourceStatus, waitForTransactionStatus, and more.
  • Undo/Redo. mesh.undo() / mesh.redo() with configurable maxHistory, path-filtered tracking, batch-aware grouping, and reset-aware capture.
  • State Time Travel. mesh.enableTimeTravel() with replayTo(index) and replayToTimestamp(ts) using binary search over a bounded ring buffer.
  • Middleware Pipelines. mesh.pipeline(name, stages, options) with Express-style next() pattern, async stages, short-circuit, event filtering, and before/after phasing.
  • Performance. Path tokenization cache, stable status references, profiler hot-path filter, DevTools snapshot throttling, and shallow-equality action skip.
  • Suspense support. Resource reads via React.use() with error boundary integration.
  • StateMesh Doctor. Runtime diagnostics for common misconfigurations.

Performance characteristics

  • Subscriptions are path-scoped and equality-checked — only relevant subscribers re-render.
  • batch(fn) defers notification flush until the callback returns.
  • Resources deduplicate in-flight requests by key.
  • Computed values are lazily evaluated and cached until dependencies change.
  • Undo/redo and time travel are opt-in and lazy — no memory or CPU cost unless enabled.
  • Time travel uses a bounded ring buffer with configurable maxEntries.
  • Undo stack uses structuredClone snapshots with configurable maxHistory.

Migration

This is the initial release. No migration is needed.


Development History

The following entries document the incremental development milestones that led to 1.0.0.

0.6.0

Undo/Redo

StateMesh now tracks state history for undo/redo operations. Every state change automatically captures a snapshot, and undo()/redo() restore previous/next states atomically.

  • mesh.undo(). Restore the previous state. No-op when the undo stack is empty.
  • mesh.redo(). Restore the next state (undone by undo). No-op when the redo stack is empty.
  • mesh.canUndo. True when the undo stack has at least one entry.
  • mesh.canRedo. True when the redo stack has at least one entry.
  • mesh.undoStackSize. Current number of entries in the undo stack.
  • mesh.redoStackSize. Current number of entries in the redo stack.
  • mesh.clearUndoHistory(). Clear both undo and redo stacks.
  • undo.maxHistory. Maximum undo entries retained. Oldest entries are evicted first. Defaults to 50.
  • undo.paths. Optional array of state paths to track. When omitted, the full state is tracked. Reduces memory by cloning only tracked paths.
  • Batch-aware. Multiple state changes inside mesh.batch() are captured as a single undo entry.
  • Reset-aware. mesh.reset() pushes the pre-reset state to the undo stack.
  • Events. Undo/redo emit state.changed events with metadata.phase set to "undo" or "redo".

State Replay / Time Travel

StateMesh can record all state changes and replay to any point in time. Useful for debugging, testing, and audit trails.

  • mesh.enableTimeTravel(). Start recording state changes.
  • mesh.disableTimeTravel(). Stop recording. Existing log is preserved.
  • mesh.isTimeTravelEnabled. True when recording is active.
  • mesh.getTimeTravelLog(). Return a copy of the recorded log. Each entry contains index, event, stateBefore, stateAfter, and timestamp.
  • mesh.replayTo(index). Restore the state recorded at the given log index.
  • mesh.replayToTimestamp(timestamp). Restore the state recorded nearest to the given timestamp. Uses binary search for O(log n) lookup.
  • mesh.clearTimeTravelLog(). Clear the log and free memory.
  • timeTravel.maxEntries. Ring buffer size. Oldest entries are evicted when exceeded. Defaults to 1000.
  • Replay-safe. Replay does not trigger undo bookkeeping or time travel re-recording.

Middleware Pipelines

StateMesh supports named, composable middleware pipelines with an Express-style next() pattern. Unlike flat middleware, pipelines support short-circuiting, async stages, and before/after phasing relative to existing middleware.

  • mesh.pipeline(name, stages, options?). Register a named pipeline. Each stage receives a PipelineContext (event, mesh, state, stageIndex, stageName) and a next() function. Call next() to continue to the next stage; return without calling next() to short-circuit.
  • mesh.removePipeline(name). Remove a previously registered pipeline.
  • options.filter. Only run the pipeline for events matching type or name filters. Supports exact strings, RegExp, and * wildcard prefix matching.
  • options.phase. "before" (default) or "after" — when to run relative to existing flat middleware.
  • Async-native. Each stage can be async. The pipeline awaits each stage before continuing.
  • Error-isolated. Pipeline errors are caught and logged. They never break state mutations.
  • Duplicate guard. Registering a pipeline with the same name throws DuplicateRegistrationError.

0.5.0

Comprehensive Test Suite

Expanded the test suite from 115 test cases across 13 files to 534 test cases across 16 files — full coverage of every feature, utility, error class, plugin, hook, and edge case in the library.

New Test Files

  • tests/utils/utils.test.ts — 100 tests covering all 12 utility functions: clone, deepEqual, shallowEqual, getPath, setPath, mergeDeep, splitPath, debounce, batch, noop, stableStringify, and backoff. Includes extreme edge cases: circular references, sparse arrays, Date/RegExp/Map/Set/ArrayBuffer/SharedArrayBuffer cloning, getter/setter traps, NaN/-0/Infinity equality, prototype pollution guards, and debounced function cancellation.
  • tests/computed/computed.test.ts — 15 tests for dependencyIntersects and mesh.computed(). Covers single/multiple dependency paths, nested path matching, wildcard deps, dot-segment collision prevention, value caching, invalidation on dependency change, and circular reference handling.
  • tests/react/hooks-extended.test.ts — 35 tests covering the mesh API surface behind all React hooks: form registration, validation, replace mode, transaction lifecycle (idle → pending → success/error), optimistic updates with rollback, retry with backoff, action execution and error wrapping, computed values with dependency tracking, batch grouping with nested batches, resource fetch/status/invalidation, mutation lifecycle, redirect errors, and createMemoryHistory edge cases (forward truncation, back-at-start no-op, listener unsubscribe).

Expanded Test Files

  • tests/errors/errors.test.ts — 1 test → 131 tests. Covers all 16 error classes (StateMeshError, ProviderError, SelectorError, ComputedError, ActionError, DuplicateRegistrationError, TransactionError, TransactionRollbackError, ResourceError, MutationError, ApiClientError, GuardError, PersistenceError, UrlStateError, FormError, SyncError) and all 5 helper functions (getErrorMessage, getErrorMetadata, getErrorStatus, isApiClientError, isStateMeshError). Tests class hierarchy, cause chaining, metadata propagation, code field, timestamp, and non-Error fallback handling.
  • tests/sync/sync.test.ts — 1 test → 25 tests. Covers tabSyncPlugin with BroadcastChannel and localStorage fallback, createBroadcastChannelAdapter with custom channels, createLocalStorageAdapter with same-tab detection, createTabSyncMessage structure, self-message filtering, TTL expiration, custom serialize/deserialize, and batch message handling.
  • tests/persist/persist.test.ts — 3 tests → 35 tests. Covers createLocalStorageAdapter, createSessionStorageAdapter, createMemoryStorageAdapter, IndexedDBAdapter, persistPlugin integration, version migration, TTL expiration, key whitelisting, corrupt data handling, empty/null values, and cross-adapter consistency.
  • tests/url/url.test.ts — 5 tests → 38 tests. Covers toQueryParams with all primitive types, nested objects, arrays, null/undefined filtering, empty string preservation, Date objects, BigInt, circular references, fromQueryParams round-trip, boolean parsing, and createBrowserHistory/createMemoryHistory edge cases.
  • tests/devtools/devtools.test.tsx — 3 tests → 34 tests. Covers createMockSnapshot (all fields populated), formatEvent (all event types), maskEvent (nested paths, arrays, dot-paths), createDevtoolsLogger (enable/disable, timestamp, log levels), and createDevtoolsBridge (subscribe/unsubscribe, update batching, destroy() cleanup).
  • tests/testing/testing.test.ts — 2 tests → 25 tests. Covers createTestMesh (custom state, initial state, override defaults), createMockMesh (mocked actions, mock return values), mockActions (multiple mocks, error mocks), assertStatePath (nested paths, not-found), assertResourceStatus (all statuses), assertTransactionStatus, waitForMutations (success, timeout, error), and waitForTransactionStatus (success, timeout).
  • tests/router/router.test.ts — 28 tests → 63 tests. Covers createBrowserHistory (basename, popstate, same-URL skip, replaceState, forward truncation), createMemoryHistory (entries, initial index, go beyond bounds, replace, createHref, state), updateDocumentMeta (title, og:*, canonical, description removal, null values, cleanup), and defineRoutes (tree normalization, trailing slash, nested children).

Pre-existing Issues

  • React component rendering tests (hooks.test.tsx, realworld-support-desk.test.tsx) fail due to a pre-existing React 19 + @testing-library/react act() incompatibility. This is an upstream dependency issue, not a StateMesh bug.
  • createRouter() integration tests hang in jsdom due to browser history adapter initialization. Router logic is tested through createMemoryHistory and mesh API tests instead.

0.4.0

Router

StateMesh now ships a built-in router where routing IS state management. Every route transition is a transaction. Every loader is a resource. Every guard is middleware. No other React router reuses the state management primitives this way.

  • defineRoutes(routes). Define a nested route tree with path patterns, lazy components, loaders, guards, and metadata.
  • mesh.router(routes, options). Create a router instance bound to the mesh. The router manages navigation, data loading, and rendering.
  • <RouterProvider>. Context provider that wires the router to the React tree.
  • <Outlet>. Renders the matched route's component. Used for nested layouts.
  • <Link>. Navigation component with preload-on-hover/focus support, active class detection, and search param encoding.
  • useNavigate(). Stable navigation function for programmatic routing.
  • useMatch(). Read the current route match including params, search, loader data, and error state.
  • useParams(). Read the current route's path params.
  • useSearch(). Read and update the current route's search params.
  • redirect(target, options?). Throw a redirect from guards or loaders. The router handles the redirect automatically.

Route Middleware Pipeline

  • router.use(middleware). Express-style middleware that runs on every navigation. Middleware can continue (next()), redirect (throw redirect()), or block (return false). Runs in registration order before any loader.

Route Guards

  • router.beforeEach(guard). Register a guard that runs before every navigation. Guards are observational — they can redirect but cannot block silently.
  • rollback: true on a route definition. If the loader fails, the entire navigation rolls back — the URL reverts and the user stays on the previous route. No broken page is ever shown.

Route Memory Pool (Keep-Alive)

  • keepAlive: true on a route definition. The component stays mounted when navigating away. The router maintains a configurable pool of alive routes with LRU eviction.
  • keepAlive router option. Configure maxRoutes, evictionStrategy ("lru" or "fifo"), and maxAge.

Predictive Prefetch

  • predictivePrefetch router option. The router learns which routes users visit next from the current route, builds a probability graph, and speculatively prefetches the top N most likely next routes. After visiting /products/products/:id three times, the fourth visit prefetches the detail route automatically.

Automatic Route Analytics

  • analytics router option. Zero-config page view tracking, time on page, scroll depth, bounce rate, and navigation funnels. All data stored as mesh state, visible in DevTools.

Route Dependencies

  • dependencies on a route definition. Declare data dependencies that prefetch in parallel with the main loader. If data is already cached, the dependency resolves instantly.

Error Recovery

  • errorRecovery on a route definition. Configure retry, retryDelay (works with the backoff() helper), fallbackComponent, and onError. The router retries failed loaders automatically, showing a fallback component during retries.

Route-Level Offline Support

  • offline router option. Serve routes from the mesh resource cache when offline. Configure strategy, cacheRoutes, and fallbackRoute.

Shared Element Transitions

  • <SharedElement id>. Place matching components on source and target routes. The router animates between them using FLIP (First, Last, Invert, Play).

SEO + Meta Management

  • meta on a route definition. Static or dynamic metadata per route. The updateDocumentMeta() helper updates <title>, Open Graph tags, and canonical URLs automatically on navigation.

History Adapters

  • createBrowserHistory(basename?). Browser history adapter using window.history. Listens to popstate for back/forward navigation.
  • createMemoryHistory(initialPath?, entries?). Memory history adapter for testing and SSR. Supports push, replace, back, forward, and listener notifications.

0.3.0

Wildcard Event Subscription

  • mesh.on(filter, handler). Subscribe to events matching a pattern. The filter accepts type and name fields that match exactly or with a RegExp. Supports * wildcards for prefix matching (e.g. "action.*" matches all action events).

Transaction Improvements

  • Exponential backoff helper. New backoff() utility exported from statemesh-core. Creates a delay function with configurable base, max, factor, and jitter options. Use with retry.delay for exponential backoff strategies.
  • retry.totalTimeout. Wall-clock timeout across all retry attempts. If the total elapsed time exceeds this value, the transaction aborts even if retries remain.
  • retry.onRetry. Callback invoked before each retry delay. Receives the attempt number, the last error, and the transaction context. Useful for logging, analytics, or user feedback.

Resource Improvements

  • enabled option. Conditional fetching at the resource definition level. Accepts a boolean or (params, state) => boolean. When false, the resource returns cached data without fetching.
  • select option. Transform raw fetched data before caching. The transformed value is returned to consumers while the original data is cached internally.
  • onSuccess callback. Called after a successful fetch. Receives the data and params.
  • onError callback. Called after a failed fetch. Receives the error and params.
  • mesh.cancelResource(name, params?). Cancel an in-flight fetch by name and params. Aborts the controller and resets the fetching state.
  • ResourceHandle.cancel(params?). Cancel an in-flight fetch directly from the resource handle.
  • mesh.isFetching(filter?). Returns the count of resources currently fetching. Accepts optional names and tags filters.

Form Improvements

  • validateDebounce option. Debounce delay in milliseconds for field-level validation when validateOnChange is true. Defaults to 0 (immediate).
  • isValid derived flag. form.isValid is true when there are no errors and no validation is in progress. Available on both FormState and FormApi.

DevTools

  • Dark theme. StateMeshDevtools accepts a theme prop ("light" or "dark"). A toggle button in the header switches themes at runtime. Panel backgrounds, borders, text, and tab styles adapt to the selected theme.

Testing Utilities

  • mesh.mockResource(name, options). Set cached resource data directly for a test. Accepts data, params, and status options.
  • mesh.mockMutation(name, options). Set mutation status directly for a test. Accepts result, error, and status options.
  • waitForTransactionStatus(mesh, name, status, options?). Async helper that polls until a transaction reaches the expected status or times out.
  • waitForMutationStatus(mesh, name, status, options?). Async helper that polls until a mutation reaches the expected status or times out.

React Hooks

  • useMeshBatch. Returns a stable batch callback that groups multiple state updates into a single notification flush. Available from statemesh-core.

  • Performance: skip clone on no-op actions. Actions that produce the same state as the current snapshot skip the clone-and-commit cycle entirely. shallowEqual(state, draft) guards every action run.

  • Performance: path tokenization cache. Repeated path.split('.') calls (from getPath, setPath, computed deps, subscriptions) are cached per path string via a shared splitPath module.

  • Performance: stable status references. getResourceStatus, getTransactionStatus, and getMutationStatus return the same object reference when their underlying state has not changed, reducing unnecessary React re-renders.

  • Performance: profiler hot-path filter. Profiled event type checks use a module-scoped Set for O(1) lookups. Unprofiled events like state.changed are skipped without a function call.

  • Performance: DevTools snapshot throttling. DevTools notifications are throttled to once per animation frame (~16ms). Rapid state changes are batched into a single DevTools render.

  • Performance: LRU resource cache eviction. Resources accept maxCacheEntries to limit memory usage. When the cache exceeds the limit, the oldest unused entry is evicted first.

  • Feature: createSelector memoized selector. Exported from statemesh-core. Creates a stable memoized selector with explicit dependency tracking — only recomputes when any dependency changes.

  • Feature: batch operations (mesh.batch). Every mesh instance exposes batch(fn) to group multiple state mutations into a single subscription notification. Useful for coordinating state changes across different subsystems.

  • Resource maxCacheEntries option. Bounds the per-resource cache size. Configurable per-resource without modifying the mesh's shared defaults.

  • Initial production-focused StateMesh package scaffold.

  • Adds core mesh store, React bindings, actions, computed values, transactions, persistence, URL state, forms, tab sync, errors, logger bridge, testing utilities, examples, and documentation.

  • Adds resource cache, request deduplication, invalidation tags, mutations, optimistic rollback, pagination helpers, and a built-in API client with auth refresh queueing.

  • Adds fully controllable API client timeouts, retry/backoff, retry predicates, jitter, per-request overrides, and retry/timeout events.

  • Adds production form upgrades: async field validation, server errors, autosave, mutation submit, dirty fields, reset-to-server data, schema adapters, and field arrays.

  • Adds resource prefetch aliases, focus/reconnect refetch, polling, resource cache dehydration/hydration, resource cache persistence, offline mutation queueing, entity cache helpers, and an in-app DevTools timeline component.

  • Adds tested real-world support desk examples for TypeScript and plain JavaScript React.

  • Adds a Vite development full-reload guard in StateMeshProvider so broken saves do not leave the last successful UI visible.

  • Treats duplicate named registrations as replacements during Vite browser HMR while keeping production duplicate guards strict.

  • Adds custom URL query parameter names for mesh.urlState through paramNames maps and resolver functions.

  • Adds resource UI helpers for keepPreviousData, placeholderData, and per-component select transforms in useMeshResource.

  • Adds guarded operations with mesh.guard, GuardError, full mesh dehydrate/hydrate, dynamic URL param capture, persisted offline mutation queues, and error helper utilities.

  • Adds API upload support with api.upload, upload progress callbacks, and relative API base URL joining such as baseUrl: "/api".

  • Adds checkbox, radio, select, and file helpers to production forms.

  • Adds DevTools timeline search, category filters, failed-only view, and export/copy support.

  • Adds tested TypeScript and plain JavaScript production-upgrades examples for the new daily-app APIs.

  • Adds Suspense resource reads, reset-aware mesh error boundaries, StateMesh Doctor diagnostics, bounded performance profiling, DevTools profiler/Doctor tabs, and tested production-observability examples.

Released under the MIT License.