Skip to content

jorgeguberte/multiverse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multiverse State (multiverse-js)

An application state management library to solve the "Single-Timeline State Paradox" by introducing Git-style branching semantics directly into synchronous local memory space.

The Problem

In modern React, Vue, or Vanilla frontend apps, we constantly struggle with Optimistic UI Updates and Modal Drafts. Consider opening a modal to edit a complex data object. You have two choices:

  1. Deep clone the object into a temporary draftData state, and write custom logic to apply changes back to the main store when the user hits "Save".
  2. Mutate the main store immediately, and write complex logic to reverse mutations if the user hits "Cancel" or if an API call fails.

This is because we live in a Single-Timeline paradigm.

The Paradigm Shift

What if your local application state worked like Git branches? With multiverse-js, you fork your state. You mutate your sandbox timeline exactly like you would mutate the main timeline, with O(K) performance thanks to under-the-hood Proxy lazy-evaluation. If the API call fails or the user cancels? You simply discard() the branch. The timeline collapses painlessly. If the API call succeeds? You merge() the branch. The universe patches effortlessly fold your changes into the main timeline, gracefully handling conflicts (even if the main timeline advanced or deleted objects while you were branched).


Usage for Mammalian Brains

1. Initialize your Universe

import { Multiverse } from 'multiverse-js';

const state = new Multiverse({
  metrics: { connections: 0 },
  users: [{ id: 1, name: 'Alice', role: 'Admin' }],
  lastSync: new Date() // Complex instances are preserved natively!
});

2. Forking a Draft (Optimistic Updates)

Open your modal component and just render the isolated branch!

// Create a temporary timeline
state.fork('optimistic-save');

state.mutate(draft => {
  // This draft mutation is fully isolated!
  // Powered by a lazy Proxy engine, it only clones what you actually touch (Copy-on-Write).
  const alice = draft.users.find(u => u.id === 1);
  if (alice) alice.name = 'Alice Wonderland';
}, 'optimistic-save');

3. Native React Integration

multiverse-js ships with a useMultiverse hook powered by useSyncExternalStore for tear-free concurrent rendering.

import { useMultiverse } from 'multiverse-js/react';
import { state } from './store'; 

function OptimisticProfile() {
  // Subscribe specifically to the 'optimistic-save' branch.
  // The component only re-renders when the `users` array changes in this branch.
  const users = useMultiverse(state, (s) => s.users, 'optimistic-save');

  return <div>{users[0].name}</div>; // Renders "Alice Wonderland"
}

4. Merging or Discarding

React to async API boundaries without writing complex rollback reducers.

try {
  await api.saveUser(1, { name: 'Alice Wonderland' });
  
  // It worked! Effortlessly push the patched timeline to reality.
  state.merge('optimistic-save');
  state.squash(); // Optional: Garbage collect the patch history to free memory
} catch (error) {
  // It failed! Throw the sandbox away. No rollbacks required.
  state.discard('optimistic-save');
}

Quick Demos

These demos run locally with tsc + node and do not require React or API keys.

npm run demo:optimistic
npm run demo:merge
npm run demo:agents

If you want the full pass:

npm run demo:all

What each demo shows:

  • demo:optimistic: modal draft workflow with isolated edits, cancel, and save.
  • demo:merge: primitive arrays, entity arrays, and last-merge-wins conflict semantics.
  • demo:agents: async branch orchestration without depending on an external LLM.

React Demo

There is also a small browser playground in examples/react-demo that uses the shipped useMultiverse hook directly from src/.

npm run demo:react:dev
npm run demo:react:build

It includes:

  • A modal-style draft editor with fork, merge, and discard.
  • A merge playground for relative array patching and conflict resolution.
  • An async orchestration scene that simulates parallel agent branches.

Advanced Edge-Case Resolution (CRDT-Lite)

Due to our strict Identity Contract and custom Patch Engine, multiverse-js intelligently applies only the semantic delta.

The Orphan Problem & Identity Tracking

To guarantee structural safety, objects inside arrays must have an id property. If Branch A is modifying a deeply nested property (e.g., user.profile.age), but Main deleted the user entirely before Branch A could merge, multiverse-js gracefully ignores the orphan patch. It tracks the entity by its id, recognizes it is natively gone, and collapses the mutation. No silent array-index overwriting.

Strict Array Homogeneity

To prevent silent data loss, multiverse-js enforces strict array homogeneity. An array must consist of 100% primitives OR 100% objects with id properties. Mixing primitives and objects in the same array will throw a runtime error during mutation, keeping your data structures predictable.

"Last-Branch-Wins" Dimensional Overwrites

If two branches both modify config.theme simultaneously, the branch that merges last functionally overwrites the property, natively mirroring expectations of asynchronous API resolutions.

True Longest Common Subsequence (LCS) for Primitives

If your array contains primitive values (e.g., ['A', 'B', 'A']), the engine uses a rigorous dynamic programming LCS diffing algorithm. If a branch appends 'C' and the main timeline unshifts 'X', merging results perfectly in ['X', 'A', 'B', 'A', 'C'] without destroying sequence data or getting confused by duplicates.

About

Git-like branching for synchronous local UI state. Fork, mutate, and merge application state to painlessly handle optimistic updates and complex drafts. Features an O(K) copy-on-write Proxy engine, CRDT-lite array conflict resolution, and a native React hook.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors