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

@jashkasoft/rx-jstore

v0.0.8

Published

JashkaStore - simple, flexible, reactive store

Readme

JStore - simple, flexible, reactive store

Install

yarn add @jashkasoft/rx-jstore

JStore

  • initValue only condition check if operator

  • clone with last value only if jstore has config property initial value

  • formatters run with priority by index ( prev value passed to next formatter ) return last formatted value

  • middleware

  • snapshot ( current state if exists )

  • Base: formatters: - to number - to string - trim storage: - simple storage ( in memory )

Examples
  • Initial value

    import { JStore } from '@jashkasoft/rx-jstore';
    
    const store = new JStore<string>({
         initValue: 'string',
    });
    
    console.log('snapshot with value', store.snapshot());
    
    const subscription = store.subscribe((value: string) => {
        console.log('store', value); // string and after new str
    });
    
    store.dispatch('new str');
    
    // complete store & unsubscribe
    store.destroy(subscription);
  • Custom input & output formatters ( Formatters are Observable )

    import { JStore, TrimFormatter, FormatterInterface } from '@jashkasoft/rx-jstore';   
    import { of, Observable } from 'rxjs';
    
    class TrimFormatter implements FormatterInterface {
       public transform(str: string): Observable<string> {
         return of(str.trim());
       }
     }
    class StrEndOutputFormatter implements FormatterInterface {
       public transform(str: string): Observable<string> {
         return of(str + ' end of string');
       }
     }
    const store = new JStore<string>({
         inputFormatters: [
            new TrimFormatter()
         ],
         outputFormatters: [
            new StrEndOutputFormatter()
         ]
    });
    const subscription = store.subscribe((value: string) => {
        console.log('store', `'${value}'`); // 'new str end of string'
    });
    store.dispatch('      new str   ');
    store.destroy(subscription);
  • Custom storage

    import { JStore, StorageInterface, FormatterInterface } from '@jashkasoft/rx-jstore';   
    import { of, Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
       
    interface CustomObject {
       name: string;
       id: number;
     }
       
    class LocalStorage<T> implements StorageInterface<T> {
      constructor(private token: string = 'store') {
      }
       
      public get(): Observable<any> {
        return of(localStorage.getItem(this.token));
      }
       
      public set(value: any): Observable<T | null> {
        localStorage.setItem(this.token, value);
        return of(value);
      }
       
      public clear(): Observable<T | null> {
        localStorage.removeItem(this.token);
        return of(null);
      }
       
    }
       
    class StringToJSONFormatter implements FormatterInterface {
      public transform(str: string): Observable<any> {
        return of(JSON.parse(str));
      }
    }
    
    class JSONToStringFormatter implements FormatterInterface {
      public transform(json: any): Observable<string> {
        return of(json)
          .pipe(
            map(json => JSON.stringify(json))
          );
      }
    }
        
    const store = new JStore<CustomObject>({
      storage: new LocalStorage<CustomObject>(),
      inputFormatters: [
        new JSONToStringFormatter()
      ],
      outputFormatters: [
        new StringToJSONFormatter()
      ]
    });
        
    const subscription = store.subscribe((value: CustomObject) => {
      console.log('store', value);
    });
       
    store.dispatch({
      name: 'name',
      id: 2
    });
       
    store.destroy(subscription);
  • Strict storage checking

    const store = new JStore<any>({
        strictTypeCheck: true,
        initValue: '13'
    });
       
    // ok, string type
    store.dispatch('Hello, World!');
       
    // error if initValue type string
    try {
      store.dispatch(1123);
    } catch (e) {
      console.log(e);
    }
  • context run

    import { storeFactory, RunContext } from '@jashkasoft/rx-jstore';   
    
    const store = storeFactory<number>();
    const sub = store.subscribe((n: number) => {
      console.log('number', n);
    });
    
    function youContext(fn: Function) {
     fn();
    }
    
    store.changeContext((fn: RunContext) => youContext(fn));
    store.dispatch(100000000);
    store.destroy(sub);
  • selector

    import { JStore } from '@jashkasoft/rx-jstore';   
    
    interface Obj {
        name: string;
        id: number;
        extra: {
          min: number;
          max: number;
        };
    }
       
    const store = new JStore<Obj>();
     
    const subscription = store.subscribe((value: Obj) => {
      console.log('store', value);
    });
     
    store.dispatch({
      name: 'name',
      id: 2,
      extra: {
        min: 1,
        max: 10
      }
    });
    store.dispatch({
      name: 'name',
      id: 2,
      extra: {
        min: 50,
        max: 100
      }
    });
     
    // selector, maybe reuse in other stores
    function minValueSelector(value: Obj): number {
      return value.extra.min;
    }
     
    store.select<number>(minValueSelector).subscribe(value => {
      console.log('selector min value', value);
    });
     
    store.destroy(subscription);

JStoreDispatcher over JStore

import { of, Observable } from 'rxjs';

import {
  ToNumberFormatter,
  ToStringFormatter,
  JStore,
  JStoreDispatcher,
  Middleware,
  MiddlewareData
} from '@jashkasoft@rx-jstore';

const storeNumber = new JStore<number>({
  storage: new LocalStorage<number>('number'),
  inputFormatters: [
    new ToStringFormatter()
  ],
  outputFormatters: [
    new ToNumberFormatter()
  ]
});
const subscriptionNumber = storeNumber.subscribe((value: number) => {
  console.log('storeNumber', value);
});


storeNumber.dispatch(1);


// destroy subscription (subscriptionNumber) and observable call complete
// storeNumber.destroy(subscriptionNumber);
// throw error if completed
/*try {
  storeNumber.dispatch(2);
} catch (e) {
  console.log(e);
}*/
  • Actions
    const dispatcher = new JStoreDispatcher(storeNumber);
    const actionInc = JStoreDispatcher.makeAction<number>(
      'inc',
      (state: number, payload: number) => {
        return of(state + payload);
      }
    );
    const actionDec = JStoreDispatcher.makeAction<number>('dec', (state: number, payload: number) => state - payload);
       
    // listener on action by action function
    const listener = dispatcher.on(actionInc, (value: number) => {
      console.log('on action {actionInc}: ', value);
    });
       
    dispatcher.action(actionInc, 1);
       
    // destroy listener
    listener();
       
    dispatcher.action(actionInc, 1); // 3
    
    dispatcher.destroy(subscriptionNumber);
  • Lock & unlock
    // lock dispatcher, another actions disable, throw error
    console.log('lock dispatcher1');
    dispatcher.lock();
    try {
      // error
      dispatcher.action(actionInc, 1);
    } catch (e) {
      console.log(e);
    }
    // unlock, try to unlock two or more - error
    dispatcher.unlock();
       
    dispatcher.action(actionInc, 1);
  • Snapshots
    // snapshot with history & store, date, name
    const snapshot1 = dispatcher.makeSnapshot('three');
       
    dispatcher.action(actionDec, 1);
       
    console.log('restore....');
    // restore snapshot with history, value
    dispatcher.restoreSnapshot(snapshot1);
       
    dispatcher.action(actionDec, 1);
  • Middleware
    const dispatcher = new JStoreDispatcher(storeNumber);
    class AddMiddleware implements Middleware {
      public next<T>(data: MiddlewareData<T>): Observable<number> {
        const n = Math.floor(Math.random() * 10); // or http request
        /*if (n % 2 === 0) {
          throw new Error('n % 2 === 0');
        }*/
        return of(n);
      }
    }
    // named action with state, saved in history
    // action as function
    const actionInc = JStoreDispatcher.makeAction<number>(
      'inc',
      (state: number, payload: number, middlewareData: any) => {
        console.log('random number', middlewareData);
        return of(state + payload);
      },
      new AddMiddleware()
    );
    const actionDec = JStoreDispatcher.makeAction<number>('dec', (state: number, payload: number) => state - payload);
       
    // listener on action by action function
    const listener = dispatcher.on(actionInc, (value: number) => {
      console.log('on action {actionInc}: ', value);
    });
    
    // destroy listener
    listener();

For development

Переходим в директорию с проектом
cd folder-name
Установка зависимостей
yarn
Запуск сборки приложения и веб-сервера:
yarn run serve
Сборка приложения с минификацией:
yarn run build