syntax = "proto3"; package chatto.api.v1; import "buf/validate/validate.proto"; import "chatto/api/v1/permissions.proto"; import "chatto/api/v1/rooms.proto"; import "google/protobuf/timestamp.proto"; // Viewer-specific state and permission decisions for one room. message RoomViewerState { // True when the current user is an effective room member. bool is_member = 1; // True when the room has neutral Badge attention for the current user. // This state is independent of the user's last-read message cursor. bool has_unread = 2; // Effective room-scoped permission decisions after room state constraints. repeated PermissionGrant permissions = 3; // Earliest time the current user may create another message. Absent when // slow mode is disabled, expired, or bypassed by moderation permissions. google.protobuf.Timestamp slow_mode_next_post_at = 4; } // Room kinds to include in directory responses. enum RoomDirectoryScope { // Include visible channel rooms and readable active DM rooms. ROOM_DIRECTORY_SCOPE_UNSPECIFIED = 0; // Include visible channel rooms and readable active DM rooms. ROOM_DIRECTORY_SCOPE_ALL = 1; // Include visible channel rooms only. ROOM_DIRECTORY_SCOPE_CHANNELS = 2; // Include the caller's readable active DM rooms only. ROOM_DIRECTORY_SCOPE_DMS = 3; } // Room metadata plus state and capabilities resolved for the authenticated // viewer. message RoomWithViewerState { reserved 2 to 13; reserved "is_member", "has_unread", "can_list_room", "can_join_room", "can_post_message", "can_post_in_thread", "can_attach", "can_react", "can_echo_message", "can_manage_others_message", "can_manage_room", "can_ban_room_members"; // Public room metadata. Room room = 1; // State and permission decisions resolved for the current user. RoomViewerState viewer_state = 14; } // Sidebar link metadata for room group navigation. message SidebarLink { // Stable sidebar link ID. string id = 1; // Display label. string label = 2; // Absolute http(s) URL or server-local path. string url = 3; } // One ordered item in a room group. message RoomGroupItem { oneof item { // Visible room entry. RoomWithViewerState room = 1; // Sidebar link entry. SidebarLink sidebar_link = 2; } } // Viewer-specific state for one room group. message RoomGroupViewerState { reserved 1; reserved "can_create_room"; // Effective group-scoped permission decisions after group state constraints. repeated PermissionGrant permissions = 2; } // Ordered group of channel rooms and sidebar links. message RoomGroup { reserved 4; reserved "rooms"; // Stable room group ID. string id = 1; // Display name. string name = 2; // Public group description, when set. string description = 3; // Mixed room/sidebar-link entries in sidebar order. repeated RoomGroupItem items = 5; // State and permissions resolved for the current user. RoomGroupViewerState viewer_state = 6; } // Request for rooms visible to the current user. message ListRoomsRequest { // Which room kinds to include. Defaults to all. RoomDirectoryScope scope = 1 [(buf.validate.field).enum.defined_only = true]; } // Finite snapshot of rooms visible to the current user. message ListRoomsResponse { // Rooms matching the requested scope. repeated RoomWithViewerState rooms = 1; } // Request for ordered room groups visible to the current user. message ListRoomGroupsRequest { reserved 1; reserved "include_archived_rooms"; } // Finite snapshot of ordered room groups visible to the current user. message ListRoomGroupsResponse { // Channel room groups in sidebar order. repeated RoomGroup groups = 1; } // Request for one ordered room group visible to the current user. message GetRoomGroupRequest { reserved 2; reserved "include_archived_rooms"; // Required. Room group to resolve. string group_id = 1 [(buf.validate.field).string.min_len = 1]; } // One ordered room group visible to the current user. message GetRoomGroupResponse { // Resolved room group. Hidden and archived room entries are omitted. RoomGroup group = 1; } // Request visible room groups by stable group ID. message BatchGetRoomGroupsRequest { reserved 2; reserved "include_archived_rooms"; // Required room group IDs. Unknown groups are omitted from the response. repeated string group_ids = 1 [(buf.validate.field).repeated = { min_items: 1 max_items: 100 items: { string: {min_len: 1} } }]; } // Visible room group batch response for direct group hydration. message BatchGetRoomGroupsResponse { // Resolved room groups in first-seen request order. repeated RoomGroup groups = 1; } // Request for one room visible to the current user. message GetRoomRequest { // Required. Room to resolve. string room_id = 1 [(buf.validate.field).string.min_len = 1]; } // Room visible to the current user. message GetRoomResponse { // Resolved room and viewer state. RoomWithViewerState room = 1; } // Request visible rooms by stable room ID. message BatchGetRoomsRequest { // Required room IDs. Unknown rooms and rooms hidden from the caller are // omitted from the response. Archived rooms may be returned when the caller // can still refresh them directly. repeated string room_ids = 1 [(buf.validate.field).repeated = { min_items: 1 max_items: 100 items: { string: {min_len: 1} } }]; } // Visible room batch response for direct room hydration. message BatchGetRoomsResponse { // Resolved rooms in first-seen request order. repeated RoomWithViewerState rooms = 1; } // Reads room directory data. service RoomDirectoryService { // Lists rooms visible to the current user. Channel rooms are non-archived // rooms visible through membership or room.list. DM membership authorizes DM // reads. Empty DMs are omitted. Results are returned as a finite navigation // snapshot. rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse); // Lists ordered channel room groups and sidebar items visible to the current // user as a finite navigation snapshot. Hidden room entries are omitted. // Archived room entries are omitted. rpc ListRoomGroups(ListRoomGroupsRequest) returns (ListRoomGroupsResponse); // Returns one ordered room group by ID. Hidden room entries are omitted. // Archived room entries are omitted. // Returns NOT_FOUND when the room group does not exist. rpc GetRoomGroup(GetRoomGroupRequest) returns (GetRoomGroupResponse); // Returns ordered room groups for a set of stable group IDs. Hidden room // entries are omitted. Archived room entries are omitted. Unknown groups are // omitted. Results preserve first-seen request order and repeated IDs are // de-duplicated. rpc BatchGetRoomGroups(BatchGetRoomGroupsRequest) returns (BatchGetRoomGroupsResponse); // Returns one visible room by ID. DM rooms require membership. Returns // NOT_FOUND when the room does not exist and PERMISSION_DENIED when the room // exists but is hidden from the caller. rpc GetRoom(GetRoomRequest) returns (GetRoomResponse); // Returns visible rooms for a set of stable room IDs. This is a direct // hydration API, so visible archived rooms may be returned. Unknown rooms and // rooms hidden from the caller are omitted. Results preserve first-seen // request order and repeated IDs are de-duplicated. rpc BatchGetRooms(BatchGetRoomsRequest) returns (BatchGetRoomsResponse); }