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 🙏

© 2025 – Pkg Stats / Ryan Hefner

resourcex

v0.1.2

Published

ResourceX - Utilities to wrap global variables into rxjs observables with **reduced** learning curve

Readme

resourcex

resourcex - Utilities to wrap global variables into rxjs observables with reduced learning curve

This project provides a few handy utilities to make global variables slightly easier to work with, comparing to traditional Flux Architecture.

By using the utilities inside, plus some observable enhancement tools in your favorite MVVM framework, global store can be organized into a set of highly structured resources. Each resource exposes its value and corresponding mutating actions. In this way, frontend applications can integrate with backend RESTful API with less boilerplate.

Since this is a very light encapsulation on top of rxjs, anyone who doesn't mind delving into the design patterns of functional reactive programming can easily make something more elaborate from these basic tools.

Example

Both Vue and React examples can be found inside here.

// api.js
export async function getProfile() {
  return { uid: 10086, name: 'ResouceX' };
}

export async function setName(name) {
  return { success: true };
}

// resources.js
import { Resource } from 'resourcex';
import { getProfile, setName } from './api';

export const Profile = Resource(
  { uid: 0, name: '', version: 0 },
  {
    async get() {
      const profile = await getProfile();
      return { ...profile, version: 1 };
    },
    increaseVersion({ version }) {
      return { version: version + 1 };
    },
    async setName(_, name) {
      const { success } = await setName(name);
      if (success) return { name };
      else throw Error('update-failed');
    },
  },
);

Vue

For integrating with Vue, it's recommended to install vue-rx to ensure observable unregistrations are done correctly on unmount.

import { Profile } from '../resources';

new Vue({
  el: '#app',
  template: `
    <div>
      <h1>Hello, {{ profile$.name }}!</h1>
      <h2>{{ profile$.uid }} called {{ profile$.version }} times</h2>
      <button @click="setName('New Name')">Set New Name</button>
      <button @click="incProfileVersion">Bump Version</button>
    </div>
  `,

  subscriptions() {
    return { profile$: Profile };
  },

  methods: {
    setName(name) {
      Profile.setName(name); // <- discard original return
    },
    async incProfileVersion() {
      const { version } = await Profile.increaseVersion();
      console.log(version); // <- captured original return
    },
  },

  created() {
    Profile.get();
  },
});

React

For integrating with React, consider using resource-react-hook.

import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';

import useResource from 'resource-react-hook';
import { Profile } from '../resources';

const App = () => {
  const profile$ = useResource(Profile);

  // on creation do a round of fetch
  useEffect(() => {
    Profile.get();
  }, []);

  return (
    <div>
      <h1>Hello, {profile$.name}!</h1>
      <h2>
        {profile$.uid} called {profile$.version} times
      </h2>
      <button onClick={() => Profile.setName('New Name')}>Set New Name</button>
      <button onClick={Profile.increaseVersion}>Bump Version</button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('app'));

API

Resources

  • Resource(initial, actions?, middleware?, initHook?)

    Creates a resource (as an rxjs BehaviorSubject) with (optionally) actions defining how to change its value. Each action is a function that

    • Takes in as first parameter state, which is the current value of the subject
    • Returns a value which would be Object.assigned into the original state

    Therefore, the value state could be destructurally assigned. It could be left as _ or skipped with a comma if there's no dependency on previous value. Return value of Resource.action(..args) respect the the original action function.

    document and examples for middleware and initHook are under construction hohoho

  • NaiveResource(initial)

    • Almost the same as a Resource except that it only exposes a set action

    create a resource with an initial value, expose a set call to update its value

  • LocalStorageResource(localStorageKey, initial, actions?)

    • Almost the same as a Resource, just that the value is persisted into local storage with key specified

Operators

resourcex also exposes a few rxjs operators for easier use, esp in transforming DOM events:

  • catchMergeMap / catchFlatMap
  • catchConcatMap
  • catchSwitchMap
  • catchExhaustMap

The are analagous to the counterparts mergeMap / flatMap, concatMap, switchMap and exhaustMap in rxjs. They respect the same flattening strategy and simply wraps over them for error handling, so that on error thrown the source observables are preserved.

E.g. click$ is the click event stream on a button, the following line triggers Profile.get call with exhaustive strategy:

click$.pipe(catchExhaustMap(Profile.get)).subscribe()

  • .subscribe() is an empty subscription to kick start the streaming of events
  • Here is a good article explaining what flattening strategies rxjs provides

Change Log

  • 0.1.2: Fix NaiveResource null returning bug (also the undocumented middleware API)
  • 0.1.1: Allow empty actions as pure, unmutatable global variable
  • 0.1.0: Major rewrite to return Resource as Subject directly, and provide separate operators
  • 0.0.1 ~ 0.0.9: Pilot versions with $ as exposed Subject and no access to current state; not recommended anymore