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

lean-state

v2.0.1

Published

A simple yet powerful way to manage state and reactive dataflow

Downloads

5

Readme

lean-state 2.0

A State Manager built for Lean Functional Typescript

Checkout: https://github.com/attack-monkey/Lean-Functional-Typescript

Changes from 1.x

  • Syntax changes to add more context to queries

Install


npm i lean-state

Use


import { register } from 'lean-state'

Basics


import { register } from 'lean-state'

type Global = {
  greeting: string
}

type Listeners =
  | 'listener1'
  | 'listener2'
  | 'listener3'

// register
const global = register<Global, Listeners>()

// set
global.set('greeting').with('hello world')

// get
console.log(
  global.get().greeting
)

// get the current and pass to function
global.once(
  ({ greeting }) => console.log(greeting)
)

// set up a listener...
global
  .listenOn('listener1')
  .for(['greeting'])
  .subscribe(({ greeting }) => console.log('listener1: ' + greeting))

// make changes and the listener will react
global.set('greeting').with('howdy y\'all')
global.set('greeting').with('wassup')
global.set('greeting').with('g\'day mate')

// set up a listener that auto tears down when a condition is no longer met
global
  .listenOn('listener2')
  .for(['greeting'])
  .while(({ greeting }) => greeting !== 'stop listening')
  .subscribe(({ greeting }) => console.log('listener2: ' + greeting))

// make changes and both listeners will react
global.set('greeting').with('good day')

// this next change will trigger listener2 to tear down...
global.set('greeting').with('stop listening')

// listeners can also be set up to listen, starting from the next change...
global
  .listenOn('listener3')
  .fromNext(['greeting'])
  .while(({ greeting }) => greeting !== 'stop listening')
  .subscribe(({ greeting }) => console.log('listener3: ' + greeting))

// And more changes...
global.set('greeting').with('heeeey!!!')
global.set('greeting').with('stop listening')

A complex example

Lean-state is a key-value store, so while complex data can be stored at a given key, listeners can only listen to changes at that top-level key.

This isn't really a problem at all - but does change the way you think about listening to changes in data.

If for example a key stores a Record of items - but your app is focused on changes only at a given item - then it's a good idea to also capture which id is being focused on and which id is being changed.


import { register } from 'lean-state'

type Car = {
  make: string
  color: string
}

type Global = {
  cars: Record<string, Car>
  lastUpdatedCar: string,
  focusOnCar: string
}

type Listeners = 
  | 'listener1'
  | 'listener2'

const global = register<Global, Listeners>()

const listenToAllCarChanges = () => {
  global
    .listenOn('listener1')
    .fromNext(['lastUpdatedCar'])
    .subscribe(({ cars, lastUpdatedCar }) =>
      console.log(`change to car ${lastUpdatedCar} => ${JSON.stringify(cars[lastUpdatedCar], null, 2)}`)
    )
}

const listenToNewFocusCar = (id: string) => {
  // Set up the car to focus on
  global.set('focusOnCar').with(id)
  global
    .listenOn('listener2')
    // listen to the next change to lastUpdatedCar
    .fromNext(['lastUpdatedCar'])
    .subscribe(({ cars, focusOnCar, lastUpdatedCar }) => {
      if(lastUpdatedCar === focusOnCar) {
        console.log(`Focussed car is ${focusOnCar} and it changed to => ${JSON.stringify(cars[focusOnCar], null, 2)}`)
      }
    })
}

const setInitialData = () => {
  global.set('cars').with({
    '1': { make: 'Toyota', color: 'red' },
    '2': { make: 'Toyota', color: 'blue'}
  })
  global.set('focusOnCar').with('1')
}

const updateCar = (id: string) => ({
  with: (car: Car) => {
    global.set('cars').at(id).with(car)
    global.set('lastUpdatedCar').with(id)
  }
})

// Set up data
setInitialData()

// Set up listeners
listenToAllCarChanges()
listenToNewFocusCar('1')

// Make updates
updateCar('3').with({ make: 'Corvette', color: 'red' })
updateCar('1').with({ make: 'Ferrari', color: 'pink' })

// Change focus car, which re-creates the listener
listenToNewFocusCar('2')

// Make more changes
updateCar('1').with({ make: 'Ferrari', color: 'red' })
updateCar('2').with({ make: 'Lamborgini', color: 'grey' })