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:
- ws — the most widely used WebSocket library for Node.js
- websocket npm package — WebSocket client and server implementation
WARNING: Only the server side of these libraries is supported.
Client-side code (for example new WebSocket(url)) is not analyzed by this extension. For
WebSocket client support for javascript source code is provided by com.castsoftware.html5.
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.
Links
| 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 |
Send link filtering
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 Serverobject named/chat - a
callLinkfrom/chattoonConnection - a
callLinkfrom/chattoonMessage - a
callLinkfrom the inlineforEachcallback (nested insidebroadcastAll) 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 Serverobject named{}(this package has no path option) - a
callLinkfrom{}toonRequest - a
callLinkfrom{}toonMessage - a
callLinkfromnotifyAllto{}
Known limitations
- The
websocketnpm 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 aconnectioncallback, orconnection.on('message', ...)inside arequestcallback) 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'orimport { 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.