Skip to content

TypeScript Client Library

The Virtufin WebSocketManager TypeScript client library (virtufin-websocketmanager) provides a TypeScript interface for managing external WebSocket connections using gRPC-web and Connect-RPC.

Installation

From Gitea npm Registry

Configure authentication with a Gitea personal access token (scope: read:packages):

echo "//npm.haenerconsulting.com/api/packages/virtufin/npm/:_authToken=<your-gitea-token>" >> ~/.npmrc

Then install:

npm install virtufin-websocketmanager

From Local Source

{
  "dependencies": {
    "virtufin-websocketmanager": "file:path/to/src/typescript"
  }
}

Overview

The client library provides the WebSocketManagerClient class as the main entry point for WebSocket connection management.

Quick Start

import { WebSocketManagerClient } from "virtufin-websocketmanager";

const client = new WebSocketManagerClient({ url: "http://localhost:5001" });

// Connect to a WebSocket server
const { id: connectionId, status } = await client.connect({
    url: "wss://echo.websocket.org",
    autoReconnect: false
});
console.log(`Connected: ${connectionId} - ${status}`);

// List all connections
const { connections } = await client.list({});
console.log(`Total connections: ${connections.length}`);

// Send a message
const { response } = await client.send({
    id: connectionId,
    message: JSON.stringify({ type: "ping" }),
    timeoutMs: 5000
});
console.log(`Response: ${response}`);

// Disconnect
await client.disconnect({ id: connectionId });

WebSocketManagerClient

Constructor

const client = new WebSocketManagerClient({ url: string, timeout?: number });

Parameters: - url - The gRPC-web base URL (e.g., "http://localhost:5001") - timeout - Request timeout in milliseconds (default: 30000)

Methods

Connection Management

// Connect to a WebSocket server
connect(request: ConnectRequest): Promise<ConnectResponse>

// Disconnect from a WebSocket server
disconnect(request: DisconnectRequest): Promise<DisconnectResponse>

// List all managed connections
list(request: ListRequest = {}): Promise<ListResponse>

Example:

const { id: connectionId, status } = await client.connect({
    url: "wss://echo.websocket.org",
    autoReconnect: true
});

const { connections } = await client.list({});
for (const conn of connections) {
    console.log(`${conn.id}: ${conn.url} [${conn.status}]`);
}

await client.disconnect({ id: connectionId });

Pub/Sub Integration

// Start publishing WebSocket messages to a Dapr pub/sub topic
startPublish(request: StartPublishRequest): Promise<StartPublishResponse>

// Stop publishing to the topic
stopPublish(request: StopPublishRequest): Promise<StopPublishResponse>

Example:

await client.startPublish({
    id: connectionId,
    topic: "websocket-events"
});

await client.stopPublish({ id: connectionId });

Messaging

// Send a message and wait for a correlated response
send(request: SendRequest): Promise<SendResponse>

// Send a message without waiting for a response
sendRaw(request: SendRawRequest): Promise<SendRawResponse>

Example:

// Send with correlation (expects response)
const { response } = await client.send({
    id: connectionId,
    message: JSON.stringify({ type: "request", id: "123" }),
    timeoutMs: 5000
});
console.log(`Response: ${response}`);

// Fire-and-forget
await client.sendRaw({
    id: connectionId,
    message: JSON.stringify({ type: "notification" })
});


Data Models

ConnectRequest

interface ConnectRequest {
    url: string;
    autoReconnect?: boolean;
}

ConnectResponse

interface ConnectResponse {
    id: string;
    status: string;
}

WebSocketConnection

interface WebSocketConnection {
    id: string;
    url: string;
    status: string;
    topic: string;
    instanceId: string;
}

SendRequest

interface SendRequest {
    id: string;
    message: string;
    timeoutMs: number;
}

SendResponse

interface SendResponse {
    response: string;
}

Error Handling

Connection Not Found

try {
    await client.disconnect({ id: "nonexistent" });
} catch (error) {
    if (error instanceof ConnectError) {
        console.log(`Not found: ${error.message}`);
    }
}

Send Timeout

try {
    const { response } = await client.send({
        id: connectionId,
        message: "slow request",
        timeoutMs: 100 // very short
    });
} catch (error) {
    if (error instanceof ConnectError && error.code === Code.DeadlineExceeded) {
        console.log("Send timed out");
    }
}

Connection Errors

try {
    const client = new WebSocketManagerClient({ url: "http://invalid-host:5001" });
    await client.connect({ url: "wss://invalid" });
} catch (error) {
    console.log(`Connection failed: ${error.message}`);
}

Complete Example

import { WebSocketManagerClient } from "virtufin-websocketmanager";

async function main() {
    console.log("WebSocketManager Client Demo");
    console.log("==============================\n");

    const client = new WebSocketManagerClient({ url: "http://localhost:5001" });

    // Connect
    console.log("Connecting to WebSocket server...");
    const { id: connectionId, status } = await client.connect({
        url: "wss://echo.websocket.org",
        autoReconnect: false
    });
    console.log(`Connected: ${connectionId} - ${status}`);

    // List connections
    console.log("\nAll connections:");
    const { connections } = await client.list({});
    for (const conn of connections) {
        console.log(`  ${conn.id}: ${conn.url} [${conn.status}]`);
        if (conn.topic) {
            console.log(`    Publishing to: ${conn.topic}`);
        }
    }

    // Send a message
    console.log("\nSending message...");
    const { response } = await client.send({
        id: connectionId,
        message: JSON.stringify({ type: "request", id: "123", data: "hello" }),
        timeoutMs: 5000
    });
    console.log(`Response: ${response}`);

    // Start pub/sub
    console.log("\nStarting pub/sub...");
    await client.startPublish({
        id: connectionId,
        topic: "ws-events"
    });
    console.log("Publishing started");

    // Stop pub/sub
    console.log("\nStopping pub/sub...");
    await client.stopPublish({ id: connectionId });
    console.log("Publishing stopped");

    // Disconnect
    console.log("\nDisconnecting...");
    await client.disconnect({ id: connectionId });
    console.log("Disconnected");
}

main();

Protobuf Dependencies

The client library requires the peer dependency:

{
  "peerDependencies": {
    "@bufbuild/protobuf": "^1.10.0"
  }
}

Ensure your project installs the peer dependency:

npm install @bufbuild/protobuf

The proto files are pre-compiled into the src/generated directory.


Generated Protos

The client includes generated protobuf classes from websocketmanager.proto:

Type Description
ConnectRequest Request to connect to a WebSocket server
ConnectResponse Response with connection ID and status
ListRequest Request to list all connections
ListResponse Response with list of connections
DisconnectRequest Request to disconnect
DisconnectResponse Empty response
StartPublishRequest Request to start pub/sub publishing
StartPublishResponse Empty response
StopPublishRequest Request to stop publishing
StopPublishResponse Empty response
SendRequest Request to send a correlated message
SendResponse Response with server reply
SendRawRequest Request to send without waiting
SendRawResponse Empty response
WebSocketConnection Connection details
## SDK Reference