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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@taujor/eis

v1.1.5

Published

EIS ❄️ (Extremely Immutable State) A tiny, framework-agnostic state store for the web. Simple, reactive, and immutable. Works with everything.

Downloads

14

Readme

Sponsor

EIS ❄️ (Extremely Immutable State)

A tiny, framework-agnostic state store for the web. Simple, reactive, and immutable. Works with everything.


Features

Core Features

  • Immutable State: State is always frozen to prevent accidental mutations.
  • Deep Freeze: Recursively freezes all nested objects for deep immutability.
  • Deep Clone: Uses structuredClone if available, falls back to JSON.parse(JSON.stringify(...)) to ensure state updates are truly immutable.
  • Simple API: Only three methods: get, set, and subscribe.
  • Functional Updates: Supports both direct value updates and updater functions.
  • Subscription Model: Listen to state changes and react accordingly.
  • Instant Notification: Optionally call listeners immediately with the current state.
  • Unsubscribe Support: Easily remove listeners when no longer needed.
  • Clear Error Handling: Provides actionable error messages for debugging.
  • No External Dependencies: Self-contained, minimalistic, and easy to integrate.

API Methods

| Method | Description | |----------------|-------------------------------------------------------------------------------------------------| | get() | Returns the current state. | | set((state) => {}) or set(value) | Replaces the state. Accepts either a new state or an updater function that returns new state. | | subscribe((state => {})), false) | Subscribes a listener function to state changes. Returns an unsubscribe function. Setting false to true will run the listener instantly. | | eis(null, {"dev": false}) | Default exported function the first argument takes your inital state (uses set) and the second is an optional configuration object that can be used to set developer mode to false disabling freezing and cloning for better performance. |

Error Handling

  • Invalid Initial State: Logs an InitError if initialState is undefined, defaulting to null.
  • Invalid Object Freeze: Throws a TypeError if an invalid object (e.g., string, number, null) is passed to _freeze, expecting a plain object or array.
  • Non-serializable Object: Throws a CloneError if an object or array cannot be cloned due to non-serializable data (e.g., functions, Date objects, circular references).
  • Undefined Set Value: Logs a SetError if set is called with undefined.
  • Updater Returns Undefined: Logs a NoOp warning if an updater function returns undefined.
  • Invalid Listener: Logs a SubscribeError if a non-function is passed to subscribe, ignoring the subscription.

Installation

npm install @taujor/eis

or

yarn add @taujor/eis

Via CDN:

import eis from 'https://unpkg.com/@taujor/eis/eis.js'

Or include directly in your project:

import eis from '@taujor/eis'

Example

JavaScript

import eis from '@taujor/eis';
const [get, set, subscribe] = eis({ count: 0 });
// Subscribe to state changes
const unsubscribe = subscribe((state) => {
  console.log('State changed:', state);
}, true);
// Update state
set({ count: 1 });
// Logs: State changed: { count: 1 }
set((state) => ({ count: state.count + 1 }));
// Logs: State changed: { count: 2 }
// Get current state
console.log(get());
// { count: 2 }
// Unsubscribe
unsubscribe();

React

import { useEffect, useState } from 'react';
import eis from '@taujor/eis';
// Initialize the state store with a number
const [get, set, subscribe] = eis(0);
function Counter() {
  // Use React state to trigger re-renders
  const [count, setCount] = useState(get());
  // Subscribe to eis state changes
  useEffect(() => {
    const unsubscribe = subscribe((newState) => {
      console.log('Count:', newState);
      setCount(newState); // Update React state
    }, true); // Immediate invocation to sync initial state
    return unsubscribe; // Cleanup on unmount
  }, []);
  return (
    <div style={{ padding: '20px' }}>
      <h1>Simple Counter</h1>
      <p>Count: {count}</p>
      <button
        onClick={() => set((state) => state + 1)}
        style={{ marginRight: '10px' }}
      >
        Increment
      </button>
      <button
        onClick={() => set((state) => state - 1)}
      >
        Decrement
      </button>
    </div>
  );
}
export default Counter;

Use Cases

  • Simple State Management: Ideal for small to medium sized web apps.
  • Immutable Data Flow: Ensures data integrity by preventing direct state mutations.
  • Reactive UI Updates: Works well with UI libraries for reactive updates.
  • Backend Task Scheduling & Caching: Useful for caching API requests or batching background jobs.
  • Debugging: Clear error messages help identify issues during development.
  • Testing: Predictable state updates make testing straightforward.

Limitations

  • JSON Serializable Objects: JSON.parse(JSON.stringify(...)) does not handle non-serializable objects so for consistency non-serializable objects are also rejected when using structuredClone.
  • Performance Overhead: Deep cloning and freezing can be slow for very large state objects. Try to keep them small or even better flat. Use multiple local stores instead of a single global store to achieve better performance. While still good practice this is now mitigated by setting developer mode to false to disable cloning/freezing in production like so eis(null, {dev: false})

Upcoming Features

  • Documentation: A documentation website for eis with tutorials, framework integration examples, and extensive technical documentation so everyone can use eis to its full potential.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.


Working on something cool?

If you're using eis.js why not show off about it? Let everyone know in the dedicated discussion