Skip to content
nerdalyticsPublic

About

Reactive dependency graph runtime for Node.js. Track dependencies between states, computations, and effects automatically. Zero dependencies. TypeScript-first.

Topics

Resources

Code of conduct

Contributing

Stars

8 stars

Watchers

1 watching

Forks

Repository files navigation

Beacon A stylized lighthouse beacon with golden light against a dark blue background, representing the reactive state library

Reactive dependency graph runtime for Node.js backends. Tracks dependencies between signals and propagates updates automatically.

pm:yarn pm:pnpm pm:jsr pm:vlt registry:npm:version Socket Badge

tech:nodejs language:typescript linter:biome license:mit

Tracks which properties each effect reads and re-runs only when those properties change. Zero dependencies, TypeScript-first.

Installation

npm install @nerdalytics/beacon --save-exact
# or
yarn add @nerdalytics/beacon
# or
pnpm add @nerdalytics/beacon
# or
bun add @nerdalytics/beacon
# or
deno install npm:@nerdalytics/beacon
# or
npx jsr add @nerdalytics/beacon
# or
vlt install @nerdalytics/beacon

Quick Start

import { state, derive, effect } from '@nerdalytics/beacon';

const signal = state({ count: 0 });
const doubled = derive(() => signal.count * 2);

const dispose = effect(() => {
  console.log(`Count: ${signal.count}, Doubled: ${doubled.value}`);
});
// => "Count: 0, Doubled: 0"

signal.count = 5;
// => "Count: 5, Doubled: 10"

dispose();
doubled.reactive = false;

Async API (v2001)

Async derive and pending

derive accepts async compute functions. While a computation is in flight the value keeps its last settled result and pending is true; pending is itself a trackable dependency. Superseded computations are discarded, and rejections route to the onError hook.

const user = derive(async () => (await db.users.find(signal.id)) ?? null);
effect(() => {
  if (user.pending) return;
  console.log(user.value);
});

until

until(predicate, { timeout?, signal? }) resolves with the predicate's value once a settled evaluation is truthy — safe to await inside request handlers. It throws when called inside a reactive scope and disposes itself on settle, timeout, or abort.

await until(() => cache.warm, { timeout: 5000 });

onSettled

onSettled(callback) invokes the callback whenever the graph reaches quiescence after processing work (a flush or an async settlement). Returns an unsubscribe function.

Effect schedule option

effect(fn, name, hooks, { schedule: 'microtask' }) defers re-runs to a microtask, coalescing writes across await boundaries into one run. The default 'sync' preserves v2000 timing exactly.

Migration note: synchronous derive and default-schedule effects behave exactly as in v2000; the only consumer-visible changes are the new pending field on computed values and async compute support.

Documentation

Full documentation, API reference, and examples available at: nerdalytics.github.io/beacon

LLM-friendly docs

The handbook has plain-text endpoints for LLMs:

You can also append .md to any handbook page URL for its Markdown source (e.g. <version>/introduction.md).

License

MIT - See LICENSE for details.

About

Reactive dependency graph runtime for Node.js. Track dependencies between states, computations, and effects automatically. Zero dependencies. TypeScript-first.

Topics

Resources

Code of conduct

Contributing

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages