syntax = "proto3"; package chatto.api.v1; import "buf/validate/validate.proto"; import "chatto/api/v1/message_types.proto"; import "chatto/api/v1/pagination.proto"; import "chatto/api/v1/read_state.proto"; import "chatto/api/v1/room_timeline.proto"; import "chatto/api/v1/rooms.proto"; // Current follow state for one thread and viewer. message ThreadFollowState { // Room containing the thread. string room_id = 1; // Event ID of the root message for the thread. string thread_root_event_id = 2; // True when the current user follows the thread. bool following = 3; } // Request to follow one message thread. message FollowThreadRequest { // Required. Room containing the thread. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the root message for the thread. string thread_root_event_id = 2 [(buf.validate.field).string.min_len = 1]; } // Result of following a thread. message FollowThreadResponse { // True when the current user follows the thread after the operation. bool following = 1; // Current follow state after the operation. ThreadFollowState state = 2; } // Request to stop following one message thread. message UnfollowThreadRequest { // Required. Room containing the thread. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the root message for the thread. string thread_root_event_id = 2 [(buf.validate.field).string.min_len = 1]; } // Result of unfollowing a thread. message UnfollowThreadResponse { // True when the current user follows the thread after the operation. bool following = 1; // Current follow state after the operation. ThreadFollowState state = 2; } // One followed thread for the current user. message FollowedThread { reserved 1 to 3, 5 to 7; reserved "room_id", "room_name", "thread_root_event_id", "reply_count", "last_reply_at", "has_unread"; // Renderable root message, when the root is still visible. Message root_message = 4; // Room containing the thread. RoomSummary room = 8; // Aggregated thread state. ThreadSummary thread = 9; } // Request for a page of followed threads for the current user. message ListFollowedThreadsRequest { reserved 1, 2; reserved "limit", "offset"; // Page request. Defaults to 20 results when absent or limit is zero. PageRequest page = 3; } // Response containing one followed-thread page. message ListFollowedThreadsResponse { reserved 2, 3; reserved "total_count", "has_more"; // Followed threads in newest-activity-first order. repeated FollowedThread threads = 1; // Hot-path related entities needed to render this feed page without // per-thread hydration. RoomTimelineIncludes includes = 4; // Page metadata. PageInfo page = 5; } // Manages thread follow state for the current user. service ThreadService { // Returns followed threads in rooms where the current user is a member. // Channel-room threads also require message.read or an active relationship // with message.read-interactions. Historical DM threads use DM membership. // The result includes enough root-message data for clients to render the // list without extra per-field fetches. rpc ListFollowedThreads(ListFollowedThreadsRequest) returns (ListFollowedThreadsResponse); // Follows a thread for the current user. Room membership plus message.read or // an active relationship with message.read-interactions are required. DMs do // not support current thread actions. // Followed threads can be surfaced in clients and can participate in thread // notification behavior. rpc FollowThread(FollowThreadRequest) returns (FollowThreadResponse); // Stops following a thread for the current user. Room membership plus // message.read or an active relationship with message.read-interactions are // required. DMs do not support current thread actions. The response reports // the resulting follow state so clients can update local UI immediately. rpc UnfollowThread(UnfollowThreadRequest) returns (UnfollowThreadResponse); // Returns one page of events in a message thread. Room membership is // required. Channel-room reads also require message.read or an active // relationship with message.read-interactions. Historical DM threads use DM // membership. Initial pages include the thread root message; cursor pages // return replies in the requested direction. rpc GetThreadEvents(GetThreadEventsRequest) returns (GetThreadEventsResponse); // Returns a thread timeline window centered around a specific event. Use this // to open a reply from a notification or search result in context. Returns // NOT_FOUND when the thread root or anchor event is missing or hidden. // Returns PERMISSION_DENIED when room membership is missing, both read modes // are missing, or an interaction-scoped account has no relationship with the // thread. Historical DM threads use DM membership. rpc GetThreadEventsAround(GetThreadEventsAroundRequest) returns (GetThreadEventsAroundResponse); // Marks a thread timeline as read through the supplied event without changing // the room-level read marker. Room membership plus message.read or an active // relationship with message.read-interactions are required. DMs do not // support current thread actions. rpc MarkThreadAsRead(MarkThreadAsReadRequest) returns (MarkThreadAsReadResponse); }