syntax = "proto3"; package chatto.api.v1; import "google/protobuf/field_mask.proto"; import "buf/validate/validate.proto"; import "chatto/api/v1/link_previews.proto"; import "chatto/api/v1/message_types.proto"; import "chatto/api/v1/reactions.proto"; // Description supplied for one attachment in a new message. message MessageAttachmentDescriptionInput { // Required. Asset ID included in attachment_asset_ids on the same request. string asset_id = 1 [(buf.validate.field).string = { min_len: 1 max_bytes: 15 }]; // Plain-text description with at most 1,000 Unicode characters. Trim outer // whitespace before sending. Chatto also trims outer whitespace, preserves // internal line breaks, and omits an empty result. string description = 2 [(buf.validate.field).string.max_len = 1000]; } // Request to create a message in a room or thread. message CreateMessageRequest { // Field 8 was `link_preview`, a client-provided metadata message used before // CreateMessage accepted only server-issued link preview tokens. reserved 8; reserved "link_preview"; // Field 9 was `attachments`, inline attachment bytes accepted before // AssetUploadService moved uploads into a dedicated chunked API. reserved 9; reserved "attachments"; // Field 7 was `mention_confirmation_token`, used by a server-enforced large // mention confirmation flow before role mention confirmation became a // client-only composer affordance. reserved 7; reserved "mention_confirmation_token"; // Required. Room where the message should be created. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Message body text. Required unless attachment_asset_ids is non-empty. string body = 2; // Completed room-scoped asset IDs uploaded by the caller and not yet attached // to a message. The server attaches them exclusively and atomically to this // message. At most 10 IDs may be supplied. repeated string attachment_asset_ids = 3 [(buf.validate.field).repeated = { max_items: 10 items: { string: { min_len: 1 max_bytes: 15 } } }]; // Event ID of the thread root message when posting a thread reply. string thread_root_event_id = 4; // Event ID this message replies to for attribution. string in_reply_to = 5; // True to also echo a thread reply into the main room timeline. bool also_send_to_channel = 6; // Short-lived token returned by FetchLinkPreview for the selected URL. The // server resolves the token to cached, server-fetched metadata during post. string link_preview_token = 10; // True to establish the new root message as a thread immediately. Requires // message.post (which includes thread posting). Cannot be combined with // thread_root_event_id. bool create_thread = 11; // Optional descriptions for assets in attachment_asset_ids. Asset IDs must // be unique in this list. At most one description can target each asset. repeated MessageAttachmentDescriptionInput attachment_descriptions = 12 [(buf.validate.field).repeated = { max_items: 10 }]; } // Result of creating a message. message CreateMessageResponse { // Field 2 was `mention_confirmation`, used by a server-enforced large // mention confirmation flow before role mention confirmation became a // client-only composer affordance. reserved 2; reserved "mention_confirmation"; // Field 3 was `includes`, used before create responses were narrowed to the // generated message. reserved 3; reserved "includes"; // Renderable message created by the request. Message message = 1; } // Request to patch a message. update_mask selects fields to apply or reset. // Fields outside the mask stay unchanged. message UpdateMessageRequest { // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the message to edit. string event_id = 2 [(buf.validate.field).string.min_len = 1]; // New message body text. Select body in update_mask to change it. optional string body = 3 [(buf.validate.field).string.max_len = 10000]; // For thread replies, whether a channel echo should exist after saving. // Select also_send_to_channel in update_mask to change it. optional bool also_send_to_channel = 4; // Editable fields to apply or reset: body, also_send_to_channel. // Omit to infer populated fields; * selects all editable fields. An explicit // empty mask is invalid. Unselected values are ignored. Selected absent values // reset the field to its default, subject to field validation. google.protobuf.FieldMask update_mask = 5; } // Result of editing a message. message UpdateMessageResponse { reserved 1; reserved "updated"; // Field 3 was `includes`, used before update responses were narrowed to the // edited message. reserved 3; reserved "includes"; // Renderable message after the edit. Message message = 2; } // Request to retract a message. message DeleteMessageRequest { // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the message to retract. string event_id = 2 [(buf.validate.field).string.min_len = 1]; } // Result of retracting a message. message DeleteMessageResponse { reserved 1; reserved "deleted"; } // Request to remove one attachment from a message. message DeleteAttachmentRequest { // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the message containing the attachment. string event_id = 2 [(buf.validate.field).string.min_len = 1]; // Required. Attachment ID to remove from the message. string attachment_id = 3 [(buf.validate.field).string.min_len = 1]; } // Result of removing one attachment from a message. message DeleteAttachmentResponse { reserved 1; reserved "deleted"; } // Request to set or clear one attachment description. message SetAttachmentDescriptionRequest { // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Message event containing the attachment, or its channel echo. string event_id = 2 [(buf.validate.field).string.min_len = 1]; // Required. Attachment asset ID in the current message body. string attachment_id = 3 [(buf.validate.field).string.min_len = 1]; // Replacement description with at most 1,000 Unicode characters. Trim outer // whitespace before sending. Chatto also trims outer whitespace and preserves // internal line breaks. An empty result clears the description. string description = 4 [(buf.validate.field).string.max_len = 1000]; } // Result of setting or clearing an attachment description. message SetAttachmentDescriptionResponse { // Renderable message after the description change. Message message = 1; } // Request to remove the accepted link preview from a message. message DeleteLinkPreviewRequest { // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Event ID of the message containing the link preview. string event_id = 2 [(buf.validate.field).string.min_len = 1]; // Required. URL of the link preview to remove. string url = 3 [(buf.validate.field).string.min_len = 1]; } // Result of removing a link preview from a message. message DeleteLinkPreviewResponse { reserved 1; reserved "deleted"; } // Request to read one visible message. message GetMessageRequest { // Field 3 was `thumbnail`, used before custom attachment URL hydration moved // to AssetService. reserved 3; reserved "thumbnail"; // Required. Room containing the message. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Message event ID. string event_id = 2 [(buf.validate.field).string.min_len = 1]; } // Response containing one renderable message. message GetMessageResponse { // Field 2 was `includes`, used before message read responses were narrowed // to messages. reserved 2; reserved "includes"; // Renderable message. Message message = 1; } // Request to read many visible messages in one room. message BatchGetMessagesRequest { // Field 3 was `thumbnail`, used before custom attachment URL hydration moved // to AssetService. reserved 3; reserved "thumbnail"; // Required. Room containing the messages. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Required. Message event IDs. Missing, retracted, non-message, and // wrong-room event IDs are omitted from the response. repeated string event_ids = 2 [(buf.validate.field).repeated = { min_items: 1 max_items: 100 items: { string: {min_len: 1} } }]; } // Response containing renderable messages. message BatchGetMessagesResponse { // Field 2 was `includes`, used before message read responses were narrowed // to messages. reserved 2; reserved "includes"; // Renderable messages in first-seen request order. repeated Message messages = 1; } // Creates messages in room and thread timelines. service MessageService { // Lists all users with the requested reaction. Requires room membership and // permission to read the message. A missing reaction returns an empty page; // a missing or hidden message returns NOT_FOUND or PERMISSION_DENIED. rpc ListReactionUsers(ListReactionUsersRequest) returns (ListReactionUsersResponse); // Fetches and caches metadata for a composer URL. Authentication is required // to avoid exposing the preview fetcher as an unauthenticated network proxy. // Successful responses include a short-lived token accepted by CreateMessage. rpc FetchLinkPreview(FetchLinkPreviewRequest) returns (FetchLinkPreviewResponse); // Creates a message for the current user. The user must be a room member and // must have message.post for room messages. Thread replies require read // access and either message.post, message.post-in-thread, or // message.post-in-interactions with an existing interaction relationship. // Echoing a thread reply also requires message.echo and // message.post. The room's Threading Mode may automatically establish a root // thread or reject a thread placement that the mode does not allow. rpc CreateMessage(CreateMessageRequest) returns (CreateMessageResponse); // Edits a message body. Authors can edit their own messages within the edit // window. Effective message.manage permits edits at any time. Only the // message author can change channel echo state. Disabled rooms reject // creation of a new channel echo while allowing an existing echo to be // removed. Room membership is also required. // Edits require message.read or a matching thread relationship with // message.read-interactions. rpc UpdateMessage(UpdateMessageRequest) returns (UpdateMessageResponse); // Retracts a message. Authors can delete their own messages. Non-authors need // message.manage. rpc DeleteMessage(DeleteMessageRequest) returns (DeleteMessageResponse); // Removes one attachment from the author's own message. rpc DeleteAttachment(DeleteAttachmentRequest) returns (DeleteAttachmentResponse); // Sets or clears one attachment description. Authors can change descriptions // within the message edit window. Effective message.manage permits changes // at any time and to other users' messages. Room membership and message read // access are required. rpc SetAttachmentDescription(SetAttachmentDescriptionRequest) returns (SetAttachmentDescriptionResponse); // Removes the accepted link preview from the author's own message. rpc DeleteLinkPreview(DeleteLinkPreviewRequest) returns (DeleteLinkPreviewResponse); // Reads one renderable message, including current body, attachment metadata, // link preview, reactions, thread metadata, and pin state. Authentication // and room membership are required. Reads also require // message.read or a matching thread relationship with // message.read-interactions. Returns // NOT_FOUND when the event does not exist, is not a message, has been // retracted, or belongs to a different room. rpc GetMessage(GetMessageRequest) returns (GetMessageResponse); // Reads many renderable messages and their current pin state in one room. // Authentication and room membership are required. Reads also // require message.read or a matching thread relationship with // message.read-interactions. Missing, // retracted, non-message, wrong-room, and inaccessible event IDs are omitted. // Results preserve first-seen request order, and repeated event IDs are // de-duplicated. rpc BatchGetMessages(BatchGetMessagesRequest) returns (BatchGetMessagesResponse); // Adds a reaction to a message. The user must be a room member and have // message.react. Reactions also require message.read or a matching thread // relationship with message.read-interactions. rpc AddReaction(AddReactionRequest) returns (AddReactionResponse); // Removes a reaction from a message. The user must be a room member and have // message.react. Reactions also require message.read or a matching thread // relationship with message.read-interactions. rpc RemoveReaction(RemoveReactionRequest) returns (RemoveReactionResponse); }