mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-04-28 05:14:10 +02:00
Merge branch 'main' into travis/ref-rel
This commit is contained in:
commit
b65ad68361
1
changelogs/client_server/newsfragments/1211.feature
Normal file
1
changelogs/client_server/newsfragments/1211.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add `m.replace` relations (event edits), as per [MSC2676](https://github.com/matrix-org/matrix-spec-proposals/pull/2676).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
1
changelogs/client_server/newsfragments/1216.feature.1
Normal file
1
changelogs/client_server/newsfragments/1216.feature.1
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add `m.read.private` receipts, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||||
1
changelogs/client_server/newsfragments/1216.feature.2
Normal file
1
changelogs/client_server/newsfragments/1216.feature.2
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Make `m.fully_read` optional on `/read_markers`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||||
1
changelogs/client_server/newsfragments/1216.feature.3
Normal file
1
changelogs/client_server/newsfragments/1216.feature.3
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Allow `m.fully_read` markers to be set from `/receipts`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Reinforce the relationship of refreshed access tokens to transaction IDs.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify enum values by separating possible values with commas.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
1
changelogs/internal/newsfragments/1230.clarification
Normal file
1
changelogs/internal/newsfragments/1230.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix the spacing of mapping types generated from the OpenAPI spec.
|
||||||
|
|
@ -213,12 +213,19 @@ See the [Server Notices](#server-notices) module for more information.
|
||||||
|
|
||||||
The client-server API typically uses `HTTP PUT` to submit requests with
|
The client-server API typically uses `HTTP PUT` to submit requests with
|
||||||
a client-generated transaction identifier. This means that these
|
a client-generated transaction identifier. This means that these
|
||||||
requests are idempotent. The scope of a transaction identifier is a
|
requests are idempotent. It **only** serves to identify new requests
|
||||||
particular access token. It **only** serves to identify new requests
|
|
||||||
from retransmits. After the request has finished, the `{txnId}` value
|
from retransmits. After the request has finished, the `{txnId}` value
|
||||||
should be changed (how is not specified; a monotonically increasing
|
should be changed (how is not specified; a monotonically increasing
|
||||||
integer is recommended).
|
integer is recommended).
|
||||||
|
|
||||||
|
The scope of a transaction ID is a "client session", where that session
|
||||||
|
is identified by a particular access token. When [refreshing](#refreshing-access-tokens)
|
||||||
|
an access token, the transaction ID's scope is retained. This means that
|
||||||
|
if a client with token `A` uses `TXN1` as their transaction ID, refreshes
|
||||||
|
the token to `B`, and uses `TXN1` again it'll be assumed to be a duplicate
|
||||||
|
request and ignored. If the client logs out and back in between the `A` and
|
||||||
|
`B` tokens, `TXN1` could be used once for each.
|
||||||
|
|
||||||
Some API endpoints may allow or require the use of `POST` requests
|
Some API endpoints may allow or require the use of `POST` requests
|
||||||
without a transaction ID. Where this is optional, the use of a `PUT`
|
without a transaction ID. Where this is optional, the use of a `PUT`
|
||||||
request is strongly recommended.
|
request is strongly recommended.
|
||||||
|
|
@ -1955,16 +1962,6 @@ rooms, or the relationship missing properties required by the schema below. Clie
|
||||||
handling such invalid relationships should show the events independently of each
|
handling such invalid relationships should show the events independently of each
|
||||||
other, optionally with an error message.
|
other, optionally with an error message.
|
||||||
|
|
||||||
{{% boxes/note %}}
|
|
||||||
While this specification describes an `m.relates_to` object containing a `rel_type`, there
|
|
||||||
is not currently any relationship type which uses this structure. Replies, described below,
|
|
||||||
form their relationship outside of the `rel_type` as a legacy type of relationship. Future
|
|
||||||
versions of the specification might change replies to better match the relationship structures.
|
|
||||||
|
|
||||||
Custom `rel_type`s can, and should, still use the schema described above for relevant
|
|
||||||
behaviour.
|
|
||||||
{{% /boxes/note %}}
|
|
||||||
|
|
||||||
`m.relates_to` is defined as follows:
|
`m.relates_to` is defined as follows:
|
||||||
|
|
||||||
{{% definition path="api/client-server/definitions/m.relates_to" %}}
|
{{% definition path="api/client-server/definitions/m.relates_to" %}}
|
||||||
|
|
@ -1974,6 +1971,7 @@ behaviour.
|
||||||
This specification describes the following relationship types:
|
This specification describes the following relationship types:
|
||||||
|
|
||||||
* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
|
* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
|
||||||
|
* [Event replacements](#event-replacements).
|
||||||
* [References](#reference-relations)
|
* [References](#reference-relations)
|
||||||
|
|
||||||
#### Aggregations
|
#### Aggregations
|
||||||
|
|
@ -2644,4 +2642,5 @@ systems.
|
||||||
{{< cs-module name="server_notices" >}}
|
{{< cs-module name="server_notices" >}}
|
||||||
{{< cs-module name="moderation_policies" >}}
|
{{< cs-module name="moderation_policies" >}}
|
||||||
{{< cs-module name="spaces" >}}
|
{{< cs-module name="spaces" >}}
|
||||||
|
{{< cs-module name="event_replacements" >}}
|
||||||
{{< cs-module name="reference_relations" >}}
|
{{< cs-module name="reference_relations" >}}
|
||||||
|
|
@ -17,10 +17,10 @@ data with the same `type`.
|
||||||
#### Events
|
#### Events
|
||||||
|
|
||||||
The client receives the account data as events in the `account_data`
|
The client receives the account data as events in the `account_data`
|
||||||
sections of a `/sync`.
|
sections of a [`/sync`](#get_matrixclientv3sync) response.
|
||||||
|
|
||||||
These events can also be received in a `/events` response or in the
|
These events can also be received in a `/events` response or in the
|
||||||
`account_data` section of a room in `/sync`. `m.tag` events appearing in
|
`account_data` section of a room in a `/sync` response. `m.tag` events appearing in
|
||||||
`/events` will have a `room_id` with the room the tags are for.
|
`/events` will have a `room_id` with the room the tags are for.
|
||||||
|
|
||||||
#### Client Behaviour
|
#### Client Behaviour
|
||||||
|
|
|
||||||
330
content/client-server-api/modules/event_replacements.md
Normal file
330
content/client-server-api/modules/event_replacements.md
Normal file
|
|
@ -0,0 +1,330 @@
|
||||||
|
---
|
||||||
|
type: module
|
||||||
|
---
|
||||||
|
|
||||||
|
### Event replacements
|
||||||
|
|
||||||
|
{{% added-in v="1.4" %}}
|
||||||
|
|
||||||
|
Event replacements, or "message edit events", are events that use an [event
|
||||||
|
relationship](#forming-relationships-between-events)
|
||||||
|
with a `rel_type` of `m.replace`, which indicates that the original event is
|
||||||
|
intended to be replaced.
|
||||||
|
|
||||||
|
An example of a message edit event might look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "* Hello! My name is bar",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"m.new_content": {
|
||||||
|
"body": "Hello! My name is bar",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
"rel_type": "m.replace",
|
||||||
|
"event_id": "$some_event_id"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ... other fields required by events
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `content` of the replacement must contain a `m.new_content` property which
|
||||||
|
defines the replacement `content`. The normal `content` properties (`body`,
|
||||||
|
`msgtype` etc.) provide a fallback for clients which do not understand
|
||||||
|
replacement events.
|
||||||
|
|
||||||
|
`m.new_content` can include any properties that would normally be found in
|
||||||
|
an event's content property, such as `formatted_body` (see [`m.room.message`
|
||||||
|
`msgtypes`](#mroommessage-msgtypes)).
|
||||||
|
|
||||||
|
#### Validity of replacement events
|
||||||
|
|
||||||
|
There are a number of requirements on replacement events, which must be satisfied for the replacement to be considered valid:
|
||||||
|
|
||||||
|
* As with all event relationships, the original event and replacement event
|
||||||
|
must have the same `room_id` (i.e. you cannot send an event in
|
||||||
|
one room and then an edited version in a different room).
|
||||||
|
|
||||||
|
* The original event and replacement event must have the same `sender`
|
||||||
|
(i.e. you cannot edit someone else's messages).
|
||||||
|
|
||||||
|
* The replacement and original events must have the same `type` (i.e. you
|
||||||
|
cannot change the original event's type).
|
||||||
|
|
||||||
|
* The replacement and original events must not have a `state_key` property
|
||||||
|
(i.e. you cannot edit state events at all).
|
||||||
|
|
||||||
|
* The original event must not, itself, have a `rel_type` of `m.replace`
|
||||||
|
(i.e. you cannot edit an edit — though you can send multiple edits for a
|
||||||
|
single original event).
|
||||||
|
|
||||||
|
* The replacement event (once decrypted, if appropriate) must have an
|
||||||
|
`m.new_content` property.
|
||||||
|
|
||||||
|
If any of these criteria are not satisfied, implementations should ignore the
|
||||||
|
replacement event (the content of the original should not be replaced, and the
|
||||||
|
edit should not be included in the server-side aggregation).
|
||||||
|
|
||||||
|
Note that the [`msgtype`](#mroommessage-msgtypes) property of replacement
|
||||||
|
`m.room.message` events does *not* need to be the same as in the original event. For
|
||||||
|
example, it is legitimate to replace an `m.text` event with an `m.emote`.
|
||||||
|
|
||||||
|
#### Editing encrypted events
|
||||||
|
|
||||||
|
If the original event was [encrypted](#end-to-end-encryption), the replacement
|
||||||
|
should be too. In that case, `m.new_content` is placed in the content of the
|
||||||
|
encrypted payload. As with all event relationships, the `m.relates_to` property
|
||||||
|
must be sent in the unencrypted (cleartext) part of the event.
|
||||||
|
|
||||||
|
For example, a replacement for an encrypted event might look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "m.room.encrypted",
|
||||||
|
"content": {
|
||||||
|
"m.relates_to": {
|
||||||
|
"rel_type": "m.replace",
|
||||||
|
"event_id": "$some_event_id"
|
||||||
|
},
|
||||||
|
"algorithm": "m.megolm.v1.aes-sha2",
|
||||||
|
"sender_key": "<sender_curve25519_key>",
|
||||||
|
"device_id": "<sender_device_id>",
|
||||||
|
"session_id": "<outbound_group_session_id>",
|
||||||
|
"ciphertext": "<encrypted_payload_base_64>"
|
||||||
|
}
|
||||||
|
// irrelevant fields not shown
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... and, once decrypted, the payload might look like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "m.room.<event_type>",
|
||||||
|
"room_id": "!some_room_id",
|
||||||
|
"content": {
|
||||||
|
"body": "* Hello! My name is bar",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"m.new_content": {
|
||||||
|
"body": "Hello! My name is bar",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that:
|
||||||
|
|
||||||
|
* There is no `m.relates_to` property in the encrypted payload. If there was, it would be ignored.
|
||||||
|
* There is no `m.new_content` property in the cleartext content of the `m.room.encrypted` event. As above, if there was then it would be ignored.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
The payload of an encrypted replacement event must be encrypted as normal, including
|
||||||
|
ratcheting any [Megolm](#mmegolmv1aes-sha2) session as normal. The original Megolm
|
||||||
|
ratchet entry should **not** be re-used.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
|
||||||
|
#### Applying `m.new_content`
|
||||||
|
|
||||||
|
When applying a replacement, the `content` of the original event is treated as
|
||||||
|
being overwritten entirely by `m.new_content`, with the exception of `m.relates_to`,
|
||||||
|
which is left *unchanged*. Any `m.relates_to` property within `m.new_content`
|
||||||
|
is ignored.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
Note that server implementations must not *actually* overwrite
|
||||||
|
the original event's `content`: instead the server presents it as being overwritten
|
||||||
|
when it is served over the client-server API. See [Server-side replacement of content](#server-side-replacement-of-content)
|
||||||
|
below.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
|
For example, given a pair of events:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_id": "$original_event",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "I really like cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"formatted_body": "I really like cake",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_id": "$edit_event",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "* I really like *chocolate* cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"m.new_content": {
|
||||||
|
"body": "I really like *chocolate* cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"com.example.extension_property": "chocolate"
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
"rel_type": "m.replace",
|
||||||
|
"event_id": "$original_event_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
... then the end result is an event as shown below:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_id": "$original_event",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "I really like *chocolate* cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"com.example.extension_property": "chocolate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `formatted_body` is now absent, because it was absent in the
|
||||||
|
replacement event.
|
||||||
|
|
||||||
|
#### Server behaviour
|
||||||
|
|
||||||
|
##### Server-side aggregation of `m.replace` relationships
|
||||||
|
|
||||||
|
Note that there can be multiple events with an `m.replace` relationship to a
|
||||||
|
given event (for example, if an event is edited multiple times). These should
|
||||||
|
be [aggregated](#aggregations) by the homeserver.
|
||||||
|
|
||||||
|
The aggregation format of `m.replace` relationships gives the `event_id`,
|
||||||
|
`origin_server_ts`, and `sender` of the **most recent** replacement event. The
|
||||||
|
most recent event is determined by comparing `origin_server_ts`; if two or more
|
||||||
|
replacement events have identical `origin_server_ts`, the event with the
|
||||||
|
lexicographically largest `event_id` is treated as more recent.
|
||||||
|
|
||||||
|
This aggregation is bundled under the `unsigned` property as `m.relations` for any
|
||||||
|
event that is the target of an `m.replace` relationship. For example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event_id": "$original_event_id",
|
||||||
|
// irrelevant fields not shown
|
||||||
|
"unsigned": {
|
||||||
|
"m.relations": {
|
||||||
|
"m.replace": {
|
||||||
|
"event_id": "$latest_edit_event_id",
|
||||||
|
"origin_server_ts": 1649772304313,
|
||||||
|
"sender": "@editing_user:localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the original event is
|
||||||
|
[redacted](#redactions), any
|
||||||
|
`m.replace` relationship should **not** be bundled with it (whether or not any
|
||||||
|
subsequent replacements are themselves redacted). Note that this behaviour is
|
||||||
|
specific to the `m.replace` relationship. See also [redactions of edited
|
||||||
|
events](#redactions-of-edited-events) below.
|
||||||
|
|
||||||
|
##### Server-side replacement of content
|
||||||
|
|
||||||
|
Whenever an `m.replace` is to be bundled with an event as above, the server
|
||||||
|
should also modify the content of the original event according to the
|
||||||
|
`m.new_content` of the most recent replacement event (determined as above).
|
||||||
|
|
||||||
|
An exception applies to [`GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid),
|
||||||
|
which should return the unmodified event (though the relationship should still
|
||||||
|
be bundled, as described above).
|
||||||
|
|
||||||
|
#### Client behaviour
|
||||||
|
|
||||||
|
Clients can often ignore `m.replace` events, because any events returned
|
||||||
|
by the server to the client will be updated by the server to account for
|
||||||
|
subsequent edits.
|
||||||
|
|
||||||
|
However, clients should apply the replacement themselves when the server is
|
||||||
|
unable to do so. This happens in the following situations:
|
||||||
|
|
||||||
|
* The client has already received and stored the original event before the
|
||||||
|
message edit event arrives.
|
||||||
|
|
||||||
|
* The original event (and hence its replacement) are encrypted.
|
||||||
|
|
||||||
|
Client authors are reminded to take note of the requirements for [Validity of
|
||||||
|
message edit events](#validity-of-message-edit-events), and to ignore any
|
||||||
|
invalid edit events that are received.
|
||||||
|
|
||||||
|
##### Permalinks
|
||||||
|
|
||||||
|
When creating [links](/appendices/#uris) to events (also known as permalinks),
|
||||||
|
clients build links which reference the event that the creator of the permalink
|
||||||
|
is viewing at that point (which might be a message edit event).
|
||||||
|
|
||||||
|
The client viewing the permalink should resolve this reference to the original
|
||||||
|
event, and then display the most recent version of that event.
|
||||||
|
|
||||||
|
#### Redactions of edited events
|
||||||
|
|
||||||
|
When an event using a `rel_type` of `m.replace` is [redacted](#redactions), it
|
||||||
|
removes that edit revision. This has little effect if there were subsequent
|
||||||
|
edits. However, if it was the most recent edit, the event is in effect
|
||||||
|
reverted to its content before the redacted edit.
|
||||||
|
|
||||||
|
Redacting the *original* message in effect removes the message, including all
|
||||||
|
subsequent edits, from the visible timeline. In this situation, homeservers
|
||||||
|
will return an empty `content` for the original event as with any other
|
||||||
|
redacted event, and as
|
||||||
|
[above](#server-side-aggregation-of-mreplace-relationships) the replacement
|
||||||
|
events will not be bundled with the original event. Note that the subsequent edits are
|
||||||
|
not actually redacted themselves: they simply serve no purpose within the visible timeline.
|
||||||
|
|
||||||
|
#### Edits of replies
|
||||||
|
|
||||||
|
Some particular constraints apply to events which replace a
|
||||||
|
[reply](#rich-replies). In particular:
|
||||||
|
|
||||||
|
* In contrast to the original reply, there should be no `m.in_reply_to`
|
||||||
|
property in the the `m.relates_to` object, since it would be redundant (see
|
||||||
|
[Applying `m.new_content`](#applying-mnew_content) above, which notes that
|
||||||
|
the original event's `m.relates_to` is preserved), as well as being contrary
|
||||||
|
to the spirit of the event relationships mechanism which expects only one
|
||||||
|
"parent" per event.
|
||||||
|
|
||||||
|
* `m.new_content` should **not** contain any [reply
|
||||||
|
fallback](#fallbacks-for-rich-replies),
|
||||||
|
since it is assumed that any client which can handle edits can also display
|
||||||
|
replies natively. However, the `content` of the replacement event should provide
|
||||||
|
fallback content for clients which support neither rich replies nor edits.
|
||||||
|
|
||||||
|
An example of an edit to a reply is as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "m.room.message",
|
||||||
|
// irrelevant fields not shown
|
||||||
|
"content": {
|
||||||
|
"body": "> <@alice:example.org> question\n\n* reply",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a> <a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />question</blockquote></mx-reply>* reply",
|
||||||
|
"m.new_content": {
|
||||||
|
"body": "reply",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "reply"
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
"rel_type": "m.replace",
|
||||||
|
"event_id": "$original_reply_event"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -107,7 +107,19 @@ determined by the push rules which apply to an event.
|
||||||
|
|
||||||
When the user updates their read receipt (either by using the API or by
|
When the user updates their read receipt (either by using the API or by
|
||||||
sending an event), notifications prior to and including that event MUST
|
sending an event), notifications prior to and including that event MUST
|
||||||
be marked as read.
|
be marked as read. Note that users can send both an `m.read` and
|
||||||
|
`m.read.private` receipt, both of which are capable of clearing notifications.
|
||||||
|
|
||||||
|
If the user has both `m.read` and `m.read.private` set in the room then
|
||||||
|
the receipt which is more recent/ahead must be used to determine where
|
||||||
|
the user has read up to. For example, given an oldest-first set of events A,
|
||||||
|
B, C, and D the `m.read` receipt could be at event C and `m.read.private`
|
||||||
|
at event A - the user is considered to have read up to event C. If the
|
||||||
|
`m.read.private` receipt is then updated to point to B or C, the user's
|
||||||
|
notification state doesn't change (the `m.read` receipt is still more
|
||||||
|
ahead), however if the `m.read.private` receipt were to be updated to
|
||||||
|
event D then the user has read up to D (the `m.read` receipt is now
|
||||||
|
behind the `m.read.private` receipt).
|
||||||
|
|
||||||
##### Push Rules
|
##### Push Rules
|
||||||
|
|
||||||
|
|
@ -768,7 +780,7 @@ per-device using the APIs below.
|
||||||
##### Push Rules: Events
|
##### Push Rules: Events
|
||||||
|
|
||||||
When a user changes their push rules a `m.push_rules` event is sent to
|
When a user changes their push rules a `m.push_rules` event is sent to
|
||||||
all clients in the `account_data` section of their next `/sync` request.
|
all clients in the `account_data` section of their next [`/sync`](#get_matrixclientv3sync) request.
|
||||||
The content of the event is the current push rules for the user.
|
The content of the event is the current push rules for the user.
|
||||||
|
|
||||||
{{% event event="m.push_rules" %}}
|
{{% event event="m.push_rules" %}}
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,16 @@ The client cannot update fully read markers by directly modifying the
|
||||||
`m.fully_read` account data event. Instead, the client must make use of
|
`m.fully_read` account data event. Instead, the client must make use of
|
||||||
the read markers API to change the values.
|
the read markers API to change the values.
|
||||||
|
|
||||||
|
{{< changed-in v="1.4" >}} `m.read.private` receipts can now be sent from
|
||||||
|
`/read_markers`.
|
||||||
|
|
||||||
The read markers API can additionally update the user's read receipt
|
The read markers API can additionally update the user's read receipt
|
||||||
(`m.read`) location in the same operation as setting the fully read
|
(`m.read` or `m.read.private`) location in the same operation as setting
|
||||||
marker location. This is because read receipts and read markers are
|
the fully read marker location. This is because read receipts and read
|
||||||
commonly updated at the same time, and therefore the client might wish
|
markers are commonly updated at the same time, and therefore the client
|
||||||
to save an extra HTTP call. Providing an `m.read` location performs the
|
might wish to save an extra HTTP call. Providing `m.read` and/or
|
||||||
same task as a request to `/receipt/m.read/$event:example.org`.
|
`m.read.private` performs the same task as a request to
|
||||||
|
[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid).
|
||||||
|
|
||||||
{{% http-api spec="client-server" api="read_markers" %}}
|
{{% http-api spec="client-server" api="read_markers" %}}
|
||||||
|
|
||||||
|
|
@ -44,8 +48,9 @@ same task as a request to `/receipt/m.read/$event:example.org`.
|
||||||
|
|
||||||
The server MUST prevent clients from setting `m.fully_read` directly in
|
The server MUST prevent clients from setting `m.fully_read` directly in
|
||||||
room account data. The server must additionally ensure that it treats
|
room account data. The server must additionally ensure that it treats
|
||||||
the presence of `m.read` in the `/read_markers` request the same as how
|
the presence of `m.read` and `m.read.private` in the `/read_markers`
|
||||||
it would for a request to `/receipt/m.read/$event:example.org`.
|
request the same as how it would for a request to
|
||||||
|
[`/receipt/{receiptType}/{eventId}`](#post_matrixclientv3roomsroomidreceiptreceipttypeeventid).
|
||||||
|
|
||||||
Upon updating the `m.fully_read` event due to a request to
|
Upon updating the `m.fully_read` event due to a request to
|
||||||
`/read_markers`, the server MUST send the updated account data event
|
`/read_markers`, the server MUST send the updated account data event
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@ type: module
|
||||||
|
|
||||||
### Receipts
|
### Receipts
|
||||||
|
|
||||||
|
{{< changed-in v="1.4" >}} Added private read receipts.
|
||||||
|
|
||||||
This module adds in support for receipts. These receipts are a form of
|
This module adds in support for receipts. These receipts are a form of
|
||||||
acknowledgement of an event. This module defines a single
|
acknowledgement of an event. This module defines the `m.read` receipt
|
||||||
acknowledgement: `m.read` which indicates that the user has read up to a
|
for indicating that the user has read up to a given event, and `m.read.private`
|
||||||
given event.
|
to achieve the same purpose without any other user being aware. Primarily,
|
||||||
|
`m.read.private` is intended to clear [notifications](#receiving-notifications)
|
||||||
|
without advertising read-up-to status to others.
|
||||||
|
|
||||||
Sending a receipt for each event can result in sending large amounts of
|
Sending a receipt for each event can result in sending large amounts of
|
||||||
traffic to a homeserver. To prevent this from becoming a problem,
|
traffic to a homeserver. To prevent this from becoming a problem,
|
||||||
|
|
@ -59,12 +63,36 @@ following HTTP APIs.
|
||||||
|
|
||||||
{{% http-api spec="client-server" api="receipts" %}}
|
{{% http-api spec="client-server" api="receipts" %}}
|
||||||
|
|
||||||
|
##### Private read receipts
|
||||||
|
|
||||||
|
{{% added-in v="1.4" %}}
|
||||||
|
|
||||||
|
Some users would like to mark a room as read, clearing their [notification counts](#receiving-notifications),
|
||||||
|
but not give away the fact that they've read a particular message yet. To
|
||||||
|
achieve this, clients can send `m.read.private` receipts instead of `m.read`
|
||||||
|
to do exactly that: clear notifications and not broadcast the receipt to
|
||||||
|
other users.
|
||||||
|
|
||||||
|
Servers MUST NOT send the `m.read.private` receipt to any other user than the
|
||||||
|
one which originally sent it.
|
||||||
|
|
||||||
|
Between `m.read` and `m.read.private`, the receipt which is more "ahead" or
|
||||||
|
"recent" is used when determining the highest read-up-to mark. See the
|
||||||
|
[notifications](#receiving-notifications) section for more information on
|
||||||
|
how this affects notification counts.
|
||||||
|
|
||||||
|
If a client sends an `m.read` receipt which is "behind" the `m.read.private`
|
||||||
|
receipt, other users will see that change happen but the sending user will
|
||||||
|
not have their notification counts rewound to that point in time. While
|
||||||
|
uncommon, it is considered valid to have an `m.read` (public) receipt lag
|
||||||
|
several messages behind the `m.read.private` receipt, for example.
|
||||||
|
|
||||||
#### Server behaviour
|
#### Server behaviour
|
||||||
|
|
||||||
For efficiency, receipts SHOULD be batched into one event per room
|
For efficiency, receipts SHOULD be batched into one event per room
|
||||||
before delivering them to clients.
|
before delivering them to clients.
|
||||||
|
|
||||||
Receipts are sent across federation as EDUs with type `m.receipt`. The
|
Some receipts are sent across federation as EDUs with type `m.receipt`. The
|
||||||
format of the EDUs are:
|
format of the EDUs are:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -80,7 +108,8 @@ format of the EDUs are:
|
||||||
```
|
```
|
||||||
|
|
||||||
These are always sent as deltas to previously sent receipts. Currently
|
These are always sent as deltas to previously sent receipts. Currently
|
||||||
only a single `<receipt_type>` should be used: `m.read`.
|
only a single `<receipt_type>` should be used: `m.read`. `m.read.private`
|
||||||
|
MUST NOT appear in this federated `m.receipt` EDU.
|
||||||
|
|
||||||
#### Security considerations
|
#### Security considerations
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ clients can access, depending on what keys are given to them.
|
||||||
##### Key storage
|
##### Key storage
|
||||||
|
|
||||||
Each key has an ID, and the description of the key is stored in the
|
Each key has an ID, and the description of the key is stored in the
|
||||||
user's account\_data using the event type
|
user's account data using the event type
|
||||||
`m.secret_storage.key.[key ID]`. The contents of the account data for
|
`m.secret_storage.key.[key ID]`. The contents of the account data for
|
||||||
the key will include an `algorithm` property, which indicates the
|
the key will include an `algorithm` property, which indicates the
|
||||||
encryption algorithm used, as well as a `name` property, which is a
|
encryption algorithm used, as well as a `name` property, which is a
|
||||||
|
|
@ -51,7 +51,7 @@ Other properties depend on the encryption algorithm, and are described
|
||||||
below.
|
below.
|
||||||
|
|
||||||
A key can be marked as the "default" key by setting the user's
|
A key can be marked as the "default" key by setting the user's
|
||||||
account\_data with event type `m.secret_storage.default_key` to an
|
account data with event type `m.secret_storage.default_key` to an
|
||||||
object that has the ID of the key as its `key` property. The default key
|
object that has the ID of the key as its `key` property. The default key
|
||||||
will be used to encrypt all secrets that the user would expect to be
|
will be used to encrypt all secrets that the user would expect to be
|
||||||
available on all their clients. Unless the user specifies otherwise,
|
available on all their clients. Unless the user specifies otherwise,
|
||||||
|
|
@ -71,8 +71,8 @@ default key.
|
||||||
|
|
||||||
##### Secret storage
|
##### Secret storage
|
||||||
|
|
||||||
Encrypted data is stored in the user's account\_data using the event
|
Encrypted data is stored in the user's account data using the event
|
||||||
type defined by the feature that uses the data. The account\_data will
|
type defined by the feature that uses the data. The account data will
|
||||||
have an `encrypted` property that is a map from key ID to an object. The
|
have an `encrypted` property that is a map from key ID to an object. The
|
||||||
algorithm from the `m.secret_storage.key.[key ID]` data for the given
|
algorithm from the `m.secret_storage.key.[key ID]` data for the given
|
||||||
key defines how the other properties are interpreted, though it's
|
key defines how the other properties are interpreted, though it's
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,12 @@ securityDefinitions:
|
||||||
paths:
|
paths:
|
||||||
"/user/{userId}/account_data/{type}":
|
"/user/{userId}/account_data/{type}":
|
||||||
put:
|
put:
|
||||||
summary: Set some account_data for the user.
|
summary: Set some account data for the user.
|
||||||
description: |-
|
description: |-
|
||||||
Set some account_data for the client. This config is only visible to the user
|
Set some account data for the client. This config is only visible to the user
|
||||||
that set the account_data. The config will be synced to clients in the
|
that set the account data. The config will be available to clients through the
|
||||||
top-level `account_data`.
|
top-level `account_data` field in the homeserver response to
|
||||||
|
[/sync](#get_matrixclientv3sync).
|
||||||
operationId: setAccountData
|
operationId: setAccountData
|
||||||
security:
|
security:
|
||||||
- accessToken: []
|
- accessToken: []
|
||||||
|
|
@ -43,7 +44,7 @@ paths:
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the user to set account_data for. The access token must be
|
The ID of the user to set account data for. The access token must be
|
||||||
authorized to make requests for this user ID.
|
authorized to make requests for this user ID.
|
||||||
x-example: "@alice:example.com"
|
x-example: "@alice:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
|
|
@ -51,14 +52,14 @@ paths:
|
||||||
name: type
|
name: type
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The event type of the account_data to set. Custom types should be
|
The event type of the account data to set. Custom types should be
|
||||||
namespaced to avoid clashes.
|
namespaced to avoid clashes.
|
||||||
x-example: "org.example.custom.config"
|
x-example: "org.example.custom.config"
|
||||||
- in: body
|
- in: body
|
||||||
name: content
|
name: content
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The content of the account_data
|
The content of the account data.
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
example: {
|
example: {
|
||||||
|
|
@ -66,7 +67,7 @@ paths:
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description:
|
description:
|
||||||
The account_data was successfully added.
|
The account data was successfully added.
|
||||||
examples:
|
examples:
|
||||||
application/json: {}
|
application/json: {}
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -107,10 +108,10 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
get:
|
get:
|
||||||
summary: Get some account_data for the user.
|
summary: Get some account data for the user.
|
||||||
description: |-
|
description: |-
|
||||||
Get some account_data for the client. This config is only visible to the user
|
Get some account data for the client. This config is only visible to the user
|
||||||
that set the account_data.
|
that set the account data.
|
||||||
operationId: getAccountData
|
operationId: getAccountData
|
||||||
security:
|
security:
|
||||||
- accessToken: []
|
- accessToken: []
|
||||||
|
|
@ -120,7 +121,7 @@ paths:
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the user to get account_data for. The access token must be
|
The ID of the user to get account data for. The access token must be
|
||||||
authorized to make requests for this user ID.
|
authorized to make requests for this user ID.
|
||||||
x-example: "@alice:example.com"
|
x-example: "@alice:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
|
|
@ -128,7 +129,7 @@ paths:
|
||||||
name: type
|
name: type
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The event type of the account_data to get. Custom types should be
|
The event type of the account data to get. Custom types should be
|
||||||
namespaced to avoid clashes.
|
namespaced to avoid clashes.
|
||||||
x-example: "org.example.custom.config"
|
x-example: "org.example.custom.config"
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -157,7 +158,7 @@ paths:
|
||||||
examples:
|
examples:
|
||||||
application/json: {
|
application/json: {
|
||||||
"errcode": "M_NOT_FOUND",
|
"errcode": "M_NOT_FOUND",
|
||||||
"error": "Room account data not found."
|
"error": "Account data not found."
|
||||||
}
|
}
|
||||||
schema:
|
schema:
|
||||||
$ref: "../client-server/definitions/errors/error.yaml"
|
$ref: "../client-server/definitions/errors/error.yaml"
|
||||||
|
|
@ -165,11 +166,11 @@ paths:
|
||||||
- User data
|
- User data
|
||||||
"/user/{userId}/rooms/{roomId}/account_data/{type}":
|
"/user/{userId}/rooms/{roomId}/account_data/{type}":
|
||||||
put:
|
put:
|
||||||
summary: Set some account_data for the user that is specific to a room.
|
summary: Set some account data for the user that is specific to a room.
|
||||||
description: |-
|
description: |-
|
||||||
Set some account_data for the client on a given room. This config is only
|
Set some account data for the client on a given room. This config is only
|
||||||
visible to the user that set the account_data. The config will be synced to
|
visible to the user that set the account data. The config will be delivered to
|
||||||
clients in the per-room `account_data`.
|
clients in the per-room entries via [/sync](#get_matrixclientv3sync).
|
||||||
operationId: setAccountDataPerRoom
|
operationId: setAccountDataPerRoom
|
||||||
security:
|
security:
|
||||||
- accessToken: []
|
- accessToken: []
|
||||||
|
|
@ -179,7 +180,7 @@ paths:
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the user to set account_data for. The access token must be
|
The ID of the user to set account data for. The access token must be
|
||||||
authorized to make requests for this user ID.
|
authorized to make requests for this user ID.
|
||||||
x-example: "@alice:example.com"
|
x-example: "@alice:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
|
|
@ -187,21 +188,21 @@ paths:
|
||||||
name: roomId
|
name: roomId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the room to set account_data on.
|
The ID of the room to set account data on.
|
||||||
x-example: "!726s6s6q:example.com"
|
x-example: "!726s6s6q:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: type
|
name: type
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The event type of the account_data to set. Custom types should be
|
The event type of the account data to set. Custom types should be
|
||||||
namespaced to avoid clashes.
|
namespaced to avoid clashes.
|
||||||
x-example: "org.example.custom.room.config"
|
x-example: "org.example.custom.room.config"
|
||||||
- in: body
|
- in: body
|
||||||
name: content
|
name: content
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The content of the account_data
|
The content of the account data.
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
example: {
|
example: {
|
||||||
|
|
@ -209,7 +210,7 @@ paths:
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description:
|
description:
|
||||||
The account_data was successfully added.
|
The account data was successfully added.
|
||||||
examples:
|
examples:
|
||||||
application/json: {}
|
application/json: {}
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -251,10 +252,10 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- User data
|
- User data
|
||||||
get:
|
get:
|
||||||
summary: Get some account_data for the user that is specific to a room.
|
summary: Get some account data for the user that is specific to a room.
|
||||||
description: |-
|
description: |-
|
||||||
Get some account_data for the client on a given room. This config is only
|
Get some account data for the client on a given room. This config is only
|
||||||
visible to the user that set the account_data.
|
visible to the user that set the account data.
|
||||||
operationId: getAccountDataPerRoom
|
operationId: getAccountDataPerRoom
|
||||||
security:
|
security:
|
||||||
- accessToken: []
|
- accessToken: []
|
||||||
|
|
@ -264,7 +265,7 @@ paths:
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the user to set account_data for. The access token must be
|
The ID of the user to get account data for. The access token must be
|
||||||
authorized to make requests for this user ID.
|
authorized to make requests for this user ID.
|
||||||
x-example: "@alice:example.com"
|
x-example: "@alice:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
|
|
@ -272,14 +273,14 @@ paths:
|
||||||
name: roomId
|
name: roomId
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The ID of the room to get account_data for.
|
The ID of the room to get account data for.
|
||||||
x-example: "!726s6s6q:example.com"
|
x-example: "!726s6s6q:example.com"
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: type
|
name: type
|
||||||
required: true
|
required: true
|
||||||
description: |-
|
description: |-
|
||||||
The event type of the account_data to get. Custom types should be
|
The event type of the account data to get. Custom types should be
|
||||||
namespaced to avoid clashes.
|
namespaced to avoid clashes.
|
||||||
x-example: "org.example.custom.room.config"
|
x-example: "org.example.custom.room.config"
|
||||||
responses:
|
responses:
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ properties:
|
||||||
}
|
}
|
||||||
transaction_id:
|
transaction_id:
|
||||||
description: |
|
description: |
|
||||||
The client-supplied transaction ID, for example, provided via
|
The client-supplied [transaction ID](/client-server-api/#transaction-identifiers), for example, provided via
|
||||||
`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`,
|
`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`,
|
||||||
if the client being given the event is the same one which sent it.
|
if the client being given the event is the same one which sent it.
|
||||||
type: string
|
type: string
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ paths:
|
||||||
post:
|
post:
|
||||||
summary: Start the requesting user participating in a particular room.
|
summary: Start the requesting user participating in a particular room.
|
||||||
description: |-
|
description: |-
|
||||||
*Note that this API takes either a room ID or alias, unlike* `/room/{roomId}/join`.
|
*Note that this API takes either a room ID or alias, unlike* `/rooms/{roomId}/join`.
|
||||||
|
|
||||||
This API starts a user participating in a particular room, if that user
|
This API starts a user participating in a particular room, if that user
|
||||||
is allowed to participate in that room. After this call, the client is
|
is allowed to participate in that room. After this call, the client is
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ paths:
|
||||||
x-example: "@alice:example.com"
|
x-example: "@alice:example.com"
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: The avatar URL for this user.
|
description: The profile information for this user.
|
||||||
examples:
|
examples:
|
||||||
application/json: {
|
application/json: {
|
||||||
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
|
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Copyright 2018 New Vector Ltd
|
# Copyright 2018 New Vector Ltd
|
||||||
|
# Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
|
@ -56,6 +57,9 @@ paths:
|
||||||
The event ID the read marker should be located at. The
|
The event ID the read marker should be located at. The
|
||||||
event MUST belong to the room.
|
event MUST belong to the room.
|
||||||
example: "$somewhere:example.org"
|
example: "$somewhere:example.org"
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
1.4: |
|
||||||
|
This property is no longer required.
|
||||||
"m.read":
|
"m.read":
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
|
|
@ -63,11 +67,18 @@ paths:
|
||||||
equivalent to calling `/receipt/m.read/$elsewhere:example.org`
|
equivalent to calling `/receipt/m.read/$elsewhere:example.org`
|
||||||
and is provided here to save that extra call.
|
and is provided here to save that extra call.
|
||||||
example: "$elsewhere:example.org"
|
example: "$elsewhere:example.org"
|
||||||
required: ['m.fully_read']
|
"m.read.private":
|
||||||
|
x-addedInMatrixVersion: "1.4"
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The event ID to set the *private* read receipt location at. This
|
||||||
|
equivalent to calling `/receipt/m.read.private/$elsewhere:example.org`
|
||||||
|
and is provided here to save that extra call.
|
||||||
|
example: "$elsewhere:example.org"
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: |-
|
description: |-
|
||||||
The read marker, and read receipt if provided, have been updated.
|
The read marker, and read receipt(s) if provided, have been updated.
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties: {}
|
properties: {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Copyright 2016 OpenMarket Ltd
|
# Copyright 2016 OpenMarket Ltd
|
||||||
|
# Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
|
@ -46,10 +47,19 @@ paths:
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: receiptType
|
name: receiptType
|
||||||
description: The type of receipt to send.
|
description: |-
|
||||||
|
The type of receipt to send. This can also be `m.fully_read` as an
|
||||||
|
alternative to [`/read_makers`](/client-server-api/#post_matrixclientv3roomsroomidread_markers).
|
||||||
|
|
||||||
|
Note that `m.fully_read` does not appear under `m.receipt`: this endpoint
|
||||||
|
effectively calls `/read_markers` internally when presented with a receipt
|
||||||
|
type of `m.fully_read`.
|
||||||
required: true
|
required: true
|
||||||
x-example: "m.read"
|
x-example: "m.read"
|
||||||
enum: ["m.read"]
|
x-changedInMatrixVersion:
|
||||||
|
1.4: |
|
||||||
|
Allow `m.read.private` receipts and `m.fully_read` markers to be set.
|
||||||
|
enum: ["m.read", "m.read.private", "m.fully_read"]
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: eventId
|
name: eventId
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ paths:
|
||||||
name: txnId
|
name: txnId
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
The transaction ID for this event. Clients should generate a
|
The [transaction ID](/client-server-api/#transaction-identifiers) for this event. Clients should generate a
|
||||||
unique ID; it will be used by the server to ensure idempotency of requests.
|
unique ID; it will be used by the server to ensure idempotency of requests.
|
||||||
required: true
|
required: true
|
||||||
x-example: "37"
|
x-example: "37"
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ paths:
|
||||||
name: txnId
|
name: txnId
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
The transaction ID for this event. Clients should generate an
|
The [transaction ID](/client-server-api/#transaction-identifiers) for this event. Clients should generate an
|
||||||
ID unique across requests with the same access token; it will be
|
ID unique across requests with the same access token; it will be
|
||||||
used by the server to ensure idempotency of requests.
|
used by the server to ensure idempotency of requests.
|
||||||
required: true
|
required: true
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ paths:
|
||||||
name: txnId
|
name: txnId
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
The transaction ID for this event. Clients should generate an
|
The [transaction ID](/client-server-api/#transaction-identifiers) for this event. Clients should generate an
|
||||||
ID unique across requests with the same access token; it will be
|
ID unique across requests with the same access token; it will be
|
||||||
used by the server to ensure idempotency of requests.
|
used by the server to ensure idempotency of requests.
|
||||||
required: true
|
required: true
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@
|
||||||
"@rikj:jki.re": {
|
"@rikj:jki.re": {
|
||||||
"ts": 1436451550453
|
"ts": 1436451550453
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"m.read.private": {
|
||||||
|
"@self:example.org": {
|
||||||
|
"ts": 1661384801651
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,54 @@
|
||||||
{
|
type: object
|
||||||
"type": "object",
|
title: Receipt Event
|
||||||
"title": "Receipt Event",
|
description: Informs the client of new receipts.
|
||||||
"description": "Informs the client of new receipts.",
|
x-changedInMatrixVersion:
|
||||||
"allOf": [{
|
1.4: |
|
||||||
"$ref": "core-event-schema/event.yaml"
|
Added `m.read.private` receipts to the event's `content`.
|
||||||
}],
|
allOf:
|
||||||
"properties": {
|
- $ref: "core-event-schema/event.yaml"
|
||||||
"content": {
|
properties:
|
||||||
"type": "object",
|
content:
|
||||||
"patternProperties": {
|
type: object
|
||||||
"^\\$": {
|
patternProperties:
|
||||||
"type": "object",
|
"^\\$":
|
||||||
"x-pattern": "$EVENT_ID",
|
type: object
|
||||||
"title": "Receipts",
|
x-pattern: "$EVENT_ID"
|
||||||
"description": "The mapping of event ID to a collection of receipts for this event ID. The event ID is the ID of the event being acknowledged and *not* an ID for the receipt itself.",
|
title: Receipts
|
||||||
"properties": {
|
description: |-
|
||||||
"m.read": {
|
The mapping of event ID to a collection of receipts for this
|
||||||
"type": "object",
|
event ID. The event ID is the ID of the event being acknowledged
|
||||||
"title": "Users",
|
and *not* an ID for the receipt itself.
|
||||||
"description": "A collection of users who have sent `m.read` receipts for this event.",
|
properties:
|
||||||
"patternProperties": {
|
"m.read":
|
||||||
"^@": {
|
type: object
|
||||||
"type": "object",
|
title: Users
|
||||||
"title": "Receipt",
|
description: |-
|
||||||
"description": "The mapping of user ID to receipt. The user ID is the entity who sent this receipt.",
|
A collection of users who have sent `m.read` receipts for
|
||||||
"x-pattern": "$USER_ID",
|
this event.
|
||||||
"properties": {
|
patternProperties:
|
||||||
"ts": {
|
"^@": &receiptUserMap
|
||||||
"type": "integer",
|
type: object
|
||||||
"format": "int64",
|
title: Receipt
|
||||||
"description": "The timestamp the receipt was sent at."
|
description: |-
|
||||||
}
|
The mapping of user ID to receipt. The user ID is the
|
||||||
}
|
entity who sent this receipt.
|
||||||
}
|
x-pattern: "$USER_ID"
|
||||||
}
|
properties:
|
||||||
}
|
ts:
|
||||||
}
|
type: integer
|
||||||
}
|
format: int64
|
||||||
},
|
description: The timestamp the receipt was sent at.
|
||||||
"additionalProperties": false
|
"m.read.private":
|
||||||
},
|
type: object
|
||||||
"type": {
|
title: Own User
|
||||||
"type": "string",
|
description: |-
|
||||||
"enum": ["m.receipt"]
|
Similar to `m.read`, the users who have sent `m.read.private`
|
||||||
}
|
receipts for this event. Due to the nature of private read
|
||||||
},
|
receipts, this should only ever have the current user's ID.
|
||||||
"required": ["type", "content"]
|
patternProperties:
|
||||||
}
|
"^@": *receiptUserMap
|
||||||
|
additionalProperties: false
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum: ["m.receipt", "m.receipt.private"]
|
||||||
|
required: ["type", "content"]
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
*/}}
|
*/}}
|
||||||
{{ if reflect.IsMap $property.additionalProperties }}
|
{{ if reflect.IsMap $property.additionalProperties }}
|
||||||
{{ if $property.additionalProperties.title }}
|
{{ if $property.additionalProperties.title }}
|
||||||
{{ $type = delimit (slice "{ string: " $property.additionalProperties.title "}" ) "" }}
|
{{ $type = delimit (slice "{string: " $property.additionalProperties.title "}" ) "" }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
<td>
|
<td>
|
||||||
{{ if $required }}<strong>Required: </strong>{{end -}}
|
{{ if $required }}<strong>Required: </strong>{{end -}}
|
||||||
{{ $property.description | markdownify -}}
|
{{ $property.description | markdownify -}}
|
||||||
{{ if eq $type "enum"}}<p>One of: <code>{{ $property.enum }}</code>.</p>{{ end -}}
|
{{ if eq $type "enum"}}<p>One of: <code>[{{ delimit $property.enum ", " }}]</code>.</p>{{ end -}}
|
||||||
{{ if (index $property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index $property "x-addedInMatrixVersion")) }}{{ end -}}
|
{{ if (index $property "x-addedInMatrixVersion") }}{{ partial "added-in" (dict "v" (index $property "x-addedInMatrixVersion")) }}{{ end -}}
|
||||||
{{ if (index $property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index $property "x-changedInMatrixVersion")) }}{{ end -}}
|
{{ if (index $property "x-changedInMatrixVersion") }}{{ partial "changed-in" (dict "changes_dict" (index $property "x-changedInMatrixVersion")) }}{{ end -}}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue