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

afrojack

v1.1.2

Published

A unique, minimal React state management library with middleware and AI integration.

Readme

🧠 AfroJack

AfroJack is a fast, simple, and powerful React state management library written from scratch. No Redux, no external dependencies — just clean, minimal code built for modern React apps.

Created with ❤️ by Sam Paniagua — reach me at [email protected]


✨ Features

  • 🧩 Global Store — with getState, setState, and subscribe.
  • Zero Redux — no affiliation, no boilerplate, no magic.
  • 🔧 Middleware Support — easily add logging, error handling, analytics, etc.
  • 🧠 Smart Selectors — prevent re-renders using shallow equality.
  • 🔁 Optional Actions — action-based state updates for bigger apps.
  • 🔬 DevTools Friendly — optional integration with Redux DevTools for debugging.
  • 🤖 AI-Ready Agents — built-in agent middleware for async/AI task handling (OpenAI, workers, bots).

📦 Installation

npm install afrojack

🚀 Getting Started

1. Create Your Store

// store.js
import {
  createStore,
  applyMiddleware,
  loggerMiddleware,
  errorMiddleware,
  agentMiddleware,
} from 'afrojack';

const middlewares = applyMiddleware(
  loggerMiddleware,
  errorMiddleware,
  agentMiddleware
);

export const store = createStore(
  {
    user: null,
    theme: 'dark',
    loading: false,
    data: null,
    error: null,
  },
  middlewares
);

2. Use in a React Component

import React, { useRef } from 'react';
import { store } from './store';
import { useAfroJackSelector, useAfroJackDispatch } from 'afrojack';

export function App() {
  const storeRef = useRef(store);
  const theme = useAfroJackSelector(storeRef, (state) => state.theme);
  const dispatch = useAfroJackDispatch(storeRef);

  const toggleTheme = () => {
    dispatch({ type: 'TOGGLE_THEME' });
  };

  return (
    <div style={{ background: theme === 'dark' ? '#111' : '#fff', color: theme === 'dark' ? '#fff' : '#111' }}>
      <h1>AfroJack Demo</h1>
      <p>Current Theme: {theme}</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

🔧 Middleware

Logger Middleware

export const loggerMiddleware = ({ getState }) => next => update => {
  console.group('AfroJack Update');
  console.log('Prev State:', getState());
  console.log('Update:', update);
  next(update);
  console.log('Next State:', getState());
  console.groupEnd();
};

Error Handling Middleware

export const errorMiddleware = () => next => update => {
  try {
    next(update);
  } catch (err) {
    console.error('AfroJack state error:', err);
  }
};

🤖 AI Agent Middleware (Built-in)

AfroJack supports async agents for tasks like fetching from AI APIs (e.g. OpenAI, LangChain) or performing side-effect-based work.

Register an Agent

store.setState({
  type: 'REGISTER_AGENT',
  payload: {
    name: 'fetchUserProfile',
    handler: async ({ getState }) => {
      const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
      return await res.json();
    }
  }
});

Trigger the Agent

store.setState({
  type: 'AGENT_TRIGGER',
  payload: {
    name: 'fetchUserProfile',
    onSuccess: (result) => ({ user: result, loading: false }),
    onError: (error) => ({ error: error.message, loading: false }),
  }
});

This pattern lets you fire async operations declaratively and apply their results straight into your state — ideal for integrating OpenAI, AI assistants, background workers, etc.


🧪 Selector Example

const user = useAfroJackSelector(storeRef, state => state.user);

Only triggers re-render when user slice of state changes (uses shallow comparison by default).


📤 Optional Action-Based Dispatch

const dispatch = useAfroJackDispatch(storeRef);

dispatch({ type: 'SET_USER', payload: { name: 'Alice' } });
dispatch({ type: 'TOGGLE_THEME' });

Your app stays clean and logic remains reusable.


🧠 Philosophy

AfroJack is not Redux, and that's the point.

  • No context wrapping required.
  • No reducers, thunks, or saga trees.
  • Just your state, your way — enhanced with smart tools when you want them.

🔌 DevTools Integration (Optional)

You can optionally hook into Redux DevTools:

const devtools =
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();

const devtoolsMiddleware = (devtools) => ({ getState }) => next => (update) => {
  next(update);
  devtools.send('state_update', getState());
};

export const store = createStore(initialState, [
  loggerMiddleware,
  errorMiddleware,
  devtoolsMiddleware(devtools)
].filter(Boolean));

🛠 API Summary

createStore(initialState, middlewares?)

Creates a store with initial state and optional middlewares.

setState(update)

Updates the state directly or via updater function.

getState()

Retrieves the current state.

subscribe(callback)

Subscribes to changes and returns an unsubscribe function.


🪪 License

MIT © Sam Paniagua


🙌 Contributing

Pull requests and suggestions welcome! Open an issue or shoot me an email at [email protected]


AfroJack — Modern State. Made Simple.