Pular para o conteúdo principal

WebSocket Client

O TyForge fornece uma classe base abstrata ServiceWebSocket para construir clientes WebSocket type-safe com Result pattern, reconnect automático e proteção contra SSRF/DNS rebinding.

Conceito

ServiceWebSocket estende ServiceBase e encapsula a API nativa WebSocket (Node.js >=24) com:

  • Conversão automática de https:// para wss:// (e http://localhost para ws://)
  • Validação DNS contra ranges privados antes da conexão
  • Reconnect automático com backoff exponencial, jitter e delay cap de 30s
  • Sanitização de mensagens contra prototype pollution com limite de profundidade
  • Subscribe/unsubscribe para eventos tipados
  • Timeout configurável na conexão
  • Retorno sempre via Result pattern

Criando um cliente WebSocket

import { ServiceWebSocket, ExceptionWebSocket } from "@tyforge/websocket";
import { ok, isFailure } from "tyforge/result";
import { FString, FInt, FBoolean, FUrlOrigin } from "tyforge/type-fields";
import type { Result } from "tyforge/result";
import type { Exceptions } from "tyforge/exceptions";

class ChatService extends ServiceWebSocket {
protected readonly _classInfo = { name: "ChatService", version: "1.0.0", description: "Chat WebSocket client" };
readonly endpoint = FUrlOrigin.createOrThrow("https://chat.api.com");

protected async getAuthHeaders(): Promise<Result<Record<string, FString>, Exceptions>> {
return ok({ "Authorization": FString.createOrThrow("Bearer my-token") });
}

async connectToChat(): Promise<void> {
const result = await this.connect({
authenticated: FBoolean.createOrThrow(true),
timeout: FInt.createOrThrow(5000),
reconnect: FBoolean.createOrThrow(true),
maxReconnectAttempts: FInt.createOrThrow(5),
});
if (isFailure(result)) throw result.error;
}

async sendMessage(text: string): Promise<void> {
const result = await this.send(
FString.createOrThrow("chat.message"),
{ text },
);
if (isFailure(result)) throw result.error;
}

onMessage(handler: (data: Record<string, unknown>) => void): void {
this.subscribe(FString.createOrThrow("chat.message"), handler);
}
}

Segurança

ProteçãoDescrição
DNS rebindingvalidateEndpointDns() resolve hostname e valida contra IPs privados antes da conexão
IPs privadosBloqueia 10.x, 172.16-31.x, 192.168.x, 169.254.x, 127.x, CGNAT, IPv6 link-local/ULA
IPv4-mapped IPv6Detecta ::ffff:10.0.0.1 e re-valida o IPv4 embutido
Prototype pollutionsanitizeMessage() recursiva com DANGEROUS_KEYS filtering
ProfundidadeLimite de 50 níveis na sanitização — retorna Result com erro explícito
TamanhoMensagens acima de 10MB são descartadas antes do JSON.parse

Reconnect

O reconnect automático usa backoff exponencial com jitter:

  • Base delay: 1s, dobrando a cada tentativa
  • Delay cap: 30s (nunca excede)
  • Jitter: 50-100% do delay calculado (previne thundering herd)
  • Tentativas configuráveis via maxReconnectAttempts (default: 3)

ExceptionWebSocket

Factory MethodCódigoStatusRetriable
connectionFailed()WS_CONNECTION_FAILED502Sim
connectionTimeout()WS_CONNECTION_TIMEOUT504Sim
disconnected()WS_DISCONNECTED503Sim
sendFailed(event)WS_SEND_FAILED502Sim
subscriptionFailed(event)WS_SUBSCRIPTION_FAILED400Não
authFailed(cause?)WS_AUTH_FAILED401Não
invalidMessage()WS_INVALID_MESSAGE400Não
invalidParams(detail)WS_INVALID_PARAMS400Não

Instalação

npm install @tyforge/websocket
import { ServiceWebSocket, ServiceWebSocketSecurity, ExceptionWebSocket } from "@tyforge/websocket";