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

@sitnikov/connection-broker

v0.1.1

Published

Generic connection broker for routing messages between clients

Readme

@sitnikov/connection-broker

Generic connection broker that enables ANY two parties to communicate when they can't reach each other directly.

Overview

The connection broker is a completely reusable, domain-agnostic WebSocket server that routes messages between clients. It knows nothing about browsers, MCP, or any specific use case - it just manages connections, channels, and message routing.

Key Concepts

  • Connections: Clients connect to the broker and register with a "role" (arbitrary string)
  • Roles: Used to discover connections (e.g., list all connections with role "browser-tab")
  • Channels: Ephemeral pseudo-connections between two clients
  • Messages: Opaque payloads routed between channels

Protocol Flow

  1. Client connects → declares a role → gets assigned a UUID
  2. Any client can list all connections by role (returns UUIDs only)
  3. Any client can open a channel (pseudo-connection) to another client by UUID
  4. Both ends of channel can send messages to each other (with confirmation)
  5. Either end can close the channel

ID Types

  • Connection IDs: UUID (persistent per client)
  • Channel IDs: UUID (persistent per channel)
  • Message IDs: Auto-increment integers (unique per message, used for request/response tracking)

Installation

npm install @sitnikov/connection-broker

Usage

Starting the Broker Server

connection-broker --port 3004

Or programmatically:

import { ConnectionBroker } from '@sitnikov/connection-broker'

const broker = new ConnectionBroker(3004)
// Broker is now running on port 3004

Using the Client SDK

import { BrokerClient } from '@sitnikov/connection-broker/client'

// Connect to broker with a role
const client = new BrokerClient('ws://localhost:3004')
await client.connect('my-role')

console.log('My ID:', client.getMyId())

// Optional: Pass a logger for debugging
import { Logger } from './Logger'
const logger = new Logger('/path/to/log.txt')
const clientWithLogger = new BrokerClient('ws://localhost:3004', logger)
await clientWithLogger.connect('my-role')

// Discover connections by role
const ids = await client.listByRole('other-role')
console.log('Found connections:', ids)

// Open a channel to a specific connection
const channel = await client.openChannel(targetId)

// Send messages (returns promise that resolves when broker confirms delivery)
await channel.send({ type: 'greeting', message: 'Hello!' })

// Listen for messages
channel.onMessage = (payload) => {
  console.log('Received:', payload)
  channel.send({ type: 'response', message: 'Got it!' })
}

// Listen for channel close
channel.onClosed = () => {
  console.log('Channel closed')
}

// Close the channel
channel.close()

// Listen for incoming channels
client.onIncomingChannel = (channel) => {
  console.log('Incoming channel from:', channel.getPeerId())

  channel.onMessage = (payload) => {
    console.log('Received:', payload)
  }
}

// Disconnect from broker
client.disconnect()

Example Use Cases

Browser Automation

  • Browser tabs connect with role "browser-tab"
  • MCP server connects with role "mcp-server"
  • MCP server lists tabs, opens channels, sends commands
  • Tabs execute commands and send back results

Chat Application

  • Users connect with role "user"
  • Server connects with role "chat-server"
  • Server can list all users and route messages between them

Remote Procedure Calls

  • Service A connects with role "service-a"
  • Service B connects with role "service-b"
  • Services can discover each other and exchange RPC requests/responses

Protocol Reference

All messages include:

  • id: Auto-increment integer (unique message ID)
  • replyTo: Integer (optional, references request message ID for responses)

Client → Broker Messages

Register

{
  "type": "register",
  "id": 1,
  "role": "my-role"
}

Response (success):

{
  "type": "registered",
  "id": 2,
  "replyTo": 1,
  "connectionId": "connection-uuid"
}

Response (failure):

{
  "type": "register_failed",
  "id": 2,
  "replyTo": 1,
  "error": "Error message"
}

List by Role

{
  "type": "list_by_role",
  "id": 3,
  "role": "other-role"
}

Response (success):

{
  "type": "connections",
  "id": 4,
  "replyTo": 3,
  "ids": ["uuid-1", "uuid-2", "uuid-3"]
}

Response (failure):

{
  "type": "list_by_role_failed",
  "id": 4,
  "replyTo": 3,
  "error": "Error message"
}

Open Channel

{
  "type": "open",
  "id": 5,
  "targetId": "connection-uuid"
}

Response to opener (success):

{
  "type": "channel_opened",
  "id": 6,
  "replyTo": 5,
  "channelId": "channel-uuid",
  "targetId": "connection-uuid"
}

Notification to target (unsolicited):

{
  "type": "incoming_channel",
  "id": 7,
  "from": "connection-uuid",
  "channelId": "channel-uuid"
}

Response (failure):

{
  "type": "channel_open_failed",
  "id": 6,
  "replyTo": 5,
  "targetId": "connection-uuid",
  "error": "Target connection not found"
}

Send Message on Channel

{
  "type": "message",
  "id": 8,
  "channelId": "channel-uuid",
  "payload": { "any": "data" }
}

Notification to recipient (unsolicited):

{
  "type": "channel_message",
  "id": 9,
  "channelId": "channel-uuid",
  "payload": { "any": "data" }
}

Response to sender (success):

{
  "type": "channel_message_sent",
  "id": 10,
  "replyTo": 8,
  "channelId": "channel-uuid"
}

Response (failure):

{
  "type": "channel_message_failed",
  "id": 10,
  "replyTo": 8,
  "channelId": "channel-uuid",
  "error": "Channel not found"
}

Close Channel

{
  "type": "close",
  "id": 11,
  "channelId": "channel-uuid"
}

Response to closer (success):

{
  "type": "channel_closed",
  "id": 12,
  "replyTo": 11,
  "channelId": "channel-uuid"
}

Notification to other party (unsolicited):

{
  "type": "channel_closed_notification",
  "id": 13,
  "channelId": "channel-uuid"
}

Response (failure):

{
  "type": "channel_close_failed",
  "id": 12,
  "replyTo": 11,
  "channelId": "channel-uuid",
  "error": "Channel not found"
}

Message Flow Patterns

Request-Response (expects reply):

  • registerregistered or register_failed
  • list_by_roleconnections or list_by_role_failed
  • openchannel_opened or channel_open_failed
  • messagechannel_message_sent or channel_message_failed
  • closechannel_closed or channel_close_failed

Unsolicited Notifications (no replyTo):

  • incoming_channel - Notifies target about new channel
  • channel_message - Notifies recipient about message
  • channel_closed_notification - Notifies other party about closure

Architecture

The broker is designed with these principles:

  1. Role-agnostic: Roles are just strings, no validation or special handling
  2. Payload-agnostic: Messages are opaque, broker doesn't inspect them
  3. Stateless channels: No persistent state beyond active connections and channels
  4. Simple ID system:
    • Connection IDs & Channel IDs: UUIDs (persistent identifiers)
    • Message IDs: Auto-increment integers (for request/response tracking)
  5. Generic routing: Routes messages between parties without understanding content
  6. Request-Response Pattern: All operations (register, list, open, send, close) get explicit success or failure responses
  7. Unsolicited Notifications: Events like incoming channels, messages, and closures are pushed to clients without replyTo

License

MIT