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

fluxcord

v0.1.0

Published

Session-based Components V2 UI framework for Discord bots: flows, screens, TSX views.

Readme

CI npm npm downloads License Node

TypeScript discord.js GitHub issues last commit

Sponsor

Stateful, multi-screen Discord UIs in TSX. Built on discord.js v14 (Components V2).

A screen is a plain function of state: when a click changes that state through a handler you wrote, the framework re-renders the screen and edits the message, so you never touch edits or component ids yourself. fluxcord was extracted from a production Discord bot, where it runs every admin panel today.

A taco order panel: building an order, checking out, and starting a new one

Features

  • Every mounted panel becomes a session that owns its state. Clicks on one panel run one at a time through a FIFO queue, so handlers never race each other, and idle sessions are swept on an interval.
  • Flows carry as many screens as you want, and navigation targets such as ui.go('history') are checked against the screens map at compile time.
  • Screens are authored in TSX through a custom JSX runtime, or with plain builder functions, and both compile to the same trees.
  • Buttons bind to handler functions by identity, so there are no custom-id strings to parse, and every committed change re-renders the screen and edits the message.
  • Permission gates are declared on a flow or on a single control, and the policy port you wire at boot decides every click.
  • An optional rehydrate store lets open panels survive a restart.
  • The core entry is platform-free; the discord.js binding lives behind a peer-dependent fluxcord/discord entry.

Requirements

  • Node 22 or newer
  • discord.js 14.25 or newer, installed as a peer
  • TypeScript 5 or newer, for TSX authoring

Install

npm install fluxcord discord.js

For TSX authoring, point jsxImportSource at the package:

{
	"compilerOptions": {
		"jsx": "react-jsx",
		"jsxImportSource": "fluxcord",
		"module": "Node16",
		"moduleResolution": "Node16"
	}
}

Example

A counter written as a flow:

import { action, screen, flow } from 'fluxcord';

interface CounterData {
	count: number;
}

const plus = action<CounterData>()((event) => {
	event.mutate((data) => {
		data.count += 1;
	});
});

const minus = action<CounterData>()((event) => {
	event.mutate((data) => {
		data.count -= 1;
	});
});

const counterScreen = screen<CounterData>()((data, { Button }) => (
	<view>
		<text>Count: {data.count}</text>
		<row>
			<Button onClick={minus} label="-1" secondary />
			<Button onClick={plus} label="+1" />
		</row>
	</view>
));

export const counterFlow = flow<CounterData>('counter', {
	screens: { main: counterScreen },
	first: 'main',
	initialData: { count: 0 },
});

Here the two action functions are the entire click surface: a click runs one of them, event.mutate applies the change, and the framework handles the re-render and the message edit. Buttons bind to handlers by identity instead of through id strings, so there is nothing to parse and nothing that can drift out of sync, and the state lives in a session the framework tracks rather than in a Map you babysit.

Documentation

You'll find full documentation in docs/. The guide walks you from an empty folder to a running bot; since it is written directly from the example bot in examples/, every snippet comes from code that actually builds and runs.

Contributing

fluxcord is young and maintained by one person. Bug reports with a minimal reproduction are the most useful thing right now. Before filing one, check KNOWN_ISSUES.md in case it is already on the list. For anything larger, open an issue first so the scope can settle before code arrives.

Roadmap

Version goals and their checkboxes live in ROADMAP.md, and notable changes are tracked in CHANGELOG.md.


Released under the MIT license.

Support the project on GitHub Sponsors.