or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-nestjs--platform-ws

WebSocket adapter implementation for NestJS framework providing real-time bidirectional communication

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@nestjs/platform-ws@11.1.x

To install, run

npx @tessl/cli install tessl/npm-nestjs--platform-ws@11.1.0

0

# NestJS Platform WebSocket

1

2

NestJS Platform WebSocket (`@nestjs/platform-ws`) is a WebSocket adapter implementation for the NestJS framework that provides real-time bidirectional communication between server and client applications. It uses the 'ws' library as the underlying WebSocket implementation and integrates seamlessly with NestJS's dependency injection system, decorators, and reactive programming model using RxJS.

3

4

## Package Information

5

6

- **Package Name**: @nestjs/platform-ws

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @nestjs/platform-ws`

10

11

## Core Imports

12

13

```typescript

14

import { WsAdapter } from "@nestjs/platform-ws";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { WsAdapter } = require("@nestjs/platform-ws");

21

```

22

23

## Basic Usage

24

25

```typescript

26

import { WsAdapter } from "@nestjs/platform-ws";

27

import { NestFactory } from "@nestjs/core";

28

import { AppModule } from "./app.module";

29

30

async function bootstrap() {

31

const app = await NestFactory.create(AppModule);

32

33

// Use the WebSocket adapter

34

app.useWebSocketAdapter(new WsAdapter(app));

35

36

await app.listen(3000);

37

}

38

bootstrap();

39

```

40

41

## Architecture

42

43

The @nestjs/platform-ws package is built around the following key components:

44

45

- **WsAdapter Class**: Main adapter extending AbstractWsAdapter from @nestjs/websockets

46

- **Message Parsing**: Configurable message parsing with custom parser support

47

- **Connection Management**: Handles WebSocket server creation, client connections, and lifecycle events

48

- **Server Registry**: Manages multiple WebSocket servers and HTTP server sharing

49

- **RxJS Integration**: Uses observables for reactive message handling and event streams

50

- **Error Handling**: Comprehensive error handling with logging integration

51

52

## Capabilities

53

54

### WebSocket Adapter

55

56

Core WebSocket adapter class that provides complete WebSocket functionality for NestJS applications.

57

58

```typescript { .api }

59

/**

60

* WebSocket adapter implementation for NestJS using the 'ws' library

61

* @publicApi

62

*/

63

class WsAdapter extends AbstractWsAdapter {

64

constructor(

65

appOrHttpServer?: INestApplicationContext | object,

66

options?: WsAdapterOptions

67

);

68

69

/** Creates a WebSocket server with specified configuration */

70

create(

71

port: number,

72

options?: Record<string, any> & {

73

namespace?: string;

74

server?: any;

75

path?: string;

76

}

77

): any;

78

79

/** Sets up message handling for WebSocket client connections */

80

bindMessageHandlers(

81

client: any,

82

handlers: MessageMappingProperties[],

83

transform: (data: any) => Observable<any>

84

): void;

85

86

/** Handles individual message processing and routing */

87

bindMessageHandler(

88

buffer: any,

89

handlersMap: Map<string, MessageMappingProperties>,

90

transform: (data: any) => Observable<any>

91

): Observable<any>;

92

93

/** Attaches error event handlers to WebSocket server */

94

bindErrorHandler(server: any): any;

95

96

/** Binds disconnect event handler to WebSocket client */

97

bindClientDisconnect(client: any, callback: Function): void;

98

99

/** Gracefully closes WebSocket server and terminates client connections */

100

close(server: any): Promise<void>;

101

102

/** Cleans up all HTTP and WebSocket server registries */

103

dispose(): Promise<void>;

104

105

/** Sets custom message parser for processing incoming messages */

106

setMessageParser(parser: WsMessageParser): void;

107

108

/** Protected method to ensure HTTP server exists for the given port */

109

protected ensureHttpServerExists(

110

port: number,

111

httpServer?: any

112

): any;

113

114

/** Protected method to add WebSocket server to internal registry */

115

protected addWsServerToRegistry<T extends Record<'path', string>>(

116

wsServer: T,

117

port: number,

118

path: string

119

): void;

120

}

121

```

122

123

### Message Parsing

124

125

Custom message parser support for handling different message formats.

126

127

```typescript { .api }

128

/**

129

* Message parser function type for processing WebSocket data

130

*/

131

type WsMessageParser = (data: WsData) => { event: string; data: any } | void;

132

133

/** WebSocket data types supported by the parser */

134

type WsData = string | Buffer | ArrayBuffer | Buffer[];

135

```

136

137

### Configuration Options

138

139

Adapter configuration options for customizing behavior.

140

141

```typescript { .api }

142

interface WsAdapterOptions {

143

/** Custom message parser for handling different message formats */

144

messageParser?: WsMessageParser;

145

}

146

```

147

148

### Connection States

149

150

WebSocket connection ready states used internally by the adapter.

151

152

```typescript { .api }

153

enum READY_STATE {

154

CONNECTING_STATE = 0,

155

OPEN_STATE = 1,

156

CLOSING_STATE = 2,

157

CLOSED_STATE = 3

158

}

159

```

160

161

## Usage Examples

162

163

### Basic WebSocket Setup

164

165

```typescript

166

import { WsAdapter } from "@nestjs/platform-ws";

167

import { NestFactory } from "@nestjs/core";

168

169

const app = await NestFactory.create(AppModule);

170

app.useWebSocketAdapter(new WsAdapter(app));

171

```

172

173

### Custom Message Parser

174

175

```typescript

176

import { WsAdapter } from "@nestjs/platform-ws";

177

178

const customParser = (data) => {

179

try {

180

// Custom parsing logic

181

const parsed = JSON.parse(data.toString());

182

return { event: parsed.type, data: parsed.payload };

183

} catch {

184

return null;

185

}

186

};

187

188

const adapter = new WsAdapter(app, { messageParser: customParser });

189

app.useWebSocketAdapter(adapter);

190

```

191

192

### WebSocket Server with Custom Path

193

194

```typescript

195

// In your WebSocket gateway

196

@WebSocketGateway(3001, { path: '/custom-ws' })

197

export class CustomGateway {

198

@WebSocketServer()

199

server: Server;

200

201

// The adapter automatically handles path-based routing

202

}

203

```

204

205

### Multiple WebSocket Servers

206

207

```typescript

208

// Multiple gateways can share the same HTTP server

209

@WebSocketGateway(3001, { path: '/chat' })

210

export class ChatGateway { }

211

212

@WebSocketGateway(3001, { path: '/notifications' })

213

export class NotificationGateway { }

214

215

// The WsAdapter manages multiple servers with different paths

216

```

217

218

### Error Handling

219

220

```typescript

221

@WebSocketGateway()

222

export class MyGateway implements OnGatewayConnection, OnGatewayDisconnect {

223

224

handleConnection(client: WebSocket) {

225

console.log('Client connected');

226

// Connection handling

227

}

228

229

handleDisconnect(client: WebSocket) {

230

console.log('Client disconnected');

231

// Cleanup logic

232

}

233

234

@SubscribeMessage('error')

235

handleError(client: WebSocket, error: any) {

236

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

237

// Error handling

238

}

239

}

240

```

241

242

### Advanced Configuration

243

244

```typescript

245

import { WsAdapter } from "@nestjs/platform-ws";

246

import { INestApplication } from "@nestjs/common";

247

248

// Custom adapter with advanced configuration

249

class CustomWsAdapter extends WsAdapter {

250

constructor(app: INestApplication) {

251

// Custom message parser that handles binary data

252

const binaryParser = (data: Buffer | string) => {

253

if (Buffer.isBuffer(data)) {

254

// Handle binary WebSocket frames

255

const eventLength = data.readUInt8(0);

256

const event = data.subarray(1, 1 + eventLength).toString();

257

const payload = data.subarray(1 + eventLength);

258

return { event, data: payload };

259

}

260

// Fallback to JSON parsing for text frames

261

return JSON.parse(data.toString());

262

};

263

264

super(app, { messageParser: binaryParser });

265

}

266

267

// Override error handling for custom logging

268

bindErrorHandler(server: any) {

269

server.on('connection', (ws: any) => {

270

ws.on('error', (err: any) => {

271

// Custom error handling logic

272

this.logger.error(`WebSocket error: ${err.message}`, err.stack);

273

});

274

});

275

server.on('error', (err: any) => {

276

this.logger.error(`Server error: ${err.message}`, err.stack);

277

});

278

return server;

279

}

280

}

281

282

// Use custom adapter

283

const app = await NestFactory.create(AppModule);

284

app.useWebSocketAdapter(new CustomWsAdapter(app));

285

```

286

287

### Performance Optimization

288

289

```typescript

290

// Gateway with connection pooling and rate limiting

291

@WebSocketGateway(3001, {

292

cors: true,

293

transports: ['websocket'],

294

})

295

export class OptimizedGateway {

296

private connectionPool = new Map<string, WebSocket>();

297

private messageCount = new Map<string, number>();

298

299

@OnEvent('server.created')

300

handleServerCreated(server: any) {

301

// Configure server-level options after creation

302

server.options.perMessageDeflate = {

303

threshold: 1024,

304

concurrencyLimit: 10,

305

};

306

}

307

308

handleConnection(client: WebSocket, request: any) {

309

const clientId = this.generateClientId(request);

310

311

// Add to connection pool

312

this.connectionPool.set(clientId, client);

313

this.messageCount.set(clientId, 0);

314

315

// Set up rate limiting

316

const rateLimit = setInterval(() => {

317

this.messageCount.set(clientId, 0);

318

}, 60000); // Reset every minute

319

320

client.on('close', () => {

321

clearInterval(rateLimit);

322

this.connectionPool.delete(clientId);

323

this.messageCount.delete(clientId);

324

});

325

}

326

327

@SubscribeMessage('message')

328

handleMessage(client: WebSocket, data: any) {

329

const clientId = this.getClientId(client);

330

const count = this.messageCount.get(clientId) || 0;

331

332

// Rate limiting

333

if (count > 100) { // Max 100 messages per minute

334

client.send(JSON.stringify({

335

error: 'Rate limit exceeded'

336

}));

337

return;

338

}

339

340

this.messageCount.set(clientId, count + 1);

341

// Process message...

342

}

343

344

private generateClientId(request: any): string {

345

return `${request.socket.remoteAddress}:${Date.now()}`;

346

}

347

348

private getClientId(client: WebSocket): string {

349

// Implementation to retrieve client ID

350

return '';

351

}

352

}

353

```

354

355

## Types

356

357

```typescript { .api }

358

/** HTTP server registry key type - uses port number as key */

359

type HttpServerRegistryKey = number;

360

361

/** HTTP server registry entry type - stores HTTP server instances */

362

type HttpServerRegistryEntry = any;

363

364

/** WebSocket server registry key type - uses port number as key */

365

type WsServerRegistryKey = number;

366

367

/** WebSocket server registry entry type - array of WebSocket servers */

368

type WsServerRegistryEntry = any[];

369

370

/** Port constant used for underlying HTTP server sharing */

371

const UNDERLYING_HTTP_SERVER_PORT = 0;

372

```

373

374

## Internal Registry Management

375

376

The adapter maintains internal registries for HTTP and WebSocket servers:

377

378

```typescript { .api }

379

/** Map storing HTTP servers by port number */

380

protected readonly httpServersRegistry: Map<HttpServerRegistryKey, HttpServerRegistryEntry>;

381

382

/** Map storing WebSocket servers by port number */

383

protected readonly wsServersRegistry: Map<WsServerRegistryKey, WsServerRegistryEntry>;

384

```

385

386

## Error Handling

387

388

The adapter provides comprehensive error handling:

389

390

- **Connection Errors**: Automatically logged and handled through the NestJS logger

391

- **Message Parsing Errors**: Returns empty observable for invalid messages

392

- **Server Errors**: Bound to error event handlers with logging

393

- **Namespace Errors**: Throws explicit error if namespaces are used (not supported)

394

- **Upgrade Errors**: Socket connections are terminated for invalid upgrade requests

395

- **Malformed URLs**: HTTP 400 responses for invalid WebSocket upgrade URLs

396

397

### Error Scenarios

398

399

```typescript

400

// Namespace error (thrown during server creation)

401

const error = new Error(

402

'"WsAdapter" does not support namespaces. If you need namespaces in your project, consider using the "@nestjs/platform-socket.io" package instead.'

403

);

404

405

// Message parsing error (returns EMPTY observable)

406

try {

407

const message = this.messageParser(buffer.data);

408

if (!message) {

409

return EMPTY; // Invalid message format

410

}

411

} catch {

412

return EMPTY; // Parsing failed

413

}

414

415

// HTTP upgrade error handling

416

httpServer.on('upgrade', (request, socket, head) => {

417

try {

418

// URL parsing and routing logic

419

} catch (err) {

420

socket.end('HTTP/1.1 400\r\n' + err.message);

421

}

422

});

423

```