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

rx-extensions

v1.3.5

Published

Library for useful RxJS extensions and operators

Readme

Rx Extensions

A set of useful extensions and operators for RxJS

State Store

Specialized subject for storing and modifying application state. Inspired by the NgRx Store.

Usage

// instantiate with initial state
const stateStore = new StateStore<MyState>(INITIAL_STATE);

// call modify to update the state
// modify takes 2 arguments, some data to feed into the modifier, and the modifier itself which is a function that updates the state

const modifier = (state: MyState, data: MyModifierData): MyState => {
    // use non mutative methods to update state
    return {...state, ...{data}};
}

stateStore.modify(myData, modifier);

// modifiers can also return observables of data
const modifier$ = (state: MyState, data$: Observable<MyModifierData>): Observable<MyState> => {
    return data$.pipe(
        map(data => ({...state, ...{data}}))
    );
}

stateStore.modify(myData$, modifier$);

// get data with select, feed as many key arguments as needed for nested keys
stateStore.select('data').subscribe(data => console.log('got data:' data));

// calling next will reset the data modifier to whatever is fed as an argument
// semantic reset method is available as a wrapper
stateStore.reset(myNewState)

Data Store

Specialized extension of StateStore for data that meets the interface {[key: string]: T}

Usage

// initial state is optional, defaults to {}
const dataStore = new DataStore<MyData>()

// set data key with set, can also take observable of the data (this is true for all set and update operations)
dataStore.set('dataKey', myData)

// get data key with get
dataStore.get('dataKey').subscribe(data => console.log('got data:' data));

// update data key with update, takes modifier of the data at the key and data to update (can return observable)
// use set to totally replace, use update when you need the data in the store to make the update
const myUpdateModifier = (state: MyData, data: MyUpdateData) =>{
    return {...state, ...{data}};
}
dataStore.update('dataKey', myUpdateData, myUpdateModifier);

// delete keys with delete
dataStore.delete('dataKey');

// the above all also have `Many` variations:
dataStore.setMany({dataKey1: myData1, dataKey2: myData2})

dataStore.getMany(['dataKey1', 'dataKey2']).subscribe(([myData1, myData2]) => console.log(myData1, myData2));

// updateMany takes an argument of an object with keys to update and the data to use in the update, and the modifier to run on each key
const myUpdateManyModifier = (state: MyData, data: MyUpdateData) =>{
    return {...state, ...data};
}
dataStore.updateMany({dataKey1: myUpdateData1, dataKey2: myUpdateData2}, myUpdateManyModifier);

dataStore.deleteMany(['dataKey1', 'dataKey2']);

// reset data, takes optional argument of data state, will be {} by default
dataStore.reset()

Resource Store

Specialized extension of DataStore that deals with a remote resource

Usage

// two ways to use

// 1. via construction that takes a config with (optional) inistial state and a function to fetch the remote resource

function getResource(url: string): Observable<MyType> {
    return http.get(url);
}

const resourceStore = new ResourceStore<MyType, string>({getResource});

// 2. or you may extend the AbstractResourceStore and provide a getResource function

class MyResourceStore extends AbstractResourceStore<MyType, string> {
    getResource(url: string) {
        return http.get(url);
    }
}

// both methods may define a key builder function as well in the case of more complex input:

type MyInput = { id: string };
function keyBuilder(input: MyInput) {
    return input.id
}

const resourceStore = new ResourceStore<MyType, string>({getResource, keyBuilder});

class MyResourceStore extends AbstractResourceStore<MyType, string> {
    getResource(input: MyInput) {
        return http.get('https://my.api.com/' + input.id);
    }

     keyBuilder(input: MyInput) {
        return input.id
    }
}

// the resource store provides a cacheGet method that will check the cache, if it's not there, it will call the getResource method and set it

resourceStore.cacheGet(url).subsribe(v => console.log(v, "this resource was fetched from cache or remote!"))

// it also provides a cacheSet method that gets the remote resource and populates the cache with the response

resourceStore.cacheSet(url)

Array Store

Specialized extension of StateStore for data that meets the interface Array<T>

Work In Progress... Documentation coming

Pull Subject

Implements observer pattern to pull responses from observers and gather responses

Usage

// using this interface
interface MyType {
    key: string;
    key2: number;
}

// declare like a normal subject, optionally declare with a collector reducer
// default collector reducer merges partials like {...collected, ...collector}
const pullSubject = new PullSubject<MyType>();

// use pull method to register a collector, which needs to return a partial type
pullSubject.pull(() => {
    return {key: 'value'};
});

// register async collectors with pullASync (these MUST complete!)
pullSubject.pullAsync(() => {
    return of({key2: 10});
});

// subscribe to the pull subject to receive the merged result of all collectors
pullSubject.subscribe(collected => {
    console.log('got the result', collected);
});

// trigger the collection with pull subject next (you can pass initial or default values for the reducer here, defaults to {})
pullSubject.next();

// deregister a collector with the pull return value
const pullSub = pullSubject.pull(() => {
    return {key: 'value'};
});

pullSub.unsubscribe();

Utilities and Operators

concatJoin

Like forkJoin but executes streams sequentially

batchJoin

Like forkJoin but executes streams sequentially in batches of a specified size, default 5

pluckDistinct

combines pluck and distinctUntilChanged

pluckManyLatest

plucks several keys and emits all when any of them change

pluckManyMerge

plucks several keys and the key that changed when it changes, along with the key that changed