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

@supaproxy/consumers

v0.4.1

Published

Plugin package for SupaProxy consumer types

Readme

@supaproxy/consumers

npm version license

Plugin package for SupaProxy consumer types. Consumers are the channels through which users interact with SupaProxy -- Slack, REST API, WhatsApp, and more.

Each consumer is a self-contained plugin that handles inbound messages, outbound replies, and channel binding. The dashboard auto-discovers consumers via the plugin registry.

Installation

npm install @supaproxy/consumers

Peer dependencies

Some plugins require optional peer dependencies:

# For the Slack consumer
npm install @slack/bolt

Quick start

import { registry } from '@supaproxy/consumers'

// All built-in plugins are auto-registered on import.

// List available consumer types
const plugins = registry.list()
console.log(registry.types()) // ['slack', 'api']

// Get a specific plugin
const slack = registry.get('slack')

// Get config schemas for dashboard form rendering
const schemas = registry.schemas()

// Start a consumer
await slack.start(
  {
    onMessage: async (msg) => {
      // Handle incoming message, return agent response
      return { answer: 'Hello!', conversationId: '123' }
    },
    onError: (err) => console.error(err),
    logger: pinoLogger,
    getWorkspaceForChannel: async (channelId) => {
      return { id: 'ws_1', name: 'My Workspace' }
    },
  },
  { SLACK_BOT_TOKEN: 'xoxb-...', SLACK_APP_TOKEN: 'xapp-...' }
)

// Send an outbound message
await slack.sendMessage('#general', 'Proactive notification', 'thread_ts')

// Stop the consumer
await slack.stop()

API reference

ConsumerPlugin

The interface every consumer type must implement.

interface ConsumerPlugin {
  readonly type: string          // Unique identifier: 'slack', 'api', etc.
  readonly name: string          // Human-readable name
  readonly description: string   // Short description for the dashboard
  readonly configSchema: ConfigSchema

  validateCredentials(config: Record<string, string>): Promise<ValidationResult>
  start(ctx: ConsumerContext, config: Record<string, string>): Promise<void>
  stop(): Promise<void>
  bindChannel(config: ChannelBindConfig): Promise<{ ok: boolean; error?: string }>
  sendMessage(channel: string, message: string, threadId?: string): Promise<void>
}

ConsumerContext

The context provided to consumers by the host server.

interface ConsumerContext {
  onMessage: (msg: IncomingMessage) => Promise<AgentResponse>
  onError: (error: Error) => void
  logger: Logger
  getWorkspaceForChannel: (channelId: string) => Promise<Workspace | null>
}

IncomingMessage

interface IncomingMessage {
  query: string
  channel: string
  userId: string
  userName: string
  threadId: string
  consumerType: string
}

ConfigSchema

Drives dynamic form rendering in the dashboard. Each field specifies its type, label, placeholder, and validation requirements.

interface ConfigSchema {
  fields: ConfigField[]
}

interface ConfigField {
  name: string
  label: string
  type: 'text' | 'password' | 'select' | 'textarea'
  required: boolean
  placeholder?: string
  helpText?: string
  options?: string[]    // For 'select' type
}

ValidationResult

interface ValidationResult {
  ok: boolean
  detail?: Record<string, string>
  error?: string
}

Registry methods

| Method | Returns | Description | |--------|---------|-------------| | registry.list() | ConsumerPlugin[] | All registered plugins | | registry.get(type) | ConsumerPlugin | Get plugin by type (throws if not found) | | registry.has(type) | boolean | Check if a plugin type is registered | | registry.types() | string[] | List all registered type identifiers | | registry.schemas() | Array<{type, name, description, configSchema}> | Config schemas for dashboard forms | | registry.register(plugin) | void | Register a custom plugin |

Available plugins

| Plugin | Type | Description | |--------|------|-------------| | Slack | slack | Slack integration via Socket Mode. Receives messages from Slack channels and threads, sends replies back. Requires @slack/bolt peer dependency. | | API | api | REST API consumer. Exposes an HTTP endpoint for programmatic access to SupaProxy conversations. |

Adding a new consumer plugin

Adding a new consumer type is a one-file change. Create a file that implements ConsumerPlugin:

import type { ConsumerPlugin, ConsumerContext, ValidationResult } from '@supaproxy/consumers'

export const myPlugin: ConsumerPlugin = {
  type: 'my-consumer',
  name: 'My Consumer',
  description: 'A custom consumer channel',
  configSchema: {
    fields: [
      { name: 'API_KEY', label: 'API Key', type: 'password', required: true },
    ],
  },

  async validateCredentials(config) {
    // Validate the provided credentials
    return { ok: true }
  },

  async start(ctx, config) {
    // Connect to the external service
    // Call ctx.onMessage() when a message arrives
  },

  async stop() {
    // Disconnect cleanly
  },

  async bindChannel(config) {
    // Bind a channel to a workspace
    return { ok: true }
  },

  async sendMessage(channel, message, threadId) {
    // Send an outbound message
  },
}

Then register it:

import { registry } from '@supaproxy/consumers'
import { myPlugin } from './my-plugin.js'

registry.register(myPlugin)

Contributing

See the SupaProxy contributing guide for development workflow, code standards, and PR process.

Documentation

Full documentation at docs.supaproxy.cloud.

License

MIT