diff --git a/content/api/realtime-sdk/types.textile b/content/api/realtime-sdk/types.textile index b3f817d4d5..3301c29e52 100644 --- a/content/api/realtime-sdk/types.textile +++ b/content/api/realtime-sdk/types.textile @@ -81,11 +81,12 @@ h3(#message). <%= partial partial_version('types/_message') %> -blang[jsall]. - h3(#message-action). - default: Message action +h3(#message-action). + default: MessageAction + objc,swift: ARTMessageAction + java: io.ably.lib.types.Message.Action - <%= partial partial_version('types/_message_action') %> +<%= partial partial_version('types/_message_action') %> h3(#message-annotations). default: MessageAnnotations diff --git a/content/api/rest-api.textile b/content/api/rest-api.textile index 57854cbf6f..408bbc7be1 100644 --- a/content/api/rest-api.textile +++ b/content/api/rest-api.textile @@ -14,6 +14,10 @@ jump_to: Channel API: - publish - message history#message-history + - get message#get-message + - update message#update-message + - delete message#delete-message + - message versions#message-versions - presence - presence history Push API: @@ -499,6 +503,227 @@ bc[json]. [{ timestamp: }] +h3(#get-message). Get latest version of a message + +h6. GET main.realtime.ably.net/channels/@@/messages/@@ + +Retrieve the latest version of a specific message by its serial identifier. + +Example request: + +bc[sh]. curl https://main.realtime.ably.net/channels/rest-example/messages/01826232498871-001@abcdefghij:001 \ + -u "{{API_KEY}}" + + +h5. Options + +- Accept := @application/json@ or @application/x-msgpack@ +- Auth required := yes ("basic":#basic-authentication or "token":#token-authentication with @history@ capability) + +h5. Returns + +A successful request returns a single @Message@ object containing the latest version of the message. + +See "MessageAction":/docs/api/realtime-sdk/types#message-action for the possible values of the @action@ enum. + +bc[json]. { + serial: , + name: , + data: , + timestamp: , + clientId: , + action: , + version: { + serial: , + clientId: , + timestamp: , + description: , + metadata: + } +} + +An unsuccessful request returns an error. A 404 error is returned if a message with that serial does not exist. + +h3(#update-message). Update a message + +h6. PATCH main.realtime.ably.net/channels/@@/messages/@@ + +Update an existing message on a channel, the message with the specified serial. This endpoint requires that the channel is configured with the "Message annotations, updates, and deletes" channel rule. + +See "Updating and deleting messages":/docs/messages/updates-deletes#update for more information about message updates and field semantics. + +The request body contains the message fields to update, along with optional operation metadata. Any fields not specified will be left as their original values. + +bc[json]. { + name: , + data: , + encoding: , + extras: , + operation: { + clientId: , + description: , + metadata: + } +} + +Example request: + +bc[sh]. curl -X PATCH https://main.realtime.ably.net/channels/rest-example/messages/01826232498871-001@abcdefghij:001 \ + -u "{{API_KEY}}" \ + -H "Content-Type: application/json" \ + --data \ + '{ + "data": "updated message content", + "operation": { + "description": "Fixed typo" + } + }' + +h5. Options + +- Content-Type := @application/json@, @application/x-msgpack@ or @application/x-www-form-urlencoded@ +- Accept := @application/json@ by default or @application/x-msgpack@ +- Auth required := yes ("basic":#basic-authentication or "token":#token-authentication with @message-update-own@ or @message-update-any@ capability) + +h5. Capabilities + +- @message-update-own@ := Can update your own messages (messages where the original publisher's @clientId@ matches the updater's @clientId@, where both are "identified":/docs/auth/identified-clients) +- @message-update-any@ := Can update any message on the channel + +h5. Returns + +A successful request returns the updated @Message@ object with the new version information. + +See "MessageAction":/docs/api/realtime-sdk/types#message-action for the possible values of the @action@ enum. + +bc[json]. { + serial: , + name: , + data: , + timestamp: , + clientId: , + action: , + version: { + serial: , + clientId: , + timestamp: , + description: , + metadata: + } +} + +An unsuccessful request returns an error. + +h3(#delete-message). Delete a message + +h6. POST main.realtime.ably.net/channels/@@/messages/@@/delete + +Delete a message on a channel, the message with the specified serial. This is a 'soft' delete that publishes a new version of the message with an action of @message.delete@. The full message history remains accessible through the "message versions":#message-versions endpoint. This endpoint requires that the channel is configured with the "Message annotations, updates, and deletes" channel rule. + +See "Updating and deleting messages":/docs/messages/updates-deletes#update for more information about message updates and field semantics. + +The request body contains the message fields to update, along with optional operation metadata. Any fields not specified will be left as their original values. + +bc[json]. { + name: , + data: , + encoding: , + extras: , + operation: { + clientId: , + description: , + metadata: + } +} + +Example request: + +bc[sh]. curl -X POST https://main.realtime.ably.net/channels/rest-example/messages/01826232498871-001@abcdefghij:001/delete \ + -u "{{API_KEY}}" \ + -H "Content-Type: application/json" \ + --data \ + '{ + "operation": { + "description": "Content violation" + } + }' + +h5. Options + +- Content-Type := @application/json@, @application/x-msgpack@ or @application/x-www-form-urlencoded@ +- Accept := @application/json@ by default, or @application/x-msgpack@, @text/html@ +- Auth required := yes ("basic":#basic-authentication or "token":#token-authentication with @message-delete-own@ or @message-delete-any@ capability) + +h5. Capabilities + +- @message-delete-own@ := Can delete your own messages (messages where the original publisher's @clientId@ matches the deleter's @clientId@, where both are "identified":/docs/auth/identified-clients) +- @message-delete-any@ := Can delete any message on the channel + +h5. Returns + +A successful request returns the updated @Message@ object with @action@ set to @message.delete@. + +See "MessageAction":/docs/api/realtime-sdk/types#message-action for the possible values of the @action@ enum. + +bc[json]. { + serial: , + name: , + data: , + timestamp: , + clientId: , + action: , + version: { + serial: , + clientId: , + timestamp: , + description: , + metadata: + } +} + +An unsuccessful request returns an error. + +h3(#message-versions). Retrieve message version history + +h6. GET main.realtime.ably.net/channels/@@/messages/@@/versions + +Retrieve all historical versions of a specific message, including the original and all subsequent updates or delete operations. This endpoint requires that the channel is configured with the "Message annotations, updates, and deletes" channel rule. + +Example request: + +bc[sh]. curl https://main.realtime.ably.net/channels/rest-example/messages/01826232498871-001@abcdefghij:001/versions \ + -u "{{API_KEY}}" + +h5. Options + +- Content-Type := not applicable +- Accept := @application/json@ by default, or @application/x-msgpack@, @text/html@ +- Auth required := yes ("basic":#basic-authentication or "token":#token-authentication with @history@ capability) + +h5. Returns + +A successful request returns a "paginated response":#pagination containing all versions of the message, ordered by version serial (oldest to newest). + +See "MessageAction":/docs/api/realtime-sdk/types#message-action for the possible values of the @action@ enum. + +bc[json]. [{ + serial: , + name: , + data: , + timestamp: , + clientId: , + action: , + version: { + serial: , + clientId: , + timestamp: , + description: , + metadata: + } +}] + +An unsuccessful request returns an error. + h3(#presence). Retrieve instantaneous presence status for a channel h6. GET main.realtime.ably.net/channels/@@/presence @@ -525,13 +750,16 @@ h5. Options h5. Returns A successful request returns a "paginated response":#pagination with an array containing the members that are currently present on the given channel. If there are no members present, an empty collection is returned. +, + +See "PresenceAction":/docs/api/realtime-sdk/types#presence-action for the possible values of the @action@ enum. bc[json]. [{ id: , clientId: , connectionId: timestamp: - action: , + action: data: }] @@ -563,12 +791,14 @@ h5. Returns A successful request returns a "paginated response":#pagination with an array containing the members that are currently present on the given channel. If there are no members present, an empty collection is returned. +See "PresenceAction":/docs/api/realtime-sdk/types#presence-action for the possible values of the @action@ enum. + bc[json]. [{ id: , clientId: , connectionId: timestamp: - action: , + action: data: }] @@ -1476,10 +1706,12 @@ bc[text]. [{ clientId: , connectionId: timestamp: - action: , + action: data: }] +See "PresenceAction":/docs/api/realtime-sdk/types#presence-action for the possible values of the @action@ enum. + *Failure*: If the batch request itself fails the response body contains an "ErrorInfo":/docs/api/rest-sdk/types#error-info object. *Partial success*: If the batch request itself succeeds, but one or more of the requests within the batch fails, then the response for the failed request contains an error object with the error code @40020@ and a status code of @400@. Successful requests within the batch include a @presence@ array that describes the presence state of each of the channel members. diff --git a/content/api/rest-sdk/channels.textile b/content/api/rest-sdk/channels.textile new file mode 100644 index 0000000000..918c58401d --- /dev/null +++ b/content/api/rest-sdk/channels.textile @@ -0,0 +1,379 @@ +--- +title: Channels +meta_description: "Client Library SDK REST API Reference Channels documentation." +meta_keywords: "Ably, Ably REST, API Reference, REST SDK, REST interface, REST API, Channels" +section: api +languages: + - javascript + - nodejs + - php + - python + - ruby + - java + - swift + - objc + - csharp + - go + - flutter +redirect_from: + - /docs/api/versions/v1.1/rest-sdk/channels + - /docs/api/versions/v1.0/rest-sdk/channels + - /docs/api/versions/v0.8/rest-sdk/channels +--- + +h2(#channels-object). + default: Channels + +The @Channels@ object, accessed from the "rest library client constructor":/docs/api/rest-sdk#channels, is used to create and destroy @Channel@ objects. It exposes the following public methods: + +h3(#channels-methods). Channels Methods + +h6(#get). + default: get + csharp: Get + +bq(definition). + default: "Channel":#properties get(String channelName, "ChannelOptions":#channel-options channelOptions) + csharp: "Channel":#properties Get(String channelName, "ChannelOptions":#channel-options channelOptions) + objc,swift: "ARTRealtimeChannel":#properties get(String channelName, "ARTChannelOptions":#channel-options channelOptions); + +Creates a new "Channel":#properties object if none for the channel exists, or returns the existing channel object. + +h6(#release). + default: release + csharp: Release + +bq(definition). + default: release(String channelName) + java,objc,swift,flutter: void release(String channelName) + csharp: bool Release(string channelName) + +Releases a "Channel":#properties object, deleting it from the local SDK client instance and enabling it to be garbage collected. + +This method only affects the local client-side representation of the channel. The channel itself on the Ably platform is not deleted or changed, and other client instances (in the same or different processes) are unaffected. + +After releasing a channel, calling @channels.get(channelName)@ will create a fresh channel object. If using a singleton REST client pattern with multiple execution contexts, be cautious when calling @release@ as it will affect all parts of your application using that client instance. Subsequent publish operations on the same channel name will require obtaining a new channel object. + +h2(#channel-object). Channel + +The Channel object, created via the "Channels":#channels-object object, is used to interact with a specific channel. + +h3(#properties). + default: Channel Properties + python: Channel Attributes + php: Ably\Channel Properties + objc,swift: ARTRestChannel Properties + ruby: Ably::Rest::Channel Attributes + java: io.ably.lib.rest.Channel Members + csharp: IO.Ably.Rest.RestChannel Members + +The @Channel@ object exposes the following public propertiesattributesmembers: + +h6(#name). + default: name + csharp,go: Name + +The name @String@ unique to this channel. + +h6(#presence). + default: presence + csharp,go: Presence + +Provides access to the "REST Presence":/docs/presence-occupancy/presence object for this channel which can be used to get members present on the channel, or retrieve presence event history. + +h6(#push). + default: push + +Provides access to the "PushChannel":/docs/api/realtime-sdk/push#push-channel object for this channel which can be used to access members present on the channel, or participate in presence. + +h3. Channel Methods + +h6(#publish). + default: publish + csharp,go: Publish + +There are two overloaded versions of this method: + +bq(definition#publish-data). + default: publish(String name, Object data, callback("ErrorInfo":/docs/api/realtime-sdk/types#error-info err)) + jsall: publish(String name, Object data, "PublishOptions":#publish-options options?) Promise + ruby,php: publish(String name, Object data) + python: publish(name=Unicode, data=Object) + java: void publish(String name, Object data) + csharp: Task PublishAsync(string name, object data, string clientId = null) + objc,swift: publish(name: String?, data: AnyObject?, callback: (("ARTErrorInfo":/docs/api/realtime-sdk/types#error-info?) -> Void)?) + go: (c *RestChannel) Publish(name string, data interface{}) (error "ErrorInfo":#error-info) + flutter: Future publish({String name, Object data}) + +Publish a single message on this channel based on a given event name and payload. A callback may optionally be passed in to this call to be notified of success or failure of the operation.A listener may optionally be passed in to this call to be notified of success or failure of the operation.A callback may optionally be passed in to this call to be notified of success of the operation. + +It is also possible to publish a message to multiple channels at once using our "batch publish feature":/docs/messages/batch#batch-publish. + +blang[jsall]. + + bq(definition#publish-msg). + jsall: publish("Message":#message message, "PublishOptions":#publish-options options?): Promise + + Publish a single message on this channel. + +bq(definition#publish-msg-array). + default: publish(Object[] messages, callback("ErrorInfo":/docs/api/realtime-sdk/types#error-info err)) + jsall: publish("Message[]":#message messages, "PublishOptions":#publish-options options?): Promise + ruby,php: publish("Message[]":#message messages) + python: publish(messages=List<"Message":#message>) + java: void publish("Message[]":#message messages) + csharp: Task PublishAsync(IEnumerable<"Message":#message> messages) + objc,swift: publish(messages: [ "ARTMessage":#message ], callback: (("ARTErrorInfo":/docs/api/realtime-sdk/types#error-info?) -> Void)?) + go: (c *RestChannel) PublishAll(messages []*proto.Message) (error "ErrorInfo":#error-info) + flutter: Future publish({List<"Message":#message> messages}) + +Publish several messages on this channel. A callback may optionally be passed in to this call to be notified of success or failure of the operation.A listener may optionally be passed in to this call to be notified of success or failure of the operation.A callback may optionally be passed in to this call to be notified of success of the operation. + +The entire @messages@ array is published atomically. This means that: + +* Either they will all be successfully published or none of them will +* The "max message size":/docs/platform/pricing/limits#message limit applies to the total size of all messages in the array +* The publish will only count as a single message for the purpose of "per-channel rate limit":/docs/platform/pricing/limits#message +* If you are using client-specified message IDs for publish idempotency, "they must conform to certain restrictions":https://faqs.ably.com/client-specified-message-id-restrictions-for-multiple-messages-published-atomically + +h4. Parameters + +-
name
:= event name for the published message
__Type: @String@__ +-
name
:= event name for the published message
__Type: @Unicode@ for Python 2, @String@ for Python 3__ +-
data
:= data payload for the message. The supported payload types are Strings, objects or arrays capable of JSON representation, buffers containing arbitrary binary data, and null. (Note that if sending a binary, that binary should be the entire payload; an object with a binary field within it may not be correctly encoded)
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are Strings, JsonObject, binary data as byte arrays, and null.
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are strings, plain .NET objects, binary data as byte arrays, and null.
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are Strings, Hash or Array objects that can be serialized to JSON using @to_json@, binary data as @ASCII-8BIT@ byte arrays, and null. (Note that if sending a byte array, it should be the entire payload; a hash or array with a bytearray field within it may not be correctly encoded)
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are unicode Strings, Dict, or List objects that can be serialized to JSON using @json.dumps@, binary data as @bytearray@ (in Python 3, @bytes@ also works), and None.
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are @NS@@String@, @NS@@Dictionary@ or @NS@@Array@ objects that can be serialized to JSON, binary data as @NSData@, and @nil@.
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload types are Strings, Associative Array or Array objects that can be serialized to JSON, binary data as byte arrays, and null.
__Type: @Object@__ +-
data
:= data payload for the message. The supported payload type are strings, objects that can be serialized to JSON, binary data as byte arrays, and nil.
__Type: @interface@ +-
data
:= data payload for the message. The supported payload types are String, Map, List, and null.
__Type: @Object@__ + +-
message
:= payload for the message as a "@Message@":#message object.
__Type: "@Message@":#message__ +- messages := An array of message objects to publish
__Type: "@Message []@":#message__ + +-
callback
:= called upon publishing the message, or with an error + +-
options
:= optional parameters to provide to the publish operation
__Type:"@PublishOptions@":#publish-options__ + +blang[jsall]. + h4. Returns + + Returns a promise. On success, the promise resolves. On failure, the promise is rejected with an "@ErrorInfo@":#error-info object that details the reason why it was rejected. + +blang[swift,objc]. + h4. Callback result + + On successful publish of the message, @err@ is null. On failure to publish the message, @err@ contains an "@ErrorInfo@":#error-info object describing the failure reason. + +blang[java,ruby,php]. + h4. Failure + + On failure to publish the message, an "@AblyException@":/docs/api/rest-sdk/types#ably-exception will be raised. + +blang[csharp]. + h4. Returns + + The method is asynchronous and returns a Task that can be awaited. + + On failure to publish the message, an "@AblyException@":/docs/api/rest-sdk/types#ably-exception will be raised. + +blang[go]. + h4. Returns + + The function returns "@ErrorInfo@":#error-info if an error has occurred, otherwise it returns @nil@. + +blang[flutter]. + h4. Returns + + The function throws "@ably.AblyException@" if an error has occurred. + +h6(#history). + default: history + csharp,go: History + +bq(definition). + default: history(Object options, callback("ErrorInfo":/docs/api/realtime-sdk/types#error-info err, "PaginatedResult":#paginated-result<"Message":#message> resultPage)) + jsall: history(Object params?): Promise<"PaginatedResult":#paginated-result<"Message":#message>> + ruby: "PaginatedResult":#paginated-result<"Message":#message> history(Hash options) + python: "PaginatedResult":#paginated-result<"Message":#message> history(kwargs_options) + php: "PaginatedResult":#paginated-result<"Message":#message> history(Array options) + java: "PaginatedResult":#paginated-result<"Message":#message> history("Param":#param[] options) + csharp: Task<"PaginatedResult":#paginated-result<"Message":#message>> HistoryAsync("PaginatedRequestParams":#paginated-request-params dataQuery) + objc,swift: history(query: ARTRealtimeHistoryQuery?, callback: ("ARTPaginatedResult":#paginated-result<"ARTMessage":#message>?, ARTErrorInfo?) -> Void) throws + go: (c *RestChannel) History(options *PaginateParams) (*"PaginatedResult":#paginated-result, "error":#error-info) + +Gets a "paginated":#paginated-result set of historical messages for this channel. If the "channel is configured to persist messages to disk":https://faqs.ably.com/how-long-are-messages-stored-for, then message history will "typically be available for 24 - 72 hours":https://faqs.ably.com/how-long-are-messages-stored-for. If not, messages are only retained in memory by the Ably service for two minutes. + +h4. Parameters + +- optionsparamsquery"Param":#param[] options := an optional object containing the query parametersoptional keyword arguments containing the query parametersan optional set of key value pairs containing the query parametersan optional Associative Array containing the query parameters, as specified in the "message history API documentation":/docs/api/rest-sdk/history#channel-history. + +-
callback
:= called with a "ARTPaginatedResult":#paginated-result<"ARTMessage":#message> object or an error + +blang[jsall]. + h4. Returns + + Returns a promise. On success, the promise is fulfilled with a "PaginatedResult":#paginated-result object containing an array of messages. On failure, the promise is rejected with an "@ErrorInfo@":#error-info object that details the reason why it was rejected. + +blang[objc,swift]. + h4. Callback result + + On success, @resultPage@ contains a "@PaginatedResult@":#paginated-result encapsulating an array of "@Message@":#message objects corresponding to the current page of results. "@PaginatedResult@":#paginated-result supports pagination using "@next()@":#paginated-result and "@first()@":#paginated-result methods. + + On failure to retrieve message history, @err@ contains an "@ErrorInfo@":#error-info object with the failure reason. + +blang[java,ruby,php,python]. + h4. Returns + + On success, the returned "@PaginatedResult@":#paginated-result encapsulates an array of "@Message@":#message objects corresponding to the current page of results. "@PaginatedResult@":#paginated-result supports pagination using "@next@":#paginated-result and "@first@":#paginated-result methods. + + Failure to retrieve the message history will raise an "@AblyException@":/docs/api/realtime-sdk/types#ably-exception + +blang[csharp]. + h4. Returns + + The method is asynchronous and return a Task that has to be awaited to get the result. + + On success, the returned "@PaginatedResult@":#paginated-result encapsulates an array of "@Message@":#message objects corresponding to the current page of results. "@PaginatedResult@":#paginated-result supports pagination using "@NextAsync@":#paginated-result and "@FirstAsync@":#paginated-result methods. + + Failure to retrieve the message history will raise an "@AblyException@":/docs/api/realtime-sdk/types#ably-exception + +blang[go]. + h4. Returns + + On success, the returned "@PaginatedResult@":#paginated-result encapsulates an array of "@Message@":#message objects corresponding to the current page of results. "@PaginatedResult@":#paginated-result supports pagination using "@next@":#paginated-result and "@first@":#paginated-result methods. @error@ will be nil. + + On failure to retrieve message history, the @error@ contains an "@ErrorInfo@":#error-info object with the failure reason. + +blang[jsall]. + + h6(#get-message). + jsall: getMessage + + bq(definition). + jsall: getMessage(serialOrMessage: string | "Message":#message): Promise<"Message":#message> + + Retrieves the latest version of a specific message by its serial identifier. Requires the *history* "capability":/docs/auth/capabilities. + + h4. Parameters + + - serialOrMessage := Either the serial identifier string of the message to retrieve, or a "@Message@":#message object containing a populated @serial@ field
__Type: @String@ or "@Message@":#message__ + + h4. Returns + + Returns a promise which, upon success, will be fulfilled with a "@Message@":#message object representing the latest version of the message. Upon failure, the promise will be rejected with an "@ErrorInfo@":#error-info object which explains the error. + + h6(#update-message). + jsall: updateMessage + + bq(definition). + jsall: updateMessage(message: "Message":#message, operation?: MessageOperation, params?: Object): Promise<"Message":#message> + + Publishes an update to an existing message with patch semantics. Non-null @name@, @data@, and @extras@ fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the *message-update-own* or *message-update-any* "capability":/docs/auth/capabilities. + + See "updating and deleting messages":/docs/messages/updates-deletes for more information. + + h4. Parameters + + - message := A "@Message@":#message object containing a populated @serial@ field and the fields to update
__Type: "@Message@":#message__ + - operation := An optional @MessageOperation@ object containing metadata about the update operation. Can include @clientId@, @description@, and @metadata@ fields
__Type: @MessageOperation@ (optional)__ + - params := Optional parameters sent as part of the query string
__Type: @Object@ (optional)__ + + h4. Returns + + Returns a promise which, upon success, will be fulfilled with a "@Message@":#message object containing the updated message. Upon failure, the promise will be rejected with an "@ErrorInfo@":#error-info object which explains the error. + + h6(#delete-message). + jsall: deleteMessage + + bq(definition). + jsall: deleteMessage(message: "Message":#message, operation?: MessageOperation, params?: Object): Promise<"Message":#message> + + Marks a message as deleted by publishing an update with an action of @MESSAGE_DELETE@. This does not remove the message from the server, and the full message history remains accessible. Uses patch semantics: non-null @name@, @data@, and @extras@ fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the *message-delete-own* or *message-delete-any* "capability":/docs/auth/capabilities. + + See "updating and deleting messages":/docs/messages/updates-deletes for more information. + + h4. Parameters + + - message := A "@Message@":#message object containing a populated @serial@ field
__Type: "@Message@":#message__ + - operation := An optional @MessageOperation@ object containing metadata about the delete operation. Can include @clientId@, @description@, and @metadata@ fields
__Type: @MessageOperation@ (optional)__ + - params := Optional parameters sent as part of the query string
__Type: @Object@ (optional)__ + + h4. Returns + + Returns a promise which, upon success, will be fulfilled with a "@Message@":#message object containing the deleted message. Upon failure, the promise will be rejected with an "@ErrorInfo@":#error-info object which explains the error. + + h6(#get-message-versions). + jsall: getMessageVersions + + bq(definition). + jsall: getMessageVersions(serialOrMessage: string | "Message":#message, params?: Object): Promise<"PaginatedResult":#paginated-result<"Message":#message>> + + Retrieves all historical versions of a specific message, ordered by version. This includes the original message and all subsequent updates or delete operations. Requires the *history* "capability":/docs/auth/capabilities. + + See "updating and deleting messages":/docs/messages/updates-deletes for more information. + + h4. Parameters + + - serialOrMessage := Either the serial identifier string of the message whose versions are to be retrieved, or a "@Message@":#message object containing a populated @serial@ field
__Type: @String@ or "@Message@":#message__ + - params := Optional parameters sent as part of the query string
__Type: @Object@ (optional)__ + + h4. Returns + + Returns a promise which, upon success, will be fulfilled with a "@PaginatedResult@":#paginated-result object containing an array of "@Message@":#message objects representing all versions of the message. Upon failure, the promise will be rejected with an "@ErrorInfo@":#error-info object which explains the error. + +h2(#related-types). Related types + +h3(#message). + default: Message + objc,swift: ARTMessage + ruby: Ably::Models::Message + php: Ably\Models\Message + java: io.ably.lib.types.Message + csharp: IO.Ably.Message + +<%= partial partial_version('types/_message') %> + +h3(#channel-options). + default: ChannelOptions Object + objc,swift: ARTChannelOptions + ruby: ChannelOptions Hash + python: ChannelOptions keyword arguments + php: ChannelOptions Array + java: io.ably.lib.types.ChannelOptions + csharp: IO.Ably.ChannelOptions + +<%= partial partial_version('types/_channel_options') %> + +h3(#publish-options). + jsall: PublishOptions + +Options passed to a "@publish()@":#publish operation to customize its behavior. + +h4(). Parameters + +- quickAck := Reduces the latency of REST publishes, though provides a "slightly lower quality of service":https://faqs.ably.com/why-are-some-rest-publishes-on-a-channel-slow-and-then-typically-faster-on-subsequent-publishes
__Type: @Boolean@__ + +h3(#paginated-request-params). + csharp: PaginatedRequestParams + +blang[csharp]. + <%= partial partial_version('types/_history_request_params'), indent: 2, skip_first_indent: true %> + +h3(#paginated-result). + default: PaginatedResult + objc,swift: ARTPaginatedResult + ruby: Ably::Models::PaginatedResult + php: Ably\Models\PaginatedResult + java: io.ably.lib.types.PaginatedResult + csharp: IO.Ably.PaginatedResult + +<%= partial partial_version('types/_paginated_result') %> + +h3(#param). + java: io.ably.lib.types.Param + +blang[java]. + <%= partial partial_version('types/_param'), indent: 2, skip_first_indent: true %> diff --git a/content/partials/types/_message.textile b/content/partials/types/_message.textile index d392589dea..00f65e50bb 100644 --- a/content/partials/types/_message.textile +++ b/content/partials/types/_message.textile @@ -64,18 +64,23 @@ blang[jsall]. h6(#action). default: action - The action type of the message, one of the "@MessageAction@":/docs/api/realtime-sdk/types#message-action enum values.
__Type: @int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }@__ + The action type of the message, one of the "@MessageAction@":#message-action enum values.
__Type: @int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }@__ h6(#serial). default: serial - A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in "channel rules":/docs/channels#rules .
__Type: @String@__ + A server-assigned identifier that will be the same in all future updates of this message. It can be used to add "annotations":/docs/messages/annotations to a message or to "update or delete":/docs/messages/updates-deletes it. Serial will only be set if you enable annotations, updates, and deletes in "channel rules":/docs/channels#rules .
__Type: @String@__ h6(#annotations). default: annotations An object containing information about annotations that have been made to the object.
__Type: "@MessageAnnotations@":/docs/api/realtime-sdk/types#message-annotations__ + h6(#version). + default: version + + An object containing version metadata for messages that have been updated or deleted. See "updating and deleting messages":/docs/messages/updates-deletes for more information.
__Type: "@MessageVersion@":#message-version__ + h3(constructors). default: Message constructors @@ -112,3 +117,15 @@ h4. Parameters h4. Returns An @Array@ of "@Message@":/docs/api/realtime-sdk/types#message objects + +h3(#message-version). + default: MessageVersion + +h4. Properties + +|_. Property |_. Description |_. Type | +| serial | An Ably-generated ID that uniquely identifies this version of the message. Can be compared lexicographically to determine version ordering. For an original message with an action of @message.create@, this will be equal to the top-level @serial@. | @String@ | +| timestamp | The time this version was created (when the update or delete operation was performed). For an original message, this will be equal to the top-level @timestamp@. | @Integer@@Long Integer@@DateTimeOffset@@Time@@NSDate@ | +| clientId | The client identifier of the user who performed the update or delete operation. Only present for @message.update@ and @message.delete@ actions. | @String@ (optional) | +| description | Optional description provided when the update or delete was performed. Only present for @message.update@ and @message.delete@ actions. | @String@ (optional) | +| metadata | Optional metadata provided when the update or delete was performed. Only present for @message.update@ and @message.delete@ actions. | @Object@ (optional) | diff --git a/content/partials/types/_message_action.textile b/content/partials/types/_message_action.textile index b525ba9066..ef6d69b2ae 100644 --- a/content/partials/types/_message_action.textile +++ b/content/partials/types/_message_action.textile @@ -1,11 +1,61 @@ -@Message@ @action@ is a String representing the action type of the message. +blang[default]. + @MessageAction@ is an enum representing the action type of the message. -```[javascript] - const MessageActions = [ + ``` + enum MessageAction { + MESSAGE_CREATE, // 0 + MESSAGE_UPDATE, // 1 + MESSAGE_DELETE, // 2 + META, // 3 + MESSAGE_SUMMARY // 4 + } + ``` + +blang[jsall]. + @Message@ @action@ is a String representing the action type of the message. + + ```[javascript] + var MessageActions = [ 'message.create', 'message.update', 'message.delete', 'meta', 'message.summary' - ] -``` + ] + ``` + +blang[java]. + @io.ably.lib.types.Message.Action@ is an enum representing the action type of the message. + + ```[java] + public enum Action { + MESSAGE_CREATE, // 0 + MESSAGE_UPDATE, // 1 + MESSAGE_DELETE, // 2 + META, // 3 + MESSAGE_SUMMARY // 4 + } + ``` + +blang[objc,swift]. + @ARTMessageAction@ is an enum representing the action type of the message. + + ```[objc] + typedef NS_ENUM(NSUInteger, ARTMessageAction) { + ARTMessageActionCreate, + ARTMessageActionUpdate, + ARTMessageActionDelete, + ARTMessageActionMeta, + ARTMessageActionMessageSummary + }; + ``` + + ```[swift] + enum ARTMessageAction : UInt { + case Create + case Update + case Delete + case Meta + case Summary + } + ``` diff --git a/src/data/nav/pubsub.ts b/src/data/nav/pubsub.ts index 3d949f045d..b29bc548d4 100644 --- a/src/data/nav/pubsub.ts +++ b/src/data/nav/pubsub.ts @@ -199,6 +199,10 @@ export default { name: 'Message annotations', link: '/docs/messages/annotations', }, + { + name: 'Updates and deletes', + link: '/docs/messages/updates-deletes', + }, ], }, { diff --git a/src/pages/docs/api/realtime-sdk/channels.mdx b/src/pages/docs/api/realtime-sdk/channels.mdx index 4e3f16472b..d95c25bb2a 100644 --- a/src/pages/docs/api/realtime-sdk/channels.mdx +++ b/src/pages/docs/api/realtime-sdk/channels.mdx @@ -816,6 +816,85 @@ Failure to retrieve the message history will trigger the `errback` callbacks of + + +#### getMessage + +`getMessage(serialOrMessage: string | Message): Promise` + +Retrieves the latest version of a specific message by its serial identifier. Requires the **history** [capability](/docs/auth/capabilities). + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| serialOrMessage | Either the serial identifier string of the message to retrieve, or a [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | `string` or [`Message`](/docs/api/realtime-sdk/messages) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object representing the latest version of the message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### updateMessage + +`updateMessage(message: Message, operation?: MessageOperation, params?: Record): Promise` + +Publishes an update to an existing message with patch semantics. Non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-update-own** or **message-update-any** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| message | A [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field and the fields to update | [`Message`](/docs/api/realtime-sdk/messages) | +| operation | An optional `MessageOperation` object containing metadata about the update operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object containing the updated message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### deleteMessage + +`deleteMessage(message: Message, operation?: MessageOperation, params?: Record): Promise` + +Marks a message as deleted by publishing an update with an action of `MESSAGE_DELETE`. This does not remove the message from the server, and the full message history remains accessible. Uses patch semantics: non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-delete-own** or **message-delete-any** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| message | A [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | [`Message`](/docs/api/realtime-sdk/messages) | +| operation | An optional `MessageOperation` object containing metadata about the delete operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object containing the deleted message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### getMessageVersions + +`getMessageVersions(serialOrMessage: string | Message, params?: Record): Promise>` + +Retrieves all historical versions of a specific message, ordered by version. This includes the original message and all subsequent updates or delete operations. Requires the **history** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| serialOrMessage | Either the serial identifier string of the message whose versions are to be retrieved, or a [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | `string` or [`Message`](/docs/api/realtime-sdk/messages) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`PaginatedResult`](#paginated-result) object containing an array of [`Message`](/docs/api/realtime-sdk/messages) objects representing all versions of the message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + + + #### setOptions @@ -1847,22 +1926,23 @@ Timestamp when the message was first received by the Ably, as + -#### action +### action
-The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values. -**Type: `int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`** +The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ -#### serial +### serial
-A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in [channel rules](/docs/channels#rules). -**Type: `String`** +A server-assigned identifier that will be the same in all future updates of this message. It can be used to add [annotations](/docs/messages/annotations) to a message or to [update or delete](/docs/messages/updates-deletes) it. Serial will only be set if you enable annotations, updates, and deletes in [channel rules](/docs/channels#rules).
_Type: `String`_ + +### annotations
+ +An object containing information about annotations that have been made to the object.
_Type: [`MessageAnnotations`](/docs/api/realtime-sdk/types#message-annotations)_ -#### annotations +### version
-An object containing information about annotations that have been made to the object. -**Type: [`MessageAnnotations`](/docs/api/realtime-sdk/types#message-annotations)** +An object containing version metadata for messages that have been updated or deleted. See [updating and deleting messages](/docs/messages/updates-deletes) for more information.
_Type: [`MessageVersion`](#message-version)_ diff --git a/src/pages/docs/api/realtime-sdk/messages.mdx b/src/pages/docs/api/realtime-sdk/messages.mdx index 13aaa7a243..7118cd20df 100644 --- a/src/pages/docs/api/realtime-sdk/messages.mdx +++ b/src/pages/docs/api/realtime-sdk/messages.mdx @@ -48,20 +48,24 @@ Timestamp when the message was first received by the Ably, as + -### action
+### action -The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ +The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ -### serial
+### serial -A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in [channel rules](/docs/channels#rules).
_Type: `String`_ +A server-assigned identifier that will be the same in all future updates of this message. It can be used to add [annotations](/docs/messages/annotations) to a message or to [update or delete](/docs/messages/updates-deletes) it. Serial will only be set if you enable annotations, updates, and deletes in [channel rules](/docs/channels#rules).
_Type: `String`_ -### annotations
+### annotations An object containing information about annotations that have been made to the object.
_Type: [`MessageAnnotations`](/docs/api/realtime-sdk/types#message-annotations)_ +### version
+ +An object containing version metadata for messages that have been updated or deleted. See [updating and deleting messages](/docs/messages/updates-deletes) for more information.
_Type: [`MessageVersion`](#message-version)_ + ### Message constructors
@@ -107,3 +111,15 @@ An `Array` of [`Message`](/docs/api/realtime-sdk/types#message) objects | Property | Description | Type | |----------|-------------|------| | summary | An object whose keys are annotation types, and the values are aggregated summaries for that annotation type | `Record` | + +## MessageVersion + +#### PropertiesMembersAttributes + +| Property | Description | Type | +|----------|-------------|------| +| serial | An Ably-generated ID that uniquely identifies this version of the message. Can be compared lexicographically to determine version ordering. For an original message with an action of `message.create`, this will be equal to the top-level `serial`. | `String` | +| timestamp | The time this version was created (when the update or delete operation was performed). For an original message, this will be equal to the top-level `timestamp`. | `Integer``Long Integer``DateTimeOffset``Time``NSDate` | +| clientId | The client identifier of the user who performed the update or delete operation. Only present for `message.update` and `message.delete` actions. | `String` (optional) | +| description | Optional description provided when the update or delete was performed. Only present for `message.update` and `message.delete` actions. | `String` (optional) | +| metadata | Optional metadata provided when the update or delete was performed. Only present for `message.update` and `message.delete` actions. | `Object` (optional) | diff --git a/src/pages/docs/api/rest-sdk/channels.mdx b/src/pages/docs/api/rest-sdk/channels.mdx index 76b1d045e8..46027754b1 100644 --- a/src/pages/docs/api/rest-sdk/channels.mdx +++ b/src/pages/docs/api/rest-sdk/channels.mdx @@ -465,6 +465,85 @@ On failure to retrieve message history, the `error` contains an [`ErrorInfo`](#e + + +#### getMessage + +`getMessage(serialOrMessage: string | Message): Promise` + +Retrieves the latest version of a specific message by its serial identifier. Requires the **history** [capability](/docs/auth/capabilities). + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| serialOrMessage | Either the serial identifier string of the message to retrieve, or a [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | `string` or [`Message`](/docs/api/realtime-sdk/messages) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object representing the latest version of the message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### updateMessage + +`updateMessage(message: Message, operation?: MessageOperation, params?: Record): Promise` + +Publishes an update to an existing message with patch semantics. Non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-update-own** or **message-update-any** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| message | A [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field and the fields to update | [`Message`](/docs/api/realtime-sdk/messages) | +| operation | An optional `MessageOperation` object containing metadata about the update operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object containing the updated message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### deleteMessage + +`deleteMessage(message: Message, operation?: MessageOperation, params?: Record): Promise` + +Marks a message as deleted by publishing an update with an action of `MESSAGE_DELETE`. This does not remove the message from the server, and the full message history remains accessible. Uses patch semantics: non-null `name`, `data`, and `extras` fields in the provided message will replace the corresponding fields in the existing message, while null fields will be left unchanged. Requires the **message-delete-own** or **message-delete-any** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| message | A [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | [`Message`](/docs/api/realtime-sdk/messages) | +| operation | An optional `MessageOperation` object containing metadata about the delete operation. Can include `clientId`, `description`, and `metadata` fields | `MessageOperation` (optional) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`Message`](/docs/api/realtime-sdk/messages) object containing the deleted message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + +#### getMessageVersions + +`getMessageVersions(serialOrMessage: string | Message, params?: Record): Promise>` + +Retrieves all historical versions of a specific message, ordered by version. This includes the original message and all subsequent updates or delete operations. Requires the **history** [capability](/docs/auth/capabilities). + +See [updating and deleting messages](/docs/messages/updates-deletes) for more information. + +##### Parameters + +| Parameter | Description | Type | +|-----------|-------------|------| +| serialOrMessage | Either the serial identifier string of the message whose versions are to be retrieved, or a [`Message`](/docs/api/realtime-sdk/messages) object containing a populated `serial` field | `string` or [`Message`](/docs/api/realtime-sdk/messages) | +| params | Optional parameters sent as part of the query string | `Record` (optional) | + +##### Returns + +Returns a promise which, upon success, will be fulfilled with a [`PaginatedResult`](#paginated-result) object containing an array of [`Message`](/docs/api/realtime-sdk/messages) objects representing all versions of the message. Upon failure, the promise will be rejected with an [`ErrorInfo`](/docs/api/realtime-sdk/types#error-info) object which explains the error. + + + ## Related types ### MessageARTMessageAbly::Models::MessageAbly\Models\Messageio.ably.lib.types.MessageIO.Ably.Message @@ -507,20 +586,24 @@ Timestamp when the message was first received by the Ably, as + -#### action +### action -The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ +The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ -#### serial +### serial
-A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in [channel rules](/docs/channels#rules) .
_Type: `String`_ +A server-assigned identifier that will be the same in all future updates of this message. It can be used to add [annotations](/docs/messages/annotations) to a message or to [update or delete](/docs/messages/updates-deletes) it. Serial will only be set if you enable annotations, updates, and deletes in [channel rules](/docs/channels#rules).
_Type: `String`_ -#### annotations +### annotations
An object containing information about annotations that have been made to the object.
_Type: [`MessageAnnotations`](/docs/api/realtime-sdk/types#message-annotations)_ +### version
+ +An object containing version metadata for messages that have been updated or deleted. See [updating and deleting messages](/docs/messages/updates-deletes) for more information.
_Type: [`MessageVersion`](#message-version)_ + ### Message constructors diff --git a/src/pages/docs/api/rest-sdk/messages.mdx b/src/pages/docs/api/rest-sdk/messages.mdx index b774a90ad2..3312386224 100644 --- a/src/pages/docs/api/rest-sdk/messages.mdx +++ b/src/pages/docs/api/rest-sdk/messages.mdx @@ -48,15 +48,15 @@ This will typically be empty as all messages received from Ably are automaticall -### action
+#### action The action type of the message, one of the [`MessageAction`](/docs/api/realtime-sdk/types#message-action) enum values.
_Type: `int enum { MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, META, MESSAGE_SUMMARY }`_ -### serial
+#### serial -A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in [channel rules](/docs/channels#rules).
_Type: `String`_ +A server-assigned identifier that will be the same in all future updates of this message. It can be used to add annotations to a message. Serial will only be set if you enable annotations in [channel rules](/docs/channels#rules) .
_Type: `String`_ -### annotations
+#### annotations An object containing information about annotations that have been made to the object.
_Type: [`MessageAnnotations`](/docs/api/realtime-sdk/types#message-annotations)_ @@ -97,3 +97,15 @@ A static factory method to create an array of [`Messages`](/docs/api/realtime-sd #### Returns An `Array` of [`Message`](/docs/api/realtime-sdk/types#message) objects + +## MessageVersion
+ +#### Properties + +| Property | Description | Type | +|----------|-------------|------| +| serial | An Ably-generated ID that uniquely identifies this version of the message. Can be compared lexicographically to determine version ordering. For an original message with an action of `message.create`, this will be equal to the top-level `serial`. | `String` | +| timestamp | The time this version was created (when the update or delete operation was performed). For an original message, this will be equal to the top-level `timestamp`. | `Integer``Long Integer``DateTimeOffset``Time``NSDate` | +| clientId | The client identifier of the user who performed the update or delete operation. Only present for `message.update` and `message.delete` actions. | `String` (optional) | +| description | Optional description provided when the update or delete was performed. Only present for `message.update` and `message.delete` actions. | `String` (optional) | +| metadata | Optional metadata provided when the update or delete was performed. Only present for `message.update` and `message.delete` actions. | `Object` (optional) | diff --git a/src/pages/docs/auth/capabilities.mdx b/src/pages/docs/auth/capabilities.mdx index 1551dac175..5611b30067 100644 --- a/src/pages/docs/auth/capabilities.mdx +++ b/src/pages/docs/auth/capabilities.mdx @@ -42,6 +42,10 @@ The following capability operations are available for API keys and issued tokens | **object-publish** | Can update objects on a channel | | **annotation-subscribe** | Can subscribe to individual annotations on a channel | | **annotation-publish** | Can publish annotations to messages on a channel | +| **message-update-own** | Can [update messages](/docs/messages/updates-deletes) where the original publisher's `clientId` matches the updater's `clientId` | +| **message-update-any** | Can [update any message](/docs/messages/updates-deletes) on the channel | +| **message-delete-own** | Can [delete messages](/docs/messages/updates-deletes) where the original publisher's `clientId` matches the deleter's `clientId` | +| **message-delete-any** | Can [delete any message](/docs/messages/updates-deletes) on the channel | | **history** | Can retrieve message and presence state history on channels | | **stats** | Can retrieve current and historical usage statistics for an app | | **push-subscribe** | Can subscribe devices for push notifications | diff --git a/src/pages/docs/messages/index.mdx b/src/pages/docs/messages/index.mdx index 5c41d59998..f858d2675a 100644 --- a/src/pages/docs/messages/index.mdx +++ b/src/pages/docs/messages/index.mdx @@ -34,8 +34,9 @@ The following are the properties of a message: | **extras** | A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads. Valid payloads include those related to [Push Notifications](/docs/push), [deltas](/docs/channels/options/deltas) and headers | | **encoding** | This is typically empty, as all messages received from Ably are automatically decoded client-side using this value. However, if the message encoding cannot be processed, this attribute contains the remaining transformations not applied to the data payload | | **action** | An [enum](/docs/api/realtime-sdk/types#message-action) telling you whether this is a normal ('create') message, an update to a previous message, an annotation summary, etc. | -| **serial** | The message's serial (a server-assigned identifier that will be the same in all future updates of this message, and can be used to add [annotations](/docs/messages/annotations)). Right now this will only be set if you enable annotations in [channel rules](/docs/channels#rules) | +| **serial** | The message's serial (a server-assigned identifier that will be the same in all future updates of this message, and can be used to add [annotations](/docs/messages/annotations) or to [update or delete](/docs/messages/updates-deletes) the message). This will only be set if you enable annotations, updates, and deletes in [channel rules](/docs/channels#rules) | | **annotations** | An object containing a summary of any [annotations](/docs/messages/annotations) that have been made to the message | +| **version** | An object containing [version metadata](/docs/messages/updates-deletes#version-structure) for messages that have been updated or deleted | ## Message conflation diff --git a/src/pages/docs/messages/updates-deletes.mdx b/src/pages/docs/messages/updates-deletes.mdx new file mode 100644 index 0000000000..911d6aab48 --- /dev/null +++ b/src/pages/docs/messages/updates-deletes.mdx @@ -0,0 +1,344 @@ +--- +title: Updating and deleting messages +meta_description: "Update and delete messages published to a channel, and retrieve message version history." +--- + + + +You can update and delete messages that have been published to a channel, for use cases such as: + +* **Message editing** - allow users to edit their messages in chat-like applications +* **Content moderation** - remove or edit inappropriate content after publication +* **Gradual message building** - a message can be published while still unfinished, and then repeatedly edited with more complete information, so that someone querying history once the message is complete will only see the final version + +Updating or deleting a message does not modify any messages that have been received by subscribing clients in-place: a given Message object is immutable. Rather, it publishes a new message to the channel, with an action of `message.update` or `message.delete`, with the same `serial` as the original message, that subscribing clients can see and act on. + +It also replaces the original message in message history, so history queries will see the latest version of the message (but in the place in history of the original). + +You can specify metadata (such as the reason for the update and which client is doing the update), which is published along with it. + +You can access the full version history of any given message. + +## Enable message updates and deletes + +Message updates and deletes can be enabled for a channel or channel namespace with the *Message annotations, updates, and deletes* channel rule. + + + +1. Go to the **Settings** tab of an app in your dashboard. +2. Under [channel rules](/docs/channels#rules), click **Add new rule**. +3. Enter the channel name or channel namespace on which to enable message updates and deletes. +4. Check **Message annotations, updates, and deletes** to enable the feature. +5. Click **Create channel rule** to save. + +## Update a message + +To update an existing message, use the `updateMessage()` method on a REST or realtime channel. The published update will have an `action` of `message.update`. + +The message is identified by its `serial`, which is populated by Ably. So to publish an update to a message, you have to have received it, as a subscriber or by querying history. Once you have that message, you can either take it, make your desired changes, and use that; or make a new Message object and just set its `serial` to that of the original message, as appropriate in your usecase. + + +```javascript +const realtime = new Ably.Realtime({ key: '{{API_KEY}}' }); +// This assumes there is an 'updates' namespace with a channel rule enabling updates and deletes +const channel = realtime.channels.get('updates:example'); + +// First subscribe to messages +await channel.subscribe((msg) => { + if (msg.data === 'original-data') { + // Publish an update + + // First way: mutate the received Message + msg.data = 'new-data-1'; + await channel.updateMessage(msg, { description: 'reason for first update' }); + + // Second way: publish a new Message using the serial + const msg2 = { + name: 'message-name', + serial: msg.serial, + }; + await channel.updateMessage(msg2, { description: 'reason for second update' }); + } +}); + +// Publish the original message +await channel.publish({ + name: 'message-name', + data: 'original-data', +}); +``` + +```nodejs +const realtime = new Ably.Realtime({ key: '{{API_KEY}}' }); +// This assumes there is an 'updates' namespace with a channel rule enabling updates and deletes +const channel = realtime.channels.get('updates:example'); + +// First subscribe to messages +await channel.subscribe((msg) => { + if (msg.data === 'original-data') { + // Publish an update + // First way: mutate the received Message + msg.data = 'new-data-1'; + await channel.updateMessage(msg, { description: 'reason for first update' }); + + // Second way: publish a new Message using the serial + const msg2 = { + name: 'message-name', + serial: msg.serial, + }; + await channel.updateMessage(msg2, { description: 'reason for second update' }); + } +}); + +// Publish the original message +await channel.publish({ + name: 'message-name', + data: 'original-data', +}); +``` + + +#### Patch semantics + +When updating a message, the fields you specify in the update will replace the corresponding fields in the existing message, and other fields will remain as they were. For example, if a message has `{ name: "greeting", data: "hello" }`, and you update it with `{ data: "hi" }`, the result will be `{ name: "greeting", data: "hi" }`. + +The fields that can be updated are: +- `data` +- `name` +- `extras` + +#### Capabilities + +To update messages, clients need one of the following [capabilities](/docs/auth/capabilities): + +| Capability | Description | +| ---------- | ----------- | +| **message-update-own** | Can update your own messages (more precisely, messages where the original publisher's `clientId` matches the updater's `clientId`, where both are [identified](/docs/auth/identified-clients)). | +| **message-update-any** | Can update any message on the channel. | + +#### Operation metadata + +When updating a message, you can optionally provide metadata about the update operation: + +| Property | Description | Type | +| -------- | ----------- | ---- | +| clientId | The client identifier of the user performing the update (automatically populated if the delete is done by an identified client). | String | +| description | A description of why the update was made. | String | +| metadata | Additional metadata about the update operation. | Object | + +This metadata will end up in the message's `version` property. See [Message version structure](/docs/messages/updates-deletes#version-structure) for what this looks like. + +## Delete a message + +To delete a message, use the `deleteMessage()` method on a REST or realtime channel. This is very much a 'soft' delete: it's just an update, but with an `action` of `message.delete` instead of `message.update`. It's up to your application to interpret it. + +The latest version of each message will be accessible from history, including if that latest version happens to be a delete. + +As with updating, the message is identified by its `serial`, which is populated by Ably. So to delete a message, you have to have received it, as a subscriber or by querying history. Once you have that message, you can either take it, make your desired changes, and use that; or make a new Message object and just set its `serial` to that of the original message, as appropriate in your usecase. + +Deleting a message marks it as deleted without removing it from the server. The full message history remains accessible through the [message versions](#versions) API. + + +```javascript +const realtime = new Ably.Realtime({ key: '{{API_KEY}}' }); +// This assumes there is an 'updates' namespace with a channel rule enabling updates and deletes +const channel = realtime.channels.get('updates:example'); + +// First subscribe to messages +await channel.subscribe((msg) => { + if (msg.data === 'original-data') { + // Publish a delete + // First way: just use the received Message + await channel.deleteMessage(msg, { description: 'reason for first delete' }); + + // Second way: publish a new Message using the serial + const msg2 = { serial: msg.serial }; + await channel.deleteMessage(msg2, { description: 'reason for second delete' }); + } +}); + +// Publish the original message +await channel.publish({ + name: 'message-name', + data: 'original-data', +}); +``` + +```nodejs +const realtime = new Ably.Realtime({ key: '{{API_KEY}}' }); +// This assumes there is an 'updates' namespace with a channel rule enabling updates and deletes +const channel = realtime.channels.get('updates:example'); + +// First subscribe to messages +await channel.subscribe((msg) => { + if (msg.data === 'original-data') { + // Publish a delete + // First way: just use the received Message + await channel.deleteMessage(msg, { description: 'reason for first delete' }); + + // Second way: publish a new Message using the serial + const msg2 = { serial: msg.serial }; + await channel.deleteMessage(msg2, { description: 'reason for second delete' }); + } +}); + +// Publish the original message +await channel.publish({ + name: 'message-name', + data: 'original-data', +}); +``` + + +#### Patch semantics + +Deleting has the same semantics as updating, so only fields you specify in the update will replace the corresponding fields in the existing message. + +That means that if you e.g. want the deleted message to have empty `data` (to prevent users looking at raw history results from the API from seeing what the data used to be), you must explicitly set to e.g. an empty object when publishing the delete. (And even then, all previous versions are accessible through the version history API). + +As with update, the fields that can be updated are `data`, `name`, and `extras`. + +#### Capabilities + +To delete messages, clients need one of the following [capabilities](/docs/auth/capabilities): + +| Capability | Description | +| ---------- | ----------- | +| **message-delete-own** | Can delete your own messages (more precisely, messages where the original publisher's `clientId` matches the deleter's `clientId`, where both are [identified](/docs/auth/identified-clients)). | +| **message-delete-any** | Can delete any message on the channel. | + +#### Operation metadata + +When deleting a message, you can optionally provide metadata: + +| Property | Description | Type | +| -------- | ----------- | ---- | +| clientId | The client identifier of the user performing the delete (automatically populated if the delete is done by an identified client). | String | +| description | A description of why the delete was made. | String | +| metadata | Additional metadata about the delete operation. | Object | + +This metadata will end up in the message's `version` property. See [Message version structure](/docs/messages/updates-deletes#version-structure) for what this looks like. + +## Get the latest version of a message + +To retrieve the most recent version of a specific message, use the `getMessage()` method on a REST channel. You can pass either the message's serial identifier as a string, or a message object with a `serial` property. + +This operation requires the history [capability](/docs/auth/capabilities). + + +```javascript +const rest = new Ably.Rest({ key: '{{API_KEY}}' }); +const channel = rest.channels.get('updates:example'); + +// could also use msg.serial, useful if you want to retrieve a +// message for a serial you have stored or passed around +const message = await channel.getMessage(msg); +``` + +```nodejs +const rest = new Ably.Rest({ key: '{{API_KEY}}' }); +const channel = rest.channels.get('updates:example'); + +// could also use msg.serial, useful if you want to retrieve a +// message for a serial you have stored or passed around +const message = await channel.getMessage(msg); +``` + + +## Get message versions + +To retrieve all historical versions of a message, use the `getMessageVersions()` method. This returns a paginated result containing all versions of the message, including the original and all subsequent updates or delete operations, ordered by version. + +This operation requires the history [capability](/docs/auth/capabilities). + + +```javascript +const rest = new Ably.Rest({ key: '{{API_KEY}}' }); +const channel = rest.channels.get('updates:example'); + +const page = await channel.getMessageVersions(msg); +console.log(`Found ${page.items.length} versions`); +``` + +```nodejs +const rest = new Ably.Rest({ key: '{{API_KEY}}' }); +const channel = rest.channels.get('updates:example'); + +const page = await channel.getMessageVersions(msg); +console.log(`Found ${page.items.length} versions`); +``` + + +## Message version structure + +A published update or delete contains version metadata in the `version` property. The following shows the structure of a message after it has been updated: + + +```json +{ + // The top-level serial is a permanent identifier of the message, and remains + // the same for all updates and deletes of that message + "serial": "01826232498871-001@abcdefghij:001", + + // The clientId of the user who published the original message + "clientId": "user123", + + // The timestamp of that original publish + "timestamp": 1718195879988, + + // Main payload fields + "name": "greeting", + "data": "hello world (edited)", + + // The action tells you if it's an original ("message.create"), update, + // delete, or annotation summary + "action": "message.update", + + "version": { + // The serial of the current version. For an original (with an action of + // "message.create"), this will be equal to the top-level serial. You can + // use this to compare different versions to see which one is more recent + "serial": "01826232512345-002@abcdefghij:002", + + // The clientId of the user who made the update + "clientId": "user123", + + // The timestamp of this latest version + "timestamp": 1718195912345, + + // Update metadata, supplied by the user who published the update + "description": "Fixed typo", + "metadata": { + "reason": "correction" + } + } +} +``` + + +#### Message actions + +The `action` property on a message indicates the type of operation: + +| Action | Description | +| ------ | ----------- | +| message.create | The original message | +| message.update | An update to an existing message | +| message.delete | A deletion of a message | +| meta | A message originating from ably rather than being published by a user, such as [inband occupancy events](/docs/channels/options#occupancy) | +| message.summary | TM5 | A message containing the [latest rolled-up summary of annotations](/docs/messages/annotations#annotation-summaries) | + + +## Version ordering + +Both the message `serial` and `version.serial` are lexicographically sortable strings, providing a deterministic ordering of messages and their versions. + +To determine which version of a message is newer, compare the `version.serial` values. + +In the case of updates or deletes made by different users at similar times, both will be published on the channel, but the one that is assigned the lexicographically-highest `version.serial` will 'win', in the sense that retrieving channel history will eventually always return that version of the message.