or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

push.mddocs/

0

# Push Operations

1

2

Push mechanism for sending messages to channels with delivery status tracking and timeout handling, enabling reliable message delivery confirmation.

3

4

## Capabilities

5

6

### Push Constructor

7

8

Creates a new Push instance for sending messages with status tracking.

9

10

```typescript { .api }

11

/**

12

* Creates a new Push instance for sending messages with status tracking

13

* @param channel - Channel to send message through

14

* @param event - Event name for the message

15

* @param payload - Message payload object

16

* @param timeout - Timeout in milliseconds for the push operation

17

*/

18

constructor(channel: Channel, event: string, payload: object, timeout: number);

19

```

20

21

**Note:** Push instances are typically created through `channel.push()` rather than directly constructing them.

22

23

### Message Sending

24

25

Send and resend push messages.

26

27

```typescript { .api }

28

/**

29

* Send the push message

30

*/

31

send(): void;

32

33

/**

34

* Resend the push message with a new timeout

35

* @param timeout - New timeout value in milliseconds

36

*/

37

resend(timeout: number): void;

38

```

39

40

**Usage Example:**

41

42

```typescript

43

import { Channel, Socket } from "phoenix";

44

45

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

46

const channel = socket.channel("room:lobby");

47

48

// Create push through channel (recommended)

49

const push = channel.push("new_message", {

50

body: "Hello, Phoenix!",

51

user_id: 123

52

}, 5000);

53

54

// Send immediately (usually not needed as channel.push() sends automatically)

55

push.send();

56

57

// Resend with longer timeout if needed

58

push.resend(10000);

59

```

60

61

### Status Handling

62

63

Register callbacks for different push response statuses.

64

65

```typescript { .api }

66

/**

67

* Register callback for specific push status

68

* @param status - Push status to handle ("ok", "error", or "timeout")

69

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

70

* @returns Push instance for chaining

71

*/

72

receive(status: PushStatus, callback: (response?: any) => any): this;

73

74

type PushStatus = "ok" | "error" | "timeout";

75

```

76

77

**Usage Example:**

78

79

```typescript

80

// Chain status handlers

81

channel.push("create_post", {

82

title: "My Post",

83

content: "Post content here..."

84

})

85

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

86

console.log("Post created successfully:", response.post);

87

// Navigate to new post

88

window.location.href = `/posts/${response.post.id}`;

89

})

90

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

91

console.error("Failed to create post:", errors);

92

// Show validation errors to user

93

displayErrors(errors);

94

})

95

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

96

console.warn("Post creation timed out");

97

// Show retry option to user

98

showRetryDialog();

99

});

100

```

101

102

## Advanced Usage Patterns

103

104

### Error Handling with Retry Logic

105

106

```typescript

107

function sendMessageWithRetry(channel: Channel, event: string, payload: object, maxRetries = 3) {

108

let attempts = 0;

109

110

function attempt(): Promise<any> {

111

return new Promise((resolve, reject) => {

112

attempts++;

113

114

channel.push(event, payload, 5000)

115

.receive("ok", resolve)

116

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

117

if (attempts < maxRetries) {

118

console.log(`Attempt ${attempts} failed, retrying...`);

119

setTimeout(() => {

120

attempt().then(resolve).catch(reject);

121

}, 1000 * attempts); // Exponential backoff

122

} else {

123

reject(new Error(`Failed after ${maxRetries} attempts: ${JSON.stringify(errors)}`));

124

}

125

})

126

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

127

if (attempts < maxRetries) {

128

console.log(`Attempt ${attempts} timed out, retrying...`);

129

setTimeout(() => {

130

attempt().then(resolve).catch(reject);

131

}, 1000 * attempts);

132

} else {

133

reject(new Error(`Timed out after ${maxRetries} attempts`));

134

}

135

});

136

});

137

}

138

139

return attempt();

140

}

141

142

// Usage

143

sendMessageWithRetry(channel, "important_action", { data: "critical" })

144

.then(result => console.log("Success:", result))

145

.catch(error => console.error("Final failure:", error));

146

```

147

148

### Status-based Flow Control

149

150

```typescript

151

function handleFormSubmission(channel: Channel, formData: object) {

152

const submitButton = document.getElementById("submit-btn") as HTMLButtonElement;

153

const errorDiv = document.getElementById("errors") as HTMLDivElement;

154

const successDiv = document.getElementById("success") as HTMLDivElement;

155

156

// Disable submit button during request

157

submitButton.disabled = true;

158

submitButton.textContent = "Submitting...";

159

160

channel.push("form_submit", formData, 10000)

161

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

162

// Success handling

163

successDiv.style.display = "block";

164

successDiv.textContent = "Form submitted successfully!";

165

errorDiv.style.display = "none";

166

167

// Reset form

168

(document.getElementById("form") as HTMLFormElement).reset();

169

})

170

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

171

// Error handling

172

errorDiv.style.display = "block";

173

errorDiv.innerHTML = "";

174

175

// Display validation errors

176

Object.entries(errors).forEach(([field, messages]) => {

177

const errorItem = document.createElement("div");

178

errorItem.textContent = `${field}: ${(messages as string[]).join(", ")}`;

179

errorDiv.appendChild(errorItem);

180

});

181

182

successDiv.style.display = "none";

183

})

184

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

185

// Timeout handling

186

errorDiv.style.display = "block";

187

errorDiv.textContent = "Request timed out. Please try again.";

188

successDiv.style.display = "none";

189

});

190

191

// Always re-enable submit button

192

setTimeout(() => {

193

submitButton.disabled = false;

194

submitButton.textContent = "Submit";

195

}, 1000);

196

}

197

```

198

199

### Promise-based Push Wrapper

200

201

```typescript

202

function pushPromise(channel: Channel, event: string, payload: object, timeout = 5000): Promise<any> {

203

return new Promise((resolve, reject) => {

204

channel.push(event, payload, timeout)

205

.receive("ok", resolve)

206

.receive("error", reject)

207

.receive("timeout", () => reject(new Error("Push operation timed out")));

208

});

209

}

210

211

// Usage with async/await

212

async function createUser(channel: Channel, userData: object) {

213

try {

214

const response = await pushPromise(channel, "create_user", userData, 8000);

215

console.log("User created:", response.user);

216

return response.user;

217

} catch (error) {

218

console.error("Failed to create user:", error);

219

throw error;

220

}

221

}

222

```

223

224

### Batch Operations with Status Tracking

225

226

```typescript

227

async function batchOperations(channel: Channel, operations: Array<{event: string, payload: object}>) {

228

const results = [];

229

const errors = [];

230

231

for (const [index, operation] of operations.entries()) {

232

try {

233

const result = await new Promise((resolve, reject) => {

234

channel.push(operation.event, operation.payload, 5000)

235

.receive("ok", resolve)

236

.receive("error", reject)

237

.receive("timeout", () => reject(new Error("Timeout")));

238

});

239

240

results.push({ index, result });

241

} catch (error) {

242

errors.push({ index, error, operation });

243

}

244

}

245

246

return { results, errors };

247

}

248

249

// Usage

250

const operations = [

251

{ event: "create_post", payload: { title: "Post 1" } },

252

{ event: "create_post", payload: { title: "Post 2" } },

253

{ event: "update_user", payload: { name: "Updated Name" } }

254

];

255

256

batchOperations(channel, operations)

257

.then(({ results, errors }) => {

258

console.log(`Completed ${results.length} operations successfully`);

259

if (errors.length > 0) {

260

console.error(`${errors.length} operations failed:`, errors);

261

}

262

});

263

```

264

265

### Push Status Monitoring

266

267

```typescript

268

class PushMonitor {

269

private activePushes: Map<string, { push: Push, startTime: number }> = new Map();

270

271

track(id: string, channel: Channel, event: string, payload: object, timeout = 5000) {

272

const startTime = Date.now();

273

const push = channel.push(event, payload, timeout);

274

275

this.activePushes.set(id, { push, startTime });

276

277

push

278

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

279

this.complete(id, "ok", response);

280

})

281

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

282

this.complete(id, "error", errors);

283

})

284

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

285

this.complete(id, "timeout", null);

286

});

287

288

return push;

289

}

290

291

private complete(id: string, status: PushStatus, response: any) {

292

const entry = this.activePushes.get(id);

293

if (entry) {

294

const duration = Date.now() - entry.startTime;

295

console.log(`Push ${id} completed with status ${status} in ${duration}ms`);

296

this.activePushes.delete(id);

297

}

298

}

299

300

getActivePushes(): string[] {

301

return Array.from(this.activePushes.keys());

302

}

303

304

getActivePushCount(): number {

305

return this.activePushes.size;

306

}

307

}

308

309

// Usage

310

const monitor = new PushMonitor();

311

312

monitor.track("post-creation", channel, "create_post", {

313

title: "My New Post",

314

content: "Post content..."

315

});

316

317

console.log("Active pushes:", monitor.getActivePushCount());

318

```