
Security News
Node.js Drops Bug Bounty Rewards After Funding Dries Up
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.
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
The npm package horizonstate receives a total of 11 weekly downloads. As such, horizonstate popularity was classified as not popular.
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.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.