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

agera

v1.0.0-alpha.4

Published

A small push-pull based signal library based on alien-signals algorithm.

Downloads

31

Readme

Agera

ESM-only package NPM version Dependencies status Install size Build status Coverage status

A small push-pull based signal library based on alien-signals algorithm.

Was created as reactivity system for nanoviews and Kida.

  • Small. Around 1.8 kB for basic methods (minified and brotlied). Zero dependencies.
  • Super fast as alien-signals.
  • Designed for best Tree-Shaking: only the code you use is included in your bundle.
  • TypeScript-first.
import { signal, computed, effect } from 'agera'

const $count = signal(1)
const $doubleCount = computed(() => count() * 2)

effect(() => {
  console.log(`Count is: ${$count()}`);
}) // Console: Count is: 1

console.log($doubleCount()) // 2

$count(2) // Console: Count is: 2

console.log($doubleCount()) // 4

Install

pnpm add agera
# or
npm i agera
# or
yarn add agera

API

Signal

Signal is a basic store type. It stores a single value.

import { signal } from 'agera'

const $count = signal(0)

$count($count() + 1)
// or
$count(count => count + 1)

To watch signal changes, use the effect function. Effect will be called immediately and every time the signal changes.

import { signal, effect } from 'agera'

const $count = signal(0)

const stop = effect(() => {
  console.log('Count:', $count())

  return () => {
    // Cleanup function. Will be called before effect update and before effect stop.
  }
})
// later you can stop effect
stop()

Computed

Computed is a signal that computes its value based on other signals.

import { computed } from 'agera'

const $firstName = signal('John')
const $lastName = signal('Doe')
const $fullName = computed(() => `${$firstName()} ${$lastName()}`)

console.log($fullName()) // John Doe

effectScope

effectScope creates a scope for effects. It allows to stop all effects in the scope at once.

import { signal, effectScope, effect } from 'agera'

const $a = signal(0)
const $b = signal(0)
const stop = effectScope(() => {
  effect(() => {
    console.log('A:', $a())
  })

  effectScope(() => {
    effect(() => {
      console.log('B:', $b())
    })
  })
})

stop() // stop all effects

Also there is a possibility to create a lazy scope.

import { signal, effectScope, effect } from 'agera'

const $a = signal(0)
const $b = signal(0)
// All scopes will run immediately, but effects run is delayed
const start = effectScope(() => {
  effect(() => {
    console.log('A:', $a())
  })

  effectScope(() => {
    effect(() => {
      console.log('B:', $b())
    })
  })
}, true) // marks scope as lazy
// start all effects
const stop = start()

stop() // stop all effects

Lifecycles

One of main feature of Agera is that you can create mountable signals. It allows to create lazy signals, which will use resources only if signal is really used in the UI.

  • Signal is mounted when one or more effects is attached to it.
  • Signal is unmounted when signal has no effects.

mountable method makes signal mountable.

onMounted lifecycle method adds callback for mount and unmount events.

import { signal, mountable, onMounted, effect } from 'agera'

const $count = mountable(signal(0))

onMounted($count, (mounted) => {
  console.log('Signal is', mounted ? 'mounted' : 'unmounted')
})

// will mount signal
const stop = effect(() => {
  console.log('Count:', $count())
})
// will unmount signal
stop()

Batch updates

To batch updates you should wrap signal updates between startBatch and endBatch.

import { signal, startBatch, endBatch, effect } from 'agera'

const $a = signal(0)
const $b = signal(0)

effect(() => {
  console.log('Sum:', $a() + $b())
})

// Effects will be called only once
startBatch()
$a(1)
$b(2)
endBatch()

Skip tracking

To skip tracking of signal changes you should wrap signal into untracked function.

import { signal, untracked, effect } from 'agera'

const $a = signal(0)
const $b = signal(0)

effect(() => {
  const a = $a()

  untracked(() => {
    const b = $b()

    resumeTracking()

    console.log('Sum:', a + b)
  })
})
// or short variant
effect(() => {
  console.log('Sum:', $a() + untracked($b))
})

// Will trigger effect run
$a(1)

// Will not trigger effect run
$b(2)

Morph

morph methods allows to create signals that can change their getter and setter on the fly.

import { signal, morph, $$get, $$set, $$source } from 'agera'

const $string = signal('')
// Debounce signal updates
const $debouncedString = morph($string, {
  [$$set]: debounce($string, 300)
})
// Lazy initialization
const $lazyString = morph($string, {
  [$$get]() {
    this[$$set]('Lazy string')
    this[$$get] = this[$$source]
    return 'Lazy string'
  }
})

isSignal

isSignal method checks if the value is a signal.

import { isSignal, signal } from 'agera'

isSignal(signal(1)) // true

Why?

Key differences from alien-signals:

  • Tree-shaking. Agera is designed to be tree-shakable. Only the code you use is included in your bundle. Alien-signals is not well tree-shakable.
  • Size. Agera has a little bit smaller size for basic methods than alien-signals.
  • Lifecycles. Agera has lifecycles for signals. You can listen to signal activation and deactivation events.
  • Modificated effectScope. Agera has a possibility to put effect scope inside another effect scope. Also there is a possibility to create a lazy scope.
  • Effects supports cleanup function.