Merge branch 'main'

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille 2026-01-21 09:43:56 +01:00
commit a26024107e
No known key found for this signature in database
GPG key ID: F26F4BE20A08255B
130 changed files with 1489 additions and 1547 deletions

View file

@ -1,8 +1,9 @@
name: "Spec"
env:
HUGO_VERSION: 0.148.1
HUGO_VERSION: 0.153.3
PYTHON_VERSION: 3.13
NODE_VERSION: 24
on:
push:
@ -27,7 +28,7 @@ jobs:
- name: " Setup Node"
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: ${{ env.NODE_VERSION }}
- name: "🔎 Run validator"
run: |
npx @redocly/cli@latest lint data/api/*/*.yaml
@ -195,11 +196,13 @@ jobs:
needs: [calculate-baseurl, build-openapi, generate-changelog]
# run even if generate-changelog was skipped
if: ${{ always() }}
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
steps:
- name: " Setup Node"
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: ${{ env.NODE_VERSION }}
- name: " Setup Hugo"
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
with:
@ -217,8 +220,10 @@ jobs:
with:
name: changelog-artifact
path: content/changelog
- name: "⚙️ hugo"
run: hugo --baseURL "${{ needs.calculate-baseurl.outputs.baseURL }}" -d "spec"
run: hugo --baseURL "${baseURL}" -d "spec${baseURL}"
# We manually unpack the spec OpenAPI definition JSON to the website tree
# to make it available to the world in a canonical place:
# https://spec.matrix.org/latest/client-server-api/api.json
@ -229,10 +234,13 @@ jobs:
name: openapi-artifact
- name: "📝 Unpack the OpenAPI definitions in the right location"
run: |
tar -xzf openapi.tar.gz
tar -C "spec${baseURL}" --strip-components=1 -xzf openapi.tar.gz
- name: "📦 Tarball creation"
run: tar -czf spec.tar.gz spec
run: |
cd spec
tar -czf ../spec.tar.gz *
- name: "📤 Artifact upload"
uses: actions/upload-artifact@v4
with:
@ -243,6 +251,14 @@ jobs:
name: "🔎 Validate generated HTML"
runs-on: ubuntu-latest
needs: [calculate-baseurl, build-spec]
# Run even if `generate-changelog` was skipped.
#
# `build-spec` has a dependency on `generate-changelog` to ensure order of execution
# and to access `needs.generate-changelog.result`. However, `generate-changelog` is
# skipped on tag builds; even a transient dependency on `generate-changelog` is then
# enough for this step to also be skipped by default on tag builds. Hence the need for
# this explicit `if`.
if: ${{ !failure() && !cancelled() }}
steps:
- name: "📥 Source checkout"
uses: actions/checkout@v4
@ -253,14 +269,9 @@ jobs:
name: spec-artifact
- name: "📝 Unpack the spec"
# we have to unpack it into the right path given the baseurl, so that the
# links are correct.
# eg if baseurl is `/unstable`, we want to put the site in `spec/unstable`.
run: |
mkdir -p "spec${baseURL}"
tar -C "spec${baseURL}" --strip-components=1 -xvzf spec.tar.gz
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
mkdir spec
tar -C spec -xvzf spec.tar.gz
- name: "Run htmltest"
uses: wjdp/htmltest-action@master
@ -270,13 +281,15 @@ jobs:
build-historical-spec:
name: "📖 Build the historical backup spec"
runs-on: ubuntu-latest
needs: [build-openapi]
needs: [calculate-baseurl, build-openapi]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
steps:
- name: " Setup Node"
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: ${{ env.NODE_VERSION }}
- name: " Setup Hugo"
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
with:
@ -291,9 +304,8 @@ jobs:
- name: "⚙️ hugo"
env:
HUGO_PARAMS_VERSION_STATUS: "historical"
# Create a baseURL like `/v1.2` out of the `v1.2` tag
run: |
hugo --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec"
hugo --baseURL "${baseURL}" -d "spec${baseURL}"
- name: "📥 Spec definition download"
uses: actions/download-artifact@v4
@ -301,12 +313,51 @@ jobs:
name: openapi-artifact
- name: "📝 Unpack the OpenAPI definitions in the right location"
run: |
tar -xzf openapi.tar.gz
tar -C "spec${baseURL}" --strip-components=1 -xzf openapi.tar.gz
- name: "📦 Tarball creation"
run: tar -czf spec-historical.tar.gz spec
run: |
cd spec
tar -czf ../spec-historical.tar.gz *
- name: "📤 Artifact upload"
uses: actions/upload-artifact@v4
with:
name: spec-historical-artifact
path: spec-historical.tar.gz
# If we're building a tag, create a release and publish the artifacts
create_release:
name: "Create release"
if: ${{ !failure() && !cancelled() && startsWith(github.ref, 'refs/tags/') }}
needs:
- build-spec
- build-historical-spec
runs-on: ubuntu-latest
steps:
- name: "📥 Check out changelogs"
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
sparse-checkout: |
content/changelog
- name: "📥 Download built spec"
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: spec-artifact
- name: "📥 Download historical spec artifact"
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: spec-historical-artifact
- name: "✨ Create draft release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Remove front-matter from changelog
sed '1,/^---$/d' "content/changelog/${{ github.ref_name }}.md" > changelog.md
# Create a draft release, using the changelog as release notes, and attaching the spec artifacts.
gh release create -d -t "${{ github.ref_name }}" \
-F "changelog.md" \
"${{ github.ref_name }}" \
spec.tar.gz \
spec-historical.tar.gz

View file

@ -45,7 +45,9 @@ jobs:
name: spec-artifact
- name: "📦 Extract Artifacts"
run: tar -xzvf spec.tar.gz && rm spec.tar.gz
run: |
mkdir spec
tar -C spec -xzvf spec.tar.gz && rm spec.tar.gz
- name: "📤 Deploy to Netlify"
id: netlify

View file

@ -50,7 +50,7 @@ function getHeadings() {
let headings = [];
// First get the anchors in the ToC.
const toc_anchors = document.querySelectorAll("#toc nav a");
const toc_anchors = document.querySelectorAll("#TableOfContents a");
for (const anchor of toc_anchors) {
// Then get the heading from its selector in the anchor's href.
@ -59,7 +59,7 @@ function getHeadings() {
console.error("Got ToC anchor without href");
continue;
}
const heading = document.querySelector(selector);
if (!heading) {
console.error("Heading not found for selector:", selector);
@ -122,13 +122,13 @@ function getCurrentHeading(headings, headerOffset) {
*/
function selectTocEntry(id) {
// Deselect previously selected entries.
const activeEntries = document.querySelectorAll("#toc nav a.active");
const activeEntries = document.querySelectorAll("#TableOfContents a.active");
for (const activeEntry of activeEntries) {
activeEntry.classList.remove('active');
}
// Find the new entry and select it.
const newEntry = document.querySelector(`#toc nav a[href="#${id}"]`);
const newEntry = document.querySelector(`#TableOfContents a[href="#${id}"]`);
if (!newEntry) {
console.error("ToC entry not found for ID:", id);
return;

View file

@ -76,52 +76,126 @@ Custom SCSS for the Matrix spec
scroll-behavior: smooth;
overscroll-behavior: contain;
&>.td-sidebar-nav__section {
& > .td-sidebar-nav__section {
margin-top: 1rem;
}
.td-sidebar-nav__section .ul-1 ul {
padding-left: 0;
}
/* This is to make the width of the items that have sub-items (like room versions)
the same as the width of items that don't (like changelog) */
.pr-md-3, .px-md-3 {
padding-right: 0 !important;
}
.ul-1 > li > a {
padding-left: 1rem !important;
}
.ul-2 > li > a {
padding-left: 2rem !important;
}
a.td-sidebar-link.tree-root {
color: $gray-800;
font-weight: $font-weight-bold;
font-size: 1.3rem;
margin-bottom: 0;
border-bottom: none;
}
a, a.td-sidebar-link {
color: $gray-800;
font-weight: $font-weight-normal;
padding-top: .2rem;
padding-bottom: .2rem;
display: block;
transition: all 100ms ease-in-out;
&:hover {
background-color: $secondary-lighter-background;
color: $gray-800;
.ul-1 ul {
padding-left: 0;
}
&.active, &active:hover {
background-color: $secondary-background;
/* This is to make the width of the items that have sub-items (like room versions)
the same as the width of items that don't (like changelog) */
.pr-md-3, .px-md-3 {
padding-right: 0 !important;
}
.ul-1 > li > a {
padding-left: 1rem !important;
}
.ul-2 > li > a {
padding-left: 2rem !important;
}
}
/* Styles for the table of contents */
& > .td-toc {
padding-top: 1rem;
padding-left: 1.5rem;
/* Add border above the toc */
border-top: 1px solid var(--bs-tertiary-color);
ol {
padding-left: 1rem;
counter-reset: section;
list-style-type: none;
}
#TableOfContents {
/* Remove the space between the title and the ToC */
margin-top: 0;
&>ol>li {
margin-bottom: .5rem;
&>a {
font-weight: $font-weight-bold;
}
}
ol {
padding-left: 0;
}
&>ol>li>a {
padding-left: 1rem;
}
&>ol>li>ol>li>a {
padding-left: 2rem;
}
&>ol>li>ol>li>ol>li>a {
padding-left: 3rem;
}
&>ol>li>ol>li>ol>li>ol>li>a {
padding-left: 4rem;
}
&>ol>li>ol>li>ol>li>ol>li>ol>li>a {
padding-left: 5rem;
}
}
li a:before {
counter-increment: section;
content: counters(section, ".") " ";
}
.td-toc-title {
font-weight: $font-weight-bold;
font-size: 1.3rem;
/* Remove the border under the title */
border-bottom: 0;
/* Remove the space under the title */
margin-bottom: 0;
/* Fix the top of page link color */
a, a:hover {
color: $secondary;
}
}
}
/* Apply the same style to links in the navigation and in the ToC */
& > .td-sidebar-nav__section, & > .td-toc #TableOfContents {
li a.td-sidebar-link.tree-root {
color: $gray-800;
font-weight: $font-weight-bold;
font-size: 1.3rem;
margin-bottom: 0;
border-bottom: none;
}
li a, li a.td-sidebar-link {
color: $gray-800;
font-weight: $font-weight-normal;
padding-top: .2rem;
padding-bottom: .2rem;
transition: all 100ms ease-in-out;
&:hover {
background-color: $secondary-lighter-background;
color: $gray-800;
}
&.active, &active:hover {
background-color: $secondary-background;
}
}
}
}
@ -199,62 +273,67 @@ Custom SCSS for the Matrix spec
scroll-margin-top: 5.5rem;
}
/* Styles for the table of contents */
#toc {
padding-top: .5rem;
padding-left: 1.5rem;
ol {
padding-left: 1rem;
counter-reset: section;
list-style-type: none;
}
#TableOfContents {
&>ol>li {
margin-bottom: .5rem;
&>a {
font-weight: $font-weight-bold;
}
}
ol {
padding-left: 0;
}
&>ol>li>a {
padding-left: 1rem;
}
&>ol>li>ol>li>a {
padding-left: 2rem;
}
&>ol>li>ol>li>ol>li>a {
padding-left: 3rem;
}
&>ol>li>ol>li>ol>li>ol>li>a {
padding-left: 4rem;
}
&>ol>li>ol>li>ol>li>ol>li>ol>li>a {
padding-left: 5rem;
}
}
li a:before {
counter-increment: section;
content: counters(section, ".") " ";
}
#toc-title {
.endpoints-toc {
summary {
cursor: pointer;
font-weight: $font-weight-bold;
font-size: 1.3rem;
font-size: 1.05rem;
margin-bottom: 0.5rem;
}
.endpoint-list {
list-style: none;
padding-left: 0;
margin: 0;
}
.endpoint-list li {
margin: 0.2rem 0;
}
.endpoint-list a {
text-decoration: none;
color: inherit;
padding: 0.05rem 0.25rem;
border-radius: 0.2rem;
&:hover {
background-color: $secondary-background;
}
}
.endpoint-list .http-api-method {
margin-right: 0.35rem;
font-weight: $font-weight-bold;
}
.endpoint-path {
font-family: $font-family-monospace;
color: $secondary;
}
.endpoint-deprecated {
color: $danger;
font-weight: $font-weight-bold;
margin-left: 0.35rem;
}
.endpoint-module {
&:not(:first-child) {
margin-top: 0.75rem;
}
}
.endpoint-module-title {
// font-weight: $font-weight-bold;
font-size: 1.20rem;
margin-bottom: 0.35rem;
}
}
.page-description {
margin-bottom: 1rem;
color: inherit;
}
/* Styles for alert boxes */
@ -581,4 +660,4 @@ dd {
.breadcrumb {
margin: 0;
}
}
}

View file

@ -18,6 +18,7 @@ $primary: #FFF;
$secondary: #0098D4;
$dark: #333;
$gray-100: #FBFBFB;
$code-color: #005b7f;
$secondary-background: #E5F5FB;
$secondary-lighter-background: #F4FAFC;

View file

@ -1 +0,0 @@
Fix JSON formatting in the "Server admin style permissions" examples.

View file

@ -1 +0,0 @@
Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326).

View file

@ -1 +0,0 @@
Remove legacy mentions, as per [MSC4210](https://github.com/matrix-org/matrix-spec-proposals/issues/4210).

View file

@ -1 +0,0 @@
Push rule IDs are globally unique within their kind.

View file

@ -1 +0,0 @@
Don't advertise `creator` field in description of room creation.

View file

@ -1 +0,0 @@
`room_id` is required for peeking via `/_matrix/client/v3/events`.

View file

@ -1 +0,0 @@
The `server-name` segment of MXC URIs is sanitised differently from the `media-id` segment.

View file

@ -1 +0,0 @@
Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326).

View file

@ -1 +0,0 @@
Add note to each endpoint that uses capability negotiation.

View file

@ -1 +0,0 @@
Fix various typos throughout the specification.

View file

@ -1 +0,0 @@
Additional OpenGraph properties can be present in URL previews.

View file

@ -1 +0,0 @@
Fix various typos throughout the specification.

View file

@ -1 +0,0 @@
Clarify the special casing of membership events and redactions in power levels.

View file

@ -1 +0,0 @@
`M_RESOURCE_LIMIT_EXCEEDED` is now listed as a common error code.

View file

@ -1 +0,0 @@
Add `m.login.terms` to enumeration of authentication types.

View file

@ -1 +0,0 @@
Add the `m.oauth` authentication type for User-Interactive Authentication as per [MSC4312](https://github.com/matrix-org/matrix-spec-proposals/pull/4312).

View file

@ -1 +0,0 @@
Clarify how to use `state_after` ahead of declaring full support for its spec version.

View file

@ -1 +0,0 @@
`device_one_time_keys_count` is only optional if no unclaimed one-time keys exist.

View file

@ -1 +0,0 @@
Clarify that servers may choose not to use `M_USER_DEACTIVATED` at login time, for example for privacy reasons when they can't authenticate deactivated users.

View file

@ -1 +0,0 @@
Minor grammatical fix in the Secrets module description.

View file

@ -1 +0,0 @@
Usage of the `event_id_only` format for push notifications is not mandatory.

View file

@ -0,0 +1 @@
Add the account management capabilities for the OAuth 2.0 authentication API, as per [MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191).

View file

@ -0,0 +1,3 @@
The optional `submit_url` response parameter of the `/requestToken` endpoints uses the same request
and response parameters and error codes as the Identity Service API's `POST /_matrix/identity/v2/validate/email/submitToken`,
as per [MSC4183](https://github.com/matrix-org/matrix-spec-proposals/pull/4183).

View file

@ -0,0 +1 @@
Update non-historic mentions of matrix-doc repo to matrix-spec/-proposals. Contributed by @HarHarLinks.

View file

@ -0,0 +1 @@
Remove unintended TeX formatting. Contributed by @HarHarLinks.

View file

@ -0,0 +1 @@
Add `m.recent_emoji` account data event to track recently used emoji as per [MSC4356](https://github.com/matrix-org/matrix-spec-proposals/pull/4356).

View file

@ -0,0 +1,3 @@
Clarify the error codes that can be returned with a 400 HTTP status code by the `POST /_matrix/identity/v2/validate/email/submitToken`
and `POST /_matrix/identity/v2/validate/msisdn/submitToken` endpoints, introducing the `M_TOKEN_INCORRECT`
error code, as per [MSC4183](https://github.com/matrix-org/matrix-spec-proposals/pull/4183).

View file

@ -1 +0,0 @@
Swapped icon for X (fka. twitter) to updated logo in footer.

View file

@ -0,0 +1 @@
Clarify vendor prefixing requirements.

View file

@ -1 +0,0 @@
Inline Olm & Megolm specifications.

View file

@ -1 +0,0 @@
Silence failing redocly-cli rule.

View file

@ -1 +0,0 @@
Use NPM Trusted Publishers for publishing `@matrix-org/spec` to npm.

View file

@ -1 +0,0 @@
Inline Olm & Megolm specifications.

View file

@ -1 +0,0 @@
Inline Olm & Megolm specifications.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -1 +0,0 @@
Add version picker in the navbar.

View file

@ -0,0 +1 @@
Auto-create draft releases when building release tags.

View file

@ -0,0 +1 @@
Include the spec release version in the filenames in the tarballs generated by CI.

View file

@ -0,0 +1 @@
Replace the Twitter link in the footer with our BlueSky and Mastodon socials.

View file

@ -0,0 +1 @@
Upgrade to docsy v0.13.0.

View file

@ -0,0 +1 @@
Updates to the release documentation.

View file

@ -0,0 +1 @@
Remove unused leftover CSS files.

View file

@ -1 +0,0 @@
In room versions 8 through 12, clarify that "sufficient permission to invite users" on restricted joins also includes being a joined member of the room.

View file

@ -1 +0,0 @@
In room versions 3 through 12, clarify that when you have the power to redact, it is possible to redact events that you don't have the power to send.

View file

@ -0,0 +1 @@
Specify that callers of `/_matrix/federation/v1/openid/userinfo` must validate the returned user ID.

View file

@ -75,8 +75,8 @@ 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.
# major = "1"
# minor = "16"
#major = "1"
#minor = "17"
[[params.versions]]
# We must include this parameter to enable docsy's version picker in the navbar. The picker
@ -106,25 +106,30 @@ sidebar_menu_compact = true
# desc = "Matrix on GitHub"
# Custom links shown in the center of the footer. (Only supported by our fork of docsy's 'footer/central' partial.)
[[params.links.bottom]]
name = "GitHub"
url = "https://github.com/matrix-org"
icon = "fab fa-github"
name = "GitHub"
url = "https://github.com/matrix-org"
icon = "fab fa-github"
desc = "Matrix on GitHub"
[[params.links.bottom]]
name = "GitLab"
url = "https://gitlab.matrix.org/matrix-org"
icon = "fab fa-gitlab"
name = "GitLab"
url = "https://gitlab.matrix.org/matrix-org"
icon = "fab fa-gitlab"
desc = "Matrix on GitLab"
[[params.links.bottom]]
name = "YouTube"
url = "https://www.youtube.com/channel/UCVFkW-chclhuyYRbmmfwt6w"
icon = "fab fa-youtube"
name = "YouTube"
url = "https://www.youtube.com/channel/UCVFkW-chclhuyYRbmmfwt6w"
icon = "fab fa-youtube"
desc = "Matrix YouTube channel"
[[params.links.bottom]]
name = "Twitter"
url = "https://twitter.com/matrixdotorg"
icon = "fab fa-x-twitter"
desc = "Matrix on Twitter"
name = "Mastodon"
url = "https://mastodon.matrix.org/@matrix"
icon = "fab fa-mastodon"
desc = "Matrix on Mastodon"
[[params.links.bottom]]
name = "Bluesky"
url = "https://bsky.app/profile/matrix.org"
icon = "fab fa-bluesky"
desc = "Matrix on Bluesky"
# configuration for the hugo development server
@ -161,3 +166,11 @@ sidebar_menu_compact = true
mediaType = "text/markdown"
isPlainText = true
baseName = "checklist"
# Add font media types for downloading KaTeX fonts.
# See: https://www.docsy.dev/docs/content/diagrams-and-formulae/#create-media-types-for-katex-fonts
[mediaTypes]
[mediaTypes.'font/woff']
suffixes = ['woff']
[mediaTypes.'font/woff2']
suffixes = ['woff2']

View file

@ -2,16 +2,14 @@
title: "Application Service API"
weight: 30
type: docs
description: |
The Matrix client-server API and server-server APIs provide a consistent,
self-contained federated messaging fabric but leave little room for custom
server-side behaviour such as gateways, filters, or extensible hooks. The
Application Service API defines a standard way to add this extensible
functionality, independent of the underlying homeserver implementation.
---
The Matrix client-server API and server-server APIs provide the means to
implement a consistent self-contained federated messaging fabric.
However, they provide limited means of implementing custom server-side
behaviour in Matrix (e.g. gateways, filters, extensible hooks etc). The
Application Service API (AS API) defines a standard API to allow such
extensible functionality to be implemented irrespective of the
underlying homeserver implementation.
## Application Services
Application services are passive and can only observe events from the
@ -428,6 +426,8 @@ imports and similar behaviour).
#### Server admin style permissions
{{% changed-in v="1.17" %}}
The homeserver needs to give the application service *full control* over
its namespace, both for users and for room aliases. This means that the
AS should be able to manage any users and room alias in its namespace. No additional API
@ -444,33 +444,59 @@ achieved by including the `as_token` on a `/register` request, along
with a login type of `m.login.application_service` to set the desired
user ID without a password.
POST /_matrix/client/v3/register
Authorization: Bearer YourApplicationServiceTokenHere
```http
POST /_matrix/client/v3/register
Authorization: Bearer YourApplicationServiceTokenHere
```
Content:
{
"type": "m.login.application_service",
"username": "_irc_example"
}
```json
{
"type": "m.login.application_service",
"username": "_irc_example"
}
```
Similarly, logging in as users needs API changes in order to allow the AS to
log in without needing the user's password. This is achieved by including the
`as_token` on a `/login` request, along with a login type of
`m.login.application_service`:
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Servers MUST still allow application services to use the `/register` endpoint
with a login type of `m.login.application_service` even if they don't support
the [Legacy Authentication API](/client-server-api/#legacy-api).
In that case application services MUST set the `"inhibit_login": true` parameter
as they cannot use it to log in as users. If the `inhibit_login` parameter is
not set to `true`, the server MUST return a 400 HTTP status code with an
`M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
Similarly, logging in as users using the [Legacy authentication API](/client-server-api/#legacy-api)
needs API changes in order to allow the AS to log in without needing the user's
password. This is achieved by including the `as_token` on a `/login` request,
along with a login type of `m.login.application_service`:
{{% added-in v="1.2" %}}
POST /_matrix/client/v3/login
Authorization: Bearer YourApplicationServiceTokenHere
```http
POST /_matrix/client/v3/login
Authorization: Bearer YourApplicationServiceTokenHere
```
Content:
{
"type": "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_irc_example"
}
}
```json
{
"type": "m.login.application_service",
"identifier": {
"type": "m.id.user",
"user": "_irc_example"
}
}
```
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Application services MUST NOT use the `/login` endpoint if the server doesn't
support the Legacy authentication API. If `/login` is called with the
`m.login.application_service` login type the server MUST return a 400 HTTP
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
Application services which attempt to create users or aliases *outside*
of their defined namespaces, or log in as users outside of their defined
@ -512,6 +538,38 @@ client-server endpoint.
{{% http-api spec="client-server" api="appservice_room_directory" %}}
#### Device management
{{% added-in v="1.17" %}}
Application services need to be able to create and delete devices to manage the
encryption for their users without having to rely on `/login`, which also
generates an access token for the user, and which might not be available for
homeservers that only support the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
##### Creating devices
Application services can use the [`PUT /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#put_matrixclientv3devicesdeviceid)
endpoint to create new devices.
##### Deleting devices
The following endpoints used to delete devices MUST NOT require [User-Interactive
Authentication](/client-server-api/#user-interactive-authentication-api) when
used by an application service:
* [`DELETE /_matrix/client/v3/devices/{deviceId}`](/client-server-api/#delete_matrixclientv3devicesdeviceid)
* [`POST /_matrix/client/v3/delete_devices`](/client-server-api/#post_matrixclientv3delete_devices)
#### Cross-signing
{{% added-in v="1.17" %}}
Appservices need to be able to verify themselves and replace their cross-signing
keys, so the [`POST /_matrix/client/v3/keys/device_signing/upload`](/client-server-api/#post_matrixclientv3keysdevice_signingupload)
endpoint MUST NOT require [User-Interactive Authentication](/client-server-api/#user-interactive-authentication-api)
when used by an application service, even if cross-signing keys already exist.
### Referencing messages from a third-party network
Application services should include an `external_url` in the `content`

View file

@ -0,0 +1,91 @@
---
title: v1.17 Changelog
linkTitle: v1.17
type: docs
layout: changelog
outputs:
- html
- checklist
date: 2025-12-18
---
## Client-Server API
**Removed Endpoints**
- Remove legacy mentions, as per [MSC4210](https://github.com/matrix-org/matrix-spec-proposals/issues/4210). ([#2186](https://github.com/matrix-org/matrix-spec/issues/2186))
**Backwards Compatible Changes**
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
- Add the `m.oauth` authentication type for User-Interactive Authentication, as per [MSC4312](https://github.com/matrix-org/matrix-spec-proposals/pull/4312). ([#2234](https://github.com/matrix-org/matrix-spec/issues/2234))
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
**Spec Clarifications**
- Push rule IDs are globally unique within their kind. ([#2214](https://github.com/matrix-org/matrix-spec/issues/2214))
- Don't advertise `creator` field in description of room creation. ([#2215](https://github.com/matrix-org/matrix-spec/issues/2215))
- `room_id` is required for peeking via `/_matrix/client/v3/events`. ([#2216](https://github.com/matrix-org/matrix-spec/issues/2216))
- The `server-name` segment of MXC URIs is sanitised differently from the `media-id` segment. ([#2217](https://github.com/matrix-org/matrix-spec/issues/2217))
- Add note to each endpoint that uses capability negotiation. ([#2223](https://github.com/matrix-org/matrix-spec/issues/2223))
- Additional OpenGraph properties can be present in URL previews. ([#2225](https://github.com/matrix-org/matrix-spec/issues/2225))
- Clarify the special casing of membership events and redactions in power levels. ([#2231](https://github.com/matrix-org/matrix-spec/issues/2231))
- `M_RESOURCE_LIMIT_EXCEEDED` is now listed as a common error code. ([#2232](https://github.com/matrix-org/matrix-spec/issues/2232))
- Add `m.login.terms` to enumeration of authentication types. ([#2233](https://github.com/matrix-org/matrix-spec/issues/2233))
- Clarify how to use `state_after` ahead of declaring full support for its spec version. ([#2240](https://github.com/matrix-org/matrix-spec/issues/2240))
- `device_one_time_keys_count` is only optional if no unclaimed one-time keys exist. ([#2245](https://github.com/matrix-org/matrix-spec/issues/2245))
- Clarify that servers may choose not to use `M_USER_DEACTIVATED` at login time, for example for privacy reasons when they can't authenticate deactivated users. ([#2246](https://github.com/matrix-org/matrix-spec/issues/2246))
- Usage of the `event_id_only` format for push notifications is not mandatory. ([#2255](https://github.com/matrix-org/matrix-spec/issues/2255))
- Fix various typos throughout the specification. ([#2224](https://github.com/matrix-org/matrix-spec/issues/2224), [#2227](https://github.com/matrix-org/matrix-spec/issues/2227), [#2250](https://github.com/matrix-org/matrix-spec/issues/2250))
## Server-Server API
No significant changes.
## Application Service API
**Backwards Compatible Changes**
- Allow application services to masquerade as specific devices belonging to users, as per [MSC4326](https://github.com/matrix-org/matrix-spec-proposals/pull/4326). ([#2221](https://github.com/matrix-org/matrix-spec/issues/2221))
- Allow application services to manage devices and register users without the legacy authentication API, as per [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190). ([#2267](https://github.com/matrix-org/matrix-spec/issues/2267))
**Spec Clarifications**
- Fix JSON formatting in the "Server admin style permissions" examples. ([#2213](https://github.com/matrix-org/matrix-spec/issues/2213))
## Identity Service API
No significant changes.
## Push Gateway API
No significant changes.
## Room Versions
**Spec Clarifications**
- In room versions 8 through 12, clarify that "sufficient permission to invite users" on restricted joins also includes being a joined member of the room. ([#2220](https://github.com/matrix-org/matrix-spec/issues/2220))
- In room versions 3 through 12, clarify that when you have the power to redact, it is possible to redact events that you don't have the power to send. ([#2249](https://github.com/matrix-org/matrix-spec/issues/2249))
## Appendices
No significant changes.
## Internal Changes/Tooling
**Spec Clarifications**
- Swapped icon for X (fka. twitter) to updated logo in footer. ([#2219](https://github.com/matrix-org/matrix-spec/issues/2219))
- Inline Olm & Megolm specifications. ([#2226](https://github.com/matrix-org/matrix-spec/issues/2226), [#2241](https://github.com/matrix-org/matrix-spec/issues/2241), [#2242](https://github.com/matrix-org/matrix-spec/issues/2242))
- Silence failing redocly-cli rule. ([#2238](https://github.com/matrix-org/matrix-spec/issues/2238))
- Use NPM Trusted Publishers for publishing `@matrix-org/spec` to npm. ([#2239](https://github.com/matrix-org/matrix-spec/issues/2239))
- Add version picker in the navbar. ([#2256](https://github.com/matrix-org/matrix-spec/issues/2256), [#2258](https://github.com/matrix-org/matrix-spec/issues/2258), [#2259](https://github.com/matrix-org/matrix-spec/issues/2259), [#2260](https://github.com/matrix-org/matrix-spec/issues/2260), [#2261](https://github.com/matrix-org/matrix-spec/issues/2261), [#2264](https://github.com/matrix-org/matrix-spec/issues/2264), [#2268](https://github.com/matrix-org/matrix-spec/issues/2268))
- Add a list of endpoints to the top of each spec page. ([#2262](https://github.com/matrix-org/matrix-spec/issues/2262))

View file

@ -2,14 +2,14 @@
title: "Client-Server API"
weight: 10
type: docs
description: |
The client-server API allows clients to send messages, control rooms and
synchronise conversation history. It is designed to support both lightweight
clients which store no state and lazy-load data from the server as required,
as well as heavyweight clients which maintain a full local persistent copy of
server state.
---
The client-server API allows clients to
send messages, control rooms and synchronise conversation history. It is
designed to support both lightweight clients which store no state and
lazy-load data from the server as required - as well as heavyweight
clients which maintain a full local persistent copy of server state.
## API Standards
{{% boxes/note %}}
@ -477,8 +477,7 @@ the API that was used to obtain their current access token.
{{% boxes/note %}}
Currently the OAuth 2.0 API doesn't cover all the use cases of the legacy API,
such as automated applications that cannot use a web browser, or
user management by [application services](application-service-api/#server-admin-style-permissions).
such as automated applications that cannot use a web browser.
{{% /boxes/note %}}
{{% boxes/note %}}
@ -509,6 +508,12 @@ user must do that directly in the homeserver's web UI. However, the client can
signal to the homeserver that the user wishes to create a new account with the
[`prompt=create`](#user-registration) parameter during authorization.
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Application services can use the `/register` endpoint to create users regardless
of the authentication API supported by the homeserver.
{{% /boxes/note %}}
### Login
With the legacy API, a client can obtain an access token by using one of the
@ -647,7 +652,7 @@ manage their account like [changing their password](#password-management),
[deactivating their account](#account-deactivation).
With the OAuth 2.0 API, all account management is done via the homeserver's web
UI.
UI that can be accessed by users via the [account management URL](#oauth-20-account-management).
### Legacy API
@ -1574,6 +1579,10 @@ If the access token does correspond to an appservice, but the user id does
not lie within its namespace then the homeserver will respond with an
errcode of `M_EXCLUSIVE`.
{{% added-in v="1.17" %}} If this login type is used and the server doesn't
support logging in via the Legacy authentication API, it MUST return a 400 HTTP
status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
##### Login Fallback
If a client does not recognize any or all login flows it can use the
@ -2340,6 +2349,46 @@ The server SHOULD return one of the following responses:
- For other errors, the server returns a `400 Bad Request` response with error
details
#### Account management {id="oauth-20-account-management"}
{{% added-in v="1.18" %}}
All account management is done via the homeserver's web UI.
This specification defines extensions to the [OAuth Authorization Server
Metadata registry](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#authorization-server-metadata)
to offer clients a way to deep-link to the account management capabilities of
the homeserver to allow the user to complete the account management operations
in a browser.
##### Account management URL discovery
The [OAuth 2.0 authorization server metadata](#server-metadata-discovery) is
extended to include the following **optional** fields.
{{% definition path="schemas/oauth2-account-management-server-metadata" %}}
##### Account management URL parameters
The account management URL MAY accept the following minimum query parameters.
{{% definition path="schemas/oauth2-account-management-url" %}}
##### Account management URL actions
Account management actions are unique to the application. They SHOULD follow the
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar)
where feasible. The Matrix-specific actions are:
| Action | Description |
|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `org.matrix.profile` | The user wishes to view/edit their profile (name, avatar, contact details). |
| `org.matrix.devices_list` | The user wishes to view a list of their devices. |
| `org.matrix.device_view` | The user wishes to view the details of a specific device. A `device_id` SHOULD be provided. |
| `org.matrix.device_delete` | The user wishes to delete/log out a specific device. A `device_id` SHOULD be provided. |
| `org.matrix.account_deactivate` | The user wishes to deactivate their account. |
| `org.matrix.cross_signing_reset` | The user wishes to reset their cross-signing identity. Servers SHOULD use this action in the URL of the [`m.oauth`](#oauth-authentication) UIA type. |
### Account moderation
#### Account locking
@ -3967,6 +4016,7 @@ that profile.
| [Guest Access](#guest-access) | Optional | Optional | Optional | Optional | Optional |
| [Moderation Policy Lists](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional |
| [OpenID](#openid) | Optional | Optional | Optional | Optional | Optional |
| [Recently used emoji](#recently-used-emoji) | Optional | Optional | Optional | Optional | Optional |
| [Reference Relations](#reference-relations) | Optional | Optional | Optional | Optional | Optional |
| [Reporting Content](#reporting-content) | Optional | Optional | Optional | Optional | Optional |
| [Rich replies](#rich-replies) | Optional | Optional | Optional | Optional | Optional |
@ -4031,42 +4081,43 @@ operations and run in a resource constrained environment. Like embedded
applications, they are not intended to be fully-fledged communication
systems.
{{% cs-module name="instant_messaging" %}}
{{% cs-module name="rich_replies" %}}
{{% cs-module name="voip_events" %}}
{{% cs-module name="typing_notifications" %}}
{{% cs-module name="receipts" %}}
{{% cs-module name="read_markers" %}}
{{% cs-module name="presence" %}}
{{% cs-module name="content_repo" %}}
{{% cs-module name="send_to_device" %}}
{{% cs-module name="device_management" %}}
{{% cs-module name="end_to_end_encryption" %}}
{{% cs-module name="secrets" %}}
{{% cs-module name="history_visibility" %}}
{{% cs-module name="push" %}}
{{% cs-module name="third_party_invites" %}}
{{% cs-module name="search" %}}
{{% cs-module name="guest_access" %}}
{{% cs-module name="room_previews" %}}
{{% cs-module name="tags" %}}
{{% cs-module name="account_data" %}}
{{% cs-module name="admin" %}}
{{% cs-module name="event_context" %}}
{{% cs-module name="sso_login" %}}
{{% cs-module name="dm" %}}
{{% cs-module name="ignore_users" %}}
{{% cs-module name="stickers" %}}
{{% cs-module name="report_content" %}}
{{% cs-module name="third_party_networks" %}}
{{% cs-module name="openid" %}}
{{% cs-module name="server_acls" %}}
{{% cs-module name="mentions" %}}
{{% cs-module name="room_upgrades" %}}
{{% cs-module name="server_notices" %}}
{{% cs-module name="moderation_policies" %}}
{{% cs-module name="spaces" %}}
{{% cs-module name="event_replacements" %}}
{{% cs-module name="event_annotations" %}}
{{% cs-module name="threading" %}}
{{% cs-module name="reference_relations" %}}
{{% cs-module name="Instant Messaging" filename="instant_messaging" %}}
{{% cs-module name="Rich replies" filename="rich_replies" %}}
{{% cs-module name="Voice over IP" filename="voip_events" %}}
{{% cs-module name="Typing Notifications" filename="typing_notifications" %}}
{{% cs-module name="Receipts" filename="receipts" %}}
{{% cs-module name="Read and unread markers" filename="read_markers" %}}
{{% cs-module name="Presence" filename="presence" %}}
{{% cs-module name="Content repository" filename="content_repo" %}}
{{% cs-module name="Send-to-Device messaging" filename="send_to_device" %}}
{{% cs-module name="Device Management" filename="device_management" %}}
{{% cs-module name="End-to-End Encryption" filename="end_to_end_encryption" %}}
{{% cs-module name="Secrets" filename="secrets" %}}
{{% cs-module name="Room History Visibility" filename="history_visibility" %}}
{{% cs-module name="Push Notifications" filename="push" %}}
{{% cs-module name="Third-party invites" filename="third_party_invites" %}}
{{% cs-module name="Server Side Search" filename="search" %}}
{{% cs-module name="Guest Access" filename="guest_access" %}}
{{% cs-module name="Room Previews" filename="room_previews" %}}
{{% cs-module name="Room Tagging" filename="tags" %}}
{{% cs-module name="Client Config" filename="account_data" %}}
{{% cs-module name="Server Administration" filename="admin" %}}
{{% cs-module name="Event Context" filename="event_context" %}}
{{% cs-module name="SSO client login/authentication" filename="sso_login" %}}
{{% cs-module name="Direct Messaging" filename="dm" %}}
{{% cs-module name="Ignoring Users" filename="ignore_users" %}}
{{% cs-module name="Sticker Messages" filename="stickers" %}}
{{% cs-module name="Reporting Content" filename="report_content" %}}
{{% cs-module name="Third-party Networks" filename="third_party_networks" %}}
{{% cs-module name="OpenID" filename="openid" %}}
{{% cs-module name="Server Access Control Lists (ACLs) for rooms" filename="server_acls" %}}
{{% cs-module name="User and room mentions" filename="mentions" %}}
{{% cs-module name="Room Upgrades" filename="room_upgrades" %}}
{{% cs-module name="Server Notices" filename="server_notices" %}}
{{% cs-module name="Moderation policy lists" filename="moderation_policies" %}}
{{% cs-module name="Spaces" filename="spaces" %}}
{{% cs-module name="Event replacements" filename="event_replacements" %}}
{{% cs-module name="Event annotations and reactions" filename="event_annotations" %}}
{{% cs-module name="Recently used emoji" filename="recent_emoji" %}}
{{% cs-module name="Threading" filename="threading" %}}
{{% cs-module name="Reference relations" filename="reference_relations" %}}

View file

@ -87,7 +87,7 @@ Matrix 1.12 is expected to be released in the July-September 2024 calendar quart
The homeserver SHOULD be able to supply thumbnails for uploaded images
and videos. The exact file types which can be thumbnailed are not
currently specified - see [Issue
\#1938](https://github.com/matrix-org/matrix-doc/issues/1938) for more
\#1938](https://github.com/matrix-org/matrix-spec/issues/453) for more
information.
The thumbnail methods are "crop" and "scale". "scale" tries to return an

View file

@ -921,7 +921,7 @@ collaborate to create a common set of translations for all languages.
{{% boxes/note %}}
Known translations for the emoji are available from
<https://github.com/matrix-org/matrix-doc/blob/master/data-definitions/>
<https://github.com/matrix-org/matrix-spec/tree/main/data-definitions/>
and can be translated online:
<https://translate.riot.im/projects/matrix-doc/sas-emoji-v1>
{{% /boxes/note %}}

View file

@ -119,7 +119,7 @@ Clients SHOULD verify the structure of incoming events to ensure that
the expected keys exist and that they are of the right type. Clients can
discard malformed events or display a placeholder message to the user.
Redacted `m.room.message` events MUST be removed from the client. This
can either be replaced with placeholder text (e.g. "\[REDACTED\]") or
can either be replaced with placeholder text (e.g. "[REDACTED]") or
the redacted message can be removed entirely from the messages view.
Events which have attachments (e.g. `m.image`, `m.file`) SHOULD be

View file

@ -0,0 +1,40 @@
### Recently used emoji
{{% added-in v="1.18" %}}
This module enables clients to track a user's cumulated emoji usage across different
devices. The data is stored in the [`m.recent_emoji`](#mrecent_emoji)
global [account data](#client-config) and can, among other things, be used to
generate recommendations in emoji pickers.
#### Events
{{% event event="m.recent_emoji" %}}
#### Client behaviour
What exactly constitutes trackable emoji usage is left as an implementation detail
for clients. It is RECOMMENDED to include sending emoji in both messages and
annotations.
When an emoji is used, the sending client moves (or adds) it to the beginning of
the `recent_emoji` array and increments (or initializes) its counter. This keeps
the array ordered by last usage time which facilitates evaluating the data. How
exactly the client evaluates and uses the collected data is deliberately left
unspecified.
To prevent excessive growth of the event as new emoji are being used, clients
SHOULD limit the length of the `recent_emoji` array by dropping elements from
its end. A RECOMMENDED maximum length is 100 emoji.
To enable future extension, clients MUST tolerate and preserve array elements
within `recent_emoji` regardless of whether they understand or support the
contained `emoji` value. This means ignoring entries with unrecognised values
of `emoji` when deciding what to display to the user while retaining them when
modifying the array (unless the modification is for truncation).
To prevent undefined behavior, clients SHOULD remove array elements that
don't conform to the event schema such as elements with negative counters.

View file

@ -2,17 +2,15 @@
title: "Identity Service API"
weight: 40
type: docs
description: |
The Matrix client-server and server-server APIs are largely expressed in
Matrix user identifiers. Sometimes it is useful to refer to users by other
(“third-party”) identifiers such as email addresses or phone numbers. The
Identity Service API describes how mappings between 3PIDs and Matrix user
IDs can be established, validated, and used; in practice this has been
applied to email addresses and phone numbers.
---
The Matrix client-server and server-server APIs are largely expressed in
Matrix user identifiers. From time to time, it is useful to refer to
users by other ("third-party") identifiers, or "3PID"s, e.g. their email
address or phone number. This Identity Service Specification describes
how mappings between third-party identifiers and Matrix user identifiers
can be established, validated, and used. This description technically
may apply to any 3PID, but in practice has only been applied
specifically to email addresses and phone numbers.
## General principles
The purpose of an identity server is to validate, store, and answer

View file

@ -408,41 +408,9 @@ development or testing data.
that a particular MSC works) do not have to follow this process.
1. Have an idea for a feature.
1. Implement the feature using unstable endpoints, vendor prefixes, and
unstable feature flags as appropriate.
- When using unstable endpoints, they MUST include a vendor
prefix. For example:
`/_matrix/client/unstable/com.example/login`. Vendor prefixes
throughout Matrix always use the Java package naming convention.
The MSC for the feature should identify which preferred vendor
prefix is to be used by early adopters.
- Note that unstable namespaces do not automatically inherit
endpoints from stable namespaces: for example, the fact that
`/_matrix/client/r0/sync` exists does not imply that
`/_matrix/client/unstable/com.example/sync` exists.
- If the client needs to be sure the server supports the feature,
an unstable feature flag that MUST be vendor prefixed is to be
used. This kind of flag shows up in the `unstable_features`
section of `/versions` as, for example, `com.example.new_login`.
The MSC for the feature should identify which preferred feature
flag is to be used by early adopters.
- When using this approach correctly, the implementation can
ship/release the feature at any time, so long as the
implementation is able to accept the technical debt that results
from needing to provide adequate backwards and forwards
compatibility. The implementation MUST support the flag (and
server-side implementation) disappearing and be generally safe
for users. Note that implementations early in the MSC review
process may also be required to provide backwards compatibility
with earlier editions of the proposal.
- If the implementation cannot support the technical debt (or if
it's impossible to provide forwards/backwards compatibility -
e.g. a user authentication change which can't be safely rolled
back), the implementation should not attempt to implement the
feature and should instead wait for a spec release.
- If at any point after early release, the idea changes in a
backwards-incompatible way, the feature flag should also change
so that implementations can adapt as needed.
1. Implement the feature using [unstable endpoints, vendor prefixes, and
unstable feature flags](#unstable-endpoints-features-and-vendor-prefixes)
as appropriate.
1. In parallel, or ahead of implementation, open an MSC and solicit
review per above.
1. Before FCP can be called, the Spec Core Team will require evidence
@ -452,10 +420,7 @@ that a particular MSC works) do not have to follow this process.
forwards/backwards compatibility concerns mentioned here.
1. The FCP process is completed, and assuming nothing is flagged the
MSC lands.
1. Implementations can now switch to using stable prefixes
(for example, for an endpoint, moving from
`/unstable/org.matrix.mscxxxx/frobnicate`
to `/v1/frobnicate`), assuming that the change
1. Implementations can now switch to using stable prefixes, assuming that the change
is backwards compatible with older implementations. In the rare occasion
where backwards compatibility is not possible without a new spec release,
implementations should continue to use unstable prefixes.
@ -471,13 +436,6 @@ that a particular MSC works) do not have to follow this process.
started supporting the new spec release, some noise should be raised
in the general direction of the implementation.
{{% boxes/note %}}
MSCs MUST still describe what the stable endpoints/feature looks like
with a note towards the bottom for what the unstable feature
flag/prefixes are. For example, an MSC would propose `/_matrix/client/r0/new/endpoint`, not `/_matrix/client/unstable/
com.example/new/endpoint`.
{{% /boxes/note %}}
In summary:
- Implementations MUST NOT use stable endpoints before the MSC has
@ -489,14 +447,90 @@ In summary:
- Implementations SHOULD be wary of the technical debt they are
incurring by moving faster than the spec.
- The vendor prefix is chosen by the developer of the feature, using
the Java package naming convention. The foundation's preferred
vendor prefix is `org.matrix`.
the Java package naming convention.
- The vendor prefixes, unstable feature flags, and unstable endpoints
should be included in the MSC, though the MSC MUST be written in a
way that proposes new stable endpoints. Typically this is solved by
a small table at the bottom mapping the various values from stable
to unstable.
#### Unstable endpoints, features and vendor prefixes
Unstable endpoints MUST use `/unstable` as the endpoint version and a
vendor prefix in Java package naming format. For example:
`/_matrix/client/unstable/com.example.mscxxxx/login`.
{{% boxes/note %}}
Proposal authors operating with a Matrix.org Foundation mandate SHOULD use
a vendor prefix within the `org.matrix` namespace. This namespace is otherwise
restricted. Authors who don't own a domain MAY use the `io.github` namespace
instead.
{{% /boxes/note %}}
Note that unstable namespaces do not automatically inherit endpoints from
stable namespaces: for example, the fact that `/_matrix/client/v3/sync`
exists does not imply that `/_matrix/client/unstable/com.example.mscxxxx/sync`
exists.
Vendor prefixes MUST also be used for:
- New parameters on existing endpoints. For example:
`/_matrix/client/v3/publicRooms?com.example.mscxxxx.ordered_by=member_count`.
- New properties in existing JSON objects. For example:
```json
{
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
"displayname": "Alice Margatroid",
"com.example.mscxxxx.phone": [{
"type": "landline",
"number": "+1-206-555-7000"
}],
...
}
```
- New values for existing parameters or properties. For example:
```json
{
"errcode": "COM.EXAMPLE.MSCXXXX.M_INVALID_EMAIL",
"error": "The email address you provided is invalid."
}
```
If the client needs to be sure the server supports the feature, an
unstable feature flag that MUST also be vendor prefixed is to be used.
This flag shows up in the `unstable_features` section of
[`/_matrix/client/versions`](/client-server-api/#get_matrixclientversions)
as, for example, `com.example.mscxxxx.new_login`.
{{% boxes/note %}}
MSCs MUST still describe what the stable endpoints/feature looks like
with a note towards the bottom for what the unstable feature
flag/prefixes are. For example, an MSC would propose `/_matrix/client/v1/new/endpoint`,
not `/_matrix/client/unstable/com.example.mscxxxx/new/endpoint`.
{{% /boxes/note %}}
When using this approach correctly, the implementation can release
the feature at any time, so long as the implementation is able to
accept the technical debt that results from needing to provide
adequate backwards and forwards compatibility. The implementation
MUST support the flag (and server-side implementation) disappearing
and be generally safe for users. Note that implementations early in
the MSC review process may also be required to provide backwards
compatibility with earlier editions of the proposal.
If the implementation cannot support the technical debt (or if it's
impossible to provide forwards/backwards compatibility - e.g. a user
authentication change which can't be safely rolled back), the
implementation should not attempt to implement the feature and should
instead wait for a spec release.
If at any point after early release, the idea changes in a
backwards-incompatible way, the feature flag should also change so
that implementations can adapt as needed.
### Placeholder MSCs
Some proposals may contain security-sensitive or private context which can't be

View file

@ -2,12 +2,11 @@
title: "Push Gateway API"
weight: 50
type: docs
description: |
Clients may want to receive push notifications when events are received at the
homeserver. This is managed by a distinct entity called the Push Gateway.
---
Clients may want to receive push notifications when events are received
at the homeserver. This is managed by a distinct entity called the Push
Gateway.
## Overview
A client's homeserver forwards information about received events to the

View file

@ -2,49 +2,46 @@
title: "Server-Server API"
weight: 20
type: docs
description: |
Matrix homeservers use the Federation APIs (also known as server-server APIs)
to communicate with each other. Homeservers use these APIs to push messages in
real-time, retrieve historic messages, and query profile or presence
information about users on other servers. The APIs are implemented over HTTPS,
with authentication provided by public key signatures both at the TLS
transport layer and in HTTP Authorization headers.
There are three main kinds of communication that occur between
homeservers:
Persistent Data Units (PDUs):
These events are broadcast from one homeserver to any others that have
joined the same room (identified by Room ID). They are persisted in
long-term storage and record the history of messages and state for a
room.
Like email, it is the responsibility of the originating server of a PDU
to deliver that event to its recipient servers. However PDUs are signed
using the originating server's private key so that it is possible to
deliver them through third-party servers.
Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not
persisted and are not part of the history of a room, nor does the
receiving homeserver have to reply to them.
Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain
some information, and responded by the other. They are not persisted and
contain no long-term significant history. They simply request a snapshot
state at the instant the query is made.
EDUs and PDUs are further wrapped in an envelope called a Transaction,
which is transferred from the origin to the destination homeserver using
an HTTPS PUT request.
---
Matrix homeservers use the Federation APIs (also known as server-server
APIs) to communicate with each other. Homeservers use these APIs to push
messages to each other in real-time, to retrieve historic messages from
each other, and to query profile and presence information about users on
each other's servers.
The APIs are implemented using HTTPS requests between each of the
servers. These HTTPS requests are strongly authenticated using public
key signatures at the TLS transport layer and using public key
signatures in HTTP Authorization headers at the HTTP layer.
There are three main kinds of communication that occur between
homeservers:
Persistent Data Units (PDUs):
These events are broadcast from one homeserver to any others that have
joined the same room (identified by Room ID). They are persisted in
long-term storage and record the history of messages and state for a
room.
Like email, it is the responsibility of the originating server of a PDU
to deliver that event to its recipient servers. However PDUs are signed
using the originating server's private key so that it is possible to
deliver them through third-party servers.
Ephemeral Data Units (EDUs):
These events are pushed between pairs of homeservers. They are not
persisted and are not part of the history of a room, nor does the
receiving homeserver have to reply to them.
Queries:
These are single request/response interactions between a given pair of
servers, initiated by one side sending an HTTPS GET request to obtain
some information, and responded by the other. They are not persisted and
contain no long-term significant history. They simply request a snapshot
state at the instant the query is made.
EDUs and PDUs are further wrapped in an envelope called a Transaction,
which is transferred from the origin to the destination homeserver using
an HTTPS PUT request.
## API standards
The mandatory baseline for server-server communication in Matrix is

View file

@ -21,13 +21,17 @@ paths:
x-addedInMatrixVersion: "1.1"
x-changedInMatrixVersion:
"1.11": UIA is not always required for this endpoint.
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
summary: Upload cross-signing keys.
description: |-
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),
except when used by an application service.
User-Interactive Authentication MUST be performed, except in these cases:
User-Interactive Authentication MUST be performed for regular clients, 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

View file

@ -0,0 +1,29 @@
# Copyright 2026 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.
title: Recent Emoji
type: object
properties:
emoji:
type: string
description: The Unicode emoji as string.
example: 🚀
total:
type: number
description: |-
The number of times the emoji has been used.
MUST be non-negative and smaller than 2^53.
required:
- emoji
- total

View file

@ -24,16 +24,23 @@ properties:
submit_url:
type: string
format: uri
x-changedInMatrixVersion:
"1.18": |-
The URL has the same request and response parameters and error codes as
the Identity Service API's endpoint.
description: |-
An optional field containing a URL where the client must submit the
validation token to, with identical parameters to the Identity Service
API's `POST /validate/email/submitToken` endpoint (without the requirement
for an access token). The homeserver must send this token to the user (if
applicable), who should then be prompted to provide it to the client.
validation token, with identical request and response parameters and error
codes to the Identity Service API's
[`POST /validate/email/submitToken`](/identity-service-api/#post_matrixidentityv2validateemailsubmittoken)
and [`POST /validate/msisdn/submitToken`](/identity-service-api/#post_matrixidentityv2validatemsisdnsubmittoken)
endpoints (without the requirement for an access token). The homeserver
must send this token to the user (if applicable), who should then be
prompted to provide it to the client.
If this field is not present, the client can assume that verification
will happen without the client's involvement provided the homeserver
advertises this specification version in the `/versions` response
(ie: r0.5.0).
advertises a sufficiently recent version in the [`GET /versions`](/client-server-api/#get_matrixclientversions)
response (ie: r0.5.0).
example: "https://example.org/path/to/submitToken"
required: ['sid']

View file

@ -87,8 +87,21 @@ paths:
tags:
- Device management
put:
summary: Update a device
description: Updates the metadata on the given device.
summary: Create or update a device
x-changedInMatrixVersion:
"1.17": The ability to create new devices was added.
description: |-
Updates the metadata on the given device, or creates a new device.
The ability to create new devices is only available to application
services: regular clients may only update existing devices.
When a new device was created, the homeserver MUST return a 201 HTTP
status code. It MUST return a 200 HTTP status code if a device was
updated.
This endpoint is rate-limited for device creation. Servers MAY use login
rate limits.
operationId: updateDevice
security:
- accessTokenQuery: []
@ -127,19 +140,34 @@ paths:
examples:
response:
value: {}
"201":
description: |-
The device was successfully created by the application service.
content:
application/json:
schema:
type: object
examples:
response:
value: {}
"404":
description: The current user has no device with the given ID.
tags:
- Device management
delete:
summary: Delete a device
x-changedInMatrixVersion:
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
description: |-
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),
except when used by an application service.
Deletes the given device, and invalidates any access token associated with it.
{{% boxes/warning %}}
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
{{% /boxes/warning %}}
@ -197,13 +225,18 @@ paths:
/delete_devices:
post:
summary: Bulk deletion of devices
x-changedInMatrixVersion:
"1.17": |-
This endpoint no longer requires User-Interactive Authentication when used by an
application service.
description: |-
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),
except when used by an application service.
Deletes the given devices, and invalidates any access token associated with them.
{{% boxes/warning %}}
Since this endpoint uses User-Interactive Authentication, it cannot be used when the access token was obtained
When this endpoint requires User-Interactive Authentication, it cannot be used when the access token was obtained
via the [OAuth 2.0 API](/client-server-api/#oauth-20-api).
{{% /boxes/warning %}}

View file

@ -243,8 +243,13 @@ paths:
}
}
"400":
description: Part of the request was invalid. For example, the login type may
not be recognised.
description: |-
Part of the request was invalid. For example, the login type may not be recognised.
Specific error codes used with this status code include:
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
used the `m.login.application_service` type, but the server doesn't support logging
in via the Legacy authentication API.
content:
application/json:
schema:

View file

@ -139,6 +139,32 @@ paths:
items:
type: string
description: A prompt value that the server supports.
account_management_uri:
x-addedInMatrixVersion: "1.18"
type: string
format: uri
description: |-
The URL where the user is able to access the account management capabilities
of the homeserver.
This is an extension [defined in this specification](/client-server-api/#oauth-20-account-management).
account_management_actions_supported:
x-addedInMatrixVersion: "1.18"
type: array
description: |-
List of actions that the account management URL supports.
This is an extension [defined in this specification](/client-server-api/#oauth-20-account-management).
items:
type: string
enum:
- "org.matrix.profile"
- "org.matrix.devices_list"
- "org.matrix.device_view"
- "org.matrix.device_delete"
- "org.matrix.account_deactivate"
- "org.matrix.cross_signing_reset"
description: An action that the account management URL supports.
required:
- issuer
- authorization_endpoint
@ -159,6 +185,15 @@ paths:
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_modes_supported": ["query", "fragment"],
"code_challenge_methods_supported": ["S256"],
"account_management_uri": "https://account.example.com/manage",
"account_management_actions_supported": [
"org.matrix.profile",
"org.matrix.devices_list",
"org.matrix.device_view",
"org.matrix.device_delete",
"org.matrix.account_deactivate",
"org.matrix.cross_signing_reset",
],
}
tags:
- Session management

View file

@ -61,6 +61,18 @@ paths:
Any user ID returned by this API must conform to the grammar given in the
[Matrix specification](/appendices/#user-identifiers).
{{% boxes/note %}}
{{% added-in v="1.17" %}}
Even if the server doesn't support the Legacy authentication API, it
MUST support this endpoint for application services to be able to
[create users](/application-service-api/#server-admin-style-permissions).
In that case application services MUST set the `"inhibit_login": true`
parameter as they cannot use it to log in as users. If the
`inhibit_login` parameter is not set to `true`, the server MUST return a
400 HTTP status code with an `M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
{{% /boxes/note %}}
{{% boxes/warning %}}
{{% added-in v="1.18" %}} [OAuth 2.0 aware clients](/client-server-api/#oauth-20-aware-clients)
MUST NOT use this endpoint when the server offers the [`m.login.sso`
@ -211,6 +223,9 @@ paths:
* `M_INVALID_USERNAME` : The desired user ID is not a valid user name.
* `M_EXCLUSIVE` : The desired user ID is in the exclusive namespace
claimed by an application service.
* {{% added-in v="1.17" %}} `M_APPSERVICE_LOGIN_UNSUPPORTED`: an application service
used the `m.login.application_service` type without setting `inhibit_login` to `true`,
but the server doesn't support logging in via the Legacy authentication API.
These errors may be returned at any stage of the registration process,
including after authentication if the requested user ID was registered

View file

@ -223,7 +223,7 @@ paths:
type: string
# XXX: As mentioned in MSC1227, replacing `[not_]membership` with a JSON
# filter might be a better alternative.
# See https://github.com/matrix-org/matrix-doc/issues/1337
# See https://github.com/matrix-org/matrix-doc/issues/1227
- in: query
name: membership
description: |-

View file

@ -78,7 +78,7 @@ paths:
},
"room": {
"regexp": "[^\\s]+\\/[^\\s]+",
"placeholder": "matrix-org/matrix-doc"
"placeholder": "matrix-org/matrix-spec"
}
},
"instances": [

View file

@ -153,6 +153,24 @@ paths:
value: {
"success": true
}
"400":
description: |
An error occurred. Some possible errors are:
- {{% added-in v="1.18" %}} `M_TOKEN_INCORRECT`: The token that the user entered to validate the session is
incorrect.
- {{% added-in v="1.18" %}} `M_INVALID_PARAM`: One of the supplied parameters is not valid.
- {{% added-in v="1.18" %}} `M_SESSION_EXPIRED`: The validation session in question has expired.
content:
application/json:
schema:
$ref: ../client-server/definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_TOKEN_INCORRECT",
"error": "The token is incorrect"
}
"403":
description: |
The user must do something in order to use this endpoint. One example

View file

@ -155,6 +155,24 @@ paths:
value: {
"success": true
}
"400":
description: |
An error occurred. Some possible errors are:
- {{% added-in v="1.18" %}} `M_TOKEN_INCORRECT`: The token that the user entered to validate the session is
incorrect.
- {{% added-in v="1.18" %}} `M_INVALID_PARAM`: One of the supplied parameters is not valid.
- {{% added-in v="1.18" %}} `M_SESSION_EXPIRED`: The validation session in question has expired.
content:
application/json:
schema:
$ref: ../client-server/definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_TOKEN_INCORRECT",
"error": "The token is incorrect"
}
"403":
description: |
The user must do something in order to use this endpoint. One example

View file

@ -43,7 +43,12 @@ paths:
properties:
sub:
type: string
description: The Matrix User ID who generated the token.
description: |
The Matrix User ID who generated the token.
The caller MUST validate that the returned user ID is on the server they
called (i.e. if you make a request to example.com and it returns
`@alice:matrix.org`, the result is invalid).
example: "@alice:example.com"
required:
- sub

View file

@ -0,0 +1,16 @@
{
"$ref": "core/event.json",
"type": "m.recent_emoji",
"content": {
"recent_emoji": [{
"emoji": "🤔",
"total": 19
}, {
"emoji": "👍",
"total": 7
}, {
"emoji": "😅",
"total": 84
}]
}
}

View file

@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Recent Emoji Event",
"description": "Lets clients maintain a list of recently used emoji.",
"allOf": [{
"$ref": "core-event-schema/event.yaml"
}],
"properties": {
"type": {
"type": "string",
"enum": ["m.recent_emoji"]
},
"content": {
"type": "object",
"properties": {
"recent_emoji": {
"description": "The list of recently used emoji. Elements in the list are ordered descendingly by last usage time.",
"type": "array",
"items": {
"$ref": "../../api/client-server/definitions/recent_emoji.yaml"
},
}
},
"required": ["recent_emoji"]
}
},
"required": ["type", "content"]
}

View file

@ -0,0 +1,30 @@
# Copyright 2026 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: OAuth 2.0 Server Metadata Account Management Extension
properties:
account_management_uri:
type: string
format: uri
description: |-
The URL where the user is able to access the account management capabilities of the
server.
account_management_actions_supported:
type: array
description: |-
List of [actions](/client-server-api/#account-management-url-actions) that the account
management URL supports.
items:
type: string
description: An action that the account management URL supports.

View file

@ -0,0 +1,29 @@
# Copyright 2026 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
type: object
title: OAuth 2.0 Account Management URL Query Parameters
properties:
action:
type: string
description: |-
The action that the user wishes to take. Must match one of the actions advertised by the
server in [`account_management_actions_supported`](/client-server-api/#account-management-url-discovery).
device_id:
type: string
description: |-
For Matrix-specific actions, the user's device ID. Actions which don't support the device ID
will ignore it.
If the `org.matrix.device_view` or `org.matrix.device_delete` actions are advertised as
supported by the server then the server SHOULD support the `device_id` parameter.

2
go.mod
View file

@ -2,4 +2,4 @@ module github.com/matrix-org/matrix-spec
go 1.12
require github.com/matrix-org/docsy v0.0.0-20250722140156-5df72519f5af // indirect
require github.com/matrix-org/docsy v0.0.0-20260106184755-71d103ebb20a // indirect

6
go.sum
View file

@ -1,4 +1,4 @@
github.com/FortAwesome/Font-Awesome v0.0.0-20241216213156-af620534bfc3/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo=
github.com/matrix-org/docsy v0.0.0-20250722140156-5df72519f5af h1:XghgUC0H5BoGrvtT9/oWBUi+5Zux875qRHhpAZ0RURI=
github.com/matrix-org/docsy v0.0.0-20250722140156-5df72519f5af/go.mod h1:4/t21g/nPraob/DVMm3jrk26k0CDL5I7Mxf+ar0IAgs=
github.com/twbs/bootstrap v5.3.6+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0=
github.com/matrix-org/docsy v0.0.0-20260106184755-71d103ebb20a h1:WB3unuZJy7ewAf33sxbtEwYnC+i+Jt1sJpAR3BtzvEo=
github.com/matrix-org/docsy v0.0.0-20260106184755-71d103ebb20a/go.mod h1:mdn1m5HJug6ZddQgrOyCrXNegbtdl5evHiqqbEQLzdI=
github.com/twbs/bootstrap v5.3.8+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0=

View file

@ -5,15 +5,7 @@
We use it to send the delimited passthrough element through KaTeX to render maths
in the Olm / Megolm spec.
See: https://gohugo.io/functions/transform/tomath/#step-2
See: https://www.docsy.dev/docs/content/diagrams-and-formulae/#add-passthrough-render-hook
*/ -}}
{{- $opts := dict "output" "htmlAndMathml" "displayMode" (eq .Type "block") }}
{{- with try (transform.ToMath .Inner $opts) }}
{{- with .Err }}
{{- errorf "Unable to render mathematical markup to HTML using the transform.ToMath function. The KaTeX display engine threw the following error: %s: see %s." . $.Position }}
{{- else }}
{{- .Value }}
{{- $.Page.Store.Set "hasMath" true }}
{{- end }}
{{- end -}}
{{ partial "scripts/math.html" . }}

View file

@ -1,28 +1,35 @@
{{/*
A copy of the breadcrumb.html partial in Docsy, modified
to:
A copy of the breadcrumb.html partial in Docsy, modified to:
* show the breadcrumbs by default by removing the `td-breadcrumbs__single`
class
* omit breadcrumbs when this is the homepage
* otherwise, include the homepage in the breadcrumbs
*/}}
{{ if not .IsHome }}
{{ if not .IsHome -}}
<nav aria-label="breadcrumb" class="td-breadcrumbs">
<ol class="breadcrumb">
{{ template "breadcrumbnav" (dict "p1" . "p2" .) }}
</ol>
</nav >
{{ end }}
<ol class="breadcrumb">
{{- template "breadcrumbnav" (dict "p1" . "p2" .) }}
</ol>
</nav>
{{ end -}}
{{ define "breadcrumbnav" }}
{{ if .p1.Parent }}
{{ template "breadcrumbnav" (dict "p1" .p1.Parent "p2" .p2 ) }}
{{ else if not .p1.IsHome }}
{{ template "breadcrumbnav" (dict "p1" .p1.Site.Home "p2" .p2 ) }}
{{ end }}
{{ $isActive := eq .p1 .p2 }}
<li class="breadcrumb-item{{ if $isActive }} active{{ end }}" {{ if $isActive }}aria-current="page"{{ end }}>
<a href="{{ .p1.RelPermalink }}">{{ .p1.LinkTitle }}</a>
</li>
{{ end }}
{{- define "breadcrumbnav" -}}
{{ if .p1.Parent -}}
{{ template "breadcrumbnav" (dict "p1" .p1.Parent "p2" .p2 ) -}}
{{ else if not .p1.IsHome -}}
{{ template "breadcrumbnav" (dict "p1" .p1.Site.Home "p2" .p2 ) -}}
{{ end -}}
{{ $isActive := eq .p1 .p2 }}
<li class="breadcrumb-item{{ if $isActive }} active{{ end }}"
{{- if $isActive }}aria-current="page"{{ end }}>
{{ if $isActive -}}
{{ .p1.LinkTitle -}}
{{ else -}}
<a href="{{ .p1.RelPermalink }}">{{ .p1.LinkTitle }}</a>
{{- end -}}
</li>
{{- end -}}

View file

@ -0,0 +1,61 @@
{{/*
Renders a list of API endpoints for the current page, given:
The outer page's Scratch must contain an "api_endpoints" key, which is either
a slice of maps (a list of endpoint metadata dicts) or a map of module name ->
slice of endpoint metadata dicts (representing the API modules and the
endpoints they each contain). Each endpoint dict must contain the following
keys:
* `anchor`: the HTML anchor for the endpoint
* `method`: the HTTP method
* `endpoint`: the endpoint path
* `summary`: a short summary of the endpoint
* `deprecated`: whether the endpoint is deprecated
* `module`: the CS API module name, if any, for grouping purposes. If empty,
the endpoint is considered "base" or "required".
*/}}
{{ $raw := .Scratch.Get "api_endpoints" }}
{{/* Normalize to a slice */}}
{{ $endpoints := slice }}
{{ if reflect.IsSlice $raw }}
{{ $endpoints = $raw }}
{{ else if reflect.IsMap $raw }}
{{ range $raw }}
{{ $endpoints = append $endpoints . }}
{{ end }}
{{ end }}
{{ if gt (len $endpoints) 0 }}
<div class="endpoints-toc mb-4">
<details>
<summary>List of Endpoints</summary>
{{/* Sort by module to group visually */}}
{{ $sorted := sort $endpoints "module" }}
{{ $current := "" }}
{{ range $sorted }}
{{ $mod := .module }}
{{/* Set a title for the base endpoints */}}
{{ if not $mod }}{{ $mod = "Required" }}{{ end }}
{{ if ne $mod $current }}
{{ if $current }}</ul></div>{{ end }}
<div class="endpoint-module">
<div class="endpoint-module-title">{{ $mod }}</div>
<ul class="endpoint-list">
{{ $current = $mod }}
{{ end }}
{{ $key := printf "%s|%s" .method .anchor }}
<li>
<a href="#{{ .anchor }}">
<span class="http-api-method">{{ .method }}</span>
<span class="endpoint-path">{{ .endpoint }}</span>
{{ if .deprecated }}<span class="endpoint-deprecated">(deprecated)</span>{{ end }}
</a>
</li>
{{ end }}
{{ if $current }}</ul></div>{{ end }}
</details>
</div>
{{ end }}

View file

@ -1,8 +1,11 @@
{{- /*
A version of the navbar.html partial in Docsy, only modified
to include the spec version, which is calculated using an
inline `version-string` partial.
A copy of the navbar.html partial in Docsy, modified to:
* remove `data-bs-theme` at L20, otherwise the title disappears on hover.
* replace the site title with "specification" at L31.
* include the spec version from the config at L34-35, which is calculated
using an inline `version-string` partial.
*/ -}}
@ -13,8 +16,8 @@
{{ $baseURL := urls.Parse $.Site.Params.Baseurl -}}
<nav class="td-navbar js-navbar-scroll
{{- if $cover }} td-navbar-cover {{- end }}" data-bs-theme="light">
<div class="container-fluid flex-column flex-md-row">
{{- if $cover }} td-navbar-cover {{- end }}">
<div class="td-navbar-container container-fluid flex-column flex-md-row">
<a class="navbar-brand" href="{{ .Site.Home.RelPermalink }}">
{{- /**/ -}}
<span class="navbar-brand__logo navbar-logo">
@ -32,7 +35,8 @@
<span class="navbar-version"> &mdash; {{ partial "version-string" . }}</span>
{{- /**/ -}}
</a>
<div class="td-navbar-nav-scroll ms-md-auto" id="main_navbar">
<div class="td-navbar-nav-scroll td-navbar-nav-scroll--indicator" id="main_navbar">
<div class="scroll-indicator scroll-left"></div>
<ul class="navbar-nav">
{{ $p := . -}}
{{ range .Site.Menus.main -}}
@ -58,39 +62,41 @@
</li>
{{ end -}}
{{ if .Site.Params.versions -}}
<li class="nav-item dropdown d-none d-lg-block">
<li class="nav-item dropdown d-none d-lg-block td-navbar__version-menu">
{{ partial "navbar-version-selector.html" . -}}
</li>
{{ end -}}
{{ if (gt (len .Site.Home.Translations) 0) -}}
<li class="nav-item dropdown d-none d-lg-block">
<li class="nav-item td-navbar__lang-menu">
{{ partial "navbar-lang-selector.html" . -}}
</li>
{{ end -}}
{{ if .Site.Params.ui.showLightDarkModeMenu -}}
<li class="td-light-dark-menu nav-item dropdown">
{{- $darkMode := partialCached "dark-mode-config.html" "dark-mode-global" -}}
{{ if $darkMode.showMenu -}}
<li class="nav-item td-navbar__light-dark-menu">
{{ partial "theme-toggler" . }}
</li>
{{ end -}}
</ul>
<div class="scroll-indicator scroll-right"></div>
</div>
<div class="d-none d-lg-block">
<div class="d-none d-lg-block td-navbar__search">
{{ partial "search-input.html" . }}
</div>
</div>
</nav>
{{ define "_partials/version-string" }}
{{ $ret := "unstable version"}}
{{- define "_partials/version-string" -}}
{{ $ret := "unstable version" -}}
{{ $status := .Site.Params.version.status }}
{{ $status := .Site.Params.version.status -}}
{{ if ne $status "unstable"}}
{{ $path := path.Join "changelogs" }}
{{ if ne $status "unstable" -}}
{{ $path := path.Join "changelogs" -}}
{{/* produces a string similar to "version v1.5" */}}
{{ $ret = delimit (slice "version v" .Site.Params.version.major "." .Site.Params.version.minor) "" }}
{{ end }}
{{/* produces a string similar to "version v1.5" */ -}}
{{ $ret = delimit (slice "version v" .Site.Params.version.major "." .Site.Params.version.minor) "" -}}
{{ end -}}
{{ return $ret }}
{{ end }}
{{ return $ret -}}
{{- end -}}

View file

@ -7,6 +7,8 @@
of each value in `paths` to get a complete URL.
* `anchor_base`: an optional prefix for the HTML IDs generated by
this template.
* `page`: the (Hugo) Page object to store endpoint metadata in the Scratch of. Used to build the endpoints TOC.
* `module`: the current CS API module name, if any. Used to group endpoints in the TOC.
This template replaces the old {{*_http_api}} template.
@ -15,6 +17,8 @@
{{ $api_data := index .api_data }}
{{ $base_url := .base_url }}
{{ $anchor_base := .anchor_base }}
{{ $page := .page }}
{{ $module := .module }}
{{ range $path_name, $path_data := $api_data.paths }}
@ -26,28 +30,28 @@
{{ with $path_data.get }}
{{ $operation_params := merge $params (dict "method" "GET" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "GET" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.post }}
{{ $operation_params := merge $params (dict "method" "POST" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "POST" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.put }}
{{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "PUT" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}
{{ with $path_data.delete }}
{{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . "anchor_base" $anchor_base) }}
{{ $operation_params := merge $params (dict "method" "DELETE" "operation_data" . "anchor_base" $anchor_base "page" $page "module" $module) }}
{{ partial "openapi/render-operation" $operation_params }}
{{ end }}

View file

@ -7,6 +7,8 @@
* `operation_data`: the OpenAPI data for the operation
* `anchor_base`: an optional prefix for the HTML IDs generated by
this template.
* `page`: the (Hugo) Page object to store endpoint metadata in the Scratch of. Used to build the endpoints TOC.
* `module`: the current CS API module name, if any. Used to group endpoints in the TOC.
This template renders the operation as a `<section>` containing:
@ -22,6 +24,8 @@
{{ $method := .method }}
{{ $endpoint := .endpoint }}
{{ $operation_data := .operation_data }}
{{ $page := .page }}
{{ $module := .module }}
{{ $anchor := "" }}
{{ if .anchor_base }}
@ -29,6 +33,27 @@
{{ end }}
{{ $anchor = printf "%s%s%s" $anchor (lower $method) (anchorize $endpoint) }}
{{/* Collect endpoints for the on-page endpoints TOC */}}
{{ if $page }}
{{/* Store each endpoint's metadata in a scratch variable */}}
{{ $entry := dict "anchor" $anchor "method" $method "endpoint" $endpoint "summary" $operation_data.summary "deprecated" $operation_data.deprecated "module" $module }}
{{ if not ($page.Scratch.Get "api_endpoints_seen") }}
{{ $page.Scratch.Set "api_endpoints_seen" dict }}
{{ end }}
{{/* Keep a map of seen endpoints. This is necessary as this partial may be
rendered multiple times for the same endpoint (e.g. in the TOC and
in the main content), leading to duplicates. */}}
{{ $seen := $page.Scratch.Get "api_endpoints_seen" }}
{{ $key := printf "%s|%s" $method $endpoint }}
{{ if not (index $seen $key) }}
{{ if not (reflect.IsSlice ($page.Scratch.Get "api_endpoints")) }}
{{ $page.Scratch.Set "api_endpoints" (slice) }}
{{ end }}
{{ $page.Scratch.Add "api_endpoints" (slice $entry) }}
{{ $page.Scratch.SetInMap "api_endpoints_seen" $key true }}
{{ end }}
{{ end }}
<section class="rendered-data">
<details {{ if not site.Params.ui.rendered_data_collapsed }}open{{ end }}>

View file

@ -1,37 +1,57 @@
{{- /*
A modified version of the siderbar-tree.html partial in Docsy, adding:
* The "toc.html" partial at L45.
A copy of the siderbar-tree.html partial in Docsy, modified to:
* Ignore the `sidebarRoot` parameter, because of this regression:
<https://github.com/google/docsy/issues/2426>
* Add the "toc.html" partial at L68.
*/ -}}
{{/* 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 -}}
{{ $context := .context -}}
{{ $sidebarRoot := .sidebarRoot -}}
{{ $sidebarRootID := .sidebarRootID -}}
{{ $cacheSidebar := .cacheSidebar -}}
{{ with $context -}}
{{/* When the sidebar is cached, "active" class is set client side. */ -}}
{{ $shouldDelayActive := $cacheSidebar -}}
<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 class="btn btn-link td-sidebar__toggle" 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 -}}
{{- 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 class="btn btn-link td-sidebar__toggle" 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 -}}
{{- 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">
{{- 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 .Site.Params.ui.sidebar_root_enabled }} data-sidebar-root-id="{{ $sidebarRootID }}"{{ end -}}
>
{{ if and .Site.Params.ui.sidebar_lang_menu (gt (len .Site.Home.Translations) 0) -}}
<div class="td-sidebar-nav__section nav-item d-block d-lg-none">
{{ partial "navbar-lang-selector.html" . }}
</div>
{{ end -}}
@ -45,44 +65,129 @@
{{ partial "toc.html" . }}
</nav>
</div>
{{- end }}{{/* with $context */ -}}
{{ 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 -}}
{{ $truncatedEntryCount := sub (len $pages_tmp) $sidebarMenuTruncate -}}
{{ if gt $truncatedEntryCount 0 -}}
{{ warnf "WARNING: %d sidebar entries have been truncated. To avoid this, increase `params.ui.sidebar_menu_truncate` to at least %d (from %d) in your config file. Section: %s"
$truncatedEntryCount (len $pages_tmp) $sidebarMenuTruncate $s.Path -}}
{{ end -}}
{{ $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) }}
{{/* cSpell:ignore manuallink manuallinkrelref manuallinktitle */ -}}
{{ $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 -}}
{{ $truncatedEntryCount := sub (len $pages_tmp) $sidebarMenuTruncate -}}
{{ if gt $truncatedEntryCount 0 -}}
{{ warnf "WARNING: %d sidebar entries have been truncated. To avoid this, increase `params.ui.sidebar_menu_truncate` to at least %d (from %d) in your config file. Section: %s"
$truncatedEntryCount (len $pages_tmp) $sidebarMenuTruncate $s.Path -}}
{{ end -}}
{{ $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
-}}
{{ if and $treeRoot (eq $s.Params.sidebar_root_for "self") -}}
{{ with $s.Parent -}}
{{ $manualLink = .RelPermalink -}}
{{ end -}}
{{ end -}}
<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 -}}
{{- if and $s.Params.sidebar_root_for site.Params.ui.sidebar_root_enabled }} td-sidebar-root-up-icon{{ 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 }}
{{- end }}
</ul>
{{- end }}
</li>
{{- end -}}
</li>
{{- end }}

View file

@ -0,0 +1,14 @@
{{- /* Shared render for spec pages: title, optional description, endpoints list, body, and last-mod info. */ -}}
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ with .Params.description }}<p class="page-description">{{ . | markdownify }}</p>{{ end }}
{{/*
Render an endpoints table of contents. This is the main difference
between our templates (which call the spec-content partial) and the default
Docsy template.
*/}}
{{ partial "endpoints-toc.html" . }}
{{ .Content }}
</div>

View file

@ -1,15 +1,29 @@
{{/*
A modified version of the toc.html partial in Docsy.
A copy of the toc.html partial in Docsy, modified to:
*/}}
{{ $page := .Params }}
* show the page's title instead of "on this page"
*/ -}}
{{/*
Always render the td-toc element. ScrollSpy is counting on it to exist,
even if it's empty.
cSpell:ignore notoc
*/ -}}
<div class="td-toc" data-proofer-ignore>
{{ if not .Params.notoc -}}
{{ with .TableOfContents -}}
<hr>
<div id="toc">
<a id="toc-title" href="#">{{ $page.Title }}</a>
{{ . }}
{{ $toc := .TableOfContents -}}
{{ if and $toc (ne $toc `<nav id="TableOfContents"></nav>`) -}}
<div class="td-toc-title">
<span class="td-toc-title__text">{{ .Params.Title }}</span>
<a class="td-toc-title__link" title="{{ i18n "toc_top_of_page" }}" href="#"></a>
</div>
{{ $toc | safeHTML }}
{{ end -}}
{{ end -}}
</div>
{{/* */ -}}

View file

@ -3,14 +3,39 @@
This template is used to render a Client-Server API Module. Modules are defined
alongside the `_index.md` for the CS API.
The `name` parameter is the file name without extension.
The following parameters are expected:
* `filename` the name of the module file to render, without extension (i.e. `spaces`).
* `name` the display name of the module (i.e. `Spaces`).
*/}}
{{ $name := .Params.name }}
{{ $filename := .Params.filename }}
{{ with .Site.GetPage "client-server-api/modules" }}
{{ with .Resources.GetMatch (printf "%s%s" $name ".md") }}
{{ with .Resources.GetMatch (printf "%s%s" $filename ".md") }}
{{/* Preserve previous scratch values so nested modules don't leak */}}
{{ $prevPage := .Scratch.Get "endpoint_page" }}
{{ $prevModule := .Scratch.Get "endpoint_module" }}
{{/* Allow endpoints rendered in the module to accumulate on the parent page */}}
{{ .Scratch.Set "endpoint_page" $.Page }}
{{/* Name the module for grouping in the endpoints list */}}
{{ .Scratch.Set "endpoint_module" $name }}
{{ .RenderShortcodes }}
{{/* Restore previous scratch values */}}
{{ if $prevPage }}
{{ .Scratch.Set "endpoint_page" $prevPage }}
{{ else }}
{{ .Scratch.Delete "endpoint_page" }}
{{ end }}
{{ if $prevModule }}
{{ .Scratch.Set "endpoint_module" $prevModule }}
{{ else }}
{{ .Scratch.Delete "endpoint_module" }}
{{ end }}
{{ end }}
{{ end }}

View file

@ -23,6 +23,20 @@
{{ $api := .Params.api}}
{{ $anchor_base := .Params.anchor_base}}
{{/*
Figure out which Page object to pass to the `openapi/render-api` partial.
Either our own, or one stored under `endpoint_page` in the Scratch, if one
exists.
*/}}
{{ $target_page := .Page }}
{{ with .Page.Scratch.Get "endpoint_page" }}
{{ $target_page = . }}
{{ end }}
{{ $module_name := .Page.Scratch.Get "endpoint_module" }}
{{ $api_data := index .Site.Data.api .Params.spec .Params.api }}
{{ $base_url := (index $api_data.servers 0).variables.basePath.default }}
{{ $path := delimit (slice "api" $spec $api) "/" }}
@ -30,4 +44,4 @@
{{ $api_data = partial "json-schema/resolve-refs" (dict "schema" $api_data "path" $path) }}
{{ $api_data = partial "json-schema/resolve-allof" $api_data }}
{{ partial "openapi/render-api" (dict "api_data" $api_data "base_url" $base_url "anchor_base" $anchor_base) }}
{{ partial "openapi/render-api" (dict "api_data" $api_data "base_url" $base_url "anchor_base" $anchor_base "page" $target_page "module" $module_name) }}

View file

@ -1,4 +0,0 @@
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ .Content }}
</div>

View file

@ -1,11 +1,14 @@
{{/*
A copy of the baseof.html partial in Docsy, modified
to remove the right-hand column from the layout.
A copy of the baseof.html partial in Docsy, modified to:
*/}}
* generate a static file `versions.json` that can be used to populate the
version picker.
* remove the right-hand column from the layout.
{{/* Generate a static file versions.json that can be used to populate the version picker */}}
*/ -}}
{{/* Generate a static file versions.json that can be used to populate the version picker */ -}}
{{ if .IsHome }}
{{- /* Load all changelog subpages, sorted by release date */ -}}
{{ $changelog := site.GetPage "changelog" }}
@ -28,20 +31,18 @@
<html itemscope itemtype="http://schema.org/WebPage"
{{- with .Site.Language.LanguageDirection }} dir="{{ . }}" {{- end -}}
{{ with .Site.Language.Lang }} lang="{{ . }}" {{- end }} {{/**/ -}}
class="no-js">
class="no-js"
{{- $darkMode := partialCached "dark-mode-config.html" "dark-mode-global" -}}
{{- if $darkMode.enable }} data-theme-init{{ end }}>
<head>
{{ partial "head.html" . }}
{{ if .Page.Store.Get "hasMath" }}
<link href="{{ relURL "css/katex.min.css" }}" rel="preload" as="style">
<link href="{{ relURL "css/katex.min.css" }}" rel="stylesheet">
{{ end }}
</head>
<body class="td-{{ .Kind }}{{ with .Page.Params.body_class }} {{ . }}{{ end }}">
<header>
{{ partial "navbar.html" . }}
</header>
<div class="container-fluid td-outer">
<div class="td-main">
<div class="td-main" {{- partialCached "td/scrollspy-attr.txt" . .Section | safeHTMLAttr }}>
<div class="row flex-xl-nowrap">
<aside class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none">
{{ partial "sidebar.html" . }}

View file

@ -1,13 +1,19 @@
{{/*
A simplified version of the list.html partial in Docsy.
Override the `layouts/docs/list.html` template from Docsy. While this template
is equivalent to `single.html`, it's necessary to override both templates to
avoid falling back to the default Docsy templates.
https://gohugo.io/templates/types/#list
We use this list template to render the Client-Server API spec page and each
of its modules.
The contents of the "main" block below are inserted into the `./baseof.html`
base template.
*/}}
{{ define "main" }}
<div class="td-content">
<h1>{{ .Title }}</h1>
{{ with .Params.description }}<div class="lead">{{ . | markdownify }}</div>{{ end }}
{{ .Content }}
</div>
{{ partial "spec-content.html" . }}
{{ end }}

19
layouts/docs/single.html Normal file
View file

@ -0,0 +1,19 @@
{{/*
Override the `layouts/docs/single.html` template from Docsy. While this template
is equivalent to `list.html`, it's necessary to override both templates to
avoid falling back to the default Docsy templates.
https://gohugo.io/templates/types/#single
We use this single template to render the all API spec pages *except* the
Client-Server API. The Client-Server API spec page contains modules, and thus
is handled separately, via the `layouts/docs/list.html` template.
The contents of the "main" block below are inserted into the `./baseof.html`
base template.
*/}}
{{ define "main" }}
{{ partial "spec-content.html" . }}
{{ end }}

Some files were not shown because too many files have changed in this diff Show more