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

storaje

v1.0.3

Published

## A configurable model stack to implement in your favorite front-end framework

Downloads

1

Readme

storaje

A configurable model stack to implement in your favorite front-end framework

The goal of storage is to give a very simple model implementation (like a database with events), that you can tweak and customize to fit your needs.

Quite everything is based on two aspects: a Store, which is where you store your data, and Observers, which allow you to register through data changes.

In the future, there will be integrations with popular frameworks, such as Svelte and React, and also a way for you to keep this data in a persistent cache (through local storage, filesystem or real databases).

Installation

For now the project is not published, but you could use it as a submodule and link it locally for now

  • Clone the repo
  • Intialize and build the repo
npm install
npm build

or just run yarn

  • Create the link
# In the storaje repository
npm link

# In your project repository
npm link storaje

or with yarn

# In the storaje repository
yarn link

# In your project repository
yarn link storaje
  • Import the project as any library, and enjoy
import { Store } from "storaje"

const store = new Store()

Documentation

Stores are based on the idea that you will have objects with a unique id parameter. For now it is hardcoded, and is intended to be a string.

Inserting / updating objects

To insert / update objects, just call the update method on Store. It takes as many objets as arguments as you want

import { Store } from "storaje"

interface Dog {
    id: string,
    name: string,
    age: number
}

const store = new Store<Dog>()

const doug: Dog = {
    id: "1",
    name: "doug",
    age: 7
}

const jake: Dog = {
    id: "2",
    name: "jake",
    age: 3
}

const jimmy: Dog = {
    id: "3",
    name: "jimmy",
    age: 7
}

store.update(doug, jake)

Retrieving objects

Now that you've populated your store, you can get them by id using get, or with a Query using find.
Querys are a partial representation of your objects, where all the filled fields have to be equal in the target object to be accepted (may be clearer in code).

// Using the same store

const dog1 = store.get("1") // doug

const dog2 = store.find({ age: 3 }) // jake

const dog3 = store.find({ name: "beatrice" }) // null, because no dog has the name beatrice wtf

const dog4 = store.find({ name: "jake", age: 4 }) // null, because no dog has the name "jake" AND is 4 years old

If you want to get multiple objects, you can use the getAll and findAll equivalents.

// Using the same store

const allDogs = store.getAll() // [doug, jake, jimmy]

const dogsThatAre3YearsOld = store.find({ age: 3 }) // [doug, jimmy]

Deleting objects

To delete objects, you can call the method delete, giving all the ids of the objects you want to delete as arguments

store.delete("1", "3")

store.get("1") // null, cuz doug has been killed

Registering to changes

To register to changes, you will have to use Observers. The concept of the observer is to act like a query for your store, which will be updated when objects are updates / deleted.

Observer<T>.value: T

Lets you get the current value of an observer

const callback = (value: T) => { }
Observer<T>.bind(callback)

Lets you bind to this observer's changes. Whenever the value changes, the given callback will be called

Observer<T>.unbind(callback)

Lets you unbind a previously set callback via bind

Observer.destroy()

Destroys the observers, making it unable to get changes and cleaning all the binded callbacks.

You can register to single objects using store.observe. This method takes either an id or a query as a parameter. The value of this observer will either be an object or null.

const observer = store.observe("some-id")
console.log(observer.value) // null

observer.bind(value => console.log("New value name:", value.name))

store.update({ id: "some-id", name: "test" })
// New value name: "test"

console.log(observer.value) // { id: "some-id", name: "test" }

To register to multiple objects, you can use the method store.observeAll, which takes an optionnal query as a parameter. If you do not set it, the observer will register for the entire store.

Known issues

There are some strange behaviors to be expected if you register an observer on a single object with a query, but that matches multiple objects. In this case, the observer will "hook" to one object, and if it's deleted, the observer will have the value null instead of falling back to the second match.

Example :

const store = new Store<{ id: string, size: number }>()

store.update(
    { id: "1", size: 10 },
    { id: "2", size: 5 },
    { id: "3", size: 5 },
    { id: "4", size: 10 },
);

const observer = store.observe({ size: 10 })
console.log(observer.value) // { id: "1", size: 10 }

store.delete("1")
console.log(observer.value) // null, even though the object with the id "4" would be a match

To avoid this behaviour, you can wrap an observerAll around an ObserverMapper, taking only the first element of the array - or null:

const store = new Store<{ id: string, size: number }>()

store.update(
    { id: "1", size: 10 },
    { id: "2", size: 5 },
    { id: "3", size: 5 },
    { id: "4", size: 10 },
);

const observer = new ObserverMapper(store.observeAll({ size: 10 }), array => array[0] ?? null)

console.log(observer.value) // { id: "1", size: 10 }

store.delete("1")
console.log(observer.value) // { id: "4", size: 10 }

Note that there is also a shorthand version of this in the Observer.array utility functions:

const observer = Observer.array.first(store.observeAll({ size: 10 }))

Roadmap

  • React implementation
  • Document ObserverReducer
  • Enhance and simplify the reducer to be accessible directly on the observer class