mirror of
https://github.com/matrix-org/matrix-spec
synced 2025-12-22 17:28:38 +01:00
Compare commits
No commits in common. "main" and "0.2.0" have entirely different histories.
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
|
@ -1 +0,0 @@
|
||||||
* @matrix-org/spec-core-team
|
|
||||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
patreon: matrixdotorg
|
|
||||||
liberapay: matrixdotorg
|
|
||||||
13
.github/ISSUE_TEMPLATE/clarification.md
vendored
13
.github/ISSUE_TEMPLATE/clarification.md
vendored
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
name: Clarity problem
|
|
||||||
about: Report an area of the spec that is unclear.
|
|
||||||
title: ''
|
|
||||||
labels: 'clarification'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Link to problem area**:
|
|
||||||
|
|
||||||
**Issue**
|
|
||||||
What is wrong? How can we improve?
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
|
|
@ -1,8 +0,0 @@
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Matrix Spec Discussion
|
|
||||||
url: "https://matrix.to/#/#matrix-spec:matrix.org"
|
|
||||||
about: Questions about the spec and proposal process can be asked here.
|
|
||||||
- name: Matrix Security Policy
|
|
||||||
url: https://www.matrix.org/security-disclosure-policy/
|
|
||||||
about: Learn more about our security disclosure policy.
|
|
||||||
13
.github/ISSUE_TEMPLATE/cosmetic-bug.md
vendored
13
.github/ISSUE_TEMPLATE/cosmetic-bug.md
vendored
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
name: Cosmetic issue
|
|
||||||
about: Report an issue with how the spec looks.
|
|
||||||
title: ''
|
|
||||||
labels: 'aesthetic'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Link to problem area**:
|
|
||||||
|
|
||||||
**Issue**
|
|
||||||
What is wrong? What can we do to improve?
|
|
||||||
12
.github/ISSUE_TEMPLATE/idea.md
vendored
12
.github/ISSUE_TEMPLATE/idea.md
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
name: Spec idea
|
|
||||||
about: Suggest a future MSC idea.
|
|
||||||
title: ''
|
|
||||||
labels: 'improvement'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Suggestion**
|
|
||||||
What would you like to see in Matrix? If your idea is vaguely complete enough, we
|
|
||||||
recommend submitting [an MSC](https://matrix.org/docs/spec/proposals) instead.
|
|
||||||
37
.github/ISSUE_TEMPLATE/release.md
vendored
37
.github/ISSUE_TEMPLATE/release.md
vendored
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
name: '[SCT] Release checklist'
|
|
||||||
about: 'Used by the Spec Core Team to create a new release.'
|
|
||||||
title: 'Matrix 1.X'
|
|
||||||
labels: 'release-blocker'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- ------------------------------------------------------------------------ -->
|
|
||||||
<!-- Please asssign the release coordinator (probably yourself) to this issue -->
|
|
||||||
<!-- ------------------------------------------------------------------------ -->
|
|
||||||
|
|
||||||
Date: **Thursday, May 25, 2023** <!-- CHANGE ME -->
|
|
||||||
Previous release: <!-- LINK TO LAST RELEASE'S CHECKLIST -->
|
|
||||||
|
|
||||||
Preflight checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)):
|
|
||||||
|
|
||||||
* [ ] Pin this issue to the repo.
|
|
||||||
* [ ] Ensure the social media account holders are available for the release day.
|
|
||||||
* [ ] Blog post written.
|
|
||||||
* [ ] Check for release blockers that may have been missed.
|
|
||||||
* [ ] Review/fix the changelog.
|
|
||||||
|
|
||||||
Release checklist ([release steps](https://github.com/matrix-org/matrix-spec/blob/main/meta/releasing.md)):
|
|
||||||
* [ ] Branch stuffs.
|
|
||||||
* [ ] Github release artifact.
|
|
||||||
* [ ] Published to spec.matrix.org.
|
|
||||||
* [ ] All links work.
|
|
||||||
* [ ] Publish blog post.
|
|
||||||
* [ ] Announce in #matrix-spec, client developers, HS developers, SCT office, and other rooms as warranted.
|
|
||||||
* [ ] Post to Twitter/Mastodon.
|
|
||||||
* [ ] Close this issue.
|
|
||||||
* [ ] Unpin this issue from the repo.
|
|
||||||
|
|
||||||
Known release blockers:
|
|
||||||
* [ ] <!-- Issue/PR link -->
|
|
||||||
16
.github/ISSUE_TEMPLATE/spec-bug.md
vendored
16
.github/ISSUE_TEMPLATE/spec-bug.md
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
---
|
|
||||||
name: Documentation error
|
|
||||||
about: Report an issue with the spec itself (incorrect text).
|
|
||||||
title: ''
|
|
||||||
labels: 'spec-bug'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Link to problem area**:
|
|
||||||
|
|
||||||
**Issue**
|
|
||||||
What is wrong?
|
|
||||||
|
|
||||||
**Expected behaviour**
|
|
||||||
How can the issue be fixed? Links to implementations/documents which prove the spec is wrong are appreciated.
|
|
||||||
13
.github/_typos.toml
vendored
13
.github/_typos.toml
vendored
|
|
@ -1,13 +0,0 @@
|
||||||
[files]
|
|
||||||
extend-exclude = ["/themes", "/attic", "/data-definitions", "*.css", "syntax.scss", "package-lock.json"]
|
|
||||||
|
|
||||||
[default]
|
|
||||||
check-filename = true
|
|
||||||
|
|
||||||
[default.extend-identifiers]
|
|
||||||
au1ba7o = "au1ba7o"
|
|
||||||
|
|
||||||
[default.extend-words]
|
|
||||||
Appy = "Appy"
|
|
||||||
fo = "fo"
|
|
||||||
Iy = "Iy"
|
|
||||||
8
.github/pull_request_template.md
vendored
8
.github/pull_request_template.md
vendored
|
|
@ -1,8 +0,0 @@
|
||||||
|
|
||||||
### Pull Request Checklist
|
|
||||||
|
|
||||||
<!-- Please read CONTRIBUTING.rst before submitting your pull request -->
|
|
||||||
|
|
||||||
* [ ] Pull request includes a [changelog file](https://github.com/matrix-org/matrix-spec/blob/master/CONTRIBUTING.rst#adding-to-the-changelog)
|
|
||||||
* [ ] Pull request includes a [sign off](https://github.com/matrix-org/matrix-spec/blob/master/CONTRIBUTING.rst#sign-off)
|
|
||||||
* [ ] Pull request is classified as ['other changes'](https://github.com/matrix-org/matrix-spec/blob/master/CONTRIBUTING.rst#other-changes)
|
|
||||||
18
.github/workflows/checks.yaml
vendored
18
.github/workflows/checks.yaml
vendored
|
|
@ -1,18 +0,0 @@
|
||||||
# workflow steps that ought to pass on a PR, but shouldn't block a preview.
|
|
||||||
|
|
||||||
name: "Checks"
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-newsfragments:
|
|
||||||
name: "🔎 Check that new newsfragments are valid"
|
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- run: scripts/check-newsfragments
|
|
||||||
env:
|
|
||||||
PULL_REQUEST_NUMBER: ${{ github.event.number }}
|
|
||||||
312
.github/workflows/main.yml
vendored
312
.github/workflows/main.yml
vendored
|
|
@ -1,312 +0,0 @@
|
||||||
name: "Spec"
|
|
||||||
|
|
||||||
env:
|
|
||||||
HUGO_VERSION: 0.148.1
|
|
||||||
PYTHON_VERSION: 3.13
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
tags:
|
|
||||||
- v*
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Run this workflow every day at 2am. This helps keep the page of
|
|
||||||
# current spec proposals up-to-date.
|
|
||||||
- cron: '0 2 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate-openapi:
|
|
||||||
name: "🔎 Validate OpenAPI specifications"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Node"
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
- name: "🔎 Run validator"
|
|
||||||
run: |
|
|
||||||
npx @redocly/cli@latest lint data/api/*/*.yaml
|
|
||||||
|
|
||||||
check-event-examples:
|
|
||||||
name: "🔎 Check Event schema examples"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Python"
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: scripts/requirements.txt
|
|
||||||
- name: "➕ Install dependencies"
|
|
||||||
run: |
|
|
||||||
pip install -r scripts/requirements.txt
|
|
||||||
- name: "🔎 Run validator"
|
|
||||||
run: |
|
|
||||||
python scripts/check-event-schema-examples.py
|
|
||||||
|
|
||||||
check-openapi-examples:
|
|
||||||
name: "🔎 Check OpenAPI definitions examples"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Python"
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: scripts/requirements.txt
|
|
||||||
- name: "➕ Install dependencies"
|
|
||||||
run: |
|
|
||||||
pip install -r scripts/requirements.txt
|
|
||||||
- name: "🔎 Run validator"
|
|
||||||
run: |
|
|
||||||
python scripts/check-openapi-sources.py
|
|
||||||
|
|
||||||
check-schemas-examples:
|
|
||||||
name: "🔎 Check JSON Schemas inline examples"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Python"
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: scripts/requirements.txt
|
|
||||||
- name: "➕ Install dependencies"
|
|
||||||
run: |
|
|
||||||
pip install -r scripts/requirements.txt
|
|
||||||
- name: "🔎 Run validator"
|
|
||||||
run: |
|
|
||||||
python scripts/check-json-schemas.py
|
|
||||||
|
|
||||||
calculate-baseurl:
|
|
||||||
name: "⚙️ Calculate baseURL for later jobs"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
baseURL: "${{ steps.set-baseurl.outputs.baseURL }}"
|
|
||||||
steps:
|
|
||||||
# For PRs, set the baseURL to `/`.
|
|
||||||
# For releases, set the baseURL to `/$tag` (eg: `/v1.2`).
|
|
||||||
# Otherwise, set it to `/unstable`.
|
|
||||||
- name: "⚙️ Calculate baseURL"
|
|
||||||
id: set-baseurl
|
|
||||||
# Double brackets on the elif to avoid auto-escaping refs/tags/* because we need
|
|
||||||
# the asterisk matching behaviour, not the literal string.
|
|
||||||
run: |
|
|
||||||
if [ "${GITHUB_EVENT_NAME}" == "pull_request" ]; then
|
|
||||||
echo "baseURL=/" >> "$GITHUB_OUTPUT"
|
|
||||||
elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
echo "baseURL=/${GITHUB_REF/refs\/tags\//}" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "baseURL=/unstable" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
build-openapi:
|
|
||||||
name: "🐍 Build OpenAPI definitions"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [calculate-baseurl]
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Python"
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
cache: 'pip'
|
|
||||||
cache-dependency-path: scripts/requirements.txt
|
|
||||||
- name: "➕ Install dependencies"
|
|
||||||
run: |
|
|
||||||
pip install -r scripts/requirements.txt
|
|
||||||
- name: "📦 Asset creation"
|
|
||||||
run: |
|
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
||||||
export RELEASE="${GITHUB_REF/refs\/tags\//}"
|
|
||||||
else
|
|
||||||
export RELEASE="unstable"
|
|
||||||
fi
|
|
||||||
# The output path matches the final deployment path at spec.matrix.org
|
|
||||||
scripts/dump-openapi.py \
|
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
|
||||||
--api application-service \
|
|
||||||
-r "$RELEASE" \
|
|
||||||
-o spec/application-service-api/api.json
|
|
||||||
scripts/dump-openapi.py \
|
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
|
||||||
--api client-server \
|
|
||||||
-r "$RELEASE" \
|
|
||||||
-o spec/client-server-api/api.json
|
|
||||||
scripts/dump-openapi.py \
|
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
|
||||||
--api push-gateway \
|
|
||||||
-r "$RELEASE" \
|
|
||||||
-o spec/push-gateway-api/api.json
|
|
||||||
scripts/dump-openapi.py \
|
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
|
||||||
--api server-server \
|
|
||||||
-r "$RELEASE" \
|
|
||||||
-o spec/server-server-api/api.json
|
|
||||||
scripts/dump-openapi.py \
|
|
||||||
--base-url "https://spec.matrix.org${{ needs.calculate-baseurl.outputs.baseURL }}" \
|
|
||||||
--api identity \
|
|
||||||
-r "$RELEASE" \
|
|
||||||
-o spec/identity-service-api/api.json
|
|
||||||
tar -czf openapi.tar.gz spec
|
|
||||||
- name: "📤 Artifact upload"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: openapi-artifact
|
|
||||||
path: openapi.tar.gz
|
|
||||||
|
|
||||||
generate-changelog:
|
|
||||||
name: "📢 Run towncrier for changelog"
|
|
||||||
# skip for builds of git tags
|
|
||||||
if: "!startsWith(github.ref, 'refs/tags/')"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "➕ Setup Python"
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
- name: "➕ Install towncrier"
|
|
||||||
run: "pip install 'towncrier'"
|
|
||||||
- name: "Generate changelog"
|
|
||||||
run: ./scripts/generate-changelog.sh vUNSTABLE
|
|
||||||
- name: "📤 Artifact upload"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: changelog-artifact
|
|
||||||
path: content/changelog/unstable.md
|
|
||||||
|
|
||||||
build-spec:
|
|
||||||
name: "📖 Build the spec"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [calculate-baseurl, build-openapi, generate-changelog]
|
|
||||||
# run even if generate-changelog was skipped
|
|
||||||
if: ${{ always() }}
|
|
||||||
steps:
|
|
||||||
- name: "➕ Setup Node"
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
- name: "➕ Setup Hugo"
|
|
||||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
|
|
||||||
with:
|
|
||||||
hugo-version: ${{ env.HUGO_VERSION }}
|
|
||||||
extended: true
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "⚙️ npm"
|
|
||||||
run: |
|
|
||||||
npm i
|
|
||||||
npm run get-proposals
|
|
||||||
- name: "📥 Download generated changelog"
|
|
||||||
if: "needs.generate-changelog.result == 'success'"
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: changelog-artifact
|
|
||||||
path: content/changelog
|
|
||||||
- name: "⚙️ hugo"
|
|
||||||
run: hugo --baseURL "${{ needs.calculate-baseurl.outputs.baseURL }}" -d "spec"
|
|
||||||
# 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
|
|
||||||
# Works for /unstable/ and /v1.1/ as well.
|
|
||||||
- name: "📥 Spec definition download"
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: openapi-artifact
|
|
||||||
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
|
||||||
run: |
|
|
||||||
tar -xzf openapi.tar.gz
|
|
||||||
|
|
||||||
- name: "📦 Tarball creation"
|
|
||||||
run: tar -czf spec.tar.gz spec
|
|
||||||
- name: "📤 Artifact upload"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: spec-artifact
|
|
||||||
path: spec.tar.gz
|
|
||||||
|
|
||||||
htmlcheck:
|
|
||||||
name: "🔎 Validate generated HTML"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [calculate-baseurl, build-spec]
|
|
||||||
steps:
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: "📥 Fetch built spec"
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
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 }}"
|
|
||||||
|
|
||||||
- name: "Run htmltest"
|
|
||||||
uses: wjdp/htmltest-action@master
|
|
||||||
with:
|
|
||||||
config: .htmltest.yml
|
|
||||||
|
|
||||||
build-historical-spec:
|
|
||||||
name: "📖 Build the historical backup spec"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build-openapi]
|
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
||||||
steps:
|
|
||||||
- name: "➕ Setup Node"
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
- name: "➕ Setup Hugo"
|
|
||||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
|
|
||||||
with:
|
|
||||||
hugo-version: ${{ env.HUGO_VERSION }}
|
|
||||||
extended: true
|
|
||||||
- name: "📥 Source checkout"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: "⚙️ npm"
|
|
||||||
run: |
|
|
||||||
npm i
|
|
||||||
npm run get-proposals
|
|
||||||
- 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"
|
|
||||||
|
|
||||||
- name: "📥 Spec definition download"
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: openapi-artifact
|
|
||||||
- name: "📝 Unpack the OpenAPI definitions in the right location"
|
|
||||||
run: |
|
|
||||||
tar -xzf openapi.tar.gz
|
|
||||||
|
|
||||||
- name: "📦 Tarball creation"
|
|
||||||
run: tar -czf spec-historical.tar.gz spec
|
|
||||||
- name: "📤 Artifact upload"
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: spec-historical-artifact
|
|
||||||
path: spec-historical.tar.gz
|
|
||||||
72
.github/workflows/netlify.yaml
vendored
72
.github/workflows/netlify.yaml
vendored
|
|
@ -1,72 +0,0 @@
|
||||||
# GHA workflow which publishes previews of spec PRs to netlify.
|
|
||||||
#
|
|
||||||
# We keep this in a separate workflow to the main spec build, because it
|
|
||||||
# requires access to the Netlify secret. By having it run on `workflow_run`, we
|
|
||||||
# will only use the workflow definition file on the default branch, so we can
|
|
||||||
# ensure that the secret can't be exfiltrated.
|
|
||||||
#
|
|
||||||
|
|
||||||
name: Upload Preview Build to Netlify
|
|
||||||
on:
|
|
||||||
workflow_run:
|
|
||||||
workflows: [Spec]
|
|
||||||
types: [completed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
|
|
||||||
steps:
|
|
||||||
- name: "dump context data"
|
|
||||||
run: |
|
|
||||||
jq . < $GITHUB_EVENT_PATH
|
|
||||||
|
|
||||||
- name: "🔍 Read PR number"
|
|
||||||
id: readctx
|
|
||||||
# we need to find the PR number that corresponds to the branch, which we do by
|
|
||||||
# searching the GH API
|
|
||||||
env:
|
|
||||||
OWNER_LOGIN: ${{ github.event.workflow_run.head_repository.owner.login }}
|
|
||||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
||||||
run: |
|
|
||||||
head_branch="${OWNER_LOGIN}:${HEAD_BRANCH}"
|
|
||||||
echo "head branch: $head_branch"
|
|
||||||
pulls_uri="https://api.github.com/repos/${{ github.repository }}/pulls?head=$(jq -Rr '@uri' <<<$head_branch)"
|
|
||||||
pr_number=$(curl -H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' "$pulls_uri" |
|
|
||||||
jq -r '.[] | .number')
|
|
||||||
echo "PR number: $pr_number"
|
|
||||||
echo "prnumber=$pr_number" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: '📥 Download artifact'
|
|
||||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
|
||||||
with:
|
|
||||||
workflow: main.yaml
|
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
|
||||||
name: spec-artifact
|
|
||||||
|
|
||||||
- name: "📦 Extract Artifacts"
|
|
||||||
run: tar -xzvf spec.tar.gz && rm spec.tar.gz
|
|
||||||
|
|
||||||
- name: "📤 Deploy to Netlify"
|
|
||||||
id: netlify
|
|
||||||
uses: nwtgck/actions-netlify@4cbaf4c08f1a7bfa537d6113472ef4424e4eb654 # v3.0.0
|
|
||||||
with:
|
|
||||||
publish-dir: spec
|
|
||||||
deploy-message: "Deploy from GitHub Actions"
|
|
||||||
enable-pull-request-comment: false
|
|
||||||
enable-commit-comment: false
|
|
||||||
alias: pr${{ steps.readctx.outputs.prnumber }}
|
|
||||||
env:
|
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
|
||||||
timeout-minutes: 1
|
|
||||||
|
|
||||||
- name: "📝 Edit PR Description"
|
|
||||||
# v1.0.1
|
|
||||||
uses: Beakyn/gha-comment-pull-request@2167a7aee24f9e61ce76a23039f322e49a990409
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
pull-request-number: ${{ steps.readctx.outputs.prnumber }}
|
|
||||||
description-message: |
|
|
||||||
Preview: ${{ steps.netlify.outputs.deploy-url }}
|
|
||||||
43
.github/workflows/release.yaml
vendored
43
.github/workflows/release.yaml
vendored
|
|
@ -1,43 +0,0 @@
|
||||||
name: Release packages
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
jobs:
|
|
||||||
# Releases to npm after bumping the package.json version from 0.0.0 to $TAG.0 as the tags only contain MAJOR.MINOR
|
|
||||||
npm:
|
|
||||||
name: Publish to npm
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event.release.prerelease == false
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: packages/npm
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
steps:
|
|
||||||
- name: 🧮 Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: 🔧 Yarn cache
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
cache: "yarn"
|
|
||||||
cache-dependency-path: packages/npm/yarn.lock
|
|
||||||
registry-url: "https://registry.npmjs.org"
|
|
||||||
|
|
||||||
# Ensure npm 11.5.1 or later is installed
|
|
||||||
- name: Update npm
|
|
||||||
run: npm install -g npm@latest
|
|
||||||
|
|
||||||
- name: 🔨 Install dependencies
|
|
||||||
run: "yarn install --frozen-lockfile"
|
|
||||||
|
|
||||||
# We bump the package.json version to git, we just need it for publish to do the right thing
|
|
||||||
- name: 🎖 Bump package.json version
|
|
||||||
run: "yarn version --new-version ${VERSION#v} --no-git-tag-version"
|
|
||||||
env:
|
|
||||||
VERSION: ${{ github.event.release.tag_name }}.0
|
|
||||||
|
|
||||||
- name: 🚀 Publish to npm
|
|
||||||
run: npm publish --provenance --access public --tag latest
|
|
||||||
19
.github/workflows/spell-check.yaml
vendored
19
.github/workflows/spell-check.yaml
vendored
|
|
@ -1,19 +0,0 @@
|
||||||
name: Spell Check
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run:
|
|
||||||
name: Spell Check with Typos
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Actions Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check spelling of proposals
|
|
||||||
uses: crate-ci/typos@f2c1f08a7b3c1b96050cb786baaa2a94797bdb7d # v1.20.10
|
|
||||||
with:
|
|
||||||
config: ${{github.workspace}}/.github/_typos.toml
|
|
||||||
23
.gitignore
vendored
23
.gitignore
vendored
|
|
@ -1,17 +1,8 @@
|
||||||
node_modules
|
scripts/gen
|
||||||
/data/msc
|
scripts/continuserv/continuserv
|
||||||
/env*
|
scripts/speculator/speculator
|
||||||
/resources
|
templating/out
|
||||||
/scripts/openapi
|
|
||||||
/scripts/tmp
|
|
||||||
/hugo-config.toml
|
|
||||||
/public
|
|
||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
supporting-docs/_site
|
||||||
_rendered.rst
|
supporting-docs/.sass-cache
|
||||||
/.vscode/
|
api/node_modules
|
||||||
/.idea/
|
|
||||||
/spec/
|
|
||||||
changelogs/rendered.*
|
|
||||||
.hugo_build.lock
|
|
||||||
hugo_stats.json
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# config file for htmltest. This is used by one of the checks in Github
|
|
||||||
# Actions.
|
|
||||||
|
|
||||||
IgnoreDirectoryMissingTrailingSlash: true
|
|
||||||
DirectoryPath: spec
|
|
||||||
CheckExternal: false
|
|
||||||
IgnoreInternalEmptyHash: true
|
|
||||||
41
CHANGELOG.rst
Normal file
41
CHANGELOG.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
.. This file is automatically processed by the templating system. To make it
|
||||||
|
.. happy, you MUST use '=' as the title underline and you MUST stick the version
|
||||||
|
.. in the title. The version MUST follow the numbering format
|
||||||
|
.. "v<num>.<num>.<num>" - You cannot use a-z. If the templating system fails to
|
||||||
|
.. find the right info, it will be treated as a test failure and so will show up
|
||||||
|
.. in Jenkins. Comments like this are ignored by both RST and the templating
|
||||||
|
.. system. Add the newest release notes beneath this comment.
|
||||||
|
|
||||||
|
Specification changes in v0.2.0 (2015-10-02)
|
||||||
|
============================================
|
||||||
|
|
||||||
|
This update fundamentally restructures the specification. The specification has
|
||||||
|
been split into more digestible "modules" which each describe a particular
|
||||||
|
function (e.g. typing). This was done in order make the specification easier to
|
||||||
|
maintain and help define which modules are mandatory for certain types
|
||||||
|
of clients. Types of clients along with the mandatory modules can be found in a
|
||||||
|
new "Feature Profiles" section. This update also begins to aggressively
|
||||||
|
standardise on using Swagger and JSON Schema to document HTTP endpoints and
|
||||||
|
Events respectively. It also introduces a number of new concepts to Matrix.
|
||||||
|
|
||||||
|
Additions:
|
||||||
|
- New section: Feature Profiles.
|
||||||
|
- New section: Receipts.
|
||||||
|
- New section: Room history visibility.
|
||||||
|
- New event: ``m.receipt``.
|
||||||
|
- New event: ``m.room.canonical_alias``
|
||||||
|
- New event: ``m.room.history_visibility``
|
||||||
|
- New keys: ``/createRoom`` - allows room "presets" using ``preset`` and
|
||||||
|
``initial_state`` keys.
|
||||||
|
- New endpoint: ``/tokenrefresh`` - Related to refreshing access tokens.
|
||||||
|
|
||||||
|
Modifications:
|
||||||
|
- Convert most of the older HTTP APIs to Swagger documentation.
|
||||||
|
- Convert most of the older event formats to JSON Schema.
|
||||||
|
- Move selected client-server sections to be "Modules".
|
||||||
|
|
||||||
|
Specification changes in v0.1.0 (2015-06-01)
|
||||||
|
============================================
|
||||||
|
- First numbered release.
|
||||||
|
- Restructure the format of Event information. Add more information.
|
||||||
|
- Restructure the format of the Client-Server HTTP APIs.
|
||||||
170
CONTRIBUTING.rst
170
CONTRIBUTING.rst
|
|
@ -1,170 +0,0 @@
|
||||||
Contributing to matrix-spec
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Everyone is welcome to contribute to the Matrix specification!
|
|
||||||
|
|
||||||
Please ensure that you sign off your contributions. See `Sign off`_ below.
|
|
||||||
|
|
||||||
Code style
|
|
||||||
----------
|
|
||||||
|
|
||||||
The documentation style is described at
|
|
||||||
https://github.com/matrix-org/matrix-spec/blob/main/meta/documentation_style.rst.
|
|
||||||
|
|
||||||
Matrix-spec workflows
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
Specification changes
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The Matrix specification documents the APIs which Matrix clients and servers use.
|
|
||||||
For this to be effective, the APIs need to be present and working correctly in a
|
|
||||||
server before they can be documented in the specification. This process can take
|
|
||||||
some time to complete.
|
|
||||||
|
|
||||||
Changes to the protocol (new endpoints, ideas, etc) need to go through the
|
|
||||||
`proposals process <https://matrix.org/docs/spec/proposals>`_.
|
|
||||||
|
|
||||||
Other changes
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The above process is unnecessary for smaller changes, and those which do not
|
|
||||||
put new requirements on servers. This category of changes includes the
|
|
||||||
following:
|
|
||||||
|
|
||||||
* Changes to the scripts used to generate the specification.
|
|
||||||
|
|
||||||
* Addition of features which have been in use in practice for some time, but
|
|
||||||
have never made it into the spec (including anything with the `spec-omission
|
|
||||||
<https://github.com/matrix-org/matrix-spec/labels/spec-omission>`_ label).
|
|
||||||
|
|
||||||
* Likewise, corrections to the specification, to fix situations where, in
|
|
||||||
practice, servers and clients behave differently to the specification,
|
|
||||||
including anything with the `spec-bug
|
|
||||||
<https://github.com/matrix-org/matrix-spec/labels/spec-bug>`_ label.
|
|
||||||
|
|
||||||
(If there is any doubt about whether it is the spec or the implementations
|
|
||||||
that need fixing, please discuss it with us first in `#matrix-spec:matrix.org`_.)
|
|
||||||
|
|
||||||
* Clarifications to the specification which do not change the behaviour of
|
|
||||||
Matrix servers or clients in a way which might introduce compatibility
|
|
||||||
problems for existing deployments. This includes anything with the
|
|
||||||
`clarification <https://github.com/matrix-org/matrix-spec/labels/clarification>`_
|
|
||||||
label.
|
|
||||||
|
|
||||||
For example, areas where the specification is unclear do not require a proposal
|
|
||||||
to fix. On the other hand, introducing new behaviour is best represented by a
|
|
||||||
proposal.
|
|
||||||
|
|
||||||
* Design or aesthetic changes, such as improving accessibility, colour schemes,
|
|
||||||
etc. Please check in with us at `#matrix-docs:matrix.org`_ with your proposed
|
|
||||||
design change before opening a PR so we can work with you on it.
|
|
||||||
|
|
||||||
For such changes, please do just open a `pull request`_. If you're not sure if
|
|
||||||
your change is covered by the above, please visit `#matrix-spec:matrix.org` and
|
|
||||||
ask.
|
|
||||||
|
|
||||||
.. _`pull request`: https://help.github.com/articles/about-pull-requests
|
|
||||||
.. _`#matrix-spec:matrix.org`: https://matrix.to/#/#matrix-spec:matrix.org
|
|
||||||
.. _`#matrix-docs:matrix.org`: https://matrix.to/#/#matrix-docs:matrix.org
|
|
||||||
|
|
||||||
|
|
||||||
Adding to the changelog
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
All changes to the contents of this repository require a changelog entry. Adding to the changelog can only
|
|
||||||
be done after you've opened your pull request, so be sure to do that first.
|
|
||||||
|
|
||||||
The changelog is managed by `Towncrier <https://github.com/twisted/towncrier>`_ in the
|
|
||||||
form of "news fragments". Depending on which API you changed, an entry should be added to
|
|
||||||
each relevant API's ``newsfragments`` directory. A directory exists for each API under
|
|
||||||
``changelogs/``. For instance, news fragments for the client-server API are stored
|
|
||||||
under ``changelogs/client_server/newsfragments``. Any changes to the repository that do
|
|
||||||
not affect the spec content itself, such as changes to the build script, formatting, CSS,
|
|
||||||
etc. should be documented under ``changelogs/internal/newsfragments``.
|
|
||||||
|
|
||||||
To create a changelog entry, create a file named in the format ``prNumber.type`` in
|
|
||||||
the ``newsfragments`` directory. The ``type`` can be one of the following:
|
|
||||||
|
|
||||||
* ``new`` - Used when adding new endpoints. Please have the file contents be the
|
|
||||||
method and route being added, surrounded in markdown code tags. For example: \`POST
|
|
||||||
/accounts/whoami\`.
|
|
||||||
|
|
||||||
* ``feature`` - Used when adding backwards-compatible changes to the API.
|
|
||||||
|
|
||||||
* ``clarification`` - Used when an area of the spec is being improved upon and does
|
|
||||||
not change or introduce any functionality.
|
|
||||||
|
|
||||||
* ``breaking`` - Used when the change is not backwards compatible.
|
|
||||||
|
|
||||||
* ``deprecation`` - Used when deprecating something.
|
|
||||||
|
|
||||||
* ``removal`` - Used when removing something that was unused or previously deprecated.
|
|
||||||
|
|
||||||
All news fragments must have a brief summary explaining the change in the
|
|
||||||
contents of the file. The summary must end in a full stop to be in line with
|
|
||||||
the style guide and formatting must be done using Markdown.
|
|
||||||
|
|
||||||
Sign off
|
|
||||||
--------
|
|
||||||
|
|
||||||
We ask that everybody who contributes to this project signs off their
|
|
||||||
contributions, as explained below.
|
|
||||||
|
|
||||||
We follow a simple 'inbound=outbound' model for contributions: the act of
|
|
||||||
submitting an 'inbound' contribution means that the contributor agrees to
|
|
||||||
license their contribution under the same terms as the project's overall 'outbound'
|
|
||||||
license - in our case, this is Apache Software License v2 (see LICENSE).
|
|
||||||
|
|
||||||
In order to have a concrete record that your contribution is intentional
|
|
||||||
and you agree to license it under the same terms as the project's license, we've adopted the
|
|
||||||
same lightweight approach used by the `Linux Kernel <https://www.kernel.org/doc/html/latest/process/submitting-patches.html>`_,
|
|
||||||
`Docker <https://github.com/docker/docker/blob/master/CONTRIBUTING.md>`_, and many other
|
|
||||||
projects: the `Developer Certificate of Origin <http://developercertificate.org/>`_
|
|
||||||
(DCO). This is a simple declaration that you wrote
|
|
||||||
the contribution or otherwise have the right to contribute it to Matrix::
|
|
||||||
|
|
||||||
Developer Certificate of Origin
|
|
||||||
Version 1.1
|
|
||||||
|
|
||||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
|
||||||
660 York Street, Suite 102,
|
|
||||||
San Francisco, CA 94110 USA
|
|
||||||
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies of this
|
|
||||||
license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Developer's Certificate of Origin 1.1
|
|
||||||
|
|
||||||
By making a contribution to this project, I certify that:
|
|
||||||
|
|
||||||
(a) The contribution was created in whole or in part by me and I
|
|
||||||
have the right to submit it under the open source license
|
|
||||||
indicated in the file; or
|
|
||||||
|
|
||||||
(b) The contribution is based upon previous work that, to the best
|
|
||||||
of my knowledge, is covered under an appropriate open source
|
|
||||||
license and I have the right under that license to submit that
|
|
||||||
work with modifications, whether created in whole or in part
|
|
||||||
by me, under the same open source license (unless I am
|
|
||||||
permitted to submit under a different license), as indicated
|
|
||||||
in the file; or
|
|
||||||
|
|
||||||
(c) The contribution was provided directly to me by some other
|
|
||||||
person who certified (a), (b) or (c) and I have not modified
|
|
||||||
it.
|
|
||||||
|
|
||||||
(d) I understand and agree that this project and the contribution
|
|
||||||
are public and that a record of the contribution (including all
|
|
||||||
personal information I submit with it, including my sign-off) is
|
|
||||||
maintained indefinitely and may be redistributed consistent with
|
|
||||||
this project or the open source license(s) involved.
|
|
||||||
|
|
||||||
If you agree to this for your contribution, then all that's needed is to
|
|
||||||
include the line in your commit or pull request comment::
|
|
||||||
|
|
||||||
Signed-off-by: Your Name <your@email.example.org>
|
|
||||||
|
|
||||||
Git allows you to add this signoff automatically when using the ``-s``
|
|
||||||
flag to ``git commit``, which uses the name and email set in your
|
|
||||||
``user.name`` and ``user.email`` git configs.
|
|
||||||
177
LICENSE
177
LICENSE
|
|
@ -1,177 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
101
README.md
101
README.md
|
|
@ -1,101 +0,0 @@
|
||||||
# Matrix Specification
|
|
||||||
|
|
||||||
This repository contains the Matrix Specification. The current release version is rendered at https://spec.matrix.org, while the latest available build of the `main` branch is at https://spec.matrix.org/unstable.
|
|
||||||
|
|
||||||
Developers looking to use Matrix should join [#matrix-dev:matrix.org](https://matrix.to/#/#matrix-dev:matrix.org)
|
|
||||||
on Matrix for help.
|
|
||||||
|
|
||||||
Spec authors and proposal writers are welcome to join [#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org).
|
|
||||||
We welcome contributions! See [CONTRIBUTING.rst](./CONTRIBUTING.rst) for details.
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
The Matrix spec is compiled with [Hugo](https://gohugo.io/) (a static site generator) with the following structure:
|
|
||||||
|
|
||||||
* `/assets`: assets that need postprocessing using [Hugo Pipes](https://gohugo.io/hugo-pipes/introduction/).
|
|
||||||
For example, Sass files would go here.
|
|
||||||
|
|
||||||
* `/content`: files that will become pages in the site go here. Typically these are Markdown files with some YAML front
|
|
||||||
matter indicating, [among other things](https://gohugo.io/content-management/front-matter/), what layout should be
|
|
||||||
applied to this page. The organization of files under `/content` determines the organization of pages in the built
|
|
||||||
site.
|
|
||||||
|
|
||||||
* `/data`: this can contain TOML, YAML, or JSON files. Files kept here are directly available to template code as
|
|
||||||
[data objects](https://gohugo.io/templates/data-templates/), so templates don't need to load them from a file and
|
|
||||||
parse them. This is also where our OpenAPI definitions and schemas are.
|
|
||||||
|
|
||||||
* `/layouts`: this contains [Hugo templates](https://gohugo.io/templates/). Some templates define the overall layout of
|
|
||||||
a page: for example, whether it has header, footer, sidebar, and so on.
|
|
||||||
* `/layouts/partials`: these templates can be called from other templates, so they can be used to factor out
|
|
||||||
template code that's used in more than one template. An obvious example here is something like a sidebar, where
|
|
||||||
several different page layouts might all include the sidebar. But also, partial templates can return values: this
|
|
||||||
means they can be used like functions, that can be called by multiple templates to do some common processing.
|
|
||||||
* `/layouts/shortcodes`: these templates can be called directly from files in `/content`.
|
|
||||||
|
|
||||||
* `/static`: static files which don't need preprocessing. JS or CSS files could live here.
|
|
||||||
|
|
||||||
* `/themes`: you can use just Hugo or use it with a theme. Themes primarily provide additional templates, which are
|
|
||||||
supplied in a `/themes/$theme_name/layouts` directory. You can use a theme but customise it by providing your own
|
|
||||||
versions of any of the theme layouts in the base `/layouts` directory. That is, if a theme provides
|
|
||||||
`/themes/$theme_name/layouts/sidebar.html` and you provide `/layouts/sidebar.html`, then your version of the
|
|
||||||
template will be used.
|
|
||||||
|
|
||||||
It also has the following top-level file:
|
|
||||||
|
|
||||||
* `config.toml`: site-wide configuration settings. Some of these are built-in and you can add your own. Config settings
|
|
||||||
defined here are available in templates. All these directories above are configurable via `config.toml` settings.
|
|
||||||
|
|
||||||
Additionally, the following directories may be of interest:
|
|
||||||
|
|
||||||
* `/attic`: Here contains historical sections of specification and legacy drafts for the specification.
|
|
||||||
* `/changelogs`: Various bits of changelog for the specification areas.
|
|
||||||
* `/data-definitions`: Bits of structured data consumable by Matrix implementations.
|
|
||||||
* `/meta`: Documentation relating to the spec's processes that are otherwise untracked (release instructions, etc).
|
|
||||||
* `/scripts`: Various scripts for generating the spec and validating its contents.
|
|
||||||
* `/packages`: Various packages for shipping spec files like OpenAPI bindings and data definitions.
|
|
||||||
|
|
||||||
## Authoring changes to the spec
|
|
||||||
|
|
||||||
Please read [CONTRIBUTING.rst](./CONTRIBUTING.rst) before authoring a change to the spec. Note that spec authoring takes
|
|
||||||
place after an MSC has been accepted, not as part of a proposal itself.
|
|
||||||
|
|
||||||
1. Install the extended version (often the OS default) of Hugo:
|
|
||||||
<https://gohugo.io/getting-started/installing>. Note that at least Hugo
|
|
||||||
v0.146.0 is required.
|
|
||||||
|
|
||||||
Alternatively, use the Docker image at
|
|
||||||
https://hub.docker.com/r/klakegg/hugo/. (The "extended edition" is required
|
|
||||||
to process the SCSS.)
|
|
||||||
2. Run `npm i` to install the dependencies. Note that this will require NodeJS to be installed.
|
|
||||||
3. Run `npm run get-proposals` to seed proposal data. This is merely for populating the content of the "Spec Change Proposals"
|
|
||||||
page and is not required.
|
|
||||||
4. Run `hugo serve` (or `docker run --rm -it -v $(pwd):/src -p 1313:1313
|
|
||||||
klakegg/hugo:ext serve`) to run a local webserver which builds whenever a file
|
|
||||||
change is detected. If watching doesn't appear to be working for you, try
|
|
||||||
adding `--disableFastRender` to the commandline.
|
|
||||||
5. Edit the specification 🙂
|
|
||||||
|
|
||||||
We use a highly customized [Docsy](https://www.docsy.dev/) theme for our generated site, which uses Bootstrap and Font
|
|
||||||
Awesome. If you're looking at making design-related changes to the spec site, please coordinate with us in
|
|
||||||
[#matrix-docs:matrix.org](https://matrix.to/#/#matrix-docs:matrix.org) before opening a PR.
|
|
||||||
|
|
||||||
## Building the specification
|
|
||||||
|
|
||||||
If for some reason you're not a CI/CD system and want to render a static version of the spec for yourself, follow the above
|
|
||||||
steps for authoring changes to the specification and instead of `hugo serve` run `hugo -d "spec"` - this will generate the
|
|
||||||
spec to `/spec`. If you'd like to serve the spec off a path instead of a domain root (eg: `/unstable`), add `--baseURL "/unstable"`
|
|
||||||
to the `hugo -d "spec"` command.
|
|
||||||
|
|
||||||
For building the OpenAPI definitions, create a python3 virtualenv and activate it. Then run `pip install -r ./scripts/requirements.txt`
|
|
||||||
and finally `python ./scripts/dump-openapi.py` to generate it to `./scripts/openapi/api-docs.json`. To make use of the generated file,
|
|
||||||
there are a number of options:
|
|
||||||
|
|
||||||
* You can open `./scripts/openapi-preview.html` in your browser, and then open the file by clicking on `Local JSON File`.
|
|
||||||
* You can run a local HTTP server by running `./scripts/openapi-http-server.py`, and then view the documentation by
|
|
||||||
opening `./scripts/openapi-preview.html` in your browser.
|
|
||||||
|
|
||||||
## Issue tracking
|
|
||||||
|
|
||||||
Specification issues are tracked on github at <https://github.com/matrix-org/matrix-spec/issues>.
|
|
||||||
|
|
||||||
See [meta/github-labels.rst](./meta/github-labels.rst) for information on what the labels mean.
|
|
||||||
30
README.rst
Normal file
30
README.rst
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
This repository contains the documentation for Matrix.
|
||||||
|
|
||||||
|
Structure
|
||||||
|
=========
|
||||||
|
|
||||||
|
- ``api`` : Contains the HTTP API specification.
|
||||||
|
- ``drafts`` : Contains documents which will make it into the specification
|
||||||
|
and/or supporting documentation at some point in the future.
|
||||||
|
- ``event-schemas`` : Contains the `JSON Schema`_ for all Matrix events
|
||||||
|
contained in the specification, along with example JSON files.
|
||||||
|
- ``meta`` : Contains documents outlining the processes involved when writing
|
||||||
|
documents, e.g. documentation style, guidelines.
|
||||||
|
- ``scripts`` : Contains scripts to generate formatted versions of the
|
||||||
|
documentation, typically HTML.
|
||||||
|
- ``specification`` : Contains the specification split up into sections.
|
||||||
|
- ``supporting-docs`` : Contains additional documents which explain design
|
||||||
|
decisions, examples, use cases, etc.
|
||||||
|
- ``templating`` : Contains the templates and templating system used to
|
||||||
|
generate the spec.
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
============
|
||||||
|
|
||||||
|
Known issues with the specification are represented as JIRA issues at
|
||||||
|
https://matrix.org/jira/browse/SPEC
|
||||||
|
|
||||||
|
If you want to ask more about the specification, or have suggestions for
|
||||||
|
improvements, join us on ``#matrix-dev:matrix.org`` via https://matrix.org/beta.
|
||||||
|
|
||||||
|
.. _JSON Schema: http://json-schema.org/
|
||||||
4
api/README
Normal file
4
api/README
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
To get this running:
|
||||||
|
python -m SimpleHTTPServer
|
||||||
|
|
||||||
|
Go to http://localhost:8000/swagger.html
|
||||||
118
api/check_examples.py
Executable file
118
api/check_examples.py
Executable file
|
|
@ -0,0 +1,118 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def import_error(module, package, debian, error):
|
||||||
|
sys.stderr.write((
|
||||||
|
"Error importing %(module)s: %(error)r\n"
|
||||||
|
"To install %(module)s run:\n"
|
||||||
|
" pip install %(package)s\n"
|
||||||
|
"or on Debian run:\n"
|
||||||
|
" sudo apt-get install python-%(debian)s\n"
|
||||||
|
) % locals())
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import jsonschema
|
||||||
|
except ImportError as e:
|
||||||
|
import_error("jsonschema", "jsonschema", "jsonschema", e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError as e:
|
||||||
|
import_error("yaml", "PyYAML", "yaml", e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def check_parameter(filepath, request, parameter):
|
||||||
|
schema = parameter.get("schema")
|
||||||
|
example = None
|
||||||
|
try:
|
||||||
|
example_json = schema.get('example')
|
||||||
|
if example_json and not schema.get("format") == "byte":
|
||||||
|
example = json.loads(example_json)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Error parsing JSON example request for %r" % (
|
||||||
|
request
|
||||||
|
), e)
|
||||||
|
fileurl = "file://" + os.path.abspath(filepath)
|
||||||
|
if example and schema:
|
||||||
|
try:
|
||||||
|
print ("Checking request schema for: %r %r" % (
|
||||||
|
filepath, request
|
||||||
|
))
|
||||||
|
# Setting the 'id' tells jsonschema where the file is so that it
|
||||||
|
# can correctly resolve relative $ref references in the schema
|
||||||
|
schema['id'] = fileurl
|
||||||
|
jsonschema.validate(example, schema)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Error validating JSON schema for %r %r" % (
|
||||||
|
request, code
|
||||||
|
), e)
|
||||||
|
|
||||||
|
|
||||||
|
def check_response(filepath, request, code, response):
|
||||||
|
example = None
|
||||||
|
try:
|
||||||
|
example_json = response.get('examples', {}).get('application/json')
|
||||||
|
if example_json:
|
||||||
|
example = json.loads(example_json)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Error parsing JSON example response for %r %r" % (
|
||||||
|
request, code
|
||||||
|
), e)
|
||||||
|
schema = response.get('schema')
|
||||||
|
fileurl = "file://" + os.path.abspath(filepath)
|
||||||
|
if example and schema:
|
||||||
|
try:
|
||||||
|
print ("Checking response schema for: %r %r %r" % (
|
||||||
|
filepath, request, code
|
||||||
|
))
|
||||||
|
# Setting the 'id' tells jsonschema where the file is so that it
|
||||||
|
# can correctly resolve relative $ref references in the schema
|
||||||
|
schema['id'] = fileurl
|
||||||
|
jsonschema.validate(example, schema)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Error validating JSON schema for %r %r" % (
|
||||||
|
request, code
|
||||||
|
), e)
|
||||||
|
|
||||||
|
|
||||||
|
def check_swagger_file(filepath):
|
||||||
|
with open(filepath) as f:
|
||||||
|
swagger = yaml.load(f)
|
||||||
|
|
||||||
|
for path, path_api in swagger.get('paths', {}).items():
|
||||||
|
|
||||||
|
for method, request_api in path_api.items():
|
||||||
|
request = "%s %s" % (method.upper(), path)
|
||||||
|
for parameter in request_api.get('parameters', ()):
|
||||||
|
if parameter['in'] == 'body':
|
||||||
|
check_parameter(filepath, request, parameter)
|
||||||
|
|
||||||
|
try:
|
||||||
|
responses = request_api['responses']
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError("No responses for %r" % (request,))
|
||||||
|
for code, response in responses.items():
|
||||||
|
check_response(filepath, request, code, response)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
paths = sys.argv[1:]
|
||||||
|
if not paths:
|
||||||
|
paths = []
|
||||||
|
for (root, dirs, files) in os.walk(os.curdir):
|
||||||
|
for filename in files:
|
||||||
|
if filename.endswith(".yaml"):
|
||||||
|
paths.append(os.path.join(root, filename))
|
||||||
|
for path in paths:
|
||||||
|
try:
|
||||||
|
check_swagger_file(path)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Error checking file %r" % (path,), e)
|
||||||
50
api/client-server/api-docs
Normal file
50
api/client-server/api-docs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "-login",
|
||||||
|
"description": "Login operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-registration",
|
||||||
|
"description": "Registration operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-rooms",
|
||||||
|
"description": "Room operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-profile",
|
||||||
|
"description": "Profile operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-presence",
|
||||||
|
"description": "Presence operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-events",
|
||||||
|
"description": "Event operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-directory",
|
||||||
|
"description": "Directory operations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "-content",
|
||||||
|
"description": "Content repository operations"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authorizations": {
|
||||||
|
"token": {
|
||||||
|
"scopes": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"title": "Matrix Client-Server API Reference",
|
||||||
|
"description": "This contains the client-server API for the reference implementation of the home server",
|
||||||
|
"termsOfServiceUrl": "http://matrix.org",
|
||||||
|
"license": "Apache 2.0",
|
||||||
|
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
|
}
|
||||||
|
}
|
||||||
119
api/client-server/api-docs-content
Normal file
119
api/client-server/api-docs-content
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"basePath": "http://localhost:8008/_matrix",
|
||||||
|
"resourcePath": "/media/v1/",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/media/v1/upload",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"summary": "Upload some content to the content repository.",
|
||||||
|
"type": "ContentUploadResponse",
|
||||||
|
"nickname": "upload_content",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The file to upload.",
|
||||||
|
"required": true,
|
||||||
|
"type": "file",
|
||||||
|
"paramType": "body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/media/v1/download/{serverName}/{mediaId}",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get the content stored at this address.",
|
||||||
|
"type": "file",
|
||||||
|
"nickname": "download_content",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "serverName",
|
||||||
|
"description": "The serverName from the mxc://<serverName>/<mediaId> URI (the authority component).",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mediaId",
|
||||||
|
"description": "The mediaId from the mxc://<serverName>/<mediaId> URI (the path component).",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/media/v1/thumbnail/{serverName}/{mediaId}",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get a thumbnail of the content stored at this address.",
|
||||||
|
"type": "file",
|
||||||
|
"nickname": "thumbnail_content",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "serverName",
|
||||||
|
"description": "The serverName from the mxc://<serverName>/<mediaId> URI (the authority component).",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mediaId",
|
||||||
|
"description": "The mediaId from the mxc://<serverName>/<mediaId> URI (the path component).",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "width",
|
||||||
|
"description": "The desired width of the thumbnail.",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"paramType": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "height",
|
||||||
|
"description": "The desired height of the thumbnail.",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"paramType": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "method",
|
||||||
|
"description": "The desired resizing method.",
|
||||||
|
"enum": [
|
||||||
|
"crop",
|
||||||
|
"scale"
|
||||||
|
],
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "query"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"ContentUploadResponse": {
|
||||||
|
"id": "ContentUploadResponse",
|
||||||
|
"properties": {
|
||||||
|
"content_uri": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The mxc:// URI where this content is stored. This is of the form 'mxc://{serverName}/{mediaId}'",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
api/client-server/api-docs-directory
Normal file
101
api/client-server/api-docs-directory
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"resourcePath": "/directory",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/directory/room/{roomAlias}",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get the room ID corresponding to this room alias.",
|
||||||
|
"notes": "Volatile: This API is likely to change.",
|
||||||
|
"type": "DirectoryResponse",
|
||||||
|
"nickname": "get_room_id_for_alias",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "roomAlias",
|
||||||
|
"description": "The room alias.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"summary": "Create a new mapping from room alias to room ID.",
|
||||||
|
"notes": "Volatile: This API is likely to change.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "add_room_alias",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "roomAlias",
|
||||||
|
"description": "The room alias to set.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The room ID to set.",
|
||||||
|
"required": true,
|
||||||
|
"type": "RoomAliasRequest",
|
||||||
|
"paramType": "body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"summary": "Removes a mapping of room alias to room ID.",
|
||||||
|
"notes": "Only privileged users can perform this action.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "remove_room_alias",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "roomAlias",
|
||||||
|
"description": "The room alias to remove.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"DirectoryResponse": {
|
||||||
|
"id": "DirectoryResponse",
|
||||||
|
"properties": {
|
||||||
|
"room_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The fully-qualified room ID.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"servers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "string"
|
||||||
|
},
|
||||||
|
"description": "A list of servers that know about this room.",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RoomAliasRequest": {
|
||||||
|
"id": "RoomAliasRequest",
|
||||||
|
"properties": {
|
||||||
|
"room_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The room ID to map the alias to.",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
247
api/client-server/api-docs-events
Normal file
247
api/client-server/api-docs-events
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"resourcePath": "/events",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/events",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Listen on the event stream",
|
||||||
|
"notes": "This can only be done by the logged in user. This will block until an event is received, or until the timeout is reached.",
|
||||||
|
"type": "PaginationChunk",
|
||||||
|
"nickname": "get_event_stream",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "from",
|
||||||
|
"description": "The token to stream from.",
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "timeout",
|
||||||
|
"description": "The maximum time in milliseconds to wait for an event.",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"paramType": "query"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"responseMessages": [
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "Bad pagination token."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/events/{eventId}",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get information about a single event.",
|
||||||
|
"notes": "Get information about a single event.",
|
||||||
|
"type": "Event",
|
||||||
|
"nickname": "get_event",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "eventId",
|
||||||
|
"description": "The event ID to get.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responseMessages": [
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"message": "Event not found."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/initialSync",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get this user's current state.",
|
||||||
|
"notes": "Get this user's current state.",
|
||||||
|
"type": "InitialSyncResponse",
|
||||||
|
"nickname": "initial_sync",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"description": "The maximum number of messages to return for each room.",
|
||||||
|
"type": "integer",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/publicRooms",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get a list of publicly visible rooms.",
|
||||||
|
"type": "PublicRoomsPaginationChunk",
|
||||||
|
"nickname": "get_public_room_list"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"PaginationChunk": {
|
||||||
|
"id": "PaginationChunk",
|
||||||
|
"properties": {
|
||||||
|
"start": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"chunk": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "An array of events.",
|
||||||
|
"required": true,
|
||||||
|
"items": {
|
||||||
|
"$ref": "Event"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Event": {
|
||||||
|
"id": "Event",
|
||||||
|
"properties": {
|
||||||
|
"event_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "An ID which uniquely identifies this event.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"room_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The room in which this event occurred.",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PublicRoomInfo": {
|
||||||
|
"id": "PublicRoomInfo",
|
||||||
|
"properties": {
|
||||||
|
"aliases": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of room aliases for this room.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the room, as given by the m.room.name state event."
|
||||||
|
},
|
||||||
|
"room_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The room ID for this public room.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"topic": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The topic of this room, as given by the m.room.topic state event."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PublicRoomsPaginationChunk": {
|
||||||
|
"id": "PublicRoomsPaginationChunk",
|
||||||
|
"properties": {
|
||||||
|
"start": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A token which correlates to the first value in \"chunk\" for paginating.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A token which correlates to the last value in \"chunk\" for paginating.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"chunk": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of public room data.",
|
||||||
|
"required": true,
|
||||||
|
"items": {
|
||||||
|
"$ref": "PublicRoomInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"InitialSyncResponse": {
|
||||||
|
"id": "InitialSyncResponse",
|
||||||
|
"properties": {
|
||||||
|
"end": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A streaming token which can be used with /events to continue from this snapshot of data.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of presence events.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Event"
|
||||||
|
},
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"rooms": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of initial sync room data.",
|
||||||
|
"required": false,
|
||||||
|
"items": {
|
||||||
|
"$ref": "InitialSyncRoomData"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"InitialSyncRoomData": {
|
||||||
|
"id": "InitialSyncRoomData",
|
||||||
|
"properties": {
|
||||||
|
"membership": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "This user's membership state in this room.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"room_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The ID of this room.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"type": "PaginationChunk",
|
||||||
|
"description": "The most recent messages for this room, governed by the limit parameter.",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of state events representing the current state of the room.",
|
||||||
|
"required": false,
|
||||||
|
"items": {
|
||||||
|
"$ref": "Event"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
api/client-server/api-docs-login
Normal file
120
api/client-server/api-docs-login
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"nickname": "get_login_info",
|
||||||
|
"notes": "All login stages MUST be mentioned if there is >1 login type.",
|
||||||
|
"summary": "Get the login mechanism to use when logging in.",
|
||||||
|
"type": "LoginFlows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"nickname": "submit_login",
|
||||||
|
"notes": "If this is part of a multi-stage login, there MUST be a 'session' key.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "A login submission",
|
||||||
|
"name": "body",
|
||||||
|
"paramType": "body",
|
||||||
|
"required": true,
|
||||||
|
"type": "LoginSubmission"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responseMessages": [
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "Bad login type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "Missing JSON keys"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Submit a login action.",
|
||||||
|
"type": "LoginResult"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"path": "/login"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"LoginFlows": {
|
||||||
|
"id": "LoginFlows",
|
||||||
|
"properties": {
|
||||||
|
"flows": {
|
||||||
|
"description": "A list of valid login flows.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "LoginInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LoginInfo": {
|
||||||
|
"id": "LoginInfo",
|
||||||
|
"properties": {
|
||||||
|
"stages": {
|
||||||
|
"description": "Multi-stage login only: An array of all the login types required to login.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"description": "The login type that must be used when logging in.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LoginResult": {
|
||||||
|
"id": "LoginResult",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"description": "The access token for this user's login if this is the final stage of the login process.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"description": "The user's fully-qualified user ID.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"next": {
|
||||||
|
"description": "Multi-stage login only: The next login type to submit.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"description": "Multi-stage login only: The session token to send when submitting the next login type.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LoginSubmission": {
|
||||||
|
"id": "LoginSubmission",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "The type of login being submitted.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"description": "Multi-stage login only: The session token from an earlier login stage.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"_login_type_defined_keys_": {
|
||||||
|
"description": "Keys as defined by the specified login type, e.g. \"user\", \"password\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"resourcePath": "/login",
|
||||||
|
"swaggerVersion": "1.2"
|
||||||
|
}
|
||||||
|
|
||||||
164
api/client-server/api-docs-presence
Normal file
164
api/client-server/api-docs-presence
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"resourcePath": "/presence",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/presence/{userId}/status",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"summary": "Update this user's presence state.",
|
||||||
|
"notes": "This can only be done by the logged in user.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "update_presence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The new presence state",
|
||||||
|
"required": true,
|
||||||
|
"type": "PresenceUpdate",
|
||||||
|
"paramType": "body"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose presence to set.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get this user's presence state.",
|
||||||
|
"notes": "Get this user's presence state.",
|
||||||
|
"type": "PresenceUpdate",
|
||||||
|
"nickname": "get_presence",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose presence to get.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/presence/list/{userId}",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Retrieve a list of presences for all of this user's friends.",
|
||||||
|
"notes": "",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "Presence"
|
||||||
|
},
|
||||||
|
"nickname": "get_presence_list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose presence list to get.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"summary": "Add or remove users from this presence list.",
|
||||||
|
"notes": "Add or remove users from this presence list.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "modify_presence_list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose presence list is being modified.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The modifications to make to this presence list.",
|
||||||
|
"required": true,
|
||||||
|
"type": "PresenceListModifications",
|
||||||
|
"paramType": "body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"PresenceUpdate": {
|
||||||
|
"id": "PresenceUpdate",
|
||||||
|
"properties": {
|
||||||
|
"presence": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Enum: The presence state.",
|
||||||
|
"enum": [
|
||||||
|
"offline",
|
||||||
|
"unavailable",
|
||||||
|
"online",
|
||||||
|
"free_for_chat"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status_msg": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The user-defined message associated with this presence state."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"subTypes": [
|
||||||
|
"Presence"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Presence": {
|
||||||
|
"id": "Presence",
|
||||||
|
"properties": {
|
||||||
|
"last_active_ago": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "The last time this user performed an action on their home server."
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The fully qualified user ID"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PresenceListModifications": {
|
||||||
|
"id": "PresenceListModifications",
|
||||||
|
"properties": {
|
||||||
|
"invite": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of user IDs to add to the list.",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A fully qualified user ID."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drop": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of user IDs to remove from the list.",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A fully qualified user ID."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
122
api/client-server/api-docs-profile
Normal file
122
api/client-server/api-docs-profile
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"swaggerVersion": "1.2",
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"resourcePath": "/profile",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"path": "/profile/{userId}/displayname",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"summary": "Set a display name.",
|
||||||
|
"notes": "This can only be done by the logged in user.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "set_display_name",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The new display name for this user.",
|
||||||
|
"required": true,
|
||||||
|
"type": "DisplayName",
|
||||||
|
"paramType": "body"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose display name to set.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get a display name.",
|
||||||
|
"notes": "This can be done by anyone.",
|
||||||
|
"type": "DisplayName",
|
||||||
|
"nickname": "get_display_name",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose display name to get.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/profile/{userId}/avatar_url",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"summary": "Set an avatar URL.",
|
||||||
|
"notes": "This can only be done by the logged in user.",
|
||||||
|
"type": "void",
|
||||||
|
"nickname": "set_avatar_url",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"description": "The new avatar url for this user.",
|
||||||
|
"required": true,
|
||||||
|
"type": "AvatarUrl",
|
||||||
|
"paramType": "body"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose avatar url to set.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"summary": "Get an avatar url.",
|
||||||
|
"notes": "This can be done by anyone.",
|
||||||
|
"type": "AvatarUrl",
|
||||||
|
"nickname": "get_avatar_url",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "userId",
|
||||||
|
"description": "The user whose avatar url to get.",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"paramType": "path"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"DisplayName": {
|
||||||
|
"id": "DisplayName",
|
||||||
|
"properties": {
|
||||||
|
"displayname": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The textual display name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AvatarUrl": {
|
||||||
|
"id": "AvatarUrl",
|
||||||
|
"properties": {
|
||||||
|
"avatar_url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A url to an image representing an avatar."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
api/client-server/api-docs-registration
Normal file
120
api/client-server/api-docs-registration
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "1.0.0",
|
||||||
|
"apis": [
|
||||||
|
{
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"nickname": "get_registration_info",
|
||||||
|
"notes": "All login stages MUST be mentioned if there is >1 login type.",
|
||||||
|
"summary": "Get the login mechanism to use when registering.",
|
||||||
|
"type": "RegistrationFlows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"nickname": "submit_registration",
|
||||||
|
"notes": "If this is part of a multi-stage registration, there MUST be a 'session' key.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "A registration submission",
|
||||||
|
"name": "body",
|
||||||
|
"paramType": "body",
|
||||||
|
"required": true,
|
||||||
|
"type": "RegistrationSubmission"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responseMessages": [
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "Bad login type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "Missing JSON keys"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Submit a registration action.",
|
||||||
|
"type": "RegistrationResult"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"path": "/register"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"basePath": "http://localhost:8008/_matrix/client/api/v1",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"models": {
|
||||||
|
"RegistrationFlows": {
|
||||||
|
"id": "RegistrationFlows",
|
||||||
|
"properties": {
|
||||||
|
"flows": {
|
||||||
|
"description": "A list of valid registration flows.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "RegistrationInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RegistrationInfo": {
|
||||||
|
"id": "RegistrationInfo",
|
||||||
|
"properties": {
|
||||||
|
"stages": {
|
||||||
|
"description": "Multi-stage registration only: An array of all the login types required to registration.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"description": "The first login type that must be used when logging in.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RegistrationResult": {
|
||||||
|
"id": "RegistrationResult",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"description": "The access token for this user's registration if this is the final stage of the registration process.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"description": "The user's fully-qualified user ID.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"next": {
|
||||||
|
"description": "Multi-stage registration only: The next registration type to submit.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"description": "Multi-stage registration only: The session token to send when submitting the next registration type.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RegistrationSubmission": {
|
||||||
|
"id": "RegistrationSubmission",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"description": "The type of registration being submitted.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"description": "Multi-stage registration only: The session token from an earlier registration stage.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"_registration_type_defined_keys_": {
|
||||||
|
"description": "Keys as defined by the specified registration type, e.g. \"user\", \"password\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"resourcePath": "/register",
|
||||||
|
"swaggerVersion": "1.2"
|
||||||
|
}
|
||||||
|
|
||||||
1128
api/client-server/api-docs-rooms
Normal file
1128
api/client-server/api-docs-rooms
Normal file
File diff suppressed because it is too large
Load diff
127
api/client-server/v1/content-repo.yaml
Normal file
127
api/client-server/v1/content-repo.yaml
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Content Repository API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
basePath: /_matrix/media/v1
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
- "*/*"
|
||||||
|
paths:
|
||||||
|
"/upload":
|
||||||
|
post:
|
||||||
|
summary: Upload some content to the content repository.
|
||||||
|
produces: ["application/json"]
|
||||||
|
parameters:
|
||||||
|
- in: header
|
||||||
|
name: Content-Type
|
||||||
|
type: string
|
||||||
|
description: The content type of the file being uploaded
|
||||||
|
x-example: "Content-Type: audio/mpeg"
|
||||||
|
- in: body
|
||||||
|
name: "<content>"
|
||||||
|
description: The content to be uploaded.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: "<bytes>"
|
||||||
|
format: byte
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The MXC URI for the uploaded content.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: ["content_uri"]
|
||||||
|
properties:
|
||||||
|
content_uri:
|
||||||
|
type: string
|
||||||
|
description: "The MXC URI to the uploaded content."
|
||||||
|
examples:
|
||||||
|
"application/json": |-
|
||||||
|
{
|
||||||
|
"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
|
||||||
|
}
|
||||||
|
"/download/{serverName}/{mediaId}":
|
||||||
|
get:
|
||||||
|
summary: "Download content from the content repository."
|
||||||
|
produces: ["*/*"]
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: serverName
|
||||||
|
x-example: matrix.org
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
The server name from the ``mxc://`` URI (the authoritory component)
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: mediaId
|
||||||
|
x-example: ascERGshawAWawugaAcauga
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
The media ID from the ``mxc://`` URI (the path component)
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "The content that was previously uploaded."
|
||||||
|
headers:
|
||||||
|
Content-Type:
|
||||||
|
description: "The content type of the file that was previously uploaded."
|
||||||
|
type: "string"
|
||||||
|
Content-Disposition:
|
||||||
|
description: "The name of the file that was previously uploaded, if set."
|
||||||
|
type: "string"
|
||||||
|
schema:
|
||||||
|
type: file
|
||||||
|
"/thumbnail/{serverName}/{mediaId}":
|
||||||
|
get:
|
||||||
|
summary: "Download a thumbnail of the content from the content repository."
|
||||||
|
produces: ["image/jpeg", "image/png"]
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: serverName
|
||||||
|
required: true
|
||||||
|
x-example: matrix.org
|
||||||
|
description: |
|
||||||
|
The server name from the ``mxc://`` URI (the authoritory component)
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: mediaId
|
||||||
|
x-example: ascERGshawAWawugaAcauga
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
The media ID from the ``mxc://`` URI (the path component)
|
||||||
|
- in: query
|
||||||
|
type: integer
|
||||||
|
x-example: 64
|
||||||
|
name: width
|
||||||
|
description: |-
|
||||||
|
The *desired* width of the thumbnail. The actual thumbnail may not
|
||||||
|
match the size specified.
|
||||||
|
- in: query
|
||||||
|
type: integer
|
||||||
|
x-example: 64
|
||||||
|
name: height
|
||||||
|
description: |-
|
||||||
|
The *desired* height of the thumbnail. The actual thumbnail may not
|
||||||
|
match the size specified.
|
||||||
|
- in: query
|
||||||
|
type: string
|
||||||
|
enum: ["crop", "scale"]
|
||||||
|
name: method
|
||||||
|
x-example: "scale"
|
||||||
|
description: The desired resizing method.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "A thumbnail of the requested content."
|
||||||
|
headers:
|
||||||
|
Content-Type:
|
||||||
|
description: "The content type of the thumbnail."
|
||||||
|
type: "string"
|
||||||
|
enum: ["image/jpeg", "image/png"]
|
||||||
|
schema:
|
||||||
|
type: file
|
||||||
|
|
||||||
|
|
||||||
1
api/client-server/v1/core-event-schema
Symbolic link
1
api/client-server/v1/core-event-schema
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
v1-event-schema/core-event-schema
|
||||||
10
api/client-server/v1/definitions/error.yaml
Normal file
10
api/client-server/v1/definitions/error.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
type: object
|
||||||
|
description: A Matrix-level Error
|
||||||
|
properties:
|
||||||
|
errcode:
|
||||||
|
type: string
|
||||||
|
description: An error code.
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
description: A human-readable error message.
|
||||||
|
required: ["errcode"]
|
||||||
87
api/client-server/v1/directory.yaml
Normal file
87
api/client-server/v1/directory.yaml
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Directory API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1/directory
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/room/{roomAlias}":
|
||||||
|
put:
|
||||||
|
summary: Create a new mapping from room alias to room ID.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomAlias
|
||||||
|
description: The room alias to set.
|
||||||
|
required: true
|
||||||
|
- in: body
|
||||||
|
name: roomInfo
|
||||||
|
description: Information about this room alias.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: The room ID to set.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The mapping was created.
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
get:
|
||||||
|
summary: Get the room ID corresponding to this room alias.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomAlias
|
||||||
|
description: The room alias.
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The room ID and other information for this alias.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: The room ID for this room alias.
|
||||||
|
servers:
|
||||||
|
type: array
|
||||||
|
description: A list of servers that are aware of this room ID.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: A server which is aware of this room ID.
|
||||||
|
404:
|
||||||
|
description: There is no mapped room ID for this room alias.
|
||||||
|
delete:
|
||||||
|
summary: Remove a mapping of room alias to room ID.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomAlias
|
||||||
|
description: The room alias to remove.
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The mapping was removed.
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
|
||||||
147
api/client-server/v1/login.yaml
Normal file
147
api/client-server/v1/login.yaml
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Registration and Login API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/login":
|
||||||
|
post:
|
||||||
|
summary: Authenticates the user.
|
||||||
|
description: |-
|
||||||
|
Authenticates the user by password, and issues an access token they can
|
||||||
|
use to authorize themself in subsequent requests.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"username": "cheeky_monkey",
|
||||||
|
"password": "ilovebananas"
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: The fully qualified user ID or just local part of the user ID, to log in.
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: The user's password.
|
||||||
|
required: ["username", "password"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The user has been authenticated.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"user_id": "@cheeky_monkey:matrix.org",
|
||||||
|
"access_token": "abc123",
|
||||||
|
"home_server": "matrix.org"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
description: The fully-qualified Matrix ID that has been registered.
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An access token for the account.
|
||||||
|
This access token can then be used to authorize other requests.
|
||||||
|
The access token may expire at some point, and if so, it SHOULD come with a ``refresh_token``.
|
||||||
|
There is no specific error message to indicate that a request has failed because
|
||||||
|
an access token has expired; instead, if a client has reason to believe its
|
||||||
|
access token is valid, and it receives an auth error, they should attempt to
|
||||||
|
refresh for a new token on failure, and retry the request with the new token.
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
# TODO: Work out how to linkify /tokenrefresh
|
||||||
|
description: |-
|
||||||
|
(optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the /tokenrefresh API endpoint.
|
||||||
|
home_server:
|
||||||
|
type: string
|
||||||
|
description: The hostname of the Home Server on which the account has been registered.
|
||||||
|
403:
|
||||||
|
description: |-
|
||||||
|
The login attempt failed. For example, the password may have been incorrect.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"errcode": "M_FORBIDDEN"}
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
"/tokenrefresh":
|
||||||
|
post:
|
||||||
|
summary: Exchanges a refresh token for an access token.
|
||||||
|
description: |-
|
||||||
|
Exchanges a refresh token for a new access token.
|
||||||
|
This is intended to be used if the access token has expired.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"refresh_token": "a1b2c3"
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
description: The refresh token which was issued by the server.
|
||||||
|
required: ["refresh_token"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |-
|
||||||
|
The refresh token was accepted, and a new access token has been issued.
|
||||||
|
The passed refresh token is no longer valid and cannot be used.
|
||||||
|
A new refresh token will have been returned unless some policy does
|
||||||
|
not allow the user to continue to renew their session.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"access_token": "bearwithme123",
|
||||||
|
"refresh_token": "exchangewithme987"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
An access token for the account.
|
||||||
|
This access token can then be used to authorize other requests.
|
||||||
|
The access token may expire at some point, and if so, it SHOULD come with a ``refresh_token``.
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
description: (optional) A ``refresh_token`` may be exchanged for a new ``access_token`` using the TODO Linkify /tokenrefresh API endpoint.
|
||||||
|
403:
|
||||||
|
description: |-
|
||||||
|
The exchange attempt failed. For example, the refresh token may have already been used.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"errcode": "M_FORBIDDEN"}
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
128
api/client-server/v1/membership.yaml
Normal file
128
api/client-server/v1/membership.yaml
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Room Membership API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/rooms/{roomId}/join":
|
||||||
|
post:
|
||||||
|
summary: Start the requesting user participating in a particular room.
|
||||||
|
description: |-
|
||||||
|
This API starts a user participating in a particular room, if that user
|
||||||
|
is allowed to participate in that room. After this call, the client is
|
||||||
|
allowed to see all current state events in the room, and all subsequent
|
||||||
|
events associated with the room until the user leaves the room.
|
||||||
|
|
||||||
|
After a user has joined a room, the room will appear as an entry in the
|
||||||
|
response of the |initialSync| API.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room identifier or room alias to join.
|
||||||
|
required: true
|
||||||
|
x-example: "#monkeys:matrix.org"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |-
|
||||||
|
The room has been joined.
|
||||||
|
|
||||||
|
The joined room ID must be returned in the ``room_id`` field.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"room_id": "!d41d8cd:matrix.org"}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
403:
|
||||||
|
description: |-
|
||||||
|
You do not have permission to join the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejection are:
|
||||||
|
- The room is invite-only and the user was not invited.
|
||||||
|
- The user has been banned from the room.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
x-alias:
|
||||||
|
canonical-link: "post-matrix-client-api-v1-rooms-roomid-join"
|
||||||
|
aliases:
|
||||||
|
- /join/{roomId}
|
||||||
|
|
||||||
|
"/rooms/{roomId}/invite":
|
||||||
|
post:
|
||||||
|
summary: Invite a user to participate in a particular room.
|
||||||
|
description: |-
|
||||||
|
This API invites a user to participate in a particular room.
|
||||||
|
They do not start participating in the room until they actually join the
|
||||||
|
room.
|
||||||
|
|
||||||
|
This serves two purposes; firstly, to notify the user that the room
|
||||||
|
exists (and that their presence is requested). Secondly, some rooms can
|
||||||
|
only be joined if a user is invited to join it; sending the invite gives
|
||||||
|
that user permission to join the room.
|
||||||
|
|
||||||
|
Only users currently in a particular room can invite other users to
|
||||||
|
join that room.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room identifier (not alias) to which to invite the user.
|
||||||
|
required: true
|
||||||
|
x-example: "!d41d8cd:matrix.org"
|
||||||
|
- in: body
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"user_id": "@cheeky_monkey:matrix.org"
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
description: The fully qualified user ID of the invitee.
|
||||||
|
required: ["user_id"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The user has been invited to join the room.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
403:
|
||||||
|
description: |-
|
||||||
|
You do not have permission to invite the user to the room. A meaningful ``errcode`` and description error text will be returned. Example reasons for rejections are:
|
||||||
|
- The invitee has been banned from the room.
|
||||||
|
- The invitee is already a member of the room.
|
||||||
|
- The inviter is not currently in the room.
|
||||||
|
- The inviter's power level is insufficient to invite users to the room.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
208
api/client-server/v1/presence.yaml
Normal file
208
api/client-server/v1/presence.yaml
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Presence API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/presence/{userId}/status":
|
||||||
|
put:
|
||||||
|
summary: Update this user's presence state.
|
||||||
|
description: |-
|
||||||
|
This API sets the given user's presence state. When setting the status,
|
||||||
|
the activity time is updated to reflect that activity; the client does
|
||||||
|
not need to specify the ``last_active_ago`` field. You cannot set the
|
||||||
|
presence state of another user.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose presence state to update.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: body
|
||||||
|
name: presenceState
|
||||||
|
description: The updated presence state.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"presence": "online",
|
||||||
|
"status_msg": "I am here."
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
presence:
|
||||||
|
type: string
|
||||||
|
enum: ["online", "offline", "unavailable", "free_for_chat"]
|
||||||
|
description: The new presence state.
|
||||||
|
status_msg:
|
||||||
|
type: string
|
||||||
|
description: "The status message to attach to this state."
|
||||||
|
required: ["presence"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The new presence state was set.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
get:
|
||||||
|
summary: Get this user's presence state.
|
||||||
|
description: |-
|
||||||
|
Get the given user's presence state.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose presence state to get.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The presence state for this user.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"presence": "unavailable",
|
||||||
|
"last_active_ago": 420845,
|
||||||
|
"status_msg": null
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
presence:
|
||||||
|
type: string
|
||||||
|
enum: ["online", "offline", "unavailable", "free_for_chat"]
|
||||||
|
description: This user's presence.
|
||||||
|
last_active_ago:
|
||||||
|
type: integer
|
||||||
|
description: |-
|
||||||
|
The length of time in milliseconds since an action was performed
|
||||||
|
by this user.
|
||||||
|
status_msg:
|
||||||
|
type: [string, "null"]
|
||||||
|
description: The state message for this user if one was set.
|
||||||
|
404:
|
||||||
|
description: |-
|
||||||
|
There is no presence state for this user. This user may not exist or
|
||||||
|
isn't exposing presence information to you.
|
||||||
|
"/presence/list/{userId}":
|
||||||
|
post:
|
||||||
|
summary: Add or remove users from this presence list.
|
||||||
|
description: |-
|
||||||
|
Adds or removes users from this presence list.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose presence list is being modified.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: body
|
||||||
|
name: presence_diff
|
||||||
|
description: The modifications to make to this presence list.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"invite": [
|
||||||
|
"@bob:matrix.org"
|
||||||
|
],
|
||||||
|
"drop": [
|
||||||
|
"@alice:matrix.org"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
invite:
|
||||||
|
type: array
|
||||||
|
description: A list of user IDs to add to the list.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: A list of user IDs.
|
||||||
|
drop:
|
||||||
|
type: array
|
||||||
|
description: A list of user IDs to remove from the list.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: A list of user IDs.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The list was updated.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
get:
|
||||||
|
summary: Get presence events for this presence list.
|
||||||
|
description: |-
|
||||||
|
Retrieve a list of presence events for every user on this list.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose presence list should be retrieved.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: A list of presence events for this list.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://matrix.org/AfwefuigfWEfhuiPP",
|
||||||
|
"displayname": "Alice Margatroid",
|
||||||
|
"last_active_ago": 395,
|
||||||
|
"presence": "offline",
|
||||||
|
"user_id": "@alice:matrix.org"
|
||||||
|
},
|
||||||
|
"type": "m.presence"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://matrix.org/FWEhuiwegfWEfhuiwf",
|
||||||
|
"displayname": "Marisa Kirisame",
|
||||||
|
"last_active_ago": 16874,
|
||||||
|
"presence": "online",
|
||||||
|
"user_id": "@marisa:matrix.org"
|
||||||
|
},
|
||||||
|
"type": "m.presence"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: PresenceEvent
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/event.json"
|
||||||
195
api/client-server/v1/profile.yaml
Normal file
195
api/client-server/v1/profile.yaml
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Profile API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/profile/{userId}/displayname":
|
||||||
|
put:
|
||||||
|
summary: Set the user's display name.
|
||||||
|
description: |-
|
||||||
|
This API sets the given user's display name. You must have permission to
|
||||||
|
set this user's display name, e.g. you need to have their ``access_token``.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose display name to set.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: body
|
||||||
|
name: displayName
|
||||||
|
description: The display name info.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"displayname": "Alice Margatroid"
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
displayname:
|
||||||
|
type: string
|
||||||
|
description: The new display name for this user.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The display name was set.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
get:
|
||||||
|
summary: Get the user's display name.
|
||||||
|
description: |-
|
||||||
|
Get the user's display name. This API may be used to fetch the user's
|
||||||
|
own displayname or to query the name of other users; either locally or
|
||||||
|
on remote homeservers.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose display name to get.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The display name for this user.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"displayname": "Alice Margatroid"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
displayname:
|
||||||
|
type: string
|
||||||
|
description: The user's display name if they have set one.
|
||||||
|
404:
|
||||||
|
description: There is no display name for this user or this user does not exist.
|
||||||
|
"/profile/{userId}/avatar_url":
|
||||||
|
put:
|
||||||
|
summary: Set the user's avatar URL.
|
||||||
|
description: |-
|
||||||
|
This API sets the given user's avatar URL. You must have permission to
|
||||||
|
set this user's avatar URL, e.g. you need to have their ``access_token``.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose avatar URL to set.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: body
|
||||||
|
name: avatar_url
|
||||||
|
description: The avatar url info.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34"
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
avatar_url:
|
||||||
|
type: string
|
||||||
|
description: The new avatar URL for this user.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The avatar URL was set.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
get:
|
||||||
|
summary: Get the user's avatar URL.
|
||||||
|
description: |-
|
||||||
|
Get the user's avatar URL. This API may be used to fetch the user's
|
||||||
|
own avatar URL or to query the URL of other users; either locally or
|
||||||
|
on remote homeservers.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose avatar URL to get.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The avatar URL for this user.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"avatar_url": "mxc://matrix.org/SDGdghriugerRg"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
avatar_url:
|
||||||
|
type: string
|
||||||
|
description: The user's avatar URL if they have set one.
|
||||||
|
404:
|
||||||
|
description: There is no avatar URL for this user or this user does not exist.
|
||||||
|
"/profile/{userId}":
|
||||||
|
get:
|
||||||
|
summary: Get this user's profile information.
|
||||||
|
description: |-
|
||||||
|
Get the combined profile information for this user. This API may be used
|
||||||
|
to fetch the user's own profile information or other users; either
|
||||||
|
locally or on remote homeservers. This API may return keys which are not
|
||||||
|
limited to ``displayname`` or ``avatar_url``.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user whose avatar URL to get.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The avatar URL for this user.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
|
||||||
|
"displayname": "Alice Margatroid"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
avatar_url:
|
||||||
|
type: string
|
||||||
|
description: The user's avatar URL if they have set one.
|
||||||
|
displayname:
|
||||||
|
type: string
|
||||||
|
description: The user's display name if they have set one.
|
||||||
|
404:
|
||||||
|
description: There is no profile information for this user or this user does not exist.
|
||||||
448
api/client-server/v1/rooms.yaml
Normal file
448
api/client-server/v1/rooms.yaml
Normal file
|
|
@ -0,0 +1,448 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Rooms API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/rooms/{roomId}/state/{eventType}/{stateKey}":
|
||||||
|
get:
|
||||||
|
summary: Get the state identified by the type and key.
|
||||||
|
description: |-
|
||||||
|
Looks up the contents of a state event in a room. If the user is
|
||||||
|
joined to the room then the state is taken from the current
|
||||||
|
state of the room. If the user has left the room then the state is
|
||||||
|
taken from the state of the room when they left.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room to look up the state in.
|
||||||
|
required: true
|
||||||
|
x-example: "!636q39766251:example.com"
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: eventType
|
||||||
|
description: The type of state to look up.
|
||||||
|
required: true
|
||||||
|
x-example: "m.room.name"
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: stateKey
|
||||||
|
description: The key of the state to look up. Defaults to the empty string.
|
||||||
|
required: true
|
||||||
|
x-example: ""
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The content of the state event.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{"name": "Example room name"}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
404:
|
||||||
|
description: The room has no state with the given type or key.
|
||||||
|
403:
|
||||||
|
description: >
|
||||||
|
You aren't a member of the room and weren't previously a
|
||||||
|
member of the room.
|
||||||
|
|
||||||
|
"/rooms/{roomId}/state":
|
||||||
|
get:
|
||||||
|
summary: Get all state events in the current state of a room.
|
||||||
|
description: |-
|
||||||
|
Get the state events for the current state of a room.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room to look up the state for.
|
||||||
|
required: true
|
||||||
|
x-example: "!636q39766251:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The current state of the room
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"age": 7148266897,
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997323TLwtb:example.com",
|
||||||
|
"origin_server_ts": 1425999732392,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 6547561012,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
|
||||||
|
"displayname": null,
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1426600438280zExKY:example.com",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1426600438277,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@alice:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267200,
|
||||||
|
"content": {
|
||||||
|
"creator": "@alice:example.com"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997320KhbwJ:example.com",
|
||||||
|
"origin_server_ts": 1425999732089,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 1622568720,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto",
|
||||||
|
"displayname": "Bob",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1431525430134MxlLX:example.com",
|
||||||
|
"origin_server_ts": 1431525430569,
|
||||||
|
"replaces_state": "$142652023736BSXcM:example.com",
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@bob:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@bob:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267004,
|
||||||
|
"content": {
|
||||||
|
"ban": 50,
|
||||||
|
"events": {
|
||||||
|
"m.room.name": 100,
|
||||||
|
"m.room.power_levels": 100
|
||||||
|
},
|
||||||
|
"events_default": 0,
|
||||||
|
"kick": 50,
|
||||||
|
"redact": 50,
|
||||||
|
"state_default": 50,
|
||||||
|
"users": {
|
||||||
|
"@alice:example.com": 100
|
||||||
|
},
|
||||||
|
"users_default": 0
|
||||||
|
},
|
||||||
|
"event_id": "$14259997322mqfaq:example.com",
|
||||||
|
"origin_server_ts": 1425999732285,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.power_levels",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
title: RoomState
|
||||||
|
description: |-
|
||||||
|
If the user is a member of the room this will be the
|
||||||
|
current state of the room as a list of events. If the user
|
||||||
|
has left the room then this will be the state of the room
|
||||||
|
when they left as a list of events.
|
||||||
|
items:
|
||||||
|
title: StateEvent
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/state_event.json"
|
||||||
|
403:
|
||||||
|
description: >
|
||||||
|
You aren't a member of the room and weren't previously a
|
||||||
|
member of the room.
|
||||||
|
|
||||||
|
"/rooms/{roomId}/initialSync":
|
||||||
|
get:
|
||||||
|
summary: Snapshot the current state of a room and its most recent messages.
|
||||||
|
description: |-
|
||||||
|
Get a copy of the current state and the most recent messages in a room.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room to get the data.
|
||||||
|
required: true
|
||||||
|
x-example: "!636q39766251:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The current state of the room
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"membership": "join",
|
||||||
|
"messages": {
|
||||||
|
"chunk": [
|
||||||
|
{
|
||||||
|
"age": 343513403,
|
||||||
|
"content": {
|
||||||
|
"body": "foo",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$14328044851tzTJS:example.com",
|
||||||
|
"origin_server_ts": 1432804485886,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 343511809,
|
||||||
|
"content": {
|
||||||
|
"body": "bar",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$14328044872spjFg:example.com",
|
||||||
|
"origin_server_ts": 1432804487480,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"user_id": "@bob:example.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": "s3456_9_0",
|
||||||
|
"start": "t44-3453_9_0"
|
||||||
|
},
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state": [
|
||||||
|
{
|
||||||
|
"age": 7148266897,
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997323TLwtb:example.com",
|
||||||
|
"origin_server_ts": 1425999732392,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 6547561012,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
|
||||||
|
"displayname": null,
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1426600438280zExKY:example.com",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1426600438277,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@alice:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267200,
|
||||||
|
"content": {
|
||||||
|
"creator": "@alice:example.com"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997320KhbwJ:example.com",
|
||||||
|
"origin_server_ts": 1425999732089,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 1622568720,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto",
|
||||||
|
"displayname": "Bob",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1431525430134MxlLX:example.com",
|
||||||
|
"origin_server_ts": 1431525430569,
|
||||||
|
"replaces_state": "$142652023736BSXcM:example.com",
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@bob:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@bob:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267004,
|
||||||
|
"content": {
|
||||||
|
"ban": 50,
|
||||||
|
"events": {
|
||||||
|
"m.room.name": 100,
|
||||||
|
"m.room.power_levels": 100
|
||||||
|
},
|
||||||
|
"events_default": 0,
|
||||||
|
"kick": 50,
|
||||||
|
"redact": 50,
|
||||||
|
"state_default": 50,
|
||||||
|
"users": {
|
||||||
|
"@alice:example.com": 100
|
||||||
|
},
|
||||||
|
"users_default": 0
|
||||||
|
},
|
||||||
|
"event_id": "$14259997322mqfaq:example.com",
|
||||||
|
"origin_server_ts": 1425999732285,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.power_levels",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visibility": "private"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
title: RoomInfo
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: "The ID of this room."
|
||||||
|
membership:
|
||||||
|
type: string
|
||||||
|
description: "The user's membership state in this room."
|
||||||
|
enum: ["invite", "join", "leave", "ban"]
|
||||||
|
messages:
|
||||||
|
type: object
|
||||||
|
title: PaginationChunk
|
||||||
|
description: "The pagination chunk for this room."
|
||||||
|
properties:
|
||||||
|
start:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the first value in ``chunk``.
|
||||||
|
Used for pagination.
|
||||||
|
end:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the last value in ``chunk``.
|
||||||
|
Used for pagination.
|
||||||
|
chunk:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
If the user is a member of the room this will be a
|
||||||
|
list of the most recent messages for this room. If
|
||||||
|
the user has left the room this will be the
|
||||||
|
messages that preceeded them leaving. This array
|
||||||
|
will consist of at most ``limit`` elements.
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: RoomEvent
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/room_event.json"
|
||||||
|
required: ["start", "end", "chunk"]
|
||||||
|
state:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
If the user is a member of the room this will be the
|
||||||
|
current state of the room as a list of events. If the
|
||||||
|
user has left the room this will be the state of the
|
||||||
|
room when they left it.
|
||||||
|
items:
|
||||||
|
title: StateEvent
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/state_event.json"
|
||||||
|
visibility:
|
||||||
|
type: string
|
||||||
|
enum: ["private", "public"]
|
||||||
|
description: |-
|
||||||
|
Whether this room is visible to the ``/publicRooms`` API
|
||||||
|
or not."
|
||||||
|
required: ["room_id", "membership"]
|
||||||
|
403:
|
||||||
|
description: >
|
||||||
|
You aren't a member of the room and weren't previously a
|
||||||
|
member of the room.
|
||||||
|
|
||||||
|
"/rooms/{roomId}/members":
|
||||||
|
get:
|
||||||
|
summary: Get the m.room.member events for the room.
|
||||||
|
description:
|
||||||
|
Get the list of members for this room.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room to get the member events for.
|
||||||
|
required: true
|
||||||
|
x-example: "!636q39766251:example.com"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: |-
|
||||||
|
A list of members of the room. If you are joined to the room then
|
||||||
|
this will be the current members of the room. If you have left te
|
||||||
|
room then this will be the members of the room when you left.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"chunk": [
|
||||||
|
{
|
||||||
|
"age": 6547561012,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/fzysBrHpPEeTGANCVLXWXNMI#auto",
|
||||||
|
"displayname": null,
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1426600438280zExKY:example.com",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1426600438277,
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@alice:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@alice:example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 1622568720,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://example.com/GCmhgzMPRjqgpODLsNQzVuHZ#auto",
|
||||||
|
"displayname": "Bob",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1431525430134MxlLX:example.com",
|
||||||
|
"origin_server_ts": 1431525430569,
|
||||||
|
"replaces_state": "$142652023736BSXcM:example.com",
|
||||||
|
"room_id": "!636q39766251:example.com",
|
||||||
|
"state_key": "@bob:example.com",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@bob:example.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
chunk:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
title: MemberEvent
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- "$ref": "v1-event-schema/m.room.member"
|
||||||
|
403:
|
||||||
|
description: >
|
||||||
|
You aren't a member of the room and weren't previously a
|
||||||
|
member of the room.
|
||||||
|
|
||||||
361
api/client-server/v1/sync.yaml
Normal file
361
api/client-server/v1/sync.yaml
Normal file
|
|
@ -0,0 +1,361 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Sync API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/events":
|
||||||
|
get:
|
||||||
|
summary: Listen on the event stream.
|
||||||
|
description: |-
|
||||||
|
This will listen for new events and return them to the caller. This will
|
||||||
|
block until an event is received, or until the ``timeout`` is reached.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
type: string
|
||||||
|
name: from
|
||||||
|
description: The token to stream from.
|
||||||
|
required: false
|
||||||
|
x-example: "s3456_9_0"
|
||||||
|
- in: query
|
||||||
|
type: integer
|
||||||
|
name: timeout
|
||||||
|
description: The maximum time in milliseconds to wait for an event.
|
||||||
|
required: false
|
||||||
|
x-example: "35000"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "The events received, which may be none."
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"start": "s3456_9_0",
|
||||||
|
"end": "s3457_9_0",
|
||||||
|
"chunk": [
|
||||||
|
{
|
||||||
|
"age": 32,
|
||||||
|
"content": {
|
||||||
|
"body": "incoming message",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$14328055551tzaee:localhost",
|
||||||
|
"origin_server_ts": 1432804485886,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"user_id": "@bob:localhost"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
start:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the first value in ``chunk``. Used
|
||||||
|
for pagination.
|
||||||
|
end:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the last value in ``chunk``. Used
|
||||||
|
for pagination.
|
||||||
|
chunk:
|
||||||
|
type: array
|
||||||
|
description: "An array of events."
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: RoomEvent
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/room_event.json"
|
||||||
|
400:
|
||||||
|
description: "Bad pagination ``from`` parameter."
|
||||||
|
"/initialSync":
|
||||||
|
get:
|
||||||
|
summary: Get the user's current state.
|
||||||
|
description: |-
|
||||||
|
This returns the full state for this user, with an optional limit on the
|
||||||
|
number of messages per room to return.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
type: integer
|
||||||
|
name: limit
|
||||||
|
description: The maximum number of messages to return for each room.
|
||||||
|
required: false
|
||||||
|
x-example: "2"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The user's current state.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"end": "s3456_9_0",
|
||||||
|
"presence": [
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto",
|
||||||
|
"displayname": "Bob",
|
||||||
|
"last_active_ago": 31053,
|
||||||
|
"presence": "online",
|
||||||
|
"user_id": "@bob:localhost"
|
||||||
|
},
|
||||||
|
"type": "m.presence"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rooms": [
|
||||||
|
{
|
||||||
|
"membership": "join",
|
||||||
|
"messages": {
|
||||||
|
"chunk": [
|
||||||
|
{
|
||||||
|
"age": 343513403,
|
||||||
|
"content": {
|
||||||
|
"body": "foo",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$14328044851tzTJS:localhost",
|
||||||
|
"origin_server_ts": 1432804485886,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"user_id": "@alice:localhost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 343511809,
|
||||||
|
"content": {
|
||||||
|
"body": "bar",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$14328044872spjFg:localhost",
|
||||||
|
"origin_server_ts": 1432804487480,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"user_id": "@bob:localhost"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"end": "s3456_9_0",
|
||||||
|
"start": "t44-3453_9_0"
|
||||||
|
},
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state": [
|
||||||
|
{
|
||||||
|
"age": 7148266897,
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997323TLwtb:localhost",
|
||||||
|
"origin_server_ts": 1425999732392,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"user_id": "@alice:localhost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 6547561012,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://localhost/fzysBrHpPEeTGANCVLXWXNMI#auto",
|
||||||
|
"displayname": null,
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1426600438280zExKY:localhost",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1426600438277,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state_key": "@alice:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@alice:localhost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267200,
|
||||||
|
"content": {
|
||||||
|
"creator": "@alice:localhost"
|
||||||
|
},
|
||||||
|
"event_id": "$14259997320KhbwJ:localhost",
|
||||||
|
"origin_server_ts": 1425999732089,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
"user_id": "@alice:localhost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 1622568720,
|
||||||
|
"content": {
|
||||||
|
"avatar_url": "mxc://localhost/GCmhgzMPRjqgpODLsNQzVuHZ#auto",
|
||||||
|
"displayname": "Bob",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$1431525430134MxlLX:localhost",
|
||||||
|
"origin_server_ts": 1431525430569,
|
||||||
|
"replaces_state": "$142652023736BSXcM:localhost",
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state_key": "@bob:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"user_id": "@bob:localhost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"age": 7148267004,
|
||||||
|
"content": {
|
||||||
|
"ban": 50,
|
||||||
|
"events": {
|
||||||
|
"m.room.name": 100,
|
||||||
|
"m.room.power_levels": 100
|
||||||
|
},
|
||||||
|
"events_default": 0,
|
||||||
|
"kick": 50,
|
||||||
|
"redact": 50,
|
||||||
|
"state_default": 50,
|
||||||
|
"users": {
|
||||||
|
"@alice:localhost": 100
|
||||||
|
},
|
||||||
|
"users_default": 0
|
||||||
|
},
|
||||||
|
"event_id": "$14259997322mqfaq:localhost",
|
||||||
|
"origin_server_ts": 1425999732285,
|
||||||
|
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.power_levels",
|
||||||
|
"user_id": "@alice:localhost"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visibility": "private"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
end:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the last value in ``chunk``. This
|
||||||
|
token should be used with the ``/events`` API to listen for new
|
||||||
|
events.
|
||||||
|
presence:
|
||||||
|
type: array
|
||||||
|
description: A list of presence events.
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: Event
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/event.json"
|
||||||
|
rooms:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: RoomInfo
|
||||||
|
properties:
|
||||||
|
room_id:
|
||||||
|
type: string
|
||||||
|
description: "The ID of this room."
|
||||||
|
membership:
|
||||||
|
type: string
|
||||||
|
description: "The user's membership state in this room."
|
||||||
|
enum: ["invite", "join", "leave", "ban"]
|
||||||
|
invite:
|
||||||
|
type: object
|
||||||
|
title: "InviteEvent"
|
||||||
|
description: "The invite event if ``membership`` is ``invite``"
|
||||||
|
allOf:
|
||||||
|
- "$ref": "v1-event-schema/m.room.member"
|
||||||
|
messages:
|
||||||
|
type: object
|
||||||
|
title: PaginationChunk
|
||||||
|
description: "The pagination chunk for this room."
|
||||||
|
properties:
|
||||||
|
start:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the first value in ``chunk``.
|
||||||
|
Used for pagination.
|
||||||
|
end:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
A token which correlates to the last value in ``chunk``.
|
||||||
|
Used for pagination.
|
||||||
|
chunk:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
If the user is a member of the room this will be a
|
||||||
|
list of the most recent messages for this room. If
|
||||||
|
the user has left the room this will be the
|
||||||
|
messages that preceeded them leaving. This array
|
||||||
|
will consist of at most ``limit`` elements.
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
title: RoomEvent
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/room_event.json"
|
||||||
|
required: ["start", "end", "chunk"]
|
||||||
|
state:
|
||||||
|
type: array
|
||||||
|
description: |-
|
||||||
|
If the user is a member of the room this will be the
|
||||||
|
current state of the room as a list of events. If the
|
||||||
|
user has left the room this will be the state of the
|
||||||
|
room when they left it.
|
||||||
|
items:
|
||||||
|
title: StateEvent
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/state_event.json"
|
||||||
|
visibility:
|
||||||
|
type: string
|
||||||
|
enum: ["private", "public"]
|
||||||
|
description: |-
|
||||||
|
Whether this room is visible to the ``/publicRooms`` API
|
||||||
|
or not."
|
||||||
|
required: ["room_id", "membership"]
|
||||||
|
required: ["end", "rooms", "presence"]
|
||||||
|
404:
|
||||||
|
description: There is no avatar URL for this user or this user does not exist.
|
||||||
|
"/events/{eventId}":
|
||||||
|
get:
|
||||||
|
summary: Get a single event by event ID.
|
||||||
|
description: |-
|
||||||
|
Get a single event based on ``event_id``. You must have permission to
|
||||||
|
retrieve this event e.g. by being a member in the room for this event.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: eventId
|
||||||
|
description: The event ID to get.
|
||||||
|
required: true
|
||||||
|
x-example: "$asfDuShaf7Gafaw:matrix.org"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The full event.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "Hello world!",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"room_id:": "!wfgy43Sg4a:matrix.org",
|
||||||
|
"user_id": "@bob:matrix.org",
|
||||||
|
"event_id": "$asfDuShaf7Gafaw:matrix.org",
|
||||||
|
"type": "m.room.message"
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- "$ref": "core-event-schema/event.json"
|
||||||
|
404:
|
||||||
|
description: The event was not found or you do not have permission to read this event.
|
||||||
77
api/client-server/v1/typing.yaml
Normal file
77
api/client-server/v1/typing.yaml
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Typing API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/rooms/{roomId}/typing/{userId}":
|
||||||
|
put:
|
||||||
|
summary: Informs the server that the user has started or stopped typing.
|
||||||
|
description: |-
|
||||||
|
This tells the server that the user is typing for the next N
|
||||||
|
milliseconds where N is the value specified in the ``timeout`` key.
|
||||||
|
Alternatively, if ``typing`` is ``false``, it tells the server that the
|
||||||
|
user has stopped typing.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user who has started to type.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room in which the user is typing.
|
||||||
|
required: true
|
||||||
|
x-example: "!wefh3sfukhs:example.com"
|
||||||
|
- in: body
|
||||||
|
name: typingState
|
||||||
|
description: The current typing state.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"typing": true,
|
||||||
|
"timeout": 30000
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
typing:
|
||||||
|
type: boolean
|
||||||
|
description: |-
|
||||||
|
Whether the user is typing or not. If ``false``, the ``timeout``
|
||||||
|
key can be omitted.
|
||||||
|
timeout:
|
||||||
|
type: integer
|
||||||
|
description: The length of time in milliseconds to mark this user as typing.
|
||||||
|
required: ["typing"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The new typing state was set.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
|
||||||
1
api/client-server/v1/v1-event-schema
Symbolic link
1
api/client-server/v1/v1-event-schema
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../../event-schemas/schema/v1
|
||||||
68
api/client-server/v1/voip.yaml
Normal file
68
api/client-server/v1/voip.yaml
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Voice over IP API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/turnServer":
|
||||||
|
get:
|
||||||
|
summary: Obtain TURN server credentials.
|
||||||
|
description: |-
|
||||||
|
This API provides credentials for the client to use when initiating
|
||||||
|
calls.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The TURN server credentials.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{
|
||||||
|
"username":"1443779631:@user:example.com",
|
||||||
|
"password":"JlKfBy1QwLrO20385QyAtEyIv0=",
|
||||||
|
"uris":[
|
||||||
|
"turn:turn.example.com:3478?transport=udp",
|
||||||
|
"turn:10.20.30.40:3478?transport=tcp",
|
||||||
|
"turns:10.20.30.40:443?transport=tcp"
|
||||||
|
],
|
||||||
|
"ttl":86400
|
||||||
|
}
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The username to use.
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
The password to use.
|
||||||
|
uris:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
description: A list of TURN URIs
|
||||||
|
ttl:
|
||||||
|
type: integer
|
||||||
|
description: The time-to-live in seconds
|
||||||
|
required: ["username", "password", "uris", "ttl"]
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
|
||||||
68
api/client-server/v2_alpha/receipts.yaml
Normal file
68
api/client-server/v2_alpha/receipts.yaml
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v2 Receipts API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/v2_alpha
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/rooms/{roomId}/receipt/{receiptType}/{eventId}":
|
||||||
|
post:
|
||||||
|
summary: Send a receipt for the given event ID.
|
||||||
|
description: |-
|
||||||
|
This API updates the marker for the given receipt type to the event ID
|
||||||
|
specified.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room in which to send the event.
|
||||||
|
required: true
|
||||||
|
x-example: "!wefuh21ffskfuh345:example.com"
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: receiptType
|
||||||
|
description: The type of receipt to send.
|
||||||
|
required: true
|
||||||
|
x-example: "m.read"
|
||||||
|
enum: ["m.read"]
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: eventId
|
||||||
|
description: The event ID to acknowledge up to.
|
||||||
|
required: true
|
||||||
|
x-example: "$1924376522eioj:example.com"
|
||||||
|
- in: body
|
||||||
|
description: |-
|
||||||
|
Extra receipt information to attach to ``content`` if any. The
|
||||||
|
server will automatically set the ``ts`` field.
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{}
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The receipt was sent.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
38
api/files/backbone-min.js
vendored
Normal file
38
api/files/backbone-min.js
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Backbone.js 0.9.2
|
||||||
|
|
||||||
|
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||||
|
// Backbone may be freely distributed under the MIT license.
|
||||||
|
// For all details and documentation:
|
||||||
|
// http://backbonejs.org
|
||||||
|
(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks=
|
||||||
|
{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g=
|
||||||
|
z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent=
|
||||||
|
{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null==
|
||||||
|
b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent:
|
||||||
|
b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};
|
||||||
|
a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error,
|
||||||
|
h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();
|
||||||
|
return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending=
|
||||||
|
{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||
|
||||||
|
!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator);
|
||||||
|
this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;i=e.id;j[g]||this._byCid[g]||null!=i&&(k[i]||this._byId[i])?
|
||||||
|
l.push(c):j[g]=k[i]=e}for(c=l.length;c--;)a.splice(l[c],1);c=0;for(d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=e.id&&(this._byId[e.id]=e);this.length+=d;A.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;c=0;for(d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?
|
||||||
|
a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a},
|
||||||
|
shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?
|
||||||
|
this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,
|
||||||
|
e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId=
|
||||||
|
{};this._byCid={}},_prepareModel:function(a,b){b||(b={});a instanceof o?a.collection||(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,
|
||||||
|
arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/:\w+/g,
|
||||||
|
C=/\*\w+/g,D=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,k,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,
|
||||||
|
this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(D,"\\$&").replace(B,"([^/]+)").replace(C,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,E=/msie [\w.]+/;m.started=!1;f.extend(m.prototype,k,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]:
|
||||||
|
""},getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");m.started=!0;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=
|
||||||
|
!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=E.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,
|
||||||
|
this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},
|
||||||
|
stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,
|
||||||
|
function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||
|
||||||
|
this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");
|
||||||
|
f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();
|
||||||
|
for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,
|
||||||
|
!1);else{var a=n(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=G(this,a,b);c.extend=this.extend;return c};var H={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=H[a];c||(c={});var e={type:d,dataType:"json"};c.url||(e.url=n(b,"url")||t());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",
|
||||||
|
e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},G=function(a,
|
||||||
|
b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');}}).call(this);
|
||||||
16
api/files/css
Normal file
16
api/files/css
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Droid Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Droid Sans'), local('DroidSans'), url(http://fonts.gstatic.com/s/droidsans/v5/s-BiyweUPV0v-yRb-cjciPk_vArhqVIZ0nv9q090hN8.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Droid Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Droid Sans Bold'), local('DroidSans-Bold'), url(http://fonts.gstatic.com/s/droidsans/v5/EFpQQyG9GqCrobXxL-KRMYWiMMZ7xLd792ULpGE4W_Y.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
|
}
|
||||||
2278
api/files/handlebars-1.0.0.js
Normal file
2278
api/files/handlebars-1.0.0.js
Normal file
File diff suppressed because it is too large
Load diff
1
api/files/highlight.7.3.pack.js
Normal file
1
api/files/highlight.7.3.pack.js
Normal file
File diff suppressed because one or more lines are too long
2
api/files/jquery-1.8.0.min.js
vendored
Normal file
2
api/files/jquery-1.8.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
18
api/files/jquery.ba-bbq.min.js
vendored
Normal file
18
api/files/jquery.ba-bbq.min.js
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
|
||||||
|
* http://benalman.com/projects/jquery-bbq-plugin/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||||
|
* Dual licensed under the MIT and GPL licenses.
|
||||||
|
* http://benalman.com/about/license/
|
||||||
|
*/
|
||||||
|
(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M<N?O[P]||(R[M+1]&&isNaN(R[M+1])?{}:[]):J}}else{if($.isArray(H[P])){H[P].push(J)}else{if(H[P]!==i){H[P]=[H[P],J]}else{H[P]=J}}}}else{if(P){H[P]=F?i:""}}});return H};function z(H,F,G){if(F===i||typeof F==="boolean"){G=F;F=a[H?D:A]()}else{F=E(F)?F.replace(H?w:x,""):F}return l(F,G)}l[A]=B(z,0);l[D]=v=B(z,1);$[y]||($[y]=function(F){return $.extend(C,F)})({a:k,base:k,iframe:t,img:t,input:t,form:"action",link:k,script:t});j=$[y];function s(I,G,H,F){if(!E(H)&&typeof H!=="object"){F=H;H=G;G=i}return this.each(function(){var L=$(this),J=G||j()[(this.nodeName||"").toLowerCase()]||"",K=J&&L.attr(J)||"";L.attr(J,a[I](K,H,F))})}$.fn[A]=B(s,A);$.fn[D]=B(s,D);b.pushState=q=function(I,F){if(E(I)&&/^#/.test(I)&&F===i){F=2}var H=I!==i,G=c(p[g][k],H?I:{},H?F:2);p[g][k]=G+(/#/.test(G)?"":"#")};b.getState=u=function(F,G){return F===i||typeof F==="boolean"?v(F):v(G)[F]};b.removeState=function(F){var G={};if(F!==i){G=u();$.each($.isArray(F)?F:arguments,function(I,H){delete G[H]})}q(G,2)};e[d]=$.extend(e[d],{add:function(F){var H;function G(J){var I=J[D]=c();J.getState=function(K,L){return K===i||typeof K==="boolean"?l(I,K):l(I,L)[K]};H.apply(this,arguments)}if($.isFunction(F)){H=F;return G}else{H=F.handler;F.handler=G}}})})(jQuery,this);
|
||||||
|
/*
|
||||||
|
* jQuery hashchange event - v1.2 - 2/11/2010
|
||||||
|
* http://benalman.com/projects/jquery-hashchange-plugin/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||||
|
* Dual licensed under the MIT and GPL licenses.
|
||||||
|
* http://benalman.com/about/license/
|
||||||
|
*/
|
||||||
|
(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this);
|
||||||
1
api/files/jquery.slideto.min.js
vendored
Normal file
1
api/files/jquery.slideto.min.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
(function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery);
|
||||||
8
api/files/jquery.wiggle.min.js
vendored
Normal file
8
api/files/jquery.wiggle.min.js
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
jQuery Wiggle
|
||||||
|
Author: WonderGroup, Jordan Thomas
|
||||||
|
URL: http://labs.wondergroup.com/demos/mini-ui/index.html
|
||||||
|
License: MIT (http://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
*/
|
||||||
|
jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('<div class="wiggle-wrap"></div>').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);}
|
||||||
|
if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});};
|
||||||
125
api/files/reset.css
Normal file
125
api/files/reset.css
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
div,
|
||||||
|
span,
|
||||||
|
applet,
|
||||||
|
object,
|
||||||
|
iframe,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
blockquote,
|
||||||
|
pre,
|
||||||
|
a,
|
||||||
|
abbr,
|
||||||
|
acronym,
|
||||||
|
address,
|
||||||
|
big,
|
||||||
|
cite,
|
||||||
|
code,
|
||||||
|
del,
|
||||||
|
dfn,
|
||||||
|
em,
|
||||||
|
img,
|
||||||
|
ins,
|
||||||
|
kbd,
|
||||||
|
q,
|
||||||
|
s,
|
||||||
|
samp,
|
||||||
|
small,
|
||||||
|
strike,
|
||||||
|
strong,
|
||||||
|
sub,
|
||||||
|
sup,
|
||||||
|
tt,
|
||||||
|
var,
|
||||||
|
b,
|
||||||
|
u,
|
||||||
|
i,
|
||||||
|
center,
|
||||||
|
dl,
|
||||||
|
dt,
|
||||||
|
dd,
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
li,
|
||||||
|
fieldset,
|
||||||
|
form,
|
||||||
|
label,
|
||||||
|
legend,
|
||||||
|
table,
|
||||||
|
caption,
|
||||||
|
tbody,
|
||||||
|
tfoot,
|
||||||
|
thead,
|
||||||
|
tr,
|
||||||
|
th,
|
||||||
|
td,
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
canvas,
|
||||||
|
details,
|
||||||
|
embed,
|
||||||
|
figure,
|
||||||
|
figcaption,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
output,
|
||||||
|
ruby,
|
||||||
|
section,
|
||||||
|
summary,
|
||||||
|
time,
|
||||||
|
mark,
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
details,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote,
|
||||||
|
q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before,
|
||||||
|
blockquote:after,
|
||||||
|
q:before,
|
||||||
|
q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
1221
api/files/screen.css
Normal file
1221
api/files/screen.css
Normal file
File diff suppressed because it is too large
Load diff
2765
api/files/shred.bundle.js
Normal file
2765
api/files/shred.bundle.js
Normal file
File diff suppressed because it is too large
Load diff
211
api/files/swagger-oauth.js
Normal file
211
api/files/swagger-oauth.js
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
var appName;
|
||||||
|
var popupMask;
|
||||||
|
var popupDialog;
|
||||||
|
var clientId;
|
||||||
|
var realm;
|
||||||
|
|
||||||
|
function handleLogin() {
|
||||||
|
var scopes = [];
|
||||||
|
|
||||||
|
if(window.swaggerUi.api.authSchemes
|
||||||
|
&& window.swaggerUi.api.authSchemes.oauth2
|
||||||
|
&& window.swaggerUi.api.authSchemes.oauth2.scopes) {
|
||||||
|
scopes = window.swaggerUi.api.authSchemes.oauth2.scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(window.swaggerUi.api
|
||||||
|
&& window.swaggerUi.api.info) {
|
||||||
|
appName = window.swaggerUi.api.info.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(popupDialog.length > 0)
|
||||||
|
popupDialog = popupDialog.last();
|
||||||
|
else {
|
||||||
|
popupDialog = $(
|
||||||
|
[
|
||||||
|
'<div class="api-popup-dialog">',
|
||||||
|
'<div class="api-popup-title">Select OAuth2.0 Scopes</div>',
|
||||||
|
'<div class="api-popup-content">',
|
||||||
|
'<p>Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.',
|
||||||
|
'<a href="#">Learn how to use</a>',
|
||||||
|
'</p>',
|
||||||
|
'<p><strong>' + appName + '</strong> API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>',
|
||||||
|
'<ul class="api-popup-scopes">',
|
||||||
|
'</ul>',
|
||||||
|
'<p class="error-msg"></p>',
|
||||||
|
'<div class="api-popup-actions"><button class="api-popup-authbtn api-button green" type="button">Authorize</button><button class="api-popup-cancel api-button gray" type="button">Cancel</button></div>',
|
||||||
|
'</div>',
|
||||||
|
'</div>'].join(''));
|
||||||
|
$(document.body).append(popupDialog);
|
||||||
|
|
||||||
|
popup = popupDialog.find('ul.api-popup-scopes').empty();
|
||||||
|
for (i = 0; i < scopes.length; i ++) {
|
||||||
|
scope = scopes[i];
|
||||||
|
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope;
|
||||||
|
if (scope.description) {
|
||||||
|
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>';
|
||||||
|
}
|
||||||
|
str += '</label></li>';
|
||||||
|
popup.append(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var $win = $(window),
|
||||||
|
dw = $win.width(),
|
||||||
|
dh = $win.height(),
|
||||||
|
st = $win.scrollTop(),
|
||||||
|
dlgWd = popupDialog.outerWidth(),
|
||||||
|
dlgHt = popupDialog.outerHeight(),
|
||||||
|
top = (dh -dlgHt)/2 + st,
|
||||||
|
left = (dw - dlgWd)/2;
|
||||||
|
|
||||||
|
popupDialog.css({
|
||||||
|
top: (top < 0? 0 : top) + 'px',
|
||||||
|
left: (left < 0? 0 : left) + 'px'
|
||||||
|
});
|
||||||
|
|
||||||
|
popupDialog.find('button.api-popup-cancel').click(function() {
|
||||||
|
popupMask.hide();
|
||||||
|
popupDialog.hide();
|
||||||
|
});
|
||||||
|
popupDialog.find('button.api-popup-authbtn').click(function() {
|
||||||
|
popupMask.hide();
|
||||||
|
popupDialog.hide();
|
||||||
|
|
||||||
|
var authSchemes = window.swaggerUi.api.authSchemes;
|
||||||
|
var host = window.location;
|
||||||
|
var redirectUrl = host.protocol + '//' + host.host + "/o2c.html";
|
||||||
|
var url = null;
|
||||||
|
|
||||||
|
var p = window.swaggerUi.api.authSchemes;
|
||||||
|
for (var key in p) {
|
||||||
|
if (p.hasOwnProperty(key)) {
|
||||||
|
var o = p[key].grantTypes;
|
||||||
|
for(var t in o) {
|
||||||
|
if(o.hasOwnProperty(t) && t === 'implicit') {
|
||||||
|
var dets = o[t];
|
||||||
|
url = dets.loginEndpoint.url + "?response_type=token";
|
||||||
|
window.swaggerUi.tokenName = dets.tokenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var scopes = []
|
||||||
|
var o = $('.api-popup-scopes').find('input:checked');
|
||||||
|
|
||||||
|
for(k =0; k < o.length; k++) {
|
||||||
|
scopes.push($(o[k]).attr("scope"));
|
||||||
|
}
|
||||||
|
|
||||||
|
window.enabledScopes=scopes;
|
||||||
|
|
||||||
|
url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
|
||||||
|
url += '&realm=' + encodeURIComponent(realm);
|
||||||
|
url += '&client_id=' + encodeURIComponent(clientId);
|
||||||
|
url += '&scope=' + encodeURIComponent(scopes);
|
||||||
|
|
||||||
|
window.open(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
popupMask.show();
|
||||||
|
popupDialog.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
for(key in window.authorizations.authz){
|
||||||
|
window.authorizations.remove(key)
|
||||||
|
}
|
||||||
|
window.enabledScopes = null;
|
||||||
|
$('.api-ic.ic-on').addClass('ic-off');
|
||||||
|
$('.api-ic.ic-on').removeClass('ic-on');
|
||||||
|
|
||||||
|
// set the info box
|
||||||
|
$('.api-ic.ic-warning').addClass('ic-error');
|
||||||
|
$('.api-ic.ic-warning').removeClass('ic-warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
function initOAuth(opts) {
|
||||||
|
var o = (opts||{});
|
||||||
|
var errors = [];
|
||||||
|
|
||||||
|
appName = (o.appName||errors.push("missing appName"));
|
||||||
|
popupMask = (o.popupMask||$('#api-common-mask'));
|
||||||
|
popupDialog = (o.popupDialog||$('.api-popup-dialog'));
|
||||||
|
clientId = (o.clientId||errors.push("missing client id"));
|
||||||
|
realm = (o.realm||errors.push("missing realm"));
|
||||||
|
|
||||||
|
if(errors.length > 0){
|
||||||
|
log("auth unable initialize oauth: " + errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('pre code').each(function(i, e) {hljs.highlightBlock(e)});
|
||||||
|
$('.api-ic').click(function(s) {
|
||||||
|
if($(s.target).hasClass('ic-off'))
|
||||||
|
handleLogin();
|
||||||
|
else {
|
||||||
|
handleLogout();
|
||||||
|
}
|
||||||
|
false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onOAuthComplete(token) {
|
||||||
|
if(token) {
|
||||||
|
if(token.error) {
|
||||||
|
var checkbox = $('input[type=checkbox],.secured')
|
||||||
|
checkbox.each(function(pos){
|
||||||
|
checkbox[pos].checked = false;
|
||||||
|
});
|
||||||
|
alert(token.error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var b = token[window.swaggerUi.tokenName];
|
||||||
|
if(b){
|
||||||
|
// if all roles are satisfied
|
||||||
|
var o = null;
|
||||||
|
$.each($('.auth #api_information_panel'), function(k, v) {
|
||||||
|
var children = v;
|
||||||
|
if(children && children.childNodes) {
|
||||||
|
var requiredScopes = [];
|
||||||
|
$.each((children.childNodes), function (k1, v1){
|
||||||
|
var inner = v1.innerHTML;
|
||||||
|
if(inner)
|
||||||
|
requiredScopes.push(inner);
|
||||||
|
});
|
||||||
|
var diff = [];
|
||||||
|
for(var i=0; i < requiredScopes.length; i++) {
|
||||||
|
var s = requiredScopes[i];
|
||||||
|
if(window.enabledScopes && window.enabledScopes.indexOf(s) == -1) {
|
||||||
|
diff.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(diff.length > 0){
|
||||||
|
o = v.parentNode;
|
||||||
|
$(o.parentNode).find('.api-ic.ic-on').addClass('ic-off');
|
||||||
|
$(o.parentNode).find('.api-ic.ic-on').removeClass('ic-on');
|
||||||
|
|
||||||
|
// sorry, not all scopes are satisfied
|
||||||
|
$(o).find('.api-ic').addClass('ic-warning');
|
||||||
|
$(o).find('.api-ic').removeClass('ic-error');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
o = v.parentNode;
|
||||||
|
$(o.parentNode).find('.api-ic.ic-off').addClass('ic-on');
|
||||||
|
$(o.parentNode).find('.api-ic.ic-off').removeClass('ic-off');
|
||||||
|
|
||||||
|
// all scopes are satisfied
|
||||||
|
$(o).find('.api-ic').addClass('ic-info');
|
||||||
|
$(o).find('.api-ic').removeClass('ic-warning');
|
||||||
|
$(o).find('.api-ic').removeClass('ic-error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2315
api/files/swagger-ui.js
Normal file
2315
api/files/swagger-ui.js
Normal file
File diff suppressed because it is too large
Load diff
1604
api/files/swagger.js
Normal file
1604
api/files/swagger.js
Normal file
File diff suppressed because it is too large
Load diff
32
api/files/underscore-min.js
vendored
Normal file
32
api/files/underscore-min.js
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Underscore.js 1.3.3
|
||||||
|
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||||
|
// Underscore is freely distributable under the MIT license.
|
||||||
|
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||||
|
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||||
|
// For all details and documentation:
|
||||||
|
// http://documentcloud.github.com/underscore
|
||||||
|
(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
|
||||||
|
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break;
|
||||||
|
g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,
|
||||||
|
c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&&
|
||||||
|
a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
|
||||||
|
c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
|
||||||
|
a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
|
||||||
|
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&
|
||||||
|
(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
|
||||||
|
j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,
|
||||||
|
0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,
|
||||||
|
e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
|
||||||
|
i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=
|
||||||
|
1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=
|
||||||
|
i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=
|
||||||
|
g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));
|
||||||
|
return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
|
||||||
|
c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
|
||||||
|
function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
|
||||||
|
b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
|
||||||
|
b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
|
||||||
|
function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
|
||||||
|
u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
|
||||||
|
b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
|
||||||
|
this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
|
||||||
15
api/package.json
Normal file
15
api/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "swagger-cli-validator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "validator.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"nopt": "^3.0.2",
|
||||||
|
"swagger-parser": "^3.2.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
76
api/swagger.html
Normal file
76
api/swagger.html
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||||
|
<title>Matrix Client-Server API Documentation</title>
|
||||||
|
<link href="./files/css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="./files/reset.css" media="screen" rel="stylesheet" type="text/css">
|
||||||
|
<link href="./files/screen.css" media="screen" rel="stylesheet" type="text/css">
|
||||||
|
<link href="./files/reset.css" media="print" rel="stylesheet" type="text/css">
|
||||||
|
<link href="./files/screen.css" media="print" rel="stylesheet" type="text/css">
|
||||||
|
<script type="text/javascript" src="./files/shred.bundle.js"></script>
|
||||||
|
<script src="./files/jquery-1.8.0.min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/jquery.slideto.min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/jquery.wiggle.min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/jquery.ba-bbq.min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/handlebars-1.0.0.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/underscore-min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/backbone-min.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/swagger.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/swagger-ui.js" type="text/javascript"></script>
|
||||||
|
<script src="./files/highlight.7.3.pack.js" type="text/javascript"></script>
|
||||||
|
|
||||||
|
<!-- enabling this will enable oauth2 implicit scope support -->
|
||||||
|
<script src="./files/swagger-oauth.js" type="text/javascript"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
|
window.swaggerUi = new SwaggerUi({
|
||||||
|
url: "http://localhost:8000/client-server/api-docs",
|
||||||
|
dom_id: "swagger-ui-container",
|
||||||
|
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
|
||||||
|
onComplete: function(swaggerApi, swaggerUi){
|
||||||
|
log("Loaded SwaggerUI");
|
||||||
|
|
||||||
|
if(typeof initOAuth == "function") {
|
||||||
|
initOAuth({
|
||||||
|
clientId: "your-client-id",
|
||||||
|
realm: "your-realms",
|
||||||
|
appName: "your-app-name"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$('pre code').each(function(i, e) {
|
||||||
|
hljs.highlightBlock(e)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onFailure: function(data) {
|
||||||
|
log("Unable to Load SwaggerUI");
|
||||||
|
},
|
||||||
|
docExpansion: "none"
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#input_apiKey').change(function() {
|
||||||
|
var key = $('#input_apiKey')[0].value;
|
||||||
|
log("key: " + key);
|
||||||
|
if(key && key.trim() != "") {
|
||||||
|
log("added key " + key);
|
||||||
|
window.authorizations.add("key", new ApiKeyAuthorization("access_token", key, "query"));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.swaggerUi.load();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="swagger-section">
|
||||||
|
<div id="swagger-header">
|
||||||
|
<div class="swagger-ui-wrap">
|
||||||
|
<form id="api_selector">
|
||||||
|
<div class="input"><input placeholder="access_token" id="input_apiKey" name="apiKey" type="text"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="message-bar" class="swagger-ui-wrap message-fail">Can't read from server. It may not have the appropriate access-control-origin settings.</div>
|
||||||
|
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
||||||
71
api/validator.js
Normal file
71
api/validator.js
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
"use strict";
|
||||||
|
var fs = require("fs");
|
||||||
|
var nopt = require("nopt");
|
||||||
|
var parser = require("swagger-parser");
|
||||||
|
var path = require("path");
|
||||||
|
|
||||||
|
var opts = nopt({
|
||||||
|
"help": Boolean,
|
||||||
|
"schema": path
|
||||||
|
}, {
|
||||||
|
"h": "--help",
|
||||||
|
"s": "--schema"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
console.log(
|
||||||
|
"Use swagger-parser to validate against Swagger 2.0\n"+
|
||||||
|
"Usage:\n"+
|
||||||
|
" node validator.js -s <schema_file_or_folder>"
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (!opts.schema) {
|
||||||
|
console.error("No [s]chema specified.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var errFn = function(err, api) {
|
||||||
|
if (!err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
var isDir = fs.lstatSync(opts.schema).isDirectory()
|
||||||
|
if (isDir) {
|
||||||
|
console.log("Checking directory %s for .yaml files...", opts.schema);
|
||||||
|
fs.readdir(opts.schema, function(err, files) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
files.forEach(function(f) {
|
||||||
|
var suffix = ".yaml";
|
||||||
|
if (f.indexOf(suffix, f.length - suffix.length) > 0) {
|
||||||
|
parser.validate(path.join(opts.schema, f), function(err, api, metadata) {
|
||||||
|
if (!err) {
|
||||||
|
console.log("%s is valid.", f);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error("%s is not valid.", f);
|
||||||
|
errFn(err, api, metadata);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
parser.validate(opts.schema, function(err, api) {
|
||||||
|
if (!err) {
|
||||||
|
console.log("%s is valid", opts.schema);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errFn(err, api);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-cyrillic-ext-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-cyrillic-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
/* greek-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-greek-ext-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+1F00-1FFF;
|
|
||||||
}
|
|
||||||
/* greek */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-greek-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
|
|
||||||
}
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-vietnamese-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-latin-ext-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Inter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Inter'), url(../../fonts/Inter-latin-normal.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
# Fonts
|
|
||||||
|
|
||||||
## Inter.css
|
|
||||||
|
|
||||||
`Inter.css` is a local copy of
|
|
||||||
https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap, modified to pull
|
|
||||||
font files (`.woff2`) from local sources. It was created
|
|
||||||
using `download_google_fonts_css.py`.
|
|
||||||
|
|
||||||
## download_google_fonts_css.py
|
|
||||||
|
|
||||||
`download_google_fonts_css.py` is a script that takes a google fonts CSS URL, downloads
|
|
||||||
the file and linked fonts, then saves the fonts locally along with a modified CSS file to
|
|
||||||
load them. Example call:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
python3 download_google_fonts_css.py \
|
|
||||||
"https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap" \
|
|
||||||
../../../static/fonts \
|
|
||||||
../../fonts
|
|
||||||
```
|
|
||||||
|
|
||||||
Which would pop out a `Inter.css` file that should be `@import url("Inter.css")`d
|
|
||||||
somewhere in the site's SCSS (currently in
|
|
||||||
[/assets/scss/_variables_project.scss](/assets/scss/_variables_project.scss)).
|
|
||||||
|
|
||||||
Re-running the script and committing any new files is only necessary when a desired
|
|
||||||
font updates (not very often), or we want to change the font we're using. In that case,
|
|
||||||
remove the existing font files at `/static/fonts/*.woff2` and re-run the script with a
|
|
||||||
different URL.
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# Copyright 2021 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.
|
|
||||||
|
|
||||||
# This script takes a google fonts CSS URL, downloads the referenced fonts locally
|
|
||||||
# and spits out a modified CSS file which now points to those local fonts.
|
|
||||||
#
|
|
||||||
# Purely for the purposes of converting a website to use local font files instead of
|
|
||||||
# making requests to Google Fonts.
|
|
||||||
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# Pull the font filename to process and output directory to point at
|
|
||||||
if len(sys.argv) < 4:
|
|
||||||
print(f"""
|
|
||||||
Error: Not enough arguments.
|
|
||||||
|
|
||||||
Usage: {sys.argv[0]} google_fonts_url font_directory css_font_path
|
|
||||||
* google fonts url: A URL leading to a google font css file (i.e https://fonts.googleapis.com/css?family=Inter)
|
|
||||||
* font directory: The location that font files will be downloaded to (i.e ../../fonts)
|
|
||||||
* font path: The directory the resulting CSS will be pointing to, relative to site root (i.e /unstable/css/fonts).
|
|
||||||
This is where the browser will look for fonts.
|
|
||||||
""")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
google_fonts_url = sys.argv[1]
|
|
||||||
font_output_dir = sys.argv[2]
|
|
||||||
css_font_path = sys.argv[3]
|
|
||||||
|
|
||||||
# Get font name
|
|
||||||
if google_fonts_url.count(":") > 1:
|
|
||||||
# Account for font weights specified in the URL
|
|
||||||
# (i.e https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i)
|
|
||||||
url_match = re.match(r".*family=(.*):", google_fonts_url)
|
|
||||||
else:
|
|
||||||
url_match = re.match(r".*family=(.*)", google_fonts_url)
|
|
||||||
|
|
||||||
if not url_match:
|
|
||||||
print("Unable to extract font name, invalid google fonts URL:", google_fonts_url)
|
|
||||||
print("URL should look something like: https://fonts.googleapis.com/css?family=Inter...")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
font_name = url_match.group(1)
|
|
||||||
|
|
||||||
# Ensure font paths end with a trailing slash
|
|
||||||
if not font_output_dir.endswith("/"):
|
|
||||||
font_output_dir += "/"
|
|
||||||
if not css_font_path.endswith("/"):
|
|
||||||
css_font_path += "/"
|
|
||||||
|
|
||||||
# Download the css file and split by newline
|
|
||||||
resp = requests.get(
|
|
||||||
google_fonts_url,
|
|
||||||
# We need to set a believable user-agent, else google fonts won't give us
|
|
||||||
# all of the font weights we requested for some reason
|
|
||||||
headers={
|
|
||||||
"User-Agent": "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if resp.status_code != 200:
|
|
||||||
print("Failed to download:", google_fonts_url, resp.status_code)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
original_contents = resp.text.split("\n")
|
|
||||||
|
|
||||||
# Download all referenced font files and write out new font file
|
|
||||||
new_css_file_lines = []
|
|
||||||
|
|
||||||
# Store metadata for helping give friendly names to each font file
|
|
||||||
font_lang = None
|
|
||||||
font_family = None
|
|
||||||
font_style = None
|
|
||||||
for line in original_contents:
|
|
||||||
# Check if this line contains a font URL
|
|
||||||
match = re.match(r".*url\((.*)\) format.*", line)
|
|
||||||
if match:
|
|
||||||
# Download the font file
|
|
||||||
font_url = match.group(1)
|
|
||||||
print("Downloading font:", font_url)
|
|
||||||
|
|
||||||
resp = requests.get(font_url)
|
|
||||||
if resp.status_code == 200:
|
|
||||||
# Save the font file
|
|
||||||
filename = "%s-%s-%s.woff2" % (
|
|
||||||
font_family, font_lang, font_style
|
|
||||||
)
|
|
||||||
font_filepath = font_output_dir + filename
|
|
||||||
with open(font_filepath, "wb") as f:
|
|
||||||
print("Writing font file:", font_filepath)
|
|
||||||
f.write(resp.content)
|
|
||||||
|
|
||||||
# Replace google URL with local URL and allow the browser to load the
|
|
||||||
# local font if it exists.
|
|
||||||
line = re.sub(r"url\(.+?\)", f"local('{font_family}'), url({css_font_path + filename})", line)
|
|
||||||
else:
|
|
||||||
print("Warning: failed to download font file:", font_url)
|
|
||||||
|
|
||||||
# Check for font metadata. If there is some, we'll note it down and use it to help
|
|
||||||
# name font files when we write them out.
|
|
||||||
# Makes for nicer font filenames than fvQtMwCp50KnMw2boKod... etc.
|
|
||||||
font_lang_match = re.match(r"^/\* (.+) \*/$", line)
|
|
||||||
if font_lang_match:
|
|
||||||
font_lang = font_lang_match.group(1)
|
|
||||||
font_family_match = re.match(r".*font-family: '(.+)';$", line)
|
|
||||||
if font_family_match:
|
|
||||||
font_family = font_family_match.group(1)
|
|
||||||
font_style_match = re.match(r".*font-style: (.+);$", line)
|
|
||||||
if font_style_match:
|
|
||||||
font_style = font_style_match.group(1)
|
|
||||||
|
|
||||||
# Append the potentially modified line to the new css file
|
|
||||||
new_css_file_lines.append(line)
|
|
||||||
|
|
||||||
# Write out the new font css file
|
|
||||||
with open(font_name + ".css", "w") as f:
|
|
||||||
new_css_file_contents = "\n".join(new_css_file_lines)
|
|
||||||
f.write(new_css_file_contents)
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
requests
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
# Spec diagrams
|
|
||||||
|
|
||||||
Non-ascii diagrams for the spec can be placed here for reference in the actual spec.
|
|
||||||
Please include source material so the diagram can be recreated by a future editor.
|
|
||||||
|
|
||||||
https://www.diagrams.net/ is a great ([open source](https://github.com/jgraph/drawio))
|
|
||||||
tool for these sorts of things - include your `.drawio` file next to your diagram.
|
|
||||||
|
|
||||||
Suggested settings for diagrams.net:
|
|
||||||
* Export as WebP.
|
|
||||||
* 200% size.
|
|
||||||
* `20` for a border width.
|
|
||||||
* Light appearance.
|
|
||||||
* No shadow, or grid.
|
|
||||||
|
|
||||||
To reference a diagram, use the `diagram` shortcode. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
{{% diagram name="membership" alt="Diagram presenting the possible membership state transitions" %}}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where `name` is the file name without extension, and `alt` is a textual
|
|
||||||
replacement for the image, useful for accessibility.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<mxfile host="Electron" modified="2022-02-18T05:31:13.369Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.5.1 Chrome/96.0.4664.110 Electron/16.0.7 Safari/537.36" etag="FwSKbslSItXwNPoLLuzM" version="16.5.1" type="device"><diagram id="4a_pTli-mcEMNPq0ciXK" name="Page-1">1VvZkto4FP0aqjIPdNnyBo9peklSnZmeoWayvKQECHC3sSghN5CvHxnLeFMbyeCFh1TQ9ZUX6Zyje6/UPWO02j0SuF5+xTPk9YA22/WMux4Auu4M2H+hZR9ZHE2LDAvizrhTYhi7vxE3xm6BO0ObjCPF2KPuOmucYt9HU5qxQULwNus2x172qWu4QAXDeAq9ovWbO6PLyDoATmL/hNzFMn6ybg+jKysYO/Mv2SzhDG9TJuO+Z4wIxjT6tdqNkBcOXjwuUb+Hd64eX4wgn8p0eNas3x+fbr2x/3O79n9ao2BI+zq/zRv0Av7F7A4v2PX5S9N9PBJoxgaGNzGhS7zAPvTuE+stwYE/Q+HjNNZKfJ4wXjOjzowviNI9n2UYUMxMS7ry+NXiJ/HX2+CATFHZd3BoQLJAtMQPRH7ht6QewAfsEeEVomTPHDh++9qNo5tG1IkgD1L3LQsMyPG1OPblt/tICNynHNZsTOkm9bTn0JA8Cgw5TjhRDDs3nWr+7Ef0Brne8evg+XzDRirbIzUEiekAIxVIFRDl+m8uRQVAZeGyXTKf8RoepnnLxEQSGm+IULSTmUymPZkRAxZvbxNi67E8LVOkjv1Ec50ZPeWhskXs8xBkIAMaJr2Q0g+v7vT1utgIJNloqrFRu9GG9qAKGZvEPwCiSZ3AVhQV7Vz6Pex+Y/HWj9SVux2/86Gxjxs+G4CoE7Di9rFb2Ej6HVpxx/oBYyjLt21Vk+9GEVMAjHABVtLLOfbpA1y5Xjg5Izb+Lgrl5E+0rUdMTbN1MR2IeBf4bTMvxTsWTVhy1NPTvIu71UI948JaLU2zsybbKMy1aJo7xRjLygVsoHXGCFeqSHs0d94Dtsde4XbChsFehL+g5+EtG0+gTfbFq2HHXyTwWLpWuPZhHUw8d9oDoxBDdPpHu4shqLQaOpnVUKuNkqYkJWWTmWYoqRc5ye7zTuzfxGy/N3GnwhixcoNy5W5gti3l4MfqeuSjOx2MlXWVeU9Qll2xQX0rtixgZIPlZuTBLMw0z3O7vGYb+SJL62u2MMhtUWSF+aVWiTL1MQYM69NYx7TPU9kYiPnqlGNlbxF9Je8lKgw2INfaiYBRO0aI+QAwDBi1q4kQs0uAbNKWw3ONSZs8oC+9BsiB17TlwKtcJAe553CSvFskL/gPcrxIFckvVs4R7qm0FdQkUXC1IFihcNgAntULgANg6LUItGXWg3Fdzz3HKN8IsrVS//Y2goBwd6MDsUo1cVdM/zOh6SfkvSHqTuF5LKkrVWQkN0GljRVVcBsxaeIoRysR5CbBanRKtIVhiDRQwdUAVV3OHcs6U84bEL5irvvqY8Embqdz3eN610Su+/W7/up/s/99HgXOuK/dYQT+FpwkCHfDhSN5ZamuZHUox4uKZLRkVw3zFPlMfQA6RD4haIAINOJSU/cTSkUpbwM1p0EzMIYdAk3p11740FLTm/CNnmgSsq+48l3qANNLsFrH/pBMz9Vw53wRl6zvXIaOsgnySToOHKuRSF83c6VzKxPpnyzV5PxbTGOHBUzf7ygiDHe98J0LhUwfH16M/Vuh1QSRYiUzQbauKCJS8bnCmYRcecwQ6AcQ6Idd1/aGIaww85gvKjEXR/xwuQ8nbHhLDyW0GTOCKnpzc5lELi2dPvZRbIre2mmoEq142DPM9WzTaUKqBrnExywvuJlmqX+LJ6+LStV+DaMR6BeDgwYiX/XixdDQzCYADYbZKptuqZWQc/4trr3C8yE8m8tLfdvn5c88a301RTt1IT9zh/yiOPuCbNsb//X58fafh/92v54o+fFZcJw0F3VUDTny19rFZaWkR/H0XHUASu9uqAPQzMhbv8VzcayZ/Mlf5J784aRx/z8=</diagram></mxfile>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
|
|
@ -1 +0,0 @@
|
||||||
<mxfile host="app.diagrams.net" modified="2022-09-27T03:26:23.216Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" etag="YZcXq9Sm_7Lqw5o2RvSU" version="14.6.7" type="device"><diagram id="_rQ0dgHO1UnHExDn0l7E" name="Page-1">7ZpdU+IwFIZ/DZc6bdNWuJQCujPquOvOrl452TbQaNowIXztr9+EJv0goLCirYwyo81JGpL3PQ8nU2mBIFlcMDiOr2mESMuxokUL9FqO41i+I/7IyDKL2JbvZZERw5GKFYE7/BfpgSo6xRGaVAZySgnH42owpGmKQl6JQcbovDpsSEn1XcdwhIzAXQiJGf2NIx5n0bZzVsQvER7F+p1tv5P1JFAPVjuZxDCi81II9FsgYJTy7CpZBIhI9bQu2X2DLb35whhK+S43/PIf6YMfPSfXNzfx1WP3ez/2ToDaxwySqdrxz5ghGInYudQaJ4jgFKkt8KXWhdFpGiE5td0C3XmMObobw1D2zkUqiFjME6K6hzTlA5hgIrPgEpEZ4jiEsgMTElBC2WpS0O/Jl4jPEJMjyDnBo1T0cTpW09ypJajty4FosVURO9dZZCiiCeJsKYbo9NTWqOT0dHteOO2c+acqY+Oyz201FKr8GuWzFxaIC+XCPo742x3pHrsjAFQdcS3TEdu3Nvhhv5sfruHHNcTpsTuRq7zUHJhO5G59jBO2YcS5If0rYsPJOCsSQ7yQBq2LHAR9byDW2D2Egp2qgsDeoOAGAcG76dc25EKRKHaqSRmP6YimkPSLaLeay8WYKyrTbhV8QpwvVeWGU06rkqMF5vfi2lLXD/JafKRmrd6i1NVb6kYq9nuvJ5CN0l2yWdy2aun7Kiz9FHhOxHZv0Fz8/kETmObGyn2/bKuQiU5ZiF7QUx1tOGQjxF/LWzNNGCKQ41l1HQc33TGg6TYZGsdvGDQueDM0T9NkrMenNEU1cFRC56GM1RaOCPyDSBeGz6PVTkpeDwL5eqlsHRAw8BkAAwZgwZsBOwRIbn5u1afbjlczSs4XSnWh5O6IklMnSuZJu9cElMBaTXLdumuSewwg7Xm2awhI3o4ggTpB8gyQ+o0AyW5eTbINYb5Q+iCU/B1RcutEyXwaN2gCSu76g7K6axLoGEIlpwzBkGOaHgNje577IjiJ8+XLxi3kHLF0FXEstzkYnr2toqmEPLFObfFTSUpbfbjvTKqa/ZZisYliCB0OJ2Jp6ymaL+L/s9b878dFE+g2C6Xv1lwoQXsD3yjC/BjY3rN+fh62Ozuy7dVZYs3KcdkECF3QvNOqZQhz/LQ1BCX9ILrZj1D0KkswfWsETO6HPdcXzeJLFdlBofhuCuj/Aw==</diagram></mxfile>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
|
|
@ -1 +0,0 @@
|
||||||
<mxfile host="app.diagrams.net" modified="2022-09-27T03:11:43.523Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" etag="L_ujIRop4Jndk67DcTE9" version="14.6.7" type="device"><diagram id="_rQ0dgHO1UnHExDn0l7E" name="Page-1">7VpbU+IwFP41PMqkTS/wKDfdGXXcdWdXn5wsDTTaNkwIAvvrN6UJbYlCF1gbXcYZTU5P0ub0u6S1DdiNFxcMTcJrGuCoYYNg0YC9hm3bwLPFnzSyzCIW8NwsMmYkkLE8cEd+Y5UoozMS4GkpkVMacTIpB4c0SfCQl2KIMTovp41oVD7rBI2xFrgbokiP/iQBD7Noy/bz+CUm41Cd2fLa2ZEYqWS5kmmIAjovhGC/AbuMUp614kUXR2n1VF2ycYM3jq4vjOGEVxnww3ukD17wHF/f3IRXj52v/dA9k7O8oGgmF3wur5YvVQnmIeH4boKGaX8u7nMDdkIeR6JniSaaTrLCj8gCi3N15JSYcbx481qtdQUEdjCNMWdLkaIGQFk0BRtH9uf5PVApYaH8KobkXR+vZ84LIxqyNn9Tp5ZWFhwIoMguZTykY5qgqJ9HO4zOkiAtyapOec4VpRMZfMKcLyXq0YzTcmnxgvB70Qay/ZC2m67s9RaFQ72l6iRivfdqgrRTGJV282Grnho3ogkfoJhEaeA7iQXpbHCD5+L3NxqjZH1j03Vvv62iTHTGhnhLPaUscMTGmO/Cpw4ThiPEyUv5Oo5+022NHB0TyGED08jhn8hxTHLAiuSwayWHr7EjbvKQYRQcjIanWTxR+QlN8IEAadpuASNWNYSApu8WQWLtgEiApuF6AWnnFnGOWbKK2MAR0Qj9wlEHDZ/Hq+V2aUTZqkBw0E1/NoF2iaMXzMkQ1QOvWrUXaujqGqG9vmna2z5p7zHJ4VQkB6xVe52Po71F6QXVALIpvWAHQj6O9FZFV63OroOrZ4L0Qsc06XVP0ntMcrgVyeHUKr3ux5He/ba99ifd9laF13YVOgNNB/pSIitDbjXdOWNoWUiYUJLwaeFst2kgP5WjZpSCp577B2/kW7C1LV80sivYGK0uh45GU1GYTYKsS7A/Z3TK9E0wFMeCTdcwS3FOlnJMznsVOe/Wain6e0ZjLWWv3bz9SXfzVdF16G5+L/dwwYa27XAPG7S25Zfd41jO4GnIHxjhDG3THjXgyReOyVy/InO9Wn1BZ0fcFK4w5IQmRjvDf/+KvSq+Dn2LuJ8ztMrOoH04sOkMbbgt/984g/7fpQsTnME17v2/fZASgJMzlOvZrshcv1ZnAK84Aw4If7ddwrvq/puKXcEQpkIeSDL+vloMyAOi54LXbbCA8wp2UgP2an1abWvQuzRBmD3XNGG2tLKchPkAcqgPQneyo10nOyxdmb+YQA///T6oFN38o9ZsO5h/Gwz7fwA=</diagram></mxfile>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<style>
|
|
||||||
path { fill: #000000; }
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
path { fill: #ffffff; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<path d="M 30,2.0000001 V 30 h -1 -2 v 2 h 5 V -3.3333334e-8 L 27,0 v 2 z"/>
|
|
||||||
<path d="M 9.9515939,10.594002 V 12.138 h 0.043994 c 0.3845141,-0.563728 0.8932271,-1.031728 1.4869981,-1.368 0.580003,-0.322998 1.244999,-0.485 1.993002,-0.485 0.72,0 1.376999,0.139993 1.971998,0.42 0.595,0.279004 1.047001,0.771001 1.355002,1.477001 0.338003,-0.500001 0.795999,-0.941 1.376999,-1.323001 0.579999,-0.382998 1.265998,-0.574 2.059998,-0.574 0.602003,0 1.160002,0.074 1.674002,0.220006 0.514,0.148006 0.953998,0.382998 1.321999,0.706998 0.36601,0.322999 0.653001,0.746 0.859,1.268002 0.205001,0.521998 0.307994,1.15 0.307994,1.887001 v 7.632997 h -3.127 v -6.463997 c 0,-0.383002 -0.01512,-0.743002 -0.04399,-1.082003 -0.02079,-0.3072 -0.103219,-0.607113 -0.242003,-0.881998 -0.133153,-0.25081 -0.335962,-0.457777 -0.584001,-0.596002 -0.257008,-0.146003 -0.605998,-0.220006 -1.046997,-0.220006 -0.440002,0 -0.796003,0.085 -1.068,0.253002 -0.272013,0.170003 -0.485001,0.390002 -0.639001,0.662003 -0.159119,0.287282 -0.263585,0.601602 -0.307994,0.926997 -0.05197,0.346923 -0.07801,0.697217 -0.07801,1.048002 v 6.353999 h -3.128005 v -6.398 c 0,-0.338003 -0.0072,-0.673001 -0.02116,-1.004001 -0.01134,-0.313663 -0.07487,-0.623229 -0.187994,-0.915999 -0.107943,-0.276623 -0.300435,-0.512126 -0.550001,-0.673001 -0.25799,-0.168 -0.636,-0.253002 -1.134999,-0.253002 -0.198123,0.0083 -0.394383,0.04195 -0.584002,0.100006 -0.258368,0.07446 -0.498455,0.201827 -0.704999,0.373985 -0.227981,0.183987 -0.421999,0.449 -0.583997,0.794003 -0.161008,0.345978 -0.242003,0.797998 -0.242003,1.356998 v 6.618999 H 6.99942 V 10.590001 Z"/>
|
|
||||||
<path d="M 2,2.0000001 V 30 h 3 v 2 H 0 V 9.2650922e-8 L 5,0 v 2 z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
|
@ -1,5 +0,0 @@
|
||||||
<svg width="75" height="32" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g fill="#000" fill-rule="nonzero">
|
|
||||||
<path d="M.936.732V31.25H3.13v.732H.095V0h3.034v.732zM9.386 10.407v1.544h.044a4.461 4.461 0 0 1 1.487-1.368c.58-.323 1.245-.485 1.993-.485.72 0 1.377.14 1.972.42.595.279 1.047.771 1.355 1.477.338-.5.796-.941 1.377-1.323.58-.383 1.266-.574 2.06-.574.602 0 1.16.074 1.674.22.514.148.954.383 1.322.707.366.323.653.746.859 1.268.205.522.308 1.15.308 1.887v7.633H20.71v-6.464c0-.383-.015-.743-.044-1.082a2.305 2.305 0 0 0-.242-.882 1.473 1.473 0 0 0-.584-.596c-.257-.146-.606-.22-1.047-.22-.44 0-.796.085-1.068.253-.272.17-.485.39-.639.662a2.654 2.654 0 0 0-.308.927 7.074 7.074 0 0 0-.078 1.048v6.354h-3.128v-6.398c0-.338-.007-.673-.021-1.004a2.825 2.825 0 0 0-.188-.916 1.411 1.411 0 0 0-.55-.673c-.258-.168-.636-.253-1.135-.253a2.33 2.33 0 0 0-.584.1 1.94 1.94 0 0 0-.705.374c-.228.184-.422.449-.584.794-.161.346-.242.798-.242 1.357v6.619H6.434V10.407h2.952zM25.842 12.084a3.751 3.751 0 0 1 1.233-1.17 5.37 5.37 0 0 1 1.685-.629 9.579 9.579 0 0 1 1.884-.187c.573 0 1.153.04 1.74.121.588.081 1.124.24 1.609.475.484.235.88.562 1.19.981.308.42.462.975.462 1.666v5.934c0 .516.03 1.008.088 1.478.058.471.161.824.308 1.06H32.87a4.435 4.435 0 0 1-.22-1.104c-.5.515-1.087.876-1.762 1.081a7.084 7.084 0 0 1-2.071.31c-.544 0-1.05-.067-1.52-.2a3.472 3.472 0 0 1-1.234-.617 2.87 2.87 0 0 1-.826-1.059c-.199-.426-.298-.934-.298-1.522 0-.647.114-1.18.342-1.6.227-.419.52-.753.881-1.004.36-.25.771-.437 1.234-.562.462-.125.929-.224 1.399-.298.47-.073.932-.132 1.387-.176.456-.044.86-.11 1.212-.199.353-.088.631-.217.837-.386.206-.169.301-.415.287-.74 0-.337-.055-.606-.166-.804a1.217 1.217 0 0 0-.44-.464 1.737 1.737 0 0 0-.639-.22 5.292 5.292 0 0 0-.782-.055c-.617 0-1.101.132-1.454.397-.352.264-.558.706-.617 1.323h-3.128c.044-.735.227-1.345.55-1.83zm6.179 4.423a5.095 5.095 0 0 1-.639.165 9.68 9.68 0 0 1-.716.11c-.25.03-.5.067-.749.11a5.616 5.616 0 0 0-.694.177 2.057 2.057 0 0 0-.594.298c-.17.125-.305.284-.408.474-.103.192-.154.434-.154.728 0 .28.051.515.154.706.103.192.242.342.419.453.176.11.381.187.617.231.234.044.477.066.726.066.617 0 1.094-.102 1.432-.309.338-.205.587-.452.75-.739.16-.286.26-.576.297-.87.036-.295.055-.53.055-.707v-1.17a1.4 1.4 0 0 1-.496.277zM43.884 10.407v2.096h-2.291v5.647c0 .53.088.883.264 1.059.176.177.529.265 1.057.265.177 0 .345-.007.507-.022.161-.015.316-.037.463-.066v2.426a7.49 7.49 0 0 1-.882.089 21.67 21.67 0 0 1-.947.022c-.484 0-.944-.034-1.377-.1a3.233 3.233 0 0 1-1.145-.386 2.04 2.04 0 0 1-.782-.816c-.191-.353-.287-.816-.287-1.39v-6.728H36.57v-2.096h1.894v-3.42h3.129v3.42h2.29zM48.355 10.407v2.118h.044a3.907 3.907 0 0 1 1.454-1.754 4.213 4.213 0 0 1 1.036-.497 3.734 3.734 0 0 1 1.145-.176c.206 0 .433.037.683.11v2.912a5.862 5.862 0 0 0-.528-.077 5.566 5.566 0 0 0-.595-.033c-.573 0-1.058.096-1.454.287a2.52 2.52 0 0 0-.958.783 3.143 3.143 0 0 0-.518 1.158 6.32 6.32 0 0 0-.154 1.434v5.14h-3.128V10.407h2.973zM54.039 8.642V6.06h3.128v2.582H54.04zm3.128 1.765v11.405H54.04V10.407h3.128zM58.797 10.407h3.569l2.005 2.978 1.982-2.978h3.459l-3.745 5.339 4.208 6.067h-3.57l-2.378-3.596-2.38 3.596h-3.502l4.097-6.001zM74.094 31.25V.732H71.9V0h3.035v31.982H71.9v-.732z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB |
169
assets/js/toc.js
169
assets/js/toc.js
|
|
@ -1,169 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020, 2021 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Only call the given function once every 250 milliseconds to avoid impacting
|
|
||||||
the performance of the browser.
|
|
||||||
Source: https://remysharp.com/2010/07/21/throttling-function-calls
|
|
||||||
*/
|
|
||||||
function throttle(fn) {
|
|
||||||
const threshold = 250;
|
|
||||||
let last = null;
|
|
||||||
let deferTimer = null;
|
|
||||||
|
|
||||||
return function (...args) {
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
if (last && now < last + threshold) {
|
|
||||||
// Hold on to it.
|
|
||||||
clearTimeout(deferTimer);
|
|
||||||
deferTimer = setTimeout(() => {
|
|
||||||
last = now;
|
|
||||||
fn.apply(this, args);
|
|
||||||
}, threshold);
|
|
||||||
} else {
|
|
||||||
last = now;
|
|
||||||
fn.apply(this, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the list of headings that appear in the ToC.
|
|
||||||
This is not as simple as querying all the headings in the content, because
|
|
||||||
some headings are not rendered in the ToC (e.g. in the endpoint definitions).
|
|
||||||
*/
|
|
||||||
function getHeadings() {
|
|
||||||
let headings = [];
|
|
||||||
|
|
||||||
// First get the anchors in the ToC.
|
|
||||||
const toc_anchors = document.querySelectorAll("#toc nav a");
|
|
||||||
|
|
||||||
for (const anchor of toc_anchors) {
|
|
||||||
// Then get the heading from its selector in the anchor's href.
|
|
||||||
const selector = anchor.getAttribute("href");
|
|
||||||
if (!selector) {
|
|
||||||
console.error("Got ToC anchor without href");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const heading = document.querySelector(selector);
|
|
||||||
if (!heading) {
|
|
||||||
console.error("Heading not found for selector:", selector);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
headings.push(heading);
|
|
||||||
}
|
|
||||||
|
|
||||||
return headings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the heading of the text visible at the top of the viewport.
|
|
||||||
This is the first heading above or at the top of the viewport.
|
|
||||||
*/
|
|
||||||
function getCurrentHeading(headings, headerOffset) {
|
|
||||||
const scrollTop = document.documentElement.scrollTop;
|
|
||||||
let prevHeading = null;
|
|
||||||
let currentHeading = null;
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
for (const heading of headings) {
|
|
||||||
// Compute the position compared to the viewport.
|
|
||||||
const rect = heading.getBoundingClientRect();
|
|
||||||
|
|
||||||
if (rect.top >= headerOffset && rect.top <= headerOffset + 30) {
|
|
||||||
// This heading is at the top of the viewport, this is the current heading.
|
|
||||||
currentHeading = heading;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (rect.top >= headerOffset) {
|
|
||||||
// This is in or below the viewport, the current heading should be the
|
|
||||||
// previous one.
|
|
||||||
if (prevHeading) {
|
|
||||||
currentHeading = prevHeading;
|
|
||||||
} else {
|
|
||||||
// The first heading does not have a prevHeading.
|
|
||||||
currentHeading = heading;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prevHeading = heading;
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At the bottom of the page we might not have a heading.
|
|
||||||
if (!currentHeading) {
|
|
||||||
currentHeading = prevHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Select the ToC entry that points to the given ID.
|
|
||||||
Clear any previously highlighted ToC items, select the new one,
|
|
||||||
and adjust the ToC scroll position.
|
|
||||||
*/
|
|
||||||
function selectTocEntry(id) {
|
|
||||||
// Deselect previously selected entries.
|
|
||||||
const activeEntries = document.querySelectorAll("#toc nav 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}"]`);
|
|
||||||
if (!newEntry) {
|
|
||||||
console.error("ToC entry not found for ID:", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
newEntry.classList.add('active');
|
|
||||||
|
|
||||||
// Don't scroll the sidebar nav if the main content is not scrolled
|
|
||||||
const nav = document.querySelector("#td-section-nav");
|
|
||||||
const content = document.querySelector("html");
|
|
||||||
if (content.scrollTop !== 0) {
|
|
||||||
nav.scrollTop = newEntry.offsetTop - 100;
|
|
||||||
} else {
|
|
||||||
nav.scrollTop = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Track when the view is scrolled, and use this to update the highlight for the
|
|
||||||
corresponding ToC entry.
|
|
||||||
*/
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
|
||||||
// Part of the viewport is below the header so we should take it into account.
|
|
||||||
const headerOffset = document.querySelector("body > header > nav").clientHeight;
|
|
||||||
const headings = getHeadings();
|
|
||||||
|
|
||||||
const onScroll = throttle((_e) => {
|
|
||||||
// Update the ToC.
|
|
||||||
let heading = getCurrentHeading(headings, headerOffset);
|
|
||||||
selectTocEntry(heading.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize the state of the ToC.
|
|
||||||
onScroll();
|
|
||||||
|
|
||||||
// Listen to scroll and resizing changes.
|
|
||||||
document.addEventListener('scroll', onScroll, false);
|
|
||||||
document.addEventListener('resize', onScroll, false);
|
|
||||||
});
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2025 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Determine the current version as defined in hugo.toml. This will either be
|
|
||||||
// "unstable" or "vX.X" and doesn't depend on the current URL.
|
|
||||||
//
|
|
||||||
// The oddity below is an attempt at producing a readable Hugo template while
|
|
||||||
// avoiding JS syntax errors in your IDE.
|
|
||||||
const currentVersion = `{{ if eq .Site.Params.version.status "unstable" }}
|
|
||||||
{{- /**/ -}}
|
|
||||||
unstable
|
|
||||||
{{- /**/ -}}
|
|
||||||
{{ else }}
|
|
||||||
{{- /**/ -}}
|
|
||||||
{{ printf "v%s.%s" .Site.Params.version.major .Site.Params.version.minor }}
|
|
||||||
{{- /**/ -}}
|
|
||||||
{{ end }}`;
|
|
||||||
|
|
||||||
// Determine the current version segment by regex matching the URL. This will either
|
|
||||||
// be "unstable", "latest", "vX.X" (production) or undefined (local & netlify).
|
|
||||||
const href = window.location.href;
|
|
||||||
const segmentMatches = href.match(/(?<=\/)unstable|latest|v\d+.\d+(?=\/)/);
|
|
||||||
const currentSegment = segmentMatches ? segmentMatches[0] : undefined;
|
|
||||||
|
|
||||||
// Determine the selected menu element. If we were able to obtain the version
|
|
||||||
// segment from the URL (production), use that. Otherwise (local & netlify),
|
|
||||||
// fall back to the version as defined in Hugo.
|
|
||||||
const selected = currentSegment ?? currentVersion;
|
|
||||||
|
|
||||||
function appendVersion(parent, name, segment, url) {
|
|
||||||
// The list item
|
|
||||||
const li = document.createElement("li");
|
|
||||||
if (segment === selected) {
|
|
||||||
li.classList.add("version-picker-selected");
|
|
||||||
}
|
|
||||||
if (segment === "latest") {
|
|
||||||
li.classList.add("version-picker-latest");
|
|
||||||
}
|
|
||||||
parent.appendChild(li);
|
|
||||||
|
|
||||||
// The link
|
|
||||||
const a = document.createElement("a");
|
|
||||||
a.classList.add("dropdown-item");
|
|
||||||
a.setAttribute("href", url);
|
|
||||||
li.appendChild(a);
|
|
||||||
|
|
||||||
// Handle clicks manually to preserve the current path / fragment
|
|
||||||
a.addEventListener("click", (ev) => {
|
|
||||||
// If the URL is a relative link (i.e. the historical versions changelog), just
|
|
||||||
// let the browser load it
|
|
||||||
if (url.startsWith("/")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we couldn't determine the current segment, we cannot safely replace
|
|
||||||
// it and have to let the browser load the (root) URL instead
|
|
||||||
if (!currentSegment) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, stop further event handling and replace the segment
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
window.location.href = href.replace(`/${currentSegment}/`, `/${segment}/`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// The link text
|
|
||||||
const text = document.createTextNode(name);
|
|
||||||
a.appendChild(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're in the unstable version, we're the latest thing and can just load
|
|
||||||
// versions.json from our own resources. Otherwise, we fall back to loading it
|
|
||||||
// from /unstable/versions.json, assuming we are on the spec.matrix.org deployment.
|
|
||||||
const url = currentVersion === "unstable"
|
|
||||||
? '{{ .Site.Home.Permalink }}versions.json'
|
|
||||||
: "/unstable/versions.json";
|
|
||||||
|
|
||||||
fetch(url)
|
|
||||||
.then(r => r.json())
|
|
||||||
.then(versions => {
|
|
||||||
// Find the surrounding list element
|
|
||||||
const ul = document.querySelector("ul#version-selector");
|
|
||||||
if (!ul) {
|
|
||||||
console.error("Cannot populate version selector: ul element not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a entries for the unstable version and the "latest" shortcut
|
|
||||||
appendVersion(ul, "unstable", "unstable", "https://spec.matrix.org/unstable");
|
|
||||||
const latestName = versions?.length ? `latest (${versions[0].name})` : "latest";
|
|
||||||
appendVersion(ul, latestName, "latest", "https://spec.matrix.org/latest");
|
|
||||||
|
|
||||||
// Add an entry for each proper version
|
|
||||||
for (const version of versions) {
|
|
||||||
appendVersion(ul, version.name, version.name, `https://spec.matrix.org/${version.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For historical versions, simply link to the changelog
|
|
||||||
appendVersion(ul, "historical", "historical", '{{ (site.GetPage "changelog/historical").RelPermalink }}');
|
|
||||||
});
|
|
||||||
|
|
@ -1,647 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020, 2021 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Custom SCSS for the Matrix spec
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Import the CSS classes for the syntax highlighter.
|
|
||||||
*
|
|
||||||
* This is generated with:
|
|
||||||
*
|
|
||||||
* hugo gen chromastyles --style=tango > assets/scss/syntax.scss
|
|
||||||
*/
|
|
||||||
@import "syntax.scss";
|
|
||||||
|
|
||||||
/* Overrides for the navbar */
|
|
||||||
.td-navbar {
|
|
||||||
box-shadow: 0px 0px 8px rgba(179, 179, 179, 0.25);
|
|
||||||
min-height: 5rem;
|
|
||||||
|
|
||||||
.navbar-brand {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
|
|
||||||
/* Allow the text to wrap if it is wider than the viewport */
|
|
||||||
text-align: center;
|
|
||||||
white-space: normal;
|
|
||||||
|
|
||||||
.navbar-version {
|
|
||||||
color: $secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $black;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make the version dropdown scroll if it's too large */
|
|
||||||
ul#version-selector {
|
|
||||||
max-height: 80vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul#version-selector li.version-picker-selected a {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul#version-selector li.version-picker-latest a {
|
|
||||||
color: $secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styles for the sidebar nav */
|
|
||||||
.td-sidebar {
|
|
||||||
/* don't attempt to use the sidebar (or things in it) as a scroll anchor. */
|
|
||||||
overflow-anchor: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.td-sidebar-nav {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
overscroll-behavior: contain;
|
|
||||||
|
|
||||||
&>.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active, &active:hover {
|
|
||||||
background-color: $secondary-background;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
@supports (position: sticky) {
|
|
||||||
.td-sidebar-nav {
|
|
||||||
/* This overrides calc(100vh - 10rem);, which gives us a blank space at the bottom of the sidebar */
|
|
||||||
max-height: calc(100vh - 6rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Customise footer */
|
|
||||||
.td-footer {
|
|
||||||
box-shadow: 0px 0px 8px rgba(179, 179, 179, 0.25);
|
|
||||||
padding-top: 2rem;
|
|
||||||
color: var(--bs-body-color);
|
|
||||||
background-color: var(--bs-body-color-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Auto numbering for headings */
|
|
||||||
.td-content {
|
|
||||||
|
|
||||||
counter-reset: h2;
|
|
||||||
|
|
||||||
&> h2 {
|
|
||||||
counter-reset: h3
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h3 {
|
|
||||||
counter-reset: h4
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h4 {
|
|
||||||
counter-reset: h5
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h5 {
|
|
||||||
counter-reset: h6
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h2:not(.no-numbers):before {
|
|
||||||
display: inline; visibility: visible; counter-increment: h2; content: counter(h2) ". "
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h3:not(.no-numbers):before {
|
|
||||||
display: inline; visibility: visible; counter-increment: h3; content: counter(h2) "." counter(h3) ". "
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h4:not(.no-numbers):before {
|
|
||||||
display: inline; visibility: visible; counter-increment: h4; content: counter(h2) "." counter(h3) "." counter(h4) ". "
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h5:not(.no-numbers):before {
|
|
||||||
display: inline; visibility: visible; counter-increment: h5; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". "
|
|
||||||
}
|
|
||||||
|
|
||||||
&> h6:not(.no-numbers):before {
|
|
||||||
display: inline; visibility: visible; counter-increment: h6; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove some padding before the main content, when the sidebar is disabled */
|
|
||||||
.td-main main {
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust the scroll margin for everything in the main content, so that
|
|
||||||
* it doesn't disappear behind the header bar */
|
|
||||||
.td-content * {
|
|
||||||
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 {
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.endpoints-toc {
|
|
||||||
summary {
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
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 */
|
|
||||||
.alert {
|
|
||||||
&.note {
|
|
||||||
&:not(.omit-title):before {
|
|
||||||
content: "INFO: ";
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
border: 2px solid $note;
|
|
||||||
border-left-width: 5px;
|
|
||||||
background: $note-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rationale {
|
|
||||||
&:not(.omit-title):before {
|
|
||||||
content: "RATIONALE: ";
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
border: 2px solid $note;
|
|
||||||
border-left-width: 5px;
|
|
||||||
background: $note-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
&:not(.omit-title):before {
|
|
||||||
content: "WARNING: ";
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
border: 2px solid $warning;
|
|
||||||
border-left-width: 5px;
|
|
||||||
background: $warning-background;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styles for sections that are rendered from data, such as HTTP APIs and event schemas */
|
|
||||||
.td-content .rendered-data {
|
|
||||||
background-color: $secondary-lightest-background;
|
|
||||||
padding: 0.85rem;
|
|
||||||
margin: 0.85rem 0;
|
|
||||||
|
|
||||||
details {
|
|
||||||
summary {
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
|
||||||
/* Ensure the disclosure control is vertically centred with the header text. */
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
max-width: 80%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.deprecated-inline {
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: " — DEPRECATED";
|
|
||||||
color: $warning;
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
|
|
||||||
.endpoint {
|
|
||||||
color: $secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
margin: 1.5rem 0 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
margin: 1.5rem 0 1rem 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reduce top margin of h3 if previous sibling is a h2 */
|
|
||||||
h2 + h3 {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border-bottom: 2px solid $dark;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p code, table code {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
/* Docsy by default applies `overflow-x: auto;` to tables, which
|
|
||||||
* results in annoying horizontal scrolling on mobile, so we instead
|
|
||||||
* switch to a fixed table layout on a narrow browser width.
|
|
||||||
* (On a wider width the default auto table-layout provides better readability.)
|
|
||||||
*
|
|
||||||
* Docsy makes all tables "responsive tables", which causes Bootstrap 4 to create
|
|
||||||
* tables with a "display" property of "block".
|
|
||||||
* However, for "table-layout: fixed" to be effective, an element must have a
|
|
||||||
* "display" property of "table".
|
|
||||||
*
|
|
||||||
* Thus, we override the "display" property here. This may no longer be necessary once
|
|
||||||
* Docsy updates to Bootstrap v5+: https://github.com/google/docsy/issues/470.
|
|
||||||
* For more details, see
|
|
||||||
* https://github.com/matrix-org/matrix-spec/pull/1295/files#r1010759688 */
|
|
||||||
display: table;
|
|
||||||
table-layout: fixed;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.col-name, .col-type, .col-status {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-description {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-status-description {
|
|
||||||
width: 75%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
caption-side: top;
|
|
||||||
color: $dark;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
th, td, caption {
|
|
||||||
padding: 1rem;
|
|
||||||
border-top: 1px $table-border-color solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
td > p:last-child {
|
|
||||||
// Avoid unnecessary space at the bottom of the cells.
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.object-table, &.response-table, &.content-type-table {
|
|
||||||
border: 1px $table-border-color solid;
|
|
||||||
|
|
||||||
caption {
|
|
||||||
// the caption is outside the table's border box,
|
|
||||||
// so we have to give it its own border.
|
|
||||||
border: 1px $table-border-color solid;
|
|
||||||
|
|
||||||
// ... but avoid double border between caption and table
|
|
||||||
border-bottom: 0;
|
|
||||||
|
|
||||||
background-color: $secondary-lighter-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody tr {
|
|
||||||
--bs-table-striped-bg: #{$secondary-lighter-background};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.basic-info, &.basic-info th, &.basic-info td {
|
|
||||||
table-layout: fixed;
|
|
||||||
margin: 1rem 0 .5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.basic-info th {
|
|
||||||
width: 15rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Arrange rows vertically when horizontal space is constrained to avoid overflowing */
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
/* Make cells full width without vertical margin */
|
|
||||||
&.basic-info th, &.basic-info td {
|
|
||||||
width: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove border and padding between header & data cells to make them appear like a single cell */
|
|
||||||
&.basic-info td {
|
|
||||||
padding-top: 0;
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
&.basic-info th {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove top border on all but the first header cell to prevent double borders between rows */
|
|
||||||
&.basic-info tr + tr th {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Have consistent spacing around tables and examples */
|
|
||||||
table, .highlight {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
|
|
||||||
/* We don't need the margin on the last child of the .rendered-data block */
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
border: 0;
|
|
||||||
border-left: solid 5px $secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.http-api-method {
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Miscellaneous custom bits */
|
|
||||||
|
|
||||||
/* Update link colours for MAtrix style */
|
|
||||||
a, a:hover {
|
|
||||||
color: $secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is needed to stop the bottom of the Matrix icon from getting snipped off. */
|
|
||||||
.td-navbar .navbar-brand svg {
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Give code samples and pre elements full-width */
|
|
||||||
.td-content > .highlight, .td-content > pre {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The default CSS applies a style for blockquotes but only to immediate children
|
|
||||||
of .td-content. This applies the same style to any blockquotes that descend from
|
|
||||||
.td-content. */
|
|
||||||
.td-content blockquote {
|
|
||||||
padding: 0 0 0 1rem;
|
|
||||||
margin-bottom: $spacer;
|
|
||||||
color: $gray-600;
|
|
||||||
border-left: 6px solid $secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Make padding symmetrical (this selector is used in the default styles to apply padding-left: 3rem)
|
|
||||||
*/
|
|
||||||
.pl-md-5, .px-md-5 {
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
padding-right: 3rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust the width of math to match normal paragraphs */
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
.katex-display {
|
|
||||||
max-width: 80%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust default styles for info banner */
|
|
||||||
.pageinfo-primary {
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
max-width: 80%;
|
|
||||||
}
|
|
||||||
margin-top: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
border: 0;
|
|
||||||
border-left: solid 5px $secondary;
|
|
||||||
background-color: $gray-100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pageinfo-unstable {
|
|
||||||
background-image: url('../icons/unstable.png');
|
|
||||||
background-position: left 1rem center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
padding-left: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjust the styling of definition lists. */
|
|
||||||
|
|
||||||
/* Add a little spacing between the term and its definition. */
|
|
||||||
dt {
|
|
||||||
margin-bottom: 0.15rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* _reboot.scss deliberately sets margin-left to 0. Undo this. */
|
|
||||||
dd {
|
|
||||||
margin-left: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* docsy's _code.scss does only styles <code> elements matching
|
|
||||||
* .td-content { p code, li > code, table code }.
|
|
||||||
* Copy those styles here to apply to code <elements> in definition terms too. */
|
|
||||||
|
|
||||||
.td-content {
|
|
||||||
dt code {
|
|
||||||
color: inherit;
|
|
||||||
padding: 0.2em 0.4em;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 85%;
|
|
||||||
word-break: normal;
|
|
||||||
background-color: rgba($black, 0.05);
|
|
||||||
border-radius: 0.25rem; // was $border-radius, but that var isn't accessible here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style for breadcrumbs */
|
|
||||||
.td-breadcrumbs {
|
|
||||||
padding: .75rem 1rem;
|
|
||||||
background-color: #eee;
|
|
||||||
border-radius: .25rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
.breadcrumb {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020, 2021 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
$primary: #FFF;
|
|
||||||
$secondary: #0098D4;
|
|
||||||
$dark: #333;
|
|
||||||
$gray-100: #FBFBFB;
|
|
||||||
|
|
||||||
$secondary-background: #E5F5FB;
|
|
||||||
$secondary-lighter-background: #F4FAFC;
|
|
||||||
$secondary-lightest-background: #FBFDFD;
|
|
||||||
|
|
||||||
|
|
||||||
$warning: #FF6666;
|
|
||||||
$note: $secondary;
|
|
||||||
|
|
||||||
$note-background: $secondary-background;
|
|
||||||
$warning-background: #FFE0E0;
|
|
||||||
|
|
||||||
// colours for definition tables.
|
|
||||||
// the border colour matches that used for "highlight" divs
|
|
||||||
$table-border-color: rgba(black, .125);
|
|
||||||
$table-bg: $secondary-lightest-background;
|
|
||||||
|
|
||||||
/* Configure docsy to use the default system fonts instead of Google Fonts.
|
|
||||||
* See https://www.docsy.dev/docs/adding-content/lookandfeel/#fonts */
|
|
||||||
$td-enable-google-fonts: false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The $font-family-sans-serif definition here overrides the default value set by docsy
|
|
||||||
* (https://github.com/matrix-org/docsy/blob/66a4e61d2d34edc7196b9df83a7d09cd4af14b47/assets/scss/_variables.scss#L68)
|
|
||||||
*/
|
|
||||||
$font-family-sans-serif:
|
|
||||||
// Add "Inter" to the front, making it the default. The font itself is loaded via stylesheet
|
|
||||||
// links in layouts/partials/hooks/head-end.html.
|
|
||||||
"Inter",
|
|
||||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
|
||||||
// Insert fonts suited for mathematical symbols on different platforms before "Arial"
|
|
||||||
"STIX Two Math", "Cambria Math", "Noto Sans Math", "Dejavu Sans",
|
|
||||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
|
|
||||||
// Disable smooth scrolling as it makes TOC highlighting jump during the transition.
|
|
||||||
$enable-smooth-scroll: false;
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
/* Background */ .chroma { background-color: #f8f8f8 }
|
|
||||||
/* Other */ .chroma .x { color: #000000 }
|
|
||||||
/* Error */ .chroma .err { color: #a40000 }
|
|
||||||
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
|
|
||||||
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
|
|
||||||
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
|
|
||||||
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
|
||||||
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
|
||||||
/* Keyword */ .chroma .k { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordConstant */ .chroma .kc { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordDeclaration */ .chroma .kd { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordNamespace */ .chroma .kn { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordPseudo */ .chroma .kp { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordReserved */ .chroma .kr { color: #204a87; font-weight: bold }
|
|
||||||
/* KeywordType */ .chroma .kt { color: #204a87; font-weight: bold }
|
|
||||||
/* Name */ .chroma .n { color: #000000 }
|
|
||||||
/* NameAttribute */ .chroma .na { color: #c4a000 }
|
|
||||||
/* NameBuiltin */ .chroma .nb { color: #204a87 }
|
|
||||||
/* NameBuiltinPseudo */ .chroma .bp { color: #3465a4 }
|
|
||||||
/* NameClass */ .chroma .nc { color: #000000 }
|
|
||||||
/* NameConstant */ .chroma .no { color: #000000 }
|
|
||||||
/* NameDecorator */ .chroma .nd { color: #5c35cc; font-weight: bold }
|
|
||||||
/* NameEntity */ .chroma .ni { color: #ce5c00 }
|
|
||||||
/* NameException */ .chroma .ne { color: #cc0000; font-weight: bold }
|
|
||||||
/* NameFunction */ .chroma .nf { color: #000000 }
|
|
||||||
/* NameFunctionMagic */ .chroma .fm { color: #000000 }
|
|
||||||
/* NameLabel */ .chroma .nl { color: #f57900 }
|
|
||||||
/* NameNamespace */ .chroma .nn { color: #000000 }
|
|
||||||
/* NameOther */ .chroma .nx { color: #000000 }
|
|
||||||
/* NameProperty */ .chroma .py { color: #000000 }
|
|
||||||
/* NameTag */ .chroma .nt { color: #204a87; font-weight: bold }
|
|
||||||
/* NameVariable */ .chroma .nv { color: #000000 }
|
|
||||||
/* NameVariableClass */ .chroma .vc { color: #000000 }
|
|
||||||
/* NameVariableGlobal */ .chroma .vg { color: #000000 }
|
|
||||||
/* NameVariableInstance */ .chroma .vi { color: #000000 }
|
|
||||||
/* NameVariableMagic */ .chroma .vm { color: #000000 }
|
|
||||||
/* Literal */ .chroma .l { color: #000000 }
|
|
||||||
/* LiteralDate */ .chroma .ld { color: #000000 }
|
|
||||||
/* LiteralString */ .chroma .s { color: #4e9a06 }
|
|
||||||
/* LiteralStringAffix */ .chroma .sa { color: #4e9a06 }
|
|
||||||
/* LiteralStringBacktick */ .chroma .sb { color: #4e9a06 }
|
|
||||||
/* LiteralStringChar */ .chroma .sc { color: #4e9a06 }
|
|
||||||
/* LiteralStringDelimiter */ .chroma .dl { color: #4e9a06 }
|
|
||||||
/* LiteralStringDoc */ .chroma .sd { color: #8f5902; font-style: italic }
|
|
||||||
/* LiteralStringDouble */ .chroma .s2 { color: #4e9a06 }
|
|
||||||
/* LiteralStringEscape */ .chroma .se { color: #4e9a06 }
|
|
||||||
/* LiteralStringHeredoc */ .chroma .sh { color: #4e9a06 }
|
|
||||||
/* LiteralStringInterpol */ .chroma .si { color: #4e9a06 }
|
|
||||||
/* LiteralStringOther */ .chroma .sx { color: #4e9a06 }
|
|
||||||
/* LiteralStringRegex */ .chroma .sr { color: #4e9a06 }
|
|
||||||
/* LiteralStringSingle */ .chroma .s1 { color: #4e9a06 }
|
|
||||||
/* LiteralStringSymbol */ .chroma .ss { color: #4e9a06 }
|
|
||||||
/* LiteralNumber */ .chroma .m { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberBin */ .chroma .mb { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberFloat */ .chroma .mf { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberHex */ .chroma .mh { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberInteger */ .chroma .mi { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberIntegerLong */ .chroma .il { color: #0000cf; font-weight: bold }
|
|
||||||
/* LiteralNumberOct */ .chroma .mo { color: #0000cf; font-weight: bold }
|
|
||||||
/* Operator */ .chroma .o { color: #ce5c00; font-weight: bold }
|
|
||||||
/* OperatorWord */ .chroma .ow { color: #204a87; font-weight: bold }
|
|
||||||
/* Punctuation */ .chroma .p { color: #000000; font-weight: bold }
|
|
||||||
/* Comment */ .chroma .c { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentHashbang */ .chroma .ch { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentMultiline */ .chroma .cm { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentSingle */ .chroma .c1 { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentSpecial */ .chroma .cs { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentPreproc */ .chroma .cp { color: #8f5902; font-style: italic }
|
|
||||||
/* CommentPreprocFile */ .chroma .cpf { color: #8f5902; font-style: italic }
|
|
||||||
/* Generic */ .chroma .g { color: #000000 }
|
|
||||||
/* GenericDeleted */ .chroma .gd { color: #a40000 }
|
|
||||||
/* GenericEmph */ .chroma .ge { color: #000000; font-style: italic }
|
|
||||||
/* GenericError */ .chroma .gr { color: #ef2929 }
|
|
||||||
/* GenericHeading */ .chroma .gh { color: #000080; font-weight: bold }
|
|
||||||
/* GenericInserted */ .chroma .gi { color: #00a000 }
|
|
||||||
/* GenericOutput */ .chroma .go { color: #000000; font-style: italic }
|
|
||||||
/* GenericPrompt */ .chroma .gp { color: #8f5902 }
|
|
||||||
/* GenericStrong */ .chroma .gs { color: #000000; font-weight: bold }
|
|
||||||
/* GenericSubheading */ .chroma .gu { color: #800080; font-weight: bold }
|
|
||||||
/* GenericTraceback */ .chroma .gt { color: #a40000; font-weight: bold }
|
|
||||||
/* GenericUnderline */ .chroma .gl { color: #000000; text-decoration: underline }
|
|
||||||
/* TextWhitespace */ .chroma .w { color: #f8f8f8; text-decoration: underline }
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
Abstract
|
|
||||||
========
|
|
||||||
|
|
||||||
This document outlines a proposed format for human-readable IDs within Matrix.
|
|
||||||
For status see https://github.com/matrix-org/matrix-doc/pull/3/files
|
|
||||||
|
|
||||||
Background
|
|
||||||
----------
|
|
||||||
UTF-8 is the dominant character encoding for Unicode on the web. However,
|
|
||||||
using Unicode as the character set for human-readable IDs is troublesome. There
|
|
||||||
are many different characters which appear identical to each other, but would
|
|
||||||
produce different IDs. In addition, there are non-printable characters which
|
|
||||||
cannot be rendered by the end-user. This creates an opportunity for
|
|
||||||
phishing/spoofing of IDs, commonly known as a homograph attack.
|
|
||||||
|
|
||||||
Web browsers encountered this problem when International Domain Names were
|
|
||||||
introduced. A variety of checks were put in place in order to protect users. If
|
|
||||||
an address failed the check, the raw punycode would be displayed to
|
|
||||||
disambiguate the address.
|
|
||||||
|
|
||||||
The human-readable IDs in Matrix are Room Aliases and User IDs.
|
|
||||||
Room aliases look like ``#localpart:domain``. These aliases point to opaque
|
|
||||||
non human-readable room IDs. These pointers can change to point at a different
|
|
||||||
room ID at any time. User IDs look like ``@localpart:domain``. These represent
|
|
||||||
actual end-users (there is no indirection).
|
|
||||||
|
|
||||||
Proposal
|
|
||||||
========
|
|
||||||
|
|
||||||
User IDs and Room Aliases MUST be Unicode as UTF-8. Checks are performed on
|
|
||||||
these IDs by homeservers to protect users from phishing/spoofing attacks.
|
|
||||||
These checks are:
|
|
||||||
|
|
||||||
User ID Localparts:
|
|
||||||
- MUST NOT contain a ``:`` or start with a ``@`` or ``.``
|
|
||||||
- MUST NOT contain one of the 107 blacklisted characters on this list:
|
|
||||||
http://kb.mozillazine.org/Network.IDN.blacklist_chars
|
|
||||||
- After stripping " 0-9, +, -, [, ], _, and the space character it MUST NOT
|
|
||||||
contain characters from >1 language, defined by the `exemplar characters`_
|
|
||||||
on http://cldr.unicode.org/
|
|
||||||
|
|
||||||
.. _exemplar characters: http://cldr.unicode.org/translation/characters#TOC-Exemplar-Characters
|
|
||||||
|
|
||||||
Room Alias Localparts:
|
|
||||||
- MUST NOT contain a ``:``
|
|
||||||
- MUST NOT contain one of the 107 blacklisted characters on this list:
|
|
||||||
http://kb.mozillazine.org/Network.IDN.blacklist_chars
|
|
||||||
- After stripping " 0-9, +, -, [, ], _, and the space character it MUST NOT
|
|
||||||
contain characters from >1 language, defined by the `exemplar characters`_
|
|
||||||
on http://cldr.unicode.org/
|
|
||||||
|
|
||||||
.. _exemplar characters: http://cldr.unicode.org/translation/characters#TOC-Exemplar-Characters
|
|
||||||
|
|
||||||
In the event of a failed user ID check, well behaved homeservers MUST:
|
|
||||||
- Rewrite user IDs in the offending events to be punycode with an additional ``@``
|
|
||||||
prefix **before** delivering them to clients. There are no guarantees for
|
|
||||||
consistency between homeserver ID checking implementations. As a result, user
|
|
||||||
IDs MUST be sent in their *original* form over federation. This can be done in
|
|
||||||
a stateless manner as the punycode form has no information loss.
|
|
||||||
|
|
||||||
In the event of a failed room alias check, well behaved homeservers MUST:
|
|
||||||
- Send an HTTP status code 400 with an ``errcode`` of ``M_FAILED_HUMAN_ID_CHECK``
|
|
||||||
to the client if the client is attempting to *create* this alias.
|
|
||||||
- Send an HTTP status code 400 with an ``errcode`` of ``M_FAILED_HUMAN_ID_CHECK``
|
|
||||||
to the client if the client is attempting to *join* a room via this alias.
|
|
||||||
|
|
||||||
Examples::
|
|
||||||
|
|
||||||
@ebаy:example.org (Cyrillic 'a', everything else English)
|
|
||||||
@@xn--eby-7cd:example.org (Punycode with additional '@')
|
|
||||||
|
|
||||||
Homeservers SHOULD NOT allow two user IDs that differ only by case. This
|
|
||||||
SHOULD be applied based on the capitalisation rules in the CLDR dataset:
|
|
||||||
http://cldr.unicode.org/
|
|
||||||
|
|
||||||
This check SHOULD be applied when the user ID is created, in order to prevent
|
|
||||||
registration with the same name and different capitalisations, e.g.
|
|
||||||
``@foo:bar`` vs ``@Foo:bar`` vs ``@FOO:bar``. Homeservers MAY canonicalise
|
|
||||||
the user ID to be completely lower-case if desired.
|
|
||||||
|
|
||||||
Rationale
|
|
||||||
=========
|
|
||||||
|
|
||||||
Each ID is split into segments (localpart/domain) around the ``:``. For
|
|
||||||
this reason, ``:`` is a reserved character and cannot be a localpart character.
|
|
||||||
The 107 blacklisted characters are used to prevent non-printable characters and
|
|
||||||
spaces from being used. The decision to ban characters from more than 1 language
|
|
||||||
matches the behaviour of `Google Chrome for IDN handling`_. This is to protect
|
|
||||||
against common homograph attacks such as ebаy.com (Cyrillic "a", rest is
|
|
||||||
English). This would always result in a failed check. Even with this though
|
|
||||||
there are limitations. For example, сахар is entirely Cyrillic, whereas caxap is
|
|
||||||
entirely Latin.
|
|
||||||
|
|
||||||
.. _Google Chrome for IDN handling: https://www.chromium.org/developers/design-documents/idn-in-google-chrome
|
|
||||||
|
|
||||||
User ID localparts cannot start with ``@`` so that a namespace of localparts
|
|
||||||
beginning with ``@`` can be created. This namespace is used for user IDs which
|
|
||||||
fail the ID checks. A failed ID could look like ``@@xn--c1yn36f:example.org``.
|
|
||||||
|
|
||||||
If a user ID fails the check, the user ID on the event is renamed. This doesn't
|
|
||||||
require extra work for clients, and users will see an odd user ID rather than a
|
|
||||||
spoofed name. Renaming is done in order to protect users of a given HS, so if a
|
|
||||||
malicious HS doesn't rename their IDs, it doesn't affect any other HS.
|
|
||||||
|
|
||||||
Room aliases cannot be rewritten as punycode and sent to the HS the alias is
|
|
||||||
referring to as the HS will not necessarily understand the rewritten alias.
|
|
||||||
|
|
||||||
Other rejected solutions for failed checks
|
|
||||||
------------------------------------------
|
|
||||||
- Additional key: Informational key on the event attached by HS to say "unsafe
|
|
||||||
ID". Problem: clients can just ignore it, and since it will appear only very
|
|
||||||
rarely, easy to forget when implementing clients.
|
|
||||||
- Require client handshake: Forces clients to implement
|
|
||||||
a check, else they cannot communicate with the misleading ID. However, this
|
|
||||||
is extra overhead in both client implementations and round-trips.
|
|
||||||
- Reject event: Outright rejection of the ID at the point of creation /
|
|
||||||
receiving event. Point of creation rejection is preferable to avoid the ID
|
|
||||||
entering the system in the first place. However, malicious HSes can just
|
|
||||||
allow the ID. Hence, other homeservers must reject them if they see them in
|
|
||||||
events. Client never sees the problem ID, provided the HS is correctly
|
|
||||||
implemented. However, it is difficult to ensure that ALL HSes will come to the
|
|
||||||
same conclusion (given the CLDR dataset does come out with new versions).
|
|
||||||
|
|
||||||
Outstanding Problems
|
|
||||||
====================
|
|
||||||
|
|
||||||
Capitalisation
|
|
||||||
--------------
|
|
||||||
|
|
||||||
The capitalisation rules outlined above are nice but do not fully resolve issues
|
|
||||||
where ``@alice:example.com`` tries to speak with ``@bob:example.org`` using
|
|
||||||
``@Bob:example.org``. It is up to ``example.org`` to map ``Bob`` to ``bob`` in
|
|
||||||
a sensible way.
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
(a stream of incoherent consciousness from matthew which should go somewhere)
|
|
||||||
|
|
||||||
Invite-graph based reputation data:
|
|
||||||
|
|
||||||
* Users need a reputation score to issue invites or join public rooms.
|
|
||||||
* A user can have many reputation scores in different audiences (and perhaps a global average?)
|
|
||||||
* A room (degenerate case: user) can align itself with a given audience in order to consume the reputation data for that audience.
|
|
||||||
* The people that a user invites inherits a proportion of their reputation.
|
|
||||||
* If your reputation in an audience is ever reduced, it similarly reduces the reputation you have ever conveyed to anyone else (which propagates through the invite graph).
|
|
||||||
* Users increase reputation by:
|
|
||||||
* Inviting someone.
|
|
||||||
* Upvoting their messages in a room (i.e. for the suitability of that audience)
|
|
||||||
* Users decrease reputation by:
|
|
||||||
* Blocking them.
|
|
||||||
* Downvoting their messages in a room (i.e. for the suitability of that audience)
|
|
||||||
|
|
||||||
Need to ensure the accounts are of a decent quality - making it harder to create sockpuppet accounts and associating them with real people is more important than the actual reputation problem.
|
|
||||||
|
|
||||||
Build a war game simulation to test?
|
|
||||||
|
|
||||||
|
|
||||||
Problems:
|
|
||||||
* How are audiences defined? Just a given unique set of users? Which then makes inheriting reputation easy between audiences - if the overlap is significant, the chances are the reputation rules are the same.
|
|
||||||
* But is it possible to have the same set of users in two different rooms have different rules for reputation? Probably yes, as the potential audience may include future invitees or indeed the general public, so history visibility rules should probably also contribute to this. But given privacy rules can change over time, each room should effectively define its own audience. So in the end, an audience === a room.
|
|
||||||
* Create a large network of fake users, and go and have them all vote up each other's score for a given audience.
|
|
||||||
* This can be solved if the root inviter is penalised, which then destroys all the reputation they conveyed to their graph.
|
|
||||||
|
|
||||||
Could Reputation == Power Level (!?!?!)
|
|
||||||
|
|
||||||
Inheritence semantics for reputation between different audiences is hard.
|
|
||||||
* You should base the reputation of a stranger on their reputation in other communities that you or your communities have some overlap with.
|
|
||||||
* Do you consider 2nd hand reputation data at all from private rooms? Or do you look only at the public reputation data?
|
|
||||||
|
|
||||||
How do you do these calculations in a byzantine world?
|
|
||||||
|
|
||||||
How do you do these calculations whilst preserving privacy?
|
|
||||||
* Only consider reputation data from rooms you are actually in?
|
|
||||||
* Store reputation data in room state?
|
|
||||||
* Have a function (HS? client? AS? spider?) that aggregates reputation data (and proves that the aggregation is accurate, almost like blockchain mining?)?
|
|
||||||
* Or have a separate reputation global db seperate from room state that people contribute metrics into (which gathers the aggregate data into a single place, and makes it easier to query reputation data for strangers)
|
|
||||||
|
|
||||||
How do you avoid backstabbing? (People maliciously ganging up on someone to downvote them)?
|
|
||||||
|
|
||||||
How do you avoid a voting war? (Community fragments; different factions turn up and try to downvote the other)?
|
|
||||||
* This is effectively two different audiences emerging in a single room.
|
|
||||||
* Perhaps this means we should model audiences separately from rooms.
|
|
||||||
* Perhaps audiences are literally ACL groups? And eventually, one might change the ACLs of a room to eject one of the groups?
|
|
||||||
* Or do you just synthesise audiences based on cliques of people who support each other? The act of upvoting someone is effectively aligning yourself as being part of the same audience?
|
|
||||||
|
|
||||||
|
|
||||||
So:
|
|
||||||
* Gather all public upvote/downvotes/invites/blocks in a global DB.
|
|
||||||
* Partition this into audiences based on who votes on who. Stuff which is read and not complained about could provide a small implicit approval? Although this makes it easy to flood content to boost your reputation, so bad idea.
|
|
||||||
* Partitioning algorithm could be quite subtle.
|
|
||||||
* You could end up with lots of small audiences (including invalid ones), and it's fairly unclear how they get aggregated into a single view. How should you treat a stranger who you have no audience-overlap with at all? Treat them as effectively having zero reputation from your perspective?
|
|
||||||
|
|
||||||
Problem:
|
|
||||||
* If the douchebag who invites spammers never says anything, how do you go vote on their reputation? Should there be some kind of back-propagation? Or is there explicitly a "this person invited a douchebag" downvote? Or hang on - how can they ever get reputation in the first place to invite their sockpuppets if they don't say anything (beyond the initial invite)?
|
|
||||||
* What if users simply don't talk in public? Is it right that we prevent them issuing invites just because they stick to private rooms? What about inviting people into those private rooms? I guess the point is that if these are public invites, then they need to have some kind of public reputation, or rely on out-of-band private invitation to establish trust?
|
|
||||||
* Are we rewarding people who don't change their habits? There's no time component considered here, and we punish people's entire history of invites and rep if they misbehave. The only way to escape is to create a new identity atm. Is this a feature or a bug?
|
|
||||||
* How does this handle people's accounts getting 0wn3d and doing things which wipe out their reputation? => This is always a risk; ignore it.
|
|
||||||
* Do you need a particular level of reputation to be able to vote on people?
|
|
||||||
|
|
||||||
Summary?
|
|
||||||
* Partition the global population into multiple overlapping clusters called 'audiences' based on mutual(?) upvote/downvote relationships in public rooms.
|
|
||||||
* Clusters of the same people but in different rooms could be modelled as separate (but overlapping) clusters.
|
|
||||||
* Each audience builds up a reputation score for the global population, blending in damped scores from overlapping audiences.
|
|
||||||
* Anyone can upvote/downvote, but the votes will not contribute to your personal opinion unless the voter overlaps with your audience's scoresheet.
|
|
||||||
* A room could adopt a given audience (that of the moderators'?) for considering the reputation of who can join, invite people, etc.
|
|
||||||
* A user uses their own 'audience of one' scoresheet to put a threshold on filtering out contact from other users (invites, messages, etc).
|
|
||||||
* Their personal scoresheet is presumably a blend of all the audiences they are already in.
|
|
||||||
* The act of inviting someone gives them some reputation, within your audiences, proportional to your own. Similarly blocking reduces reputation.
|
|
||||||
* If you are downvoted, it retrospectively reduces the weight of all of your upvote/downvotes (at least for audiences that the downvoter's opinion contributes to). Similarly for upvoting.
|
|
||||||
* This penalisation process is transitive.
|
|
||||||
|
|
||||||
Do we even need the penalisation stuff if audience partitioning works?
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
URL Previews
|
|
||||||
============
|
|
||||||
|
|
||||||
Design notes on a URL previewing service for Matrix:
|
|
||||||
|
|
||||||
Options are:
|
|
||||||
|
|
||||||
1. Have an AS which listens for URLs, downloads them, and inserts an event that describes their metadata.
|
|
||||||
* Pros:
|
|
||||||
* Decouples the implementation entirely from Synapse.
|
|
||||||
* Uses existing Matrix events & content repo to store the metadata.
|
|
||||||
* Cons:
|
|
||||||
* Which AS should provide this service for a room, and why should you trust it?
|
|
||||||
* Doesn't work well with E2E; you'd have to cut the AS into every room
|
|
||||||
* the AS would end up subscribing to every room anyway.
|
|
||||||
|
|
||||||
2. Have a generic preview API (nothing to do with Matrix) that provides a previewing service:
|
|
||||||
* Pros:
|
|
||||||
* Simple and flexible; can be used by any clients at any point
|
|
||||||
* Cons:
|
|
||||||
* If each HS provides one of these independently, all the HSes in a room may needlessly DoS the target URI
|
|
||||||
* We need somewhere to store the URL metadata rather than just using Matrix itself
|
|
||||||
* We can't piggyback on matrix to distribute the metadata between HSes.
|
|
||||||
|
|
||||||
3. Make the synapse of the sending user responsible for spidering the URL and inserting an event asynchronously which describes the metadata.
|
|
||||||
* Pros:
|
|
||||||
* Works transparently for all clients
|
|
||||||
* Piggy-backs nicely on using Matrix for distributing the metadata.
|
|
||||||
* No confusion as to which AS
|
|
||||||
* Cons:
|
|
||||||
* Doesn't work with E2E
|
|
||||||
* We might want to decouple the implementation of the spider from the HS, given spider behaviour can be quite complicated and evolve much more rapidly than the HS. It's more like a bot than a core part of the server.
|
|
||||||
|
|
||||||
4. Make the sending client use the preview API and insert the event itself when successful.
|
|
||||||
* Pros:
|
|
||||||
* Works well with E2E
|
|
||||||
* No custom server functionality
|
|
||||||
* Lets the client customise the preview that they send (like on FB)
|
|
||||||
* Cons:
|
|
||||||
* Entirely specific to the sending client, whereas it'd be nice if /any/ URL was correctly previewed if clients support it.
|
|
||||||
|
|
||||||
5. Have the option of specifying a shared (centralised) previewing service used by a room, to avoid all the different HSes in the room DoSing the target.
|
|
||||||
|
|
||||||
Best solution is probably a combination of both 2 and 4.
|
|
||||||
* Sending clients do their best to create and send a preview at the point of sending the message, perhaps delaying the message until the preview is computed? (This also lets the user validate the preview before sending)
|
|
||||||
* Receiving clients have the option of going and creating their own preview if one doesn't arrive soon enough (or if the original sender didn't create one)
|
|
||||||
|
|
||||||
This is a bit magical though in that the preview could come from two entirely different sources - the sending HS or your local one. However, this can always be exposed to users: "Generate your own URL previews if none are available?"
|
|
||||||
|
|
||||||
This is tantamount also to senders calculating their own thumbnails for sending in advance of the main content - we are trusting the sender not to lie about the content in the thumbnail. Whereas currently thumbnails are calculated by the receiving homeserver to avoid this attack.
|
|
||||||
|
|
||||||
However, this kind of phishing attack does exist whether we let senders pick their thumbnails or not, in that a malicious sender can send normal text messages around the attachment claiming it to be legitimate. We could rely on (future) reputation/abuse management to punish users who phish (be it with bogus metadata or bogus descriptions). Bogus metadata is particularly bad though, especially if it's avoidable.
|
|
||||||
|
|
||||||
As a first cut, let's do #2 and have the receiver hit the API to calculate its own previews (as it does currently for image thumbnails). We can then extend/optimise this to option 4 as a special extra if needed.
|
|
||||||
|
|
||||||
API
|
|
||||||
---
|
|
||||||
|
|
||||||
```
|
|
||||||
GET /_matrix/media/r0/preview_url?url=http://wherever.com
|
|
||||||
200 OK
|
|
||||||
{
|
|
||||||
"og:type" : "article"
|
|
||||||
"og:url" : "https://twitter.com/matrixdotorg/status/684074366691356672"
|
|
||||||
"og:title" : "Matrix on Twitter"
|
|
||||||
"og:image" : "https://pbs.twimg.com/profile_images/500400952029888512/yI0qtFi7_400x400.png"
|
|
||||||
"og:description" : "“Synapse 0.12 is out! Lots of polishing, performance &amp; bugfixes: /sync API, /r0 prefix, fulltext search, 3PID invites https://t.co/5alhXLLEGP”"
|
|
||||||
"og:site_name" : "Twitter"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* Downloads the URL
|
|
||||||
* If HTML, just stores it in RAM and parses it for OG meta tags
|
|
||||||
* Download any media OG meta tags to the media repo, and refer to them in the OG via mxc:// URIs.
|
|
||||||
* If a media filetype we know we can thumbnail: store it on disk, and hand it to the thumbnailer. Generate OG meta tags from the thumbnailer contents.
|
|
||||||
* Otherwise, don't bother downloading further.
|
|
||||||
|
|
@ -1,288 +0,0 @@
|
||||||
WebSockets API
|
|
||||||
==============
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
This document is a proposal for a WebSockets-based client-server API. It is not
|
|
||||||
intended to replace the REST API, but rather to complement it and provide an
|
|
||||||
alternative interface for certain operations.
|
|
||||||
|
|
||||||
The primary goal is to offer a more efficient interface than the REST API: by
|
|
||||||
using a bidirectional protocol such as WebSockets we can avoid the overheads
|
|
||||||
involved in long-polling (SSL negotiation, HTTP headers, etc). In doing so we
|
|
||||||
will reduce the latency between server and client by allowing the server to
|
|
||||||
send events as soon as they arrive, rather than having to wait for a poll from
|
|
||||||
the client.
|
|
||||||
|
|
||||||
Note: This proposal got continued in a google document you can find here:
|
|
||||||
https://docs.google.com/document/d/104ClehFBgqLQbf4s-AKX2ijr8sOAxcizfcRs_atsB0g
|
|
||||||
|
|
||||||
Handshake
|
|
||||||
---------
|
|
||||||
1. Instead of calling ``/sync``, the client makes a websocket request to
|
|
||||||
``/_matrix/client/rN/stream``, passing the query parameters ``access_token``
|
|
||||||
and ``since``, and optionally ``filter`` - all of which have the same
|
|
||||||
meaning as for ``/sync``.
|
|
||||||
|
|
||||||
* The client sets the ``Sec-WebSocket-Protocol`` to ``m.json``. (Servers may
|
|
||||||
offer alternative encodings; at present only the JSON encoding is
|
|
||||||
specified but in future we will specify alternative encodings.)
|
|
||||||
|
|
||||||
#. The server returns the websocket handshake; the socket is then connected.
|
|
||||||
|
|
||||||
If the server does not return a valid websocket handshake, this indicates that
|
|
||||||
the server or an intermediate proxy does not support WebSockets. In this case,
|
|
||||||
the client should fall back to polling the ``/sync`` REST endpoint.
|
|
||||||
|
|
||||||
Example
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
Client request:
|
|
||||||
|
|
||||||
.. code:: http
|
|
||||||
|
|
||||||
GET /_matrix/client/v2_alpha/stream?access_token=123456&since=s72594_4483_1934 HTTP/1.1
|
|
||||||
Host: matrix.org
|
|
||||||
Upgrade: websocket
|
|
||||||
Connection: Upgrade
|
|
||||||
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
|
|
||||||
Sec-WebSocket-Protocol: m.json
|
|
||||||
Sec-WebSocket-Version: 13
|
|
||||||
Origin: https://matrix.org
|
|
||||||
|
|
||||||
Server response:
|
|
||||||
|
|
||||||
.. code:: http
|
|
||||||
|
|
||||||
HTTP/1.1 101 Switching Protocols
|
|
||||||
Upgrade: websocket
|
|
||||||
Connection: Upgrade
|
|
||||||
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
|
|
||||||
Sec-WebSocket-Protocol: m.json
|
|
||||||
|
|
||||||
|
|
||||||
Update Notifications
|
|
||||||
--------------------
|
|
||||||
Once the socket is connected, the server begins streaming updates over the
|
|
||||||
websocket. The server sends Update notifications about new messages or state
|
|
||||||
changes. To make it easy for clients to parse, Update notifications have the
|
|
||||||
same structure as the response to ``/sync``: an object with the following
|
|
||||||
members:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Key Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
next_batch string The batch token to supply in the ``since`` param of
|
|
||||||
the next /sync request. This is not required for
|
|
||||||
streaming of events over the WebSocket, but is
|
|
||||||
provided so that clients can reconnect if the
|
|
||||||
socket is disconnected.
|
|
||||||
presence Presence The updates to the presence status of other users.
|
|
||||||
rooms Rooms Updates to rooms.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
Example
|
|
||||||
~~~~~~~
|
|
||||||
Message from the server:
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
{
|
|
||||||
"next_batch": "s72595_4483_1934",
|
|
||||||
"presence": {
|
|
||||||
"events": []
|
|
||||||
},
|
|
||||||
"rooms": {
|
|
||||||
"join": {},
|
|
||||||
"invite": {},
|
|
||||||
"leave": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Client-initiated operations
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
The client can perform certain operations by sending a websocket message to
|
|
||||||
the server. Such a "Request" message should be a JSON-encoded object with
|
|
||||||
the following members:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Key Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
id string A unique identifier for this request
|
|
||||||
method string Specifies the name of the operation to be
|
|
||||||
performed; see below for available operations
|
|
||||||
param object The parameters for the requested operation.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
The server responds to a client Request with a Response message. This is a
|
|
||||||
JSON-encoded object with the following members:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Key Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
id string The same as the value in the corresponding Request
|
|
||||||
object. The presence of the ``id`` field
|
|
||||||
distinguishes a Response message from an Update
|
|
||||||
notification.
|
|
||||||
result object On success, the results of the request.
|
|
||||||
error object On error, an object giving the resons for the
|
|
||||||
error. This has the same structure as the "standard
|
|
||||||
error response" for the Matrix API: an object with
|
|
||||||
the fields ``errcode`` and ``error``.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
Request methods
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
It is not intended that all operations which are available via the REST API
|
|
||||||
will be available via the WebSockets API, but a few simple, common operations
|
|
||||||
will be exposed. The initial operations will be as follows.
|
|
||||||
|
|
||||||
``ping``
|
|
||||||
^^^^^^^^
|
|
||||||
This is a no-op which clients may use to keep their connection alive.
|
|
||||||
|
|
||||||
The request ``params`` and the response ``result`` should be empty.
|
|
||||||
|
|
||||||
``send``
|
|
||||||
^^^^^^^^
|
|
||||||
Send a message event to a room. The parameters are as follows:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Parameter Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
room_id string **Required.** The room to send the event to
|
|
||||||
event_type string **Required.** The type of event to send.
|
|
||||||
content object **Required.** The content of the event.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
The result is as follows:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Key Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
event_id string A unique identifier for the event.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
The ``id`` from the Request message is used as the transaction ID by the
|
|
||||||
server.
|
|
||||||
|
|
||||||
``state``
|
|
||||||
^^^^^^^^^
|
|
||||||
Update the state on a room.
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Parameter Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
room_id string **Required.** The room to set the state in
|
|
||||||
event_type string **Required.** The type of event to send.
|
|
||||||
state_key string **Required.** The state_key for the state to send.
|
|
||||||
content object **Required.** The content of the event.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
The result is as follows:
|
|
||||||
|
|
||||||
============= ========== ===================================================
|
|
||||||
Key Type Description
|
|
||||||
============= ========== ===================================================
|
|
||||||
event_id string A unique identifier for the event.
|
|
||||||
============= ========== ===================================================
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
|
||||||
~~~~~~~
|
|
||||||
Client request:
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": "12345",
|
|
||||||
"method": "send",
|
|
||||||
"params": {
|
|
||||||
"room_id": "!d41d8cd:matrix.org",
|
|
||||||
"event_type": "m.room.message",
|
|
||||||
"content": {
|
|
||||||
"msgtype": "m.text",
|
|
||||||
"body": "hello"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Server response:
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": "12345",
|
|
||||||
"result": {
|
|
||||||
"event_id": "$66697273743031:matrix.org"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Alternative server response, in case of error:
|
|
||||||
|
|
||||||
.. code:: json
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": "12345",
|
|
||||||
"error": {
|
|
||||||
"errcode": "M_MISSING_PARAM",
|
|
||||||
"error": "Missing parameter: event_type"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
|
||||||
---------
|
|
||||||
Alternatives to WebSockets include HTTP/2, CoAP, and simply rolling our own
|
|
||||||
protocol over raw TCP sockets. However, the need to implement browser-based
|
|
||||||
clients essentially reduces our choice to WebSockets. HTTP/2 streams will
|
|
||||||
probably provide an interesting alternative in the future, but current browsers
|
|
||||||
do not appear to give javascript applications low-level access to the protocol.
|
|
||||||
|
|
||||||
Concerning the continued use of the JSON encoding: we prefer to focus on the
|
|
||||||
transition to WebSockets initially. Replacing JSON with a compact
|
|
||||||
representation such as CBOR, MessagePack, or even just compressed JSON will be
|
|
||||||
a likely extension for the future. The support for negotiation of subprotocols
|
|
||||||
within WebSockets should make this a simple transition once time permits.
|
|
||||||
|
|
||||||
The number of methods available for client requests is deliberately limited, as
|
|
||||||
each method requires code to be written to map it onto the equivalent REST
|
|
||||||
implementation. Some REST methods - for instance, user registration and login -
|
|
||||||
would be pointless to expose via WebSockets. It is likely, however, that we
|
|
||||||
will increate the number of methods available via the WebSockets API as it
|
|
||||||
becomes clear which would be most useful.
|
|
||||||
|
|
||||||
Open questions
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Throttling
|
|
||||||
~~~~~~~~~~
|
|
||||||
At least in v2 sync, clients are inherently self-throttling - if they do not
|
|
||||||
poll quickly enough, events will be dropped from the next result. This proposal
|
|
||||||
raises the possibility that events will be produced more quickly than they can
|
|
||||||
be sent to the client; backlogs will build up on the server and/or in the
|
|
||||||
intermediate network, which will not only lead to high latency on events being
|
|
||||||
delivered, but will lead to responses to client requests also being delayed.
|
|
||||||
|
|
||||||
We may need to implement some sort of throttling mechanism by which the server
|
|
||||||
can start to drop events. The difficulty is in knowing when to start dropping
|
|
||||||
events. A few ideas:
|
|
||||||
|
|
||||||
* Use websocket pings to measure the RTT; if it starts to increase, start
|
|
||||||
dropping events. But this requires knowledge of the base RTT, and a useful
|
|
||||||
model of what constitutes an excessive increase.
|
|
||||||
|
|
||||||
* Have the client acknowledge each batch of events, and use a window to ensure
|
|
||||||
the number of outstanding batches is limited. This is annoying as it requires
|
|
||||||
the client to have to acknowledge batches - and it's not clear what the right
|
|
||||||
window size is: we want a big window for long fat networks (think of mobile
|
|
||||||
clients), but a small one for one with lower latency.
|
|
||||||
|
|
||||||
* Start dropping events if the server's TCP buffer starts filling up. This has
|
|
||||||
the advantage of delegating the congestion-detection to TCP (which already
|
|
||||||
has a number of algorithms to deal with it, to greater or lesser
|
|
||||||
effectiveness), but relies on homeservers being hosted on OSes which use
|
|
||||||
sensible TCP congestion-avoidance algorithms, and more critically, an ability
|
|
||||||
to read the fill level of the TCP send buffer.
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
Registration and Login
|
Registration and Login
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Clients must register with a homeserver in order to use Matrix. After
|
Clients must register with a home server in order to use Matrix. After
|
||||||
registering, the client will be given an access token which must be used in ALL
|
registering, the client will be given an access token which must be used in ALL
|
||||||
requests to that homeserver as a query parameter 'access_token'.
|
requests to that home server as a query parameter 'access_token'.
|
||||||
|
|
||||||
If the client has already registered, they need to be able to login to their
|
If the client has already registered, they need to be able to login to their
|
||||||
account. The homeserver may provide many different ways of logging in, such as
|
account. The home server may provide many different ways of logging in, such as
|
||||||
user/password auth, login via a social network (OAuth2), login by confirming a
|
user/password auth, login via a social network (OAuth2), login by confirming a
|
||||||
token sent to their email address, etc. This specification does not define how
|
token sent to their email address, etc. This specification does not define how
|
||||||
homeservers should authorise their users who want to login to their existing
|
home servers should authorise their users who want to login to their existing
|
||||||
accounts, but instead defines the standard interface which implementations
|
accounts, but instead defines the standard interface which implementations
|
||||||
should follow so that ANY client can login to ANY homeserver. Clients login
|
should follow so that ANY client can login to ANY home server. Clients login
|
||||||
using the |login|_ API. Clients register using the |register|_ API.
|
using the |login|_ API. Clients register using the |register|_ API.
|
||||||
Registration follows the same general procedure as login, but the path requests
|
Registration follows the same general procedure as login, but the path requests
|
||||||
are sent to and the details contained in them are different.
|
are sent to and the details contained in them are different.
|
||||||
|
|
@ -26,7 +26,7 @@ In order to determine up-front what the server's requirements are, the client
|
||||||
can request from the server a complete description of all of its acceptable
|
can request from the server a complete description of all of its acceptable
|
||||||
flows of the registration or login process. It can then inspect the list of
|
flows of the registration or login process. It can then inspect the list of
|
||||||
returned flows looking for one for which it believes it can complete all of the
|
returned flows looking for one for which it believes it can complete all of the
|
||||||
required stages, and perform it. As each homeserver may have different ways of
|
required stages, and perform it. As each home server may have different ways of
|
||||||
logging in, the client needs to know how they should login. All distinct login
|
logging in, the client needs to know how they should login. All distinct login
|
||||||
stages MUST have a corresponding ``type``. A ``type`` is a namespaced string
|
stages MUST have a corresponding ``type``. A ``type`` is a namespaced string
|
||||||
which details the mechanism for logging in.
|
which details the mechanism for logging in.
|
||||||
|
|
@ -64,12 +64,12 @@ ID and a new access token MUST be returned::
|
||||||
"access_token": "abcdef0123456789"
|
"access_token": "abcdef0123456789"
|
||||||
}
|
}
|
||||||
|
|
||||||
The ``user_id`` key is particularly useful if the homeserver wishes to support
|
The ``user_id`` key is particularly useful if the home server wishes to support
|
||||||
localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as
|
localpart entry of usernames (e.g. "user" rather than "@user:matrix.org"), as
|
||||||
the client may not be able to determine its ``user_id`` in this case.
|
the client may not be able to determine its ``user_id`` in this case.
|
||||||
|
|
||||||
If the flow has multiple stages to it, the homeserver may wish to create a
|
If the flow has multiple stages to it, the home server may wish to create a
|
||||||
session to store context between requests. If a homeserver responds with a
|
session to store context between requests. If a home server responds with a
|
||||||
``session`` key to a request, clients MUST submit it in subsequent requests
|
``session`` key to a request, clients MUST submit it in subsequent requests
|
||||||
until the flow is completed::
|
until the flow is completed::
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ To respond to this type, reply with::
|
||||||
"password": "<password>"
|
"password": "<password>"
|
||||||
}
|
}
|
||||||
|
|
||||||
The homeserver MUST respond with either new credentials, the next stage of the
|
The home server MUST respond with either new credentials, the next stage of the
|
||||||
login process, or a standard error response.
|
login process, or a standard error response.
|
||||||
|
|
||||||
Captcha-based
|
Captcha-based
|
||||||
|
|
@ -123,7 +123,7 @@ To respond to this type, reply with::
|
||||||
Recaptcha.get_challenge();
|
Recaptcha.get_challenge();
|
||||||
Recaptcha.get_response();
|
Recaptcha.get_response();
|
||||||
|
|
||||||
The homeserver MUST respond with either new credentials, the next stage of the
|
The home server MUST respond with either new credentials, the next stage of the
|
||||||
login process, or a standard error response.
|
login process, or a standard error response.
|
||||||
|
|
||||||
OAuth2-based
|
OAuth2-based
|
||||||
|
|
@ -146,24 +146,24 @@ The server MUST respond with::
|
||||||
"uri": <Authorization Request URI OR service selection URI>
|
"uri": <Authorization Request URI OR service selection URI>
|
||||||
}
|
}
|
||||||
|
|
||||||
The homeserver acts as a 'confidential' client for the purposes of OAuth2. If
|
The home server acts as a 'confidential' client for the purposes of OAuth2. If
|
||||||
the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts
|
the uri is a ``sevice selection URI``, it MUST point to a webpage which prompts
|
||||||
the user to choose which service to authorize with. On selection of a service,
|
the user to choose which service to authorize with. On selection of a service,
|
||||||
this MUST link through to an ``Authorization Request URI``. If there is only 1
|
this MUST link through to an ``Authorization Request URI``. If there is only 1
|
||||||
service which the homeserver accepts when logging in, this indirection can be
|
service which the home server accepts when logging in, this indirection can be
|
||||||
skipped and the "uri" key can be the ``Authorization Request URI``.
|
skipped and the "uri" key can be the ``Authorization Request URI``.
|
||||||
|
|
||||||
The client then visits the ``Authorization Request URI``, which then shows the
|
The client then visits the ``Authorization Request URI``, which then shows the
|
||||||
OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the
|
OAuth2 Allow/Deny prompt. Hitting 'Allow' returns the ``redirect URI`` with the
|
||||||
auth code. Homeservers can choose any path for the ``redirect URI``. The
|
auth code. Home servers can choose any path for the ``redirect URI``. The
|
||||||
client should visit the ``redirect URI``, which will then finish the OAuth2
|
client should visit the ``redirect URI``, which will then finish the OAuth2
|
||||||
login process, granting the homeserver an access token for the chosen service.
|
login process, granting the home server an access token for the chosen service.
|
||||||
When the homeserver gets this access token, it verifies that the cilent has
|
When the home server gets this access token, it verifies that the cilent has
|
||||||
authorised with the 3rd party, and can now complete the login. The OAuth2
|
authorised with the 3rd party, and can now complete the login. The OAuth2
|
||||||
``redirect URI`` (with auth code) MUST respond with either new credentials, the
|
``redirect URI`` (with auth code) MUST respond with either new credentials, the
|
||||||
next stage of the login process, or a standard error response.
|
next stage of the login process, or a standard error response.
|
||||||
|
|
||||||
For example, if a homeserver accepts OAuth2 from Google, it would return the
|
For example, if a home server accepts OAuth2 from Google, it would return the
|
||||||
Authorization Request URI for Google::
|
Authorization Request URI for Google::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -171,7 +171,7 @@ Authorization Request URI for Google::
|
||||||
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos"
|
client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos"
|
||||||
}
|
}
|
||||||
|
|
||||||
The client then visits this URI and authorizes the homeserver. The client then
|
The client then visits this URI and authorizes the home server. The client then
|
||||||
visits the REDIRECT_URI with the auth code= query parameter which returns::
|
visits the REDIRECT_URI with the auth code= query parameter which returns::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -195,7 +195,7 @@ To respond to this type, reply with::
|
||||||
"email": "<email address>"
|
"email": "<email address>"
|
||||||
}
|
}
|
||||||
|
|
||||||
After validating the email address, the homeserver MUST send an email
|
After validating the email address, the home server MUST send an email
|
||||||
containing an authentication code and return::
|
containing an authentication code and return::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -212,7 +212,7 @@ code::
|
||||||
"code": "<code in email sent>"
|
"code": "<code in email sent>"
|
||||||
}
|
}
|
||||||
|
|
||||||
The homeserver MUST respond to this with either new credentials, the next
|
The home server MUST respond to this with either new credentials, the next
|
||||||
stage of the login process, or a standard error response.
|
stage of the login process, or a standard error response.
|
||||||
|
|
||||||
Email-based (url)
|
Email-based (url)
|
||||||
|
|
@ -231,7 +231,7 @@ To respond to this type, reply with::
|
||||||
"email": "<email address>"
|
"email": "<email address>"
|
||||||
}
|
}
|
||||||
|
|
||||||
After validating the email address, the homeserver MUST send an email
|
After validating the email address, the home server MUST send an email
|
||||||
containing an authentication URL and return::
|
containing an authentication URL and return::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -247,7 +247,7 @@ client should perform another request::
|
||||||
"session": "<session id>"
|
"session": "<session id>"
|
||||||
}
|
}
|
||||||
|
|
||||||
The homeserver MUST respond to this with either new credentials, the next
|
The home server MUST respond to this with either new credentials, the next
|
||||||
stage of the login process, or a standard error response.
|
stage of the login process, or a standard error response.
|
||||||
|
|
||||||
A common client implementation will be to periodically poll until the link is
|
A common client implementation will be to periodically poll until the link is
|
||||||
|
|
@ -264,7 +264,7 @@ Email-based (identity server)
|
||||||
|
|
||||||
Prior to submitting this, the client should authenticate with an identity
|
Prior to submitting this, the client should authenticate with an identity
|
||||||
server. After authenticating, the session information should be submitted to
|
server. After authenticating, the session information should be submitted to
|
||||||
the homeserver.
|
the home server.
|
||||||
|
|
||||||
To respond to this type, reply with::
|
To respond to this type, reply with::
|
||||||
|
|
||||||
|
|
@ -293,7 +293,7 @@ of a previous login stage::
|
||||||
"next": "<next login type>"
|
"next": "<next login type>"
|
||||||
}
|
}
|
||||||
|
|
||||||
If a homeserver implements N-factor authentication, it MUST respond with all
|
If a home server implements N-factor authentication, it MUST respond with all
|
||||||
``stages`` when initially queried for their login requirements::
|
``stages`` when initially queried for their login requirements::
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
# Changelogs
|
|
||||||
|
|
||||||
[Towncrier](https://github.com/hawkowl/towncrier) is used to manage the changelog and
|
|
||||||
keep it up to date. Because of this, updating a changelog is really easy.
|
|
||||||
|
|
||||||
## Generating the changelog
|
|
||||||
|
|
||||||
Please see the [release docs](../meta/releasing.md) for more information.
|
|
||||||
|
|
||||||
## Creating a new changelog
|
|
||||||
|
|
||||||
There are a few places you'll have to update:
|
|
||||||
* `/layouts/shortcodes/changelog/changelog-changes.html` to account for the new changelog.
|
|
||||||
* `/scripts/generate-changelog.sh` to render the changelog for releases.
|
|
||||||
* Supporting documentation such as the contributing guidelines.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
!.gitignore
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
!.gitignore
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
!.gitignore
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
!.gitignore
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Replace the Twitter link in the footer with our BlueSky and Mastodon socials.
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
r0.1.2
|
|
||||||
======
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Clearer wording for the legacy routes section. (`#2160 <https://github.com/matrix-org/matrix-doc/issues/2160>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.1.1
|
|
||||||
======
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Change examples to use example.org instead of a real domain. (`#1650 <https://github.com/matrix-org/matrix-doc/issues/1650>`_)
|
|
||||||
- Add missing definition for how appservices verify requests came from a homeserver. (`#2037 <https://github.com/matrix-org/matrix-doc/issues/2037>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.1.0
|
|
||||||
======
|
|
||||||
|
|
||||||
This is the first release of the Application Service specification. It
|
|
||||||
includes support for application services being able to interact with
|
|
||||||
homeservers and bridge third-party networks, such as IRC, over to Matrix
|
|
||||||
in a standard and accessible way.
|
|
||||||
|
|
@ -1,575 +0,0 @@
|
||||||
r0.6.1
|
|
||||||
======
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- Added ``/rooms/{roomId}/aliases`` for retrieving local aliases for a room. (`#2562 <https://github.com/matrix-org/matrix-doc/issues/2562>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatible Changes
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
- Added data structures for defining moderation policies in rooms per `MSC2313 <https://github.com/matrix-org/matrix-doc/pull/2313>`_. (`#2434 <https://github.com/matrix-org/matrix-doc/issues/2434>`_)
|
|
||||||
- Optionally invalidate other access tokens during password modification per `MSC2457 <https://github.com/matrix-org/matrix-doc/pull/2457>`_. (`#2523 <https://github.com/matrix-org/matrix-doc/issues/2523>`_)
|
|
||||||
- Add User-Interactive Authentication for SSO-backed homeserver per `MSC2454 <https://github.com/matrix-org/matrix-doc/pull/2454>`_. (`#2532 <https://github.com/matrix-org/matrix-doc/issues/2532>`_)
|
|
||||||
- Add soft-logout support per `MSC1466 <https://github.com/matrix-org/matrix-doc/issues/1466>`_. (`#2546 <https://github.com/matrix-org/matrix-doc/issues/2546>`_)
|
|
||||||
- Replaced legacy room alias handling with a more sustainable solution per `MSC2432 <https://github.com/matrix-org/matrix-doc/pull/2432>`_. (`#2562 <https://github.com/matrix-org/matrix-doc/issues/2562>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- List available enum values for the room versions capability. (`#2245 <https://github.com/matrix-org/matrix-doc/issues/2245>`_)
|
|
||||||
- Fix various spelling errors throughout the specification. (`#2351 <https://github.com/matrix-org/matrix-doc/issues/2351>`_, `#2415 <https://github.com/matrix-org/matrix-doc/issues/2415>`_, `#2453 <https://github.com/matrix-org/matrix-doc/issues/2453>`_, `#2524 <https://github.com/matrix-org/matrix-doc/issues/2524>`_, `#2553 <https://github.com/matrix-org/matrix-doc/issues/2553>`_, `#2569 <https://github.com/matrix-org/matrix-doc/issues/2569>`_)
|
|
||||||
- Minor clarifications to token-based User-Interactive Authentication. (`#2369 <https://github.com/matrix-org/matrix-doc/issues/2369>`_)
|
|
||||||
- Minor clarification for what the user directory searches. (`#2381 <https://github.com/matrix-org/matrix-doc/issues/2381>`_)
|
|
||||||
- Fix key export format example to match the specification. (`#2430 <https://github.com/matrix-org/matrix-doc/issues/2430>`_)
|
|
||||||
- Clarify the IV data type for encrypted files. (`#2492 <https://github.com/matrix-org/matrix-doc/issues/2492>`_)
|
|
||||||
- Fix the ``.m.rule.contains_user_name`` default push rule to set the highlight tweak. (`#2519 <https://github.com/matrix-org/matrix-doc/issues/2519>`_)
|
|
||||||
- Clarify that an ``event_id`` is returned when sending events. (`#2525 <https://github.com/matrix-org/matrix-doc/issues/2525>`_)
|
|
||||||
- Fix some numbers in the specification to match their explanation text. (`#2554 <https://github.com/matrix-org/matrix-doc/issues/2554>`_)
|
|
||||||
- Move redaction algorithm into the room version specifications. (`#2563 <https://github.com/matrix-org/matrix-doc/issues/2563>`_)
|
|
||||||
- Clarify signature object structures for encryption. (`#2566 <https://github.com/matrix-org/matrix-doc/issues/2566>`_)
|
|
||||||
- Clarify which events are created as part of ``/createRoom``. (`#2571 <https://github.com/matrix-org/matrix-doc/issues/2571>`_)
|
|
||||||
- Remove claims that the homeserver is exclusively responsible for profile information in membership events. (`#2574 <https://github.com/matrix-org/matrix-doc/issues/2574>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.6.0
|
|
||||||
======
|
|
||||||
|
|
||||||
Breaking Changes
|
|
||||||
----------------
|
|
||||||
|
|
||||||
- Add ``id_access_token`` as a required request parameter to a few endpoints which require an ``id_server`` parameter as part of `MSC2140 <https://github.com/matrix-org/matrix-doc/pull/2140>`_. (`#2255 <https://github.com/matrix-org/matrix-doc/issues/2255>`_)
|
|
||||||
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- Add ``POST /account/3pid/unbind`` for removing a 3PID from an identity server. (`#2282 <https://github.com/matrix-org/matrix-doc/issues/2282>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatible Changes
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
- Add ``M_USER_DEACTIVATED`` error code. (`#2234 <https://github.com/matrix-org/matrix-doc/issues/2234>`_)
|
|
||||||
- Remove ``bind_msisdn`` and ``bind_email`` from ``/register`` now that the identity server's bind endpoint requires authentication. (`#2279 <https://github.com/matrix-org/matrix-doc/issues/2279>`_)
|
|
||||||
- Add ``m.identity_server`` account data for tracking the user's preferred identity server. (`#2281 <https://github.com/matrix-org/matrix-doc/issues/2281>`_)
|
|
||||||
- Deprecate ``id_server`` and make it optional in several places. (`#2310 <https://github.com/matrix-org/matrix-doc/issues/2310>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Add missing format fields to ``m.room.message$m.notice`` schema. (`#2125 <https://github.com/matrix-org/matrix-doc/issues/2125>`_)
|
|
||||||
- Remove "required" designation from the ``url`` field of certain ``m.room.message`` msgtypes. (`#2129 <https://github.com/matrix-org/matrix-doc/issues/2129>`_)
|
|
||||||
- Fix various typos throughout the specification. (`#2131 <https://github.com/matrix-org/matrix-doc/issues/2131>`_, `#2136 <https://github.com/matrix-org/matrix-doc/issues/2136>`_, `#2148 <https://github.com/matrix-org/matrix-doc/issues/2148>`_, `#2215 <https://github.com/matrix-org/matrix-doc/issues/2215>`_)
|
|
||||||
- Clarify the distinction between ``m.key.verification.start`` and its ``m.sas.v1`` variant. (`#2132 <https://github.com/matrix-org/matrix-doc/issues/2132>`_)
|
|
||||||
- Fix link to Olm signing specification. (`#2133 <https://github.com/matrix-org/matrix-doc/issues/2133>`_)
|
|
||||||
- Clarify the conditions for the ``.m.rule.room_one_to_one`` push rule. (`#2152 <https://github.com/matrix-org/matrix-doc/issues/2152>`_)
|
|
||||||
- Clarify the encryption algorithms supported by the device of the device keys example. (`#2157 <https://github.com/matrix-org/matrix-doc/issues/2157>`_)
|
|
||||||
- Clarify that ``/rooms/:roomId/event/:eventId`` returns a Matrix error. (`#2204 <https://github.com/matrix-org/matrix-doc/issues/2204>`_)
|
|
||||||
- Add a missing ``state_key`` check on ``.m.rule.tombstone``. (`#2223 <https://github.com/matrix-org/matrix-doc/issues/2223>`_)
|
|
||||||
- Fix the ``m.room_key_request`` ``action`` value, setting it from ``cancel_request`` to ``request_cancellation``. (`#2247 <https://github.com/matrix-org/matrix-doc/issues/2247>`_)
|
|
||||||
- Clarify that the ``submit_url`` field is without authentication. (`#2341 <https://github.com/matrix-org/matrix-doc/issues/2341>`_)
|
|
||||||
- Clarify the expected phone number format. (`#2342 <https://github.com/matrix-org/matrix-doc/issues/2342>`_)
|
|
||||||
- Clarify that clients should consider not requesting URL previews in encrypted rooms. (`#2343 <https://github.com/matrix-org/matrix-doc/issues/2343>`_)
|
|
||||||
- Add missing information on how filters are meant to work with ``/context``. (`#2344 <https://github.com/matrix-org/matrix-doc/issues/2344>`_)
|
|
||||||
- Clarify what the keys are for rooms in ``/sync``. (`#2345 <https://github.com/matrix-org/matrix-doc/issues/2345>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.5.0
|
|
||||||
======
|
|
||||||
|
|
||||||
Breaking Changes
|
|
||||||
----------------
|
|
||||||
|
|
||||||
- Add a new ``submit_url`` field to the responses of ``/requestToken`` which older clients will not be able to handle correctly. (`#2101 <https://github.com/matrix-org/matrix-doc/issues/2101>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Deprecations
|
|
||||||
------------
|
|
||||||
|
|
||||||
- Remove references to presence lists. (`#1817 <https://github.com/matrix-org/matrix-doc/issues/1817>`_)
|
|
||||||
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- ``GET /account_data`` routes. (`#1873 <https://github.com/matrix-org/matrix-doc/issues/1873>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatible Changes
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
- Add megolm session export format. (`#1701 <https://github.com/matrix-org/matrix-doc/issues/1701>`_)
|
|
||||||
- Add support for advertising experimental features to clients. (`#1786 <https://github.com/matrix-org/matrix-doc/issues/1786>`_)
|
|
||||||
- Add a generic SSO login API. (`#1789 <https://github.com/matrix-org/matrix-doc/issues/1789>`_)
|
|
||||||
- Add a mechanism for servers to redirect clients to an alternative homeserver after logging in. (`#1790 <https://github.com/matrix-org/matrix-doc/issues/1790>`_)
|
|
||||||
- Add room version upgrades. (`#1791 <https://github.com/matrix-org/matrix-doc/issues/1791>`_, `#1875 <https://github.com/matrix-org/matrix-doc/issues/1875>`_)
|
|
||||||
- Support optional features by having clients query for capabilities. (`#1829 <https://github.com/matrix-org/matrix-doc/issues/1829>`_, `#1879 <https://github.com/matrix-org/matrix-doc/issues/1879>`_)
|
|
||||||
- Add ``M_RESOURCE_LIMIT_EXCEEDED`` as an error code for when homeservers exceed limits imposed on them. (`#1874 <https://github.com/matrix-org/matrix-doc/issues/1874>`_)
|
|
||||||
- Emit ``M_UNSUPPORTED_ROOM_VERSION`` error codes where applicable on ``/createRoom`` and ``/invite`` APIs. (`#1908 <https://github.com/matrix-org/matrix-doc/issues/1908>`_)
|
|
||||||
- Add a ``.m.rule.tombstone`` default push rule for room upgrade notifications. (`#2020 <https://github.com/matrix-org/matrix-doc/issues/2020>`_)
|
|
||||||
- Add support for sending server notices to clients. (`#2026 <https://github.com/matrix-org/matrix-doc/issues/2026>`_)
|
|
||||||
- Add MSISDN (phone number) support to User-Interactive Authentication. (`#2030 <https://github.com/matrix-org/matrix-doc/issues/2030>`_)
|
|
||||||
- Add the option to lazy-load room members for increased client performance. (`#2035 <https://github.com/matrix-org/matrix-doc/issues/2035>`_)
|
|
||||||
- Add ``id_server`` to ``/deactivate`` and ``/3pid/delete`` endpoints to unbind from a specific identity server. (`#2046 <https://github.com/matrix-org/matrix-doc/issues/2046>`_)
|
|
||||||
- Add support for Olm sessions becoming un-stuck. (`#2059 <https://github.com/matrix-org/matrix-doc/issues/2059>`_)
|
|
||||||
- Add interactive device verification, including a common framework for device verification. (`#2072 <https://github.com/matrix-org/matrix-doc/issues/2072>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Change examples to use example.org instead of a real domain. (`#1650 <https://github.com/matrix-org/matrix-doc/issues/1650>`_)
|
|
||||||
- Clarify that ``state_default`` in ``m.room.power_levels`` always defaults to 50. (`#1656 <https://github.com/matrix-org/matrix-doc/issues/1656>`_)
|
|
||||||
- Add missing ``status_msg`` to ``m.presence`` schema. (`#1744 <https://github.com/matrix-org/matrix-doc/issues/1744>`_)
|
|
||||||
- Fix various spelling mistakes throughout the specification. (`#1838 <https://github.com/matrix-org/matrix-doc/issues/1838>`_, `#1853 <https://github.com/matrix-org/matrix-doc/issues/1853>`_, `#1860 <https://github.com/matrix-org/matrix-doc/issues/1860>`_, `#1933 <https://github.com/matrix-org/matrix-doc/issues/1933>`_, `#1969 <https://github.com/matrix-org/matrix-doc/issues/1969>`_, `#1988 <https://github.com/matrix-org/matrix-doc/issues/1988>`_, `#1989 <https://github.com/matrix-org/matrix-doc/issues/1989>`_, `#1991 <https://github.com/matrix-org/matrix-doc/issues/1991>`_, `#1992 <https://github.com/matrix-org/matrix-doc/issues/1992>`_)
|
|
||||||
- Add the missing ``m.push_rules`` event schema. (`#1889 <https://github.com/matrix-org/matrix-doc/issues/1889>`_)
|
|
||||||
- Clarify how modern day local echo is meant to be solved by clients. (`#1891 <https://github.com/matrix-org/matrix-doc/issues/1891>`_)
|
|
||||||
- Clarify that ``width`` and ``height`` are required parameters on ``/_matrix/media/r0/thumbnail/{serverName}/{mediaId}``. (`#1975 <https://github.com/matrix-org/matrix-doc/issues/1975>`_)
|
|
||||||
- Clarify how ``m.login.dummy`` can be used to disambiguate login flows. (`#1999 <https://github.com/matrix-org/matrix-doc/issues/1999>`_)
|
|
||||||
- Remove ``prev_content`` from the redaction algorithm's essential keys list. (`#2016 <https://github.com/matrix-org/matrix-doc/issues/2016>`_)
|
|
||||||
- Fix the ``third_party_signed`` definitions for the join APIs. (`#2025 <https://github.com/matrix-org/matrix-doc/issues/2025>`_)
|
|
||||||
- Clarify why User Interactive Auth is used on password changes and how access tokens are handled. (`#2027 <https://github.com/matrix-org/matrix-doc/issues/2027>`_)
|
|
||||||
- Clarify that devices are deleted upon logout. (`#2028 <https://github.com/matrix-org/matrix-doc/issues/2028>`_)
|
|
||||||
- Add ``M_NOT_FOUND`` error definition for deleting room aliases. (`#2029 <https://github.com/matrix-org/matrix-doc/issues/2029>`_)
|
|
||||||
- Add missing ``reason`` to ``m.call.hangup``. (`#2031 <https://github.com/matrix-org/matrix-doc/issues/2031>`_)
|
|
||||||
- Clarify how redactions affect room state. (`#2032 <https://github.com/matrix-org/matrix-doc/issues/2032>`_)
|
|
||||||
- Clarify that ``FAIL_ERROR`` in autodiscovery is not limited to just homeservers. (`#2036 <https://github.com/matrix-org/matrix-doc/issues/2036>`_)
|
|
||||||
- Fix example ``Content-Type`` for ``/media/upload`` request. (`#2041 <https://github.com/matrix-org/matrix-doc/issues/2041>`_)
|
|
||||||
- Clarify that login flows are meant to be completed in order. (`#2042 <https://github.com/matrix-org/matrix-doc/issues/2042>`_)
|
|
||||||
- Clarify that clients should not send read receipts for their own messages. (`#2043 <https://github.com/matrix-org/matrix-doc/issues/2043>`_)
|
|
||||||
- Use consistent examples of events throughout the specification. (`#2051 <https://github.com/matrix-org/matrix-doc/issues/2051>`_)
|
|
||||||
- Clarify which push rule condition kinds exist. (`#2052 <https://github.com/matrix-org/matrix-doc/issues/2052>`_)
|
|
||||||
- Clarify the required fields on ``m.file`` (and similar) messages. (`#2053 <https://github.com/matrix-org/matrix-doc/issues/2053>`_)
|
|
||||||
- Clarify that User-Interactive Authentication stages cannot be attempted more than once. (`#2054 <https://github.com/matrix-org/matrix-doc/issues/2054>`_)
|
|
||||||
- Clarify which parameters apply in what scenarios on ``/register``. (`#2055 <https://github.com/matrix-org/matrix-doc/issues/2055>`_)
|
|
||||||
- Clarify how to interpret changes of ``membership`` over time. (`#2056 <https://github.com/matrix-org/matrix-doc/issues/2056>`_)
|
|
||||||
- Clarify exactly what invite_room_state consists of. (`#2067 <https://github.com/matrix-org/matrix-doc/issues/2067>`_)
|
|
||||||
- Clarify how the content repository works, and what it is used for. (`#2068 <https://github.com/matrix-org/matrix-doc/issues/2068>`_)
|
|
||||||
- Clarify the order events in chunk are returned in for ``/messages``. (`#2069 <https://github.com/matrix-org/matrix-doc/issues/2069>`_)
|
|
||||||
- Clarify the key object definition for the key management API. (`#2083 <https://github.com/matrix-org/matrix-doc/issues/2083>`_)
|
|
||||||
- Reorganize information about events into a common section. (`#2087 <https://github.com/matrix-org/matrix-doc/issues/2087>`_)
|
|
||||||
- De-duplicate ``/state/<event_type>`` endpoints, clarifying that the ``<state_key>`` is optional. (`#2088 <https://github.com/matrix-org/matrix-doc/issues/2088>`_)
|
|
||||||
- Clarify when and where CORS headers should be returned. (`#2089 <https://github.com/matrix-org/matrix-doc/issues/2089>`_)
|
|
||||||
- Clarify when authorization and rate-limiting are not applicable. (`#2090 <https://github.com/matrix-org/matrix-doc/issues/2090>`_)
|
|
||||||
- Clarify that ``/register`` must produce valid Matrix User IDs. (`#2091 <https://github.com/matrix-org/matrix-doc/issues/2091>`_)
|
|
||||||
- Clarify how ``unread_notifications`` is calculated. (`#2097 <https://github.com/matrix-org/matrix-doc/issues/2097>`_)
|
|
||||||
- Clarify what a "module" is and update feature profiles for clients. (`#2098 <https://github.com/matrix-org/matrix-doc/issues/2098>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.4.0
|
|
||||||
======
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- ``POST /user_directory/search`` (`#1096 <https://github.com/matrix-org/matrix-doc/issues/1096>`_)
|
|
||||||
- ``GET /rooms/{roomId}/event/{eventId}`` (`#1110 <https://github.com/matrix-org/matrix-doc/issues/1110>`_)
|
|
||||||
- ``POST /delete_devices`` (`#1239 <https://github.com/matrix-org/matrix-doc/issues/1239>`_)
|
|
||||||
- ``GET /thirdparty/*`` Endpoints (`#1353 <https://github.com/matrix-org/matrix-doc/issues/1353>`_)
|
|
||||||
- ``POST /account/3pid/msisdn/requestToken``, ``POST /register/msisdn/requestToken``, and ``POST /account/password/msisdn/requestToken`` (`#1507 <https://github.com/matrix-org/matrix-doc/issues/1507>`_)
|
|
||||||
- ``POST /account/3pid/delete`` (`#1567 <https://github.com/matrix-org/matrix-doc/issues/1567>`_)
|
|
||||||
- ``POST /rooms/{roomId}/read_markers`` (`#1635 <https://github.com/matrix-org/matrix-doc/issues/1635>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatible Changes
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
- Add more presence options to the ``set_presence`` parameter of ``/sync``. (Thanks @mujx!) (`#780 <https://github.com/matrix-org/matrix-doc/issues/780>`_)
|
|
||||||
- Add ``token`` parameter to the ``/keys/query`` endpoint (`#1104 <https://github.com/matrix-org/matrix-doc/issues/1104>`_)
|
|
||||||
- Add the room visibility options for the room directory (`#1141 <https://github.com/matrix-org/matrix-doc/issues/1141>`_)
|
|
||||||
- Add spec for ignoring users (`#1142 <https://github.com/matrix-org/matrix-doc/issues/1142>`_)
|
|
||||||
- Add the ``/register/available`` endpoint for username availability (`#1151 <https://github.com/matrix-org/matrix-doc/issues/1151>`_)
|
|
||||||
- Add sticker messages (`#1158 <https://github.com/matrix-org/matrix-doc/issues/1158>`_)
|
|
||||||
- Specify how to control the power level required for ``@room`` (`#1176 <https://github.com/matrix-org/matrix-doc/issues/1176>`_)
|
|
||||||
- Document ``/logout/all`` endpoint (`#1263 <https://github.com/matrix-org/matrix-doc/issues/1263>`_)
|
|
||||||
- Add report content API (`#1264 <https://github.com/matrix-org/matrix-doc/issues/1264>`_)
|
|
||||||
- Add ``allow_remote`` to the content repo to avoid routing loops (`#1265 <https://github.com/matrix-org/matrix-doc/issues/1265>`_)
|
|
||||||
- Document `highlights` field in /search response (`#1274 <https://github.com/matrix-org/matrix-doc/issues/1274>`_)
|
|
||||||
- End-to-end encryption for group chats:
|
|
||||||
|
|
||||||
* Olm and Megolm messaging algorithms.
|
|
||||||
* ``m.room.encrypted``, ``m.room.encryption``, ``m.room_key`` events.
|
|
||||||
* Device verification process.
|
|
||||||
* ``device_one_time_keys_count`` sync parameter.
|
|
||||||
* ``device_lists:left`` sync parameter. (`#1284 <https://github.com/matrix-org/matrix-doc/issues/1284>`_)
|
|
||||||
- Add ``.well-known`` server discovery method (`#1359 <https://github.com/matrix-org/matrix-doc/issues/1359>`_)
|
|
||||||
- Document the GET version of ``/login`` (`#1361 <https://github.com/matrix-org/matrix-doc/issues/1361>`_)
|
|
||||||
- Document the ``server_name`` parameter on ``/join/{roomIdOrAlias}`` (`#1364 <https://github.com/matrix-org/matrix-doc/issues/1364>`_)
|
|
||||||
- Document the CORS/preflight headers (`#1365 <https://github.com/matrix-org/matrix-doc/issues/1365>`_)
|
|
||||||
- Add new user identifier object for logging in (`#1390 <https://github.com/matrix-org/matrix-doc/issues/1390>`_)
|
|
||||||
- Document message formats on ``m.text`` and ``m.emote`` messages (`#1397 <https://github.com/matrix-org/matrix-doc/issues/1397>`_)
|
|
||||||
- Encrypt file attachments (`#1420 <https://github.com/matrix-org/matrix-doc/issues/1420>`_)
|
|
||||||
- Share room decryption keys between devices (`#1465 <https://github.com/matrix-org/matrix-doc/issues/1465>`_)
|
|
||||||
- Document and improve client interaction with pushers. (`#1506 <https://github.com/matrix-org/matrix-doc/issues/1506>`_)
|
|
||||||
- Add support for Room Versions. (`#1516 <https://github.com/matrix-org/matrix-doc/issues/1516>`_)
|
|
||||||
- Guests can now call /context and /event to fetch events (`#1542 <https://github.com/matrix-org/matrix-doc/issues/1542>`_)
|
|
||||||
- Add a common standard for user, room, and group mentions in messages. (`#1547 <https://github.com/matrix-org/matrix-doc/issues/1547>`_)
|
|
||||||
- Add server ACLs as an option for controlling federation in a room. (`#1550 <https://github.com/matrix-org/matrix-doc/issues/1550>`_)
|
|
||||||
- Add new push rules for encrypted events and ``@room`` notifications. (`#1551 <https://github.com/matrix-org/matrix-doc/issues/1551>`_)
|
|
||||||
- Add third-party network room directories, as provided by application services. (`#1554 <https://github.com/matrix-org/matrix-doc/issues/1554>`_)
|
|
||||||
- Document the ``validated_at`` and ``added_at`` fields on ``GET /acount/3pid``. (`#1567 <https://github.com/matrix-org/matrix-doc/issues/1567>`_)
|
|
||||||
- Add an ``inhibit_login`` registration option. (`#1589 <https://github.com/matrix-org/matrix-doc/issues/1589>`_)
|
|
||||||
- Recommend that servers set a Content Security Policy for the content repository. (`#1600 <https://github.com/matrix-org/matrix-doc/issues/1600>`_)
|
|
||||||
- Add "rich replies" - a way for users to better represent the conversation thread they are referencing in their messages. (`#1617 <https://github.com/matrix-org/matrix-doc/issues/1617>`_)
|
|
||||||
- Add support for read markers. (`#1635 <https://github.com/matrix-org/matrix-doc/issues/1635>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Mark ``home_server`` return field for ``/login`` and ``/register`` endpoints as deprecated (`#1097 <https://github.com/matrix-org/matrix-doc/issues/1097>`_)
|
|
||||||
- Fix response format of ``/keys/changes`` endpoint (`#1106 <https://github.com/matrix-org/matrix-doc/issues/1106>`_)
|
|
||||||
- Clarify default values for some fields on the ``/search`` API (`#1109 <https://github.com/matrix-org/matrix-doc/issues/1109>`_)
|
|
||||||
- Fix the representation of ``m.presence`` events (`#1137 <https://github.com/matrix-org/matrix-doc/issues/1137>`_)
|
|
||||||
- Clarify that ``m.tag`` ordering is done with numbers, not strings (`#1139 <https://github.com/matrix-org/matrix-doc/issues/1139>`_)
|
|
||||||
- Clarify that ``/account/whoami`` should consider application services (`#1152 <https://github.com/matrix-org/matrix-doc/issues/1152>`_)
|
|
||||||
- Update ``ImageInfo`` and ``ThumbnailInfo`` dimension schema descriptions to clarify that they relate to intended display size, as opposed to the intrinsic size of the image file. (`#1158 <https://github.com/matrix-org/matrix-doc/issues/1158>`_)
|
|
||||||
- Mark ``GET /rooms/{roomId}/members`` as requiring authentication (`#1245 <https://github.com/matrix-org/matrix-doc/issues/1245>`_)
|
|
||||||
- Clarify ``changed`` field behaviour in device tracking process (`#1284 <https://github.com/matrix-org/matrix-doc/issues/1284>`_)
|
|
||||||
- Describe ``StateEvent`` for ``/createRoom`` (`#1329 <https://github.com/matrix-org/matrix-doc/issues/1329>`_)
|
|
||||||
- Describe how the ``reason`` is handled for kicks/bans (`#1362 <https://github.com/matrix-org/matrix-doc/issues/1362>`_)
|
|
||||||
- Mark ``GET /presence/{userId}/status`` as requiring authentication (`#1371 <https://github.com/matrix-org/matrix-doc/issues/1371>`_)
|
|
||||||
- Describe the rate limit error response schema (`#1373 <https://github.com/matrix-org/matrix-doc/issues/1373>`_)
|
|
||||||
- Clarify that clients must leave rooms before forgetting them (`#1378 <https://github.com/matrix-org/matrix-doc/issues/1378>`_)
|
|
||||||
- Document guest access in ``/createRoom`` presets (`#1379 <https://github.com/matrix-org/matrix-doc/issues/1379>`_)
|
|
||||||
- Define what a ``RoomEvent`` is on ``/rooms/{roomId}/messages`` (`#1380 <https://github.com/matrix-org/matrix-doc/issues/1380>`_)
|
|
||||||
- Clarify the request and result types on ``/search`` (`#1381 <https://github.com/matrix-org/matrix-doc/issues/1381>`_)
|
|
||||||
- Clarify some of the properties on the search result (`#1400 <https://github.com/matrix-org/matrix-doc/issues/1400>`_)
|
|
||||||
- Clarify how access tokens are meant to be supplied to the homeserver. (`#1517 <https://github.com/matrix-org/matrix-doc/issues/1517>`_)
|
|
||||||
- Document additional parameters on the ``/createRoom`` API. (`#1518 <https://github.com/matrix-org/matrix-doc/issues/1518>`_)
|
|
||||||
- Clarify that new push rules should be enabled by default, and that unrecognised conditions should not match. (`#1551 <https://github.com/matrix-org/matrix-doc/issues/1551>`_)
|
|
||||||
- Update all event examples to be accurate representations of their associated events. (`#1558 <https://github.com/matrix-org/matrix-doc/issues/1558>`_)
|
|
||||||
- Clarify the supported HTML features for room messages. (`#1562 <https://github.com/matrix-org/matrix-doc/issues/1562>`_)
|
|
||||||
- Move the ``invite_room_state`` definition under ``unsigned`` where it actually resides. (`#1568 <https://github.com/matrix-org/matrix-doc/issues/1568>`_)
|
|
||||||
- Clarify the homeserver's behaviour for searching users. (`#1569 <https://github.com/matrix-org/matrix-doc/issues/1569>`_)
|
|
||||||
- Clarify the object structures and defaults for Filters. (`#1570 <https://github.com/matrix-org/matrix-doc/issues/1570>`_)
|
|
||||||
- Clarify instances of ``type: number`` in the swagger/OpenAPI schema definitions. (`#1571 <https://github.com/matrix-org/matrix-doc/issues/1571>`_)
|
|
||||||
- Clarify that left rooms also have account data in ``/sync``. (`#1572 <https://github.com/matrix-org/matrix-doc/issues/1572>`_)
|
|
||||||
- Clarify the event fields used in the ``/sync`` response. (`#1573 <https://github.com/matrix-org/matrix-doc/issues/1573>`_)
|
|
||||||
- Fix naming of the body field in ``PUT /directory/room``. (`#1574 <https://github.com/matrix-org/matrix-doc/issues/1574>`_)
|
|
||||||
- Clarify the filter object schema used in room searching. (`#1577 <https://github.com/matrix-org/matrix-doc/issues/1577>`_)
|
|
||||||
- Document the 403 error for sending state events. (`#1590 <https://github.com/matrix-org/matrix-doc/issues/1590>`_)
|
|
||||||
- specify how to handle multiple olm sessions with the same device (`#1596 <https://github.com/matrix-org/matrix-doc/issues/1596>`_)
|
|
||||||
- Add the other keys that redactions are expected to preserve. (`#1602 <https://github.com/matrix-org/matrix-doc/issues/1602>`_)
|
|
||||||
- Clarify that clients should not be generating invalid HTML for formatted events. (`#1605 <https://github.com/matrix-org/matrix-doc/issues/1605>`_)
|
|
||||||
- Clarify the room tag structure (thanks @KitsuneRal!) (`#1606 <https://github.com/matrix-org/matrix-doc/issues/1606>`_)
|
|
||||||
- Add a note that clients may use the transaction ID to avoid flickering when doing local echo. (`#1619 <https://github.com/matrix-org/matrix-doc/issues/1619>`_)
|
|
||||||
- Include the request and response structures for the various ``/requestToken`` endpoints. (`#1636 <https://github.com/matrix-org/matrix-doc/issues/1636>`_)
|
|
||||||
- Clarify the available error codes, and when to prefer the HTTP status code over the ``errcode``. (`#1637 <https://github.com/matrix-org/matrix-doc/issues/1637>`_)
|
|
||||||
- Clarify and generalise the language used for describing pagination. (`#1642 <https://github.com/matrix-org/matrix-doc/issues/1642>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.3.0
|
|
||||||
======
|
|
||||||
|
|
||||||
- Breaking changes:
|
|
||||||
|
|
||||||
- Change the rule kind of ``.m.rule.contains_display_name`` from
|
|
||||||
``underride`` to ``override``. This works with all known clients
|
|
||||||
which support push rules, but any other clients implementing
|
|
||||||
the push rules API should be aware of this change. This
|
|
||||||
makes it simple to mute rooms correctly in the API
|
|
||||||
(`#373 <https://github.com/matrix-org/matrix-doc/pull/373>`_).
|
|
||||||
- Remove ``/tokenrefresh`` from the API
|
|
||||||
(`#395 <https://github.com/matrix-org/matrix-doc/pull/395>`_).
|
|
||||||
- Remove requirement that tokens used in token-based login be macaroons
|
|
||||||
(`#395 <https://github.com/matrix-org/matrix-doc/pull/395>`_).
|
|
||||||
- Move ``thumbnail_url`` and ``thumbnail_info`` members of json objects
|
|
||||||
for ``m.room.message`` events with msgtypes ``m.image``, ``m.file``
|
|
||||||
and ``m.location``, inside the ``info`` member, to match ``m.video``
|
|
||||||
events
|
|
||||||
(`#723 <https://github.com/matrix-org/matrix-doc/pull/723>`_).
|
|
||||||
|
|
||||||
- Changes to the API which will be backwards-compatible for clients:
|
|
||||||
|
|
||||||
- Add ``filename`` parameter to ``POST /_matrix/media/r0/upload``
|
|
||||||
(`#364 <https://github.com/matrix-org/matrix-doc/pull/364>`_).
|
|
||||||
- Document CAS-based client login and the use of ``m.login.token`` in
|
|
||||||
``/login`` (`#367 <https://github.com/matrix-org/matrix-doc/pull/367>`_).
|
|
||||||
- Make ``origin_server_ts`` a mandatory field of room events
|
|
||||||
(`#379 <https://github.com/matrix-org/matrix-doc/pull/370>`_).
|
|
||||||
- Add top-level ``account_data`` key to the responses to ``GET /sync`` and
|
|
||||||
``GET /initialSync``
|
|
||||||
(`#380 <https://github.com/matrix-org/matrix-doc/pull/380>`_).
|
|
||||||
- Add ``is_direct`` flag to ``POST /createRoom`` and invite member event.
|
|
||||||
Add 'Direct Messaging' module
|
|
||||||
(`#389 <https://github.com/matrix-org/matrix-doc/pull/389>`_).
|
|
||||||
- Add ``contains_url`` option to ``RoomEventFilter``
|
|
||||||
(`#390 <https://github.com/matrix-org/matrix-doc/pull/390>`_).
|
|
||||||
- Add ``filter`` optional query param to ``/messages``
|
|
||||||
(`#390 <https://github.com/matrix-org/matrix-doc/pull/390>`_).
|
|
||||||
- Add 'Send-to-Device messaging' module
|
|
||||||
(`#386 <https://github.com/matrix-org/matrix-doc/pull/386>`_).
|
|
||||||
- Add 'Device management' module
|
|
||||||
(`#402 <https://github.com/matrix-org/matrix-doc/pull/402>`_).
|
|
||||||
- Require that User-Interactive auth fallback pages call
|
|
||||||
``window.postMessage`` to notify apps of completion
|
|
||||||
(`#398 <https://github.com/matrix-org/matrix-doc/pull/398>`_).
|
|
||||||
- Add pagination and filter support to ``/publicRooms``. Change response to
|
|
||||||
omit fields rather than return ``null``. Add estimate of total number of
|
|
||||||
rooms in list.
|
|
||||||
(`#388 <https://github.com/matrix-org/matrix-doc/pull/388>`_).
|
|
||||||
- Allow guest accounts to use a number of endpoints which are required for
|
|
||||||
end-to-end encryption.
|
|
||||||
(`#751 <https://github.com/matrix-org/matrix-doc/pull/751>`_).
|
|
||||||
- Add key distribution APIs, for use with end-to-end encryption.
|
|
||||||
(`#894 <https://github.com/matrix-org/matrix-doc/pull/894>`_).
|
|
||||||
- Add ``m.room.pinned_events`` state event for rooms.
|
|
||||||
(`#1007 <https://github.com/matrix-org/matrix-doc/pull/1007>`_).
|
|
||||||
- Add mention of ability to send Access Token via an Authorization Header.
|
|
||||||
- Add ``guest_can_join`` parameter to ``POST /createRoom``
|
|
||||||
(`#1093 <https://github.com/matrix-org/matrix-doc/pull/1093>`_).
|
|
||||||
|
|
||||||
- New endpoints:
|
|
||||||
|
|
||||||
- ``GET /joined_rooms``
|
|
||||||
(`#999 <https://github.com/matrix-org/matrix-doc/pull/999>`_).
|
|
||||||
|
|
||||||
- ``GET /rooms/{roomId}/joined_members``
|
|
||||||
(`#999 <https://github.com/matrix-org/matrix-doc/pull/999>`_).
|
|
||||||
|
|
||||||
- ``GET /account/whoami``
|
|
||||||
(`#1063 <https://github.com/matrix-org/matrix-doc/pull/1063>`_).
|
|
||||||
|
|
||||||
- ``GET /media/{version}/preview_url``
|
|
||||||
(`#1064 <https://github.com/matrix-org/matrix-doc/pull/1064>`_).
|
|
||||||
|
|
||||||
- Spec clarifications:
|
|
||||||
|
|
||||||
- Add endpoints and logic for invites and third-party invites to the federation
|
|
||||||
spec and update the JSON of the request sent by the identity server upon 3PID
|
|
||||||
binding
|
|
||||||
(`#997 <https://github.com/matrix-org/matrix-doc/pull/997>`_)
|
|
||||||
- Fix "membership" property on third-party invite upgrade example
|
|
||||||
(`#995 <https://github.com/matrix-org/matrix-doc/pull/995>`_)
|
|
||||||
- Fix response format and 404 example for room alias lookup
|
|
||||||
(`#960 <https://github.com/matrix-org/matrix-doc/pull/960>`_)
|
|
||||||
- Fix examples of ``m.room.member`` event and room state change,
|
|
||||||
and added a clarification on the membership event sent upon profile update
|
|
||||||
(`#950 <https://github.com/matrix-org/matrix-doc/pull/950>`_).
|
|
||||||
- Spell out the way that state is handled by ``POST /createRoom``
|
|
||||||
(`#362 <https://github.com/matrix-org/matrix-doc/pull/362>`_).
|
|
||||||
- Clarify the fields which are applicable to different types of push rule
|
|
||||||
(`#365 <https://github.com/matrix-org/matrix-doc/pull/365>`_).
|
|
||||||
- A number of clarifications to authentication
|
|
||||||
(`#371 <https://github.com/matrix-org/matrix-doc/pull/371>`_).
|
|
||||||
- Correct references to ``user_id`` which should have been ``sender``
|
|
||||||
(`#376 <https://github.com/matrix-org/matrix-doc/pull/376>`_).
|
|
||||||
- Correct inconsistent specification of ``redacted_because`` fields and their
|
|
||||||
values (`#378 <https://github.com/matrix-org/matrix-doc/pull/378>`_).
|
|
||||||
- Mark required fields in response objects as such
|
|
||||||
(`#394 <https://github.com/matrix-org/matrix-doc/pull/394>`_).
|
|
||||||
- Make ``m.notice`` description a bit harder in its phrasing to try to
|
|
||||||
dissuade the same issues that occurred with IRC
|
|
||||||
(`#750 <https://github.com/matrix-org/matrix-doc/pull/750>`_).
|
|
||||||
- ``GET /user/{userId}/filter/{filterId}`` requires authentication
|
|
||||||
(`#1003 <https://github.com/matrix-org/matrix-doc/pull/1003>`_).
|
|
||||||
- Add some clarifying notes on the behaviour of rooms with no
|
|
||||||
``m.room.power_levels`` event
|
|
||||||
(`#1026 <https://github.com/matrix-org/matrix-doc/pull/1026>`_).
|
|
||||||
- Clarify the relationship between ``username`` and ``user_id`` in the
|
|
||||||
``/register`` API
|
|
||||||
(`#1032 <https://github.com/matrix-org/matrix-doc/pull/1032>`_).
|
|
||||||
- Clarify rate limiting and security for content repository.
|
|
||||||
(`#1064 <https://github.com/matrix-org/matrix-doc/pull/1064>`_).
|
|
||||||
|
|
||||||
r0.2.0
|
|
||||||
======
|
|
||||||
|
|
||||||
- Spec clarifications:
|
|
||||||
|
|
||||||
- Room aliases (`#337 <https://github.com/matrix-org/matrix-doc/pull/337>`_):
|
|
||||||
|
|
||||||
- Make it clear that ``GET /directory/room/{roomAlias}`` must work for
|
|
||||||
federated aliases.
|
|
||||||
|
|
||||||
- ``GET /directory/room/{roomAlias}`` cannot return a 409; the ``PUT``
|
|
||||||
endpoint can, however.
|
|
||||||
|
|
||||||
- Power levels:
|
|
||||||
|
|
||||||
- Clarify the defaults to be used for various fields of the
|
|
||||||
``m.room.power_levels`` event
|
|
||||||
(`#286 <https://github.com/matrix-org/matrix-doc/pull/286>`_,
|
|
||||||
`#341 <https://github.com/matrix-org/matrix-doc/pull/341>`_).
|
|
||||||
|
|
||||||
- Add suggestions for mapping of names to power levels
|
|
||||||
(`#336 <https://github.com/matrix-org/matrix-doc/pull/336>`_).
|
|
||||||
|
|
||||||
- Clarify the room naming algorithm in certain edge cases
|
|
||||||
(`#351 <https://github.com/matrix-org/matrix-doc/pull/351>`_).
|
|
||||||
|
|
||||||
- Remove outdated references to the pre-r0 ``/events`` API, and clarify the
|
|
||||||
section on syncing
|
|
||||||
(`#352 <https://github.com/matrix-org/matrix-doc/pull/352>`_).
|
|
||||||
|
|
||||||
|
|
||||||
- Changes to the API which will be backwards-compatible for clients:
|
|
||||||
|
|
||||||
- New endpoints:
|
|
||||||
|
|
||||||
- ``POST /register/email/requestToken``
|
|
||||||
(`#343 <https://github.com/matrix-org/matrix-doc/pull/343>`_).
|
|
||||||
|
|
||||||
- ``POST /account/3pid/email/requestToken``
|
|
||||||
(`#346 <https://github.com/matrix-org/matrix-doc/pull/346>`_).
|
|
||||||
|
|
||||||
- ``POST /account/password/email/requestToken``
|
|
||||||
(`#346 <https://github.com/matrix-org/matrix-doc/pull/346>`_).
|
|
||||||
|
|
||||||
- ``POST /account/deactivate``
|
|
||||||
(`#361 <https://github.com/matrix-org/matrix-doc/pull/361>`_).
|
|
||||||
|
|
||||||
- Updates to the Presence module
|
|
||||||
(`#278 <https://github.com/matrix-org/matrix-doc/pull/278>`_,
|
|
||||||
`#342 <https://github.com/matrix-org/matrix-doc/pull/342>`_):
|
|
||||||
|
|
||||||
- Remove unused ``free_for_chat`` presence state
|
|
||||||
- Add ``currently_active`` flag to the ``m.presence`` event and the ``GET
|
|
||||||
/presence/{userId}/status`` response.
|
|
||||||
- Make idle timeout the responsibility of the server
|
|
||||||
- Remove requirements on servers to propagate profile information via
|
|
||||||
``m.presence`` events.
|
|
||||||
|
|
||||||
- Add new predefined push rules
|
|
||||||
(`#274 <https://github.com/matrix-org/matrix-doc/pull/274>`_,
|
|
||||||
`#340 <https://github.com/matrix-org/matrix-doc/pull/340/files>`_).
|
|
||||||
|
|
||||||
- ``/sync`` should always return a ``prev_batch`` token
|
|
||||||
(`#345 <https://github.com/matrix-org/matrix-doc/pull/345>`_).
|
|
||||||
|
|
||||||
- add ``to`` parameter to ``GET /rooms/{roomId}/messages`` API
|
|
||||||
(`#348 <https://github.com/matrix-org/matrix-doc/pull/348>`_).
|
|
||||||
|
|
||||||
r0.1.0
|
|
||||||
======
|
|
||||||
|
|
||||||
This release includes the following changes since r0.0.1:
|
|
||||||
|
|
||||||
- Breaking changes to the API [#]_:
|
|
||||||
|
|
||||||
- ``POST /rooms/{roomId}/join`` no longer permits use of a room alias instead
|
|
||||||
of a room id. (``POST /join/{roomIdOrAlias}`` continues to allow either.)
|
|
||||||
- ``POST /account/3pid``: correct the name of the ``three_pid_creds``
|
|
||||||
parameter
|
|
||||||
- The "Push Rules" module no longer supports device-specific rules:
|
|
||||||
|
|
||||||
- ``GET /pushrules`` no longer returns a ``device`` property
|
|
||||||
- ``device/{profile_tag}`` is no longer a valid ``scope`` for push rules
|
|
||||||
- ``profile_tag`` is no longer a valid kind of condition on push rules.
|
|
||||||
|
|
||||||
(Device-specific push rules will be reintroduced in the future; in the
|
|
||||||
meantime, their specification has been moved to a `draft branch`__.)
|
|
||||||
|
|
||||||
__ https://matrix.org/speculator/spec/drafts%2Freinstate_device_push_rules/
|
|
||||||
|
|
||||||
- Changes to the API which will be backwards-compatible for clients:
|
|
||||||
|
|
||||||
- New endpoints:
|
|
||||||
|
|
||||||
- ``POST /logout``
|
|
||||||
- ``POST /rooms/{roomId}/unban``
|
|
||||||
- ``POST /rooms/{roomId}/kick``
|
|
||||||
- ``GET /pushers``
|
|
||||||
- ``GET /pushrules/{scope}/{kind}/{ruleId}/enabled``
|
|
||||||
(previously ``PUT``-only)
|
|
||||||
- ``GET`` and ``PUT /pushrules/{scope}/{kind}/{ruleId}/actions``
|
|
||||||
|
|
||||||
- Add ``third_party_signed`` parameter to ``POST /rooms/{roomId}/join``
|
|
||||||
- Add ``M_INVALID_USERNAME`` as valid response to ``POST /register``
|
|
||||||
- Add ``unread_notifications`` field to ``GET /sync`` response
|
|
||||||
- Add optional ``invite`` property to ``m.room.power_levels`` state event
|
|
||||||
- Add optional ``public_key`` and ``public_keys`` to
|
|
||||||
``m.room.third_party_invite`` state event
|
|
||||||
- Password-based ``/login`` may now use a third-party identifier instead of
|
|
||||||
a matrix user id.
|
|
||||||
|
|
||||||
- Spec clarifications
|
|
||||||
|
|
||||||
- Make the state diagram for room membership explicit
|
|
||||||
- Note that a user may not be invited to a room while banned
|
|
||||||
- Clarify the expected order of events in the response to
|
|
||||||
``GET /rooms/{roomId}/context/{eventId}``, as well as correcting the
|
|
||||||
example for that API
|
|
||||||
- Clarify the behaviour of the "Room History Visibility" module; in
|
|
||||||
particular, the behaviour of the ``shared`` history visibility, and how
|
|
||||||
events at visibility boundaries should be handled
|
|
||||||
- Separate the "Room Previews" module from "Guest access"
|
|
||||||
- Reword the description of the ``profile_tag`` property in
|
|
||||||
``PUT /pushers/set``, and note that it is not mandatory.
|
|
||||||
|
|
||||||
|
|
||||||
.. [#] Our `versioning policy <../index.html#specification-versions>`_ would
|
|
||||||
strictly require that a breaking change be denoted by a new major
|
|
||||||
specification version. However we are not aware of any clients which
|
|
||||||
rely on the old behaviour here, nor server implementations which offer
|
|
||||||
it, so we have chosen to retain the r0 designation on this occasion.
|
|
||||||
|
|
||||||
r0.0.1
|
|
||||||
======
|
|
||||||
|
|
||||||
This release includes the following changes since r0.0.0:
|
|
||||||
|
|
||||||
- API changes:
|
|
||||||
- Added new ``/versions`` API
|
|
||||||
- ``/createRoom`` takes an optional ``invite_3pid`` parameter
|
|
||||||
- ``/publicRooms`` returns an ``avatar_url`` result
|
|
||||||
- The following APIs are now deprecated:
|
|
||||||
- ``/initialSync``
|
|
||||||
- ``/events``
|
|
||||||
- ``/events/:eventId``
|
|
||||||
- ``/rooms/:roomId/initialSync``
|
|
||||||
- Spec clarifications
|
|
||||||
- Document inter-version compatibility
|
|
||||||
- Document the parameters to the ``/user/:userId/filter`` API
|
|
||||||
- Document the ``next_batch`` parameter on ``/search``
|
|
||||||
- Document the membership states on ``m.room.member`` events
|
|
||||||
- Minor clarifications/corrections to:
|
|
||||||
- Guest access module
|
|
||||||
- Search module
|
|
||||||
- ``/login`` API
|
|
||||||
- ``/rooms/:roomId/send/:eventType/:txnId`` API
|
|
||||||
- ``/rooms/:roomId/context/:eventId`` API
|
|
||||||
|
|
||||||
r0.0.0
|
|
||||||
======
|
|
||||||
|
|
||||||
This is the first release of the client-server specification. It is largely a dump of what has currently been implemented, and there are several inconsistencies.
|
|
||||||
|
|
||||||
An upcoming minor release will deprecate many of these inconsistencies, and they will be removed in the next major release.
|
|
||||||
|
|
||||||
Since the draft stage, the following major changes have been made:
|
|
||||||
- /api/v1 and /v2_alpha path segments have been replaced with the major version of the release (i.e. 'r0').
|
|
||||||
- Some POST versions of APIs with both POST and PUT have been removed.
|
|
||||||
- The specification has been split into one specification per API. This is the client-server API. The server-server API can be found documented separately.
|
|
||||||
- All APIs are now documented using Swagger
|
|
||||||
- The following modules have been added:
|
|
||||||
- Content repository
|
|
||||||
- Instant messaging
|
|
||||||
- Push notification
|
|
||||||
- History visibility
|
|
||||||
- Search
|
|
||||||
- Invites based on third-party identifiers
|
|
||||||
- Room tagging
|
|
||||||
- Guest access
|
|
||||||
- Client config
|
|
||||||
- The following APIs were added:
|
|
||||||
- ``/sync``
|
|
||||||
- ``/publicRooms``
|
|
||||||
- ``/rooms/{roomId}/forget``
|
|
||||||
- ``/admin/whois``
|
|
||||||
- ``/rooms/{roomId}/redact``
|
|
||||||
- ``/user/{userId}/filter``
|
|
||||||
- The following APIs have been significantly modified:
|
|
||||||
- Invitations now contain partial room state
|
|
||||||
- Invitations can now be rejected
|
|
||||||
- ``/directory``
|
|
||||||
- The following events have been added:
|
|
||||||
- ``m.room.avatar``
|
|
||||||
- Example signed json is included for reference
|
|
||||||
- Commentary on display name calculation was added
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
r0.3.0
|
|
||||||
======
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- Add ``/account``, ``/account/register``, and ``/account/logout`` to authenticate with the identity server. (`#2255 <https://github.com/matrix-org/matrix-doc/issues/2255>`_)
|
|
||||||
- Add endpoints for accepting and handling terms of service. (`#2258 <https://github.com/matrix-org/matrix-doc/issues/2258>`_)
|
|
||||||
- Add ``/hash_details`` and a new ``/lookup`` endpoint for performing hashed association lookups. (`#2287 <https://github.com/matrix-org/matrix-doc/issues/2287>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatible Changes
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
- Deprecate the v1 API in favour of an authenticated v2 API. (`#2254 <https://github.com/matrix-org/matrix-doc/issues/2254>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.2.1
|
|
||||||
======
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Remove incorrect ``id_server`` parameter from ``/requestToken`` endpoints. (`#2124 <https://github.com/matrix-org/matrix-doc/issues/2124>`_)
|
|
||||||
- Clarify that identity servers can return 403 for unbind requests. (`#2126 <https://github.com/matrix-org/matrix-doc/issues/2126>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.2.0
|
|
||||||
======
|
|
||||||
|
|
||||||
New Endpoints
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- Add ``/3pid/unbind`` for removing 3PIDs. (`#2046 <https://github.com/matrix-org/matrix-doc/issues/2046>`_)
|
|
||||||
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Fix various spelling mistakes throughout the specification. (`#1853 <https://github.com/matrix-org/matrix-doc/issues/1853>`_)
|
|
||||||
- Fix route for ``/3pid/bind``. (`#1967 <https://github.com/matrix-org/matrix-doc/issues/1967>`_)
|
|
||||||
- Add missing aesthetic parameters to ``/store-invite``. (`#2049 <https://github.com/matrix-org/matrix-doc/issues/2049>`_)
|
|
||||||
- Clarify what the client should receive upon sending an identical email validation request multiple times. (`#2057 <https://github.com/matrix-org/matrix-doc/issues/2057>`_)
|
|
||||||
- Clarify that the default transport is JSON over HTTP. (`#2086 <https://github.com/matrix-org/matrix-doc/issues/2086>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.1.0
|
|
||||||
======
|
|
||||||
|
|
||||||
This is the first release of the Identity Service API. With this API, clients and
|
|
||||||
homeservers can store bindings between third-party identifiers such as email addresses
|
|
||||||
and phone numbers, associating them with Matrix user IDs. Additionally, identity
|
|
||||||
servers offer the ability to invite third-party users to Matrix rooms by storing
|
|
||||||
the invite until the identifier is bound.
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
r0.1.1
|
|
||||||
======
|
|
||||||
|
|
||||||
Spec Clarifications
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
- Fix ``event_id`` field in push request body. (`#2151 <https://github.com/matrix-org/matrix-doc/issues/2151>`_)
|
|
||||||
|
|
||||||
|
|
||||||
r0.1.0
|
|
||||||
======
|
|
||||||
|
|
||||||
The first release of the Push Gateway specification. This release contains
|
|
||||||
a single endpoint, ``/notify``, that pushers may use to send push notifications
|
|
||||||
to clients.
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue