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

rxfy

v3.1.1

Published

Reactive data-flow layer for your UI: typed models, states, and normalized stores as RxJS Observables

Readme

rxfy (/ɑɹ ɪks faɪ/) is a reactive data-flow layer for your React app: declare typed models, states, and normalized stores, and scale from a client-only store to a fully live app with server-side rendering and real-time updates via websockets. It's built for consistency and granular RxJS-based reactivity at no extra cost.

The problem

Render one piece of data in two components and keep them in agreement. Now render it in six — a list row, a detail panel, a sidebar counter, a search result — with two people editing it at once, and the job grows into a large share of what your app does. Much of the code you write around fetching exists only to keep those copies in sync.

Tools like TanStack Query handle this by invalidation: after a mutation you invalidate the affected query keys and refetch, and you have to get every key right, every time. Both the complexity and the risk of a missed invalidation grow non-linearly with the number of places the entity appears.

Problem deconstruction

The root cause is one thing: your app holds many copies of the same entity. The list has one, the detail view fetched another, the cache may hold a third, and every write has to find and update all of them. Add a second client and the copies span the network too.

Your database does not have this problem. Each row is one piece of data, kept in one place — a single source of truth. The question is how to carry that property up to the client, in a framework that:

  • keeps maintenance cost flat as the number of views grows
  • lets you declare each data model once and share it between server and client
  • routes every write to one place, and from there to every view that renders the entity, with no manual invalidation
  • re-renders only the components whose data actually changed
  • serializes state on the server and restores it on the client, so SSR reuses the same models
  • takes real-time updates over a websocket through that same single path
  • composes and transforms the data as streams, so each view can derive exactly the shape it needs

Solution overview

rxfy stores each entity once, in a normalized store keyed by its id, and every view references that slot instead of holding a copy. One write reaches every subscriber, and the same declaration carries the client, the server, and the wire.

Client-side

Declare an entity model and store each entity in its own slot of the model store, addressed by its id. Compose a state from those models — each page has its own — and derive it as an observable, using RxJS operators to shape it for any view. Live updates flow into the same store: a patch updates the entity's slot and every subscriber re-renders, while a create or delete marks every state that lists it stale, ready to sync when you choose.

Server-side

Bind each model to its database table with a resource, so the server reads and writes the same model the client renders. On a request it fills the page's state and serializes it into the HTML; the client restores that snapshot on hydration and skips the fetch. Writes go through the resource — an update publishes a patch on the entity's topic — and the server signs a grant per served state, so each client subscribes to exactly the entities it was handed and no others.

sequenceDiagram
    participant A as Alice
    participant S as Server
    participant DB as Database
    participant B as Bob

    A->>A: update entity in the store
    A->>S: send mutation
    S->>DB: persist change
    S-->>A: publish updated entity
    S-->>B: publish updated entity
    Note over A: store recalculates every place<br/>this entity is used
    Note over B: store recalculates every place<br/>this entity is used

Core principles

rxfy is built on five principles:

  • Everything is a data stream. rxfy builds on RxJS, not a reactivity system of its own: an Atom is an Observable with synchronous get() and set(), and entity cells, state data$, and lenses are all streams. The operator library composes over your app state, a derived value recomputes itself when its source changes, and a websocket push is just another stream flowing into the same cells.
  • Data normalization. Each entity lives once, in a single slot keyed by its id, and every view references that slot instead of holding its own copy — no second copy to drift, and a change has exactly one place to happen.
  • Late unwrapping: data travels wrapped, only the leaf component that renders a value unwraps it, and a write never unwraps anything — see Late Unwrapping.
  • No model copies. Each model shape and each state is declared once and used on both sides; the server fills and serializes a state, the client restores it and skips the fetch — SSR with no DTO layer, no client-only type, no separate path.
  • Static validation. Every model, state, param, and mutation is typed, so a wrong shape is a compile error; the store is keyed by a branded StoreKey, and because each model is a Zod schema, one declaration validates the data at runtime too.

Alternative approaches

None of these principles are new on their own — normalized stores, observable state, SSR, and real-time sync all exist elsewhere. rxfy holds all of them behind one declaration. TanStack Query keys its cache by response and leaves invalidation to you; Redux Toolkit normalizes but notifies through selectors rather than streams; sync engines stream normalized changes too, but ask you to move your schema and hosting onto their platform, where rxfy layers onto the database and API routes you already run. See the comparison for where each one fits.

📚 Documentation: rxfy.vanya2h.me

Agent skills

# getting rxfy into a project (template or add-to-existing-app)
npx skills add vanya2h/rxfy --skill rxfy-setup

# working in a project that already has rxfy
npx skills add vanya2h/rxfy --skill rxfy

Two agent skills for AI coding assistants: rxfy-setup (scaffold a create-rxfy-app template or add rxfy to an existing app at a chosen depth) and rxfy (a task-indexed reference library for the whole framework — store, React, SSR, real-time sync). Setup records the chosen variant so usage never re-detects the project type. See Agent Skills.

Install

npm install rxfy
# peer deps: rxjs zod lodash

Links

Guides

License

MIT