or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

channel.mdindex.mdpresence.mdpush.mdsocket.mdutilities.md

channel.mddocs/

0

# Channel Communication

1

2

Channel-based messaging system for subscribing to topics and exchanging real-time messages with Phoenix applications, including join/leave lifecycle and event handling.

3

4

## Capabilities

5

6

### Channel Constructor

7

8

Creates a new Channel instance for a specific topic.

9

10

```typescript { .api }

11

/**

12

* Creates a new Channel instance for a specific topic

13

* @param topic - Channel topic string (e.g., "room:lobby", "user:123")

14

* @param params - Channel parameters (static object or dynamic function)

15

* @param socket - Socket instance (optional, can be set later)

16

*/

17

constructor(topic: string, params?: object | (() => object), socket?: Socket);

18

```

19

20

**Usage Example:**

21

22

```typescript

23

import { Channel, Socket } from "phoenix";

24

25

const socket = new Socket("/socket");

26

27

// Static parameters

28

const lobbyChannel = new Channel("room:lobby", { user_id: 123 });

29

30

// Dynamic parameters

31

const userChannel = new Channel("user:456", () => ({

32

token: getCurrentUserToken(),

33

timestamp: Date.now()

34

}));

35

36

// With socket

37

const chatChannel = new Channel("chat:general", { role: "member" }, socket);

38

```

39

40

### Channel Properties

41

42

Access channel state and topic information.

43

44

```typescript { .api }

45

/**

46

* Current channel state

47

*/

48

readonly state: ChannelState;

49

50

/**

51

* Channel topic string

52

*/

53

readonly topic: string;

54

55

type ChannelState = "closed" | "errored" | "joined" | "joining" | "leaving";

56

```

57

58

**Usage Example:**

59

60

```typescript

61

console.log("Channel topic:", channel.topic);

62

console.log("Channel state:", channel.state);

63

64

// Check if channel is ready for messages

65

if (channel.state === "joined") {

66

channel.push("new_message", { body: "Hello!" });

67

}

68

```

69

70

### Channel Lifecycle

71

72

Join and leave channels with timeout handling.

73

74

```typescript { .api }

75

/**

76

* Join the channel

77

* @param timeout - Join timeout in milliseconds (optional)

78

* @returns Push instance for handling join response

79

*/

80

join(timeout?: number): Push;

81

82

/**

83

* Leave the channel

84

* @param timeout - Leave timeout in milliseconds (optional)

85

* @returns Push instance for handling leave response

86

*/

87

leave(timeout?: number): Push;

88

```

89

90

**Usage Example:**

91

92

```typescript

93

// Basic join

94

channel.join()

95

.receive("ok", (response) => {

96

console.log("Joined successfully:", response);

97

})

98

.receive("error", (response) => {

99

console.error("Failed to join:", response);

100

})

101

.receive("timeout", () => {

102

console.warn("Join timed out");

103

});

104

105

// Join with custom timeout (5 seconds)

106

channel.join(5000)

107

.receive("ok", ({ messages }) => {

108

console.log("Catching up on messages:", messages);

109

});

110

111

// Leave channel

112

channel.leave()

113

.receive("ok", () => {

114

console.log("Left channel successfully");

115

});

116

```

117

118

### Event Handling

119

120

Register and remove event listeners for channel messages.

121

122

```typescript { .api }

123

/**

124

* Register event handler for channel messages

125

* @param event - Event name to listen for

126

* @param callback - Function to call when event is received

127

* @returns Reference number for removing handler

128

*/

129

on(event: string, callback: (response?: any) => void | Promise<void>): number;

130

131

/**

132

* Remove event handler

133

* @param event - Event name

134

* @param ref - Handler reference number (optional)

135

*/

136

off(event: string, ref?: number): void;

137

```

138

139

**Usage Example:**

140

141

```typescript

142

// Listen for messages

143

const messageHandler = channel.on("new_message", (payload) => {

144

console.log("New message:", payload.body);

145

console.log("From user:", payload.user);

146

});

147

148

// Listen for user events

149

const joinHandler = channel.on("user_joined", async (payload) => {

150

console.log("User joined:", payload.user.name);

151

await updateUserList(payload.user);

152

});

153

154

// Remove specific handler

155

channel.off("new_message", messageHandler);

156

157

// Remove all handlers for an event

158

channel.off("user_joined");

159

```

160

161

### Message Sending

162

163

Send messages to the channel with status handling.

164

165

```typescript { .api }

166

/**

167

* Send message to channel

168

* @param event - Event name

169

* @param payload - Message payload object

170

* @param timeout - Send timeout in milliseconds (optional)

171

* @returns Push instance for handling response

172

*/

173

push(event: string, payload: object, timeout?: number): Push;

174

```

175

176

**Usage Example:**

177

178

```typescript

179

// Send basic message

180

channel.push("new_message", {

181

body: "Hello, world!",

182

user_id: 123

183

})

184

.receive("ok", (response) => {

185

console.log("Message sent:", response);

186

})

187

.receive("error", (reasons) => {

188

console.error("Send failed:", reasons);

189

});

190

191

// Send with timeout

192

channel.push("file_upload", {

193

filename: "document.pdf",

194

size: 1024000

195

}, 10000) // 10 second timeout

196

.receive("ok", ({ upload_url }) => {

197

console.log("Upload URL received:", upload_url);

198

})

199

.receive("timeout", () => {

200

console.warn("Upload request timed out");

201

});

202

203

// Send and chain multiple status handlers

204

channel.push("update_profile", {

205

name: "John Doe",

206

email: "john@example.com"

207

})

208

.receive("ok", (profile) => {

209

console.log("Profile updated:", profile);

210

showSuccessMessage("Profile saved!");

211

})

212

.receive("error", ({ errors }) => {

213

console.error("Validation errors:", errors);

214

showErrorMessage(errors);

215

})

216

.receive("timeout", () => {

217

showWarningMessage("Request timed out, please try again");

218

});

219

```

220

221

### Lifecycle Event Handlers

222

223

Register handlers for channel lifecycle events.

224

225

```typescript { .api }

226

/**

227

* Register callback for channel close events

228

* @param callback - Function to call when channel closes

229

* @returns Reference number for removing handler

230

*/

231

onClose(callback: (payload: any, ref: any, joinRef: any) => void | Promise<void>): number;

232

233

/**

234

* Register callback for channel error events

235

* @param callback - Function to call when channel errors occur

236

* @returns Reference number for removing handler

237

*/

238

onError(callback: (reason?: any) => void | Promise<void>): number;

239

240

/**

241

* Handle incoming messages (low-level message processing)

242

* @param event - Event name

243

* @param payload - Message payload

244

* @param ref - Message reference

245

* @returns Processed message result

246

*/

247

onMessage(event: string, payload: any, ref: any): any;

248

```

249

250

**Usage Example:**

251

252

```typescript

253

// Handle channel close

254

const closeHandler = channel.onClose((payload, ref, joinRef) => {

255

console.log("Channel closed:", payload);

256

console.log("Close ref:", ref);

257

console.log("Join ref:", joinRef);

258

259

// Cleanup or redirect user

260

showMessage("Connection to room lost");

261

});

262

263

// Handle channel errors

264

const errorHandler = channel.onError(async (reason) => {

265

console.error("Channel error:", reason);

266

267

// Attempt to rejoin after error

268

try {

269

await new Promise(resolve => setTimeout(resolve, 1000));

270

channel.join();

271

} catch (error) {

272

console.error("Failed to rejoin channel:", error);

273

}

274

});

275

276

// Custom message processing

277

channel.onMessage = (event, payload, ref) => {

278

// Log all messages

279

console.log(`Message [${event}]:`, payload);

280

281

// Custom processing logic

282

if (event === "custom_event") {

283

return { processed: true, payload };

284

}

285

286

// Return original payload for default processing

287

return payload;

288

};

289

290

// Remove lifecycle handlers when done

291

channel.off("phx_close", closeHandler);

292

channel.off("phx_error", errorHandler);

293

```

294

295

## Advanced Usage Patterns

296

297

### Channel State Management

298

299

```typescript

300

// Monitor channel state changes

301

function monitorChannelState(channel: Channel) {

302

const checkState = () => {

303

switch (channel.state) {

304

case "joining":

305

console.log("Channel is joining...");

306

break;

307

case "joined":

308

console.log("Channel is active");

309

break;

310

case "leaving":

311

console.log("Channel is leaving...");

312

break;

313

case "closed":

314

console.log("Channel is closed");

315

break;

316

case "errored":

317

console.log("Channel has errors");

318

break;

319

}

320

};

321

322

// Check state periodically

323

const interval = setInterval(checkState, 1000);

324

325

// Cleanup

326

channel.onClose(() => clearInterval(interval));

327

}

328

```

329

330

### Error Recovery

331

332

```typescript

333

// Automatic rejoin on error with exponential backoff

334

function setupAutoRejoin(channel: Channel) {

335

let rejoinAttempts = 0;

336

const maxAttempts = 5;

337

338

channel.onError(async () => {

339

if (rejoinAttempts < maxAttempts) {

340

const delay = Math.pow(2, rejoinAttempts) * 1000; // Exponential backoff

341

rejoinAttempts++;

342

343

console.log(`Rejoining in ${delay}ms (attempt ${rejoinAttempts})`);

344

345

await new Promise(resolve => setTimeout(resolve, delay));

346

347

channel.join()

348

.receive("ok", () => {

349

rejoinAttempts = 0; // Reset on success

350

});

351

} else {

352

console.error("Max rejoin attempts exceeded");

353

}

354

});

355

}