or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdclient-creation.mderror-handling.mdhttp-links.mdindex.mdutility-links.mdwebsocket-links.md

websocket-links.mddocs/

0

# WebSocket Links

1

2

Real-time communication through WebSocket connections for subscriptions and bidirectional communication. WebSocket links provide persistent connections for real-time data streaming and notifications.

3

4

## Capabilities

5

6

### wsLink

7

8

Creates a WebSocket transport link for real-time subscriptions and bidirectional communication with tRPC servers.

9

10

```typescript { .api }

11

/**

12

* Creates a WebSocket transport link for real-time communication

13

* @param opts - WebSocket link configuration options

14

* @returns WebSocket transport link for the client chain

15

*/

16

function wsLink<TRouter extends AnyRouter>(

17

opts: WebSocketLinkOptions<TRouter>

18

): TRPCLink<TRouter>;

19

20

interface WebSocketLinkOptions<TRouter extends AnyRouter> {

21

/** WebSocket client instance */

22

client: TRPCWebSocketClient;

23

/** Data transformation configuration */

24

transformer?: inferClientTypes<TRouter>['transformer'];

25

}

26

```

27

28

**Usage Examples:**

29

30

```typescript

31

import { createTRPCClient, wsLink, createWSClient } from "@trpc/client";

32

33

// Basic WebSocket setup

34

const wsClient = createWSClient({

35

url: "ws://localhost:3001",

36

});

37

38

const client = createTRPCClient<AppRouter>({

39

links: [

40

wsLink({

41

client: wsClient,

42

}),

43

],

44

});

45

46

// Subscribe to real-time updates

47

const unsubscribe = client.posts.onUpdate.subscribe(undefined, {

48

onData: (post) => {

49

console.log("Post updated:", post);

50

},

51

onError: (err) => {

52

console.error("Subscription error:", err);

53

},

54

});

55

56

// Clean up when done

57

unsubscribe.unsubscribe();

58

```

59

60

### createWSClient

61

62

Factory function for creating WebSocket clients with connection management, reconnection logic, and configuration options.

63

64

```typescript { .api }

65

/**

66

* Creates a WebSocket client with connection management

67

* @param opts - WebSocket client configuration options

68

* @returns Configured WebSocket client instance

69

*/

70

function createWSClient(opts: WebSocketClientOptions): TRPCWebSocketClient;

71

72

interface WebSocketClientOptions {

73

/** WebSocket server URL */

74

url: string;

75

76

/** WebSocket implementation (for Node.js environments) */

77

WebSocket?: typeof WebSocket;

78

79

/** Retry delay calculation function */

80

retryDelayMs?: (attemptIndex: number) => number;

81

82

/** Connection opened event handler */

83

onOpen?: () => void;

84

85

/** Connection error event handler */

86

onError?: (event?: Event) => void;

87

88

/** Connection closed event handler */

89

onClose?: (cause?: { code?: number }) => void;

90

91

/** Lazy connection configuration */

92

lazy?: LazyOptions;

93

94

/** Keep-alive ping/pong configuration */

95

keepAlive?: KeepAliveOptions;

96

}

97

98

type TRPCWebSocketClient = ReturnType<typeof createWSClient>;

99

```

100

101

**Usage Examples:**

102

103

```typescript

104

import { createWSClient } from "@trpc/client";

105

106

// Basic WebSocket client

107

const wsClient = createWSClient({

108

url: "ws://localhost:3001",

109

});

110

111

// WebSocket client with event handlers

112

const wsClient = createWSClient({

113

url: "ws://localhost:3001",

114

onOpen: () => {

115

console.log("Connected to WebSocket");

116

},

117

onError: (event) => {

118

console.error("WebSocket error:", event);

119

},

120

onClose: (cause) => {

121

console.log("WebSocket closed:", cause?.code);

122

},

123

});

124

125

// Node.js environment with WebSocket polyfill

126

import WebSocket from "ws";

127

128

const wsClient = createWSClient({

129

url: "ws://localhost:3001",

130

WebSocket: WebSocket as any,

131

});

132

133

// Custom retry strategy

134

const wsClient = createWSClient({

135

url: "ws://localhost:3001",

136

retryDelayMs: (attemptIndex) => {

137

// Custom backoff: 1s, 3s, 5s, 10s, then 10s

138

const delays = [1000, 3000, 5000, 10000];

139

return delays[attemptIndex] || 10000;

140

},

141

});

142

```

143

144

### Retry and Backoff

145

146

Configurable retry logic with exponential backoff for handling connection failures.

147

148

```typescript { .api }

149

/**

150

* Default exponential backoff calculation

151

* @param attemptIndex - Zero-based retry attempt index

152

* @returns Delay in milliseconds (0ms → 1s → 2s → 4s ... → 30s max)

153

*/

154

function exponentialBackoff(attemptIndex: number): number;

155

```

156

157

**Retry Examples:**

158

159

```typescript

160

import { createWSClient, exponentialBackoff } from "@trpc/client";

161

162

// Using default exponential backoff

163

const wsClient = createWSClient({

164

url: "ws://localhost:3001",

165

retryDelayMs: exponentialBackoff, // Default behavior

166

});

167

168

// Custom retry logic

169

const wsClient = createWSClient({

170

url: "ws://localhost:3001",

171

retryDelayMs: (attemptIndex) => {

172

if (attemptIndex === 0) return 0; // Immediate first retry

173

if (attemptIndex < 3) return 1000; // 1s for first 3 attempts

174

if (attemptIndex < 6) return 5000; // 5s for next 3 attempts

175

return 15000; // 15s for subsequent attempts

176

},

177

});

178

179

// Aggressive retry for critical connections

180

const wsClient = createWSClient({

181

url: "ws://localhost:3001",

182

retryDelayMs: (attemptIndex) => Math.min(500 * attemptIndex, 5000),

183

});

184

```

185

186

### Lazy Connections

187

188

Lazy connection management that automatically opens and closes WebSocket connections based on activity.

189

190

```typescript { .api }

191

interface LazyOptions {

192

/** Enable lazy connection mode */

193

enabled: boolean;

194

/** Close connection after this many milliseconds of inactivity */

195

closeMs: number;

196

}

197

198

/** Default lazy connection configuration */

199

const lazyDefaults: LazyOptions = {

200

enabled: false,

201

closeMs: 0,

202

};

203

```

204

205

**Lazy Connection Examples:**

206

207

```typescript

208

// Enable lazy connections with 30-second timeout

209

const wsClient = createWSClient({

210

url: "ws://localhost:3001",

211

lazy: {

212

enabled: true,

213

closeMs: 30000, // Close after 30s of inactivity

214

},

215

});

216

217

// Lazy connections for mobile apps (battery optimization)

218

const wsClient = createWSClient({

219

url: "ws://localhost:3001",

220

lazy: {

221

enabled: true,

222

closeMs: 10000, // Aggressive 10s timeout for mobile

223

},

224

});

225

```

226

227

### Keep-Alive Configuration

228

229

Ping/pong keep-alive mechanism to maintain WebSocket connections and detect connection issues.

230

231

```typescript { .api }

232

interface KeepAliveOptions {

233

/** Enable keep-alive ping/pong */

234

enabled: boolean;

235

/** Send ping every this many milliseconds */

236

intervalMs?: number;

237

/** Timeout for pong response in milliseconds */

238

pongTimeoutMs?: number;

239

}

240

241

/** Default keep-alive configuration */

242

const keepAliveDefaults: KeepAliveOptions = {

243

enabled: false,

244

pongTimeoutMs: 1000,

245

intervalMs: 5000,

246

};

247

```

248

249

**Keep-Alive Examples:**

250

251

```typescript

252

// Enable keep-alive with default settings

253

const wsClient = createWSClient({

254

url: "ws://localhost:3001",

255

keepAlive: {

256

enabled: true,

257

},

258

});

259

260

// Custom keep-alive timing

261

const wsClient = createWSClient({

262

url: "ws://localhost:3001",

263

keepAlive: {

264

enabled: true,

265

intervalMs: 10000, // Ping every 10 seconds

266

pongTimeoutMs: 2000, // Wait 2 seconds for pong

267

},

268

});

269

270

// Aggressive keep-alive for unstable networks

271

const wsClient = createWSClient({

272

url: "ws://localhost:3001",

273

keepAlive: {

274

enabled: true,

275

intervalMs: 3000, // Frequent pings

276

pongTimeoutMs: 1000, // Quick timeout detection

277

},

278

});

279

```

280

281

### Connection State Management

282

283

WebSocket links provide connection state information for handling reconnections and connection issues.

284

285

```typescript { .api }

286

/** Connection state types */

287

type TRPCConnectionState<TError = unknown> =

288

| { type: 'connecting' }

289

| { type: 'open' }

290

| { type: 'closed' }

291

| { type: 'error'; error: TError };

292

293

/** WebSocket client with connection state observable */

294

interface TRPCWebSocketClient {

295

connectionState: Observable<TRPCConnectionState>;

296

request(opts: { op: Operation; transformer: any }): Observable<any>;

297

close(): void;

298

}

299

```

300

301

**Connection State Examples:**

302

303

```typescript

304

import { createTRPCClient, wsLink, createWSClient } from "@trpc/client";

305

306

const wsClient = createWSClient({

307

url: "ws://localhost:3001",

308

});

309

310

// Monitor connection state

311

wsClient.connectionState.subscribe({

312

next: (state) => {

313

switch (state.type) {

314

case 'connecting':

315

console.log("Connecting to WebSocket...");

316

showConnectingIndicator(true);

317

break;

318

case 'open':

319

console.log("WebSocket connected");

320

showConnectingIndicator(false);

321

break;

322

case 'closed':

323

console.log("WebSocket disconnected");

324

showOfflineIndicator(true);

325

break;

326

case 'error':

327

console.error("WebSocket error:", state.error);

328

handleConnectionError(state.error);

329

break;

330

}

331

},

332

});

333

334

const client = createTRPCClient<AppRouter>({

335

links: [

336

wsLink({

337

client: wsClient,

338

}),

339

],

340

});

341

```

342

343

### Combined HTTP and WebSocket Setup

344

345

Common pattern combining HTTP transport for queries/mutations with WebSocket transport for subscriptions.

346

347

```typescript { .api }

348

import {

349

createTRPCClient,

350

httpBatchLink,

351

wsLink,

352

splitLink,

353

createWSClient

354

} from "@trpc/client";

355

```

356

357

**Combined Setup Examples:**

358

359

```typescript

360

// Split transport based on operation type

361

const wsClient = createWSClient({

362

url: "ws://localhost:3001",

363

});

364

365

const client = createTRPCClient<AppRouter>({

366

links: [

367

splitLink({

368

condition: (op) => op.type === 'subscription',

369

true: wsLink({

370

client: wsClient,

371

}),

372

false: httpBatchLink({

373

url: "http://localhost:3000/trpc",

374

}),

375

}),

376

],

377

});

378

379

// Use queries/mutations over HTTP, subscriptions over WebSocket

380

const user = await client.user.getById.query({ id: 1 }); // HTTP

381

const newUser = await client.user.create.mutate({ name: "Alice" }); // HTTP

382

383

const unsubscribe = client.posts.onUpdate.subscribe(undefined, { // WebSocket

384

onData: (post) => console.log("Post updated:", post),

385

});

386

```

387

388

### Error Handling

389

390

WebSocket connections provide specific error handling for connection and communication issues.

391

392

```typescript { .api }

393

// WebSocket-specific error handling

394

const wsClient = createWSClient({

395

url: "ws://localhost:3001",

396

onError: (event) => {

397

console.error("WebSocket connection error:", event);

398

399

// Handle specific error scenarios

400

if (event?.type === 'error') {

401

// Network error, server down, etc.

402

showRetryPrompt();

403

}

404

},

405

onClose: (cause) => {

406

if (cause?.code === 1006) {

407

// Abnormal closure - network issue

408

console.log("Unexpected disconnection, will retry");

409

} else if (cause?.code === 1000) {

410

// Normal closure

411

console.log("Connection closed normally");

412

}

413

},

414

});

415

```

416

417

**Subscription Error Handling:**

418

419

```typescript

420

const unsubscribe = client.posts.onUpdate.subscribe(undefined, {

421

onData: (post) => {

422

updateUI(post);

423

},

424

onError: (err) => {

425

if (err instanceof TRPCClientError) {

426

// Server-side subscription error

427

console.error("Subscription error:", err.message);

428

handleSubscriptionError(err);

429

} else {

430

// Connection-level error

431

console.error("Connection error:", err);

432

handleConnectionError(err);

433

}

434

},

435

onConnectionStateChange: (state) => {

436

if (state.type === 'error') {

437

console.error("Connection state error:", state.error);

438

// Attempt manual reconnection or show error UI

439

}

440

},

441

});

442

```