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

@owlmeans/server-socket

v0.1.1

Published

The **@owlmeans/server-socket** package provides WebSocket server functionality for OwlMeans Common Libraries, designed for fullstack microservices and microclients development with focus on security and proper authentication and authorization.

Readme

@owlmeans/server-socket

The @owlmeans/server-socket package provides WebSocket server functionality for OwlMeans Common Libraries, designed for fullstack microservices and microclients development with focus on security and proper authentication and authorization.

Purpose

This package serves as the server-side WebSocket implementation that:

  • Provides WebSocket server capabilities using Fastify WebSocket integration
  • Supports real-time communication between server and clients
  • Integrates with module system for WebSocket route handling
  • Implements authentication and authorization for WebSocket connections
  • Offers connection management with lifecycle hooks and proper cleanup
  • Enables bidirectional messaging with typed message handling

Core Concepts

Socket Service

A service that manages WebSocket server functionality and integrates with the Fastify web server to provide WebSocket endpoints.

Connection Handling

Provides abstraction for WebSocket connections with proper lifecycle management, authentication, and error handling.

Module Integration

WebSocket endpoints are defined using the OwlMeans module system, allowing for consistent routing, validation, and middleware application.

Authentication & Authorization

WebSocket connections can be protected using the same guard and gate system used for HTTP endpoints.

API Reference

Services

createSocketService(alias?): SocketService

Creates a WebSocket service that can be registered with a server context.

import { createSocketService } from '@owlmeans/server-socket'

const socketService = createSocketService('websocket')

Parameters:

  • alias: string (optional) - Service alias, defaults to DEFAULT_ALIAS ('socket-server')

Returns: SocketService instance

SocketService

Interface for the WebSocket service.

interface SocketService extends InitializedService {
  update: (api: ApiServer) => Promise<void>
}

Methods:

  • update(api): Configures the WebSocket server with the provided API server instance

Helper Functions

handleConnection<T>(handler): RefedModuleHandler

Creates a WebSocket connection handler that integrates with the module system.

import { handleConnection } from '@owlmeans/server-socket'
import type { Connection } from '@owlmeans/socket'

const myConnectionHandler = handleConnection<MyConnection>(
  async (conn, ctx, req, res) => {
    // Handle WebSocket connection
    console.log('New WebSocket connection')
    
    conn.onMessage(async (message) => {
      console.log('Received:', message)
      await conn.send({ type: 'echo', data: message })
    })
    
    conn.onClose(() => {
      console.log('Connection closed')
    })
  }
)

Parameters:

  • handler: Function that handles WebSocket connections with signature:
    • conn: Connection instance
    • ctx: Server context
    • req: Abstract request
    • res: Abstract response

Returns: Module handler compatible with OwlMeans modules

Types

Config

Configuration interface extending ServerConfig.

interface Config extends ServerConfig {}

Context<C>

Context interface that extends ServerContext with API server capabilities.

interface Context<C extends Config = Config> extends ServerContext<C>, ApiServerAppend {}

Constants

DEFAULT_ALIAS

Default alias for the socket service.

const DEFAULT_ALIAS = 'socket-server'

Usage Examples

Basic WebSocket Server Setup

import { makeServerContext, makeServerConfig } from '@owlmeans/server-context'
import { createSocketService } from '@owlmeans/server-socket'
import { createApiService } from '@owlmeans/server-api'
import { AppType } from '@owlmeans/context'

// Create server configuration
const config = makeServerConfig(AppType.Backend, 'websocket-server', {
  host: 'localhost',
  port: 3000
})

// Create context and services
const context = makeServerContext(config)
const apiService = createApiService()
const socketService = createSocketService()

// Register services
context.registerService(apiService)
context.registerService(socketService)

// Configure and initialize
context.configure()
await context.init()

console.log('WebSocket server running on ws://localhost:3000')

WebSocket Module with Authentication

import { module, guard } from '@owlmeans/module'
import { route } from '@owlmeans/route'
import { handleConnection } from '@owlmeans/server-socket'
import type { Connection } from '@owlmeans/socket'

// Create WebSocket module with authentication
const chatModule = module(
  route('chat-socket', '/ws/chat'),
  guard('authenticated')
)

// Set WebSocket handler
chatModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    const userId = req.auth?.user?.id
    
    if (!userId) {
      await conn.close(1008, 'Authentication required')
      return
    }
    
    console.log(`User ${userId} connected to chat`)
    
    // Join user to chat room
    await joinChatRoom(conn, userId)
    
    // Handle incoming messages
    conn.onMessage(async (message) => {
      if (message.type === 'chat-message') {
        await broadcastMessage(userId, message.content)
      }
    })
    
    // Handle disconnection
    conn.onClose(() => {
      console.log(`User ${userId} disconnected from chat`)
      leaveChatRoom(userId)
    })
  }
)

// Register module with context
context.registerModule(chatModule)

Real-time Data Streaming

import { handleConnection } from '@owlmeans/server-socket'
import type { Connection } from '@owlmeans/socket'

const dataStreamModule = module(
  route('data-stream', '/ws/data'),
  guard('authenticated')
)

dataStreamModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    const userId = req.auth?.user?.id
    
    // Start streaming data to client
    const streamInterval = setInterval(async () => {
      const data = await fetchLatestData(userId)
      await conn.send({
        type: 'data-update',
        timestamp: Date.now(),
        data: data
      })
    }, 1000)
    
    // Handle client requests
    conn.onMessage(async (message) => {
      switch (message.type) {
        case 'subscribe':
          await subscribeToChannel(userId, message.channel)
          break
        case 'unsubscribe':
          await unsubscribeFromChannel(userId, message.channel)
          break
        case 'get-history':
          const history = await getHistoricalData(message.from, message.to)
          await conn.send({
            type: 'history-data',
            requestId: message.requestId,
            data: history
          })
          break
      }
    })
    
    // Cleanup on disconnect
    conn.onClose(() => {
      clearInterval(streamInterval)
      unsubscribeFromAllChannels(userId)
    })
  }
)

WebSocket with Validation

import { module, filter, body } from '@owlmeans/module'
import { route } from '@owlmeans/route'
import { handleConnection } from '@owlmeans/server-socket'

// Define message validation schema
const messageSchema = {
  type: 'object',
  properties: {
    type: { type: 'string', enum: ['join', 'leave', 'message'] },
    content: { type: 'string', maxLength: 1000 },
    roomId: { type: 'string' }
  },
  required: ['type']
}

const validatedSocketModule = module(
  route('validated-socket', '/ws/validated'),
  filter(body(messageSchema))
)

validatedSocketModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    conn.onMessage(async (message) => {
      // Message is automatically validated against schema
      try {
        switch (message.type) {
          case 'join':
            await joinRoom(conn, message.roomId)
            await conn.send({ type: 'joined', roomId: message.roomId })
            break
          case 'leave':
            await leaveRoom(conn, message.roomId)
            await conn.send({ type: 'left', roomId: message.roomId })
            break
          case 'message':
            await broadcastToRoom(message.roomId, {
              type: 'room-message',
              content: message.content,
              sender: req.auth?.user?.id
            })
            break
        }
      } catch (error) {
        await conn.send({
          type: 'error',
          message: error.message
        })
      }
    })
  }
)

Connection Management

import { handleConnection } from '@owlmeans/server-socket'
import type { Connection } from '@owlmeans/socket'

// Global connection registry
const connections = new Map<string, Connection>()

const managedConnectionModule = module(
  route('managed-connection', '/ws/managed')
)

managedConnectionModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    const connectionId = generateConnectionId()
    
    // Register connection
    connections.set(connectionId, conn)
    
    // Send connection info
    await conn.send({
      type: 'connection-established',
      connectionId: connectionId,
      serverTime: Date.now()
    })
    
    // Handle ping/pong for connection health
    conn.onMessage(async (message) => {
      if (message.type === 'ping') {
        await conn.send({ type: 'pong', timestamp: Date.now() })
      }
    })
    
    // Cleanup on disconnect
    conn.onClose(() => {
      connections.delete(connectionId)
      console.log(`Connection ${connectionId} closed`)
    })
    
    // Send periodic server stats
    const statsInterval = setInterval(async () => {
      await conn.send({
        type: 'server-stats',
        activeConnections: connections.size,
        serverUptime: process.uptime()
      })
    }, 30000)
    
    conn.onClose(() => {
      clearInterval(statsInterval)
    })
  }
)

// Function to broadcast to all connections
const broadcastToAll = async (message: any) => {
  const promises = Array.from(connections.values()).map(conn =>
    conn.send(message).catch(console.error)
  )
  await Promise.allSettled(promises)
}

Error Handling

import { handleConnection } from '@owlmeans/server-socket'
import { ResilientError } from '@owlmeans/error'

const errorHandlingModule = module(
  route('error-handling', '/ws/errors')
)

errorHandlingModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    conn.onMessage(async (message) => {
      try {
        await processMessage(message)
      } catch (error) {
        if (error instanceof ResilientError) {
          // Handle known errors gracefully
          await conn.send({
            type: 'error',
            code: error.code,
            message: error.message,
            recoverable: true
          })
        } else {
          // Handle unknown errors
          console.error('Unexpected error:', error)
          await conn.send({
            type: 'error',
            message: 'Internal server error',
            recoverable: false
          })
        }
      }
    })
    
    conn.onError((error) => {
      console.error('WebSocket connection error:', error)
    })
  }
)

Integration Patterns

With Chat Systems

// Real-time chat implementation
const chatRooms = new Map<string, Set<Connection>>()

const joinRoom = async (conn: Connection, roomId: string) => {
  if (!chatRooms.has(roomId)) {
    chatRooms.set(roomId, new Set())
  }
  chatRooms.get(roomId)!.add(conn)
}

const broadcastToRoom = async (roomId: string, message: any) => {
  const room = chatRooms.get(roomId)
  if (room) {
    const promises = Array.from(room).map(conn => conn.send(message))
    await Promise.allSettled(promises)
  }
}

With Gaming Applications

// Game server with real-time updates
const gameSessionModule = module(
  route('game-session', '/ws/game/:sessionId'),
  guard('authenticated')
)

gameSessionModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    const sessionId = req.params.sessionId
    const playerId = req.auth?.user?.id
    
    await joinGameSession(sessionId, playerId, conn)
    
    conn.onMessage(async (message) => {
      switch (message.type) {
        case 'player-move':
          await processPlayerMove(sessionId, playerId, message.move)
          await broadcastGameState(sessionId)
          break
        case 'player-action':
          await processPlayerAction(sessionId, playerId, message.action)
          break
      }
    })
  }
)

With Monitoring Systems

// Real-time monitoring dashboard
const monitoringModule = module(
  route('monitoring', '/ws/monitor'),
  guard('admin')
)

monitoringModule.handle = handleConnection<Connection>(
  async (conn, ctx, req, res) => {
    // Send initial system state
    await conn.send({
      type: 'system-state',
      data: await getSystemMetrics()
    })
    
    // Subscribe to system events
    const unsubscribe = await subscribeToSystemEvents(async (event) => {
      await conn.send({
        type: 'system-event',
        event: event
      })
    })
    
    conn.onClose(unsubscribe)
  }
)

Security Considerations

Authentication and Authorization

  • Guard Integration - Use authentication guards to protect WebSocket endpoints
  • Token Validation - Validate JWT tokens or session tokens before accepting connections
  • Connection Limits - Implement connection limits per user or IP address

Data Validation

  • Message Validation - Always validate incoming WebSocket messages
  • Rate Limiting - Implement rate limiting for message frequency
  • Sanitization - Sanitize user input to prevent injection attacks

Connection Security

  • TLS/SSL - Use secure WebSocket connections (WSS) in production
  • Origin Validation - Validate connection origins to prevent CSRF attacks
  • Connection Timeouts - Implement proper timeout mechanisms

Best Practices

  1. Implement proper error handling - Always handle connection errors and message processing errors
  2. Use connection pooling - Manage connections efficiently to prevent memory leaks
  3. Implement heartbeat mechanism - Use ping/pong to detect dead connections
  4. Validate all messages - Never trust incoming WebSocket messages without validation
  5. Handle cleanup properly - Always clean up resources when connections close
  6. Monitor connection health - Track connection metrics and performance

Error Handling

The package integrates with OwlMeans error handling:

  • ResilientError - For recoverable errors that clients can handle
  • Connection errors - Proper handling of WebSocket connection failures
  • Authentication errors - Clear error messages for authentication failures
  • Validation errors - Detailed validation error reporting

Dependencies

This package depends on:

  • @owlmeans/context - For service registration and context management
  • @owlmeans/server-api - For API server integration
  • @owlmeans/server-context - For server-side context management
  • @owlmeans/server-module - For module system integration
  • @owlmeans/module - For core module functionality
  • @owlmeans/socket - For connection abstractions
  • @owlmeans/error - For error handling
  • @fastify/websocket - For WebSocket server implementation

Related Packages