Challenge 2: Broadcast a "Left" Presence Event — Possible Solution ==================================================================== function leaveRoom(socket, roomName) { const members = rooms.get(roomName); if (!members) return; members.delete(socket); socket.rooms.delete(roomName); // Broadcast to whoever is STILL in the room after this socket has // already been removed from it. sendToRoom(roomName, JSON.stringify({ type: "presence", event: "left", userId: socket.userId })); } WHY THIS WORKS -------------- - members.delete(socket) and socket.rooms.delete(roomName) both happen BEFORE sendToRoom() is called — this ordering matters: sendToRoom() reads whoever is currently in the room's Set, and the departing socket should not be one of the recipients of its own "left" announcement. - Reusing sendToRoom() (rather than writing a separate broadcast loop here) means this "left" event gets the exact same readyState-checked, safe-broadcast behavior as every other message sent to the room — one broadcast implementation, used consistently everywhere a room needs to be notified of something. - The message shape — { type: "presence", event: "left", userId } — deliberately mirrors the "joined" event's shape from the chapter (only the event field differs). This consistency matters on the client side: a single presence-handling function can switch on event ("joined" vs "left") rather than needing entirely separate message formats for the two cases. - If members is undefined (the room never existed, or was already fully cleaned up), the function returns early — there's nothing to remove and no one left in a nonexistent room to notify, so this guards against calling .delete() on undefined or broadcasting to a room with no Set. - Note that by the time this runs, socket.userId still holds a valid value even though the socket has just been removed from the room — deleting from a Set doesn't erase properties on the socket object itself, so the announcement can still correctly identify who left.