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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@wfh/reactivizer

v0.2.0

Published

Another RxJS auxiliary tool, which "reactive-ize" plain Javascript (Typescript) object

Downloads

11

Readme

Make your plain object reactive

contents

 |- 1. A brief introduction
 | |- 1.1 Some of implemented design goals and APIs
 | |- 1.2 Quick view of what it looks like
 | | |- 1.2.1 Use interface or type to define the shape of reusable entity
 | | |- 1.2.2 Turn plain object to reactive reusable entity

1. A brief introduction

@wfh/reactivizer is a RxJS based Reactive Programming library for programming convenience. Like a lot of other rx series library, it provides some utility functions and classes that help to program our application in an opinionated Reactive programming style or paradigm at a low level.

The idea is combining traditional object-oriented designed resuable software entity (Class/Object) with "event streaming" and reactive style.

Unlike other "rx" based librarys,

  • @wfh/reactivizer does not emphasize contribution on either frontend or backend side, it is just a low level programming utility, but it is not limited to be used as frontend state management tool or a backend service controller, even graphics scene builder.
  • @wfh/reactivizer is not a platform or architecture tool like "event sourcing" to address and solve high level design concerns in between modules or services.

Some of the concepts and conventions are inspired by Apache kafka, Redux-observable

1.1. Some of implemented design goals and APIs

  • Great Typescript type definition for type inference
  • You can use plain "interface", "class" and "member functions" to define group of Observable message streams.
  • Mimic OOP concept, You can extend exsting reusable entity (class/object), intercept input or output messages to override existing behaviors of extended entity.
  • Simple, easy to understand how it works and easy to remember any of API name, less coding in consumer program.
  • Taking care of error handling by default.
  • tables, message's state management, which is a queriable snapshot of Observable messages.
  • Message, tracing and tracking which can help to debug and locate problems of from big amount of Observable messages.
  • A recursive forkjoin API for Node.js thread_workers and browser's web worker, and on top of it, an implementation of multithread merge sort algorithm.
  • RxJS is the only required (peer) dependency, another optional dependency @wfh/algorithms is only needed in case of using forkjoin module

1.2. Quick view of what it looks like

1.2.1. Use interface or type to define the shape of reusable entity

import * as rx from 'rxjs';
import {ReactorComposite} from '@wfh/reactivizer';

// input message
type InputActions = {
  greeting(byName: string): void;
  askQuestion(topic: string, detial: string): void;
  setLanguage(locale: string): void;
};

// output message
type OutputEvents = {
  replyGreeting(word: string): void;
  answerQuestion(content: string): void;
};

export function createSample() {
  // define which actions should be stateful (treated as new ReplaySubject(1))
  const inputTableFor = ['setLanguage'] as const;

  const sample = new ReactorComposite<InputActions, OutputEvent, typeof inputTableFor>({
    name: 'Sample',
    inputTableFor
  });

  const {i: input, o: output, r: addReactor, inputTable} = sample;

  // set default value for a stateful message stream
  input.dispatcher.setLanguage('zh');

  // Plan reactions on incoming "action"
  addReactor('handle greeting', input.payloadByType.greeting.pipe(
    rx.mergeMap(async ([, byName]) => {
      const nickName = await someAsyncQuery(byName);
      output.dispatcher.replyGreeting('Hi ' + nickName);
    })
  ));

  addReactor('answer questions', input.payloadByType.askQuestion.pipe(
    // retrieve latest value of stateful message "setLanguage"
    rx.combineLatestWith(inputTable.l.setLanguage.pipe(rx.take(1)),
    // Choose to ignore last question
    rx.switchMap(async ([[meta1, topic, detail], [meta2, lang]]) => {
      const answer = await someAsyncQuery(lang, detail);
      output.dispatcherFor.answerQuestion([meta1, meta2], `>> ${topic}\n` + answer);
    })
  ));
}

1.2.2. Turn plain object to reactive reusable entity

class MyService {
  greeting(user: string, msg: string) {
    return Promise.resolve('Welcome' + user);
  }

  search(keyWords: string) {
    return rx.of('result: ...');
  }
}

export function createMyReactiveService() {
  return new ReactorComposite({name: 'myService'})
    .reactivize(new MyService());
}

// Use reactive version of MyService
const myRxService = createMyReactiveService();

// Dispatch "search" message and observe respective "returned" message, "at" stands for "actionByType"
myRxService.i.dispatchAndObserveRes.search(myRxService.o.at.searchResolved, 'ReactiveX').pipe(
  rx.tap(([, result]) => {
    console.log('we got search result', result);
  })
).subscribe();

// pt stands for abbrevation of "payloadByType"
myRxService.o.pt.greetingResolved.pipe(
  rx.tap(([, replyGreeting]) => {
    console.log('My service resplied with:', replyGreeting);
  })
).subscribe();

myRxService.i.dispatcher.greeting('Tommy', 'Hi');

2. Understand by comparing with plain object-oriented programming

Further reading

Document site is under construction, author is also working on implementing a version in Java.