
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
horizonstate
Advanced tools
A transactional state management library for JS with temporal ordering and automatic rollback

horizonstate is a transactional state management library for JS with temporal ordering and automatic rollback
🚧👷 Warning Proceed at your own risk. This is an in-development library, which is another way of saying that it will change quite a lot.
Horizonstate is a transactional state management library for JS that is designed to provide simple primitives for managing state without concern for response ordering or manual rollback of optimistic updates. It does this by saving a snapshot of the state before each transaction and recording mutations to the state via updator functions. These mutations can be replayed or dropped when prior transactions complete, ensuring that each update to the state is applied in the correct order. Transactions run concurrently and non-blocking by default, but temporal ordering results in eventual consistency and automatic conflict resolution.
Define a model:
import { Model } from "horizonstate";
let model = new Model(
{
foo: "bar",
pending: false,
},
// optional config:
{
timeout: 10000 // the minimum amount of time a transaction has to complete. Default: 10000ms
}
);
Define transactions:
let setFoo = model.addTransaction(async (args: string, { optimisticUpdate, update, applyOptimisticUpdates }) => {
// set state optimistically, which will be rolled back once this transaction completes
optimisticUpdate(draft => {
draft.foo = args;
draft.pending = true;
});
let result = await someApiCall(args);
// apply updates to the model
update(draft => draft.foo = result.foo);
// Or call applyOptimisticUpdates() if you're sure the optimistic updates will match the server state
});
Run the transaction:
setFoo.run("baz");
Subscribe to updates:
model.subscribe((state) => {
console.log(state.foo);
});
// with a selector
model.select(state => state.foo, console.log);
Transactions can await prior pending transactions:
model.addTransaction(async (args: any, { optimisticUpdate, update, pendingTransactions }) => {
await pendingTransactions;
// run transaction...
});
Transactions can read state from the model. This state is the result of previous transactions (pending and resolved), but does not reflect state updates from later transactions (temporal ordering is preserved). Keep in mind if prior transactions complete or update the model after state() is called, this state could be stale. It's generally advisable to await previous transactions if you need to send state from the model to the server.
model.addTransaction(async (args: any, { optimisticUpdate, update, state }) => {
let s = state();
// continue with transaction...
});
You can also drop optimistic updates during your transaction, which will automatically roll them back:
model.addTransaction(async (args: any, { optimisticUpdate, update, dropOptimisticUpdates }) => {
optimisticUpdate(draft => {
draft.foo = args;
draft.pending = true;
});
let result = await someApiCall(args);
if(result.someCond) {
// drop all prior optimistic updates
dropOptimisticUpdates();
}
optimisticUpdate(draft => draft.error = true);
let newResult = await someOtherApiCall(args);
update(draft => draft.foo = newResult.foo);
});
Since optimistic updates are automatically rolled back, handling errors is simply a matter of applying a different update if applicable.
model.addTransaction(async (args: any, { optimisticUpdate, update }) => {
optimisticUpdate(draft => draft.foo = args)
let result = await someApiCall(args);
if(result.success) {
update(draft => draft.foo = result.foo);
} else {
update(draft => draft.error = true);
}
});
Horizonstate exports a React hook for managing models inside of components.
import { model } from "./model.ts"
import { useModel } from 'horizonstate/react';
let Component = () => {
let state = useModel(model);
return <div>{state.foo}</div>;
};
useModel takes an additional argument for the model to use as a state selector to reduce rerenders.
let Component = () => {
let bar_baz = useModel(model, (state) => state.bar.baz);
return <div>{bar_baz}</div>;
};
Made with 💛
Published under MIT License.
FAQs
A transactional state management library for JS with temporal ordering and automatic rollback
We found that horizonstate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.