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

orbz

v0.1.5

Published

observable objects

Downloads

8

Readme


Note: orbz is actively being built out. Recursive reactivity and performance improvements need to be finished before public adoption.


Overview

  • Feels like working with objects directly, keeping your codebase clean and simple.
  • Effects get re-triggered if and only if the underlying data changes.
  • Derived values only get calculated if you need them.

Under the hood, the Model definition creates a prototype that Orbs inherit. This prototype uses accessors to track usage and coordinate reactive updates.

The magic of Orbz comes from writing Models. Models are similar to classes, but with observability built-in. Their shape is frozen, such that only methods and public state values can alter each orb. They're defined by an object literal, with the following special rules:

  • getters are "derived" - and are only calculated if they're accessed. They keep track of internal state they rely on, and remain cached until one of the underlying values changes.
  • methods are batched, meaning effects are paused until the method is finished. This allows bulk edits without spammed effects
  • keys prefixed with _ are 'hidden'. only available for internal methods and serialization
  • generator methods are semi-batched, with resumability across sessions. This is in progress
  • values that are Models are guaranteed to be that Model, or else null.
  • values that are Orbs are guaranteed to be a unique Orb per instance, or another Orb of the same Model

API

new Model(definition)

Returns: an Orb constructor that follows the shape of the definition. This allows for generating N orbs with the same shape (that share a prototype).

new Orb(definition)

Returns: a one-off Orb with the shape of the definition

effect(callback, options)

Returns: a function to cancel the effect

The effect callback is called instantly with the current values. Accessed orb values are tracked, and whenever their values change, the effect callback is re-run.


Writing Models

Model definitions are designed to be easy to read while also giving freedom for how data is stored and processed for optimal performance.

State

Normal values. Can be primitives (numbers, strings, arrays, objects). These are the values that get serialized to/from JSON when saving/loading to a database.

Derived values

Computed values that depend on state or other derived values. Derived values aren't calculated until they're requested (lazy). Once computed, the value is cached until its dependencies update. If a derived value is being observed in an effect, it updates eagerly. Derived values are good for reformatting existing state or performing costly calculations based on state.

Methods

Methods are predefined functions that can mutate state or perform parameterized queries on the Orb. State mutations within a method are batched and trigger effects only once the method is complete. If a single event can update multiple parts of state, it's good to batch them in a method.

Local keys

State, derived values, and methods are, by default, publicly available to external calls. If you want to keep parts of the orb private, you can prefix the key with an underscore (_). Local keys can be accessed by methods and derived values, but throw an error when accessed outside of the orb. Local state is still serialized like normal state, but local state can only be externally set during orb initialization.

Internal orbs

Orbs are composable, so one Orb can contain another Orb. When creating a model definition, you can define a specific Model that the ensuing value must be an instance of. If a matching external Orb isn't supplied, an error will be thrown. Alternatively, you can define an instance of a Model, that gets instantiated for every new instance. The first approach "links" an external orb, whereas the second approach creates an "internal" orb that is managed by the parent orb.

Specialized Methods

To customize Orb behavior, a few methods are available to be overriden. The keys for these specialized methods are Symbols to avoid having name clashing.

  • [Model.Save]: override default serialization (which stores all state as JSON)
  • [Model.Load]: override default deserialization (which loads JSON state)

Example

import { Model } from 'orbz'

export const Counter({
  // STATE
  count: 0,
  // STATE (LOCAL)
  _multiplier: 1,
  // DERIVED
  get total(){
    let { count, _multiplier } = this
    return count * _multiplier
  } 
  // METHODS
  inc(){
    this.count++
  },
  double_mode(is_double){
    this._multiplier = is_double ? 2 : 1
  }
})

let c = new Counter({ count: 1 }) // start counter at 1

effect(() => {
  let { count, total } = c
  console.log(`Count: ${count}. Total: ${total}.`)
})
// ~> Count: 1. Total: 1
c.double_mode(true)
// ~> Count: 1. Total: 2
c.inc()
// ~> Count: 2. Total: 4
c.count = 10
// ~> Count: 10. Total: 20

Alignment

  • COPY PASTE as a first-class citizen. Behavioral code should be visible, easily readable, and quickly edited. Public gallery of copy-pasteable models > a list of npm imports
  • Model writers should consider performance: there are plenty of design choices. But, model source code should have as little boilerplate as possible. Perfectable by pros, readable by anyone.
  • Orb users should be able to read/write values just like a normal JS object. should feel like magic to get automatic updates with interconnected orbs.
  • Orb instances should function like files. easy to download, backup, edit.