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

@aionbuilders/helios-protocol

v1.1.0

Published

Core protocol implementation for Helios - a lightweight, runtime-agnostic WebSocket messaging protocol with request/response and pub/sub patterns

Readme

@aionbuilders/helios-protocol

Core protocol implementation for Helios - a lightweight, runtime-agnostic WebSocket messaging protocol

npm version License: MIT

Features

  • 🚀 Lightweight - Zero runtime dependencies, pure JavaScript
  • 🔄 Request/Response Pattern - RPC-style async request/response with timeout support
  • 📡 Pub/Sub Events - Topic-based event system with wildcard matching
  • 🎯 Type-Safe - Full TypeScript definitions with JSDoc annotations
  • Runtime Agnostic - Works with Bun, Node.js, Deno, and browsers
  • 🔒 Validation - Built-in message validation with detailed error reporting
  • 🧪 Well Tested - 245+ test cases covering all core functionality

Installation

# Using npm
npm install @aionbuilders/helios-protocol

# Using bun
bun add @aionbuilders/helios-protocol

# Using yarn
yarn add @aionbuilders/helios-protocol

Quick Start

import { Request, Event, Parser, Serializer } from '@aionbuilders/helios-protocol';

// Create a request
const request = Request.outgoing(
  { userId: 123 },
  { method: 'user.get', timeout: 5000 }
);

// Serialize for transport
const serialized = Serializer.serialize(request);

// Parse incoming messages
const message = Parser.parse(serialized);

// Create an event
const event = Event.outgoing(
  { message: 'Hello, World!' },
  { topic: 'chat.room.general', reliable: true }
);

API Reference

Core Components

  • Messages - Request, Response, Event message types
  • MethodManager - RPC method routing with middleware
  • EventManager - Pub/sub event system with topic subscriptions
  • Parser/Serializer - Message parsing and serialization
  • Errors - Structured error hierarchy
  • Utils - PatternMatcher and CapturePatternMatcher

Messages

The protocol supports three message types: Request, Response, and Event.

Request

RPC-style request messages with timeout support.

import { Request } from '@aionbuilders/helios-protocol';

// Create outgoing request
const request = Request.outgoing(
  { userId: 123, action: 'update' },  // payload
  {
    method: 'user.update',            // required
    timeout: 5000,                    // optional (ms)
    metadata: { trace: 'abc' },       // optional
    peer: { service: 'user-service' } // optional routing
  }
);

// Access properties
console.log(request.method);    // 'user.update'
console.log(request.timeout);   // 5000
console.log(request.payload);   // { userId: 123, action: 'update' }
console.log(request.id);        // auto-generated UUID

Method format: Alphanumeric characters, dots, dashes, and underscores (e.g., user.get, chat-room.join)

Response

Response to a request message.

import { Response } from '@aionbuilders/helios-protocol';

// Success response
const success = Response.outgoing(
  { user: { id: 123, name: 'Alice' } },  // payload
  {
    requestId: request.id,                // required
    status: 200                           // required
  }
);

// Error response
const error = Response.outgoing(
  null,
  {
    requestId: request.id,
    status: 404,
    error: 'User not found'
  }
);

// Access properties
console.log(success.status);     // 200
console.log(success.requestId);  // matches request.id
console.log(success.payload);    // { user: {...} }
console.log(error.error);        // 'User not found'

Status codes: Follow HTTP conventions (200, 404, 500, etc.)

Event

Pub/sub style event messages with topic routing.

import { Event } from '@aionbuilders/helios-protocol';

// Create event
const event = Event.outgoing(
  { message: 'Hello!', user: 'Alice' },  // data
  {
    topic: 'chat.room.general',          // required
    reliable: true,                      // optional (default: false)
    metadata: { priority: 'high' }       // optional
  }
);

// Topic matching with wildcards
Event.matchTopic('chat.room.general', 'chat.*');        // true (single level)
Event.matchTopic('chat.room.general', 'chat.**');       // true (multi level)
Event.matchTopic('chat.room.general', 'user.*');        // false
Event.matchTopic('chat.room.general.dm', 'chat.*');     // false
Event.matchTopic('chat.room.general.dm', 'chat.**');    // true

// Access properties
console.log(event.topic);     // 'chat.room.general'
console.log(event.reliable);  // true
console.log(event.data);      // { message: 'Hello!', user: 'Alice' }

Topic format: Alphanumeric characters, dots, dashes, underscores, and wildcards (*, **)

  • * matches exactly one level (e.g., chat.* matches chat.room but not chat.room.general)
  • ** matches one or more levels (e.g., chat.** matches chat.room.general)

MethodManager

RPC method routing with middleware support and pattern matching.

import { MethodManager, Request } from '@aionbuilders/helios-protocol';

const methods = new MethodManager();

// Register methods
methods.register('user.get', async (context) => {
  // Access request data
  const userId = context.payload.userId;

  // Return response data directly
  return { id: userId, name: 'Alice', email: '[email protected]' };
});

methods.register('user.create', async (context) => {
  // Return custom status code using context.createResponse
  return context.createResponse({ id: 456 }, 201);
});

// Register with options
methods.register('user.update', async (context) => {
  return { updated: true };
}, { timeout: 10000 });

// Handle incoming requests
const request = Request.outgoing({ userId: 123 }, { method: 'user.get' });
const response = await methods.handle(request);

console.log(response.status);  // 200
console.log(response.data);    // { id: 123, name: 'Alice', ... }

Middleware

Add cross-cutting concerns like logging, auth, validation:

// Global middleware (runs for all methods)
methods.use('**', async (context, next) => {
  console.log(`[${context.method}] Start`);
  const result = await next();
  console.log(`[${context.method}] Done`);
  return result;
});

// Pattern-based middleware (runs for matching methods)
methods.use('user.*', async (context, next) => {
  // Auth check for all user.* methods
  if (!context.clientId) {
    throw new Error('Unauthorized');
  }
  return await next();
});

// Specific method middleware
methods.use('user.delete', async (context, next) => {
  // Audit log for user deletions
  console.log('Deleting user:', context.payload.userId);
  return await next();
});

Pattern matching:

  • user.get - Exact match
  • user.* - Single level wildcard (matches user.get, user.create)
  • user.** - Multi-level wildcard (matches user.get, user.settings.update)
  • **.admin - Prefix wildcard (matches user.admin, system.admin)

Context Data

Pass additional data to handlers (like client ID, auth info):

const response = await methods.handle(request, {
  clientId: 'client-123',
  userId: 456,
  permissions: ['read', 'write']
});

methods.register('post.create', async (context) => {
  // Access custom context data
  const { clientId, userId, permissions } = context;

  if (!permissions.includes('write')) {
    return context.createResponse(null, 403);
  }

  return { postId: 789, author: userId };
});

Namespaces

Organize methods into logical groups:

// Create namespace
const userMethods = methods.namespace('user');

// Register methods with automatic prefix
userMethods.register('get', async (context) => {
  return { id: 123 };
});

userMethods.register('create', async (context) => {
  return { id: 456 };
});

// Accessible as 'user.get' and 'user.create'
const response = await methods.handle(
  Request.outgoing({}, { method: 'user.get' })
);

EventManager

Pub/sub event system with topic routing and middleware.

import { EventManager, Event } from '@aionbuilders/helios-protocol';

const events = new EventManager();

// Subscribe to events
events.on('user:created', async (context) => {
  console.log('New user:', context.data.userId);
});

events.on('user:deleted', async (context) => {
  console.log('User deleted:', context.data.userId);
});

// Subscribe with wildcards
events.on('user:*', async (context) => {
  // Matches user:created, user:deleted, user:updated, etc.
  console.log('User event:', context.topic);
});

events.on('chat:**', async (context) => {
  // Matches chat:message, chat:room:join, chat:room:leave, etc.
  console.log('Chat event:', context.data);
});

// Dispatch events
const event = Event.outgoing(
  { userId: 123, name: 'Alice' },
  { topic: 'user:created' }
);

await events.handle(event);

One-time Listeners

Subscribe to events that auto-remove after first execution:

events.once('system:ready', async (context) => {
  console.log('System initialized');
  // This listener will be removed after first execution
});

Event Middleware

Add cross-cutting logic to event handling:

// Global middleware
events.use('**', async (context, next) => {
  console.log(`Event: ${context.topic}`);
  await next();
});

// Pattern-based middleware
events.use('user:*', async (context, next) => {
  // Log all user events
  console.log('User event data:', context.data);
  await next();
});

// Specific topic middleware
events.use('chat:message', async (context, next) => {
  // Filter profanity for chat messages
  context.data.message = filterProfanity(context.data.message);
  await next();
});

Context Data

Pass additional context when handling events:

await events.handle(event, {
  clientId: 'client-123',
  server: 'ws-server-1'
});

events.on('user:action', async (context) => {
  // Access custom context
  console.log('Client:', context.clientId);
  console.log('Server:', context.server);
});

Event Namespaces

Organize event listeners into logical groups:

// Create namespace
const userEvents = events.namespace('user');

// Register listeners with automatic prefix
userEvents.on('created', async (context) => {
  console.log('User created');
});

userEvents.on('deleted', async (context) => {
  console.log('User deleted');
});

// Accessible as 'user:created' and 'user:deleted'
await events.handle(
  Event.outgoing({}, { topic: 'user:created' })
);

Management API

// List all registered topics
const topics = events.topics();  // ['user:created', 'chat:message', ...]

// Get listeners for a topic
const listeners = events.listeners('user:created');

// Check if topic has listeners
if (events.has('user:created')) {
  console.log('Has listeners');
}

// Remove specific listener
events.off('user:created', myHandler);

// Remove all listeners for topic
events.offAll('user:created');

// Clear all listeners
events.clear();

Parser & Serializer

Serializer

Convert messages to wire format (JSON or binary).

import { Serializer } from '@aionbuilders/helios-protocol';

// Serialize to JSON (default)
const jsonString = Serializer.serialize(message);

// Serialize to binary (Uint8Array)
const binary = Serializer.serialize(message, 'binary');

// Check if message can be serialized
if (Serializer.canSerialize(message)) {
  const data = Serializer.serialize(message);
}

Parser

Parse incoming data into typed message instances.

import { Parser } from '@aionbuilders/helios-protocol';

// Parse from different formats
const message = Parser.parse(jsonString);           // from JSON string
const message = Parser.parse(uint8Array);           // from Uint8Array
const message = Parser.parse(arrayBuffer);          // from ArrayBuffer

// Returns the correct message type
if (message instanceof Request) {
  console.log('Received request:', message.method);
} else if (message instanceof Response) {
  console.log('Received response:', message.status);
} else if (message instanceof Event) {
  console.log('Received event:', message.topic);
}

Errors

The protocol provides a structured error hierarchy.

import {
  HeliosError,       // Base error class
  ValidationError,   // Invalid data provided (4xx equivalent)
  ProtocolError,     // Invalid message format (4xx equivalent)
  TimeoutError       // Request timeout (5xx equivalent)
} from '@aionbuilders/helios-protocol';

try {
  const request = Request.outgoing({}, { /* missing method */ });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.message);  // "Request requires a method"
    console.log(error.details);  // [{ field: "method", message: "Method is required" }]
  }
}

try {
  const message = Parser.parse(invalidData);
} catch (error) {
  if (error instanceof ProtocolError) {
    console.log(error.code);     // "INVALID_MESSAGE_TYPE"
    console.log(error.message);  // "Invalid message type"
  }
}

Message Properties

All messages share common properties:

// Common to all messages
message.id          // Unique identifier (UUID v4)
message.type        // 'request' | 'response' | 'event'
message.protocol    // Protocol version (e.g., 'helios/1.0.0')
message.timestamp   // Unix timestamp in milliseconds
message.direction   // 'outgoing' | 'incoming'
message.metadata    // Optional metadata object
message.peer        // Optional peer routing { id?, service?, metadata? }

// Methods
message.clone()     // Create a deep copy
message.validate()  // Validate message integrity
message.toJSON()    // Convert to plain object

Complete Export List

// Messages
import {
  Message,
  Request,
  Response,
  Event
} from '@aionbuilders/helios-protocol';

// Method Management (RPC)
import {
  MethodManager,
  MethodHandler,
  RequestContext,
  MethodNamespaceManager
} from '@aionbuilders/helios-protocol';

// Event Management (Pub/Sub)
import {
  EventManager,
  EventListener,
  EventContext,
  EventNamespaceManager
} from '@aionbuilders/helios-protocol';

// Parser & Serializer
import {
  Parser,
  Serializer
} from '@aionbuilders/helios-protocol';

// Errors
import {
  HeliosError,
  ValidationError,
  ProtocolError,
  TimeoutError
} from '@aionbuilders/helios-protocol';

// Utils
import {
  PatternMatcher,
  CapturePatternMatcher
} from '@aionbuilders/helios-protocol';

TypeScript Support

Full TypeScript definitions are included:

import type {
  MessageType,
  MessageHeaders,
  RequestHeaders,
  ResponseHeaders,
  EventHeaders,
  MessageOptions,
  PeerRouting,
  SerializedMessage
} from '@aionbuilders/helios-protocol';

// All classes are fully typed
const request = Request.outgoing<{ userId: number }>(
  { userId: 123 },
  { method: 'user.get' }
);

// Type-safe access
const userId: number = request.payload.userId;

Peer Routing

Messages can include peer routing information for multi-peer scenarios:

// Route by peer ID
const request = Request.outgoing(
  { action: 'ping' },
  {
    method: 'health.check',
    peer: { id: 'client-abc-123' }
  }
);

// Route by service type
const request = Request.outgoing(
  { userId: 123 },
  {
    method: 'user.get',
    peer: { service: 'user-service' }
  }
);

// Route with metadata
const request = Request.outgoing(
  { query: 'data' },
  {
    method: 'search',
    peer: {
      service: 'search-service',
      metadata: { region: 'eu-west-1', version: '2.0' }
    }
  }
);

Note: At least one of id or service is required when using peer routing.

Validation

The protocol uses a two-phase validation approach:

Outgoing (Creation) - Strict

When creating messages, validation is strict and throws immediately:

// ❌ Throws ValidationError: method is required
Request.outgoing({}, {});

// ❌ Throws ValidationError: invalid method format
Request.outgoing({}, { method: 'invalid method!' });

// ❌ Throws ValidationError: timeout must be positive
Request.outgoing({}, { method: 'test', timeout: -1 });

Incoming (Parsing) - Permissive

When parsing received messages, validation is permissive and only throws for critical errors:

// Parses successfully, logs warning for unusual values
const message = Parser.parse(slightlyInvalidData);

Manual Validation

You can manually validate a message at any time:

try {
  message.validate();
  console.log('Message is valid');
} catch (error) {
  console.error('Validation failed:', error.details);
}

Protocol Version

Current protocol version: helios/1.0.0

The protocol follows semantic versioning:

  • Major version changes indicate breaking protocol changes
  • Minor version changes add backward-compatible features
  • Patch version changes are bug fixes

Messages with incompatible major versions are rejected automatically.

Examples

Full Request/Response Cycle

import { Request, Response, Parser, Serializer } from '@aionbuilders/helios-protocol';

// Client side: create and send request
const request = Request.outgoing(
  { userId: 123 },
  { method: 'user.get', timeout: 5000 }
);

const requestData = Serializer.serialize(request);
// Send requestData over WebSocket...

// Server side: receive and parse request
const receivedRequest = Parser.parse(requestData);

// Process request and create response
const response = Response.outgoing(
  { id: 123, name: 'Alice', email: '[email protected]' },
  { requestId: receivedRequest.id, status: 200 }
);

const responseData = Serializer.serialize(response);
// Send responseData back over WebSocket...

// Client side: receive response
const receivedResponse = Parser.parse(responseData);
console.log(receivedResponse.payload); // { id: 123, name: 'Alice', ... }

Pub/Sub with Events

import { Event, Parser, Serializer } from '@aionbuilders/helios-protocol';

// Publisher: create and broadcast event
const event = Event.outgoing(
  { message: 'New user joined!', user: 'Bob' },
  { topic: 'chat.room.lobby', reliable: true }
);

const eventData = Serializer.serialize(event);
// Broadcast eventData to all subscribers...

// Subscriber: receive and handle event
const receivedEvent = Parser.parse(eventData);

if (receivedEvent instanceof Event) {
  // Check topic match
  if (Event.matchTopic(receivedEvent.topic, 'chat.**')) {
    console.log('Chat event:', receivedEvent.data);
  }
}

Runtime Compatibility

This protocol package is runtime agnostic and works with:

  • Bun (recommended, optimized for Bun runtime)
  • Node.js (v16+)
  • Deno
  • Browsers (modern browsers with ES2020+ support)

Related Packages

Contributing

Contributions are welcome! Please read DEVELOPMENT.md for development guidelines and architectural decisions.

License

MIT © Killian Di Vincenzo (AION Builders)


Made with ❤️ by Killian Di Vincenzo with AION Builders