npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

simple-state-model

v0.1.1

Published

Simple State Model — transport- and storage-agnostic core: config/state controllers, the RFC6902 mutation queue, and the provider interface

Readme

simple-state-model

Transport- and storage-agnostic core of the Simple State Model. It has no knowledge of Postgres, GraphQL, or the network — everything external plugs in through a provider.

Concepts

| Concept | What it is | | --- | --- | | ConfigController | Holds a value. Emits value and status. Set with setValue(). | | StateController | A ConfigController whose value is changed with RFC6902 patches. Emits patch alongside value. | | StateControllerMutationQueue | Tracks provisional vs. accepted values so a client can apply optimistic patches and roll them back. | | ConfigModel / StateModel | Registry of named providers. load(providerID, options) returns a controller. | | BaseConfigProvider / BaseStateProvider | The interface a storage backend implements: load(), has(), delete(). |

Install

npm install simple-state-model

Usage

import { StateModel } from "simple-state-model";

const stateModel = new StateModel({ logger: console });

// in-memory provider is registered as "inmemory" and is the default
const stateController = await stateModel.load(undefined, { id: "element-1" });

stateController.on("patch", (patch) => console.log("changed", patch));

stateController.patch([
    { op: "add", path: "/title", value: "Hello" }
]);

console.log(stateController.value); // { title: "Hello" }

Controller modes

StateController runs in one of two modes:

  • AUTHORITATIVE (default) — patches are accepted the moment they are queued. Use this on a server, or anywhere this process owns the truth.
  • CLIENT — patches stay provisional until something accepts them. Use this in a browser so a local edit shows immediately but can be rolled back if the server rejects it.
import { StateController } from "simple-state-model";

const stateController = new StateController({ mode: StateController.MODES.CLIENT });
const mutation = stateController.patch([{ op: "add", path: "/title", value: "Hello" }]);

mutation.accept(); // or mutation.reject({ error })

Writing a provider

A provider maps a state ID to a controller instance and decides where the value lives.

import { BaseStateProvider } from "simple-state-model";

class MyStateProvider extends BaseStateProvider {
    async load(options) {
        const stateID = options.id;
        // return a cached controller, or build one from your backing store
        return new this.controllerClass({ id: stateID, value: await this.read(stateID) });
    }

    async has(options) { /* ... */ }
    async delete(options) { /* ... */ }
}

See simple-state-model-postgres for a full implementation.

Related packages