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

interactiveflow

v1.0.0

Published

Streamline your Discord UI with declarative Containers & Stateful Pagination.

Readme


✨ Features

  • 🧱 Declarative Container Builder — Fluent, chainable API wrapping ContainerBuilder for clean, readable layouts.
  • 📄 Stateful Pagination Engine — Generic FlowPaginator<T> that handles collectors, timeouts, and navigation automatically.
  • 🔒 Fully Type-Safe — Written in strict TypeScript with comprehensive JSDoc coverage on every public member.
  • 📦 Dual Output — Ships ESM and CJS bundles via tsup with full declaration files.
  • ⚡ Validation Built-In — Checks Discord's component limits at build time with descriptive FlowError messages.
  • 🎯 Zero Config Pagination — Just provide your data, a render function, and call send(). Everything else is handled.

📦 Installation

npm install interactiveflow
# or with your preferred package manager
yarn add interactiveflow
pnpm add interactiveflow

Peer Dependency: Requires discord.js v14 or higher.


🚀 Quick Start

Building a Static Container

Create a Components V2 container in just a few lines:

import { FlowContainer } from "interactiveflow";
import { ButtonBuilder, ButtonStyle, MessageFlags } from "discord.js";

const card = new FlowContainer({ accentColor: 0x5865f2 })
  .addTitle("# 📋 Server Info")
  .addSeparator()
  .addDescription("Welcome to the server! Here's what we offer.")
  .addSection({
    content: "🔗 **Website**\nCheck out our homepage for updates.",
    buttonAccessory: new ButtonBuilder()
      .setLabel("Visit")
      .setStyle(ButtonStyle.Link)
      .setURL("https://example.com"),
  });

await interaction.reply({
  components: [card.toBuilder()],
  flags: MessageFlags.IsComponentsV2,
});

Paginated Lists

Turn any array into a navigable, paginated view with one class:

import { FlowContainer, FlowPaginator } from "interactiveflow";

const users = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Frank", "Grace"];

const paginator = new FlowPaginator<string>({
  data: users,
  pageSize: 3,
  idleTimeout: 30_000,
  render: (items, pageIndex, totalPages) => {
    const list = items
      .map((name, i) => `**${pageIndex * 3 + i + 1}.** ${name}`)
      .join("\n");

    return new FlowContainer({ accentColor: 0x57f287 })
      .addTitle("# 👥 User Directory")
      .addSeparator()
      .addDescription(list);
  },
});

await paginator.send(interaction);

The paginator automatically handles:

  • Previous / Page X/Y / Next ▶ navigation buttons
  • Filtering interactions to the original user
  • Disabling buttons and cleaning up after the idle timeout

📖 API Reference

FlowContainer

A declarative wrapper around Discord.js ContainerBuilder.

Constructor

new FlowContainer(options?: FlowContainerOptions)

| Option | Type | Description | |---|---|---| | accentColor | number | Accent color for the container sidebar. | | spoiler | boolean | Whether to render as a spoiler. |

Methods

| Method | Returns | Description | |---|---|---| | .addTitle(text) | this | Add a title text display (supports markdown). | | .addDescription(text) | this | Add a description text display. | | .addSeparator(options?) | this | Add a separator. Options: { divider?: boolean, spacing?: "small" \| "large" } | | .addSection(options) | this | Add a section with text + an optional buttonAccessory or thumbnailAccessory. | | .addActionRow(...components) | this | Add an action row with interactive components. | | .addComponent(component) | this | Escape hatch — add any raw discord.js container component. | | .setAccentColor(color) | this | Set the container accent color. | | .setSpoiler(spoiler) | this | Toggle the spoiler flag. | | .getComponentCount() | number | Current number of top-level components. | | .getRemainingCapacity() | number | Remaining slots before Discord's 10-component limit. | | .toBuilder() | ContainerBuilder | Access the underlying discord.js builder. | | .build() | APIContainerComponent | Serialize to API-ready JSON. |

All mutating methods return this for chaining.


FlowPaginator<T>

A generic, stateful pagination engine.

Constructor

new FlowPaginator<T>(options: FlowPaginatorOptions<T>)

| Option | Type | Default | Description | |---|---|---|---| | data | T[] | — | The full dataset to paginate. | | pageSize | number | 5 | Items per page. | | render | FlowPageRenderer<T> | — | Function receiving (items, pageIndex, totalPages)FlowContainer. | | idleTimeout | number | 60000 | Collector idle timeout in ms. |

Methods & Properties

| Member | Type | Description | |---|---|---| | .totalPages | number | Total number of pages (getter). | | .getState() | PaginatorState | Snapshot: { currentPage, totalPages, active }. | | .getPageData() | T[] | Data slice for the current page. | | .renderPage(disabled?) | object | Render current page with nav buttons. | | .send(target) | Promise<Message> | Send to a channel or reply to an interaction. Starts the collector. | | .stop() | void | Manually stop the collector and disable buttons. |


FlowError

Custom error class with a code property for structured error handling.

try {
  container.addTitle("...");
} catch (error) {
  if (error instanceof FlowError && error.code === "COMPONENT_LIMIT") {
    console.log("Too many components!");
  }
}

| Error Code | Source | Description | |---|---|---| | COMPONENT_LIMIT | FlowContainer | Container exceeds 10 components. | | INVALID_SECTION | FlowContainer | Section has both button + thumbnail accessory. | | EMPTY_DATA | FlowPaginator | Data array is empty. | | INVALID_PAGE_SIZE | FlowPaginator | Page size is less than 1. | | INVALID_TARGET | FlowPaginator | Unsupported send target. |


Constants

| Constant | Value | Description | |---|---|---| | MAX_CONTAINER_COMPONENTS | 10 | Max top-level components per container. | | MAX_SECTION_TEXT_COMPONENTS | 3 | Max text items in a section. | | MAX_ACTION_ROW_COMPONENTS | 5 | Max items in an action row. | | DEFAULT_PAGE_SIZE | 5 | Default items per page. | | DEFAULT_IDLE_TIMEOUT | 60000 | Default idle timeout (ms). |


📂 Examples

See the examples/ directory for complete, runnable demos:


🛠️ Development

# Install dependencies
npm install

# Build (ESM + CJS)
npm run build

# Watch mode
npm run dev

# Type-check
npm run lint

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide and Code of Conduct before getting started.


👤 Credits

Built and maintained by rly-dev.


📄 License

This project is licensed under the GNU General Public License v3.0.