mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-03-26 21:14:09 +01:00
Merge branch 'main' into travis/ref-rel
This commit is contained in:
commit
0add77dea9
|
|
@ -1 +0,0 @@
|
|||
Add HTML anchors for object definitions in the formatted specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Replace homeserver authorization approach with an `Authorization` header instead of `access_token` when talking to the application service, as per [MSC2832](https://github.com/matrix-org/matrix-spec-proposals/pull/2832).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Mention that the `/rooms/{roomId}/invite` endpoint will return a 200 response if the user is already invited to the room.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Describe return codes for account data endpoints, and clarify that per-room data does not inherit from the global data.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Clarify that policy rule globs work like ACL globs. Contributed by Nico.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Clarify the format of some structures in the End-to-end encryption module.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add HTML anchors for object definitions in the formatted specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Tweak the styling of `<code>` snippets in tables rendered from OpenAPI definitions.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Update "API Standards" section to clarify how JSON is used.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add a `.m.rule.room.server_acl` push rule to match `m.room.server_acl` events, as per [MSC3786](https://github.com/matrix-org/matrix-spec-proposals/pull/3786).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Remove unused policy room sharing mechanism, as per [MSC3844](https://github.com/matrix-org/matrix-spec-proposals/pull/3844).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add `Cross-Origin-Resource-Policy` (CORP) headers to media repository, as per [MSC3828](https://github.com/matrix-org/matrix-spec-proposals/pull/3828).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Copy a room's `type` when upgrading it, as per [MSC3818](https://github.com/matrix-org/matrix-spec-proposals/pull/3818).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add `room_types` filter and `room_type` response to `/publicRooms`, as per [MSC3827](https://github.com/matrix-org/matrix-spec-proposals/pull/3827).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add a `.m.rule.room.server_acl` push rule to match `m.room.server_acl` events, as per [MSC3786](https://github.com/matrix-org/matrix-spec-proposals/pull/3786).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Clarify that the "device_id", "user_id" and "access_token" fields are required in the response body of `POST /_matrix/client/v3/login`.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add `m.replace` relations (event edits), as per [MSC2676](https://github.com/matrix-org/matrix-spec-proposals/pull/2676).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add `m.read.private` receipts, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Make `m.fully_read` optional on `/read_markers`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Allow `m.fully_read` markers to be set from `/receipts`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285).
|
||||
|
|
@ -1 +0,0 @@
|
|||
Reinforce the relationship of refreshed access tokens to transaction IDs.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Clarify enum values by separating possible values with commas.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Fix naming of `device_one_time_keys_count` in `/sync`.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Fix various typos throughout the specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add HTML anchors for object definitions in the formatted specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Update "API Standards" section to clarify how JSON is used.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Render HTML anchors for object definition tables.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add internal changes changelog section.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Give rendered-data sections a background and some padding.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix rendering of shortcodes within the client-server API.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Fix the spacing of mapping types generated from the OpenAPI spec.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add HTML anchors for object definitions in the formatted specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
For room versions 1 through 10, clarify that events with rejected `auth_events` must be rejected.
|
||||
|
|
@ -1 +0,0 @@
|
|||
For room versions 2–10: correct a mistaken clarification to the state resolution algorithm.
|
||||
|
|
@ -1 +0,0 @@
|
|||
For room versions 7 through 10: Clarify that `invite->knock` is actually a legal transition.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Reword the event auth rules to clarify that users cannot demote other users with the same power level.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Various clarifications to the text on event authorisation rules.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Add HTML anchors for object definitions in the formatted specification.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Tweak the styling of `<code>` snippets in tables rendered from OpenAPI definitions.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Update "API Standards" section to clarify how JSON is used.
|
||||
|
|
@ -49,9 +49,9 @@ status = "unstable"
|
|||
current_version_url = "https://spec.matrix.org/latest"
|
||||
# The following is used when status = "stable", and is displayed in various UI elements on a released version
|
||||
# of the spec. CI will set these values here automatically when a release git tag (i.e `v1.5`) is created.
|
||||
#major = "1"
|
||||
#minor = "3"
|
||||
#release_date = "June 16, 2022"
|
||||
# major = "1"
|
||||
# minor = "4"
|
||||
# release_date = "September 29, 2022"
|
||||
|
||||
# User interface configuration
|
||||
[params.ui]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ underlying homeserver implementation.
|
|||
|
||||
## Application Services
|
||||
|
||||
Application services are passive and can only observe events from
|
||||
Application services are passive and can only observe events from the
|
||||
homeserver. They can inject events into rooms they are participating in.
|
||||
They cannot prevent events from being sent, nor can they modify the
|
||||
content of the event being sent. In order to observe events from a
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ weight: 1000
|
|||
{{% changelog/changelog-changes %}}
|
||||
|
||||
<!-- DO NOT REMOVE OR CHANGE - Release script puts next release here -->
|
||||
{{% changelog/changelog-rendered p="changelogs/v1.4.md" %}}
|
||||
{{% changelog/changelog-rendered p="changelogs/v1.3.md" %}}
|
||||
{{% changelog/changelog-rendered p="changelogs/v1.2.md" %}}
|
||||
{{% changelog/changelog-rendered p="changelogs/v1.1.md" %}}
|
||||
|
|
|
|||
|
|
@ -1972,6 +1972,7 @@ This specification describes the following relationship types:
|
|||
|
||||
* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
|
||||
* [Event replacements](#event-replacements).
|
||||
* [Threads](#threading).
|
||||
* [References](#reference-relations)
|
||||
|
||||
#### Aggregations
|
||||
|
|
@ -1988,11 +1989,6 @@ 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".
|
||||
|
|
@ -2057,6 +2053,7 @@ The endpoints where the server *should* include bundled aggregations are:
|
|||
* [`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`.
|
||||
* {{< added-in v="1.4" >}} [`GET /rooms/{roomId}/threads`](#get_matrixclientv1roomsroomidthreads)
|
||||
|
||||
{{% boxes/note %}}
|
||||
The server is **not** required to return bundled aggregations on deprecated endpoints
|
||||
|
|
@ -2643,4 +2640,5 @@ systems.
|
|||
{{< cs-module name="moderation_policies" >}}
|
||||
{{< cs-module name="spaces" >}}
|
||||
{{< cs-module name="event_replacements" >}}
|
||||
{{< cs-module name="threading" >}}
|
||||
{{< cs-module name="reference_relations" >}}
|
||||
|
|
@ -1622,7 +1622,7 @@ specified). The client is expected to use [`/keys/query`](/client-server-api/#po
|
|||
sync, as documented in [Tracking the device list for a
|
||||
user](#tracking-the-device-list-for-a-user).
|
||||
|
||||
It also adds a `one_time_keys_count` property. Note the spelling
|
||||
It also adds a `device_one_time_keys_count` property. Note the spelling
|
||||
difference with the `one_time_key_counts` property in the
|
||||
[`/keys/upload`](/client-server-api/#post_matrixclientv3keysupload) response.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,9 @@ Not all attributes on those tags should be permitted as they may be
|
|||
avenues for other disruption attempts, such as adding `onclick` handlers
|
||||
or excessively large text. Clients should only permit the attributes
|
||||
listed for the tags below. Where `data-mx-bg-color` and `data-mx-color`
|
||||
are listed, clients should translate the value (a 6-character hex color
|
||||
code) to the appropriate CSS/attributes for the tag.
|
||||
are listed, clients should translate the value (a `#` character followed
|
||||
by a 6-character hex color code) to the appropriate CSS/attributes for
|
||||
the tag.
|
||||
|
||||
`font`
|
||||
`data-mx-bg-color`, `data-mx-color`, `color`
|
||||
|
|
|
|||
|
|
@ -107,8 +107,10 @@ determined by the push rules which apply to an event.
|
|||
|
||||
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
|
||||
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.
|
||||
be marked as read. Which specific events are affected can vary depending
|
||||
on whether a [threaded read receipt](#threaded-read-receipts) was used.
|
||||
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
|
||||
|
|
@ -121,6 +123,17 @@ 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).
|
||||
|
||||
{{< added-in v="1.4" >}} When handling threaded read receipts, the server
|
||||
is to partition the notification count to each thread (with the main timeline
|
||||
being its own thread). To determine if an event is part of a thread the
|
||||
server follows the [event relationship](#forming-relationships-between-events)
|
||||
until it finds a thread root (as specified by the [threading module](#threading)),
|
||||
however it is not recommended that the server traverse infinitely. Instead,
|
||||
implementations are encouraged to do a maximum of 3 hops to find a thread
|
||||
before deciding that the event does not belong to a thread. This is primarily
|
||||
to ensure that future events, like `m.reaction`, are correctly considered
|
||||
"part of" a given thread.
|
||||
|
||||
##### Push Rules
|
||||
|
||||
A push rule is a single rule that states under what *conditions* an
|
||||
|
|
|
|||
|
|
@ -22,33 +22,68 @@ that the user had read all events *up to* the referenced event. See the
|
|||
[Receiving notifications](#receiving-notifications) section for more
|
||||
information on how read receipts affect notification counts.
|
||||
|
||||
{{< added-in v="1.4" >}} Read receipts exist in three major forms:
|
||||
* Unthreaded: Denotes a read-up-to receipt regardless of threads. This is how
|
||||
pre-threading read receipts worked.
|
||||
* Threaded, main timeline: Denotes a read-up-to receipt for events not in a
|
||||
particular thread. Identified by the thread ID `main`.
|
||||
* Threaded, in a thread: Denotes a read-up-to receipt within a particular
|
||||
thread. Identified by the event ID of the thread root.
|
||||
|
||||
Threaded read receipts are discussed in further detail [below](#threaded-read-receipts).
|
||||
|
||||
#### Events
|
||||
|
||||
Each `user_id`, `receipt_type` pair must be associated with only a
|
||||
single `event_id`.
|
||||
{{< changed-in v="1.4" >}} Each `user_id`, `receipt_type`, and categorisation
|
||||
(unthreaded, or `thread_id`) tuple must be associated with only a single
|
||||
`event_id`.
|
||||
|
||||
{{% event event="m.receipt" %}}
|
||||
|
||||
#### Client behaviour
|
||||
|
||||
{{< changed-in v="1.4" >}} Altered to support threaded read receipts.
|
||||
|
||||
In `/sync`, receipts are listed under the `ephemeral` array of events
|
||||
for a given room. New receipts that come down the event streams are
|
||||
deltas which update existing mappings. Clients should replace older
|
||||
receipt acknowledgements based on `user_id` and `receipt_type` pairs.
|
||||
receipt acknowledgements based on `user_id`, `receipt_type`, and the
|
||||
`thread_id` (if present).
|
||||
For example:
|
||||
|
||||
Client receives m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $aaa:example.com
|
||||
thread_id = undefined
|
||||
|
||||
Client receives another m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $bbb:example.com
|
||||
thread_id = main
|
||||
|
||||
The client should replace the older acknowledgement for $aaa:example.com with
|
||||
this one for $bbb:example.com
|
||||
The client does not replace any acknowledgements, yet.
|
||||
|
||||
Client receives yet another m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $ccc:example.com
|
||||
thread_id = undefined
|
||||
|
||||
The client replaces the older acknowledgement for $aaa:example.com
|
||||
with this new one for $ccc:example.com, but does not replace the
|
||||
acknowledgement for $bbb:example.com because it belongs to a thread.
|
||||
|
||||
Client receives yet another m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $ddd:example.com
|
||||
thread_id = main
|
||||
|
||||
Now the client replaces the older $bbb:example.com acknowledgement with
|
||||
this new $ddd:example.com acknowledgement. The client does NOT replace the
|
||||
older acknowledgement for $ccc:example.com as it is unthreaded.
|
||||
|
||||
Clients should send read receipts when there is some certainty that the
|
||||
event in question has been **displayed** to the user. Simply receiving
|
||||
|
|
@ -58,6 +93,12 @@ room that the event was sent to or dismissing a notification in order
|
|||
for the event to count as "read". Clients SHOULD NOT send read receipts
|
||||
for events sent by their own user.
|
||||
|
||||
Similar to the rules for sending receipts, threaded receipts should appear
|
||||
in the context of the thread. If a thread is rendered behind a disclosure,
|
||||
the client hasn't yet shown the event (or any applicable read receipts)
|
||||
to the user. Once they expand the thread though, a threaded read receipt
|
||||
would be sent and per-thread receipts from other users shown.
|
||||
|
||||
A client can update the markers for its user by interacting with the
|
||||
following HTTP APIs.
|
||||
|
||||
|
|
@ -87,6 +128,89 @@ 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.
|
||||
|
||||
##### Threaded read receipts
|
||||
|
||||
{{% added-in v="1.4" %}}
|
||||
|
||||
If a client does not use [threading](#threading), then they will simply only
|
||||
send "unthreaded" read receipts which affect the whole room regardless of threads.
|
||||
|
||||
A threaded read receipt is simply one which has a `thread_id` on it, targeting
|
||||
either a thread root's event ID or `main` for the main timeline.
|
||||
|
||||
Threading introduces a concept of multiple conversations being held in the same
|
||||
room and thus deserve their own read receipts and notification counts. An event is
|
||||
considered to be "in a thread" if it meets any of the following criteria:
|
||||
* It has a `rel_type` of `m.thread`.
|
||||
* It has child events with a `rel_type` of `m.thread` (in which case it'd be the
|
||||
thread root).
|
||||
* Following the event relationships, it has a parent event which qualifies for
|
||||
one of the above. Implementations should not recurse infinitely, though: a
|
||||
maximum of 3 hops is recommended to cover indirect relationships.
|
||||
|
||||
Events not in a thread but still in the room are considered to be part of the
|
||||
"main timeline", or a special thread with an ID of `main`.
|
||||
|
||||
The following is an example DAG for a room, with dotted lines showing event
|
||||
relationships and solid lines showing topological ordering.
|
||||
|
||||

|
||||
|
||||
{{% boxes/note %}}
|
||||
`m.reaction` relationships are not currently specified, but are shown here for
|
||||
their conceptual place in a threaded DAG. They are currently proposed as
|
||||
[MSC2677](https://github.com/matrix-org/matrix-spec-proposals/pull/2677).
|
||||
{{% /boxes/note %}}
|
||||
|
||||
This DAG can be represented as 3 threaded timelines, with `A` and `B` being thread
|
||||
roots:
|
||||
|
||||

|
||||
|
||||
With this, we can demonstrate that:
|
||||
* A threaded read receipt on `I` would mark `A`, `B`, and `I` as read.
|
||||
* A threaded read receipt on `E` would mark `C` and `E` as read.
|
||||
* An unthreaded read receipt on `D` would mark `A`, `B`, `C`, and `D` as read.
|
||||
|
||||
Note that marking `A` as read with a threaded read receipt would not mean
|
||||
that `C`, `E`, `G`, or `H` get marked as read: Thread A's timeline would need
|
||||
its own threaded read receipt at `H` to accomplish that.
|
||||
|
||||
The read receipts for the above 3 examples would be:
|
||||
|
||||
```json
|
||||
{
|
||||
"$I": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651,
|
||||
"thread_id": "main" // because `I` is not in a thread, but is a threaded receipt
|
||||
}
|
||||
}
|
||||
},
|
||||
"$E": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651,
|
||||
"thread_id": "$A" // because `E` is in Thread `A`
|
||||
}
|
||||
}
|
||||
},
|
||||
"$D": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651
|
||||
// no `thread_id` because the receipt is *unthreaded*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Conditions on sending read receipts apply similarly to threaded and unthreaded read
|
||||
receipts. For example, a client might send a private read receipt for a threaded
|
||||
event when the user expands that thread.
|
||||
|
||||
#### Server behaviour
|
||||
|
||||
For efficiency, receipts SHOULD be batched into one event per room
|
||||
|
|
@ -99,7 +223,7 @@ format of the EDUs are:
|
|||
{
|
||||
<room_id>: {
|
||||
<receipt_type>: {
|
||||
<user_id>: { <content> }
|
||||
<user_id>: { <content (ts & thread_id, currently)> }
|
||||
},
|
||||
...
|
||||
},
|
||||
|
|
|
|||
201
content/client-server-api/modules/threading.md
Normal file
201
content/client-server-api/modules/threading.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
type: module
|
||||
---
|
||||
|
||||
### Threading
|
||||
|
||||
{{% added-in v="1.4" %}}
|
||||
|
||||
Threads allow users to visually branch their conversations in a room. Typically mostly used
|
||||
when a room is discussing multiple topics, threads provide more organisation of communication
|
||||
that traditional [rich replies](#rich-replies) can't always offer.
|
||||
|
||||
Clients SHOULD render threads differently to regular messages or replies in the timeline, such
|
||||
as by providing some context to what is going on in the thread but keeping the full conversation
|
||||
history behind a disclosure.
|
||||
|
||||
Threads are established using a `rel_type` of `m.thread` and reference the *thread root* (the
|
||||
first event in a thread). It is not possible to create a thread from an event with a `rel_type`,
|
||||
which includes not being able to nest threads. All conversation in a thread reference the thread
|
||||
root instead of the most recent message, unlike rich reply chains.
|
||||
|
||||
As a worked example, the following represents a thread and how it'd be formed:
|
||||
|
||||
```json
|
||||
{
|
||||
// irrelevant fields excluded
|
||||
"type": "m.room.message",
|
||||
"event_id": "$alice_hello",
|
||||
"sender": "@alice:example.org",
|
||||
"content": {
|
||||
"msgtype": "m.text",
|
||||
"body": "Hello world! How are you?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
// irrelevant fields excluded
|
||||
"type": "m.room.message",
|
||||
"event_id": "$bob_hello",
|
||||
"sender": "@bob:example.org",
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$alice_hello"
|
||||
},
|
||||
"msgtype": "m.text",
|
||||
"body": "I'm doing okay, thank you! How about yourself?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
// irrelevant fields excluded
|
||||
"type": "m.room.message",
|
||||
"event_id": "$alice_reply",
|
||||
"sender": "@alice:example.org",
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$alice_hello" // note: always references the *thread root*
|
||||
},
|
||||
"msgtype": "m.text",
|
||||
"body": "I'm doing great! Thanks for asking."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As shown, any event without a `rel_type` can become a thread root by simply referencing it
|
||||
using an `m.thread` relationship.
|
||||
|
||||
#### Fallback for unthreaded clients
|
||||
|
||||
Clients which understand how to work with threads should simply do so, however clients which
|
||||
might not be aware of threads (due to age or scope) might not be able to helpfully represent
|
||||
the conversation history to its users.
|
||||
|
||||
To work around this, events sent by clients which understand threads include [rich reply](#rich-replies)
|
||||
metadata to attempt to form a reply chain representation of the conversation. This representation
|
||||
is not ideal for heavily threaded rooms, but allows for users to have context as to what is
|
||||
being discussed with respect to other messages in the room.
|
||||
|
||||
This representation is achieved by merging the two relationships and setting a new `is_falling_back`
|
||||
flag to `true`.
|
||||
|
||||
```json
|
||||
// within an event's content...
|
||||
"m.relates_to": {
|
||||
// The m.thread relationship structure
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$root",
|
||||
|
||||
// The rich reply structure
|
||||
"m.in_reply_to": {
|
||||
// The most recent message known to the client in the thread.
|
||||
// This should be something with a high chance of being rendered by the other client,
|
||||
// such as an `m.room.message` event.
|
||||
"event_id": "$target"
|
||||
},
|
||||
|
||||
// A flag to denote that this is a thread with reply fallback
|
||||
"is_falling_back": true
|
||||
}
|
||||
```
|
||||
|
||||
For `m.room.message` events represented this way, no [reply fallback](#fallbacks-for-rich-replies)
|
||||
is specified. This allows thread-aware clients to discard the `m.in_reply_to` object entirely
|
||||
when `is_falling_back` is `true`.
|
||||
|
||||
{{% boxes/note %}}
|
||||
Clients which are acutely aware of threads (they do not render threads, but are otherwise
|
||||
aware of the feature existing in the spec) can treat rich replies to an event with a `rel_type`
|
||||
of `m.thread` as a threaded reply, for conversation continuity on the threaded client's side.
|
||||
|
||||
To do this, copy the `event_id` (thread root) from the event being replied to, add the
|
||||
`m.in_reply_to` metadata, and add `is_falling_back: true` to `m.relates_to`.
|
||||
{{% /boxes/note %}}
|
||||
|
||||
#### Replies within threads
|
||||
|
||||
In the [fallback for unthreaded clients](#fallback-for-unthreaded-clients) section, a new
|
||||
`is_falling_back` flag is added to `m.relates_to`. This flag defaults to `false` when not
|
||||
provided, which also allows a threaded message to contain a reply itself.
|
||||
|
||||
Aside from `is_falling_back` being `false` (or not specified), the fallback for unthreaded
|
||||
clients is used to create a reply within a thread: clients should render the event accordingly.
|
||||
|
||||
#### Server behaviour
|
||||
|
||||
##### Validation of `m.thread` relationships
|
||||
|
||||
Servers SHOULD reject client requests which attempt to start a thread off an event with a
|
||||
`rel_type`. If the client attempts to target an event which already has an `m.thread`,
|
||||
`m.reference`, or any other `rel_type` then it should receive a HTTP 400 error response
|
||||
with appropriate error message, as per the [standard error response](#standard-error-response)
|
||||
structure.
|
||||
|
||||
{{% boxes/note %}}
|
||||
A specific error code is not currently available for this case: servers should use `M_UNKNOWN`
|
||||
alongside the HTTP 400 status code.
|
||||
{{% /boxes/note %}}
|
||||
|
||||
##### Server-side aggregation of `m.thread` relationships
|
||||
|
||||
Given threads always reference the thread root, an event can have multiple "child" events which
|
||||
then form the thread itself. These events should be [aggregated](#aggregations) by the server.
|
||||
|
||||
The aggregation for threads includes some information about the user's participation in the thread,
|
||||
the approximate number of events in the thread (as known to the server), and the most recent event
|
||||
in the thread (topologically). This is then bundled into the event as `m.thread`:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_id": "$root_event",
|
||||
// irrelevant fields not shown
|
||||
"unsigned": {
|
||||
"m.relations": {
|
||||
"m.thread": {
|
||||
"latest_event": {
|
||||
// A serialized copy of the latest event in the thread.
|
||||
// Some fields are not shown here for brevity.
|
||||
"event_id": "$message",
|
||||
"sender": "@alice:example.org",
|
||||
"room_id": "!room:example.org",
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"msgtype": "m.text",
|
||||
"body": "Woo! Threads!"
|
||||
}
|
||||
},
|
||||
"count": 7,
|
||||
"current_user_participated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`latest_event` is the most recent event (topologically to the server) in the thread sent by an
|
||||
un-[ignored user](#ignoring-users).
|
||||
|
||||
Note that any bundled aggregations on `latest_event` should also be present. The server should be
|
||||
careful to avoid loops, though loops are not currently possible due to `m.thread` not being possible
|
||||
to target an event with a `rel_type` already.
|
||||
|
||||
`count` is simply the number of events using `m.thread` as a `rel_type` pointing to the target event.
|
||||
It does not include events sent by [ignored users](#ignoring-users).
|
||||
|
||||
`current_user_participated` is `true` when the authenticated user is either:
|
||||
1. The `sender` of the event receiving the bundle (they sent the thread root).
|
||||
2. The `sender` of an event which references the thread root with a `rel_type` of `m.thread`.
|
||||
|
||||
#### Querying threads in a room
|
||||
|
||||
Clients looking to get all the events in a thread can use
|
||||
[`GET /relations/{threadRootId}/m.thread`](#get_matrixclientv1roomsroomidrelationseventidreltype),
|
||||
however getting all threads in a room is done through a dedicated API:
|
||||
|
||||
{{% http-api spec="client-server" api="threads_list" %}}
|
||||
|
|
@ -6,8 +6,9 @@ type: module
|
|||
|
||||
Users may wish to be informed when another user is typing in a room.
|
||||
This can be achieved using typing notifications. These are ephemeral
|
||||
events scoped to a `room_id`. This means they do not form part of the
|
||||
[Event Graph](index.html#event-graphs) but still have a `room_id` key.
|
||||
events, so they do not form part of the
|
||||
[Event Graph](index.html#event-graphs). Typing notifications are scoped
|
||||
to a room.
|
||||
|
||||
#### Events
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ the default power level for users in the room.
|
|||
The rules are as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Considering the event's `auth_events`:
|
||||
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||
|
|
@ -45,7 +45,8 @@ The rules are as follows:
|
|||
2. If sender's domain doesn't matches `state_key`, reject.
|
||||
3. Otherwise, allow.
|
||||
5. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. If `membership` is `join`:
|
||||
1. If the only previous event is an `m.room.create` and the
|
||||
`state_key` is the creator, allow.
|
||||
|
|
@ -56,11 +57,11 @@ The rules are as follows:
|
|||
5. If the `join_rule` is `public`, allow.
|
||||
6. Otherwise, reject.
|
||||
3. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has a `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -71,8 +72,8 @@ The rules are as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -110,29 +111,32 @@ The rules are as follows:
|
|||
9. If the event has a `state_key` that starts with an `@` and does not
|
||||
match the `sender`, reject.
|
||||
10. If type is `m.room.power_levels`:
|
||||
1. If `users` key in `content` is not a dictionary with keys that
|
||||
1. If the `users` property in `content` is not an object with keys that
|
||||
are valid user IDs with values that are integers (or a string
|
||||
that is an integer), reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
3. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
2. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events` and `users` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
4. For each entry being changed in, or removed from, the `events` property:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
5. For each entry being added to, or changed in, the `events` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
6. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
7. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
8. Otherwise, allow.
|
||||
11. If type is `m.room.redaction`:
|
||||
1. If the `sender`'s power level is greater than or equal to the
|
||||
*redact level*, allow.
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
toc_hide: true
|
||||
---
|
||||
|
||||
{{% added-in this=true %}} In room versions 1 and 2, events need a
|
||||
{{< added-in this=true >}} In room versions 1 and 2, events need a
|
||||
signature from the domain of the `event_id` in order to be considered
|
||||
valid. This room version does not include an `event_id` over federation
|
||||
in the same respect, so does not need a signature from that server.
|
||||
The event must still be signed by the server denoted by the `sender`,
|
||||
The event must still be signed by the server denoted by the `sender` property,
|
||||
however.
|
||||
|
||||
The types of state events that affect authorization are:
|
||||
|
|
@ -26,12 +26,12 @@ the default power level for users in the room.
|
|||
The complete list of rules, as of room version 3, is as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Considering the event's `auth_events`:
|
||||
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||
|
|
@ -52,7 +52,8 @@ The complete list of rules, as of room version 3, is as follows:
|
|||
2. If sender's domain doesn't matches `state_key`, reject.
|
||||
3. Otherwise, allow.
|
||||
5. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. If `membership` is `join`:
|
||||
1. If the only previous event is an `m.room.create` and the
|
||||
`state_key` is the creator, allow.
|
||||
|
|
@ -63,11 +64,11 @@ The complete list of rules, as of room version 3, is as follows:
|
|||
5. If the `join_rule` is `public`, allow.
|
||||
6. Otherwise, reject.
|
||||
3. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has a `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -78,8 +79,8 @@ The complete list of rules, as of room version 3, is as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -117,29 +118,32 @@ The complete list of rules, as of room version 3, is as follows:
|
|||
9. If the event has a `state_key` that starts with an `@` and does not
|
||||
match the `sender`, reject.
|
||||
10. If type is `m.room.power_levels`:
|
||||
1. If `users` key in `content` is not a dictionary with keys that
|
||||
1. If `users` property in `content` is not an object with keys that
|
||||
are valid user IDs with values that are integers (or a string
|
||||
that is an integer), reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
3. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
2. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events` and `users` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
4. For each entry being changed in, or removed from, the `events` property:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
5. For each entry being added to, or changed in, the `events` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
6. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
7. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
8. Otherwise, allow.
|
||||
11. Otherwise, allow.
|
||||
|
||||
{{% boxes/note %}}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
toc_hide: true
|
||||
---
|
||||
|
||||
Events must be signed by the server denoted by the `sender` key.
|
||||
Events must be signed by the server denoted by the `sender` property.
|
||||
|
||||
`m.room.redaction` events are not explicitly part of the auth rules.
|
||||
They are still subject to the minimum power level rules, but should always
|
||||
|
|
@ -27,12 +27,12 @@ the default power level for users in the room.
|
|||
The rules are as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Considering the event's `auth_events`:
|
||||
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||
|
|
@ -49,9 +49,10 @@ The rules are as follows:
|
|||
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||
does not match the `sender` domain of the create event, reject.
|
||||
4. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
2. If `content` has a `join_authorised_via_users_server`
|
||||
key:
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. {{< added-in this=true >}}
|
||||
If `content` has a `join_authorised_via_users_server` property:
|
||||
1. If the event is not validly signed by the homeserver of the user ID denoted
|
||||
by the key, reject.
|
||||
3. If `membership` is `join`:
|
||||
|
|
@ -61,7 +62,8 @@ The rules are as follows:
|
|||
3. If the `sender` is banned, reject.
|
||||
4. If the `join_rule` is `invite` or `knock` then allow if
|
||||
membership state is `invite` or `join`.
|
||||
5. If the `join_rule` is `restricted`:
|
||||
5. {{< added-in this=true >}}
|
||||
If the `join_rule` is `restricted`:
|
||||
1. If membership state is `join` or `invite`, allow.
|
||||
2. If the `join_authorised_via_users_server` key in `content`
|
||||
is not a user with sufficient permission to invite other
|
||||
|
|
@ -70,11 +72,11 @@ The rules are as follows:
|
|||
6. If the `join_rule` is `public`, allow.
|
||||
7. Otherwise, reject.
|
||||
4. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has a `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -85,8 +87,8 @@ The rules are as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -130,29 +132,34 @@ The rules are as follows:
|
|||
8. If the event has a `state_key` that starts with an `@` and does not
|
||||
match the `sender`, reject.
|
||||
9. If type is `m.room.power_levels`:
|
||||
1. If `users` key in `content` is not a dictionary with keys that
|
||||
1. If the `users` property in `content` is not an object with keys that
|
||||
are valid user IDs with values that are integers (or a string
|
||||
that is an integer), reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
3. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events`, `users`, and `notifications` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
4. For each entry being changed in, or removed from, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
5. For each entry being added to, or changed in the `events` or
|
||||
`notifications` properties:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
6. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
7. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
8. Otherwise, allow.
|
||||
10. Otherwise, allow.
|
||||
|
||||
{{% boxes/note %}}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ correctly structured are rejected under the authorization rules below.
|
|||
|
||||
### Authorization rules
|
||||
|
||||
Events must be signed by the server denoted by the `sender` key.
|
||||
Events must be signed by the server denoted by the `sender` property.
|
||||
|
||||
`m.room.redaction` events are not explicitly part of the auth rules.
|
||||
They are still subject to the minimum power level rules, but should always
|
||||
|
|
@ -99,12 +99,12 @@ the default power level for users in the room.
|
|||
The rules are as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Considering the event's `auth_events`:
|
||||
1. If there are duplicate entries for a given `type` and `state_key` pair,
|
||||
|
|
@ -121,7 +121,8 @@ The rules are as follows:
|
|||
property `m.federate` set to `false`, and the `sender` domain of the event
|
||||
does not match the `sender` domain of the create event, reject.
|
||||
4. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. If `content` has a `join_authorised_via_users_server`
|
||||
key:
|
||||
1. If the event is not validly signed by the homeserver of the user ID denoted
|
||||
|
|
@ -143,11 +144,11 @@ The rules are as follows:
|
|||
6. If the `join_rule` is `public`, allow.
|
||||
7. Otherwise, reject.
|
||||
4. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has a `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -158,8 +159,8 @@ The rules are as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -206,35 +207,40 @@ The rules are as follows:
|
|||
match the `sender`, reject.
|
||||
9. If type is `m.room.power_levels`:
|
||||
1. {{< added-in this="true" >}}
|
||||
If any of the keys `users_default`, `events_default`, `state_default`,
|
||||
If any of the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, or `invite` in `content` are present and
|
||||
not an integer, reject.
|
||||
2. {{< added-in this="true" >}}
|
||||
If either of the keys `events` or `notifications` in `content`
|
||||
are present and not a dictionary with values that are integers,
|
||||
If either of the properties `events` or `notifications` in `content`
|
||||
are present and not an object with values that are integers,
|
||||
reject.
|
||||
3. If `users` key in `content` is not a dictionary with keys that
|
||||
3. If the `users` property in `content` is not an obiect with keys that
|
||||
are valid user IDs with values that are integers, reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
4. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
5. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events`, `users`, and `notifications` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
6. For each entry being changed in, or removed from, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
7. For each entry being added to, or changed in, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
8. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
9. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
10. Otherwise, allow.
|
||||
10. Otherwise, allow.
|
||||
|
||||
{{% boxes/note %}}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ The complete structure of a event in a v3 room is shown below.
|
|||
|
||||
### Authorization rules
|
||||
|
||||
{{% added-in this=true %}} `m.room.redaction` events are no longer
|
||||
{{< added-in this=true >}} `m.room.redaction` events are no longer
|
||||
explicitly part of the auth rules. They are still subject to the
|
||||
minimum power level rules, but should always fall into "11. Otherwise,
|
||||
allow". Instead of being authorized at the time of receipt, they are
|
||||
|
|
@ -97,7 +97,7 @@ authorized at a later stage: see the [Handling Redactions](#handling-redactions)
|
|||
section below for more information.
|
||||
|
||||
<!-- set withVersioning=true so we get all the "new in this version" stuff -->
|
||||
{{% rver-fragment name="v3-auth-rules" withVersioning=true %}}
|
||||
{{< rver-fragment name="v3-auth-rules" withVersioning=true >}}
|
||||
|
||||
## Unchanged from v2
|
||||
|
||||
|
|
|
|||
|
|
@ -46,16 +46,16 @@ fall into "10. Otherwise, allow". Instead of being authorized at the time
|
|||
of receipt, they are authorized at a later stage: see the
|
||||
[Handling Redactions](#handling-redactions) section below for more information.
|
||||
|
||||
{{% added-in this=true %}} Rule 4, which related specifically to events
|
||||
{{< added-in this=true >}} Rule 4, which related specifically to events
|
||||
of type `m.room.aliases`, is removed. `m.room.aliases` events must still pass
|
||||
authorization checks relating to state events.
|
||||
|
||||
{{% added-in this=true %}} Additionally, the authorization rules for events
|
||||
of type `m.room.power_levels` now include the content key `notifications`.
|
||||
This new rule takes the place of rule 10.4, which checked the `events` and
|
||||
`users` keys.
|
||||
{{< added-in this=true >}} Additionally, the authorization rules for events of
|
||||
type `m.room.power_levels` now include a `notifications` property under
|
||||
`content`. This updates rules 10.4 and 10.5 (now 9.4 and 9.5), which checked
|
||||
the `events` property.
|
||||
|
||||
Events must be signed by the server denoted by the `sender` key.
|
||||
Events must be signed by the server denoted by the `sender` property.
|
||||
|
||||
The types of state events that affect authorization are:
|
||||
|
||||
|
|
@ -74,12 +74,12 @@ the default power level for users in the room.
|
|||
The rules are as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Reject if event has `auth_events` that:
|
||||
1. have duplicate entries for a given `type` and `state_key` pair
|
||||
|
|
@ -90,7 +90,8 @@ The rules are as follows:
|
|||
3. If event does not have a `m.room.create` in its `auth_events`,
|
||||
reject.
|
||||
4. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. If `membership` is `join`:
|
||||
1. If the only previous event is an `m.room.create` and the
|
||||
`state_key` is the creator, allow.
|
||||
|
|
@ -101,11 +102,11 @@ The rules are as follows:
|
|||
5. If the `join_rule` is `public`, allow.
|
||||
6. Otherwise, reject.
|
||||
3. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has a `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -116,8 +117,8 @@ The rules are as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -155,29 +156,36 @@ The rules are as follows:
|
|||
8. If the event has a `state_key` that starts with an `@` and does not
|
||||
match the `sender`, reject.
|
||||
9. If type is `m.room.power_levels`:
|
||||
1. If `users` key in `content` is not a dictionary with keys that
|
||||
1. If the `users` property in `content` is not an object with keys that
|
||||
are valid user IDs with values that are integers (or a string
|
||||
that is an integer), reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
3. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events`, `users`, and `notifications` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
4. {{< changed-in this="true" >}}
|
||||
For each entry being changed in, or removed from, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
5. {{< changed-in this="true" >}}
|
||||
For each entry being added to, or changed in, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
6. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
7. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
8. Otherwise, allow.
|
||||
10. Otherwise, allow.
|
||||
|
||||
{{% boxes/note %}}
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ as do the versions v6 is based upon.
|
|||
|
||||
### Authorization rules
|
||||
|
||||
{{% added-in this=true %}} For checks performed upon `m.room.member` events, a
|
||||
{{< added-in this=true >}} For checks performed upon `m.room.member` events, a
|
||||
new point for `membership=knock` is added.
|
||||
|
||||
Events must be signed by the server denoted by the `sender` key.
|
||||
Events must be signed by the server denoted by the `sender` property.
|
||||
|
||||
`m.room.redaction` events are not explicitly part of the auth rules.
|
||||
They are still subject to the minimum power level rules, but should always
|
||||
|
|
@ -60,12 +60,12 @@ the default power level for users in the room.
|
|||
The rules are as follows:
|
||||
|
||||
1. If type is `m.room.create`:
|
||||
1. If it has any previous events, reject.
|
||||
1. If it has any `prev_events`, reject.
|
||||
2. If the domain of the `room_id` does not match the domain of the
|
||||
`sender`, reject.
|
||||
3. If `content.room_version` is present and is not a recognised
|
||||
version, reject.
|
||||
4. If `content` has no `creator` field, reject.
|
||||
4. If `content` has no `creator` property, reject.
|
||||
5. Otherwise, allow.
|
||||
2. Reject if event has `auth_events` that:
|
||||
1. have duplicate entries for a given `type` and `state_key` pair
|
||||
|
|
@ -76,22 +76,24 @@ The rules are as follows:
|
|||
3. If event does not have a `m.room.create` in its `auth_events`,
|
||||
reject.
|
||||
4. If type is `m.room.member`:
|
||||
1. If no `state_key` key or `membership` key in `content`, reject.
|
||||
1. If there is no `state_key` property, or no `membership` property in
|
||||
`content`, reject.
|
||||
2. If `membership` is `join`:
|
||||
1. If the only previous event is an `m.room.create` and the
|
||||
`state_key` is the creator, allow.
|
||||
2. If the `sender` does not match `state_key`, reject.
|
||||
3. If the `sender` is banned, reject.
|
||||
4. If the `join_rule` is `invite` or `knock` then allow if
|
||||
4. {{< changed-in this=true >}}
|
||||
If the `join_rule` is `invite` or `knock` then allow if
|
||||
membership state is `invite` or `join`.
|
||||
5. If the `join_rule` is `public`, allow.
|
||||
6. Otherwise, reject.
|
||||
3. If `membership` is `invite`:
|
||||
1. If `content` has `third_party_invite` key:
|
||||
1. If `content` has `third_party_invite` property:
|
||||
1. If *target user* is banned, reject.
|
||||
2. If `content.third_party_invite` does not have a `signed`
|
||||
key, reject.
|
||||
3. If `signed` does not have `mxid` and `token` keys,
|
||||
property, reject.
|
||||
3. If `signed` does not have `mxid` and `token` properties,
|
||||
reject.
|
||||
4. If `mxid` does not match `state_key`, reject.
|
||||
5. If there is no `m.room.third_party_invite` event in the
|
||||
|
|
@ -102,8 +104,8 @@ The rules are as follows:
|
|||
7. If any signature in `signed` matches any public key in
|
||||
the `m.room.third_party_invite` event, allow. The public
|
||||
keys are in `content` of `m.room.third_party_invite` as:
|
||||
1. A single public key in the `public_key` field.
|
||||
2. A list of public keys in the `public_keys` field.
|
||||
1. A single public key in the `public_key` property.
|
||||
2. A list of public keys in the `public_keys` property.
|
||||
8. Otherwise, reject.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
reject.
|
||||
|
|
@ -113,7 +115,8 @@ The rules are as follows:
|
|||
the *invite level*, allow.
|
||||
5. Otherwise, reject.
|
||||
4. If `membership` is `leave`:
|
||||
1. If the `sender` matches `state_key`, allow if and only if
|
||||
1. {{< changed-in this=true >}}
|
||||
If the `sender` matches `state_key`, allow if and only if
|
||||
that user's current membership state is `invite`, `join`,
|
||||
or `knock`.
|
||||
2. If the `sender`'s current membership state is not `join`,
|
||||
|
|
@ -132,7 +135,8 @@ The rules are as follows:
|
|||
the *ban level*, and the *target user*'s power level is less
|
||||
than the `sender`'s power level, allow.
|
||||
3. Otherwise, reject.
|
||||
6. If `membership` is `knock`:
|
||||
6. {{< added-in this=true >}}
|
||||
If `membership` is `knock`:
|
||||
1. If the `join_rule` is anything other than `knock`, reject.
|
||||
2. If `sender` does not match `state_key`, reject.
|
||||
3. If the `sender`'s current membership is not `ban` or `join`, allow.
|
||||
|
|
@ -147,29 +151,34 @@ The rules are as follows:
|
|||
8. If the event has a `state_key` that starts with an `@` and does not
|
||||
match the `sender`, reject.
|
||||
9. If type is `m.room.power_levels`:
|
||||
1. If `users` key in `content` is not a dictionary with keys that
|
||||
1. If the `users` property in `content` is not an object with keys that
|
||||
are valid user IDs with values that are integers (or a string
|
||||
that is an integer), reject.
|
||||
2. If there is no previous `m.room.power_levels` event in the room,
|
||||
allow.
|
||||
3. For the keys `users_default`, `events_default`, `state_default`,
|
||||
3. For the properties `users_default`, `events_default`, `state_default`,
|
||||
`ban`, `redact`, `kick`, `invite` check if they were added,
|
||||
changed or removed. For each found alteration:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
level, reject.
|
||||
4. For each entry being added, changed or removed in both the
|
||||
`events`, `users`, and `notifications` keys:
|
||||
1. If the current value is higher than the `sender`'s current
|
||||
4. For each entry being changed in, or removed from, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the current value is greater than the `sender`'s current
|
||||
power level, reject.
|
||||
2. If the new value is higher than the `sender`'s current power
|
||||
5. For each entry being added to, or changed in, the `events` or
|
||||
`notifications` properties:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
5. For each entry being changed under the `users` key, other than
|
||||
the `sender`'s own entry:
|
||||
1. If the current value is equal to the `sender`'s current
|
||||
power level, reject.
|
||||
6. Otherwise, allow.
|
||||
6. For each entry being changed in, or removed from, the `users` property,
|
||||
other than the `sender`'s own entry:
|
||||
1. If the current value is greater than or equal to the `sender`'s
|
||||
current power level, reject.
|
||||
7. For each entry being added to, or changed in, the `users` property:
|
||||
1. If the new value is greater than the `sender`'s current power
|
||||
level, reject.
|
||||
8. Otherwise, allow..
|
||||
10. Otherwise, allow.
|
||||
|
||||
{{% boxes/note %}}
|
||||
|
|
|
|||
|
|
@ -83,11 +83,11 @@ room without invite. Otherwise, the room version inherits all properties of
|
|||
|
||||
### Authorization rules
|
||||
|
||||
{{% added-in this=true %}} For checks performed upon `m.room.member` events, new
|
||||
{{< added-in this=true >}} For checks performed upon `m.room.member` events, new
|
||||
points for handling `content.join_authorised_via_users_server` are added (Rule 4.2
|
||||
and 4.3.5).
|
||||
|
||||
{{% rver-fragment name="v8-auth-rules" %}}
|
||||
{{< rver-fragment name="v8-auth-rules" withVersioning=true >}}
|
||||
|
||||
### Redactions
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ completeness.
|
|||
|
||||
### Authorization rules
|
||||
|
||||
{{% rver-fragment name="v8-auth-rules" %}}
|
||||
{{< rver-fragment name="v8-auth-rules" >}}
|
||||
|
||||
### State resolution
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ properties:
|
|||
|
||||
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
|
||||
all relationships require such behaviour. For example, an [`m.thread` relationship type](/client-server-api/#threading)
|
||||
denotes that the event is part of a "thread" of messages and should be rendered as
|
||||
such.
|
||||
event_id:
|
||||
type: string
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright 2016 OpenMarket Ltd
|
||||
# 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.
|
||||
|
|
@ -16,6 +17,12 @@ allOf:
|
|||
- type: object
|
||||
title: RoomEventFilter
|
||||
properties:
|
||||
unread_thread_notifications:
|
||||
type: boolean
|
||||
description: |-
|
||||
If `true`, enables per-[thread](/client-server-api/#threading) notification
|
||||
counts. Only applies to the `/sync` endpoint. Defaults to `false`.
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
lazy_load_members:
|
||||
type: boolean
|
||||
description: |-
|
||||
|
|
|
|||
|
|
@ -74,8 +74,18 @@ paths:
|
|||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
thread_id:
|
||||
type: string
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
The root thread event's ID (or `main`) for which
|
||||
thread this receipt is intended to be under. If
|
||||
not specified, the read receipt is *unthreaded*
|
||||
(default).
|
||||
example: {
|
||||
}
|
||||
"thread_id": "main"
|
||||
}
|
||||
responses:
|
||||
200:
|
||||
description: The receipt was sent.
|
||||
|
|
@ -88,5 +98,19 @@ paths:
|
|||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/errors/rate_limited.yaml"
|
||||
400:
|
||||
description: |-
|
||||
The `thread_id` is invalid in some way. For example:
|
||||
* It is not a string.
|
||||
* It is empty.
|
||||
* It is provided for an incompatible receipt type.
|
||||
* The `event_id` is not related to the `thread_id`.
|
||||
schema:
|
||||
$ref: "definitions/errors/error.yaml"
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_INVALID_PARAM",
|
||||
"error": "thread_id field must be a non-empty string"
|
||||
}
|
||||
tags:
|
||||
- Room participation
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ paths:
|
|||
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
|
||||
Can be a `next_batch` or `prev_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
|
||||
|
|
@ -89,6 +89,16 @@ paths:
|
|||
Similarly, the server should apply a default value when not supplied.
|
||||
required: false
|
||||
x-example: 20
|
||||
- in: query
|
||||
type: string
|
||||
enum: ["b", "f"]
|
||||
name: dir
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
Optional (default `b`) direction to return events from. If this is set to `f`, events
|
||||
will be returned in chronological order starting at `from`. If it
|
||||
is set to `b`, events will be returned in *reverse* chronological
|
||||
order, again starting at `from`.
|
||||
responses:
|
||||
# note: this endpoint deliberately does not support rate limiting, therefore a
|
||||
# 429 error response is not included.
|
||||
|
|
@ -193,7 +203,7 @@ paths:
|
|||
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
|
||||
Can be a `next_batch` or `prev_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
|
||||
|
|
@ -219,6 +229,16 @@ paths:
|
|||
Similarly, the server should apply a default value when not supplied.
|
||||
required: false
|
||||
x-example: 20
|
||||
- in: query
|
||||
type: string
|
||||
enum: ["b", "f"]
|
||||
name: dir
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
Optional (default `b`) direction to return events from. If this is set to `f`, events
|
||||
will be returned in chronological order starting at `from`. If it
|
||||
is set to `b`, events will be returned in *reverse* chronological
|
||||
order, again starting at `from`.
|
||||
responses:
|
||||
# note: this endpoint deliberately does not support rate limiting, therefore a
|
||||
# 429 error response is not included.
|
||||
|
|
@ -335,7 +355,7 @@ paths:
|
|||
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
|
||||
Can be a `next_batch` or `prev_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
|
||||
|
|
@ -361,6 +381,16 @@ paths:
|
|||
Similarly, the server should apply a default value when not supplied.
|
||||
required: false
|
||||
x-example: 20
|
||||
- in: query
|
||||
type: string
|
||||
enum: ["b", "f"]
|
||||
name: dir
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
Optional (default `b`) direction to return events from. If this is set to `f`, events
|
||||
will be returned in chronological order starting at `from`. If it
|
||||
is set to `b`, events will be returned in *reverse* chronological
|
||||
order, again starting at `from`.
|
||||
responses:
|
||||
# note: this endpoint deliberately does not support rate limiting, therefore a
|
||||
# 429 error response is not included.
|
||||
|
|
|
|||
|
|
@ -239,17 +239,50 @@ paths:
|
|||
Counts of unread notifications for this room. See the
|
||||
[Receiving notifications](/client-server-api/#receiving-notifications) section
|
||||
for more information on how these are calculated.
|
||||
|
||||
If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`,
|
||||
these counts will only be for the main timeline rather than all events in the room.
|
||||
See the [threading module](#threading) for more information.
|
||||
x-changedInMatrixVersion:
|
||||
1.4: |
|
||||
Updated to reflect behaviour of having `unread_thread_notifications` as `true` in
|
||||
the `RoomEventFilter` for `/sync`.
|
||||
properties:
|
||||
highlight_count:
|
||||
title: Highlighted notification count
|
||||
type: integer
|
||||
description: The number of unread notifications
|
||||
for this room with the highlight flag set
|
||||
for this room with the highlight flag set.
|
||||
notification_count:
|
||||
title: Total notification count
|
||||
type: integer
|
||||
description: The total number of unread notifications
|
||||
for this room
|
||||
for this room.
|
||||
unread_thread_notifications:
|
||||
title: Unread Thread Notification Counts
|
||||
type: object
|
||||
description: |-
|
||||
If `unread_thread_notifications` was specified as `true` on the `RoomEventFilter`,
|
||||
the notification counts for each [thread](#threading) in this room. The object is
|
||||
keyed by thread root ID, with values matching `unread_notifications`.
|
||||
|
||||
If a thread does not have any notifications it can be omitted from this object. If
|
||||
no threads have notification counts, this whole object can be omitted.
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
additionalProperties:
|
||||
title: ThreadNotificationCounts
|
||||
type: object
|
||||
properties:
|
||||
highlight_count:
|
||||
title: ThreadedHighlightNotificationCount
|
||||
type: integer
|
||||
description: |-
|
||||
The number of unread notifications for this *thread* with the highlight flag set.
|
||||
notification_count:
|
||||
title: ThreadedTotalNotificationCount
|
||||
type: integer
|
||||
description: |-
|
||||
The total number of unread notifications for this *thread*.
|
||||
invite:
|
||||
title: Invited Rooms
|
||||
type: object
|
||||
|
|
@ -424,6 +457,16 @@ paths:
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unread_notifications": {
|
||||
"highlight_count": 1,
|
||||
"notification_count": 5
|
||||
},
|
||||
"unread_thread_notifications": {
|
||||
"$threadroot": {
|
||||
"highlight_count": 3,
|
||||
"notification_count": 6
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
135
data/api/client-server/threads_list.yaml
Normal file
135
data/api/client-server/threads_list.yaml
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# 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 Threads List 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}/threads":
|
||||
get:
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
summary: Retrieve a list of threads in a room, with optional filters.
|
||||
description: |-
|
||||
Paginates over the thread roots in a room, ordered by the `latest_event` of each thread root
|
||||
in its bundle.
|
||||
operationId: getThreadRoots
|
||||
security:
|
||||
- accessToken: []
|
||||
parameters:
|
||||
- in: path
|
||||
type: string
|
||||
name: roomId
|
||||
description: The room ID where the thread roots are located.
|
||||
required: true
|
||||
x-example: "!room:example.org"
|
||||
- in: query
|
||||
type: string
|
||||
name: include
|
||||
enum: [all, participated]
|
||||
description: |-
|
||||
Optional (default `all`) flag to denote which thread roots are of interest to the caller.
|
||||
When `all`, all thread roots found in the room are returned. When `participated`, only
|
||||
thread roots for threads the user has [participated in](/client-server-api/#server-side-aggreagtion-of-mthread-relationships)
|
||||
will be returned.
|
||||
x-example: "all"
|
||||
- in: query
|
||||
type: integer
|
||||
name: limit
|
||||
description: |-
|
||||
Optional limit for the maximum number of thread roots to include per response. Must be an integer
|
||||
greater than zero.
|
||||
|
||||
Servers should apply a default value, and impose a maximum value to avoid resource exhaustion.
|
||||
x-example: 20
|
||||
- in: query
|
||||
type: string
|
||||
name: from
|
||||
description: |-
|
||||
A pagination token from a previous result. When not provided, the server starts paginating from
|
||||
the most recent event visible to the user (as per history visibility rules; topologically).
|
||||
x-example: "next_batch_token"
|
||||
responses:
|
||||
200:
|
||||
description: |-
|
||||
A portion of the available thread roots in the room, based on the filter criteria.
|
||||
examples:
|
||||
application/json: {
|
||||
"chunk": [{ "$ref": "../../event-schemas/examples/m.room.message$m.text.yaml" }],
|
||||
"next_batch": "next_batch_token"
|
||||
}
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
chunk:
|
||||
type: array
|
||||
description: |-
|
||||
The thread roots, ordered by the `latest_event` in each event's aggregation bundle. All events
|
||||
returned include bundled [aggregations](/client-server-api/#aggregations).
|
||||
|
||||
If the thread root event was sent by an [ignored user](/client-server-api/#ignoring-users), the
|
||||
event is returned redacted to the caller. This is to simulate the same behaviour of a client doing
|
||||
aggregation locally on the thread.
|
||||
items:
|
||||
$ref: "definitions/client_event.yaml"
|
||||
next_batch:
|
||||
type: string
|
||||
description: |-
|
||||
A token to supply to `from` to keep paginating the responses. Not present when there are
|
||||
no further results.
|
||||
required: [chunk]
|
||||
403:
|
||||
description: |-
|
||||
The user cannot view or peek on the room. A meaningful `errcode`
|
||||
and description error text will be returned. Example reasons for rejection are:
|
||||
|
||||
- The room is not set up for peeking.
|
||||
- The user has been banned from the room.
|
||||
- The room does not exist.
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": "You are not allowed to view this room."
|
||||
}
|
||||
schema:
|
||||
"$ref": "definitions/errors/error.yaml"
|
||||
400:
|
||||
description: |-
|
||||
The request was invalid in some way. A meaningful `errcode`
|
||||
and description error text will be returned. Example reasons for rejection are:
|
||||
|
||||
- The `from` token is unknown to the server.
|
||||
examples:
|
||||
application/json: {
|
||||
"errcode": "M_INVALID_PARAM",
|
||||
"error": "Unknown pagination token"
|
||||
}
|
||||
schema:
|
||||
"$ref": "definitions/errors/error.yaml"
|
||||
429:
|
||||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/errors/rate_limited.yaml"
|
||||
tags:
|
||||
- Threads
|
||||
|
|
@ -65,6 +65,15 @@ allOf:
|
|||
A POSIX timestamp in milliseconds for when the user read
|
||||
the event specified in the read receipt.
|
||||
example: 1533358089009
|
||||
thread_id:
|
||||
type: string
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
The root thread event's ID (or `main`) for which
|
||||
thread this receipt is intended to be under. If
|
||||
not specified, the read receipt is *unthreaded*
|
||||
(default).
|
||||
example: "$threadroot"
|
||||
required: ['ts']
|
||||
required: ['event_ids', 'data']
|
||||
required: ['m.read']
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ paths:
|
|||
items:
|
||||
$ref: "../../event-schemas/schema/core-event-schema/stripped_state.yaml"
|
||||
description: |-
|
||||
An optional list of [stripped state events](/client-server-api/#stripped-state)
|
||||
A list of [stripped state events](/client-server-api/#stripped-state)
|
||||
to help the initiator of the knock identify the room.
|
||||
example:
|
||||
$ref: "../../event-schemas/examples/knock_room_state.json"
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ properties:
|
|||
type: integer
|
||||
format: int64
|
||||
description: The timestamp the receipt was sent at.
|
||||
thread_id:
|
||||
type: string
|
||||
x-addedInMatrixVersion: "1.4"
|
||||
description: |-
|
||||
The root thread event's ID (or `main`) for which
|
||||
thread this receipt is intended to be under. If
|
||||
not specified, the read receipt is *unthreaded*
|
||||
(default).
|
||||
"m.read.private":
|
||||
type: object
|
||||
title: Own User
|
||||
|
|
|
|||
141
layouts/partials/changelogs/v1.4.md
Normal file
141
layouts/partials/changelogs/v1.4.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<!--
|
||||
This is a header file for the generated changelog.
|
||||
|
||||
Variables:
|
||||
v1.4 = Replaced by the version number (eg: v1.2)
|
||||
September 29, 2022 = Replaced by the date (eg: April 01, 2021)
|
||||
-->
|
||||
|
||||
## v1.4
|
||||
|
||||
<table class="release-info">
|
||||
<tr><th>Git commit</th><td><a href="https://github.com/matrix-org/matrix-spec/tree/v1.4">https://github.com/matrix-org/matrix-spec/tree/v1.4</a></td>
|
||||
<tr><th>Release date</th><td>September 29, 2022</td>
|
||||
</table>
|
||||
|
||||
<!-- Intentionally blank line to ensure headers work in the concatenated changelog -->
|
||||
### Client-Server API
|
||||
|
||||
|
||||
<strong>Removed Endpoints</strong>
|
||||
|
||||
|
||||
- Remove unused policy room sharing mechanism, as per [MSC3844](https://github.com/matrix-org/matrix-spec-proposals/pull/3844). ([#1196](https://github.com/matrix-org/matrix-spec/issues/1196))
|
||||
|
||||
|
||||
<strong>Backwards Compatible Changes</strong>
|
||||
|
||||
|
||||
- Add a `.m.rule.room.server_acl` push rule to match `m.room.server_acl` events, as per [MSC3786](https://github.com/matrix-org/matrix-spec-proposals/pull/3786). ([#1190](https://github.com/matrix-org/matrix-spec/issues/1190), [#1201](https://github.com/matrix-org/matrix-spec/issues/1201))
|
||||
- Add `Cross-Origin-Resource-Policy` (CORP) headers to media repository, as per [MSC3828](https://github.com/matrix-org/matrix-spec-proposals/pull/3828). ([#1197](https://github.com/matrix-org/matrix-spec/issues/1197))
|
||||
- Copy a room's `type` when upgrading it, as per [MSC3818](https://github.com/matrix-org/matrix-spec-proposals/pull/3818). ([#1198](https://github.com/matrix-org/matrix-spec/issues/1198))
|
||||
- Add `room_types` filter and `room_type` response to `/publicRooms`, as per [MSC3827](https://github.com/matrix-org/matrix-spec-proposals/pull/3827). ([#1199](https://github.com/matrix-org/matrix-spec/issues/1199))
|
||||
- Add `m.replace` relations (event edits), as per [MSC2676](https://github.com/matrix-org/matrix-spec-proposals/pull/2676). ([#1211](https://github.com/matrix-org/matrix-spec/issues/1211))
|
||||
- Add `m.read.private` receipts, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285). ([#1216](https://github.com/matrix-org/matrix-spec/issues/1216))
|
||||
- Make `m.fully_read` optional on `/read_markers`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285). ([#1216](https://github.com/matrix-org/matrix-spec/issues/1216))
|
||||
- Allow `m.fully_read` markers to be set from `/receipts`, as per [MSC2285](https://github.com/matrix-org/matrix-spec-proposals/pull/2285). ([#1216](https://github.com/matrix-org/matrix-spec/issues/1216))
|
||||
- Add threading via `m.thread` relations, as per [MSC3440](https://github.com/matrix-org/matrix-spec-proposals/pull/3440), [MSC3816](https://github.com/matrix-org/matrix-spec-proposals/pull/3816), [MSC3856](https://github.com/matrix-org/matrix-spec-proposals/pull/3856), and [MSC3715](https://github.com/matrix-org/matrix-spec-proposals/pull/3715). ([#1254](https://github.com/matrix-org/matrix-spec/issues/1254))
|
||||
- Add per-thread notifications and read receipts, as per [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771) and [MSC3773](https://github.com/matrix-org/matrix-spec-proposals/pull/3773). ([#1255](https://github.com/matrix-org/matrix-spec/issues/1255))
|
||||
- Add `thread_id` to the `/receipt` endpoint, as per [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771). ([#1261](https://github.com/matrix-org/matrix-spec/issues/1261))
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Mention that the `/rooms/{roomId}/invite` endpoint will return a 200 response if the user is already invited to the room. ([#1084](https://github.com/matrix-org/matrix-spec/issues/1084))
|
||||
- Fix various typos throughout the specification. ([#1135](https://github.com/matrix-org/matrix-spec/issues/1135), [#1161](https://github.com/matrix-org/matrix-spec/issues/1161), [#1164](https://github.com/matrix-org/matrix-spec/issues/1164), [#1170](https://github.com/matrix-org/matrix-spec/issues/1170), [#1180](https://github.com/matrix-org/matrix-spec/issues/1180), [#1215](https://github.com/matrix-org/matrix-spec/issues/1215), [#1238](https://github.com/matrix-org/matrix-spec/issues/1238), [#1243](https://github.com/matrix-org/matrix-spec/issues/1243), [#1263](https://github.com/matrix-org/matrix-spec/issues/1263))
|
||||
- Describe return codes for account data endpoints, and clarify that per-room data does not inherit from the global data. ([#1155](https://github.com/matrix-org/matrix-spec/issues/1155))
|
||||
- Clarify that policy rule globs work like ACL globs. Contributed by Nico. ([#1165](https://github.com/matrix-org/matrix-spec/issues/1165))
|
||||
- Clarify the format of some structures in the End-to-end encryption module. ([#1166](https://github.com/matrix-org/matrix-spec/issues/1166))
|
||||
- Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174))
|
||||
- Tweak the styling of `<code>` snippets in tables rendered from OpenAPI definitions. ([#1179](https://github.com/matrix-org/matrix-spec/issues/1179))
|
||||
- Update "API Standards" section to clarify how JSON is used. ([#1185](https://github.com/matrix-org/matrix-spec/issues/1185))
|
||||
- Clarify that the "device_id", "user_id" and "access_token" fields are required in the response body of `POST /_matrix/client/v3/login`. ([#1210](https://github.com/matrix-org/matrix-spec/issues/1210))
|
||||
- Reinforce the relationship of refreshed access tokens to transaction IDs. ([#1236](https://github.com/matrix-org/matrix-spec/issues/1236))
|
||||
- Clarify enum values by separating possible values with commas. ([#1240](https://github.com/matrix-org/matrix-spec/issues/1240))
|
||||
|
||||
|
||||
### Server-Server API
|
||||
|
||||
|
||||
<strong>Backwards Compatible Changes</strong>
|
||||
|
||||
|
||||
- Add per-thread notifications and read receipts, as per [MSC3771](https://github.com/matrix-org/matrix-spec-proposals/pull/3771) and [MSC3773](https://github.com/matrix-org/matrix-spec-proposals/pull/3773). ([#1255](https://github.com/matrix-org/matrix-spec/issues/1255))
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174))
|
||||
- Tweak the styling of `<code>` snippets in tables rendered from OpenAPI definitions. ([#1179](https://github.com/matrix-org/matrix-spec/issues/1179))
|
||||
- Update "API Standards" section to clarify how JSON is used. ([#1185](https://github.com/matrix-org/matrix-spec/issues/1185))
|
||||
|
||||
|
||||
### Application Service API
|
||||
|
||||
|
||||
<strong>Breaking Changes</strong>
|
||||
|
||||
|
||||
- Replace homeserver authorization approach with an `Authorization` header instead of `access_token` when talking to the application service, as per [MSC2832](https://github.com/matrix-org/matrix-spec-proposals/pull/2832). ([#1200](https://github.com/matrix-org/matrix-spec/issues/1200))
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174))
|
||||
|
||||
|
||||
### Identity Service API
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174))
|
||||
- Update "API Standards" section to clarify how JSON is used. ([#1185](https://github.com/matrix-org/matrix-spec/issues/1185))
|
||||
|
||||
|
||||
### Push Gateway API
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Add HTML anchors for object definitions in the formatted specification. ([#1174](https://github.com/matrix-org/matrix-spec/issues/1174))
|
||||
|
||||
|
||||
### Room Versions
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- For room versions 1 through 10, clarify that events with rejected `auth_events` must be rejected. ([#1137](https://github.com/matrix-org/matrix-spec/issues/1137))
|
||||
- For room versions 2–10: correct a mistaken clarification to the state resolution algorithm. ([#1158](https://github.com/matrix-org/matrix-spec/issues/1158))
|
||||
- For room versions 7 through 10: Clarify that `invite->knock` is actually a legal transition. ([#1175](https://github.com/matrix-org/matrix-spec/issues/1175))
|
||||
|
||||
|
||||
### Appendices
|
||||
|
||||
|
||||
No significant changes.
|
||||
|
||||
|
||||
### Internal Changes/Tooling
|
||||
|
||||
|
||||
<strong>Backwards Compatible Changes</strong>
|
||||
|
||||
|
||||
- Add internal changes changelog section. ([#1194](https://github.com/matrix-org/matrix-spec/issues/1194))
|
||||
|
||||
|
||||
<strong>Spec Clarifications</strong>
|
||||
|
||||
|
||||
- Render HTML anchors for object definition tables. ([#1191](https://github.com/matrix-org/matrix-spec/issues/1191))
|
||||
- Give rendered-data sections a background and some padding. ([#1195](https://github.com/matrix-org/matrix-spec/issues/1195))
|
||||
- Fix rendering of shortcodes within the client-server API. ([#1205](https://github.com/matrix-org/matrix-spec/issues/1205))
|
||||
- Fix the spacing of mapping types generated from the OpenAPI spec. ([#1230](https://github.com/matrix-org/matrix-spec/issues/1230))
|
||||
|
|
@ -21,5 +21,6 @@
|
|||
{{ $content := $page.Content }}
|
||||
{{ if not $withVersioning }}
|
||||
{{ $content = (replace $content "[New in this version]" "") }}
|
||||
{{ $content = (replace $content "[Changed in this version]" "") }}
|
||||
{{ end }}
|
||||
{{ $content | safeHTML }}
|
||||
|
|
|
|||
|
|
@ -83,3 +83,5 @@ is typically best reserved for the next release cycle.
|
|||
4. Wait for the GitHub Actions build to complete on the tag.
|
||||
5. Update the assets on the GitHub release to those generated by the latest Actions build.
|
||||
6. Deploy the release on the webserver. See internal wiki.
|
||||
7. Remove the changelog entries from `main`, if the changes landed on `main`.
|
||||
8. Update the github release changelog and changelog on `main`, likely by hand.
|
||||
|
|
|
|||
1
static/diagrams/threaded-dag-threads.drawio
Normal file
1
static/diagrams/threaded-dag-threads.drawio
Normal file
|
|
@ -0,0 +1 @@
|
|||
<mxfile host="app.diagrams.net" modified="2022-09-27T03:26:23.216Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" etag="YZcXq9Sm_7Lqw5o2RvSU" version="14.6.7" type="device"><diagram id="_rQ0dgHO1UnHExDn0l7E" name="Page-1">7ZpdU+IwFIZ/DZc6bdNWuJQCujPquOvOrl452TbQaNowIXztr9+EJv0goLCirYwyo81JGpL3PQ8nU2mBIFlcMDiOr2mESMuxokUL9FqO41i+I/7IyDKL2JbvZZERw5GKFYE7/BfpgSo6xRGaVAZySgnH42owpGmKQl6JQcbovDpsSEn1XcdwhIzAXQiJGf2NIx5n0bZzVsQvER7F+p1tv5P1JFAPVjuZxDCi81II9FsgYJTy7CpZBIhI9bQu2X2DLb35whhK+S43/PIf6YMfPSfXNzfx1WP3ez/2ToDaxwySqdrxz5ghGInYudQaJ4jgFKkt8KXWhdFpGiE5td0C3XmMObobw1D2zkUqiFjME6K6hzTlA5hgIrPgEpEZ4jiEsgMTElBC2WpS0O/Jl4jPEJMjyDnBo1T0cTpW09ypJajty4FosVURO9dZZCiiCeJsKYbo9NTWqOT0dHteOO2c+acqY+Oyz201FKr8GuWzFxaIC+XCPo742x3pHrsjAFQdcS3TEdu3Nvhhv5sfruHHNcTpsTuRq7zUHJhO5G59jBO2YcS5If0rYsPJOCsSQ7yQBq2LHAR9byDW2D2Egp2qgsDeoOAGAcG76dc25EKRKHaqSRmP6YimkPSLaLeay8WYKyrTbhV8QpwvVeWGU06rkqMF5vfi2lLXD/JafKRmrd6i1NVb6kYq9nuvJ5CN0l2yWdy2aun7Kiz9FHhOxHZv0Fz8/kETmObGyn2/bKuQiU5ZiF7QUx1tOGQjxF/LWzNNGCKQ41l1HQc33TGg6TYZGsdvGDQueDM0T9NkrMenNEU1cFRC56GM1RaOCPyDSBeGz6PVTkpeDwL5eqlsHRAw8BkAAwZgwZsBOwRIbn5u1afbjlczSs4XSnWh5O6IklMnSuZJu9cElMBaTXLdumuSewwg7Xm2awhI3o4ggTpB8gyQ+o0AyW5eTbINYb5Q+iCU/B1RcutEyXwaN2gCSu76g7K6axLoGEIlpwzBkGOaHgNje577IjiJ8+XLxi3kHLF0FXEstzkYnr2toqmEPLFObfFTSUpbfbjvTKqa/ZZisYliCB0OJ2Jp6ymaL+L/s9b878dFE+g2C6Xv1lwoQXsD3yjC/BjY3rN+fh62Ozuy7dVZYs3KcdkECF3QvNOqZQhz/LQ1BCX9ILrZj1D0KkswfWsETO6HPdcXzeJLFdlBofhuCuj/Aw==</diagram></mxfile>
|
||||
BIN
static/diagrams/threaded-dag-threads.png
Normal file
BIN
static/diagrams/threaded-dag-threads.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
1
static/diagrams/threaded-dag.drawio
Normal file
1
static/diagrams/threaded-dag.drawio
Normal file
|
|
@ -0,0 +1 @@
|
|||
<mxfile host="app.diagrams.net" modified="2022-09-27T03:11:43.523Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" etag="L_ujIRop4Jndk67DcTE9" version="14.6.7" type="device"><diagram id="_rQ0dgHO1UnHExDn0l7E" name="Page-1">7VpbU+IwFP41PMqkTS/wKDfdGXXcdWdXn5wsDTTaNkwIAvvrN6UJbYlCF1gbXcYZTU5P0ub0u6S1DdiNFxcMTcJrGuCoYYNg0YC9hm3bwLPFnzSyzCIW8NwsMmYkkLE8cEd+Y5UoozMS4GkpkVMacTIpB4c0SfCQl2KIMTovp41oVD7rBI2xFrgbokiP/iQBD7Noy/bz+CUm41Cd2fLa2ZEYqWS5kmmIAjovhGC/AbuMUp614kUXR2n1VF2ycYM3jq4vjOGEVxnww3ukD17wHF/f3IRXj52v/dA9k7O8oGgmF3wur5YvVQnmIeH4boKGaX8u7nMDdkIeR6JniSaaTrLCj8gCi3N15JSYcbx481qtdQUEdjCNMWdLkaIGQFk0BRtH9uf5PVApYaH8KobkXR+vZ84LIxqyNn9Tp5ZWFhwIoMguZTykY5qgqJ9HO4zOkiAtyapOec4VpRMZfMKcLyXq0YzTcmnxgvB70Qay/ZC2m67s9RaFQ72l6iRivfdqgrRTGJV282Grnho3ogkfoJhEaeA7iQXpbHCD5+L3NxqjZH1j03Vvv62iTHTGhnhLPaUscMTGmO/Cpw4ThiPEyUv5Oo5+022NHB0TyGED08jhn8hxTHLAiuSwayWHr7EjbvKQYRQcjIanWTxR+QlN8IEAadpuASNWNYSApu8WQWLtgEiApuF6AWnnFnGOWbKK2MAR0Qj9wlEHDZ/Hq+V2aUTZqkBw0E1/NoF2iaMXzMkQ1QOvWrUXaujqGqG9vmna2z5p7zHJ4VQkB6xVe52Po71F6QXVALIpvWAHQj6O9FZFV63OroOrZ4L0Qsc06XVP0ntMcrgVyeHUKr3ux5He/ba99ifd9laF13YVOgNNB/pSIitDbjXdOWNoWUiYUJLwaeFst2kgP5WjZpSCp577B2/kW7C1LV80sivYGK0uh45GU1GYTYKsS7A/Z3TK9E0wFMeCTdcwS3FOlnJMznsVOe/Wain6e0ZjLWWv3bz9SXfzVdF16G5+L/dwwYa27XAPG7S25Zfd41jO4GnIHxjhDG3THjXgyReOyVy/InO9Wn1BZ0fcFK4w5IQmRjvDf/+KvSq+Dn2LuJ8ztMrOoH04sOkMbbgt/984g/7fpQsTnME17v2/fZASgJMzlOvZrshcv1ZnAK84Aw4If7ddwrvq/puKXcEQpkIeSDL+vloMyAOi54LXbbCA8wp2UgP2an1abWvQuzRBmD3XNGG2tLKchPkAcqgPQneyo10nOyxdmb+YQA///T6oFN38o9ZsO5h/Gwz7fwA=</diagram></mxfile>
|
||||
BIN
static/diagrams/threaded-dag.png
Normal file
BIN
static/diagrams/threaded-dag.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in a new issue