mirror of
https://github.com/matrix-org/matrix-spec
synced 2026-03-23 19:44:09 +01:00
Merge remote-tracking branch 'upstream/main' into clokep/conditions-link
This commit is contained in:
commit
f75fe264c2
4
.github/ISSUE_TEMPLATE/release.md
vendored
4
.github/ISSUE_TEMPLATE/release.md
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
name: [SCT] Release checklist
|
name: '[SCT] Release checklist'
|
||||||
about: Used by the Spec Core Team to create a new release.
|
about: 'Used by the Spec Core Team to create a new release.'
|
||||||
title: 'Matrix 1.X'
|
title: 'Matrix 1.X'
|
||||||
labels: 'release-blocker'
|
labels: 'release-blocker'
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
|
||||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
|
@ -193,7 +193,7 @@ jobs:
|
||||||
- name: "➕ Setup Hugo"
|
- name: "➕ Setup Hugo"
|
||||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
|
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
|
||||||
with:
|
with:
|
||||||
hugo-version: '0.113.0'
|
hugo-version: '0.117.0'
|
||||||
extended: true
|
extended: true
|
||||||
- name: "📥 Source checkout"
|
- name: "📥 Source checkout"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
IgnoreDirectoryMissingTrailingSlash: true
|
IgnoreDirectoryMissingTrailingSlash: true
|
||||||
DirectoryPath: spec
|
DirectoryPath: spec
|
||||||
CheckExternal: false
|
CheckExternal: false
|
||||||
|
IgnoreInternalEmptyHash: true
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ place after an MSC has been accepted, not as part of a proposal itself.
|
||||||
|
|
||||||
1. Install the extended version (often the OS default) of Hugo:
|
1. Install the extended version (often the OS default) of Hugo:
|
||||||
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
|
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
|
||||||
v0.113.0 is required.
|
v0.117.0 is required.
|
||||||
|
|
||||||
Alternatively, use the Docker image at
|
Alternatively, use the Docker image at
|
||||||
https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required
|
https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify specification by adding `/logout` to the overview list of endpoints that don't take a JSON request body.
|
||||||
1
changelogs/client_server/newsfragments/1828.feature
Normal file
1
changelogs/client_server/newsfragments/1828.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Do not require UIA when first uploading cross-signing keys, as per [MSC3967](https://github.com/matrix-org/matrix-spec-proposals/pull/3967).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that per-request UIA for /login/get_token is an RFC 2119 MUST requirement.
|
||||||
1
changelogs/client_server/newsfragments/1847.feature
Normal file
1
changelogs/client_server/newsfragments/1847.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add the new `unsigned.membership` property to events served over the client-server API, as per [MSC4115](https://github.com/matrix-org/matrix-spec-proposals/pull/4115).
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
1
changelogs/internal/newsfragments/1849.clarification
Normal file
1
changelogs/internal/newsfragments/1849.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Do not add empty arrays to examples.
|
||||||
1
changelogs/internal/newsfragments/1851.clarification
Normal file
1
changelogs/internal/newsfragments/1851.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Generate ToC with Hugo rather than JavaScript.
|
||||||
1
changelogs/internal/newsfragments/1856.clarification
Normal file
1
changelogs/internal/newsfragments/1856.clarification
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix syntax errors in the spec release issue template.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix various typos throughout the specification.
|
||||||
|
|
@ -1 +1 @@
|
||||||
Clarify that the `event` field of the `/v2/send_join` response is only required when `join_authorised_via_users_server` was present in the `content` field of the request.
|
Clarify that the `event` field of the `/v2/send_join` response is only required when the event is signed by the resident server.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Clarify that the `event` field of the `/v2/send_join` response is only required when the event is signed by the resident server.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Replace references to RFC 7235 and RFC 7230 that are obsoleted by RFC 9110.
|
||||||
|
|
@ -37,6 +37,10 @@ description = "Home of the Matrix specification for decentralised communication"
|
||||||
weight = 30
|
weight = 30
|
||||||
|
|
||||||
[markup]
|
[markup]
|
||||||
|
[markup.tableOfContents]
|
||||||
|
startLevel = 2
|
||||||
|
endLevel = 6
|
||||||
|
ordered = true
|
||||||
[markup.goldmark]
|
[markup.goldmark]
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
# Enables us to render raw HTML
|
# Enables us to render raw HTML
|
||||||
|
|
@ -130,7 +134,7 @@ sidebar_menu_compact = true
|
||||||
[module]
|
[module]
|
||||||
[module.hugoVersion]
|
[module.hugoVersion]
|
||||||
extended = true
|
extended = true
|
||||||
min = "0.113.0"
|
min = "0.117.0"
|
||||||
[[module.imports]]
|
[[module.imports]]
|
||||||
path = "github.com/matrix-org/docsy"
|
path = "github.com/matrix-org/docsy"
|
||||||
disable = false
|
disable = false
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,20 @@ recommended outside test environments.
|
||||||
Clients are authenticated using opaque `access_token` strings (see [Client
|
Clients are authenticated using opaque `access_token` strings (see [Client
|
||||||
Authentication](#client-authentication) for details).
|
Authentication](#client-authentication) for details).
|
||||||
|
|
||||||
All `POST` and `PUT` endpoints, with the exception of [`POST
|
All `POST` and `PUT` endpoints, with the exception of those listed below,
|
||||||
/_matrix/media/v3/upload`](#post_matrixmediav3upload) and [`PUT
|
|
||||||
/_matrix/media/v3/upload/{serverName}/{mediaId}`](#put_matrixmediav3uploadservernamemediaid),
|
|
||||||
require the client to supply a request body containing a (potentially empty)
|
require the client to supply a request body containing a (potentially empty)
|
||||||
JSON object. Clients should supply a `Content-Type` header of
|
JSON object. Clients should supply a `Content-Type` header of
|
||||||
`application/json` for all requests with JSON bodies, but this is not required.
|
`application/json` for all requests with JSON bodies, but this is not required.
|
||||||
|
|
||||||
|
The exceptions are:
|
||||||
|
|
||||||
|
- [`POST /_matrix/media/v3/upload`](#post_matrixmediav3upload) and
|
||||||
|
[`PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`](#put_matrixmediav3uploadservernamemediaid),
|
||||||
|
both of which take the uploaded media as the request body.
|
||||||
|
- [`POST /_matrix/client/v3/logout`](#post_matrixclientv3logout) and
|
||||||
|
[`POST /_matrix/client/v3/logout/all`](#post_matrixclientv3logoutall),
|
||||||
|
which take an empty request body.
|
||||||
|
|
||||||
Similarly, all endpoints require the server to return a JSON object,
|
Similarly, all endpoints require the server to return a JSON object,
|
||||||
with the exception of 200 responses to
|
with the exception of 200 responses to
|
||||||
[`GET /_matrix/media/v3/download/{serverName}/{mediaId}`](#get_matrixmediav3downloadservernamemediaid)
|
[`GET /_matrix/media/v3/download/{serverName}/{mediaId}`](#get_matrixmediav3downloadservernamemediaid)
|
||||||
|
|
@ -227,7 +234,7 @@ return a standard error response of the form:
|
||||||
```
|
```
|
||||||
|
|
||||||
Homeservers SHOULD include a [`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after)
|
Homeservers SHOULD include a [`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after)
|
||||||
for any response with a 429 status code.
|
header for any response with a 429 status code.
|
||||||
|
|
||||||
The `retry_after_ms` property MAY be included to tell the client how long
|
The `retry_after_ms` property MAY be included to tell the client how long
|
||||||
they have to wait in milliseconds before they can try again. This property is
|
they have to wait in milliseconds before they can try again. This property is
|
||||||
|
|
@ -2316,7 +2323,7 @@ following endpoint.
|
||||||
This endpoint is particularly useful if the client has lost context on the aggregation for
|
This endpoint is particularly useful if the client has lost context on the aggregation for
|
||||||
a parent event and needs to rebuild/verify it.
|
a parent event and needs to rebuild/verify it.
|
||||||
|
|
||||||
When using the `recurse` parameter, note that there no way for a client to
|
When using the `recurse` parameter, note that there is no way for a client to
|
||||||
control how far the server recurses. If the client decides that the server's
|
control how far the server recurses. If the client decides that the server's
|
||||||
recursion level is insufficient, it could, for example, perform the recursion
|
recursion level is insufficient, it could, for example, perform the recursion
|
||||||
itself, or disable whatever feature requires more recursion.
|
itself, or disable whatever feature requires more recursion.
|
||||||
|
|
@ -2805,42 +2812,42 @@ operations and run in a resource constrained environment. Like embedded
|
||||||
applications, they are not intended to be fully-fledged communication
|
applications, they are not intended to be fully-fledged communication
|
||||||
systems.
|
systems.
|
||||||
|
|
||||||
{{< cs-module name="instant_messaging" >}}
|
{{% cs-module name="instant_messaging" %}}
|
||||||
{{< cs-module name="rich_replies" >}}
|
{{% cs-module name="rich_replies" %}}
|
||||||
{{< cs-module name="voip_events" >}}
|
{{% cs-module name="voip_events" %}}
|
||||||
{{< cs-module name="typing_notifications" >}}
|
{{% cs-module name="typing_notifications" %}}
|
||||||
{{< cs-module name="receipts" >}}
|
{{% cs-module name="receipts" %}}
|
||||||
{{< cs-module name="read_markers" >}}
|
{{% cs-module name="read_markers" %}}
|
||||||
{{< cs-module name="presence" >}}
|
{{% cs-module name="presence" %}}
|
||||||
{{< cs-module name="content_repo" >}}
|
{{% cs-module name="content_repo" %}}
|
||||||
{{< cs-module name="send_to_device" >}}
|
{{% cs-module name="send_to_device" %}}
|
||||||
{{< cs-module name="device_management" >}}
|
{{% cs-module name="device_management" %}}
|
||||||
{{< cs-module name="end_to_end_encryption" >}}
|
{{% cs-module name="end_to_end_encryption" %}}
|
||||||
{{< cs-module name="secrets" >}}
|
{{% cs-module name="secrets" %}}
|
||||||
{{< cs-module name="history_visibility" >}}
|
{{% cs-module name="history_visibility" %}}
|
||||||
{{< cs-module name="push" >}}
|
{{% cs-module name="push" %}}
|
||||||
{{< cs-module name="third_party_invites" >}}
|
{{% cs-module name="third_party_invites" %}}
|
||||||
{{< cs-module name="search" >}}
|
{{% cs-module name="search" %}}
|
||||||
{{< cs-module name="guest_access" >}}
|
{{% cs-module name="guest_access" %}}
|
||||||
{{< cs-module name="room_previews" >}}
|
{{% cs-module name="room_previews" %}}
|
||||||
{{< cs-module name="tags" >}}
|
{{% cs-module name="tags" %}}
|
||||||
{{< cs-module name="account_data" >}}
|
{{% cs-module name="account_data" %}}
|
||||||
{{< cs-module name="admin" >}}
|
{{% cs-module name="admin" %}}
|
||||||
{{< cs-module name="event_context" >}}
|
{{% cs-module name="event_context" %}}
|
||||||
{{< cs-module name="sso_login" >}}
|
{{% cs-module name="sso_login" %}}
|
||||||
{{< cs-module name="dm" >}}
|
{{% cs-module name="dm" %}}
|
||||||
{{< cs-module name="ignore_users" >}}
|
{{% cs-module name="ignore_users" %}}
|
||||||
{{< cs-module name="stickers" >}}
|
{{% cs-module name="stickers" %}}
|
||||||
{{< cs-module name="report_content" >}}
|
{{% cs-module name="report_content" %}}
|
||||||
{{< cs-module name="third_party_networks" >}}
|
{{% cs-module name="third_party_networks" %}}
|
||||||
{{< cs-module name="openid" >}}
|
{{% cs-module name="openid" %}}
|
||||||
{{< cs-module name="server_acls" >}}
|
{{% cs-module name="server_acls" %}}
|
||||||
{{< cs-module name="mentions" >}}
|
{{% cs-module name="mentions" %}}
|
||||||
{{< cs-module name="room_upgrades" >}}
|
{{% cs-module name="room_upgrades" %}}
|
||||||
{{< cs-module name="server_notices" >}}
|
{{% cs-module name="server_notices" %}}
|
||||||
{{< cs-module name="moderation_policies" >}}
|
{{% cs-module name="moderation_policies" %}}
|
||||||
{{< cs-module name="spaces" >}}
|
{{% cs-module name="spaces" %}}
|
||||||
{{< cs-module name="event_replacements" >}}
|
{{% cs-module name="event_replacements" %}}
|
||||||
{{< cs-module name="event_annotations" >}}
|
{{% cs-module name="event_annotations" %}}
|
||||||
{{< cs-module name="threading" >}}
|
{{% cs-module name="threading" %}}
|
||||||
{{< cs-module name="reference_relations" >}}
|
{{% cs-module name="reference_relations" %}}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ The `redacts` property of `m.room.redaction` events is moved from a top-level
|
||||||
event property to a property under the event `content`.
|
event property to a property under the event `content`.
|
||||||
|
|
||||||
For backwards-compatibility with older clients, servers should add a `redacts` property
|
For backwards-compatibility with older clients, servers should add a `redacts` property
|
||||||
to the top level of `m.room.redaction` events in when serving such events over the
|
to the top level of `m.room.redaction` events when serving such events over the
|
||||||
Client-Server API.
|
Client-Server API.
|
||||||
|
|
||||||
For improved compatibility with newer clients, servers should add a `redacts` property
|
For improved compatibility with newer clients, servers should add a `redacts` property
|
||||||
|
|
|
||||||
|
|
@ -349,14 +349,14 @@ def authorization_headers(origin_name, origin_signing_key,
|
||||||
```
|
```
|
||||||
|
|
||||||
The format of the Authorization header is given in
|
The format of the Authorization header is given in
|
||||||
[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1). In
|
[Section 11.4 of RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#section-11.4). In
|
||||||
summary, the header begins with authorization scheme `X-Matrix`, followed by one
|
summary, the header begins with authorization scheme `X-Matrix`, followed by one
|
||||||
or more spaces, followed by a comma-separated list of parameters written as
|
or more spaces, followed by a comma-separated list of parameters written as
|
||||||
name=value pairs. Zero or more spaces and tabs around each comma are allowed.
|
name=value pairs. Zero or more spaces and tabs around each comma are allowed.
|
||||||
The names are case insensitive and order does not matter. The
|
The names are case insensitive and order does not matter. The
|
||||||
values must be enclosed in quotes if they contain characters that are not
|
values must be enclosed in quotes if they contain characters that are not
|
||||||
allowed in `token`s, as defined in
|
allowed in `token`s, as defined in
|
||||||
[RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6); if a
|
[Section 5.6.2 of RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2); if a
|
||||||
value is a valid `token`, it may or may not be enclosed in quotes. Quoted
|
value is a valid `token`, it may or may not be enclosed in quotes. Quoted
|
||||||
values may include backslash-escaped characters. When parsing the header, the
|
values may include backslash-escaped characters. When parsing the header, the
|
||||||
recipient must unescape the characters. That is, a backslash-character pair is
|
recipient must unescape the characters. That is, a backslash-character pair is
|
||||||
|
|
@ -388,6 +388,13 @@ The authorization parameters to include are:
|
||||||
|
|
||||||
Unknown parameters are ignored.
|
Unknown parameters are ignored.
|
||||||
|
|
||||||
|
{{% boxes/note %}}
|
||||||
|
{{< changed-in v="1.11" >}}
|
||||||
|
This section used to reference [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1)
|
||||||
|
and [RFC 7230](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.2), that
|
||||||
|
were obsoleted by RFC 9110 without changes to the sections of interest here.
|
||||||
|
{{% /boxes/note %}}
|
||||||
|
|
||||||
### Response Authentication
|
### Response Authentication
|
||||||
|
|
||||||
Responses are authenticated by the TLS server certificate. A homeserver
|
Responses are authenticated by the TLS server certificate. A homeserver
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,26 @@ paths:
|
||||||
/keys/device_signing/upload:
|
/keys/device_signing/upload:
|
||||||
post:
|
post:
|
||||||
x-addedInMatrixVersion: "1.1"
|
x-addedInMatrixVersion: "1.1"
|
||||||
|
x-changedInMatrixVersion:
|
||||||
|
"1.11": UIA is not always required for this endpoint.
|
||||||
summary: Upload cross-signing keys.
|
summary: Upload cross-signing keys.
|
||||||
description: |-
|
description: |-
|
||||||
Publishes cross-signing keys for the user.
|
Publishes cross-signing keys for the user.
|
||||||
|
|
||||||
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
|
This API endpoint uses the [User-Interactive Authentication API](/client-server-api/#user-interactive-authentication-api).
|
||||||
|
|
||||||
|
User-Interactive Authentication MUST be performed, except in these cases:
|
||||||
|
- there is no existing cross-signing master key uploaded to the homeserver, OR
|
||||||
|
- there is an existing cross-signing master key and it exactly matches the
|
||||||
|
cross-signing master key provided in the request body. If there are any additional
|
||||||
|
keys provided in the request (self-signing key, user-signing key) they MUST also
|
||||||
|
match the existing keys stored on the server. In other words, the request contains
|
||||||
|
no new keys.
|
||||||
|
|
||||||
|
This allows clients to freely upload one set of keys, but not modify/overwrite keys if
|
||||||
|
they already exist. Allowing clients to upload the same set of keys more than once
|
||||||
|
makes this endpoint idempotent in the case where the response is lost over the network,
|
||||||
|
which would otherwise cause a UIA challenge upon retry.
|
||||||
operationId: uploadCrossSigningKeys
|
operationId: uploadCrossSigningKeys
|
||||||
security:
|
security:
|
||||||
- accessTokenQuery: []
|
- accessTokenQuery: []
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ properties:
|
||||||
"origin_server_ts": 1632491098485,
|
"origin_server_ts": 1632491098485,
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1257,
|
"age": 1257,
|
||||||
|
"membership": "leave"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transaction_id:
|
transaction_id:
|
||||||
|
|
@ -112,3 +113,23 @@ properties:
|
||||||
this.
|
this.
|
||||||
title: EventContent
|
title: EventContent
|
||||||
type: object
|
type: object
|
||||||
|
membership:
|
||||||
|
description: |
|
||||||
|
The room membership of the user making the request, at the time of the event.
|
||||||
|
|
||||||
|
This property is the value of the `membership` property of the
|
||||||
|
requesting user's [`m.room.member`](/client-server-api#mroommember)
|
||||||
|
state at the point of the event, including any changes caused by the
|
||||||
|
event. If the user had yet to join the room at the time of the event
|
||||||
|
(i.e, they have no `m.room.member` state), this property is set to
|
||||||
|
`leave`.
|
||||||
|
|
||||||
|
Homeservers SHOULD populate this property
|
||||||
|
wherever practical, but they MAY omit it if necessary (for example,
|
||||||
|
if calculating the value is expensive, servers might choose to only
|
||||||
|
implement it in encrypted rooms). The property is *not* normally populated
|
||||||
|
in events pushed to application services via the application service transaction API
|
||||||
|
(where there is no clear definition of "requesting user").
|
||||||
|
type: string
|
||||||
|
example: join
|
||||||
|
x-addedInMatrixVersion: "1.11"
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ paths:
|
||||||
intend to log in multiple devices must generate a token for each.
|
intend to log in multiple devices must generate a token for each.
|
||||||
|
|
||||||
With other User-Interactive Authentication (UIA)-supporting endpoints, servers sometimes do not re-prompt
|
With other User-Interactive Authentication (UIA)-supporting endpoints, servers sometimes do not re-prompt
|
||||||
for verification if the session recently passed UIA. For this endpoint, servers should always re-prompt
|
for verification if the session recently passed UIA. For this endpoint, servers MUST always re-prompt
|
||||||
the user for verification to ensure explicit consent is gained for each additional client.
|
the user for verification to ensure explicit consent is gained for each additional client.
|
||||||
|
|
||||||
Servers are encouraged to apply stricter than normal rate limiting to this endpoint, such as maximum
|
Servers are encouraged to apply stricter than normal rate limiting to this endpoint, such as maximum
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,7 @@ components:
|
||||||
Whether to additionally include events which only relate indirectly to the
|
Whether to additionally include events which only relate indirectly to the
|
||||||
given event, i.e. events related to the given event via two or more direct relationships.
|
given event, i.e. events related to the given event via two or more direct relationships.
|
||||||
|
|
||||||
If set to `false`, only events which have direct a relation with the given
|
If set to `false`, only events which have a direct relation with the given
|
||||||
event will be included.
|
event will be included.
|
||||||
|
|
||||||
If set to `true`, all events which relate to the given event, or relate to
|
If set to `true`, all events which relate to the given event, or relate to
|
||||||
|
|
|
||||||
|
|
@ -207,9 +207,9 @@ paths:
|
||||||
title: SignedMembershipEvent
|
title: SignedMembershipEvent
|
||||||
x-addedInMatrixVersion: "1.2"
|
x-addedInMatrixVersion: "1.2"
|
||||||
description: |-
|
description: |-
|
||||||
Required if the `content` of the event in the request contained the `join_authorised_via_users_server`
|
The membership event sent to other servers by the resident server including a signature
|
||||||
field. The signed copy of the membership event sent to other servers by the resident server,
|
from the resident server. Required if the room is [restricted](/client-server-api/#restricted-rooms)
|
||||||
including the resident server's signature.
|
and the joining user is authorised by one of the conditions.
|
||||||
servers_in_room:
|
servers_in_room:
|
||||||
type: array
|
type: array
|
||||||
x-addedInMatrixVersion: "1.6"
|
x-addedInMatrixVersion: "1.6"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
"origin_server_ts": 1432735824653,
|
"origin_server_ts": 1432735824653,
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1234
|
"age": 1234,
|
||||||
|
"membership": "join"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@
|
||||||
*/}}
|
*/}}
|
||||||
{{ if reflect.IsMap $this_object.items }}
|
{{ if reflect.IsMap $this_object.items }}
|
||||||
{{ $items_example := partial "json-schema/resolve-example" $this_object.items }}
|
{{ $items_example := partial "json-schema/resolve-example" $this_object.items }}
|
||||||
{{ $example = slice $items_example }}
|
{{ if $items_example }}
|
||||||
{{ else }}
|
{{ $example = slice $items_example }}
|
||||||
{{ $example = slice }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
|
||||||
83
layouts/partials/sidebar-tree.html
Normal file
83
layouts/partials/sidebar-tree.html
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
{{/*
|
||||||
|
|
||||||
|
A modified version of the siderbar-tree.html partial in Docsy, adding:
|
||||||
|
|
||||||
|
* The "toc.html" partial at L45.
|
||||||
|
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{/* We cache this partial for bigger sites and set the active class client side. */ -}}
|
||||||
|
{{ $sidebarCacheLimit := .Site.Params.ui.sidebar_cache_limit | default 2000 -}}
|
||||||
|
{{ $shouldDelayActive := ge (len .Site.Pages) $sidebarCacheLimit -}}
|
||||||
|
<div id="td-sidebar-menu" class="td-sidebar__inner{{ if $shouldDelayActive }} d-none{{ end }}">
|
||||||
|
{{ if not .Site.Params.ui.sidebar_search_disable -}}
|
||||||
|
<form class="td-sidebar__search d-flex align-items-center">
|
||||||
|
{{ partial "search-input.html" . }}
|
||||||
|
<button class="btn btn-link td-sidebar__toggle d-md-none p-0 ms-3 fas fa-bars" type="button" data-bs-toggle="collapse" data-bs-target="#td-section-nav" aria-controls="td-section-nav" aria-expanded="false" aria-label="Toggle section navigation">
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{{ else -}}
|
||||||
|
<div id="content-mobile">
|
||||||
|
<form class="td-sidebar__search d-flex align-items-center">
|
||||||
|
{{ partial "search-input.html" . }}
|
||||||
|
<button class="btn btn-link td-sidebar__toggle d-md-none p-0 ms-3 fas fa-bars" type="button" data-bs-toggle="collapse" data-bs-target="#td-section-nav" aria-controls="td-section-nav" aria-expanded="false" aria-label="Toggle section navigation">
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="content-desktop"></div>
|
||||||
|
{{ end -}}
|
||||||
|
<nav class="td-sidebar-nav collapse
|
||||||
|
{{- if .Site.Params.ui.sidebar_search_disable }} td-sidebar-nav--search-disabled{{ end -}}
|
||||||
|
{{- if .Site.Params.ui.sidebar_menu_foldable }} foldable-nav{{ end -}}
|
||||||
|
" id="td-section-nav">
|
||||||
|
{{ if (gt (len .Site.Home.Translations) 0) -}}
|
||||||
|
<div class="td-sidebar-nav__section nav-item dropdown d-block d-lg-none">
|
||||||
|
{{ partial "navbar-lang-selector.html" . }}
|
||||||
|
</div>
|
||||||
|
{{ end -}}
|
||||||
|
{{ $navRoot := cond (and (ne .Params.toc_root true) (eq .Site.Home.Type "docs")) .Site.Home .FirstSection -}}
|
||||||
|
{{ $ulNr := 0 -}}
|
||||||
|
{{ $ulShow := .Site.Params.ui.ul_show | default 1 -}}
|
||||||
|
{{ $sidebarMenuTruncate := .Site.Params.ui.sidebar_menu_truncate | default 50 -}}
|
||||||
|
<ul class="td-sidebar-nav__section pe-md-3 ul-{{ $ulNr }}">
|
||||||
|
{{ template "section-tree-nav-section" (dict "page" . "section" $navRoot "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" (add $ulShow 1)) }}
|
||||||
|
</ul>
|
||||||
|
{{ partial "toc.html" . }}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{{ define "section-tree-nav-section" -}}
|
||||||
|
{{ $s := .section -}}
|
||||||
|
{{ $p := .page -}}
|
||||||
|
{{ $shouldDelayActive := .shouldDelayActive -}}
|
||||||
|
{{ $sidebarMenuTruncate := .sidebarMenuTruncate -}}
|
||||||
|
{{ $treeRoot := cond (eq .ulNr 0) true false -}}
|
||||||
|
{{ $ulNr := .ulNr -}}
|
||||||
|
{{ $ulShow := .ulShow -}}
|
||||||
|
{{ $active := and (not $shouldDelayActive) (eq $s $p) -}}
|
||||||
|
{{ $activePath := and (not $shouldDelayActive) (or (eq $p $s) ($p.IsDescendant $s)) -}}
|
||||||
|
{{ $show := cond (or (lt $ulNr $ulShow) $activePath (and (not $shouldDelayActive) (eq $s.Parent $p.Parent)) (and (not $shouldDelayActive) (eq $s.Parent $p)) (not $p.Site.Params.ui.sidebar_menu_compact) (and (not $shouldDelayActive) ($p.IsDescendant $s.Parent))) true false -}}
|
||||||
|
{{ $mid := printf "m-%s" ($s.RelPermalink | anchorize) -}}
|
||||||
|
{{ $pages_tmp := where (union $s.Pages $s.Sections).ByWeight ".Params.toc_hide" "!=" true -}}
|
||||||
|
{{ $pages := $pages_tmp | first $sidebarMenuTruncate -}}
|
||||||
|
{{ $withChild := gt (len $pages) 0 -}}
|
||||||
|
{{ $manualLink := cond (isset $s.Params "manuallink") $s.Params.manualLink ( cond (isset $s.Params "manuallinkrelref") (relref $s $s.Params.manualLinkRelref) $s.RelPermalink) -}}
|
||||||
|
{{ $manualLinkTitle := cond (isset $s.Params "manuallinktitle") $s.Params.manualLinkTitle $s.Title -}}
|
||||||
|
<li class="td-sidebar-nav__section-title td-sidebar-nav__section{{ if $withChild }} with-child{{ else }} without-child{{ end }}{{ if $activePath }} active-path{{ end }}{{ if (not (or $show $p.Site.Params.ui.sidebar_menu_foldable )) }} collapse{{ end }}" id="{{ $mid }}-li">
|
||||||
|
{{ if (and $p.Site.Params.ui.sidebar_menu_foldable (ge $ulNr 1)) -}}
|
||||||
|
<input type="checkbox" id="{{ $mid }}-check"{{ if $activePath}} checked{{ end }}/>
|
||||||
|
<label for="{{ $mid }}-check"><a href="{{ $manualLink }}"{{ if ne $s.LinkTitle $manualLinkTitle }} title="{{ $manualLinkTitle }}"{{ end }}{{ with $s.Params.manualLinkTarget }} target="{{ . }}"{{ if eq . "_blank" }} rel="noopener"{{ end }}{{ end }} class="align-left ps-0 {{ if $active}} active{{ end }} td-sidebar-link{{ if $s.IsPage }} td-sidebar-link__page{{ else }} td-sidebar-link__section{{ end }}{{ if $treeRoot }} tree-root{{ end }}" id="{{ $mid }}">{{ with $s.Params.Icon}}<i class="{{ . }}"></i>{{ end }}<span class="{{ if $active }}td-sidebar-nav-active-item{{ end }}">{{ $s.LinkTitle }}</span></a></label>
|
||||||
|
{{ else -}}
|
||||||
|
<a href="{{ $manualLink }}"{{ if ne $s.LinkTitle $manualLinkTitle }} title="{{ $manualLinkTitle }}"{{ end }}{{ with $s.Params.manualLinkTarget }} target="{{ . }}"{{ if eq . "_blank" }} rel="noopener"{{ end }}{{ end }} class="align-left ps-0{{ if $active}} active{{ end }} td-sidebar-link{{ if $s.IsPage }} td-sidebar-link__page{{ else }} td-sidebar-link__section{{ end }}{{ if $treeRoot }} tree-root{{ end }}" id="{{ $mid }}">{{ with $s.Params.Icon}}<i class="{{ . }}"></i>{{ end }}<span class="{{ if $active }}td-sidebar-nav-active-item{{ end }}">{{ $s.LinkTitle }}</span></a>
|
||||||
|
{{- end }}
|
||||||
|
{{- if $withChild }}
|
||||||
|
{{- $ulNr := add $ulNr 1 }}
|
||||||
|
<ul class="ul-{{ $ulNr }}{{ if (gt $ulNr 1)}} foldable{{end}}">
|
||||||
|
{{ range $pages -}}
|
||||||
|
{{ if (not (and (eq $s $p.Site.Home) (eq .Params.toc_root true))) -}}
|
||||||
|
{{ template "section-tree-nav-section" (dict "page" $p "section" . "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" $ulShow) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
</ul>
|
||||||
|
{{- end }}
|
||||||
|
</li>
|
||||||
|
{{- end }}
|
||||||
15
layouts/partials/toc.html
Normal file
15
layouts/partials/toc.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{{/*
|
||||||
|
|
||||||
|
A modified version of the toc.html partial in Docsy.
|
||||||
|
|
||||||
|
*/}}
|
||||||
|
{{ $page := .Params }}
|
||||||
|
{{ if not .Params.notoc -}}
|
||||||
|
{{ with .TableOfContents -}}
|
||||||
|
<hr>
|
||||||
|
<div id="toc">
|
||||||
|
<a id="toc-title" href="#">{{ $page.Title }}</a>
|
||||||
|
{{ . }}
|
||||||
|
</div>
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
@ -5,6 +5,6 @@
|
||||||
|
|
||||||
{{ with .Page.Resources.Match "*.md" }}
|
{{ with .Page.Resources.Match "*.md" }}
|
||||||
{{ range ((sort . "Params.date" "desc")) }}
|
{{ range ((sort . "Params.date" "desc")) }}
|
||||||
{{ .Content }}
|
{{ .RenderShortcodes }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@
|
||||||
|
|
||||||
{{ with .Site.GetPage "client-server-api/modules" }}
|
{{ with .Site.GetPage "client-server-api/modules" }}
|
||||||
{{ with .Resources.GetMatch (printf "%s%s" $name ".md") }}
|
{{ with .Resources.GetMatch (printf "%s%s" $name ".md") }}
|
||||||
{{ .Content }}
|
{{ .RenderShortcodes }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
170
static/js/toc.js
170
static/js/toc.js
|
|
@ -14,174 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
Account for id attributes that are in the sidebar nav
|
|
||||||
*/
|
|
||||||
function populateIds() {
|
|
||||||
const navItems = document.querySelectorAll(".td-sidebar-nav li");
|
|
||||||
return Array.from(navItems).map(item => item.id).filter(id => id != "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Given an ID and an array of IDs, return s version of the original ID that's
|
|
||||||
not equal to any of the IDs in the array.
|
|
||||||
*/
|
|
||||||
function uniquifyHeadingId(id, uniqueIDs) {
|
|
||||||
const baseId = id;
|
|
||||||
let counter = 0;
|
|
||||||
while (uniqueIDs.includes(id)) {
|
|
||||||
counter = counter + 1;
|
|
||||||
id = baseId + "-" + counter.toString();
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Given an array of heading nodes, ensure they all have unique IDs.
|
|
||||||
|
|
||||||
We have to do this mostly because of client-server modules, which are
|
|
||||||
rendered separately then glued together with a template.
|
|
||||||
Because heading IDs are generated in rendering, this means they can and will
|
|
||||||
end up with duplicate IDs.
|
|
||||||
*/
|
|
||||||
function uniquifyHeadingIds(headings) {
|
|
||||||
const uniqueIDs = populateIds();
|
|
||||||
for (let heading of headings) {
|
|
||||||
const uniqueID = uniquifyHeadingId(heading.id, uniqueIDs);
|
|
||||||
uniqueIDs.push(uniqueID);
|
|
||||||
heading.id = uniqueID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The document contains "normal" headings, and these have corresponding items
|
|
||||||
in the ToC.
|
|
||||||
|
|
||||||
The document might also contain H1 headings that act as titles for blocks of
|
|
||||||
rendered data, like HTTP APIs or event schemas. Unlike "normal" headings,
|
|
||||||
these headings don't appear in the ToC. But they do have anchor IDs to enable
|
|
||||||
links to them. When someone follows a link to one of these "rendered data"
|
|
||||||
headings we want to scroll the ToC to the item corresponding to the "normal"
|
|
||||||
heading preceding the "rendered data" heading we have visited.
|
|
||||||
|
|
||||||
To support this we need to add `data` attributes to ToC items.
|
|
||||||
These attributes identify which "rendered data" headings live underneath
|
|
||||||
the heading corresponding to that ToC item.
|
|
||||||
*/
|
|
||||||
function setTocItemChildren(toc, headings) {
|
|
||||||
let tocEntryForHeading = null;
|
|
||||||
for (const heading of headings) {
|
|
||||||
// H1 headings are rendered-data headings
|
|
||||||
if (heading.tagName !== "H1") {
|
|
||||||
tocEntryForHeading = document.querySelector(`nav li a[href="#${heading.id}"]`);
|
|
||||||
} else {
|
|
||||||
// on the ToC entry for the parent heading,
|
|
||||||
// set a data-* attribute whose name is the child's fragment ID
|
|
||||||
tocEntryForHeading.setAttribute(`data-${heading.id}`, "true");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Generate a table of contents based on the headings in the document.
|
|
||||||
*/
|
|
||||||
function makeToc() {
|
|
||||||
|
|
||||||
// make the title from the H1
|
|
||||||
const h1 = document.body.querySelector("h1");
|
|
||||||
const title = document.createElement("a");
|
|
||||||
title.id = "toc-title";
|
|
||||||
title.setAttribute("href", "#");
|
|
||||||
title.textContent = h1.textContent;
|
|
||||||
|
|
||||||
// make the content
|
|
||||||
const content = document.body.querySelector(".td-content");
|
|
||||||
let headings = [].slice.call(content.querySelectorAll("h2, h3, h4, h5, h6, .rendered-data > details > summary > h1"));
|
|
||||||
|
|
||||||
// exclude headings that don't have IDs.
|
|
||||||
headings = headings.filter(heading => heading.id);
|
|
||||||
uniquifyHeadingIds(headings);
|
|
||||||
|
|
||||||
// exclude .rendered-data > h1 headings from the ToC
|
|
||||||
const tocTargets = headings.filter(heading => heading.tagName !== "H1");
|
|
||||||
|
|
||||||
// we have to adjust heading IDs to ensure that they are unique
|
|
||||||
const nav = document.createElement("nav");
|
|
||||||
nav.id = "TableOfContents";
|
|
||||||
|
|
||||||
const section = makeTocSection(tocTargets, 0);
|
|
||||||
nav.appendChild(section.content);
|
|
||||||
// build the TOC and append to it title and content
|
|
||||||
const toc = document.createElement("div");
|
|
||||||
toc.id = "toc";
|
|
||||||
toc.appendChild(title);
|
|
||||||
toc.appendChild(nav);
|
|
||||||
|
|
||||||
// append TOC to the section navigation
|
|
||||||
const section_nav = document.body.querySelector("#td-section-nav");
|
|
||||||
let hr = document.createElement("hr");
|
|
||||||
section_nav.appendChild(hr);
|
|
||||||
section_nav.appendChild(toc);
|
|
||||||
|
|
||||||
// tell ToC items about any rendered-data headings they contain
|
|
||||||
setTocItemChildren(section.content, headings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a single ToC entry
|
|
||||||
function makeTocEntry(heading) {
|
|
||||||
const li = document.createElement("li");
|
|
||||||
const a = document.createElement("a");
|
|
||||||
a.setAttribute("href", `#${heading.id}`);
|
|
||||||
a.textContent = heading.textContent;
|
|
||||||
li.appendChild(a);
|
|
||||||
return li;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Each ToC section is an `<ol>` element.
|
|
||||||
ToC entries are `<li>` elements and these contain nested ToC sections,
|
|
||||||
whenever we go to the next heading level down.
|
|
||||||
*/
|
|
||||||
function makeTocSection(headings, index) {
|
|
||||||
const ol = document.createElement("ol");
|
|
||||||
let previousHeading = null;
|
|
||||||
let previousLi = null;
|
|
||||||
let i = index;
|
|
||||||
const lis = [];
|
|
||||||
for (i; i < headings.length; i++) {
|
|
||||||
const thisHeading = headings[i];
|
|
||||||
if (previousHeading && (thisHeading.tagName > previousHeading.tagName)) {
|
|
||||||
// we are going down a heading level, create a new nested section
|
|
||||||
const section = makeTocSection(headings, i);
|
|
||||||
previousLi.appendChild(section.content);
|
|
||||||
i = section.index -1;
|
|
||||||
}
|
|
||||||
else if (previousHeading && (previousHeading.tagName > thisHeading.tagName)) {
|
|
||||||
// we have come back up a level, so a section is finished
|
|
||||||
for (let li of lis) {
|
|
||||||
ol.appendChild(li);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
content: ol,
|
|
||||||
index: i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we are still processing this section, so add this heading to the current section
|
|
||||||
previousLi = makeTocEntry(thisHeading);
|
|
||||||
lis.push(previousLi);
|
|
||||||
previousHeading = thisHeading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let li of lis) {
|
|
||||||
ol.appendChild(li);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
content: ol,
|
|
||||||
index: i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set a new ToC entry.
|
Set a new ToC entry.
|
||||||
Clear any previously highlighted ToC items, set the new one,
|
Clear any previously highlighted ToC items, set the new one,
|
||||||
|
|
@ -303,8 +135,6 @@ for the corresponding ToC entry.
|
||||||
*/
|
*/
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
makeToc();
|
|
||||||
|
|
||||||
const toc = document.querySelector("#toc");
|
const toc = document.querySelector("#toc");
|
||||||
toc.addEventListener("click", event => {
|
toc.addEventListener("click", event => {
|
||||||
if (event.target.tagName === "A") {
|
if (event.target.tagName === "A") {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue