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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@figliolia/galena

v4.0.0

Published

A performant state management library supporting middleware and a rich developer API

Readme

Galena

Lightning fast, framework agnostic state, that doesn't glue your state operations to your UI components!

State Galena For use with react

Installation

npm i @figliolia/galena
# with react
npm i @figliolia/react-galena

Basic Usage

The State Model

The instancable State object in Galena is a reactive wrapper around any value. You can use it to apply reactivity to large objects or simple values

import { State, createState } from "@figliolia/galena";

const myState = new State(/* any value */, /* middleware */);
// or
const myState = createState(/* any value */, /* middleware */);

const currentValue = myState.getState();
const subscriber = myState.subscribe(nextValue => {});
myState.set(/* new value */);
myState.update(previousValue => /* new value */);

// to reset state back to its original value
myState.reset();

// to unregister the subscription
subscriber();

Instances of State are ultimately what compose all reactivity in Galena. They can exist as islands compose larger stateful model.

The Galena Model

Galena objects are designed to "link" multiple instances of State together to create a "global" application state.

To use it simply define your State's and pass them to a Galena instance

import { Galena, State } from "@figliolia/galena";

const AppState = new Galena(
  {
    navigation: new State({
      currentRoute: "/",
      navigationMenuOpen: false,
    }),
    user: new State({
      userID: "<id>",
      membershipTier: "free",
      friends: ["<id-1>", "<id-2>"],
    }),
    // ...and so on
  } /* middleware */,
);

// From here, operations on any slice of state are type-aware
// and operable via a single construct:
const subscriber = AppState.subscribe(
  ({
    state, // The entire state object at the time of change
    updated, // This individual State instance that was updated
  }) => {
    // react to state changes
  },
);

// to unsubscribe
subscriber();

// to access an instance of state
const UserState = AppState.get("user");
// to operate
UserState.update(state => /* next state */);
// or
AppState.update("user", state => /* next state */);

// to get the current value of the state tree
const state = AppState.getState();

Beyond the Basics

Modeling Data with Mutations

State in Galena is designed for extension and instancing - a need that ultimately motivated the library's development.

Let's take a look at a working example

import { State } from "@figliolia/galena";

export class MyGameState extends State<IMyGameState> {
  constructor(
    public readonly playerID: string,
    initialState?: Partial<IMyGameState>,
  ) {
    super({
      // ...default values for state
      score: 0,
      level: 1,
      // overrides for the current instance
      ...initialState,
    });
  }

  public incrementScore(byAmount: number) {
    this.mutate(state => {
      state.score + byAmount,
    });
  }

  public goToNextLevel() {
    this.mutate(state => {
      state.level + 1,
    });
  }

  private mutate(fn: (state: IMyGameState) => void) {
    state.update(previous => {
      const clone = {...previous};
      fn(clone);
      return clone;
    })
  }
}

These more "robust" state models assist in standardizing a developer API along with your data models. The models you create are also compatible with your your Galena instances:

import { Galena } from "@figliolia/galena";
import { MyGameState } from "./MyGameState";

const MyAppState = new Galena({
  player1: new MyGameState(),
  player2: new MyGameState(),
});

// Operate
MyAppState.get("player1").incrementScore(100);
MyAppState.get("player2").raiseLevel();

Middleware

Middleware provides a developer API for building out custom tooling for your state.

Building middleware is as simple as extending Galena's Middleware class and registering on your state.

Here's a quick example using the redux-like logger provided by this package:

import { Middleware, type State } from "@figliolia/galena";

export class Logger<T = any> extends Middleware<T> {
  private previousState: T | null = null;

  override onBeforeUpdate(state: State<T>) {
    // capture the previous state before an update takes place
    this.previousState = state.getState();
  }

  override onUpdate(state: State<T>) {
    // Log the time of mutation
    console.log(
      "%cMutation:",
      "color: rgb(187, 186, 186); font-weight: bold",
      "@",
      this.time,
    );
    // Log the previous state
    console.log(
      "   %cPrevious State",
      "color: #26ad65; font-weight: bold",
      this.previousState,
    );
    // Log the new state
    console.log(
      "   %cNext State    ",
      "color: rgb(17, 118, 249); font-weight: bold",
      state.getState(),
    );
  }

  private get time() {
    const date = new Date();
    const mHours = date.getHours();
    const hours = mHours > 12 ? mHours - 12 : mHours;
    const mins = date.getMinutes();
    const minutes = mins.toString().length === 1 ? `0${mins}` : mins;
    const secs = date.getSeconds();
    const seconds = secs.toString().length === 1 ? `0${secs}` : secs;
    const milliseconds = date.getMilliseconds();
    return `${hours}:${minutes}:${seconds}:${milliseconds}`;
  }
}

Registering middleware is simple:

import { Logger, Profiler } from "@figliolia/galena";

// To apply middleware to all instances of `State`
// attached to a `Galena` instance

const MyAppState = new Galena({
  // state
}, new Logger(), new Profiler());

// To apply middleware to a single piece of `State`
const MyState = new State(
  /* reactive value */,
  new Logger(),
  new Profiler()
);

In your console you'll now see logs like the following: And Profiler warnings such as thing one

Frameworks

With State management tools, naturally comes frontend frameworks. Galena provides bindings for React through the react-galena library