Merge branch 'master' into rav/is_token_grammar
This commit is contained in:
commit
a544b68298
27 changed files with 706 additions and 91 deletions
79
api/client-server/read_markers.yaml
Normal file
79
api/client-server/read_markers.yaml
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Copyright 2018 New Vector Ltd
|
||||
#
|
||||
# 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 Read Marker API"
|
||||
version: "1.0.0"
|
||||
host: localhost:8008
|
||||
schemes:
|
||||
- https
|
||||
- http
|
||||
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
securityDefinitions:
|
||||
$ref: definitions/security.yaml
|
||||
paths:
|
||||
"/rooms/{roomId}/read_markers":
|
||||
post:
|
||||
summary: Set the position of the read marker for a room.
|
||||
description: |-
|
||||
Sets the position of the read marker for a given room, and optionally
|
||||
the read receipt's location.
|
||||
operationId: setReadMarker
|
||||
security:
|
||||
- accessToken: []
|
||||
parameters:
|
||||
- in: path
|
||||
type: string
|
||||
name: roomId
|
||||
description: The room ID to set the read marker in for the user.
|
||||
required: true
|
||||
x-example: "!somewhere:domain.com"
|
||||
- in: body
|
||||
name: body
|
||||
description: The read marker and optional read receipt locations.
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
"m.fully_read":
|
||||
type: string
|
||||
description: |-
|
||||
The event ID the read marker should be located at. The
|
||||
event MUST belong to the room.
|
||||
example: "$somewhere:domain.com"
|
||||
"m.read":
|
||||
type: string
|
||||
description: |-
|
||||
The event ID to set the read receipt location at. This is
|
||||
equivalent to calling ``/receipt/m.read/$elsewhere:domain.com``
|
||||
and is provided here to save that extra call.
|
||||
example: "$elsewhere:domain.com"
|
||||
required: ['m.fully_read']
|
||||
responses:
|
||||
200:
|
||||
description: |-
|
||||
The read marker, and read receipt if provided, have been updated.
|
||||
schema:
|
||||
type: object
|
||||
properties: {}
|
||||
429:
|
||||
description: This request was rate-limited.
|
||||
schema:
|
||||
"$ref": "definitions/errors/rate_limited.yaml"
|
||||
tags:
|
||||
- Read Markers
|
1
changelogs/client_server/newsfragments/1420.feature
Normal file
1
changelogs/client_server/newsfragments/1420.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Encrypt file attachments
|
1
changelogs/client_server/newsfragments/1617.feature
Normal file
1
changelogs/client_server/newsfragments/1617.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Add "rich replies" - a way for users to better represent the conversation thread they are referencing in their messages.
|
1
changelogs/client_server/newsfragments/1635.feature
Normal file
1
changelogs/client_server/newsfragments/1635.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Add support for read markers.
|
1
changelogs/client_server/newsfragments/1635.new
Normal file
1
changelogs/client_server/newsfragments/1635.new
Normal file
|
@ -0,0 +1 @@
|
|||
POST ``/rooms/{roomId}/read_markers``
|
|
@ -0,0 +1 @@
|
|||
Clarify and generalise the language used for describing pagination.
|
8
event-schemas/examples/m.fully_read
Normal file
8
event-schemas/examples/m.fully_read
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"$ref": "core/event.json",
|
||||
"type": "m.fully_read",
|
||||
"room_id": "!somewhere:domain.com",
|
||||
"content": {
|
||||
"event_id": "$someplace:domain.com"
|
||||
}
|
||||
}
|
|
@ -18,8 +18,16 @@ properties:
|
|||
description: Size of the image in bytes.
|
||||
type: integer
|
||||
thumbnail_url:
|
||||
description: The URL to a thumbnail of the image.
|
||||
description: |-
|
||||
The URL to a thumbnail of the image. Only present if the
|
||||
thumbnail is unencrypted.
|
||||
type: string
|
||||
thumbnail_file:
|
||||
description: |-
|
||||
Information on the encrypted thumbnail file, as specified in
|
||||
|encrypted_files|_. Only present if the thumbnail is encrypted.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
thumbnail_info:
|
||||
allOf:
|
||||
- $ref: thumbnail_info.yaml
|
||||
|
|
29
event-schemas/schema/m.fully_read
Normal file
29
event-schemas/schema/m.fully_read
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"type": "object",
|
||||
"title": "Read Marker Location Event",
|
||||
"description": "The current location of the user's read marker in a room. This event appears in the user's room account data for the room the marker is applicable for.",
|
||||
"allOf": [{
|
||||
"$ref": "core-event-schema/event.yaml"
|
||||
}],
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "The event the user's read marker is located at in the room."
|
||||
}
|
||||
},
|
||||
"required": ["event_id"]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["m.fully_read"]
|
||||
},
|
||||
"room_id": {
|
||||
"type": "string",
|
||||
"description": "The room ID the read marker applies to."
|
||||
}
|
||||
},
|
||||
"required": ["type", "room_id", "content"]
|
||||
}
|
|
@ -27,12 +27,17 @@ properties:
|
|||
- m.audio
|
||||
type: string
|
||||
url:
|
||||
description: The URL to the audio clip.
|
||||
description: Required if the file is not encrypted. The URL to the audio clip.
|
||||
type: string
|
||||
file:
|
||||
description: |-
|
||||
Required if the file is encrypted. Information on the encrypted
|
||||
file, as specified in |encrypted_files|_.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
required:
|
||||
- msgtype
|
||||
- body
|
||||
- url
|
||||
type: object
|
||||
type:
|
||||
enum:
|
||||
|
|
|
@ -21,8 +21,16 @@ properties:
|
|||
description: The size of the file in bytes.
|
||||
type: integer
|
||||
thumbnail_url:
|
||||
description: The URL to the thumbnail of the file.
|
||||
description: |-
|
||||
The URL to the thumbnail of the file. Only present if the
|
||||
thumbnail is unencrypted.
|
||||
type: string
|
||||
thumbnail_file:
|
||||
description: |-
|
||||
Information on the encrypted thumbnail file, as specified in
|
||||
|encrypted_files|_. Only present if the thumbnail is encrypted.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
thumbnail_info:
|
||||
allOf:
|
||||
- $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml
|
||||
|
@ -34,12 +42,17 @@ properties:
|
|||
- m.file
|
||||
type: string
|
||||
url:
|
||||
description: The URL to the file.
|
||||
description: Required if the file is unencrypted. The URL to the file.
|
||||
type: string
|
||||
file:
|
||||
description: |-
|
||||
Required if the file is encrypted. Information on the encrypted
|
||||
file, as specified in |encrypted_files|_.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
required:
|
||||
- msgtype
|
||||
- body
|
||||
- url
|
||||
- filename
|
||||
type: object
|
||||
type:
|
||||
|
|
|
@ -17,12 +17,17 @@ properties:
|
|||
- m.image
|
||||
type: string
|
||||
url:
|
||||
description: The URL to the image.
|
||||
description: Required if the file is unencrypted. The URL to the image.
|
||||
type: string
|
||||
file:
|
||||
description: |-
|
||||
Required if the file is encrypted. Information on the encrypted
|
||||
file, as specified in |encrypted_files|_.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
required:
|
||||
- msgtype
|
||||
- body
|
||||
- url
|
||||
type: object
|
||||
type:
|
||||
enum:
|
||||
|
|
|
@ -19,8 +19,16 @@ properties:
|
|||
type: object
|
||||
properties:
|
||||
thumbnail_url:
|
||||
description: The URL to a thumbnail of the location being represented.
|
||||
description: |-
|
||||
The URL to the thumbnail of the file. Only present if the
|
||||
thumbnail is unencrypted.
|
||||
type: string
|
||||
thumbnail_file:
|
||||
description: |-
|
||||
Information on the encrypted thumbnail file, as specified in
|
||||
|encrypted_files|_. Only present if the thumbnail is encrypted.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
thumbnail_info:
|
||||
allOf:
|
||||
- $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml
|
||||
|
|
|
@ -27,8 +27,16 @@ properties:
|
|||
description: The size of the video in bytes.
|
||||
type: integer
|
||||
thumbnail_url:
|
||||
description: The URL to an image thumbnail of the video clip.
|
||||
description: |-
|
||||
The URL to an image thumbnail of the video clip. Only present if the
|
||||
thumbnail is unencrypted.
|
||||
type: string
|
||||
thumbnail_file:
|
||||
description: |-
|
||||
Information on the encrypted thumbnail file, as specified in
|
||||
|encrypted_files|_. Only present if the thumbnail is encrypted.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
thumbnail_info:
|
||||
allOf:
|
||||
- $ref: core-event-schema/msgtype_infos/thumbnail_info.yaml
|
||||
|
@ -40,12 +48,17 @@ properties:
|
|||
- m.video
|
||||
type: string
|
||||
url:
|
||||
description: The URL to the video clip.
|
||||
description: Required if the file is unencrypted. The URL to the video clip.
|
||||
type: string
|
||||
file:
|
||||
description: |-
|
||||
Required if the file is encrypted. Information on the encrypted
|
||||
file, as specified in |encrypted_files|_.
|
||||
title: EncryptedFile
|
||||
type: object
|
||||
required:
|
||||
- msgtype
|
||||
- body
|
||||
- url
|
||||
type: object
|
||||
type:
|
||||
enum:
|
||||
|
|
|
@ -318,6 +318,46 @@ table.citation td {
|
|||
border-bottom: none;
|
||||
}
|
||||
|
||||
table.colwidths-auto caption {
|
||||
font-family: 'Inconsolata', monospace;
|
||||
font-weight: 800;
|
||||
font-size: 120%;
|
||||
padding: 5px;
|
||||
text-align: left;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
ol, li {
|
||||
margin: 0px 0px 0px 30px !important;
|
||||
}
|
||||
|
||||
p.httpheaders {
|
||||
font-weight: 800;
|
||||
font-size: 120%;
|
||||
padding: 5px;
|
||||
text-align: left;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
table.colwidths-auto {
|
||||
width:100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
table.colwidths-auto tr td:nth-child(1) {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
table.colwidths-auto tr td:nth-child(2) {
|
||||
width: 15%;
|
||||
font-family: 'Inconsolata', monospace;
|
||||
}
|
||||
|
||||
table.colwidths-auto tr td:nth-child(3) {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
ol.arabic {
|
||||
|
|
|
@ -273,6 +273,7 @@ table {
|
|||
|
||||
td[colspan]:not([colspan="1"]) {
|
||||
background: #eeeeee;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
thead {
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
{{common_event.desc}}
|
||||
|
||||
{% for table in common_event.tables %}
|
||||
{{"``"+table.title+"``" if table.title else "" }}
|
||||
|
||||
{{ tables.paramtable(table.rows, ["Key", "Type", "Description"]) }}
|
||||
{{ tables.paramtable(table.rows, ["Key", "Type", "Description"], (table.title or "")) }}
|
||||
|
||||
{% endfor %}
|
||||
|
|
|
@ -5,16 +5,15 @@
|
|||
|
||||
{% if (event.typeof | length) %}
|
||||
*{{event.typeof}}*
|
||||
{{event.typeof_info}}
|
||||
{{event.typeof_info | indent_block(4)}}
|
||||
|
||||
{% endif -%}
|
||||
|
||||
{{event.desc}}
|
||||
|
||||
{% for table in event.content_fields %}
|
||||
{{"``"+table.title+"``" if table.title else "" }}
|
||||
|
||||
{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"]) }}
|
||||
{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"], (table.title or "")) }}
|
||||
|
||||
{% endfor %}
|
||||
Example{% if examples | length > 1 %}s{% endif %}:
|
||||
|
|
|
@ -13,13 +13,16 @@
|
|||
{{":Rate-limited: Yes." if endpoint.rate_limited else "" }}
|
||||
{{":Requires auth: Yes." if endpoint.requires_auth else "" }}
|
||||
|
||||
Request format:
|
||||
.. class:: httpheaders
|
||||
|
||||
Request format:
|
||||
|
||||
{% if (endpoint.req_param_by_loc | length) %}
|
||||
{{ tables.split_paramtable(endpoint.req_param_by_loc) }}
|
||||
{% if (endpoint.req_body_tables) %}
|
||||
{% for table in endpoint.req_body_tables -%}
|
||||
{{"``"+table.title+"``" if table.title else "" }}
|
||||
{{ tables.paramtable(table.rows) }}
|
||||
{{ tables.paramtable(table.rows, caption=(table.title or "")) }}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
|
@ -28,30 +31,41 @@ Request format:
|
|||
{% endif %}
|
||||
|
||||
{% if endpoint.res_headers is not none -%}
|
||||
Response headers:
|
||||
|
||||
.. class:: httpheaders
|
||||
|
||||
Response headers:
|
||||
|
||||
{{ tables.paramtable(endpoint.res_headers.rows) }}
|
||||
{% endif -%}
|
||||
|
||||
{% if endpoint.res_tables|length > 0 -%}
|
||||
Response format:
|
||||
|
||||
.. class:: httpheaders
|
||||
|
||||
Response format:
|
||||
|
||||
{% for table in endpoint.res_tables -%}
|
||||
{{"``"+table.title+"``" if table.title else "" }}
|
||||
|
||||
{{ tables.paramtable(table.rows) }}
|
||||
{{ tables.paramtable(table.rows, caption=(table.title or "")) }}
|
||||
|
||||
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
|
||||
Example request:
|
||||
.. class:: httpheaders
|
||||
|
||||
Example request:
|
||||
|
||||
.. code:: http
|
||||
|
||||
{{endpoint.example.req | indent_block(2)}}
|
||||
|
||||
{% if endpoint.responses|length > 0 -%}
|
||||
Response{{"s" if endpoint.responses|length > 1 else "" }}:
|
||||
|
||||
.. class:: httpheaders
|
||||
|
||||
Response{{"s" if endpoint.responses|length > 1 else "" }}:
|
||||
|
||||
{% endif -%}
|
||||
|
||||
|
@ -63,7 +77,9 @@ Response{{"s" if endpoint.responses|length > 1 else "" }}:
|
|||
|
||||
{% if res["example"] -%}
|
||||
|
||||
Example
|
||||
.. class:: httpheaders
|
||||
|
||||
Example
|
||||
|
||||
.. code:: json
|
||||
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
{{(4 + event.msgtype | length) * title_kind}}
|
||||
{{event.desc | wrap(80)}}
|
||||
{% for table in event.content_fields -%}
|
||||
{{"``"+table.title+"``" if table.title else "" }}
|
||||
|
||||
{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"]) }}
|
||||
{{ tables.paramtable(table.rows, [(table.title or "Content") ~ " Key", "Type", "Description"], (table.title or "")) }}
|
||||
|
||||
{% endfor %}
|
||||
Example:
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#
|
||||
# 'rows' is the list of parameters. Each row should be a TypeTableRow.
|
||||
#}
|
||||
{% macro paramtable(rows, titles=["Parameter", "Type", "Description"]) -%}
|
||||
{{ split_paramtable({None: rows}, titles) }}
|
||||
{% macro paramtable(rows, titles=["Parameter", "Type", "Description"], caption="") -%}
|
||||
{{ split_paramtable({None: rows}, titles, caption) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
|||
# written for that location. This is used by the standard 'paramtable' macro.
|
||||
#}
|
||||
{% macro split_paramtable(rows_by_loc,
|
||||
titles=["Parameter", "Type", "Description"]) -%}
|
||||
titles=["Parameter", "Type", "Description"], caption="") -%}
|
||||
|
||||
{% set rowkeys = ['key', 'title', 'desc'] %}
|
||||
{% set titlerow = {'key': titles[0], 'title': titles[1], 'desc': titles[2]} %}
|
||||
|
@ -36,6 +36,9 @@
|
|||
{% set fieldwidths = (([titlerow] + flatrows) |
|
||||
fieldwidths(rowkeys[0:-1], [10, 10])) + [50] -%}
|
||||
|
||||
{{".. table:: "}}{{ caption }}
|
||||
{{" :widths: auto"}}
|
||||
{{""}}
|
||||
{{ tableheader(fieldwidths) }}
|
||||
{{ tablerow(fieldwidths, titlerow, rowkeys) }}
|
||||
{{ tableheader(fieldwidths) }}
|
||||
|
@ -59,7 +62,7 @@
|
|||
# Write a table header row, for the given column widths
|
||||
#}
|
||||
{% macro tableheader(widths) -%}
|
||||
{% for arg in widths -%}
|
||||
{{" "}}{% for arg in widths -%}
|
||||
{{"="*arg}} {% endfor -%}
|
||||
{% endmacro %}
|
||||
|
||||
|
@ -71,7 +74,7 @@
|
|||
# attributes of 'row' to look up for values to put in the columns.
|
||||
#}
|
||||
{% macro tablerow(widths, row, keys) -%}
|
||||
{% for key in keys -%}
|
||||
{{" "}}{% for key in keys -%}
|
||||
{% set value=row[key] -%}
|
||||
{% if not loop.last -%}
|
||||
{# the first few columns need space after them -#}
|
||||
|
@ -81,7 +84,7 @@
|
|||
the preceding columns, plus the number of preceding columns (for the
|
||||
separators)) -#}
|
||||
{{ value | wrap(widths[loop.index0]) |
|
||||
indent_block(widths[0:-1]|sum + loop.index0) -}}
|
||||
indent_block(widths[0:-1]|sum + loop.index0 + 2) -}}
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endmacro %}
|
||||
|
@ -93,10 +96,10 @@
|
|||
# write a tablespan row. This is a single value which spans the entire table.
|
||||
#}
|
||||
{% macro tablespan(widths, value) -%}
|
||||
{{value}}
|
||||
{{" "}}{{value}}
|
||||
{# we write a trailing space to stop the separator being misinterpreted
|
||||
# as a header line. -#}
|
||||
{{"-"*(widths|sum + widths|length -1)}} {% endmacro %}
|
||||
{{" "}}{{"-"*(widths|sum + widths|length -1)}} {% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -138,9 +138,6 @@ Some requests have unique error codes:
|
|||
:``M_INVALID_ROOM_STATE``:
|
||||
Sent when the intial state given to the ``createRoom`` API is invalid.
|
||||
|
||||
:``M_BAD_PAGINATION``:
|
||||
Encountered when specifying bad pagination query parameters.
|
||||
|
||||
:``M_THREEPID_IN_USE``:
|
||||
Sent when a threepid given to an API cannot be used because the same threepid is already in use.
|
||||
|
||||
|
@ -1018,39 +1015,21 @@ Pagination is the process of dividing a dataset into multiple discrete pages.
|
|||
Matrix makes use of pagination to allow clients to view extremely large datasets.
|
||||
These datasets are not limited to events in a room (for example clients may want
|
||||
to paginate a list of rooms in addition to events within those rooms). Regardless
|
||||
of *what* is being paginated, there is a common underlying API which is used to
|
||||
to give clients a consistent way of selecting subsets of a potentially changing
|
||||
dataset. Requests pass in ``from``, ``to``, ``dir`` and ``limit`` parameters
|
||||
which describe where to read from the stream. ``from`` and ``to`` are opaque
|
||||
textual 'stream tokens' which describe the current position in the dataset.
|
||||
The ``dir`` parameter is an enum representing the direction of events to return:
|
||||
either ``f`` orwards or ``b`` ackwards. The response returns new ``start`` and
|
||||
``end`` stream token values which can then be passed to subsequent requests to
|
||||
continue pagination. Not all endpoints will make use of all the parameters
|
||||
outlined here: see the specific endpoint in question for more information.
|
||||
of what is being paginated, there is a common approach which is used to give
|
||||
clients an easy way of selecting subsets of a potentially changing dataset. Each
|
||||
endpoint that uses pagination may use different parameters. However the theme
|
||||
among them is that they take a ``from`` and ``to`` token, and occasionally
|
||||
a ``limit`` and ``dir``. Together, these parameters describe the position in a
|
||||
data set, where ``from`` and ``to`` are known as "stream tokens" matching the
|
||||
regular expression ``[a-zA-Z0-9.=_-]+``. If supported, the ``dir`` defines the
|
||||
direction of events to return: either forwards (``f``) or backwards (``b``).
|
||||
The response may contain tokens that can be used for retrieving results before
|
||||
or after the returned set. These tokens may be called `start` or `prev_batch`
|
||||
for retrieving the previous result set, or `end`, `next_batch` or `next_token`
|
||||
for retrieving the next result set.
|
||||
|
||||
Pagination Request Query Parameters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Query parameters:
|
||||
from:
|
||||
$streamtoken - The opaque token to start streaming from.
|
||||
to:
|
||||
$streamtoken - The opaque token to end streaming at. Typically,
|
||||
clients will not know the item of data to end at, so this will usually be
|
||||
omitted.
|
||||
limit:
|
||||
integer - An integer representing the maximum number of items to
|
||||
return.
|
||||
dir:
|
||||
f|b - The direction to return events in. Typically this is ``b`` to paginate
|
||||
backwards in time.
|
||||
|
||||
'START' and 'END' are placeholder values used in these examples to describe the
|
||||
start and end of the dataset respectively.
|
||||
|
||||
Unless specified, the default pagination parameters are ``from=START``,
|
||||
``to=END``, without a limit set.
|
||||
In the following examples, 'START' and 'END' are placeholders to signify the
|
||||
start and end of the data sets respectively.
|
||||
|
||||
For example, if an endpoint had events E1 -> E15. The client wants the last 5
|
||||
events and doesn't know any previous events::
|
||||
|
@ -1067,8 +1046,8 @@ events and doesn't know any previous events::
|
|||
|
||||
|
||||
Another example: a public room list has rooms R1 -> R17. The client is showing 5
|
||||
rooms at a time on screen, and is on page 2. They want to
|
||||
now show page 3 (rooms R11 -> 15)::
|
||||
rooms at a time on screen, and is on page 2. They want to now show page 3 (rooms
|
||||
R11 -> 15)::
|
||||
|
||||
S E
|
||||
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | stream token
|
||||
|
@ -1086,20 +1065,17 @@ token from the initial request was '9' which corresponded to R10. When the 2nd
|
|||
request was made, R10 did not appear again, even though from=9 was specified. If
|
||||
you know the token, you already have the data.
|
||||
|
||||
Pagination Response
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Responses for pagination-capable endpoints SHOULD have a ``chunk`` array alongside
|
||||
the applicable stream tokens to represent the result set.
|
||||
|
||||
Responses to pagination requests MUST follow the format::
|
||||
|
||||
{
|
||||
"chunk": [ ... , Responses , ... ],
|
||||
"start" : $streamtoken,
|
||||
"end" : $streamtoken
|
||||
}
|
||||
|
||||
Where $streamtoken is an opaque token which can be used in another query to
|
||||
get the next set of results. The "start" and "end" keys can only be omitted if
|
||||
the complete dataset is provided in "chunk".
|
||||
In general, when the end of a result set is reached the applicable stream token
|
||||
will be excluded from the response. For example, if a user was backwards-paginating
|
||||
events in a room they'd eventually reach the first event in the room. In this scenario,
|
||||
the ``prev_batch`` token would be excluded from the response. Some paginated
|
||||
endpoints are open-ended in one direction, such as endpoints which expose an event
|
||||
stream for an active room. In this case, it is not possible for the client to reach
|
||||
the true "end" of the data set and therefore should always be presented with a token
|
||||
to keep moving forwards.
|
||||
|
||||
.. _`filter`:
|
||||
|
||||
|
|
|
@ -39,3 +39,10 @@ Client Behaviour
|
|||
----------------
|
||||
|
||||
{{account_data_cs_http_api}}
|
||||
|
||||
|
||||
Server Behaviour
|
||||
----------------
|
||||
|
||||
Servers MUST reject clients from setting account data for event types that
|
||||
the server manages. Currently, this only includes `m.fully_read`_.
|
||||
|
|
|
@ -224,6 +224,145 @@ process:
|
|||
.. |device_lists| replace:: ``device_lists``
|
||||
.. _`device_lists`: `device_lists_sync`_
|
||||
|
||||
|
||||
Sending encrypted attachments
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When encryption is enabled in a room, files should be uploaded encrypted on
|
||||
the homeserver.
|
||||
|
||||
In order to achieve this, a client should generate a single-use 256-bit AES
|
||||
key, and encrypt the file using AES-CTR. The counter should be 64-bit long,
|
||||
starting at 0 and prefixed by a random 64-bit Initialization Vector (IV), which
|
||||
together form a 128-bit unique counter block.
|
||||
|
||||
.. Warning::
|
||||
An IV must never be used multiple times with the same key. This implies that
|
||||
if there are multiple files to encrypt in the same message, typically an
|
||||
image and its thumbnail, the files must not share both the same key and IV.
|
||||
|
||||
Then, the encrypted file can be uploaded to the homeserver.
|
||||
The key and the IV must be included in the room event along with the resulting
|
||||
``mxc://`` in order to allow recipients to decrypt the file. As the event
|
||||
containing those will be Megolm encrypted, the server will never have access to
|
||||
the decrypted file.
|
||||
|
||||
A hash of the ciphertext must also be included, in order to prevent the homeserver from
|
||||
changing the file content.
|
||||
|
||||
A client should send the data as an encrypted ``m.room.message`` event, using
|
||||
either ``m.file`` as the msgtype, or the appropriate msgtype for the file
|
||||
type. The key is sent using the `JSON Web Key`_ format, with a `W3C
|
||||
extension`_.
|
||||
|
||||
.. anchor for link from m.message api spec
|
||||
.. |encrypted_files| replace:: End-to-end encryption
|
||||
.. _encrypted_files:
|
||||
|
||||
Extensions to ``m.message`` msgtypes
|
||||
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
This module adds ``file`` and ``thumbnail_file`` properties, of type
|
||||
``EncryptedFile``, to ``m.message`` msgtypes that reference files, such as
|
||||
`m.file`_ and `m.image`_, replacing the ``url`` and ``thumbnail_url``
|
||||
properties.
|
||||
|
||||
.. todo: generate this from a swagger definition?
|
||||
|
||||
``EncryptedFile``
|
||||
|
||||
========= ================ =====================================================
|
||||
Parameter Type Description
|
||||
========= ================ =====================================================
|
||||
url string **Required.** The URL to the file.
|
||||
key JWK **Required.** A `JSON Web Key`_ object.
|
||||
iv string **Required.** The Initialisation Vector used by
|
||||
AES-CTR, encoded as unpadded base64.
|
||||
hashes {string: string} **Required.** A map from an algorithm name to a hash
|
||||
of the ciphertext, encoded as unpadded base64. Clients
|
||||
should support the SHA-256 hash, which uses the key
|
||||
``sha256``.
|
||||
v string **Required.** Version of the encrypted attachments
|
||||
protocol. Must be ``v2``.
|
||||
========= ================ =====================================================
|
||||
|
||||
``JWK``
|
||||
|
||||
========= ========= ============================================================
|
||||
Parameter Type Description
|
||||
========= ========= ============================================================
|
||||
key string **Required.** Key type. Must be ``oct``.
|
||||
key_opts [string] **Required.** Key operations. Must at least contain
|
||||
``encrypt`` and ``decrypt``.
|
||||
alg string **Required.** Algorithm. Must be ``A256CTR``.
|
||||
k string **Required.** The key, encoded as urlsafe unpadded base64.
|
||||
ext boolean **Required.** Extractable. Must be ``true``. This is a
|
||||
`W3C extension`_.
|
||||
========= ========= ============================================================
|
||||
|
||||
Example:
|
||||
|
||||
.. code :: json
|
||||
|
||||
{
|
||||
"content": {
|
||||
"body": "something-important.jpg",
|
||||
"file": {
|
||||
"url": "mxc://domain.com/FHyPlCeYUSFFxlgbQYZmoEoe",
|
||||
"mimetype": "image/jpeg",
|
||||
"v": "v2",
|
||||
"key": {
|
||||
"alg": "A256CTR",
|
||||
"ext": true,
|
||||
"k": "aWF6-32KGYaC3A_FEUCk1Bt0JA37zP0wrStgmdCaW-0",
|
||||
"key_ops": ["encrypt","decrypt"],
|
||||
"kty": "oct"
|
||||
},
|
||||
"iv": "w+sE15fzSc0AAAAAAAAAAA",
|
||||
"hashes": {
|
||||
"sha256": "fdSLu/YkRx3Wyh3KQabP3rd6+SFiKg5lsJZQHtkSAYA"
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"mimetype": "image/jpeg",
|
||||
"h": 1536,
|
||||
"size": 422018,
|
||||
"thumbnail_file": {
|
||||
"hashes": {
|
||||
"sha256": "/NogKqW5bz/m8xHgFiH5haFGjCNVmUIPLzfvOhHdrxY"
|
||||
},
|
||||
"iv": "U+k7PfwLr6UAAAAAAAAAAA",
|
||||
"key": {
|
||||
"alg": "A256CTR",
|
||||
"ext": true,
|
||||
"k": "RMyd6zhlbifsACM1DXkCbioZ2u0SywGljTH8JmGcylg",
|
||||
"key_ops": ["encrypt", "decrypt"],
|
||||
"kty": "oct"
|
||||
},
|
||||
"mimetype": "image/jpeg",
|
||||
"url": "mxc://domain.com/pmVJxyxGlmxHposwVSlOaEOv",
|
||||
"v": "v2"
|
||||
},
|
||||
"thumbnail_info": {
|
||||
"h": 768,
|
||||
"mimetype": "image/jpeg",
|
||||
"size": 211009,
|
||||
"w": 432
|
||||
},
|
||||
"w": 864
|
||||
},
|
||||
"msgtype": "m.image"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:domain.com",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||
"sender": "@example:domain.com",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
|
||||
Claiming one-time keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -583,6 +722,8 @@ Example response:
|
|||
.. _curve25519: https://cr.yp.to/ecdh.html
|
||||
.. _`Olm specification`: http://matrix.org/docs/spec/olm.html
|
||||
.. _`Megolm specification`: http://matrix.org/docs/spec/megolm.html
|
||||
.. _`JSON Web Key`: https://tools.ietf.org/html/rfc7517#appendix-A.3
|
||||
.. _`W3C extension`: https://w3c.github.io/webcrypto/#iana-section-jwk
|
||||
|
||||
.. _`Signing JSON`: ../appendices.html#signing-json
|
||||
|
||||
|
|
|
@ -62,9 +62,9 @@ support an additional ``format`` parameter of ``org.matrix.custom.html``. When
|
|||
this field is present, a ``formatted_body`` with the HTML must be provided. The
|
||||
plain text version of the HTML should be provided in the ``body``.
|
||||
|
||||
Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML
|
||||
Clients should limit the HTML they render to avoid Cross-Site Scripting, HTML
|
||||
injection, and similar attacks. The strongly suggested set of HTML tags to permit,
|
||||
denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``,
|
||||
denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``,
|
||||
``h2``, ``h3``, ``h4``, ``h5``, ``h6``, ``blockquote``, ``p``, ``a``, ``ul``,
|
||||
``ol``, ``sup``, ``sub``, ``li``, ``b``, ``i``, ``u``, ``strong``, ``em``,
|
||||
``strike``, ``code``, ``hr``, ``br``, ``div``, ``table``, ``thead``, ``tbody``,
|
||||
|
@ -73,7 +73,7 @@ denying the use and rendering of anything else, is: ``font``, ``del``, ``h1``,
|
|||
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
|
||||
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.
|
||||
|
||||
|
@ -112,6 +112,13 @@ surrounding text due to Rich Text Editors. HTML included in events should otherw
|
|||
such as having appropriate closing tags, appropriate attributes (considering the custom ones
|
||||
defined in this specification), and generally valid structure.
|
||||
|
||||
A special tag, ``mx-reply``, may appear on rich replies (described below) and should be
|
||||
allowed if, and only if, the tag appears as the very first tag in the ``formatted_body``.
|
||||
The tag cannot be nested and cannot be located after another tag in the tree. Because the
|
||||
tag contains HTML, an ``mx-reply`` is expected to have a partner closing tag and should
|
||||
be treated similar to a ``div``. Clients that support rich replies will end up stripping
|
||||
the tag and its contents and therefore may wish to exclude the tag entirely.
|
||||
|
||||
.. Note::
|
||||
A future iteration of the specification will support more powerful and extensible
|
||||
message formatting options, such as the proposal `MSC1225 <https://github.com/matrix-org/matrix-doc/issues/1225>`_.
|
||||
|
@ -346,6 +353,192 @@ change unexpectedly.
|
|||
an English-language implementation on them all? See
|
||||
https://matrix.org/jira/browse/SPEC-425.
|
||||
|
||||
|
||||
Forming relationships between events
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In some cases, events may wish to reference other events. This could be to form
|
||||
a thread of messages for the user to follow along with, or to provide more context
|
||||
as to what a particular event is describing. Currently, the only kind of relation
|
||||
defined is a "rich reply" where a user may reference another message to create a
|
||||
thread-like conversation.
|
||||
|
||||
Relationships are defined under an ``m.relates_to`` key in the event's ``content``.
|
||||
If the event is of the type ``m.room.encrypted``, the ``m.relates_to`` key MUST NOT
|
||||
be covered by the encryption and instead be put alongside the encryption information
|
||||
held in the ``content``.
|
||||
|
||||
|
||||
Rich replies
|
||||
++++++++++++
|
||||
|
||||
Users may wish to reference another message when forming their own message, and
|
||||
clients may wish to better embed the referenced message for the user to have a
|
||||
better context for the conversation being had. This sort of embedding another
|
||||
message in a message is known as a "rich reply", or occasionally just a "reply".
|
||||
|
||||
A rich reply is formed through use of an ``m.relates_to`` relation for ``m.in_reply_to``
|
||||
where a single key, ``event_id``, is used to reference the event being replied to.
|
||||
The referenced event ID SHOULD belong to the same room where the reply is being sent.
|
||||
Clients should be cautious of the event ID belonging to another room, or being invalid
|
||||
entirely. Rich replies can only be constructed in the form of ``m.room.message`` events
|
||||
with a ``msgtype`` of ``m.text`` or ``m.notice``. Due to the fallback requirements, rich
|
||||
replies cannot be constructed for types of ``m.emote``, ``m.file``, etc. Rich replies
|
||||
may reference any other ``m.room.message`` event, however. Rich replies may reference
|
||||
another event which also has a rich reply, infinitely.
|
||||
|
||||
An ``m.in_reply_to`` relationship looks like the following::
|
||||
|
||||
{
|
||||
...
|
||||
"type": "m.room.message",
|
||||
"content": {
|
||||
"msgtype": "m.text",
|
||||
"body": "<body including fallback>",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<HTML including fallback>",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$another:event.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Fallbacks and event representation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some clients may not have support for rich replies and therefore need a fallback
|
||||
to use instead. Clients that do not support rich replies should render the event
|
||||
as if rich replies were not special.
|
||||
|
||||
Clients that do support rich replies MUST provide the fallback format on replies,
|
||||
and MUST strip the fallback before rendering the reply. Rich replies MUST have
|
||||
a ``format`` of ``org.matrix.custom.html`` and therefore a ``formatted_body``
|
||||
alongside the ``body`` and appropriate ``msgtype``. The specific fallback text
|
||||
is different for each ``msgtype``, however the general format for the ``body`` is:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
> <@alice:example.org> This is the original body
|
||||
|
||||
This is where the reply goes
|
||||
|
||||
|
||||
The ``formatted_body`` should use the following template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<mx-reply>
|
||||
<blockquote>
|
||||
<a href="https://matrix.to/#/!somewhere:domain.com/$event:domain.com">In reply to</a>
|
||||
<a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
|
||||
<br />
|
||||
<!-- This is where the related event's HTML would be. -->
|
||||
</blockquote>
|
||||
</mx-reply>
|
||||
This is where the reply goes.
|
||||
|
||||
|
||||
If the related event does not have a ``formatted_body``, the event's ``body`` should
|
||||
be considered after encoding any HTML special characters. Note that the ``href`` in
|
||||
both of the anchors use a `matrix.to URI <../appendices.html#matrix-to-navigation>`_.
|
||||
|
||||
Stripping the fallback
|
||||
``````````````````````
|
||||
|
||||
Clients which support rich replies MUST strip the fallback from the event before
|
||||
rendering the event. This is because the text provided in the fallback cannot be
|
||||
trusted to be an accurate representation of the event. After removing the fallback,
|
||||
clients are recommended to represent the event referenced by ``m.in_reply_to``
|
||||
similar to the fallback's representation, although clients do have creative freedom
|
||||
for their user interface. Clients should prefer the ``formatted_body`` over the
|
||||
``body``, just like with other ``m.room.message`` events.
|
||||
|
||||
To strip the fallback on the ``body``, the client should iterate over each line of
|
||||
the string, removing any lines that start with the fallback prefix ("> ",
|
||||
including the space, without quotes) and stopping when a line is encountered without
|
||||
the prefix. This prefix is known as the "fallback prefix sequence".
|
||||
|
||||
To strip the fallback on the ``formatted_body``, the client should remove the
|
||||
entirety of the ``mx-reply`` tag.
|
||||
|
||||
Fallback for ``m.text``, ``m.notice``, and unrecognised message types
|
||||
`````````````````````````````````````````````````````````````````````
|
||||
|
||||
Using the prefix sequence, the first line of the related event's ``body`` should
|
||||
be prefixed with the user's ID, followed by each line being prefixed with the fallback
|
||||
prefix sequence. For example::
|
||||
|
||||
> <@alice:example.org> This is the first line
|
||||
> This is the second line
|
||||
|
||||
This is the reply
|
||||
|
||||
|
||||
The ``formatted_body`` uses the template defined earlier in this section.
|
||||
|
||||
Fallback for ``m.emote``
|
||||
````````````````````````
|
||||
|
||||
Similar to the fallback for ``m.text``, each line gets prefixed with the fallback
|
||||
prefix sequence. However an asterisk should be inserted before the user's ID, like
|
||||
so::
|
||||
|
||||
> * <@alice:example.org> feels like today is going to be a great day
|
||||
|
||||
This is the reply
|
||||
|
||||
|
||||
The ``formatted_body`` has a subtle difference for the template where the asterisk
|
||||
is also inserted ahead of the user's ID:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<mx-reply>
|
||||
<blockquote>
|
||||
<a href="https://matrix.to/#/!somewhere:domain.com/$event:domain.com">In reply to</a>
|
||||
* <a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
|
||||
<br />
|
||||
<!-- This is where the related event's HTML would be. -->
|
||||
</blockquote>
|
||||
</mx-reply>
|
||||
This is where the reply goes.
|
||||
|
||||
|
||||
Fallback for ``m.image``, ``m.video``, ``m.audio``, and ``m.file``
|
||||
``````````````````````````````````````````````````````````````````
|
||||
|
||||
The related event's ``body`` would be a file name, which may not be very descriptive.
|
||||
The related event should additionally not have a ``format`` or ``formatted_body``
|
||||
in the ``content`` - if the event does have a ``format`` and/or ``formatted_body``,
|
||||
those fields should be ignored. Because the filename alone may not be descriptive,
|
||||
the related event's ``body`` should be considered to be ``"sent a file."`` such that
|
||||
the output looks similar to the following::
|
||||
|
||||
> <@alice:example.org> sent a file.
|
||||
|
||||
This is the reply
|
||||
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<mx-reply>
|
||||
<blockquote>
|
||||
<a href="https://matrix.to/#/!somewhere:domain.com/$event:domain.com">In reply to</a>
|
||||
<a href="https://matrix.to/#/@alice:example.org">@alice:example.org</a>
|
||||
<br />
|
||||
sent a file.
|
||||
</blockquote>
|
||||
</mx-reply>
|
||||
This is where the reply goes.
|
||||
|
||||
|
||||
For ``m.image``, the text should be ``"sent an image."``. For ``m.video``, the text
|
||||
should be ``"sent a video."``. For ``m.audio``, the text should be ``"sent an audio file"``.
|
||||
|
||||
|
||||
Server behaviour
|
||||
----------------
|
||||
|
||||
|
@ -362,4 +555,4 @@ Clients should sanitise **all displayed keys** for unsafe HTML to prevent Cross-
|
|||
Scripting (XSS) attacks. This includes room names and topics.
|
||||
|
||||
.. _`E2E module`: `module:e2e`_
|
||||
.. _`Matrix Content (MXC) URI`: `module:content`_
|
||||
.. _`Matrix Content (MXC) URI`: `module:content`_
|
||||
|
|
67
specification/modules/read_markers.rst
Normal file
67
specification/modules/read_markers.rst
Normal file
|
@ -0,0 +1,67 @@
|
|||
.. Copyright 2018 New Vector Ltd
|
||||
..
|
||||
.. 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.
|
||||
|
||||
Fully read markers
|
||||
==================
|
||||
|
||||
.. _module:read-markers:
|
||||
|
||||
The history for a given room may be split into three sections: messages the
|
||||
user has read (or indicated they aren't interested in them), messages the user
|
||||
might have read some but not others, and messages the user hasn't seen yet.
|
||||
The "fully read marker" (also known as a "read marker") marks the last event
|
||||
of the first section, whereas the user's read receipt marks the last event of
|
||||
the second section.
|
||||
|
||||
Events
|
||||
------
|
||||
The user's fully read marker is kept as an event in the room's `account data`_.
|
||||
The event may be read to determine the user's current fully read marker location
|
||||
in the room, and just like other account data events the event will be pushed down
|
||||
the event stream when updated.
|
||||
|
||||
The fully read marker is kept under an ``m.fully_read`` event. If the event does
|
||||
not exist on the user's account data, the fully read marker should be considered
|
||||
to be the user's read receipt location.
|
||||
|
||||
{{m_fully_read_event}}
|
||||
|
||||
Client behaviour
|
||||
----------------
|
||||
The client cannot update fully read markers by directly modifying the ``m.fully_read``
|
||||
account data event. Instead, the client must make use of the read markers API
|
||||
to change the values.
|
||||
|
||||
The read markers API can additionally update the user's read receipt (``m.read``)
|
||||
location in the same operation as setting the fully read marker location. This is
|
||||
because read receipts and read markers are commonly updated at the same time,
|
||||
and therefore the client might wish to save an extra HTTP call. Providing an
|
||||
``m.read`` location performs the same task as a request to ``/receipts/m.read/$event:domain.com``.
|
||||
|
||||
{{read_markers_cs_http_api}}
|
||||
|
||||
Server behaviour
|
||||
----------------
|
||||
The server MUST prevent clients from setting ``m.fully_read`` directly in
|
||||
room account data. The server must additionally ensure that it treats the
|
||||
presence of ``m.read`` in the ``/read_markers`` request the same as how it
|
||||
would for a request to ``/receipts/m.read/$event:domain.com``.
|
||||
|
||||
Upon updating the ``m.fully_read`` event due to a request to ``/read_markers``,
|
||||
the server MUST send the updated account data event through to the client via
|
||||
the event stream (eg: ``/sync``), provided any applicable filters are also
|
||||
satisfied.
|
||||
|
||||
|
||||
.. _`account data`: #client-config
|
|
@ -45,6 +45,7 @@ groups: # reusable blobs of files when prefixed with 'group:'
|
|||
- modules/voip_events.rst
|
||||
- modules/typing_notifications.rst
|
||||
- modules/receipts.rst
|
||||
- modules/read_markers.rst
|
||||
- modules/presence.rst
|
||||
- modules/content_repo.rst
|
||||
- modules/send_to_device.rst
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue