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

restarfall

v0.3.1

Published

Restarfall is a JavaScript library for creating business logic and data management.

Downloads

46

Readme

Restarfall

Restarfall is a JavaScript library for creating business logic and data management.

Usage

import { create, use } from "restarfall";

// Create store with value of count
const $count = create.store<number>(0);

// Create event for increase value of count
const inc = create.event<void>();

// Create unit with logic for count
const counter = create.unit(() => {
  // Use depend from event `inc`
  const incEvent = use.depend(inc);

  // Use value store of count
  const count = use.value($count);

  // Use dispatch for store of count
  const setCount = use.dispatch($count);

  // If the event was triggered change the value of the storage
  if (incEvent.called) setCount(count + 1);

  // Return null, because `counter` doesn't have children units
  return null;
});

// Create shape to run `counter`
const shape = create.shape();

// Attach and run `counter`
shape.attach(counter());

Documentation

You can

Create store

A store is some kind of key to use between units and other third-party libraries.

import { create } from "restarfall";

const $count = create.store<number>(0);

Create event

An event is some kind of key to use between units and other third-party libraries.

import { create } from "restarfall";

const inc = create.event<void>();

Create unit

The unit is required to create the logic of storage update and react to events correctly. The order of unit call execution is preserved even after dependency updates, which makes your code predictable.

import { create } from "restarfall";

const counter = create.unit(() => null);

Create unit with children units

You can use child units in the unit body in various variations.

[!IMPORTANT] Calling a child unit inside a parent unit does not guarantee that the body of the child unit will be called. To call the body of the child unit, you must set it to the return of the parent unit.

import { create } from "restarfall";

// Without children
const setValue = create.unit(() => null);

// With two children
const update = create.unit(() => [setValue(), setValue()]);

// With one child
const counter = create.unit(() => update());

Use arguments for units

You can also use arguments in the unit body to fine-tune your application (reusing the unit for some dependency).

import { create } from "restarfall";

const update = create.unit((name: string, index: number) => null);

const counter = create.unit(() => [update("first", 0), update("second", 1)]);

Create element from unit and use one in other units

When a unit is called, an element is created that can be used either as a child unit or as a rooted unit.

import { create } from "restarfall";

const update = create.unit((name: string, index: number) => null);

const firstUpdate = update("first", 0);
const secondUpdate = update("second", 1);

const counter = create.unit(() => [
  firstUpdate,
  secondUpdate,
  update("last", 99),
]);

Create shape

A shape is a certain context relative to which the attached units will be launched. The form stores the raw data (e.g. received via ssr), storage state, data with which events were called, event listeners, and units, both root and child units, to ensure the order in which units are called.

import { create } from "restarfall";

const shape = create.shape();

Attach root-unit to shape

For the created units to work, they need to be attached to the shape.

[!NOTE] The order of joining affects the order of calling units.

import { create } from "restarfall";

const root = create.unit(() => null);

const shape = create.shape();

shape.attach(root());

// You can twice attach `root-unit` to `shape`
shape.attach(root());

Use value hook into unit

This hook is essential for working with storage data .

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const count = use.value($store);
  return null;
});

Use depend hook into unit

This hook is required to subscribe to a storage change or event call. When subscribing to a storage change inside the hook, it is just subscribing to an event $store.changed. This is why the return value signatures of this hook are the same. When an event is called, the entire body of the unit will be recalled. The return values of this hook will contain an object { called: boolean: payload?: EventPayload }.

[!IMPORTANT] When a unit is called again, all child units are unsubscribed from their dependencies. This implementation ensures that an event occurring in the parent unit will not be triggered in the child unit and will not cause the child unit to be called again. In addition, it is possible to enable/disable large branches of business logic under certain conditions.

import { create, use } from "restarfall";

const $count = create.store<number>(0);
const inc = create.event<void>();

const counter = create.unit(() => {
  const countChanged = use.depend($count);
  const { called, payload } = use.depend(inc);
  return null;
});

Use filter for depend hook

The filter is necessary to optimise the call to the unit body.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const countChangedMore2 = use.depend($count, (count) => count > 2);
  return null;
});

Lock depend

Sometimes you just need to get the values of an event but not subscribe to it.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const countChanged = use.depend($count, false);
  return null;
});

Use dispatch hook into unit

This hook is required to change the storage or call an event in the unit body.

import { create, use } from "restarfall";

const $count = create.store<number>(0);
const inc = create.event<void>();

const counter = create.unit(() => {
  const changeCount = use.dispatch($count);
  const changeByInc = use.distpach(inc);

  setTimeout(() => changeCount(2), 1000);
  setTimeout(() => changeByInc(), 2000);

  return null;
});

Use take hook into unit

The data hook is needed to get the storage value when the unit body context is lost, e.g. in setTimeout.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const takeCount = use.take($count);
  const changeCount = use.dispatch($count);

  setTimeout(() => changeCount(takeCount() + 1), 1000);

  return null;
});

Use promise hook into unit

This hook will come in handy if you are using ssr. Using it you can wait for all asynchronous processes to execute.

import { create, use } from "restarfall";

const request = async () => ({ count: 2 });

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const changeCount = use.dispatch($count);

  use.promise(request()).then(({ count }) => changeCount(count));

  return null;
});

const shape = create.shape();

shape.attach(counter());
shape.wait().then(() => {
  // all requests done
});

Use cache hook into unit

This hook is required to cache any data inside the unit body.

[!NOTE] It can help with reducing the number of attachments/ detachments of child units, because the comparison of children of the previous and current steps is used for optimisation.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const countCache = use.cache($count);
  const countByGet = countCache.get().value;
  const countByTake = countCache.take(() => 3);

  countCache.set(5);

  return null;
});

Use cache hook with added keys

This use of the hook will make it possible not to create an additional store for caching similar data types.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const countCacheFirst = use.cache($count, "first");
  const countCacheLast = use.cache($count, "last");

  countCacheFirst.take(() => 5);
  countCacheLast.take(() => 10);

  return null;
});

Use detach hook (effect) into unit

This hook is required to detect the event of detaching a unit element from the unit tree.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const setCount = use.dispatch($count);

  use.detach(() => setCount($count.initialValue));

  return null;
});

Use attach hook (effect) into unit

This hook is required to detect the attachment event of a unit element in the unit tree.

import { create, use } from "restarfall";

const $count = create.store<number>(0);

const counter = create.unit(() => {
  const setCount = use.dispatch($count);

  use.detach(() => setCount(4));

  return null;
});

Use rawData / deserialize / serialize into units and shape

These methods are necessary to implement the logic for ssr.

[!IMPORTANT] Raw data cannot be deserialised again. For example, if there are two units that deserialise the same data, deserialisation will happen once.

[!IMPORTANT] When deserialising, the value must be set correctly, otherwise you may get errors when trying to work with storage data.

import { create } from "restarfall";

const $count = create.store<number>(0);
const $token = create.store<string>("empty");

const counter = create.unit(() => null, {
  deserialize: (getValue) => ({
    count: {
      store: $count,
      value: getValue("_count_").value,
    },
    token: {
      store: $token,
      value: getValue("token_key").value ?? $token.initialValue,
    },
  }),
  serialize: (getValue) => ({
    _count_: getValue($count),
    _token_: getValue($count),
  }),
});

const shape = create.shape();

shape.setRawData({ _count_: 2 });
shape.attach(counter());

const data = shape.serialize(); // data equal { _count_: 2, _token_: "empty" }

Use created elements into parent unit

This technique can be used instead of caching elements inside the unit body, especially if the arguments of child units do not change dynamically.

import { create, use } from "restarfall";

const update = create.unit((name: string) => null);

const firstUpdate = update("first");
const lastUpdate = update("last");

const counter = create.unit(() => [firstUpdate, lastUpdate]);

Examples

Unit life cycle

flowchart TB
  unit("Create unit")
  element("Create element")
  instance("Create instance")
  attach("Attach instance")
  reattach("Reattach instance")
  detach("Detach instance")

  unit --> element
  element --> instance
  instance --> attach
  attach -.-> reattach
  reattach -.-> detach
  attach -.-> detach

Algorithm for attaching a root-unit to a shape

flowchart TB
  attach("Attach root unit")
  push("Push root to shape")
  link("Link depends")
  attachEffects("Call attach effects")

  attach --> push
  push -->link
  link --> attachEffects

Algorithm for updating a unit after a storage change or event call

flowchart TB
  filterDepend("Filter depend")
  unlink("Unlink depends")
  reattach("Reattach current instance")
  link("Link depends")
  detachEffects("Call detach effects")
  attachEffects("Call attach effects")

  filterDepend --> unlink
  unlink --> reattach
  reattach --> link
  link --> detachEffects
  detachEffects --> attachEffects

Algorithm of event call

flowchart TB
  updatePayload("Update payload event")
  buildIndexes("Build indexes of instances")
  buildListener("Build listeners by owner")
  callListenersOfInstances("Call listeners of instances")
  callListenersOfOutside("Call listeners of outside")

  updatePayload --> buildIndexes
  buildIndexes --> buildListener
  buildListener --> callListenersOfInstances
  callListenersOfInstances --> callListenersOfOutside

API

Event

Store

Unit

Hooks

Shape

Methods of data

Methods of values

Methods of events

Methods of units

Combined APIs for short import methods from library

This api was created to simplify the import of methods from the library.

Tests (jest)