Challenge 1: Add a "Leave Room" Message Type — Possible Solution ==================================================================== socket.on("message", (raw) => { let data; try { data = JSON.parse(raw.toString()); } catch { return; } if (!validateChatMessage(data)) return; if (data.type === "join") { joinRoom(socket, data.roomName); } if (data.type === "leave") { leaveRoom(socket, data.roomName); // explicit leave, not waiting for close } if (data.type === "chat") { sendToRoom(data.roomName, JSON.stringify({ type: "chat", userId: socket.userId, text: data.text })); } }); // validateChatMessage would also need to accept "leave" as a valid type // alongside "join" and "chat", still requiring a valid roomName field. WHY THIS WORKS -------------- - The new "leave" branch calls the EXACT SAME leaveRoom(socket, roomName) function from Chapter 6 that the "close" event handler already calls — there's no separate "leave" implementation to write, just a new message type that triggers the existing function explicitly, while the user is still connected. - This matters because a user might want to leave one specific room while staying connected overall (e.g. switching from the "lobby" room to a "support" room) — relying only on the close event's cleanup would mean the only way to leave a room is to disconnect entirely, which isn't how a real multi-room chat feature typically behaves. - leaveRoom already handles removing the socket from BOTH the room's Set and the socket's own socket.rooms tracking Set (Chapter 6) — so after an explicit "leave" message, the close handler's cleanup loop (which iterates socket.rooms) correctly no longer includes that room, since it was already removed here. - Both the new "leave" branch and the existing "join"/"chat" branches still run through the same validateChatMessage(data) check before any of this logic executes — the new message type doesn't bypass the shape-validation step this course's security chapter established for every incoming message, regardless of type.