# Protocol Documentation This is an attempt to document the HTTP and websocket protocol provided by CritterChat's backend and used by CritterChat's frontend. This serves two purposes. First, it allows a high-level overview that hopefully sidesteps some new developer ramp-up time. Second, it hopefully aids in alternative clients being developed without them having to reverse-engineer everything from as-built code. At the high level, communcation between the existing web-based JS client and the backend server is done via [Socket.IO](https://socket.io/) which uses websockets under the hood. Socket.IO presents an event-driven interface which we view as named JSON packets. The various packets, whether they are server or client-originated, what they do, and when you should expect to send or receive them is all documented below. Bulk data transfers such as attachment uploads and downloads are handled using HTTP. This is partially to allow for a CDN or other simple system to handle attachments, and partially due to size limitations of websocket packets. ## Authentication Authentication is not handled by websockets in CritterChat. Instead, there is a POST method that lives at `/login` accepting browser form data which sets a `SessionID` cookie. In the future, I'd like this endpoint to be versatile enough to accept both form data in the post body for browser-based login and JSON in the post body for alternative clients. For now, the important part of this interaction is the `SessionID` cookie that is sent back to the client which should be present on the websocket connection itself. All websocket requests use this cookie to link the websocket session to a logged-in user. If a session is invalidated for any reason, the server will respond to any request with a `reload` packet instructing the client to redo authentication to get a new `SessionID` cookie. ## Configuration Configuration properties relating to the instance as well as the currently logged in user is available at `/chat/config.json`. This includes maximum configured settings for various actions, URLs for default icons, the instance title, upload endpoints and relevant properties of the current user that a client might need to fetch before starting up a websocket. The current web client does not make use of this endpoint as the properties that it would need are embedded into the HTML that it runs in. However, alternative clients will likely need this information. ## Upload Endpoints Data uploads are handled by a series of upload endpoints which take their data as POST bodies. Note that client requests to these endpoints should include the authentication cooke as this allows us to prevent non-authenticated users from uploading arbitrary attachments. Attachments themselves are uploaded using base64 data URLs due to the need for web-based clients to load and display previews of the attachments before uploading. Depending on their purpose they have different ways of handling attachment data and returning an attachmend ID that the client can then use to refer to an attachment when sending a websocket request. Note that all endpoints return JSON representing the results of the request. ### Icon Upload This endpoint lives at `/upload/icon` and expects a text/plain POST body containing a data URL that represents the icon being uploaded. The icon must be of a supported type (png, jpg, gif, apng, webp, bmp), must be at most 512x512 in size, and must be square (width and height match). If all of those properties hold, the icon will be stored in a new attachment ID and returned as the `attachmentid` property of the response JSON. If any of these is violated, this will instead return JSON with the `error` property containing a text description of the error. Note that icons are only used for customizing the icon of a room or 1:1 chat. ### Avatar Upload This endpoint lives at `/upload/avatar`. Note that it has identical expectations and responses as the icon upload. The only difference is that this is used for user avatar customization. ### Notification Sound Upload This endpoint lives at `/upload/notifications` and expects an application/json POST body containing a `notif_sounds` attribute. That `notif_sounds` attribute should point at a JSON object whose keys are the notification being updated and the values are string data URLs that represent the notification sound being uploaded. The sound must be of a supported audio type that FFMPEG can convert and will be converted to an mp3 for broad browser support. Upon successful conversion and storage in the attachment system, a JSON response will be returned containing the same `notif_sounds` attribute. Note that in the response case, any data URL will be swapped out for the attachment ID that was generated when storing the attachment. The keys to the `notif_sounds` JSON object will be identical to the keys in the request. Just like icon and avatar uploads, a failure will cause a JSON response with the `error` string attribute. ### Message Attachment Upload This endpoint lives at `/upload/attachments` and expects an application/json POST body containing an `attachments` attribute. This attribut should point at a list of JSON objects each containing the `filename` and `data` attributes. Additionally and optionally, an `alt_text` string attribute can also be included specifying alt text to store alongside the attachment. Additionally and optionally, a `sensitive` boolean attribute can be included specifying the image is sensitive and should be blurred by default. As you would expect, the `filename` attribute should be the filename of the file being uploaded. Note that the client can send the full path or just the filename with no directory information. In either case, CritterChat strips the directory info off as it does not need it. The `data` attribute should be a string data URL representing the attachment being uploaded. Note that as of right now, only image attachments are supported for upload. The image must be of a supported type (png, jpg, gif, apng, webp, bmp) and must not exceed the network file size for attachments. Upon successful processing of the attachments, a JSON response will be returned containing an `attachments` attribute which is a list of attachment IDs. Note that the order of attachments in the upload request will match the attachment IDs in the response. This might matter if the user has picked a particular image order and described those images in an attached message. Just like the above endpoints, a failure will cause a JSON response with the `error` string attribute. ## Common Data Types The following data types are objects which are found in multiple packets. They are intentionally kept consistent across those packets and are thus documented here. ### profile An object representing a user and their profile. In CritterChat a user profile is a global object with a 1:1 map between users and their profile. Note that many packets will use occupant objects instead of profile objects. Profiles have the following attributes: - `id` - A string identifier unique to the user that was returned. Can be used to uniquely and permanently refer to a user. - `username` - A string representing the user's username, as they would log in and as other users would mention them. - `nickname` - A string representing the user's currently set nickname. If the user has not set this, it will be defaulted to the same value as the `username`. - `about` - A string representing the user's about section. If the user has not set this, it will be defaulted to the empty string. - `icon` - A string URI pointing at the user's currently set icon. If the user has not set this, this will point at the instance default avatar. - `occupantid` - A string occupant ID that should match the occupant ID used to request this profile. Only included when the profile is looked up via occupant ID and not via user ID. - `moderator` - A boolean representing whether this user is a moderator in the room they belong to. Only included when the profile is looked up via occupant ID, and in that case the flag is relative to the room the occupant exists in. - `muted` - A boolean representing whether this user is muted in the room they belong to. Only included when the profile is looked up via occupant ID, and in that case the flag is relative to the room the occupant exists in. - `invite` - An invite object representing whether this user has a pending invite to the room they are being looked up on behalf of. Only included when the profile is looked up via occupant ID, and in that case the invite is relative to the room the occupant exists in. - `inactive` - A boolean representing whether this user is inactive (true) or if they are active (false). Inactive users are those who have been deactivated by an administrator after they've joined a room. - `full_username` - A string representing the user's username including the instance domain. Not currently used, but will be relevant once 1:1 message federation exists. - `permissions` - A list of strings representing a permission that the user has granted to them. Only returned in the case that the currently logged in user making the request is an instance admin. That means if the currently logged in user is an instance admin, all profile lookups will include this. ### room An object representing a room. In CritterChat a room is an object that zero or more occupants can be joined to. All users who are joined to a room can request various things about the room and are sent updates that occur to the room such as chat messages sent, joins, leaves, and the like. Rooms have the following attributes: - `id` - A string identifier unique to the room. Can be used to uniquely and permanently refer to a room. - `type` - A string representing the type of the room. Public chat rooms are identified with "room" and private group chats, 1:1 chats and chats with onself are identified with "chat". - `name` - A string representing the current display name of the room from the requesting user's perspective. For a given 1:1 chat that hasn't had a custom name applied, this will always be set to "Chat with XXX" where XXX is the display name of the other chatter. If a custom name has been set, this will be set to that custom name. - `customname` - A string representing the custom name for this room. If a custom name has not been set, this will be an empty string. Clients should use this when allowing users to edit a room name instead of the `name` attribute above. - `topic` - A string representing the topic of the room. If a topic is not set, this will be an empty string. - `public` - A boolean representing whether this room is public or private. Public rooms are visible in search even when a user isn't joined to a room. Private rooms require an invite. - `moderated` - A boolean representing whether this room is moderated or free-for-all. Moderated rooms require a moderator to update info, and allow moderators to mute users. Free-for-all rooms allow anyone to update room info, though an administrator can still mute users. - `autojoin` - A boolean representing whether this room is an auto-join room or not. Auto-join rooms are joined by new users automatically. Rooms that are not auto-join need to be explicitly joined by users. - `oldest_action` - A string identifier pointing at the very first action in the room, referring to that action by its unique identifier. A client can infer that it has all actions in a room by checking to see if it has received the action identified by this string identifier. This is useful for determining if there is any additional scrollback to request. - `newest_action` - A string identifier pointing at the very last action in the room, referring to that action by its unique identifier. A client can infer that it has all actions in a room by checking to see if it has received the action identified by this string identifier. This is useful for determining if there are any newer messages that were missed during a disconnect. - `last_action_timestamp` - An integer unix timestamp representing the last action of this room. Rooms which have been modified more recently will have a larger integer than rooms which were modified further back in time. This will match the timestamp of the most recent action associated with a room. - `icon` - A string URI pointing at an icon resource for the room. In the case that a room does not have an icon set, this will be set to the instance default room icon. - `deficon` - A string URI pointing at the default room icon for this room based on instance configuration. Clients can use this to display a preview when a user chooses to unset a custom icon. ### occupant An occupant who is or was joined to a room. In CritterChat, all rooms have zero or more occupants. There is a 1:1 mapping between users on an instance and an occupant for a given room. The only reason why there is an occupant object instead of referring directly to user objects is because CritterChat supports per-room user customizations. Occupants have the following attributes: - `id` - A string identifier unique to the occupant. Can be used to uniquely and permanently refer to an occupant. Even if a user leaves a room and then rejoins later, the ID remains the same. - `userid` - A string identifier that uniquely identifies the user behind this occupant. Can be used to uniquely and permanently refer to the user itself when fetching profile information and the like. - `username` - A string representing the occupant's username, as they would log in and as other occupants of a room would mention them. - `nickname` - A string representing the occupant's currently set nickname for this room. If the user has not customized a nickname for the room, this defaults to the user's nickname as found in their profile, and if that isn't set defaults to the user's username. - `icon` - A string URI pointing at the user's currently set icon for this room. If the user has not customized an icon for this room, this defaults to the user's configured icon for the instance. If that is not set, the default user avatar will be returned here instead. - `present` - A boolean representing whether this occupant is in the room (true) or not (false). This is useful because clients need to render names for users who have left when showing their actions in chat history, but need to show only present uesrs in the room's user list. - `inactive` - A boolean representing whether this occupant is inactive (true) or if they are active (false). Inactive users are those who have been deactivated by an administrator after they've joined a room. - `moderator` - A boolean representing whether this occupant is a moderator (true) or not (false) in the room this occupant belongs to. Moderators can edit room info and mute users in rooms that are marked as moderated. - `muted` - A boolean representing whether this occupant is muted (true) or unmuted (false) in the room this occupant belongs to. Muted users cannot edit room info or send messages to the room. - `invite` - An invite object representing an invite to the room this occupant is found in. For joined occupants, this will always be `null`. For occupants that have not joined but are invited, this will represent the pending invite to the room. Note that an occupant will never have a valid invite when they are present in a room. ### invite An invite to a particular room for a particular occupant. In CritterChat, private conversations are invite-only. So, when somebody is invited to the room they get added as an occupant with the `present` boolean set to false, and they are issued an invite that is found on the occupant object itself. Invites have the following attributes: - `id` - A string identifier unique to the invite. Can be used to uniquely and permanently refer to a specific invite. Even if the invite is cancelled and later re-issued, the ID remains the same. - `user` - A profile object representing the user who sent the invite. This is a profile object and not an occupant object because invites can be attached to occupants, but can also be returned standalone depending on the request to the server. Clients wishing to match an invite user to a current room occupant can do so by comparing the occupant object's `userid` against this profile object's `id`. - `timestamp` - An integer unix timestamp representing when the invite was issued. - `room` - A room object representing the room that this invite was issued for. Note that this can be null when an invite is attached to an occupant since the room is already known at this point. - `cancellable` - A boolean representing whether the current user can (true) or cannot (false) cancel the invite. Invites are only cancellable by the issuer during the first 72 hours, and then they become cancellable by anyone else in the conversation. - `active` - A boolean representing whether the recipient of the invite has dismissed the invite (false) or the invite is still visible and badged (true). Note that this is not present on invites attached to occupants for privacy reasons. - `seen` - A boolean representing whether the recipient of the invite has seen the invite (true) or has not seen the invite (false). Clients can use this to determine if an invite has been clicked on, but not accepted or dismissed. Note that this is not present on invites attached to occupants for privacy reasons. ### attachment An attachment, such as an image or a downloadable file. Actions can have zero or more attachments associated with them. Attachments have the following attributes: - `uri` - A string URI where a browser or HTTP client can download the attachment from. - `mimetype` - The mime type or content type of the attachment itself. Useful for clients that wish to display different types of attachments differently. - `metadata` - A JSON object containing metadata about the attachment. For images, this includes the `width` and `height` attributes which represent the image's width and height after accounting for image orientation. For all attachments, an optional `alt_text` attribute can be present which is a string representing alt text for the attachment. For all attachments, an optional `sensitive` attribute can be present which is a boolean representing if the attachment is sensitive and the preview should be blurred by default. - `preview` - A string preview of the attachment, if it is available. Right now this is only present on text attachments (attachments that have a mimetype starting with `text/`) and will be the contents of the text file for displaying a preview directly in chat. If this is not available or not applicable to the attachment type, this attribute will be left off to save space. - `filename` - A string representing the original upload filename of the attachment, if it is available. If the original filename is not available this attribute will be left off to save space. ### action An object representing an action in a particular room. In CritterChat, actions are performed on behalf of a room occupant and stored in the room. Actions have the following attributes: - `id` - A string identifier unique to this action. Can be used to uniquely and permanently refer to an action. - `timestamp` - An integer unix timestamp representing when the action occurred. - `order` - An opaque integer specifying the action ordering relative to other actions. Effectively this is a monotonically increasing number, so newer actions will have a larger number than older actions. Aside from ordering, clients should refrain from using this attribute. - `occupant` - An occupant object detailing the occupant which performed the action. - `action` - A string representing the action type which occurred. Valid values are currently "message" for messages, "join" for occupants joining the chat, "leave" for occupants leaving the chat, "change_info" when an occupant changes room information such as the topic or name, "change_profile" when an occupant changes their own personal information, "change_users" when one or more users changes attributes such as moderator or muted, "change_message" when a message is changed in some fashion such as editing or modifying reactions, "invite_user" when an occupant invites another user to a room or conversation, and "uninvite_user" when an occupant cancels a pending invite sent to another user for a room or conversation. - `details` - A JSON object that contains different details about the action depending on the action string. For "message" actions, this is an object with the `message` attribute that contains the string message that was sent, optionally the `sensitive` boolean attribute specifying the message is sensitive and should be spoilered by default, and the `reactions` JSON object keyed by emoji/emote text whose value for each key is a list of occupant IDs who chose that reaction. For "join" and "leave" actions, this is normally an empty object since the `occupant` object contains all relevant details, but if the user was added to or removed from a chat by another user, there will be an `actor` string which is the occupant ID of the occupant who took the action. For "change_info" and "change_profile" actions, this is a JSON object containing details of the change. Currently the JS client does not make use of this info outside of the "message" action. For "change_users" actions, this is a JSON object containing an `occupants` attribute which is a list of occupant objects fetched at the time this action is sent to a client. For "change_message" actions, this is a JSON object containing an `actionid` string action ID attribute pointing at the original action that was being modified, an `edited` attribute which is a list of properties of the action modified and additional details about the modification. For "invite_user" actions, this is a JSON object containing an `invited` attribute which is a string occupant ID pointing at a room occupant who was invited. For "uninvite_user" actions, this is a JSON object containing an `uninvited` attribute which is a string occupant ID pointing at a room occupant who had their invite cancelled. - `attachments` - A list of attachment objects representing any attachments that are associated with this action. Note that right now, only `message` actions can have attachments. This is usually an empty list as most messages do not contain any attachments. ### room count An object representing the number of unread notifications for a given room. Room count objects have the following attributes: - `roomid` - A string identifier pointing at a particular room. Will match one of the room objects found in a variety of packets. - `count` - An integer count of the number of unread notifications for the given room. This will always be 0 or a positive integer. ## Client-Initiated Packets The following packets are client-initiated. For each packet, the client request as well as the server response packet are documented together. For all packets that return a response packet with the same name as the request packet, the client can optionally add a `tag` attribute which should be a UUID. The server will ensure that the response packet has a `tag` attribute in the data containing the same UUID that was sent in the request. In this way, a client can match up responses to specific requests if need be. ### profile The `profile` packet is sent from the client to load or refresh a user's profile. This can take an empty request JSON and looks up the profile of the logged in user. Additionally, it can take a JSON request that includes the `userid` attribute. The `userid` can be either a user ID or an occupant ID. In either case that object will be looked up and returned. Note that CritterChat supports custom icon and nickname per-room so if you want to pull up a user's custom profile for a given room you should provide an Occupant ID. If you only care about the user's generic profile you can instead specify a User ID. The server will respond with a `profile` packet with the user's profile in the response JSON. The response JSON will be identical to the profile object documented in the above common data types section. ### preferences The `preferences` packet is sent from the client to load or refresh the current user's preferences. This expects an empty request JSON and looks up the preferences of the logged in user. The server will respond with a `preferences` packet with the user's preferences in the response JSON with the following attributes: - `rooms_on_top` - A boolean representing whether the user wants rooms to always be displayed above conversations (true) or whether rooms and conversations should be sorted by last update (false). - `combined_messages` - A boolean representing whether messages sent right after each other by the same user should be combined into one chat block (true) or left as individual messages (false). - `color_scheme` - A string representing the user's chosen color scheme. Valid values are "light" to force light mode, "dark" to force dark mode, and "system" to let the browser pick based on system settings. - `desktop_size` - A string representing the chosen size of the client when in desktop mode. Valid values are "smallest", "smaller", "normal", "larger" and "largest", defaulting to "normal" if not changed. - `mobile_size` - A string representing the chosen size of the client when in mobile mode. Valid values are "smallest", "smaller", "normal", "larger" and "largest", defaulting to "normal" if not changed. - `admin_controls` A boolean representing whether an instance admin should see admin controls in various spots or not. Only relevant for instance admins. Setting this to true means additional buttons will be available on user profiles and additional settings will be available in the info panel. Setting this to false means additional, admin-only actions will be hidden from the interface. - `title_notifs` - A boolean representing whether the user wants notifications to show up in the tab title (true) or not (false). - `search_privacy` - A string representing the user's chosen search privacy. Valid values are "visible" and "hidden", defaulting to "visible" if not changed. Visible users will show up in "searchrooms" responses. Users who are not visible will not show up in "searchrooms" responses except in the case where a user searches for themselves. - `invite_privacy` - A string representing the user's chosen invite privacy. Valid values are "auto_accept", "choose" and "disallow". Users who choose "disallow" will not show up in "searchusers" responses except in the case where the user is already invited or already present in the room. - `mobile_audio_notifs` - A boolean representing whether the user wants audio notifications on mobile (true) or whether mobile clients should be silent (false). - `tabbable_chat_elements` - A boolean representing whether individual HTML elements in the chat history window should be tabbable (true) or whether the tab order for the client should skip these elements (false). - `audio_notifs` - A list of strings representing which audio notifications are enabled. - `notif_sounds` - A JSON object keyed by audio notification type strings whose values are string URIs pointing at an audio file to play for that given notification. Note that the keys will match the list of strings in the `audio_notifs` list and a user may have notification sounds configured for notifications that they have disabled. ### lastsettings The `lastsettings` packet is sent from the client to load or refresh the current user's last settings for this instance of the client. It expects an empty request JSON and looks up the last settings of the logged in user. Note that settings are stored per-session, meaning if a user logs in on multiple devices, each device gets separate settings. When a user logs out on a device, the settings for that device are lost. When a user logs in on a new device, the last updated settings from any other device for the same user are used to seed the settings for the current session. If no other devices are logged in, the server will create a new settings object with sane defaults. The server will respond with a `lastsettings` packet with the user's per-session settings in the response JSON with the following attributes: - `roomid` - A string representing the room that the user was last in, be it a public or private room or a 1:1 conversation. Clients should make a reasonable effort to place the user into this room upon starting up. Note that if a new settings object is sent to the client from the server, this will still point at a valid room as long as the user is in at least one room. - `info` - A string representing whether the right side info panel is currently visible. Valid values are "shown" for currently visible, and "hidden" for currently hidden. Note that if a new settings object is sent to the client from the server, this will default to "hidden". ### motd The `motd` packet is sent from the client to load or refresh the server message of the day. This expects an empty request JSON and looks up any server message of the day or welcome message depending on the onboarding state of the user. In the future the server may choose to respond with a `motd` packet that should contain a server message of the day which the client can choose to display to the user or make available in a modal. The server will sometimes respond with a `welcome` packet in the case that the user has not finished onboarding onto the instance. The `welcome` packet contains the following attributes in the response JSON: - `name` - A string representing the instance name. - `icon` - A string URL pointing at the instance icon, usually used as a favicon but also displayed next to the instance name in the web client. - `administrator` - A string representing the name, nickname or email of the instance administrator. - `source` - A string URL pointing at the source code for the instance, or null if the instance does not have a source repo. - `message` - A string welcome message that should be displayed to the client. - `rooms` - A list of room objects that the user will be auto-joined to. ### info The `info` packet is sent from the client to load or refresh the server info. This is usually performed to show the user the current details of the running instance. This expects an empty request JSON and looks up the server info before sending it to the client. The server will respond with an `info` packet with the following attributes: - `name` - A string representing the instance name. - `icon` - A string URL pointing at the instance icon, usually used as a favicon but also displayed next to the instance name in the web client. - `administrator` - A string representing the name, nickname or email of the instance administrator. - `source` - A string URL pointing at the source code for the instance, or null if the instance does not have a source repo. - `version` - A string representing the version of the server that is running. For non-production instances, the "+debug" suffix will be appended. For instances that have not been deployed to a virtual environment this will be "development". Note that even for alternate clients, this still represents the server version, but for the web client included in this repo this also represents the client version. - `info` - A HTML string that the instance owner configured which should be displayed to the user. This often includes server background, rules or other information. ### invite The `invite` packet is sent from the client to request an invite link to join the instance be created. This is performed when a user on an instance that has invites enabled wishes to generate a personalized invite URI that they can link to somebody to join the instance. Note that clients can determine that invites are enabled by inspecting the configuration endpoint JSON, specifically the `invitesenabled` boolean attribute. The server will respond with an `invite` packet with the following attributes: - `invite` - A string URL that can be used to sign up for the instance when given to somebody. ### roomlist The `roomlist` packet is sent from the client to load or refresh the list of rooms that the user has currently joined. This expects an empty request JSON and looks up all joined rooms for the current user. The server will respond with a `roomlist` packet with the following attributes: - `rooms` - A list of room objects that the user is joined to. Note that this is sorted by most recent action to least recent action regardless of client preferences. It is up to the client to respect the `rooms_on_top` preference by sorting public rooms on top of private chats. - `counts` - A list of room count objects representing the number of unread actions for a given room. Note that counts are always returned when a `roomlist` packet is sent from the server in response to a `roomlist` request from the client, but not returned when a `roomlist` packet is sent after a user joins or is joined to a room. - `selected` - A string identifier pointing at a room in the `rooms` list that the client should select on behalf of a user. Note that the `selected` attribute is not returned when the client explicitly requests a `roomlist` response from the server, but is returned when the server sends a `roomlist` packet to the client after the user has joined or been joined to a room. When present, the client should attempt to select the room idenfied by the string identifier. When not present, the client should leave the currently selected room alone. ### invites The `invites` packet is sent from the client to load or refresh the list of invites that the user currently has pending. This expects an empty request JSON and looks up all pending invites for the current user. The server will respond with an `invites` packet with the following attributes: - `active` - A list of invite objects that the user has not dismissed. This is determined by looking at the invite's `active` attribute and selecting only those with the value of true. Seen invites that have not been explicitly dismissed will still show up in this list. The invite objects will include the `active` and `seen` attributes as documented in the above common data types section. - `ignored` - A list of invite objects that the user has dismissed. This is determined by looking at the invite's `active` attribute and selecting only those with the value of false. The invite objects will include the `active` and `seen` attributes as documented in the above common data types section. ### chathistory The `chathistory` packet is sent from the client to load history actions for a given room that the user has joined. This expects a request JSON with at least the `roomid` attribute, and optionally a `before` attribute. In both cases it will verify that the user is currently in the room and then return a list of actions for that room. The `roomid` attribute should be a string room identifier found in a room object as returned by a `roomlist` response from the server. When requesting without a `before` attribute this will grab the last 100 actions that occurred in the room. Note that the server expects the client to make a `chathistory` request to populate initial messages and occupants when selecting a room, either when the user clicks on a room to view messages or when the client selects a room for the user on behalf of a `selected` attribute in a `roomlist` response packet. If a `before` attribute is specified, it should be a string action identifier. The server will fetch the most recent 100 actions that come before the specified action ID placed in the `before` attribute. The client can use this behavior to implement history loading when a user scrolls up to the top of the currently populated room's actions. In both cases the server will respond with a `chathistory` response containing the following attributes: - `roomid` - The ID of the room that this response is for. Should always match the room ID in the request `roomid`. Clients can use this to discard stale `chathistory` response packets if the user has clicked away to another room before the response could be returned. - `history` - A list of action objects representing the chat history for the room. Clients wishing to request older messages can sort the received actions by the `order` attribute and then make another `chathistory` request with the action ID of the oldest action. Clients wishing to display whether there are more messages to fetch can look at the current room object's `oldest_action` identifier and compare it to the oldest action it has. - `occupants` - A list of occupants in the room. Note that this is only returned when the `before` attribute is not specified since in that case the client is attempting to perform an intial populate. It is assumed that when the client specifies a `before` attribute that it is fetching older actions and already has the occupant list. - `lastseen` - The last seen action ID for this room for the given user. Note that this is only returned when the `before` attribute is not specified. The client can use this to denote actions with a higher order than the last seen action ID as new, for the purpose of displaying what new activity has occurred since the last time the user has looked at the given room. ### chatactions The `chatactions` packet is sent from the client to poll for newer actions to a given room that the user has joined. This expects a request JSON with the `roomid` and `after` attributes. It will verify that the user is currently in the room and then return a list of actions for that room which are newer than the specified action. The `roomid` attribute should be a string room identifier found in a room object as returned by a `roomlist` response from the server. The `after` attribute should be a string action identifier. Note that clients do not normally need to poll for updates as the server will send updates to the client automatically for all joined rooms. This is provided so that a client which has been disconnected can grab missing actions upon successfully reconnecting. The server cannot compute a reconnected client's missing messages so the client is responsible for sending a `chatactions` request with the newest action ID it knows about when reconnecting to the server. The client can determine the newest action ID by sorting known actions for a room by the `order` attribute. The server will respond with a `chatactions` response containing the following attributes: - `roomid` - The ID of the room that this response is for. Should always match the room ID in the request `roomid`. Clients can use this to discard stale `chatactions` response packets if the user has clicked away to another room before the response could be returned. - `actions` - A list of action objects representing chat history for the room. Clients wishing to denote unread actions as new should consider all of these actions as new. ### welcomeaccept The `welcomeaccept` packet is sent from the client to inform the server that the welcome message was displayed to the user and the user accepted the message. The welcome message should be displayed when receiving a `welcome` packet in response to a `motd` request as documented above. If the user never accepts the welcome message, the client should not send the `welcomeaccept` packet to the server. When receiving the `welcomeaccept` packet the server will mark the user account as having been onboarded and respond with a `roomlist` packet as documented above. Since the user is joined to the list of rooms displayed to them upon receipt of the `welcomeaccept` packet, clients should expect the `roomlist` response to contain a `selected` attribute detailing which room to select for the user, but should not expect to receive a `counts` list since CritterChat does not attempt to badge for actions taken before the user was onboarded onto the instance. ### searchrooms The `searchrooms` packet is sent from the client to request a list of search results given a search criteria. This expects a request JSON that contains the `name` attribute which should be a string name to search. This will cause the server to search for all rooms with a default or custom name containing the search string, and all users with user or nickname containing the search string. Search results will be limited to what rooms and users the current user is allowed to see, including any private room that the user is currently invited to. Searching for an empty name will return all rooms and users that the current user can see. Note that if a search for a given user is performed and the current user already has a 1:1 chat with that user, the chat will be returned instead of the user. Users will only be returned in the search result list when the current user does not have a 1:1 chat with the user. The server will respond with a `searchresults` response containing a "results" attribute. This attribute is a list of room search result objects. The room search result object has the following attributes: - `name` - The string name of the user or room that was found matching the search criteria. - `handle` - The string handle of the user or room. Currently this is the username for users, and nothing for rooms, but in the future when rooms get custom URIs this will be the URI. - `type` - The string type of search result. Valid types are "room" for public rooms, "chat" for private conversations and "dm" for private 1:1 chats or users you could chat with but have not yet. - `icon` - A string URI pointing to the user or room icon. In all cases this will be a valid icon, and will point at the custom icon if set or the default otherwise. - `public` - A boolean representing whether this search result represents a public chat or not. - `joined` - A boolean representing whether the user has joined the room this search result represents. Useful for clients that wish to prompt an action such as "jump to room" for joined rooms, "join room" for rooms the user has not joined, and "message user" for users. - `invited` - A boolean representing whether the user was invited to the room this search result represents. Useful for clients that wish to prompt an action such as "accept invite" for rooms that the suer has been invited to. - `roomid` - A string identifier for the room this search result points to if the result is a room, or set to null if this search result is a user. - `userid` - A string identifier for the user this search result points to if the result is a user, or set to null if this search result is a room. ### searchusers The `searchusers` packet is sent from the client to request a list of users in a room given a search criteria. This expects a request JSON that contains the `name` attribute which should be a string name to search, as well as a string room ID for the room in question. Note that clients who are not joined to a given room will always get empty search results regardless of who is in the room or whether the room exists. Search results will be limited to users who are in the room already or who can be invited to the room but are not in the room presently. The server will respond with a `searchresults` response containing a "results" attribute. This attribute is a list of user search result objects. The user search result object has the following attributes: - `name` - The string name of the user that was found matching the search criteria. - `handle` - The string username of the user. - `type` - The string type of search result. Valid types are "room" for users of public rooms, and "chat" for users of private conversations. - `icon` - A string URI pointing to the user icon. In all cases this will be a valid icon, and will point at the custom icon if set or the default otherwise. - `public` - A boolean representing whether this search result represents a public chat or not. - `joined` - A boolean representing whether the user has joined the room this search result was conducted for. Useful for clients that wish to prompt an action such as "invite to room" for users who are not present, or display "already present" for users who are present. - `invited` - A boolean representing whether the user was invited to the room this search result was conducted for. Useful for clients that wish to show a message such as "already invited" for users who are not present but invited. - `roomid` - Always set to null since the search results of user searches represent users. - `userid` - A string identifier for the user this search result points to. ### updateprofile The `updateprofile` packet is sent from the client to request the user's profile be updated. This expects a request JSON that contains the following attributes: - `name` - A new nickname to set. This can be empty to unset a custom nickname and it can contain emoji. It must be 255 unicode code points or less in length. It cannot consist of solely unicode control characters or other non-printable characters. Note that the user's nickname will always be set, so clients should round-trip the existing custom name if the user does not edit it. - `about` - A new about section to set. This can be empty to delete existin text, or non-empty to set a new text. It must be 65530 unicode code points or less in length. Note that the user's about section will always be set, so clients should round-trip the existing about section if the user does not edit it. - `icon` - A string attachment ID that should be used to set the new icon, obtained from the avatar upload endpoint. If this is left empty, the user's icon will not be updated. The image must be square and currently cannot exceed 128kb in size. - `icon_delete` - An optional boolean specifying that the user wants to delete their custom icon. If the client leaves this out or sets this to an empty string or `False` then the server will not attempt to delete the user's custom icon. Setting this to `True` will cause the user's icon to revert to the instance's default icon. Upon successful update, the server will send a `profile` response packet which is identical to the response to a `profile` request. It will also send an unsolicited `profile` response packet to all other connected devices belonging to the user. ### updatepreferences The `updatepreferences` packet is sent from the client to request the user's preferences be updated. This expects a request JSON that contains the following attributes: - `rooms_on_top` - A boolean representing whether the user wants rooms to always be displayed above conversations (true) or whether rooms and conversations should be sorted by last update (false). If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `combined_messages` - A boolean representing whether messages sent right after each other by the same user should be combined into one chat block (true) or left as individual messages (false). If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `color_scheme` - A string representing the user's chosen color scheme. Valid values are "light" to force light mode, "dark" to force dark mode, and "system" to let the browser pick based on system settings. If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `desktop_size` - A string representing the chosen size of the client when in desktop mode. Valid values are "smallest", "smaller", "normal", "larger" and "largest". If present, the preference will be updated to the specified value. - `mobile_size` - A string representing the chosen size of the client when in mobile mode. Valid values are "smallest", "smaller", "normal", "larger" and "largest". If present, the preference will be updated to the specified value. - `admin_controls` A boolean representing whether an instance admin should see admin controls in various spots or not. If present, the preference will be updated to the specified value. - `title_notifs` - A boolean representing whether the user wants notifications to show up in the tab title (true) or not (false). If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `search_privacy` - A string representing the user's chosen search privacy. Valid values are "visible" and "hidden". If present and valid, the preference will be updated to the specific valid value. If not present, the preference will not be updated. - `invite_privacy` - A string representing the user's chosen invite privacy. Valid values are "auto_accept", "choose" and "disallow". If present and valid, the preference will be updated to the specific valid value. If not present, the preference will not be updated. - `mobile_audio_notifs` - A boolean representing whether the user wants audio notifications on mobile (true) or whether mobile clients should be silent (false). If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `audio_notifs` - A list of strings representing which audio notifications are enabled. If not present, individual audio notification enabled settings will be left as-is. If present, the user's audio notification enabled list is updated to match the specified list of notifications. - `tabbable_chat_elements` - A boolean representing whether the user wants individual HTML elements in the chat history window should be tabbable (true) or whether the tab order for the client should skip these elements (false). If not present, the preference will not be updated. If present, the preference will be updated to the specified value. - `notif_sounds` - A JSON object keyed by audio notification type strings whose values are string attachment IDs. Note that this JSON object can be obtained from the notification upload endpoint. All audio notifications listed in this JSON object will be updated, overwriting any existing notification and adding new audio for notifications that did not have audio before. If not present, no audio notification sounds will be updated. Audio notifications not present in this JSON object will also be left as-is. - `notif_sounds_delete` - A list of strings representing which audio notification files to delete. If not present, nothing will be deleted. If present, all notifications listed will be deleted. Note that the entries in this list are the same as the keys in `notif_sounds` and the values in the `audio_notifs` list. Upon successful update, the server will send a `preferences` response packet which is identical to the response to a `preferences` request. It will also send an unsolicited `preferences` response packet to all other connected devices belonging to the user in order to keep their own local preferences copy up to date. ### updatesettings The `updatesettings` packet is sent from the client any time the client toggles the "Info" panel or switches rooms, in order to inform the server of the last settings chosen by the client. Remember that settings are saved on a per-session basis so there is no need for the server to propagate settings outward to other clients nor echo the settings back to the client after successfully saving them. Therefore the client should not expect a response from this request packet. This expects a request JSON that contains the following attributes: - `roomid` - A string representing the room that the user was last in, be it a public or private room or a 1:1 conversation. - `info` - A string representing whether the right side info panel is currently visible. Valid values are "shown" for currently visible, and "hidden" for currently hidden. ### joinroom The `joinroom` packet is sent when the client requests to join a given room. This expects a request JSON that contains the `roomid` attribute which should be a string room ID to join. This room ID can be obtained from the `roomid` attribute in a room search result object. Upon receipt of a `joinroom` request containing a valid room ID that the user is allowed to join, the user will be joined to that room. Note that the `roomid` attribute can also include a user ID to start chatting with as well. The user ID can be obtained from the `userid` attribute in a room search result object. In the case that the `roomid` attribute is actually a user ID, the server will create a new 1:1 conversation between the current user and the specified user ID and then join both people to the room. Note that if there is an existing 1:1 conversation between the requested user and the current user it will be re-used, even if the users have previously left the conversation. In that case, both users will be re-added. Upon successfully joining a room, a "join" action will be generated for the room. In the case that the user successfully joined the requested room (or a new 1:1 chat was created) the server will respond with a `roomlist` response packet as documented above. Since the user was joined to a new room, clients should expect the `roomlist` response to contain a `selected` attribute which is the room the user just joined. The client should not expect to receive a `counts` list since CritterChat does not attempt to badge for actions taken in a room before the user joined it. Note that if the room does not exist no response will be returned. Note that if a user ID is specified and the room exists already, a `roomlist` response will be returned which includes the `selected` attribute correctly pointing to the existing 1:1 chat. Clients can use this to implement "message this user" functionality that will jump to the correct existing chat or create a new chat if one does not exist. ### newroom The `newroom` packet is sent when the client requests to create a new room. This can either be a public room if the user associated with the client is an administrator or a private conversation otherwise. Any user can create a new private conversation. This expects a request JSON that contains a `type` attribute which should be a string room purpose. Valid values are "room" for a public room or "chat" for a private conversation. In the case of "chat" type private conversations no other attributes are accepted. In the case of "room" type public rooms, additional attributes `name`, `topic`, `icon`, `moderated` and `autojoin` can be included in order to set these room properties upon creation of the room. The documentation for each of these attributes is identical to the below `updateroom` request. In the case that the room or conversation was successfully created the server will respond with a `roomlist` response packet as documented above. Since the user creating the room will also be joined to the room, clients should expect the `roomlist` response to contain a `selected` attribute which is the room the user just created and joined. The client should not expect to receive a `counts` list since the room is brand new and has effectively nothing to badge. Note that if the room could not be created no response will be returned. Note that private 1:1 chats are not created through `newroom` requests. Instead, clients should use the `joinroom` request and provide the user ID of the user they wish to messagea as documented above. ### updateroom The `updateroom` packet is sent when the client requests to update the details of a particular room. This expects a request JSON that contains a `roomid` attribute representing the room being updated, as well as a `details` attribute which is a JSON object containing the attributes defined below. The server will check the user's permissions as well as verify that the user is in the room requested before performing the update. Upon successful update with at least one room detail updated, a "change_info" action will be generated for the room. The server will not respond with any specific response to this packet, but all existing clients in the room will end up receiving an unsolicited `chatactions` packet containing the "change_info" action that was generated based on this request. - `name` - A new custom room name to set. This can be empty to unset a custom room name and it can contain emoji. It must be 255 unicode code points or less in length. It cannot consist of solely unicode control characters or other non-printable characters. Note that the room name will always be set so clients should round-trip the existing custom room name if the user does not edit it. - `topic` - A new custom topic to set. Much like the above `name`, this can be empty to unset the topic, and it can contain emoji. It must also be 255 unicode code points or less and it cannot be only non-printable unicode characters. The topic will always be updated so clients should round-trip the existing topic if the user does not edit it. - `moderated` - A boolean specifying whether the room should be set as a moderated room (true) or a free-for-all room (false). The room will be updated to the moderation type specified in this attribute when present, or left as-is if not provided. Note that only instance administrators can modify this setting. If a non-admin attempts to modify the setting it will be silently ignored and not updated. - `autojoin` - A boolean representing whether the room should be an auto-join room (true) or not (false). Auto-join rooms are joined by new users automatically. Rooms that are not auto-join need to be explicitly joined by users. Note that only instance administrators can modify this setting. If a non-admin attempts to modify the setting it will be silently ignored and not updated. Note that if this room attribute is changed from false to true, all activated users on the instance who are not in the room will be joined to the room. - `icon` - A string attachment ID that should be used to set the new custom room icon, obtained from the icon upload endpoint. If this is left empty, the room's icon will not be updated. The image must be square and currently cannot exceed 128kb in size. - `icon_delete` - An optional boolean specifying that the user wants to delete the custom room icon. If the client leaves this out or sets this to an empty string or `False` then the server will not attempt to delete the custom room icon. Setting this to `True` will cause the room's icon to revert to the instance's default icon. ### message The `message` packet is sent when the client wishes to send a message to a room. This expects a request JSON that contains a `roomid` attribute representing the room being updated and a `message` attribute representing a string message that should be sent to the room. The server will check the user's permissions as well as verify that the user is in the room requested before adding the message to the room's action history. Note that while the message can contain any valid unicode characters, it cannot be blank and it cannot consist solely of un-printable unicode characters. Upon successful insertion of the message into the room's action history, a "message" action will be generated for the room. The server will not respond with any specific response to this packet, but all existing clients that are in the room will end up receiving an unsolicited `chatactions` packet containing the "message" action that was generated based on this request. Optionally, the `message` packet can also include an `attachments` attribute representing any attachments that should be associated with the message. This `attachments` attribute should be a list of attachment IDs. That list can be obtained directly from the attachment upload endpoint. Note that if you do not wish to associate attachments with a given image this can be left out entirely, or it can be sent as an empty list. Both will act the same way on the server. Note that while the attachments themselves are checked in the upload, attempting to provide an attachment ID for something other than a message attachment will result in the request being rejected. Note that while the server does not respond with a specific response, it does send a socket.io acknowledgement back in the case of either failure or success. A client can use this acknowledgement to clear user input only when successfully acknowledged by the server. The acknowledgement is a JSON object that contains a `status` attribute which is set to `success` on successful receipt and storage of the message, or `failed` under all other circumstances. Clients should not attempt to clear the user's input until a successful acknowledgement has been received in order to ensure that the user doesn't have to retype a message on error. ### reaction The `reaction` packet is sent when the client wishes to add a reaction to or remove a reaction from an existing message. This expects a request JSON that contains an `actionid` attribute which should be the string action ID of the message being reacted to, a `reaction` attribute which should be a string emoji/emote text that is being reacted, and a `type` attribute which should be a string with the value "add" or "remove". For the "remove" type, the user must have previously reacted with that emote or emoji on the specific message otherwise this has no effect. For the "add" type, the user must be reacting with a valid emote or emoji and have not previously reacted with that emoji. Otherwise, this has no effect. Note that a user may react, remove the reaction and later react again with the same reaction. Valid emojis and emotes that can be used for reactions can be obtained from the configuration endpoint JSON, specifically under the `emojis` and `emotes` attributes, both of which are JSON objects where the keys are valid reactions. Note that the server does not respond with a specific response. Instead, a `change_message` action is emitted to all clients in the room where the reaction occurred. Additionally, the message itself will be re-emitted to all clients with the modified reactions included. Note that if somehow multiple `change_message` actions are emitted during a single update to a client, only one instance of the `message` action will be emitted containing the final value of the message after all modifications. However, all `change_message` actions will be emitted alongside. In this way, a client can keep track of deltas but still render new and existing `message` actions directly. While message editing is not currently supported in CritterChat, edited messages will be sent to clients in an identical fashion. ### leaveroom The `leaveroom` packet is sent when the client exits a room and wishes to inform the server that it does not want updates to the room anymore, nor should it receive the room when requesting rooms in the `roomlist` packet. It expects a request JSON that contains a `roomid` attribute representing the room the user has left. Upon successfully leaving the room, a "leave" action will be generated for the room. The server will not respond with any specific response to this packet, but all remaining clients still in the room will end up receiving an unsolicited `chatactions` packet containing the "leave" action that was generated based on this request. Note that attempting to leave a room that the user is not in will result in a no-op. Note also that attempting to leave a non-existant room will result in a no-op. ### lastaction The `lastaction` packet is sent from the client when the client catches up to a particular action in a particular room. It is used when the client wants to acknowledge receipt of actions that it previously marked as new and displayed an unread notification badge for. It expects a request JSON that contains a `roomid` attribute representing the room that the user has caught up to as well as an `actionid` representing the action that the client wishes to acknowledge read receipt of. This packet is how the client can influence the `lastseen` action ID attribute in a `chathistory` response packet. The server will not respond with any specific response to this packet, but other devices in use by the same user which are currently connected may receive an unsolicited `roomlist` response packet with an updated `counts` attribute for the room that was just updated. This is the way in which the server can communicate notifications clearing to all connected devices for the same user. ### inviteroom The `inviteroom` packet is sent from the client when the client wishes to invite another user to a particular room. It expects a request JSON that contains a `roomid` attribute representing the string room ID that the invite is for and a `userid` attribute representing the string user ID that the invite is to be sent to. Note that invites can only be sent for private conversations and public chat rooms. Direct messages cannot be invited to as they are 1:1 conversations. If the user trying to invite is not present in the room they are inviting somebody to, if the user they are inviting is already in the room they're inviting the user to, or if the user has invites disabled in their preferences then this has no effect. Otherwise an invite is sent to the recipient. Note that a user who has configured their preferences to auto-accept invites will immediately join any room they are invited to. Users who have opted to review invites will instead get the chance to accept the invite and join the room or decline the invite. Accepting the invite is done by issuing a `joinroom` request packet pointing at the room ID in the invite. No response packet is sent for this request, but much like the `message` request packet an `invite_user` action is emitted to all clients that are in the room so they can see that the invite took place. ### uninviteroom The `uninviteroom` packet is sent from the client when the client wishes to retract a previously-sent invite for another user to a particular room. It expects a request JSON that contains a `roomid` attribute representing the string room ID that the invite is for and a `userid` attribute representing the string user ID that the invite is to be retracted from. Note that invites can only be cancelled/retracted by the user that issued the invite in the first 72 hours after the invite was sent. After that, all other users in the room the invite is for can cancel the invite. This provides a way to clean up a private conversation if the person doing the inviting suddenly stops logging in or maintaining the conversation. If the user attempting to retract an invite is not in the room the invite is for, if the recipient of the invite retraction is already in the room, or if the recipient of the invite retraction does not have an invite then this has no effect. Otherwise the invite is cancelled and that user can no longer accept the invite to join the room. Note that it is possible to cancel the invite of somebody who has disabled invites after the invite was sent, but it is not possible to re-invite them once the cancellation goes through. No response packet is sent for this request, but much like the `message` request packet an `uninvite_user` action is emitted to all clients that are in the room so they can see that the invite was cancelled. ### acknowledgeinvite The `acknowledgeinvite` packet is sent from the client when the client wishes to acknowledge receipt of a previously sent invite. It expects a request JSON that contains an `inviteid` attribute representing the string invite ID that the user wishes to acknowledge. Acknowledging an invite simply updates the `seen` attribute of the invite to true and updates the timestamp of the invite itself so that other clients signed into the same user get notified of the invite update. Clients may wish to use the `seen` attribute of an invite to determine whether to badge an invite or not, and may wish to acknowledge an invite when the user clicks on the invite, regardless of whether they act on the invite by joinnig the room or dismissing the invite. Note that a seen invite is still valid for the purpose of joining the room the invite was for. No response packet is sent for this request, but an unsolicited `invites` response packet will be sent to all clients that the user is signed in under with the updated invite that has been marked as seen. Note that other users cannot see if the current user has seen an invite. ### dismissinvite The `dismissinvite` packet is sent from the client when the client wishes to dismiss a previously sent invite. It expects a request JSON that contains an `inviteid` attribute representing the string invite ID that the user wishes to dismiss. Dismissing an invite simply updates the `active` attribute of the invite to false and updates the timestamp of the invite itself so that other clients signed into the same user get notified of the invite update. This also has the effect of moving the invite from the `active` list to the `ignored` list in an `invites` response packet. Clients may wish to only present active invites to the user, so dismissing an invite can be seen as hiding the invite without formally rejecting it. The web client will hide the invite completely but still show the room the invite was for under searches with an action of "accept invite". Note that a dismissed invite is still valid for the purpose of joining the room the invite was for. No response packet is sent for this request, but an unsolicited `invites` response packet will be sent to all clients that the user is signed in under with the updated invite that has been marked as seen. Note that other users cannot see if the current user has dismissed an invite. ### admin The `admin` packet is sent from the client when the client requests the server to perform an administrative action on behalf of the currently logged-in user. Note that the current user must be an administrator to call this command. If not, this command will refuse to perform the action requested. It expects a request JSON that contains an `action` attribute representing the action to be taken, and various other attributes depending on the action. The server will not respond with any specific response to the packet, but will send a socket.io acknowledgement back in the case of either failure or success. A client can use this to refresh information about a user that has had action taken on it by the command. Note also that in many cases, this will also return a `flash` unsolicited response packet that the client can use to display to the user. The various actions and their additional properties are documented below. #### activate - `action` - Set to the string "activate" to request a particular user be activated. Activated accounts can log in and don't appear grayed out in rooms they've joined. - `userid` - String user ID of the user that should be activated. #### deactivate - `action` - Set to the string "deactivate" to request a particular user be deactivated. Deactivated accounts are immediately logged out of all active sessions, cannot log in and appear grayed out in rooms they've joined. - `userid` - String user ID of the user that should be deactivated. #### mod - `action` - Set to the string "mod" to request a particular occupant be granted the room moderator role. Room moderators can change info in moderated rooms, and can mute/unmute users. - `occupantid` - String occupant ID of the room occupant that should be set as a moderator. #### demod - `action` - Set to the string "demod" to request a particular occupant be have the room moderator role revoked. - `occupantid` - String occupant ID of the room occupant that should be unset as a moderator. ### mod The `mod` packet is sent from the client when the client requests the server to perform a moderator action on behalf of the currently logged-in uesr. Note that the current user must be a moderator in the room that they are taking action on. If not, this command will refuse to perform the action requested. It expects a request JSON that contains an `action` attribute representing the action to be taken, and various other attributes depending on the action. The server will not respond with any specific response to the packet, but will send a socket. io acknowledgement back in the case of either failure or success. A client can use this to refresh information about a user that has had action taken on it by the command. Note also that in many cases, this will also return a `flash` unsolicited response packet that the client can use to display to the user. The various actions and their additional properties are documented below. #### mute - `action` - Set to the string "mute" to mute a particular user in the room they are in. Muted users cannot change room information or send messages to the room and appear as inactive in the web client. - `occupantid` - String occupant ID of the user that should be muted. #### unmute - `action` - Set to the string "unmute" to unmute a particular user in the room they are in. - `occupantid` - String occupant ID of the user that should be unmuted. ## Server-Initated Packets The following packets are server initiated. The server will send them to correctly connected clients so that a client does not have to poll for updates. ### emotechanges The `emotechanges` response packet will be sent to the client unsolicited whenever an administrator adds or removes custom emotes on the instance. This is sent to every connected client at the point of change so that clients do not need to refresh in order to use newly-added cusom emotes. The response JSON contains the following attributes: - `additions` - A JSON object keyed by string emote name, such as `:wiggle:`, with the value of each entry being the custom emote's URI as a string. Note that there is currently no way for a non-web client to retrieve the full list of custom emotes as they are embedded in the HTML template for the existing JS client. At some point when it becomes necessary this will change, but for now it is what it is. - `deletions` - A list of strings represnting emote names that were deleted, such as `:wiggle:`. Clients should remove any emotes listed here from any typeahead or emote search functionality and should stop attempting to replace emote text with the known URI for the emotes that were deleted. ### error The `error` response packet will be sent to the client under any circumstance where the server encounters an error in processing a request. Examples might be trying to change a nickname to something too long or trying to set a custom icon that is too large. The response packet JSON will contain an `error` attribute which is a string error. This can be directly displayed to the user in an error popup or similar modal. Currently there is no automated way for clients to determine the error returned and translate it for the user. ### flash The `flash` response packet will be sent to the client under any circumstance where the server wishes to display a less-intrusive message to the user than an error packet. The response packet JSON will contain a `severity` attribute which is one of the following string values: "success", "info", "warning", "error". It will also contain a `message` attribute which is the string message to display to the user at the previously-mentioned severity. The web client uses this to place a dismissable message at the top of the screen. Currently there is no automated way for clients to translate this for the user. ### reload The `reload` response packet will be sent to the client unsolicited whenever the server determines that the client is no longer authorized to be connected to the server. This can happen if the user's session is stale and times out, or if the user has been deactivated by an administrator. In the future this will also be used in conjunction with a "log out all other devices" feature to allow a user to safely de-authenticate any connected clients if they suspect they have been compromised. The client should respond to this by taking the user back to the login screen and asking them to re-authenticate. Upon receiving a `reload` packet, no additional requests will be handled. Instead, the server will continue sending `reload` packets to the client instead of the expected response. ### chatactions The `chatactions` response packet will be sent to the client unsolicited whenever an action occurs in a room that the user has joined. The server has no concept of what room is active on the client so it sends all room updates to the client for every joined room. The client can use this to display new actions in the currently displayed room. For actions that are associated with a room that the client is not actively displaying, the client can instead use the actions to badge notification counts. Note that the server will only start tracking and sending new actions at the point when the client successfully connects using Socket.IO. The packet is documented in the above `chatactions` request and response for client-initiated packets since the response packet follows the same format. ### roomlist The `roomlist` response packet will be sent to the client unsolicited when the user's joined room information is updated not in response to the client's request. Right now that includes when the user is joined to a room by another user (such as starting a new 1:1 chat and in the future being added to a chat by an administrator or by invite) and when notification badges are cleared for a given room. The latter happens when the user is using multiple devices and views new actions in a room on another device. CritterChat informs all other connected clients for that user so that the user doesn't have to manually click on each room to clear notifications for every device they are actively signed on with. The packet is documented in the above `roomlist` request and response for client-initiated packets since the response packet follows the same format. ### invites The `invites` response packet will be sent to the client unsolicited when the user's invite list is updated. This includes when the user is issued a new invite, when a previously-issued invite is cancelled, when an invite is removed because the user accepted the invite by joining the room the invite was for, when the user dismisses an invite to hide it and when information in the invite such as the room name or topic changes. The packet is documented in the above `invites` request and response for client-initiated packets since the response packet follows the same format. ### profile The `profile` response packet will be sent to the client unsolicited when the user's profile is updated not in response to the client's request. This can happen if an administrator changes a user's profile information or when the user edits their own profile on another device. When this happens the server will send a `profile` response to all devices so that they can get an updated version of the user's profile. The packet is documented in the above `profile` request and response for client-initated packets since the response packet follows the same format. ### preferences The `preferences` response packet will be sent to the client unsolicited when the user's preferences are updated not in response to the client's request. This happens when the user edits their preferences on another device. When this happens the server will send a `preferences` response to all devices so that they can get an updated version of the user's preferences. The packet is documented in the above `preferences` request and response for client-initated packets since the response packet follows the same format.