WebSocket support for Node.js


Introduction

WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. This extension supports the server side of the following WebSocket libraries:

Objects

Metamodel name Description
CAST_NodeJS_WebSocket_Server Represents a WebSocket server endpoint identified by its path

A NodeJS WebSocket Server object is created as soon as the server is instantiated (new WebSocketServer(...) / new server(...)), even if no handler is ever registered on it and it never sends any data. A server is named {} when its path cannot be statically determined (for example when the path is passed as a runtime parameter, or when using the websocket npm package, which has no path option). A server named {} is treated as a catch-all endpoint.

Link type From To Created when
callLink NodeJS WebSocket Server NodeJS Function / Method A handler is registered on the server (on('connection', ...), on('request', ...), on('message', ...))
callLink NodeJS Function / Method NodeJS WebSocket Server A function sends a message to clients (broadcast) or calls .send() from outside a registered handler — see filtering rule below

A send link (callLink from a function to the server) represents that the function actively pushes data to the WebSocket server’s clients, complementing the links that show which functions receive messages from it. To avoid redundant links, a send link is suppressed when the sending function is already registered as a handler (callee) of the same server:

Situation Example Result
The sending function is already a registered handler (direct callee) of the server ws.send() inside a wss.on('connection', fn) callback Suppressed — fn is already linked as a callee of the server
The sending function is not a registered handler wss.clients.forEach(...) or wsServer.broadcast() called from a scheduler or REST endpoint Created — the send link appears in the call graph

Supported API methods

ws library

API method Object created / linked Link type
new WebSocketServer({ path }) NodeJS WebSocket Server
wss.on('connection', fn) fn linked as callee of server callLink
ws.on('message', fn) inside a connection handler fn linked as callee of server callLink
ws.send(data) called from a registered handler suppressed (see filtering rule)
wss.clients.forEach(fn) + client.send(data) from non-handler code fn linked as caller (send link) callLink

websocket npm package

API method Object created / linked Link type
new server({ httpServer }) NodeJS WebSocket Server (named {})
wsServer.on('request', fn) fn linked as callee of server callLink
connection.on('message', fn) inside a request handler fn linked as callee of server callLink
conn.send(), conn.sendUTF(), conn.sendBytes() from a registered handler suppressed (see filtering rule)
wsServer.broadcast(), wsServer.broadcastUTF(), wsServer.broadcastBytes() from non-handler code fn linked as caller (send link) callLink

Example

ws library

import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080, path: '/chat' });

// callLink: wss ──→ onConnection  (callee — server registers this handler)
wss.on('connection', (ws) => {
    // callLink: wss ──→ onMessage  (callee — server registers this inner handler)
    ws.on('message', function onMessage(data) {
        // No send link: this function is already a callee of the server,
        // so ws.send() is suppressed by the filtering rule.
        ws.send('echo: ' + data);
    });
});

function broadcastAll(msg) {
    // callLink: <forEach callback> ──→ wss  (send link — this callback is NOT a
    // registered server handler, so it is attributed as a caller of the server)
    wss.clients.forEach((client) => {
        client.send(msg);
    });
}

This produces:

  • one NodeJS WebSocket Server object named /chat
  • a callLink from /chat to onConnection
  • a callLink from /chat to onMessage
  • a callLink from the inline forEach callback (nested inside broadcastAll) to /chat

Assuming that a websocket client connects to ws://{}/chat, you will get the following result:

websocket npm package

import { server as WebSocketServer } from 'websocket';

const wsServer = new WebSocketServer({ httpServer });

// callLink: wsServer ──→ onRequest  (callee — server registers this handler)
wsServer.on('request', function onRequest(request) {
    const connection = request.accept(null, request.origin);

    // callLink: wsServer ──→ onMessage  (callee — server registers this inner handler)
    connection.on('message', function onMessage(message) {
        // No send link: this function is already a callee of the server,
        // so connection.sendUTF() is suppressed by the filtering rule.
        connection.sendUTF('echo: ' + message.utf8Data);
    });
});

// callLink: notifyAll ──→ wsServer  (send link — notifyAll is NOT a server handler)
function notifyAll(msg) {
    wsServer.broadcastUTF(msg);
}

This produces:

  • one NodeJS WebSocket Server object named {} (this package has no path option)
  • a callLink from {} to onRequest
  • a callLink from {} to onMessage
  • a callLink from notifyAll to {}

Known limitations

  • The websocket npm package has no path option, so every server created with it is named {} and treated as a single catch-all endpoint, even when multiple distinct servers exist in the source code.
  • A nested handler (ws.on('message', ...) inside a connection callback, or connection.on('message', ...) inside a request callback) is only linked when it is registered directly inside the tracked outer callback. If it is registered through an intermediate function call, the link may not be created.
  • Aliased ES imports are supported regardless of the chosen alias, for example import { server as MyServer } from 'websocket' or import { WebSocketServer as WS } from 'ws'. Aliased CommonJS destructuring (const { server: MyServer } = require('websocket')) is not reliably detected — use the non-aliased form (const { server } = require('websocket')) or an ES import instead.