1.3.4 • Published 3 months ago

repostream v1.3.4

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

RepoStream

License

Concept

RepoStream serves as an intermediary layer between the UI and Business logic of your application. It leverages the StateStream to deliver the application state to the UI, while incorporating business logic through the use of middlewares and joinStates within the RepoStream.

RepoStream

RepoStream acts as the central manager of the application states. Clients connect to one or multiple states within the repo by utilizing the createStream method, which returns a StateStream object connected to the desired states. Communication between the repo and streams occurs via event messages. Clients can employ three different messages (push, pop, and request) to instruct the repo to modify the application state.

State and State Path

RepoStream maintains all application states within its states object. Here's an example of the states object structure:

states = {
  stores: {
    city: {
      hcmc: [
        'Dev Store', 'Play Store'
      ]
    }
  },
  stocks: {
    games: [
      {
        title: 'Awesome adventure of a poor dev',
        quantity: 100
      }
    ]
  }
}

In the above example, two application states are present: stores and stocks. Each state acts as the root of its respective state tree. For instance, stores and stocks serve as the root for their corresponding state trees. A state path represents the path to reach a specific point within the state tree. For example, stocks.games and stores.city.hcmc are state paths within the provided example.

State path support wildcast character, for example 'users..profile' will match users.bob.profile and users.anna.profile.

The StateStream object can request changes to the state root or a specific state path. You need to define the middleware function to handle the request for a specific state path

Middleware

const middleware = {
  push: (changePath, changeValue, currentValue, state, setState, setError) => {
    currentValue.push(changeValue);
    return currentValue;
  }
}

const repo = new Repo();
repo.addMiddleware('stores.city.*', middleware);

stream = repo.createStream(['stocks', 'stores']);

stream.push('stores.city.hcmc', 'Game Store');

The middleware function handles state path requests and can return a new state value for the specified changePath. Alternatively, it can return a promise that resolves to a new value.

If the middleware function returns undefined, the state will not be updated unless setState is called within the middleware body.

To manipulate the state object, you can use the setState callback. In certain cases, such as deleting a state branch, the callback is useful. It accepts a new state tree or a function to avoid potential issues with stale state.

Here's an example of defining a middleware function:

const middleware = {
  remove: (changePath, changeValue, currentValue, state, setState, setError) => {
    delete state.stocks.games;
    setState(state);
  },
}

joinState

The joinState method in the RepoStream API allows you to create a virtual state by joining multiple states together. Whenever any of the states in the joining array changes, the joined state will be automatically updated using the provided joinFunction.

Usage

repo.joinState(name, states, joinFunction);
  • name (string): The name of the joining state.
  • states (array): An array of states to join together.
  • joinFunction (function): A function that accepts the repo's state object, performs logic to join the states, and returns the joined state.

The joinFunction takes the repo's state object as an argument and should return the joined state object.

Example

Here's an example of using joinState to create a virtual state called itemsInStore by joining the stocks and stores states:

repo.joinState('itemsInStore', ['stocks', 'stores'], state => {
  const itemsInStore = {};
  for (let store of state.stores) {
    const items = [];
    for (let item in state.stocks) {
      items.push({
        name: item,
        quantity: state.stocks[item].filter(item => item.store === store).length
      });
    }
    itemsInStore[store] = items;
  }
  return itemsInStore;
});

In the above example, the joinFunction iterates over each store in the stores state and collects the items from the stocks state that belong to that store. It creates an object itemsInStore where each store is a key and its corresponding value is an array of items with their quantities. Whenever either the stocks or stores state changes, the itemsInStore state will be updated accordingly.

The joined state itemsInStore can then be accessed and used in the application to display the relevant information.

Installation

To use RepoStream in your project, follow these steps:

  1. Install the package via npm:
npm install repostream --save
  1. Import RepoStream into your project:
import RepoStream from 'repostream';

Usage

Here's an example of how to use RepoStream:

import RepoStream from 'repostream';

const schemas = {
  profile: {
    username: 'username',
    picture: 'default_url'
  },
  enrolls: [],
  score: {
    math: 0,
    physics: 0,
  }
};

const repo = new RepoStream({ schemas });

repo.addMiddleware('user.enrolls', {
  push: (changePath, changeValue, currentValue, state, setState, setError) => {
    state.user.enrolls = [...state.user.enrolls, changeData];
    setState(state);
  }
});

// Create a stream that connects to the 'user' state in the repo
const stream = repo.createStream(['user']);

// Set up listeners for state changes and errors
stream.onStateChange(state => console.log(state));
stream.onError(err => console.error(err));

// Push a new state change to the stream
const requestPush = stream.request('push');
requestPush('user.enrolls', 'javascript');

console.log(stream.state);

// Remove the stream itself
stream.remove();

Developer Document

RepoStream API

Methods

  • constructor({ schemas }): Initializes a new instance of RepoStream with the specified schemas.
  • createStream(states): Creates a stream that connects to the specified states in the repo.
  • addMiddleware(statePath, middleware): Adds middleware for the given state path.
  • invokeMiddleware({ statePath, action, changeValue }): Invode the middleware.
  • joinState(name, states, joinFunction): Joins multiple states using a custom join function.

Properties

  • schemas: The schemas defined for RepoStream.
  • repo: The underlying Repo instance.
  • streams: The active streams created from the repo.

StateStream API

Methods

  • constructor({ id, eventEmitter, state }): Initializes a new instance of StateStream with the provided parameters.
  • request(requestType): Returns a requester function that can be used to request a state change.
  • onStateChange(callback): Sets up a listener for state change events.
  • onError(callback): Sets up a listener for error events.
  • remove(): Removes the StateStream.

Properties

  • state: The current state associated with the StateStream.

EventEmitter API

Methods

  • addListener(eventName, handler): Adds a listener for the specified event.
  • removeListener(eventName, handler): Removes a previously added event listener.
  • emit(eventName, ...args): Emits an event with optional arguments.

TODO

  • Create repostream-middlewares package that includes common middleware functions, such as pushing to an array.
  • Enable the usage of repo.addMiddleware('state.path', { push: mw.pushToArray }).

Contributing

Contributions are welcome! If you have any ideas, suggestions, or bug reports, please open an issue or submit a pull request.

License

This project is licensed under the MIT License.

1.3.4

3 months ago

1.3.3

10 months ago

1.3.2

10 months ago

1.3.1

10 months ago

1.3.0

10 months ago

1.2.5

1 year ago

1.2.4

1 year ago

1.2.3

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.2

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.0.0

1 year ago