From c4db688af865892857242d4ec810598a8eb400c8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 8 Jun 2022 15:32:55 -0600 Subject: [PATCH] Spec `/relations` and aggregations (#1062) * Commit to show changes to rich replies section * Move rich replies to a module * Add remainder of MSC2674 * Pivot away from MSC3440: Threads * Add changelog entries so far * Make a note for why we have aggregations/relations if nothing uses it * Outright remove threads references Apparently this breaks the table of contents * Define MSC2675 * Define MSC3666 * Add note for rich replies? * Update content/client-server-api/_index.md Co-authored-by: Patrick Cloke * Clarify how ignoring works for aggregations. * Try to clarify redactions a bit * Clarify using parent/child language * Add missing bits of MSC2675 * Add changelog for aggregations * Appease the linters * Update data/api/client-server/relations.yaml Co-authored-by: Patrick Cloke * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Try to clarify the return of /relations * Fix required attribute * Fix wording round 1 * Try to fix pagination * Copy/paste the endpoint to make Open API happy * Fix code block examples for rich replies * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Apply suggestions on all 3 endpoints * Fix description of relationships API * Fix warning about server-side aggregation/bundling Co-authored-by: Patrick Cloke Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- .../newsfragments/1062.feature.1 | 1 + .../newsfragments/1062.feature.2 | 1 + .../newsfragments/1062.feature.3 | 1 + content/client-server-api/_index.md | 222 +++++++++ .../modules/instant_messaging.md | 163 ------- .../client-server-api/modules/rich_replies.md | 182 ++++++++ .../definitions/m.relates_to.yaml | 43 ++ data/api/client-server/relations.yaml | 425 ++++++++++++++++++ 8 files changed, 875 insertions(+), 163 deletions(-) create mode 100644 changelogs/client_server/newsfragments/1062.feature.1 create mode 100644 changelogs/client_server/newsfragments/1062.feature.2 create mode 100644 changelogs/client_server/newsfragments/1062.feature.3 create mode 100644 content/client-server-api/modules/rich_replies.md create mode 100644 data/api/client-server/definitions/m.relates_to.yaml create mode 100644 data/api/client-server/relations.yaml diff --git a/changelogs/client_server/newsfragments/1062.feature.1 b/changelogs/client_server/newsfragments/1062.feature.1 new file mode 100644 index 000000000..6c669e436 --- /dev/null +++ b/changelogs/client_server/newsfragments/1062.feature.1 @@ -0,0 +1 @@ +Relax the restrictions on Rich Replies, as per [MSC3676](https://github.com/matrix-org/matrix-spec-proposals/pull/3676). \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1062.feature.2 b/changelogs/client_server/newsfragments/1062.feature.2 new file mode 100644 index 000000000..8234ef2a6 --- /dev/null +++ b/changelogs/client_server/newsfragments/1062.feature.2 @@ -0,0 +1 @@ +Describe a structured system for event relationships, as per [MSC2674](https://github.com/matrix-org/matrix-spec-proposals/pull/2674). \ No newline at end of file diff --git a/changelogs/client_server/newsfragments/1062.feature.3 b/changelogs/client_server/newsfragments/1062.feature.3 new file mode 100644 index 000000000..d2a376afb --- /dev/null +++ b/changelogs/client_server/newsfragments/1062.feature.3 @@ -0,0 +1 @@ +Describe how relationships between events can be "aggregated", as per [MSC2675](https://github.com/matrix-org/matrix-spec-proposals/pull/2675) and [MSC3666](https://github.com/matrix-org/matrix-spec-proposals/pull/3666). \ No newline at end of file diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 67bca5e56..00e3f4ada 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -1798,6 +1798,16 @@ There are several APIs provided to `GET` events for a room: ### Sending events to a room +{{% boxes/note %}} +{{% added-in v="1.3" %}} + +Servers might need to post-process some events if they +[relate to](#forming-relationships-between-events) another event. The event's +relationship type (`rel_type`) determines any restrictions which might apply, +such as the user only being able to send one event of a given type in relation +to another. +{{% /boxes/note %}} + {{% http-api spec="client-server" api="room_state" %}} **Examples** @@ -1888,6 +1898,216 @@ the topic to be removed from the room. {{% http-api spec="client-server" api="redaction" %}} +### Forming relationships between events + +{{% changed-in v="1.3" %}} + +In some cases it is desirable to logically associate one event's contents with +another event's contents — for example, when replying to a message, editing an +event, or simply looking to add context for an event's purpose. + +Events are related to each other in a parent/child structure, where any event can +become a parent by simply having a child event point at it. Parent events do not +define their children, instead relying on the children to describe their parent. + +The relationship between a child and its parent event is described in the child +event's `content` as `m.relates_to` (defined below). A child event can point at +any other event, including another child event, to build the relationship so long +as both events are in the same room, however additional restrictions might be imposed +by the type of the relationship (the `rel_type`). + +{{% boxes/note %}} +Child events can point at other child events, forming a chain of events. These chains +can naturally take the shape of a tree if two independent children point at a single +parent event, for example. +{{% /boxes/note %}} + +To allow the server to aggregate and find child events for a parent, the `m.relates_to` +key of an event MUST be included in the plaintext copy of the event. It cannot be +exclusively recorded in the encrypted payload as the server cannot decrypt the event +for processing. + +{{% boxes/warning %}} +If an encrypted event contains an `m.relates_to` in its payload, it should be +ignored and instead favour the plaintext `m.relates_to` copy (including when there +is no plaintext copy). This is to ensure the client's behaviour matches the server's +capability to handle relationships. +{{% /boxes/warning %}} + +Relationships which don't match the schema, or which break the rules of a relationship, +are simply ignored. An example might be the parent and child being in different +rooms, or the relationship missing properties required by the schema below. Clients +handling such invalid relationships should show the events independently of each +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: + +{{% definition path="api/client-server/definitions/m.relates_to" %}} + +#### Relationship types + +This specification describes the following relationship types: + +* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`). + +#### Aggregations + +{{% added-in v="1.3" %}} + +Some child events can be "aggregated" by the server, depending on their +`rel_type`. This can allow a set of child events to be summarised to the client without +the client needing the child events themselves. + +An example of this might be that a `rel_type` requires an extra `key` field which, when +appropriately specified, would mean that the client receives a total count for the number +of times that `key` was used by child events. + +The actual aggregation format depends on the `rel_type`. + +{{% boxes/note %}} +This specification does not currently describe any `rel_type`s which require +aggregation. This functionality forms a framework for future extensions. +{{% /boxes/note %}} + +Aggregations are sometimes automatically included by a server alongside the parent +event. This is known as a "bundled aggregation" or "bundle" for simplicity. The +act of doing this is "bundling". + +When an event is served to the client through the APIs listed below, a `m.relations` property +is included under `unsigned` if the event has child events which can be aggregated and point +at it. The `m.relations` property is an object keyed by `rel_type` and value being the type-specific +aggregated format for that `rel_type`, also known as the bundle. + +For example (unimportant fields not included): + +```json +{ + "event_id": "$my_event", + "unsigned": { + "m.relations": { + "org.example.possible_annotations": [ + { + "key": "👍", + "origin_server_ts": 1562763768320, + "count": 3 + }, + { + "key": "👎", + "origin_server_ts": 1562763768320, + "count": 1 + } + ], + "org.example.possible_thread": { + "current_server_participated": true, + "count": 7, + "latest_event": { + "event_id": "$another_event", + "content": { + "body": "Hello world" + } + } + } + } + } +} +``` + +Note how the `org.example.possible_annotations` bundle is an array compared to the +`org.example.possible_thread` bundle where the server is summarising the state of +the relationship in a single object. Both are valid ways to aggregate, and their +exact types depend on the `rel_type`. + +{{% boxes/warning %}} +State events do not currently receive bundled aggregations. This is not +necessarily a deliberate design decision, and MSCs which aim to fix this are welcome. +{{% /boxes/warning %}} + +The endpoints where the server *should* include bundled aggregations are: + +* [`GET /rooms/{roomId}/messages`](#get_matrixclientv3roomsroomidmessages) +* [`GET /rooms/{roomId}/context/{eventId}`](#get_matrixclientv3roomsroomidcontexteventid) +* [`GET /rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid) +* [`GET /rooms/{roomId}/relations/{eventId}`](#get_matrixclientv1roomsroomidrelationseventid) +* [`GET /rooms/{roomId}/relations/{eventId}/{relType}`](#get_matrixclientv1roomsroomidrelationseventidreltype) +* [`GET /rooms/{roomId}/relations/{eventId}/{relType}/{eventType}`](#get_matrixclientv1roomsroomidrelationseventidreltypeeventtype) +* [`GET /sync`](#get_matrixclientv3sync) when the relevant section has a `limited` value + of `true`. +* [`POST /search`](#post_matrixclientv3search) for any matching events under `room_events`. + +{{% boxes/note %}} +The server is **not** required to return bundled aggregations on deprecated endpoints +such as `/initialSync`. +{{% /boxes/note %}} + +While this functionality allows the client to see what was known to the server at the +time of handling, the client should continue to aggregate locally if it is aware of +the relationship type's behaviour. For example, a client might increment a `count` +on a parent event's bundle if it saw a new child event which referenced that parent. + +The bundle provided by the server only includes child events which were known at the +time the client would receive the bundle. For example, in a single `/sync` response +with the parent and multiple child events the child events would have already been +included on the parent's `m.relations` field. Events received in future syncs would +need to be aggregated manually by the client. + +{{% boxes/note %}} +Events from [ignored users](#ignoring-users) do not appear in the aggregation +from the server, however clients might still have events from ignored users cached. Like +with normal events, clients will need to de-aggregate child events sent by ignored users to +avoid them being considered in counts. Servers must additionally ensure they do not +consider child events from ignored users when preparing a bundle for the client. +{{% /boxes/note %}} + +When a parent event is redacted, the child events which pointed to that parent remain, however +when a child event is redacted then the relationship is broken. Therefore, the server needs +to de-aggregate or disassociate the event once the relationship is lost. Clients with local +aggregation or which handle redactions locally should do the same. + +It is suggested that clients perform local echo on aggregations — for instance, aggregating +a new child event into a bundle optimistically until the server returns a failure or the client +gives up on sending the event, at which point the event should be de-aggregated and an +error or similar shown. The client should be cautious to not aggregate an event twice if +it has already optimistically aggregated the event. Clients are encouraged to take this +a step further to additionally track child events which target unsent/pending events, +likely using the transaction ID as a temporary event ID until a proper event ID is known. + +{{% boxes/warning %}} +Due to history visibility restrictions, child events might not be visible to the user +if they are in a section of history the user cannot see. This means any bundles which would +normally include those events will be lacking them and the client will not be able to +locally aggregate the events either — relating events of importance (such as votes) should +take into consideration history visibility. + +Additionally, if the server is missing portions of the room history then it may not be +able to accurately aggregate the events. +{{% /boxes/warning %}} + +#### Relationships API + +{{% added-in v="1.3" %}} + +To retrieve the child events for a parent from the server, the client can call the +following endpoint. + +This endpoint is particularly useful if the client has lost context on the aggregation for +a parent event and needs to rebuild/verify it. + +{{% boxes/note %}} +Because replies do not use `rel_type`, they will not be accessible via this API. +{{% /boxes/note %}} + +{{% http-api spec="client-server" api="relations" %}} + ## Rooms ### Types @@ -2294,6 +2514,7 @@ that profile. | Module / Profile | Web | Mobile | Desktop | CLI | Embedded | |------------------------------------------------------------|-----------|----------|----------|----------|----------| | [Instant Messaging](#instant-messaging) | Required | Required | Required | Required | Optional | +| [Rich replies](#rich-replies) | Optional | Optional | Optional | Optional | Optional | | [Direct Messaging](#direct-messaging) | Required | Required | Required | Required | Optional | | [Mentions](#user-room-and-group-mentions) | Required | Required | Required | Optional | Optional | | [Presence](#presence) | Required | Required | Required | Required | Optional | @@ -2373,6 +2594,7 @@ applications, they are not intended to be fully-fledged communication systems. {{% cs-module name="instant_messaging" %}} +{{% cs-module name="rich_replies" %}} {{% cs-module name="voip_events" %}} {{% cs-module name="typing_notifications" %}} {{% cs-module name="receipts" %}} diff --git a/content/client-server-api/modules/instant_messaging.md b/content/client-server-api/modules/instant_messaging.md index e2138e0b1..7f9b3ca18 100644 --- a/content/client-server-api/modules/instant_messaging.md +++ b/content/client-server-api/modules/instant_messaging.md @@ -287,169 +287,6 @@ when using the `m.heroes` to calculate the name. Clients SHOULD use minimum 5 heroes to calculate room names where possible, but may use more or less to fit better with their user experience. -##### Rich replies - -In some cases, events may wish to reference other events. This could be -to form a thread of messages for the user to follow along with, or to -provide more context as to what a particular event is describing. -Currently, the only kind of relation defined is a "rich reply" where a -user may reference another message to create a thread-like conversation. - -Relationships are defined under an `m.relates_to` key in the event's -`content`. If the event is of the type `m.room.encrypted`, the -`m.relates_to` key MUST NOT be covered by the encryption and instead be -put alongside the encryption information held in the `content`. - -A rich reply is formed through use of an `m.relates_to` relation for -`m.in_reply_to` where a single key, `event_id`, is used to reference the -event being replied to. The referenced event ID SHOULD belong to the -same room where the reply is being sent. Clients should be cautious of -the event ID belonging to another room, or being invalid entirely. Rich -replies can only be constructed in the form of `m.room.message` events -with a `msgtype` of `m.text` or `m.notice`. Due to the fallback -requirements, rich replies cannot be constructed for types of `m.emote`, -`m.file`, etc. Rich replies may reference any other `m.room.message` -event, however. Rich replies may reference another event which also has -a rich reply, infinitely. - -An `m.in_reply_to` relationship looks like the following: - -``` -{ - ... - "type": "m.room.message", - "content": { - "msgtype": "m.text", - "body": "", - "format": "org.matrix.custom.html", - "formatted_body": "", - "m.relates_to": { - "m.in_reply_to": { - "event_id": "$another:event.com" - } - } - } -} -``` - -##### Fallbacks for rich replies - -Some clients may not have support for rich replies and therefore need a -fallback to use instead. Clients that do not support rich replies should -render the event as if rich replies were not special. - -Clients that do support rich replies MUST provide the fallback format on -replies, and MUST strip the fallback before rendering the reply. Rich -replies MUST have a `format` of `org.matrix.custom.html` and therefore a -`formatted_body` alongside the `body` and appropriate `msgtype`. The -specific fallback text is different for each `msgtype`, however the -general format for the `body` is: - - > <@alice:example.org> This is the original body - - This is where the reply goes - -The `formatted_body` should use the following template: - - -
- In reply to - @alice:example.org -
- -
-
- This is where the reply goes. - -If the related event does not have a `formatted_body`, the event's -`body` should be considered after encoding any HTML special characters. -Note that the `href` in both of the anchors use a [matrix.to -URI](/appendices#matrixto-navigation). - -###### Stripping the fallback - -Clients which support rich replies MUST strip the fallback from the -event before rendering the event. This is because the text provided in -the fallback cannot be trusted to be an accurate representation of the -event. After removing the fallback, clients are recommended to represent -the event referenced by `m.in_reply_to` similar to the fallback's -representation, although clients do have creative freedom for their user -interface. Clients should prefer the `formatted_body` over the `body`, -just like with other `m.room.message` events. - -To strip the fallback on the `body`, the client should iterate over each -line of the string, removing any lines that start with the fallback -prefix ("> ", including the space, without quotes) and stopping when -a line is encountered without the prefix. This prefix is known as the -"fallback prefix sequence". - -To strip the fallback on the `formatted_body`, the client should remove -the entirety of the `mx-reply` tag. - -###### Fallback for `m.text`, `m.notice`, and unrecognised message types - -Using the prefix sequence, the first line of the related event's `body` -should be prefixed with the user's ID, followed by each line being -prefixed with the fallback prefix sequence. For example: - - > <@alice:example.org> This is the first line - > This is the second line - - This is the reply - -The `formatted_body` uses the template defined earlier in this section. - -###### Fallback for `m.emote` - -Similar to the fallback for `m.text`, each line gets prefixed with the -fallback prefix sequence. However an asterisk should be inserted before -the user's ID, like so: - - > * <@alice:example.org> feels like today is going to be a great day - - This is the reply - -The `formatted_body` has a subtle difference for the template where the -asterisk is also inserted ahead of the user's ID: - - -
- In reply to - * @alice:example.org -
- -
-
- This is where the reply goes. - -###### Fallback for `m.image`, `m.video`, `m.audio`, and `m.file` - -The related event's `body` would be a file name, which may not be very -descriptive. The related event should additionally not have a `format` -or `formatted_body` in the `content` - if the event does have a `format` -and/or `formatted_body`, those fields should be ignored. Because the -filename alone may not be descriptive, the related event's `body` should -be considered to be `"sent a file."` such that the output looks similar -to the following: - - > <@alice:example.org> sent a file. - - This is the reply - - -
- In reply to - @alice:example.org -
- sent a file. -
-
- This is where the reply goes. - -For `m.image`, the text should be `"sent an image."`. For `m.video`, the -text should be `"sent a video."`. For `m.audio`, the text should be -`"sent an audio file"`. - ##### Spoiler messages {{% added-in v="1.1" %}} diff --git a/content/client-server-api/modules/rich_replies.md b/content/client-server-api/modules/rich_replies.md new file mode 100644 index 000000000..60c023631 --- /dev/null +++ b/content/client-server-api/modules/rich_replies.md @@ -0,0 +1,182 @@ +--- +type: module +--- + +### Rich replies + +{{% changed-in v="1.3" %}} + +Rich replies are a +special kind of [relationship](#forming-relationships-between-events) which +effectively quotes the referenced event for the client to render/process how +it wishes. They are normally used with [`m.room.message`](#mroommessage) events. + +{{% boxes/note %}} +Until v1.3 of the spec, rich replies were limited to `m.room.message` events +which could represent an HTML-formatted body. As of v1.3 this is now expanded +to *all* event types by dropping the requirement that an HTML-formatted body +be included. + +Additionally, a rich reply can reference any other event type as of v1.3. +Previously, a rich reply could only reference another `m.room.message` event. +{{% /boxes/note %}} + +When possible, events SHOULD include a [fallback representation](#fallbacks-for-rich-replies) +to allow clients which do not render rich replies to still see something which +appears to be a quoted reply. + +Though rich replies form a relationship to another event, they do not +use `rel_type` to create this relationship. Instead, a subkey named `m.in_reply_to` +is used to describe the reply's relationship, leaving the other properties of +`m.relates_to` to describe the primary relationship of the event. This means +that if an event is simply in reply to another event, without further relationship, +the `rel_type` and `event_id` properties of `m.relates_to` become *optional*. + +An example reply would be: + +```json5 +{ + "content": { + "m.relates_to": { + "m.in_reply_to": { + "event_id": "$another_event" + } + }, + "body": "That sounds like a great idea!" + }, + // other fields as required by events +} +``` + +Note that the `event_id` of the `m.in_reply_to` object has the same requirements +as if it were to be under `m.relates_to` directly instead. + +#### Fallbacks for rich replies + +Some clients may not have support for rich replies and therefore need a +fallback to use instead. Clients that do not support rich replies should +render the event as if rich replies were not special. + +Clients that do support rich replies SHOULD provide the fallback format on +replies, and MUST strip the fallback before rendering the reply. The +specific fallback text is different for each `msgtype`, however the +general format for the `body` is: + +```text +> <@alice:example.org> This is the original body + +This is where the reply goes +``` + +The `formatted_body`, if present and using an associated `format` of +`org.matrix.custom.html`, should use the following template: + +```html + +
+ In reply to + @alice:example.org +
+ +
+
+This is where the reply goes. +``` + +If the related event does not have a `formatted_body`, the event's +`body` should be considered after encoding any HTML special characters. +Note that the `href` in both of the anchors use a [matrix.to +URI](/appendices#matrixto-navigation). + +##### Stripping the fallback + +Clients which support rich replies MUST strip the fallback from the +event before rendering the event. This is because the text provided in +the fallback cannot be trusted to be an accurate representation of the +event. After removing the fallback, clients are recommended to represent +the event referenced by `m.in_reply_to` similar to the fallback's +representation, although clients do have creative freedom for their user +interface. Clients should prefer the `formatted_body` over the `body`, +just like with other `m.room.message` events. + +To strip the fallback on the `body`, the client should iterate over each +line of the string, removing any lines that start with the fallback +prefix ("> ", including the space, without quotes) and stopping when +a line is encountered without the prefix. This prefix is known as the +"fallback prefix sequence". + +To strip the fallback on the `formatted_body`, the client should remove +the entirety of the `mx-reply` tag. + +##### Fallback for `m.text`, `m.notice`, and unrecognised message types + +Using the prefix sequence, the first line of the related event's `body` +should be prefixed with the user's ID, followed by each line being +prefixed with the fallback prefix sequence. For example: + +```text +> <@alice:example.org> This is the first line +> This is the second line + +This is the reply +``` + +The `formatted_body` uses the template defined earlier in this section. + +##### Fallback for `m.emote` + +Similar to the fallback for `m.text`, each line gets prefixed with the +fallback prefix sequence. However an asterisk should be inserted before +the user's ID, like so: + +```text +> * <@alice:example.org> feels like today is going to be a great day + +This is the reply +``` + +The `formatted_body` has a subtle difference for the template where the +asterisk is also inserted ahead of the user's ID: + +```html + +
+ In reply to + * @alice:example.org +
+ +
+
+This is where the reply goes. +``` + +##### Fallback for `m.image`, `m.video`, `m.audio`, and `m.file` + +The related event's `body` would be a file name, which may not be very +descriptive. The related event should additionally not have a `format` +or `formatted_body` in the `content` - if the event does have a `format` +and/or `formatted_body`, those fields should be ignored. Because the +filename alone may not be descriptive, the related event's `body` should +be considered to be `"sent a file."` such that the output looks similar +to the following: + +```text +> <@alice:example.org> sent a file. + +This is the reply +``` +```html + +
+ In reply to + @alice:example.org +
+ sent a file. +
+
+This is where the reply goes. +``` + +For `m.image`, the text should be `"sent an image."`. For `m.video`, the +text should be `"sent a video."`. For `m.audio`, the text should be +`"sent an audio file"`. \ No newline at end of file diff --git a/data/api/client-server/definitions/m.relates_to.yaml b/data/api/client-server/definitions/m.relates_to.yaml new file mode 100644 index 000000000..591281c39 --- /dev/null +++ b/data/api/client-server/definitions/m.relates_to.yaml @@ -0,0 +1,43 @@ +# Copyright 2022 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: object +title: m.relates_to +description: |- + Describes the relationship of an event to its parent. This is contained + within the event's `content` alongside other fields for the relevant event type. +example: { + # We deliberately "break" the example by including the top-level field so it renders + # sensibly for readers of the spec. + "m.relates_to": { + "rel_type": "org.example.relationship", + "event_id": "$an_event" + } +} +properties: + rel_type: + type: string + description: |- + The namespaced relationship type. Values must use the + [Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar). + + The relationship type determines how clients should perceive the event, and in what + context. Some relationship types are processed server-side for "bundling", though not + all relationships require such behaviour. For example, an `m.thread` relationship type + might denote that the event is part of a "thread" of messages and should be rendered as + such. + event_id: + type: string + description: The event ID of the event that this event relates to. +required: ['rel_type', 'event_id'] diff --git a/data/api/client-server/relations.yaml b/data/api/client-server/relations.yaml new file mode 100644 index 000000000..dc0d87613 --- /dev/null +++ b/data/api/client-server/relations.yaml @@ -0,0 +1,425 @@ +# Copyright 2022 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +swagger: '2.0' +info: + title: "Matrix Client-Server Relations API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/client/v1 +consumes: + - application/json +produces: + - application/json +securityDefinitions: + $ref: definitions/security.yaml +paths: + "/rooms/{roomId}/relations/{eventId}": + get: + summary: Get the child events for a given parent event. + description: |- + Retrieve all of the child events for a given parent event. + + Note that when paginating the `from` token should be "after" the `to` token in + terms of topological ordering, because it is only possible to paginate "backwards" + through events, starting at `from`. + + For example, passing a `from` token from page 2 of the results, and a `to` token + from page 1, would return the empty set. The caller can use a `from` token from + page 1 and a `to` token from page 2 to paginate over the same range, however. + operationId: getRelatingEvents + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The ID of the room containing the parent event. + required: true + x-example: "!636q39766251:matrix.org" + - in: path + type: string + name: eventId + description: The ID of the parent event whose child events are to be returned. + required: true + x-example: "$asfDuShaf7Gafaw" + - in: query + type: string + name: from + description: |- + The pagination token to start returning results from. If not supplied, results + start at the most recent topological event known to the server. + + Can be a `next_batch` token from a previous call, or a returned + `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), + or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). + required: false + x-example: "page2_token" + - in: query + type: string + name: to + description: |- + The pagination token to stop returning results at. If not supplied, results + continue up to `limit` or until there are no more events. + + Like `from`, this can be a previous token from a prior call to this endpoint + or from `/messages` or `/sync`. + required: false + x-example: "page3_token" + - in: query + type: integer + name: limit + description: |- + The maximum number of results to return in a single `chunk`. The server can + and should apply a maximum value to this parameter to avoid large responses. + + Similarly, the server should apply a default value when not supplied. + required: false + x-example: 20 + responses: + # note: this endpoint deliberately does not support rate limiting, therefore a + # 429 error response is not included. + + 200: + description: |- + The paginated child events which point to the parent. If no events are + pointing to the parent or the pagination yields no results, an empty `chunk` + is returned. + examples: + application/json: { + "chunk": [{ + "room_id": "!636q39766251:matrix.org", + "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", + "content": { + "m.relates_to": { + "rel_type": "org.example.my_relation", + "event_id": "$asfDuShaf7Gafaw" + } + } + }], + "next_batch": "page2_token", + "prev_batch": "page1_token" + } + schema: + type: object + properties: + chunk: + title: "ChildEventsChunk" + type: array + description: |- + The child events of the requested event, ordered topologically most-recent first. + items: + allOf: + - "$ref": "definitions/client_event.yaml" + next_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means there are no more results to fetch and the client should stop paginating. + prev_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means this is the start of the result set, i.e. this is the first batch/page. + required: ['chunk'] + 404: + description: |- + The parent event was not found or the user does not have permission to read + this event (it might be contained in history that is not accessible to the user). + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Event not found." + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - Event relationships + # The same as above, with added `/{relType}` + "/rooms/{roomId}/relations/{eventId}/{relType}": + get: + summary: Get the child events for a given parent event, with a given `relType`. + description: |- + Retrieve all of the child events for a given parent event which relate to the parent + using the given `relType`. + + Note that when paginating the `from` token should be "after" the `to` token in + terms of topological ordering, because it is only possible to paginate "backwards" + through events, starting at `from`. + + For example, passing a `from` token from page 2 of the results, and a `to` token + from page 1, would return the empty set. The caller can use a `from` token from + page 1 and a `to` token from page 2 to paginate over the same range, however. + operationId: getRelatingEventsWithRelType + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The ID of the room containing the parent event. + required: true + x-example: "!636q39766251:matrix.org" + - in: path + type: string + name: eventId + description: The ID of the parent event whose child events are to be returned. + required: true + x-example: "$asfDuShaf7Gafaw" + - in: path + type: string + name: relType + description: |- + The [relationship type](/client-server-api/#relationship-types) to search for. + required: true + x-example: "org.example.my_relation" + - in: query + type: string + name: from + description: |- + The pagination token to start returning results from. If not supplied, results + start at the most recent topological event known to the server. + + Can be a `next_batch` token from a previous call, or a returned + `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), + or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). + required: false + x-example: "page2_token" + - in: query + type: string + name: to + description: |- + The pagination token to stop returning results at. If not supplied, results + continue up to `limit` or until there are no more events. + + Like `from`, this can be a previous token from a prior call to this endpoint + or from `/messages` or `/sync`. + required: false + x-example: "page3_token" + - in: query + type: integer + name: limit + description: |- + The maximum number of results to return in a single `chunk`. The server can + and should apply a maximum value to this parameter to avoid large responses. + + Similarly, the server should apply a default value when not supplied. + required: false + x-example: 20 + responses: + # note: this endpoint deliberately does not support rate limiting, therefore a + # 429 error response is not included. + + 200: + description: |- + The paginated child events which point to the parent. If no events are + pointing to the parent or the pagination yields no results, an empty `chunk` + is returned. + examples: + application/json: { + "chunk": [{ + "room_id": "!636q39766251:matrix.org", + "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", + "content": { + "m.relates_to": { + "rel_type": "org.example.my_relation", + "event_id": "$asfDuShaf7Gafaw" + } + } + }], + "next_batch": "page2_token", + "prev_batch": "page1_token" + } + schema: + type: object + properties: + chunk: + title: "ChildEventsChunk" + type: array + description: |- + The child events of the requested event, ordered topologically + most-recent first. The events returned will match the `relType` + supplied in the URL. + items: + allOf: + - "$ref": "definitions/client_event.yaml" + next_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means there are no more results to fetch and the client should stop paginating. + prev_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means this is the start of the result set, i.e. this is the first batch/page. + required: ['chunk'] + 404: + description: |- + The parent event was not found or the user does not have permission to read + this event (it might be contained in history that is not accessible to the user). + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Event not found." + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - Event relationships + # The same as above, with added `/{eventType}` + "/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}": + get: + summary: Get the child events for a given parent event, with a given `relType` and `eventType`. + description: |- + Retrieve all of the child events for a given parent event which relate to the parent + using the given `relType` and have the given `eventType`. + + Note that when paginating the `from` token should be "after" the `to` token in + terms of topological ordering, because it is only possible to paginate "backwards" + through events, starting at `from`. + + For example, passing a `from` token from page 2 of the results, and a `to` token + from page 1, would return the empty set. The caller can use a `from` token from + page 1 and a `to` token from page 2 to paginate over the same range, however. + operationId: getRelatingEventsWithRelTypeAndEventType + security: + - accessToken: [] + parameters: + - in: path + type: string + name: roomId + description: The ID of the room containing the parent event. + required: true + x-example: "!636q39766251:matrix.org" + - in: path + type: string + name: eventId + description: The ID of the parent event whose child events are to be returned. + required: true + x-example: "$asfDuShaf7Gafaw" + - in: path + type: string + name: relType + description: |- + The [relationship type](/client-server-api/#relationship-types) to search for. + required: true + x-example: "org.example.my_relation" + - in: path + type: string + name: eventType + description: |- + The event type of child events to search for. + + Note that in encrypted rooms this will typically always be `m.room.encrypted` + regardless of the event type contained within the encrypted payload. + required: true + x-example: "m.room.message" + - in: query + type: string + name: from + description: |- + The pagination token to start returning results from. If not supplied, results + start at the most recent topological event known to the server. + + Can be a `next_batch` token from a previous call, or a returned + `start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages), + or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync). + required: false + x-example: "page2_token" + - in: query + type: string + name: to + description: |- + The pagination token to stop returning results at. If not supplied, results + continue up to `limit` or until there are no more events. + + Like `from`, this can be a previous token from a prior call to this endpoint + or from `/messages` or `/sync`. + required: false + x-example: "page3_token" + - in: query + type: integer + name: limit + description: |- + The maximum number of results to return in a single `chunk`. The server can + and should apply a maximum value to this parameter to avoid large responses. + + Similarly, the server should apply a default value when not supplied. + required: false + x-example: 20 + responses: + # note: this endpoint deliberately does not support rate limiting, therefore a + # 429 error response is not included. + + 200: + description: |- + The paginated child events which point to the parent. If no events are + pointing to the parent or the pagination yields no results, an empty `chunk` + is returned. + examples: + application/json: { + "chunk": [{ + "room_id": "!636q39766251:matrix.org", + "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml", + "content": { + "m.relates_to": { + "rel_type": "org.example.my_relation", + "event_id": "$asfDuShaf7Gafaw" + } + } + }], + "next_batch": "page2_token", + "prev_batch": "page1_token" + } + schema: + type: object + properties: + chunk: + title: "ChildEventsChunk" + type: array + description: |- + The child events of the requested event, ordered topologically most-recent + first. The events returned will match the `relType` and `eventType` supplied + in the URL. + items: + allOf: + - "$ref": "definitions/client_event.yaml" + next_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means there are no more results to fetch and the client should stop paginating. + prev_batch: + type: string + description: |- + An opaque string representing a pagination token. The absence of this token + means this is the start of the result set, i.e. this is the first batch/page. + required: ['chunk'] + 404: + description: |- + The parent event was not found or the user does not have permission to read + this event (it might be contained in history that is not accessible to the user). + examples: + application/json: { + "errcode": "M_NOT_FOUND", + "error": "Event not found." + } + schema: + "$ref": "definitions/errors/error.yaml" + tags: + - Event relationships +