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

@derivesome/core

v1.0.23

Published

A lightweight reactive state management library with automatic dependency tracking.

Downloads

2,562

Readme

@derivesome/core

A lightweight reactive state management library with automatic dependency tracking.

Table of Contents


Core Concepts

Reactivity is built on automatic dependency tracking. When a ref.get() is called inside an effect or derived, that ref registers the running effect as a subscriber. When the ref's value changes, all subscribed effects re-run automatically. This means you never manually declare dependencies — the system infers them at runtime.


ref

ref(value) creates a reactive reference holding a single value.

import { ref } from '@derivesome/core';

const count = ref(0);

count.get();     // read and subscribe (inside an effect/derived)
count.peek();    // read without subscribing
count.set(1);    // update value — notifies subscribers only if value changed
count.set(n => n + 1); // functional update

Values are compared with strict equality (===). If the new value is the same as the previous one, no notification is sent.

ref also supports dispose() to remove all subscribers and effects:

count.dispose(); // tears down all subscriptions

isReference

import { isReference } from '@derivesome/core';

isReference(count); // true
isReference(42);    // false

derived

derived(fn) creates a computed value that re-evaluates automatically when its reactive dependencies change. It is itself a Reference, so it can be used anywhere a ref can.

import { ref, derived } from '@derivesome/core';

const count = ref(0);
const doubled = derived(() => count.get() * 2);
const label = derived(() => `Count is: ${doubled.get()}`);

doubled.peek(); // 0
count.set(5);
doubled.peek(); // 10
label.peek();   // "Count is: 10"

Dependencies are tracked dynamically per evaluation. If a branch is not taken, its refs are not subscribed:

const enabled = ref(false);
const value = ref(42);

const result = derived(() => {
  if (!enabled.get()) return -1;
  return value.get() * 2; // only subscribed when enabled is true
});

isDerived

import { isDerived } from '@derivesome/core';

isDerived(doubled); // true
isDerived(count);   // false

effect

effect(fn) runs a function immediately and re-runs it whenever any ref.get() called inside it changes.

import { ref, effect } from '@derivesome/core';

const name = ref('Alice');

effect(() => {
  console.log('Hello,', name.get());
});
// logs: "Hello, Alice"

name.set('Bob');
// logs: "Hello, Bob"

Effects are the primary way to cause side effects in response to reactive state changes. Unlike derived, they don't return a value.


Observable / observe

Every ref implements the Observable interface, which provides observe — a way to subscribe to value changes outside of the effect/derived system.

import { ref } from '@derivesome/core';

const count = ref(0);

const unsubscribe = count.observe((value) => {
  console.log('count changed to', value);
});

count.set(1); // logs: "count changed to 1"

unsubscribe(); // stop listening

count.set(2); // nothing logged

observe accepts an optional options object:

count.observe(
  (value) => console.log(value),
  {
    immediate: true,  // call the callback immediately with the current value
    cleanup: () => {  // called when the subscription is removed
      console.log('cleaned up');
    },
  }
);

isObservable

import { isObservable } from '@derivesome/core';

isObservable(count); // true

PubSub

pubsub() is the low-level primitive underlying ref. It provides a typed publish/subscribe channel with no built-in value storage.

import { pubsub } from '@derivesome/core';

const ps = pubsub<number>();

const unsub = ps.subscribe((value) => {
  console.log('received', value);
});

ps.publish(42); // logs: "received 42"

unsub(); // unsubscribe

ps.publish(99); // nothing logged

ps.dispose(); // remove all subscribers and effects

addEffect registers a function that participates in the reactive context system (re-runs through Context.runEffect):

ps.addEffect(() => {
  // re-run as a tracked effect when published
});

ArrayProxy

ArrayProxy<T> extends the native Array and emits a typed mutation event whenever the array is modified. Useful for building reactive list state.

import { ArrayProxy } from '@derivesome/core';

const items = new ArrayProxy('a', 'b', 'c');

const unsub = items.subscribe((mutation) => {
  console.log(mutation);
});

items.push('d');
// { type: 'push', items: ['d'] }

items.pop();
// { type: 'pop', removed: 'd' }

items.splice(0, 1, 'z');
// { type: 'splice', start: 0, deleteCount: 1, removed: ['a'], added: ['z'] }

items.set(0, 'x');
// { type: 'set', index: 0, value: 'x' }

items.sort();
// { type: 'sort' }

items.reverse();
// { type: 'reverse' }

items.dispose(); // remove all subscribers

Mutation types

| Method | Mutation type | Extra fields | |---------------|----------------|-------------------------------------------------| | push | push | items: T[] | | pop | pop | removed: T \| undefined | | shift | shift | removed: T \| undefined | | unshift | unshift | items: T[] | | splice | splice | start, deleteCount, removed, added | | sort | sort | — | | reverse | reverse | — | | fill | fill | value, start, end | | copyWithin | copyWithin | target, start, end | | .set(i, v) | set | index, value |


Utilities

findRefs

Recursively walks any value (object, array, or primitive) and returns all Reference instances found within it.

import { ref, findRefs } from '@derivesome/core';

const a = ref(1);
const b = ref(2);

findRefs({ a, b, nested: { c: ref(3) } });
// [Reference<1>, Reference<2>, Reference<3>]

findRefs([a, b]);
// [Reference<1>, Reference<2>]

findRefs(42); // []

match

match(input, pattern) is a structural pattern matching utility. It checks whether input structurally matches pattern, working as a type guard.

import { match } from '@derivesome/core';

// Primitive matching
match('hello', 'hello'); // true
match(42, 42);           // true
match(42, 99);           // false

// Object structural matching (partial — only pattern keys are checked)
const user = { role: 'admin', name: 'Alice' };
match(user, { role: 'admin' }); // true — narrows type
match(user, { role: 'guest' }); // false

// Array matching (positional)
match([1, 2, 3], [1, 2]); // true (pattern checked index-by-index)

// Type narrowing
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number };

function area(shape: Shape): number {
  if (match(shape, { kind: 'circle' as const })) {
    return Math.PI * shape.radius ** 2; // shape is narrowed to circle
  }
  return shape.side ** 2;
}

diff / patch

diff(a, b) computes a list of structural differences between two values. patch(target, diffs) applies those diffs to produce a new value.

import { diff, patch } from '@derivesome/core';

const a = { x: 1, y: 2 };
const b = { x: 1, y: 3, z: 4 };

const diffs = diff(a, b);
// [
//   { type: 'changed', path: ['y'], oldValue: 2, newValue: 3 },
//   { type: 'added',   path: ['z'], newValue: 4 },
// ]

const result = patch({ ...a }, diffs);
// { x: 1, y: 3, z: 4 }

Works recursively on nested objects and arrays:

diff([1, 2, 3], [1, 2, 3, 4]);
// [{ type: 'added', path: [3], newValue: 4 }]

diff({ a: { b: 1 } }, { a: { b: 2 } });
// [{ type: 'changed', path: ['a', 'b'], oldValue: 1, newValue: 2 }]

Stack

A simple typed stack used internally by the context system. Exported for external use.

import { Stack } from '@derivesome/core';

const stack = new Stack([1, 2, 3]);

stack.current; // 3 (top of stack)
stack.push(4);
stack.current; // 4
stack.pop();   // 4
stack.current; // 3