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

@forgedevstack/synapse

v1.0.0

Published

Synapse - Ultra-simple state management for React. No dispatch, no reducers, just signals.

Downloads

99

Readme

🐙 Synapse

Ultra-simple state management for React. No dispatch, no reducers, just signals.

npm version bundle size license

Why Synapse?

State management shouldn't be complicated. Synapse makes it as simple as:

// Create your state
const counterNucleus = createNucleus((set) => ({
  count: 0,
  increment: () => set((s) => ({ count: s.count + 1 })),
  decrement: () => set((s) => ({ count: s.count - 1 })),
}));

// Use in components
function Counter() {
  const { count, increment, decrement } = useNucleus(counterNucleus);
  return <button onClick={increment}>{count}</button>;
}

No dispatch. No reducers. No selectors. No boilerplate.

Features

  • Ultra-simple API - Create state in seconds
  • Tiny bundle - < 2KB gzipped
  • Fast - Minimal re-renders with fine-grained subscriptions
  • DevTools - Chrome/Safari extension for debugging
  • TypeScript - Full type safety out of the box
  • Middleware - Logger, persist, immer-like updates
  • API integration - Built-in hooks for data fetching
  • Time travel - Debug with state history
  • React 16.8+ - Works with all modern React versions

Installation

npm i @forgedevstack/synapse
# or
yarn add @forgedevstack/synapse
# or
pnpm add @forgedevstack/synapse

Quick Start

1. Create a Nucleus (State Container)

import { createNucleus } from '@forgedevstack/synapse';

interface UserState {
  user: { name: string; email: string } | null;
  loading: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

export const userNucleus = createNucleus<UserState>((set) => ({
  user: null,
  loading: false,
  
  login: async (email, password) => {
    set({ loading: true });
    const user = await api.login(email, password);
    set({ user, loading: false });
  },
  
  logout: () => set({ user: null }),
}));

2. Use in Components

import { useNucleus, usePick } from '@forgedevstack/synapse';
import { userNucleus } from './state/user';

// Use entire state
function UserProfile() {
  const { user, logout } = useNucleus(userNucleus);
  
  if (!user) return <LoginForm />;
  
  return (
    <div>
      <h1>Welcome, {user.name}!</h1>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

// Or pick specific values (optimized re-renders)
function UserName() {
  const name = usePick(userNucleus, (s) => s.user?.name);
  return <span>{name}</span>;
}

Core Concepts

Nucleus vs Store

In Synapse, we use Nucleus instead of "store". A nucleus is the core of your state - it holds the state and provides methods to update it.

| Redux/Zustand | Synapse | |--------------|---------| | store | nucleus | | dispatch(action) | set({ ... }) | | useSelector() | usePick() | | createStore() | createNucleus() |

Signals (Reactive Primitives)

For simpler state, use signals:

import { signal, useSignal } from '@forgedevstack/synapse';

// Create a signal
const count = signal(0);

// Use in component
function Counter() {
  const value = useSignal(count);
  return (
    <button onClick={() => count.set((v) => v + 1)}>
      {value}
    </button>
  );
}

Computed Values

Derive values from signals:

import { signal, computed, useComputed } from '@forgedevstack/synapse';

const firstName = signal('John');
const lastName = signal('Doe');

const fullName = computed(() => 
  `${firstName.value} ${lastName.value}`
);

function Name() {
  const name = useComputed(fullName);
  return <h1>{name}</h1>;
}

Middleware

Logger

import { createNucleus } from '@forgedevstack/synapse';
import { logger } from '@forgedevstack/synapse/middleware';

const myNucleus = createNucleus(
  (set) => ({ count: 0 }),
  { 
    middleware: [
      logger({ diff: true, timestamp: true })
    ] 
  }
);

Persist

import { persist } from '@forgedevstack/synapse/middleware';

const userNucleus = createNucleus(
  (set) => ({
    name: '',
    email: '',
    preferences: { theme: 'dark' },
  }),
  {
    middleware: [
      persist({
        key: 'user-state',
        storage: 'local', // 'local' | 'session' | custom
        include: ['preferences'], // Only persist preferences
      })
    ]
  }
);

Immer-like Updates

import { immer } from '@forgedevstack/synapse/middleware';

const todosNucleus = createNucleus(
  (set) => ({
    todos: [{ id: 1, text: 'Learn Synapse', done: false }],
    
    toggle: (id: number) => set((draft) => {
      // Looks mutable, works immutably!
      const todo = draft.todos.find(t => t.id === id);
      if (todo) todo.done = !todo.done;
    }),
  }),
  { middleware: [immer()] }
);

API Hooks

useQuery

import { useQuery } from '@forgedevstack/synapse';

function UserList() {
  const { data, loading, error, refetch } = useQuery(
    () => fetch('/api/users').then(r => r.json()),
    { refetchOnFocus: true }
  );
  
  if (loading) return <Spinner />;
  if (error) return <Error message={error.message} />;
  
  return (
    <ul>
      {data?.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

useMutation

import { useMutation } from '@forgedevstack/synapse';

function CreateUser() {
  const { mutate, loading } = useMutation(
    (data) => fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(data),
    }).then(r => r.json()),
    {
      onSuccess: (user) => navigate(`/users/${user.id}`),
    }
  );
  
  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      mutate({ name: e.target.name.value });
    }}>
      <input name="name" />
      <button disabled={loading}>Create</button>
    </form>
  );
}

DevTools

Install the Synapse DevTools browser extension to:

  • Inspect all nuclei in your app
  • Time-travel through state history
  • Export/import state for debugging
  • Reset state to initial values

Download for Chrome | Download for Safari

Configuration

Synapse Config

import { createNucleus, type SynapseConfig } from '@forgedevstack/synapse';

const config: SynapseConfig = {
  // Action naming convention
  actionNaming: 'camelCase', // 'camelCase' | 'PascalCase' | 'snake_case' | 'SCREAMING_SNAKE_CASE'
  
  // DevTools (auto-enabled in development)
  devtools: true,
  devtoolsName: 'MyApp',
  
  // Enable action logging
  logging: process.env.NODE_ENV === 'development',
  
  // Persist state
  persist: {
    key: 'app-state',
    storage: 'local',
  },
};

const appNucleus = createNucleus((set) => ({
  // state...
}), config);

TypeScript

Synapse is written in TypeScript and provides excellent type inference:

interface Todo {
  id: number;
  text: string;
  done: boolean;
}

interface TodosState {
  todos: Todo[];
  filter: 'all' | 'active' | 'done';
  addTodo: (text: string) => void;
  toggleTodo: (id: number) => void;
  setFilter: (filter: 'all' | 'active' | 'done') => void;
}

const todosNucleus = createNucleus<TodosState>((set) => ({
  todos: [],
  filter: 'all',
  
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: Date.now(), text, done: false }],
  })),
  
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map(t => 
      t.id === id ? { ...t, done: !t.done } : t
    ),
  })),
  
  setFilter: (filter) => set({ filter }),
}));

API Reference

Core

| Function | Description | |----------|-------------| | createNucleus(initializer, config?) | Create a new nucleus | | signal(initialValue) | Create a reactive signal | | computed(computeFn) | Create a derived signal | | batch(fn) | Batch multiple updates | | effect(fn) | Run side effects on signal changes |

Hooks

| Hook | Description | |------|-------------| | useNucleus(nucleus) | Use entire nucleus state | | usePick(nucleus, selector) | Use selected state slice | | useNuclei([...nuclei]) | Use multiple nuclei | | useSignal(signal) | Use signal value | | useComputed(computed) | Use computed value | | useQuery(fetcher, options?) | Fetch data with state | | useMutation(mutationFn, options?) | Handle mutations | | useSubscribe(nucleus, callback) | Subscribe to changes | | useSnapshot(nucleus) | Get state without subscribing |

Middleware

| Middleware | Description | |------------|-------------| | logger(options?) | Log state changes | | persist(options) | Persist state to storage | | immer() | Enable mutable-style updates |

Comparison

| Feature | Synapse | Redux | Zustand | Jotai | |---------|---------|-------|---------|-------| | Bundle size | ~2KB | ~7KB | ~1KB | ~3KB | | Boilerplate | Minimal | Heavy | Low | Low | | TypeScript | Native | Needs setup | Good | Good | | DevTools | Built-in | Extension | Extension | Extension | | Async actions | Native | Middleware | Native | Native | | Learning curve | Easy | Steep | Easy | Medium |

License

MIT © John Yaghobieh


Part of the ForgeStack ecosystem.