Skip to content

Commit 51f754b

Browse files
committed
Add chat message reactions spec
1 parent 960fd1b commit 51f754b

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed

textile/chat-features.textile

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,16 @@ Broadly speaking, messages are published via REST calls to the Chat HTTP API and
326326
** @(CHA-M4a)@ @[Testable]@ A subscription can be registered to receive incoming messages. Adding a subscription has no side effects on the status of the room or the underlying realtime channel.
327327
** @(CHA-M4b)@ @[Testable]@ A subscription can de-registered from incoming messages. Removing a subscription has no side effects on the status of the room or the underlying realtime channel.
328328

329+
* @(CHA-M11)@ A @Message@ must have a method @with@ to apply changes from events (@MessageEvent@ and @MessageReactionSummaryEvent@) to produce updated message instances.
330+
** @(CHA-M11a)@ @[Testable]@ When the method receives a @MessageEvent@ of type @created@, it must throw an @ErrorInfo@ with code @40000@ and status code @400@.
331+
** @(CHA-M11b)@ @[Testable]@ For @MessageEvent@ the method must verify that the @message.serial@ in the event matches the message's own serial. If they don't match, an error with code @40000@ and status code @400@ must be thrown.
332+
** @(CHA-M11c)@ @[Testable]@ For @MessageEvent@ of type @update@ and @delete@, if the event's @message.version@ is less than or equal to the current message's @version@, the original message must be returned unchanged.
333+
** @(CHA-M11d)@ @[Testable]@ For @MessageEvent@ of type @update@ and @delete@, if the event's @message.version@ is greater than the current message's @version@, the method must return a new message based on the event and deep-copying the reactions from the original message.
334+
** @(CHA-M11e)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must verify that the @summary.messageSerial@ in the event matches the message's own serial. If they don't match, an error with code @40000@ and status code @400@ must be thrown.
335+
** @(CHA-M11f)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must return a new @Message@ instance (deep copy) with the updated reactions, preserving all other properties of the original message.
336+
** @(CHA-M11g)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must deep-copy the reactions from the event before applying them to the returned message instance.
337+
** @(CHA-M11h)@ @[Testable]@ The method must not alter the original message instance.
338+
329339
<div class=deprecated>
330340
** @(CHA-M4c)@ @[Testable]@ @(deprecated)@ When a realtime message with @name@ set to @message.created@ is received, it is translated into a message event, which contains a @type@ field with the event type as well as a @message@ field containing the "@Message Struct@":#chat-structs-message. This event is then broadcast to all subscribers.
331341
</div>
@@ -354,6 +364,59 @@ Broadly speaking, messages are published via REST calls to the Chat HTTP API and
354364
* @(CHA-M6b)@ @[Testable]@ If the REST API returns an error, then the method must throw its @ErrorInfo@ representation.
355365
* @(CHA-M7)@ This specification point has been removed. It was valid up until the single-channel migration.
356366

367+
h2(#messageReactions). Message Reactions
368+
369+
Users can add reactions to messages, such as thumbs-up or heart emojis. Summaries (counts per reaction, and who reacted) of the message reactions are stored with the message and are visible to all users in the room. Message reactions are powered by Pub/Sub message annotations.
370+
371+
@MessagesReactions@ object is the entry point for interacting with Message Reactions. It shall be exposed to consumers via a @reactions@ property insde the @Messages@ obejct. From the @Room@ level: @room.messages.reactions@.
372+
373+
* @(CHA-MR1)@ Message reactions are powered by Pub/Sub message annotations. The annotation type used is of the format @reaction:<aggregation>@.
374+
375+
* @(CHA-MR2)@ There are three types of message reactions, each corresponding to a different annotation aggregation type.
376+
** @(CHA-MR2a)@ @[Testable]@ Reactions of type @Unique@ use the annotation type @reaction:unique.v1@. In this type, each client can add a specific reaction emoji only once.
377+
** @(CHA-MR2b)@ @[Testable]@ Reactions of type @Distinct@ use the annotation type @reaction:distinct.v1@. Each client can add multiple different reactions, but each emoji only once.
378+
** @(CHA-MR2c)@ @[Testable]@ Reactions of type @Multiple@ use the annotation type @reaction:multiple.v1@. In this type, each client can add any reaction multiple times including duplicates.
379+
380+
* @(CHA-MR3)@ @[Testable]@ The @reactions@ property of the @Message@ object is an object or map that contains summaries for all message reaction types, keyed by reaction type and not annotation type (eg. "distinct" and not "reaction:distinct.v1").
381+
** @(CHA-MR3a)@ @[Testable]@ The values for each reaction type summary are the same as defined in PubSub for the respective annotation aggregation types.
382+
** @(CHA-MR3b)@ @[Testable]@ For @Unique@ reaction types, the summary is at @Message.reactions.unique@ and is of type @Dict<string, SummaryClientIdList>@ (see @TM7b2@).
383+
** @(CHA-MR3b3)@ @[Testable]@ For @Distinct@ reaction types, the summary is at @Message.reactions.distinct@ and is of type @Dict<string, SummaryClientIdList>@ (see @TM7b1@).
384+
** @(CHA-MR3b2)@ @[Testable]@ For @Multiple@ reaction types, the summary is at @Message.reactions.multiple@ and is of type @Dict<string, SummaryClientIdCounts>@ (see @TM7b3@).
385+
386+
* @(CHA-MR4)@ @[Testable]@ Sending a reaction is done via the @add@ method of the @MessagesReactions@ object (@room.messages.reactions.add@). The method accepts a message (or message serial), and an object where the @reaction@ (ie. emoji string), @type@ (optional) and @count@ (optional, only valid for type @multiple@) are specified.
387+
** @(CHA-MR4a)@ @[Testable]@ If @type@ is not specified, the default type for the room used.
388+
389+
* @(CHA-MR5)@ @[Testable]@ Users may configure a default message reactions type for a room. This configuration is provided at the @RoomOptions.messages.defaultMessageReactionType@ property, or idiomatic equivalent. The default value is @distinct@.
390+
391+
* @(CHA-MR6)@ @[Testable]@ Subscribing to message reactions is done via the @subscribe@ method of the @MessagesReactions@ object (@room.messages.reactions.subscribe@). The method accepts a callback (or similar idomatic construct) that receives message reactions summary events of type @MessageReactionSummaryEvent@.
392+
393+
* @(CHA-MR7)@ The @MessageReactionSummaryEvent@ interface provides information about reaction summaries for messages.
394+
** @(CHA-MR7a)@ @[Testable]@ The event must include a @type@ field set to indicate it's a reaction summary event.
395+
** @(CHA-MR7b)@ @[Testable]@ The event must include a @summary@ object containing:
396+
*** @(CHA-MR7b1)@ @[Testable]@ The @messageSerial@ identifying which message the reactions belong to.
397+
*** @(CHA-MR7b2)@ @[Testable]@ A @unique@ field containing reaction summaries for unique-type reactions.
398+
*** @(CHA-MR7b3)@ @[Testable]@ A @distinct@ field containing reaction summaries for distinct-type reactions.
399+
*** @(CHA-MR7b4)@ @[Testable]@ A @multiple@ field containing reaction summaries for multiple-type reactions.
400+
401+
* @(CHA-MR8)@ @[Testable]@ Subscribing to raw message reactions (as individual annotations) is done via the @subscribeRaw@ method of the @MessagesReactions@ object (@room.messages.reactions.subscribeRaw@). The method accepts a callback (or similar idomatic construct) that receives individual annotations of type @MessageReactionRawEvent@.
402+
* @(CHA-MR8a)@ @[Testable]@ Subscribing to raw message reactions throws an error if the room is not configured to support raw message reactions by setting room option @RoomOptions.messages.rawMessageReactions@ to @true@ (defaults to @false@).
403+
404+
* @(CHA-MR9)@ The @MessageReactionRawEvent@ interface provides information about individual message reaction events.
405+
** @(CHA-MR9a)@ @[Testable]@ The event must include a @type@ field indicating whether a reaction was added or removed.
406+
** @(CHA-MR9b)@ @[Testable]@ The event must include a @timestamp@ field containing the date/time when the event occurred.
407+
** @(CHA-MR9c)@ @[Testable]@ The event must include a @reaction@ object containing:
408+
*** @(CHA-MR9c1)@ @[Testable]@ A @messageSerial@ identifying which message the reaction belongs to.
409+
*** @(CHA-MR9c2)@ @[Testable]@ A @type@ field indicating the reaction type (unique, distinct, or multiple).
410+
*** @(CHA-MR9c3)@ @[Testable]@ A @reaction@ field containing the reaction string (typically an emoji).
411+
*** @(CHA-MR9c4)@ @[Testable]@ An optional @count@ field for reactions of type Multiple.
412+
*** @(CHA-MR9c5)@ @[Testable]@ A @clientId@ identifying the user who added or removed the reaction.
413+
** @(CHA-MR9d)@ Raw message reactions should not be used to update the message reaction summary on the client-side as this is likely to produce wrong results. Message reaction summaries are to be used for this.
414+
415+
* @(CHA-MR10)@ @[Testable]@ The room option @RoomOptions.messages.rawMessageReactions@ controls whether raw message reactions are enabled or not. The default value is @false@.
416+
** @(CHA-MR10a)@ @[Testable]@ If the room option is set to @true@, the SDK will add the @ANNOTATION_SUBSCRIBE@ channel mode to the realtime channel used for the room.
417+
418+
* @(CHA-MR11)@ @[Testable]@ The SDK always adds the @ANNOTATION_PUBLISH@ channel mode to the realtime channel used for the room.
419+
357420
h2(#reactions). Ephemeral Room Reactions
358421

359422
Ephemeral room reactions are one-time events that are sent to the room, such as thumbs-up or heart emojis. They are supposed to capture the current emotions in the room (e.g. everyone spamming the :tada: emoji when a team scores the winning goal).
@@ -747,6 +810,92 @@ h4(#rest-fetching-messages-response). Response V3
747810

748811
An array of V2 "@Message@ structs":#chat-structs-message-v2
749812

813+
814+
h3(#rest-sending-message-reactions). Sending message reactions
815+
816+
h4(#rest-sending-messages-reactions-request-v3). Request V3
817+
818+
Below is the full REST payload format for the V3 endpoint. The @count@ field is optional and it is only accepted for reactions of type @reaction:multiple.v1@.
819+
820+
<pre>
821+
POST /chat/v3/rooms/<roomId>/messages/<serial>/reactions
822+
{
823+
"type": "reaction:multiple.v1",
824+
"reaction": "🔥",
825+
"count": 5
826+
}
827+
</pre>
828+
829+
h4(#rest-sending-messages-response-v3). Response V3
830+
831+
A successful request shall result in status code @201 Created@.
832+
833+
The response body is as follows showing the serial of the new annotation.
834+
835+
<pre>
836+
{
837+
"serial": "01746631786947-000@cbfVqJopQBorrt95348450",
838+
}
839+
</pre>
840+
841+
h4(#rest-sending-messages-realtime-v3). Corresponding Realtime Event V3
842+
843+
Note this is an Annotation not a Message. ChannelMessage action is 21. The annotations are under the @annotations@ key.
844+
845+
<pre>
846+
{
847+
"action" : 0,
848+
"clientId" : "user-1",
849+
"messageSerial" : "01746631762878-000@cbfVqJopQBorrt95348450:000",
850+
"name" : "🔥",
851+
"serial" : "01746631786947-000@cbfVqJopQBorrt95348450:000",
852+
"type" : "reaction:multiple.v1",
853+
"count": 5
854+
}
855+
</pre>
856+
857+
A message summary event is also broadcast to the channel after adding or removing one or more annotations.
858+
859+
h3(#rest-deleting-message-reactions). Deleting message reactions
860+
861+
h4(#rest-deleting-messages-reactions-request-v3). Request V3
862+
863+
Below is the full REST payload format for the V3 endpoint. The @reaction@ param is ignored for reactions of type @reaction:unique.v1@ but it is required for all other reaction types.
864+
865+
<pre>
866+
DELETE /chat/v3/rooms/<roomId>/messages/<serial>/reactions?type=<reactionType>&reaction=<reaction>
867+
</pre>
868+
869+
h4(#rest-sending-messages-response-v3). Response V3
870+
871+
A successful request shall result in status code @200 OK@.
872+
873+
The response body is as follows showing the serial of the new annotation (annotation delete is also an annotation with annotation @action=1@).
874+
875+
<pre>
876+
{
877+
"serial": "01746632464399-000@cbfVqJopQBorrt95348450",
878+
}
879+
</pre>
880+
881+
h4(#rest-sending-messages-realtime-v3). Corresponding Realtime Event V3
882+
883+
Note this is an Annotation not a Message. ChannelMessage action is 21. The annotations are under the @annotations@ key.
884+
885+
<pre>
886+
{
887+
"action" : 1,
888+
"clientId" : "user-1",
889+
"messageSerial" : "01746631762878-000@cbfVqJopQBorrt95348450:000",
890+
"name" : "❤️",
891+
"serial" : "01746632464399-000@cbfVqJopQBorrt95348450:000",
892+
"type" : "reaction:distinct.v1"
893+
}
894+
</pre>
895+
896+
A message summary event is also broadcast to the channel after adding or removing one or more annotations.
897+
898+
750899
h2(#realtime-api). Chat Realtime API
751900

752901
This section describes the message formats for chat events that occur over a Realtime connection.
@@ -872,6 +1021,11 @@ h4(#chat-structs-message-v2). Messages V2
8721021
"bar": 1
8731022
}
8741023
},
1024+
},
1025+
"reactions": {
1026+
"unique": {"like": {"total": 2, "clientIds": ["userOne", "userTwo"]}, "love": {"total": 1, "clientIds": ["userThree"]}},
1027+
"distinct": {"like": {"total": 2, "clientIds": ["userOne", "userTwo"]}, "love": {"total": 1, "clientIds": ["userOne"]}},
1028+
"multiple": {"like": {"total": 5, "clientIds": {"userOne": 3, "userTwo": 2}}, "love": {"total": 10, "clientIds": {"userOne": 10}}},
8751029
}
8761030
}
8771031
</pre>
@@ -888,6 +1042,85 @@ Determining the global order of messages may be achieved by lexicographically co
8881042

8891043
Determining the global order of message versions may be achieved by lexicographically comparing the @version@. See @CHA-M10@ for more information.
8901044

1045+
When keeping a @Message@ updated, use the @Message.with(event)@ method to apply events to ensure correctness. The @with@ method returnes message instances with the event applied to them. If the event is not applicable due to being for an older version of the message, the method will return the message unchanged. If the event is applicable, a new instance will be returned with the event applied. @Message.with()@ correctly handles message reactions. See @CHA-M11@ for more information.
1046+
1047+
1048+
h3(#chat-structs-message-reactions-summary-event). Message reactions reaction summary
1049+
1050+
<pre>
1051+
{
1052+
type: "reaction.summary",
1053+
summary: {
1054+
messageSerial: "01726585978590-001@abcdefghij:001",
1055+
"unique": {
1056+
"like": {
1057+
"total": 2,
1058+
"clientIds": ["userOne", "userTwo"]
1059+
},
1060+
"love": {
1061+
"total": 1,
1062+
"clientIds": ["userThree"]
1063+
}
1064+
},
1065+
"distinct": {
1066+
"like" : {
1067+
"clientIds" : [
1068+
"userOne",
1069+
"userTwo"
1070+
],
1071+
"total" : 2
1072+
},
1073+
"love" : {
1074+
"clientIds" : [
1075+
"userOne"
1076+
],
1077+
"total" : 1
1078+
}
1079+
},
1080+
"multiple": {
1081+
"like" : {
1082+
"clientIds" : {
1083+
"userOne" : 3,
1084+
"userTwo" : 2
1085+
},
1086+
"total" : 5
1087+
},
1088+
"love" : {
1089+
"clientIds" : {
1090+
"userOne" : 10
1091+
},
1092+
"total" : 10
1093+
}
1094+
}
1095+
}
1096+
}
1097+
</pre>
1098+
1099+
1100+
h3(#chat-structs-message-reactions-raw-event). Message reactions raw reaction event
1101+
1102+
<pre>
1103+
{
1104+
type: "reaction.create",
1105+
timestamp: DateTime(),
1106+
reaction: {
1107+
messageSerial: "01726585978590-001@abcdefghij:001",
1108+
type: "reaction:multiple.v1",
1109+
reaction: ":like:",
1110+
count: 3,
1111+
clientId: "user1",
1112+
};
1113+
}
1114+
</pre>
1115+
1116+
Event @type@ can be @reaction.update@ or @reaction.delete@.
1117+
1118+
Event @reaction.type@ can be @reaction:unique.v1@, @reaction:distinct.v1@ or @reaction:multiple.v1@.
1119+
1120+
@reaction.count@ is optional and only set for @reaction:multiple.v1@.
1121+
1122+
1123+
8911124
h3(#chat-structs-ephemeral-reactions). Ephemeral Room Reactions
8921125

8931126
<pre>

0 commit comments

Comments
 (0)