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

@verajs/store

v0.1.2

Published

Store and reactivity primitives VeraJS core does not ship: memoised derived values, reactive collections, and more to come. Each reachable on its own subpath so a buildless page loads only what it uses.

Readme

@verajs/store

Reactivity primitives @verajs/core deliberately does not ship.

Core is the reactivity systemcreateStore, the proxy traps, the hook queue all live there. This is what core leaves out: extensions to the store that not every app needs, and that every app would otherwise pay for.

| Entry | | | | --- | ---: | --- | | @verajs/store/computed | 238 B | memoised derived values | | @verajs/store/collections | 571 B | reactive Map and Set in a store |

Import from the package root and a bundler tree-shakes to what you used; point an import map at a subpath and a buildless page downloads only that one. Both entries are additive: neither inlines core, so loading both still leaves one core, one insert registry and one store identity.

The two reach core from opposite directions, and the difference decides how any future member is written. computed calls into core — it imports createStore and createHook, because there is no derived value without a store. collections is called by core: it implements the 'collection' extension point, so core hands it addCallback and runCallbacks at dispatch and it imports nothing at all. The question that settles which shape a module takes is does core call you, or do you call core?

npm i @verajs/store

computed — memoised derived values

import { init, createStore, render, wire, html } from '@verajs/core';
import { renderer } from '@verajs/renderer';
import { computed } from '@verajs/store';

wire([renderer]);

customElements.define(
  'x-cart',
  class extends HTMLElement {
    connectedCallback() {
      init(this, { mode: 'open' });
      const cart = createStore({ items: [{ price: 3 }, { price: 4 }], coupon: '' });
      const total = computed(() => cart.items.reduce((n, item) => n + item.price, 0));

      render(() => html`
        <p>Total: ${total.value}</p>
        <button @click=${() => cart.items.push({ price: 5 })}>Add</button>
        <input .value=${cart.coupon} @input=${(e) => (cart.coupon = e.target.value)} />
      `);
    }
  }
);

document.body.append(document.createElement('x-cart'));

What it buys over a plain function

() => a + b runs on every read. computed(() => a + b) runs once per change, and only when something it actually read moves. Reading it a hundred times in one render costs one evaluation; typing in that coupon field above re-renders and costs none, because total never read coupon.

That is the entire reason the primitive exists — and it is what the older "computed is a ten-line insert" recipe never provided. That one re-invoked the function on every read, which is a getter with extra steps.

It is a store

Reading .value subscribes, so a component that reads a computed re-renders when it changes, and computeds chain — one may read another and invalidation propagates through:

const doubled = computed(() => state.n * 2);
const quadrupled = computed(() => doubled.value * 2);

The shape matches ref() deliberately: both are .value, so they are interchangeable at a call site. It derives through anything a store tracks — nested objects, arrays, Map, Set, WeakMap, WeakSet.

An evaluation that throws is reported through the 'error' insert rather than escaping, exactly as a hook is, and .value keeps serving the last good value — a derivation that fails once does not take the render down with it.

It is eager, not lazy — which is the opposite of the name's usual promise

A computed evaluates when it is created and re-evaluates on every dependency change, whether or not anything reads it. Vue, Solid and Preact all defer to the read and cache until invalidated; this does not. Measured: five writes with no reader at all produce six evaluations.

That is a consequence of how invalidation reaches a component, not an oversight. Reading .value subscribes, so a component re-renders when the computed changes — and knowing it changed means having computed it. A lazy computed can only say "I might have changed", which would re-render every reader on every dependency write and lose exactly the memoisation this exists for.

The practical consequence, and the reason it is written down here: an expensive derivation that nothing currently reads still costs on every write. Reads are free and repeated reads are free — what is not free is holding a computed nobody is using. If a derivation is expensive and conditional, guard the dependency, not the read:

// Runs on every `rows` write, even while the panel is closed.
const summary = computed(() => expensive(state.rows));

// Runs only while the panel is open.
const summary = computed(() => (state.panelOpen ? expensive(state.rows) : null));

Lifetime

A computed lives as long as you hold it. One created inside a component is collected with that component; one at module scope lasts for the page. There is nothing to dispose.

Nothing was added to core for this

It is built on createStore and createHook through their public API — @verajs/core grew two bytes, for returning a function it already constructed. That is the module system doing its job: you pay 238 B if you want memoised derivations and nothing at all if you do not.

Unlike the other modules, this one keeps @verajs/core external in every build rather than inlining it. It is built on core rather than beside it, and a standalone copy would hand a CDN page a second core — a second insert registry, a second store identity, and computeds tracking different objects from the components reading them.

collections — reactive Map and Set

wire([collections]) and a Map or Set inside a store tracks like anything else.

| Reading | Subscribes to | | --- | --- | | get(k), has(k) | that key | | size, entries(), keys(), values(), forEach() | every change | | for…of, [...collection] | every change |

set, add, delete and clear notify. Reactivity is per entry, not deep: a value comes back as it was put in, so mutating an object inside a collection notifies nothing — replace the entry instead. WeakMap and WeakSet work and cannot be iterated, so they subscribe per key only.

Two more exports are the extension point itself, for anyone implementing the 'collection' insert rather than using this one:

| | | | --- | --- | | collectionMethod | the implementation collections wires. Wrap it to add a type, or read it as the reference | | GLOBAL | the key that means the collection changed shape, as opposed to one entry changing |

GLOBAL is '_global', and it is a contract with @verajs/core, which declares the same literal rather than importing it. A production bundle inlines its dependencies, so an import would work in development and, in production, subscribe to one string while notifying another. Core tracks it from ownKeys and from a size read; a collection implementation notifies it on every mutation that adds or removes an entry. Notify something else and ${state.map.size} silently stops updating.

import { collectionMethod, GLOBAL } from '@verajs/store/collections';
import { wire } from '@verajs/core';

/** The signature is the `'collection'` insert's own — `collectionMethod` IS the registered fn,
 *  so a custom implementation wraps it: claim your type, delegate everything else verbatim.
 *  Core calls the chain's FIRST entry and caches it, so register before the first store read. */
wire({
  on: 'collection',
  priority: 40, // before the stock one at 50 — first in the chain is the one core calls
  fn: (obj, prop, propValue, addCallback, runCallbacks) =>
    obj instanceof MyCollection
      ? wrapMyCollection(obj, prop, propValue, addCallback, runCallbacks) // notify GLOBAL on shape changes
      : collectionMethod(obj, prop, propValue, addCallback, runCallbacks),
});

For AI assistants — and anyone who wants the whole API on one page

The repository root's llms.txt is the complete, hand-maintained API reference for every package, written to be pasted into a model's context window: full export tables, the buildless CDN and JSX recipes, semantics that differ from other frameworks, and the mistakes that come up most. Its recipes are executed by the test suite, so they stay honest.

License

MIT