TypeScript definitions for Phoenix JavaScript client library enabling real-time WebSocket communication with Phoenix Framework applications
Channel-based messaging system for subscribing to topics and exchanging real-time messages with Phoenix applications, including join/leave lifecycle and event handling.
Creates a new Channel instance for a specific topic.
/**
* Creates a new Channel instance for a specific topic
* @param topic - Channel topic string (e.g., "room:lobby", "user:123")
* @param params - Channel parameters (static object or dynamic function)
* @param socket - Socket instance (optional, can be set later)
*/
constructor(topic: string, params?: object | (() => object), socket?: Socket);Usage Example:
import { Channel, Socket } from "phoenix";
const socket = new Socket("/socket");
// Static parameters
const lobbyChannel = new Channel("room:lobby", { user_id: 123 });
// Dynamic parameters
const userChannel = new Channel("user:456", () => ({
token: getCurrentUserToken(),
timestamp: Date.now()
}));
// With socket
const chatChannel = new Channel("chat:general", { role: "member" }, socket);Access channel state and topic information.
/**
* Current channel state
*/
readonly state: ChannelState;
/**
* Channel topic string
*/
readonly topic: string;
type ChannelState = "closed" | "errored" | "joined" | "joining" | "leaving";Usage Example:
console.log("Channel topic:", channel.topic);
console.log("Channel state:", channel.state);
// Check if channel is ready for messages
if (channel.state === "joined") {
channel.push("new_message", { body: "Hello!" });
}Join and leave channels with timeout handling.
/**
* Join the channel
* @param timeout - Join timeout in milliseconds (optional)
* @returns Push instance for handling join response
*/
join(timeout?: number): Push;
/**
* Leave the channel
* @param timeout - Leave timeout in milliseconds (optional)
* @returns Push instance for handling leave response
*/
leave(timeout?: number): Push;Usage Example:
// Basic join
channel.join()
.receive("ok", (response) => {
console.log("Joined successfully:", response);
})
.receive("error", (response) => {
console.error("Failed to join:", response);
})
.receive("timeout", () => {
console.warn("Join timed out");
});
// Join with custom timeout (5 seconds)
channel.join(5000)
.receive("ok", ({ messages }) => {
console.log("Catching up on messages:", messages);
});
// Leave channel
channel.leave()
.receive("ok", () => {
console.log("Left channel successfully");
});Register and remove event listeners for channel messages.
/**
* Register event handler for channel messages
* @param event - Event name to listen for
* @param callback - Function to call when event is received
* @returns Reference number for removing handler
*/
on(event: string, callback: (response?: any) => void | Promise<void>): number;
/**
* Remove event handler
* @param event - Event name
* @param ref - Handler reference number (optional)
*/
off(event: string, ref?: number): void;Usage Example:
// Listen for messages
const messageHandler = channel.on("new_message", (payload) => {
console.log("New message:", payload.body);
console.log("From user:", payload.user);
});
// Listen for user events
const joinHandler = channel.on("user_joined", async (payload) => {
console.log("User joined:", payload.user.name);
await updateUserList(payload.user);
});
// Remove specific handler
channel.off("new_message", messageHandler);
// Remove all handlers for an event
channel.off("user_joined");Send messages to the channel with status handling.
/**
* Send message to channel
* @param event - Event name
* @param payload - Message payload object
* @param timeout - Send timeout in milliseconds (optional)
* @returns Push instance for handling response
*/
push(event: string, payload: object, timeout?: number): Push;Usage Example:
// Send basic message
channel.push("new_message", {
body: "Hello, world!",
user_id: 123
})
.receive("ok", (response) => {
console.log("Message sent:", response);
})
.receive("error", (reasons) => {
console.error("Send failed:", reasons);
});
// Send with timeout
channel.push("file_upload", {
filename: "document.pdf",
size: 1024000
}, 10000) // 10 second timeout
.receive("ok", ({ upload_url }) => {
console.log("Upload URL received:", upload_url);
})
.receive("timeout", () => {
console.warn("Upload request timed out");
});
// Send and chain multiple status handlers
channel.push("update_profile", {
name: "John Doe",
email: "john@example.com"
})
.receive("ok", (profile) => {
console.log("Profile updated:", profile);
showSuccessMessage("Profile saved!");
})
.receive("error", ({ errors }) => {
console.error("Validation errors:", errors);
showErrorMessage(errors);
})
.receive("timeout", () => {
showWarningMessage("Request timed out, please try again");
});Register handlers for channel lifecycle events.
/**
* Register callback for channel close events
* @param callback - Function to call when channel closes
* @returns Reference number for removing handler
*/
onClose(callback: (payload: any, ref: any, joinRef: any) => void | Promise<void>): number;
/**
* Register callback for channel error events
* @param callback - Function to call when channel errors occur
* @returns Reference number for removing handler
*/
onError(callback: (reason?: any) => void | Promise<void>): number;
/**
* Handle incoming messages (low-level message processing)
* @param event - Event name
* @param payload - Message payload
* @param ref - Message reference
* @returns Processed message result
*/
onMessage(event: string, payload: any, ref: any): any;Usage Example:
// Handle channel close
const closeHandler = channel.onClose((payload, ref, joinRef) => {
console.log("Channel closed:", payload);
console.log("Close ref:", ref);
console.log("Join ref:", joinRef);
// Cleanup or redirect user
showMessage("Connection to room lost");
});
// Handle channel errors
const errorHandler = channel.onError(async (reason) => {
console.error("Channel error:", reason);
// Attempt to rejoin after error
try {
await new Promise(resolve => setTimeout(resolve, 1000));
channel.join();
} catch (error) {
console.error("Failed to rejoin channel:", error);
}
});
// Custom message processing
channel.onMessage = (event, payload, ref) => {
// Log all messages
console.log(`Message [${event}]:`, payload);
// Custom processing logic
if (event === "custom_event") {
return { processed: true, payload };
}
// Return original payload for default processing
return payload;
};
// Remove lifecycle handlers when done
channel.off("phx_close", closeHandler);
channel.off("phx_error", errorHandler);// Monitor channel state changes
function monitorChannelState(channel: Channel) {
const checkState = () => {
switch (channel.state) {
case "joining":
console.log("Channel is joining...");
break;
case "joined":
console.log("Channel is active");
break;
case "leaving":
console.log("Channel is leaving...");
break;
case "closed":
console.log("Channel is closed");
break;
case "errored":
console.log("Channel has errors");
break;
}
};
// Check state periodically
const interval = setInterval(checkState, 1000);
// Cleanup
channel.onClose(() => clearInterval(interval));
}// Automatic rejoin on error with exponential backoff
function setupAutoRejoin(channel: Channel) {
let rejoinAttempts = 0;
const maxAttempts = 5;
channel.onError(async () => {
if (rejoinAttempts < maxAttempts) {
const delay = Math.pow(2, rejoinAttempts) * 1000; // Exponential backoff
rejoinAttempts++;
console.log(`Rejoining in ${delay}ms (attempt ${rejoinAttempts})`);
await new Promise(resolve => setTimeout(resolve, delay));
channel.join()
.receive("ok", () => {
rejoinAttempts = 0; // Reset on success
});
} else {
console.error("Max rejoin attempts exceeded");
}
});
}Install with Tessl CLI
npx tessl i tessl/npm-types--phoenix