or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client.mdconnection.mdframe.mdindex.mdrouter-request.mdserver.mdutilities.md

connection.mddocs/

0

# Connection Management

1

2

Active WebSocket connection handling for bidirectional communication between client and server with comprehensive message processing, event handling, and connection lifecycle management.

3

4

## Capabilities

5

6

### WebSocketConnection

7

8

Represents an active WebSocket connection for both client and server sides.

9

10

```javascript { .api }

11

/**

12

* Active WebSocket connection for bidirectional communication

13

* @param socket - TCP socket

14

* @param extensions - Negotiated extensions array

15

* @param protocol - Negotiated protocol string

16

* @param maskOutgoingPackets - Whether to mask outgoing packets

17

* @param config - Connection configuration

18

*/

19

class WebSocketConnection extends EventEmitter {

20

/**

21

* Send text or binary data (auto-detects type)

22

* @param data - String or Buffer to send

23

* @param callback - Optional callback for completion/error

24

*/

25

send(data: string | Buffer, callback?: (error?: Error) => void): void;

26

27

/**

28

* Send UTF-8 text data

29

* @param data - UTF-8 string to send

30

* @param callback - Optional callback for completion/error

31

*/

32

sendUTF(data: string, callback?: (error?: Error) => void): void;

33

34

/**

35

* Send binary data

36

* @param data - Buffer containing binary data

37

* @param callback - Optional callback for completion/error

38

*/

39

sendBytes(data: Buffer, callback?: (error?: Error) => void): void;

40

41

/**

42

* Send ping frame with optional payload

43

* @param data - Optional Buffer payload for ping frame

44

*/

45

ping(data?: Buffer): void;

46

47

/**

48

* Send pong frame (usually sent automatically in response to ping)

49

* @param binaryPayload - Buffer payload for pong frame

50

*/

51

pong(binaryPayload: Buffer): void;

52

53

/**

54

* Initiate clean connection close

55

* @param reasonCode - Close reason code (default: 1000)

56

* @param description - Human-readable close reason

57

*/

58

close(reasonCode?: number, description?: string): void;

59

60

/**

61

* Force close connection immediately

62

* @param reasonCode - Close reason code

63

* @param description - Human-readable close reason

64

* @param skipCloseFrame - Skip sending close frame

65

*/

66

drop(reasonCode?: number, description?: string, skipCloseFrame?: boolean): void;

67

68

/** Pause reading from socket */

69

pause(): void;

70

71

/** Resume reading from socket */

72

resume(): void;

73

74

/** Boolean connection status */

75

readonly connected: boolean;

76

77

/** Connection state: 'open', 'peer_requested_close', 'ending', 'closed' */

78

readonly state: string;

79

80

/** Negotiated WebSocket protocol */

81

readonly protocol: string;

82

83

/** Negotiated extensions (currently always empty array) */

84

readonly extensions: any[];

85

86

/** Remote IP address */

87

readonly remoteAddress: string;

88

89

/** Array of addresses including X-Forwarded-For */

90

readonly remoteAddresses: string[];

91

92

/** Close reason code (set after close) */

93

readonly closeReasonCode: number;

94

95

/** Close reason description (set after close) */

96

readonly closeDescription: string;

97

98

/** WebSocket protocol version (8 or 13) */

99

readonly webSocketVersion: number;

100

101

/** Underlying TCP socket */

102

readonly socket: object;

103

}

104

```

105

106

**Events:**

107

108

- `'message'` - `(WebSocketMessage)` - Message received

109

- `'frame'` - `(WebSocketFrame)` - Raw frame received (if assembleFragments is false)

110

- `'close'` - `(reasonCode, description)` - Connection closed

111

- `'error'` - `(error)` - Connection error

112

- `'ping'` - `(cancel, data)` - Ping frame received

113

- `'pong'` - `(data)` - Pong frame received

114

- `'drain'` - Socket drain event (outgoing buffer emptied)

115

- `'pause'` - Socket pause event

116

- `'resume'` - Socket resume event

117

118

**Usage Example:**

119

120

```javascript

121

// Server-side: handling connection from request

122

wsServer.on('request', function(request) {

123

const connection = request.accept('echo-protocol', request.origin);

124

125

// Connection event handlers

126

connection.on('message', function(message) {

127

console.log('Received Message:', message.type);

128

129

if (message.type === 'utf8') {

130

console.log('UTF-8 Data: ' + message.utf8Data);

131

// Echo back

132

connection.sendUTF('Echo: ' + message.utf8Data);

133

} else if (message.type === 'binary') {

134

console.log('Binary Data: ' + message.binaryData.length + ' bytes');

135

// Echo back binary

136

connection.sendBytes(message.binaryData);

137

}

138

});

139

140

connection.on('ping', function(cancel, data) {

141

console.log('Received ping');

142

// Pong is sent automatically, but you can cancel it

143

// cancel.cancel = true;

144

});

145

146

connection.on('pong', function(data) {

147

console.log('Received pong');

148

});

149

150

connection.on('close', function(reasonCode, description) {

151

console.log('Connection closed: ' + reasonCode + ' - ' + description);

152

});

153

154

connection.on('error', function(error) {

155

console.log('Connection error: ' + error.toString());

156

});

157

158

// Send periodic pings

159

const pingInterval = setInterval(function() {

160

if (connection.connected) {

161

connection.ping(Buffer.from('ping-data'));

162

} else {

163

clearInterval(pingInterval);

164

}

165

}, 30000);

166

});

167

168

// Client-side: handling connection

169

client.on('connect', function(connection) {

170

// Send different types of data

171

connection.sendUTF('Hello Server!');

172

connection.sendBytes(Buffer.from([0x01, 0x02, 0x03, 0x04]));

173

174

// Auto-detect send method

175

connection.send('Text message'); // Uses sendUTF

176

connection.send(Buffer.from('Binary data')); // Uses sendBytes

177

178

// Handle responses

179

connection.on('message', function(message) {

180

if (message.type === 'utf8') {

181

console.log('Server says: ' + message.utf8Data);

182

}

183

});

184

185

// Graceful close after 5 seconds

186

setTimeout(function() {

187

connection.close(1000, 'Normal closure');

188

}, 5000);

189

});

190

```

191

192

### Message Processing

193

194

**Message Object Structure:**

195

196

```javascript { .api }

197

interface WebSocketMessage {

198

/** Message type: 'utf8' for text, 'binary' for binary data */

199

type: 'utf8' | 'binary';

200

201

/** UTF-8 string data (present when type is 'utf8') */

202

utf8Data?: string;

203

204

/** Binary data as Buffer (present when type is 'binary') */

205

binaryData?: Buffer;

206

}

207

```

208

209

**Message Handling Patterns:**

210

211

```javascript

212

connection.on('message', function(message) {

213

switch (message.type) {

214

case 'utf8':

215

// Handle text message

216

const textData = message.utf8Data;

217

console.log('Text:', textData);

218

219

// Parse JSON if applicable

220

try {

221

const jsonData = JSON.parse(textData);

222

handleJsonMessage(jsonData);

223

} catch (e) {

224

handleTextMessage(textData);

225

}

226

break;

227

228

case 'binary':

229

// Handle binary message

230

const binaryData = message.binaryData;

231

console.log('Binary length:', binaryData.length);

232

233

// Process binary data

234

if (binaryData.length > 0) {

235

const firstByte = binaryData[0];

236

console.log('First byte:', firstByte);

237

}

238

break;

239

}

240

});

241

```

242

243

### Connection State Management

244

245

**Connection States:**

246

247

- `'open'` - Connection is active and ready for communication

248

- `'peer_requested_close'` - Remote peer initiated close handshake

249

- `'ending'` - Local close initiated, waiting for peer response

250

- `'closed'` - Connection is fully closed

251

252

**State Monitoring:**

253

254

```javascript

255

connection.on('close', function(reasonCode, description) {

256

console.log('Connection state:', connection.state); // 'closed'

257

console.log('Close reason:', reasonCode, description);

258

console.log('Connected status:', connection.connected); // false

259

});

260

261

// Monitor state changes

262

const originalState = connection.state;

263

setInterval(function() {

264

if (connection.state !== originalState) {

265

console.log('State changed from', originalState, 'to', connection.state);

266

}

267

}, 1000);

268

```

269

270

### Error Handling and Recovery

271

272

**Error Types and Handling:**

273

274

```javascript

275

connection.on('error', function(error) {

276

console.error('WebSocket Error:', error.message);

277

278

// Check if connection is still viable

279

if (connection.connected) {

280

console.log('Connection still active, error was recoverable');

281

} else {

282

console.log('Connection lost due to error');

283

// Attempt reconnection logic here

284

attemptReconnection();

285

}

286

});

287

288

// Handle different types of errors

289

connection.on('error', function(error) {

290

if (error.code === 'ECONNRESET') {

291

console.log('Connection reset by peer');

292

} else if (error.code === 'ETIMEDOUT') {

293

console.log('Connection timed out');

294

} else {

295

console.log('Other error:', error.code, error.message);

296

}

297

});

298

```

299

300

### Flow Control

301

302

**Backpressure Handling:**

303

304

```javascript

305

// Monitor drain events for flow control

306

let canSendMore = true;

307

308

connection.on('drain', function() {

309

console.log('Output buffer drained, can send more data');

310

canSendMore = true;

311

// Resume sending queued messages

312

sendQueuedMessages();

313

});

314

315

function sendMessage(data) {

316

if (canSendMore && connection.connected) {

317

const result = connection.sendUTF(data, function(error) {

318

if (error) {

319

console.error('Send error:', error);

320

canSendMore = false;

321

}

322

});

323

324

// Check if we should pause sending

325

if (!result) {

326

canSendMore = false;

327

console.log('Output buffer full, waiting for drain');

328

}

329

} else {

330

// Queue message for later

331

messageQueue.push(data);

332

}

333

}

334

```

335

336

### Connection Close Handling

337

338

**Close Reason Constants:**

339

340

```javascript { .api }

341

// Close reason constants (accessible as WebSocketConnection static properties)

342

WebSocketConnection.CLOSE_REASON_NORMAL = 1000;

343

WebSocketConnection.CLOSE_REASON_GOING_AWAY = 1001;

344

WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR = 1002;

345

WebSocketConnection.CLOSE_REASON_UNPROCESSABLE_INPUT = 1003;

346

WebSocketConnection.CLOSE_REASON_RESERVED = 1004;

347

WebSocketConnection.CLOSE_REASON_NOT_PROVIDED = 1005;

348

WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006;

349

WebSocketConnection.CLOSE_REASON_INVALID_DATA = 1007;

350

WebSocketConnection.CLOSE_REASON_POLICY_VIOLATION = 1008;

351

WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG = 1009;

352

WebSocketConnection.CLOSE_REASON_EXTENSION_REQUIRED = 1010;

353

WebSocketConnection.CLOSE_REASON_INTERNAL_SERVER_ERROR = 1011;

354

WebSocketConnection.CLOSE_REASON_TLS_HANDSHAKE_FAILED = 1015;

355

356

// Close descriptions mapping

357

WebSocketConnection.CLOSE_DESCRIPTIONS = {

358

1000: 'Normal connection closure',

359

1001: 'Remote end going away',

360

1002: 'Protocol error',

361

1003: 'Unprocessable input',

362

1004: 'Reserved',

363

1005: 'Reason not provided',

364

1006: 'Abnormal closure, no close frame',

365

1007: 'Invalid frame payload data',

366

1008: 'Policy violation',

367

1009: 'Message too big',

368

1010: 'Extension required',

369

1011: 'Internal server error',

370

1015: 'TLS handshake failed'

371

};

372

```

373

374

**Graceful Shutdown:**

375

376

```javascript

377

function gracefulShutdown(connection) {

378

if (connection.connected) {

379

// Send any final messages

380

connection.sendUTF(JSON.stringify({ type: 'goodbye' }));

381

382

// Initiate clean close

383

connection.close(WebSocketConnection.CLOSE_REASON_NORMAL, 'Server shutting down');

384

385

// Force close after timeout

386

setTimeout(function() {

387

if (connection.state !== 'closed') {

388

console.log('Forcing connection close');

389

connection.drop(WebSocketConnection.CLOSE_REASON_NORMAL, 'Timeout');

390

}

391

}, 5000);

392

}

393

}

394

395

// Handle different close scenarios

396

connection.on('close', function(reasonCode, description) {

397

switch (reasonCode) {

398

case WebSocketConnection.CLOSE_REASON_NORMAL:

399

console.log('Clean shutdown');

400

break;

401

case WebSocketConnection.CLOSE_REASON_GOING_AWAY:

402

console.log('Peer is going away');

403

break;

404

case WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR:

405

console.log('Protocol error occurred');

406

break;

407

default:

408

console.log('Connection closed with code:', reasonCode);

409

}

410

});

411

```

412

413

## Types

414

415

### Connection Configuration

416

417

```javascript { .api }

418

interface ConnectionConfig {

419

maxReceivedFrameSize?: number;

420

maxReceivedMessageSize?: number;

421

fragmentOutgoingMessages?: boolean;

422

fragmentationThreshold?: number;

423

assembleFragments?: boolean;

424

disableNagleAlgorithm?: boolean;

425

closeTimeout?: number;

426

}

427

```

428

429

### Connection States

430

431

```javascript { .api }

432

type ConnectionState = 'open' | 'peer_requested_close' | 'ending' | 'closed';

433

```