Compare commits

...

97 Commits

Author SHA1 Message Date
fkwp
e98b0ed1ed indentation 2025-04-11 00:06:03 +02:00
fkwp
d97332f47a Merge branch 'livekit' into fkwp/doc_update 2025-04-09 20:30:24 +02:00
fkwp
6551ce8e18 Merge pull request #3178 from nordeck/fix-selfhosting-docs
Update self-hosting.md docs formatting
2025-04-09 20:30:01 +02:00
fkwp
3c5594b7e1 prettier 2025-04-09 13:34:58 +02:00
fkwp
eb9593a4e5 add information about CORS headers 2025-04-09 13:16:25 +02:00
fkwp
078f36c14a add Community Guides & How-Tos section 2025-04-09 13:04:41 +02:00
Kim Brose
7297dbcc00 Update self-hosting.md docs formatting 2025-04-09 11:32:56 +02:00
fkwp
ba382eef75 Merge pull request #3175 from element-hq/renovate/livekit-client
Update dependency livekit-client to v2.10.0
2025-04-08 16:45:36 +02:00
fkwp
23b1a5fff5 cleanup yarn.lock 2025-04-08 16:39:09 +02:00
fkwp
95fed3fc2d bump to 2.10.0 2025-04-08 09:52:48 +02:00
renovate[bot]
6398fd2783 Update dependency livekit-client to v2.9.9 2025-04-08 07:15:13 +00:00
fkwp
e8f0398f59 Merge pull request #3165 from element-hq/fkwp/update_readme
Update readme
2025-04-08 08:52:01 +02:00
Timo
a7dc289b2d Add yarn and bundled element call renovate group. (#3173) 2025-04-07 17:52:19 +02:00
fkwp
db10903ea0 Update README.md
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
2025-04-07 16:58:07 +02:00
fkwp
ca1410bc85 hint towards cs api 2025-04-07 11:30:34 +02:00
fkwp
c78360fce2 Update README.md
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
2025-04-05 19:29:08 +02:00
renovate[bot]
e5358e8609 Update dependency vite to v6.2.5 [SECURITY] (#3169)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-04 23:26:09 +02:00
Valere Fedronic
bc0ea20343 Default vite config to support using local build of crypto wasm (#3038)
* Devex: Default vite config to support using local build of crypto wasm

* use realpathSync and make it work with linked and not-linked
We need to use sync because an async defineConfig fails for the embedded exports.

* also allow just linking matrix-sdk-crypto-wasm (without js-sdk linking)
---------

Co-authored-by: Timo <toger5@hotmail.de>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
Co-authored-by: Robin <robin@robin.town>
2025-04-04 23:24:42 +02:00
fkwp
ab8a86e451 prettier 2025-04-04 23:12:41 +02:00
fkwp
45b0a5c2a6 reordering 2025-04-04 23:12:41 +02:00
fkwp
c20aa5c1c8 rephrase Packaging and adding Figures 2025-04-04 23:12:41 +02:00
fkwp
d5481d8c20 indentation 2025-04-04 23:12:41 +02:00
fkwp
bef57b677c center images 2025-04-04 23:12:41 +02:00
fkwp
ce1c5437fc add note about in-app calling requirements 2025-04-04 23:12:41 +02:00
fkwp
46f059947b Merge pull request #3168 from element-hq/toger5/add-link-disable-enable-scripts
Add yarn scripts for disabling/enabling `.links.yaml`
2025-04-04 15:31:00 +02:00
fkwp
cf0cb2ebd2 Merge pull request #3153 from element-hq/renovate/github-actions
Pin dependencies
2025-04-04 15:28:57 +02:00
fkwp
2b35db3f39 Merge pull request #3145 from element-hq/toger5/github-release-note-categories
Add simple release note automation
2025-04-04 15:26:51 +02:00
Timo
a3f01a35c8 Add yarn scripts for disabling/enabling .links.yaml 2025-04-04 12:35:21 +02:00
Timo
14b3e49de6 Use PR- labels 2025-04-04 11:34:44 +02:00
Timo
6ceaa073a9 Add simple release note automation 2025-04-04 11:34:44 +02:00
Valere Fedronic
deac07dd13 Merge pull request #3163 from element-hq/valere/add_missing_to_device_permission
Widget: Add missing to device permission for encryption keys
2025-04-04 09:37:40 +02:00
Valere
f0126f41fb Widget: Add missing to device permission for encryption keys 2025-04-04 09:32:34 +02:00
Valere Fedronic
8bd44344e7 Merge pull request #3164 from element-hq/toger5/fix-src-js-sdk-imports
Fix lint and playwright errors caused by matrix-js-sdk/src import
2025-04-04 09:31:24 +02:00
Valere
9b945d00f7 cleaning: Remove deprecated config option for EC url 2025-04-04 09:18:58 +02:00
Valere
e9e82ca3e1 Cleaning + update docker compose pull policy for eweb 2025-04-04 09:12:27 +02:00
Timo
c91d9e5790 do the setting set later 2025-04-03 18:06:38 +02:00
Timo
7561e33e38 use localhost ew 2025-04-03 18:01:43 +02:00
Timo
afced3eb73 test fix experiment 2025-04-03 17:02:48 +02:00
Timo
70c97fa8be Fix lint errors caused by matrix-js-sdl/src import 2025-04-03 15:51:47 +02:00
Valere Fedronic
9acc1d1fe9 Merge pull request #3123 from element-hq/valere/playwright_widget_tests
Test: End to end integrated test for ElementCall in widget mode
2025-04-03 09:52:45 +02:00
renovate[bot]
622d91d7cc Update dependency vite to v6.2.4 [SECURITY] (#3151)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 11:12:25 +02:00
renovate[bot]
e7086ff8fc Pin dependencies 2025-04-01 02:20:37 +00:00
ElementRobot
5f0c3435fa Merge pull request #3152 from element-hq/actions/localazy-download
Localazy Download
2025-03-31 22:36:50 +02:00
fkwp
18972c2fb9 Translations updates 2025-03-31 20:33:53 +00:00
Hugh Nimmo-Smith
d1753c33f5 Use correct rageshake URL when running in embedded package + tests (#3132)
* Use correct rageshake URL when running in embedded package

It was incorrectly trying to use the one from config.json

* Refactor to add tests

* Empty mock config
2025-03-31 16:38:25 +01:00
Hugh Nimmo-Smith
e4c222a4e8 Expose version string in embedded SwiftPM and AAR (#3144)
* Expose version string in embedded SwiftPM and AAR

Implements https://github.com/element-hq/element-call/issues/3143

* Fix filename

* Fix location of `Version.kt`

* Use the right path for the sed replacement in the publishing workflow for Android

---------

Co-authored-by: Jorge Martín <jorgem@element.io>
2025-03-31 14:55:20 +01:00
fkwp
d12d616e28 Merge pull request #3136 from element-hq/fkwp/update_readme
Fix example JWT service .well-known endpoints in self-hosting.md
2025-03-31 15:08:57 +02:00
Timo
2073cd3ac1 Rename EULA to SSLA (#3135)
* Change EULA to SSLA
 - rename i18n fields
 - update the config property to `ssla` and deprecate `eula`
 - use `eula` instead of ssla in case it is provided in the config.

* fix default config

* completely remove eula fallback
2025-03-31 14:18:45 +02:00
Hugh Nimmo-Smith
9f2f1d8641 Improve documentation for how to use the embedded package (#3146) 2025-03-28 18:26:22 +00:00
Hugh Nimmo-Smith
fd2c1f6410 Clarify who is responsible for compliance and consent in relation to analytics (#3116)
It varies depending on if you are using the full or embedded package.
2025-03-28 14:18:53 +00:00
Hugh Nimmo-Smith
1be0733011 Always run build CI workflow (#3139)
As identified in https://github.com/element-hq/element-call/pull/3116#issuecomment-2759148857 depending on the contents of a PR it may not be possible to merge due to required workflows not actually being run.

This change will mean that the build CI workflow is run irrespective of the contents.
2025-03-28 15:06:00 +01:00
Hugh Nimmo-Smith
bfd4bb2ec1 Show URL params and environment variables in developer tab (#3134) 2025-03-27 16:35:31 -04:00
Robin
f845397b87 Merge pull request #3093 from element-hq/toger5/src-to-lib-import
Transition from consuming js-sdk source to `lib` (build output)
2025-03-27 16:13:05 -04:00
Robin
aab4efe03a Use type imports consistently 2025-03-27 16:09:59 -04:00
Robin
eb18cbef78 Consolidate imports 2025-03-27 16:04:03 -04:00
Robin
ae339ea5cc Fix formatting issues 2025-03-27 14:47:01 -04:00
Robin
33700d1529 Merge branch 'livekit' into toger5/src-to-lib-import 2025-03-27 14:35:08 -04:00
Robin
21140f6f2c Merge pull request #3095 from element-hq/robin/berry
Upgrade to Yarn v4 (Berry)
2025-03-27 14:21:10 -04:00
Robin
6927a92ad3 Improve comments in linker plugin 2025-03-27 14:16:16 -04:00
Robin
f99eb3c88f Merge branch 'livekit' into robin/berry 2025-03-27 14:07:24 -04:00
Robin
a993d8cd26 Streamline the linker hook messages 2025-03-27 14:05:10 -04:00
fkwp
53fa21b97a update .well-known example using the proposed endpoint routing 2025-03-26 22:36:47 +01:00
fkwp
a4f86492f9 Merge pull request #3130 from element-hq/fkwp/update_readme
Add endpoint routing to README.md
2025-03-26 13:48:09 +01:00
fkwp
79404fcb18 Update README.md
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
2025-03-26 13:20:51 +01:00
fkwp
defe880515 Update README.md
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
2025-03-26 13:20:27 +01:00
fkwp
fa0365c409 added MatrixRTC backend for completness 2025-03-26 00:07:13 +01:00
Timo
6a5b79143e Make pre-commit message more alerting 2025-03-25 20:26:23 +01:00
Timo
f868eca938 Add docs and git hooks 2025-03-25 20:13:34 +01:00
Timo
6fa218dd91 add links.disabled.yaml to yarn lock 2025-03-25 19:34:30 +01:00
fkwp
117b99d967 prettier 2025-03-25 17:14:18 +01:00
fkwp
7003e1f7d2 add section about endpoint routing 2025-03-25 17:09:54 +01:00
fkwp
ae7188cd65 added endpoint routing 2025-03-25 17:09:31 +01:00
fkwp
7de7886453 indentation 2025-03-25 17:07:58 +01:00
fkwp
efd08b4997 use MatrixRTC suggestion wrt. hostname and endpoints 2025-03-25 17:03:25 +01:00
Valere
0fbde40359 test: End to end integrated test for call widget 2025-03-25 16:09:38 +01:00
renovate[bot]
3ce9d71983 Update dependency vite to v6.2.3 [SECURITY] (#3125)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 15:53:30 +01:00
Hugh Nimmo-Smith
238bdea2b0 Fix compilation error when trying to use SwiftPM embedded package (#3124)
* Test SwiftPM build as part of release process

* Fix iOS embedded platform version as v17
2025-03-25 14:26:28 +00:00
Robin
fe382cfc0b Merge pull request #3053 from element-hq/robin/posthog-logout
Enable analytics only while authenticated
2025-03-24 10:14:48 -04:00
Robin
0ed1564d3e Merge branch 'livekit' into robin/posthog-logout 2025-03-24 10:10:28 -04:00
Robin
1138a21b57 Merge pull request #3118 from element-hq/robin/errors-outside-boundary
Fix join errors mistakenly showing a generic error screen
2025-03-21 17:20:52 -04:00
fkwp
eaf067f0dc Merge pull request #3117 from element-hq/fkwp/remove_fallback_matrixrtc-backend_from_netlify
remove fallback MatrixRTC backend from netlify PR builds
2025-03-21 19:00:32 +01:00
fkwp
41044ce974 remove fallback MatrixRTC backend 2025-03-21 18:55:43 +01:00
Hugh Nimmo-Smith
ff6365cfed One more --immutable 2025-03-21 17:19:34 +00:00
Hugh Nimmo-Smith
f820506184 Fix up CI 2025-03-21 17:17:23 +00:00
Hugh Nimmo-Smith
9bf046b714 Merge branch 'livekit' into robin/berry 2025-03-21 17:14:10 +00:00
Robin
cb14b727ba Merge branch 'livekit' into robin/berry 2025-03-14 11:59:21 -04:00
Robin
d633ec5fcd Update docs for Yarn Berry 2025-03-14 03:23:37 -04:00
Robin
0b26dc2f43 Create a plugin for linking other packages 2025-03-14 03:23:37 -04:00
Robin
31fb916b9d Enable CI to use Yarn Berry 2025-03-14 03:23:37 -04:00
Robin
95b37ea341 Upgrade to Yarn Berry 2025-03-14 03:23:37 -04:00
Robin
fee9841183 Remove the dependency on buffer
It's not generally available in browser environments / certain Yarn modes and can easily be replaced by TextEncoder.
2025-03-14 02:09:48 -04:00
Timo
6f93a037cf import cleanups 2025-03-13 18:00:24 -04:00
Timo
f0545ced65 make it work withotu js-sdk changes 2025-03-13 18:00:24 -04:00
Timo
46f5c44db0 temp2 2025-03-13 18:00:07 -04:00
Timo
adb5934f0b temp 2025-03-13 17:51:41 -04:00
Robin
65304473df Enable analytics only while authenticated
The one place where we should log out of PostHog and reset our analytics ID is when the user is logging out. This matches the behavior in Element Web and makes sense, I think, because logging out is essentially a request for the app to forget who you are. This means we should also start analytics at the point of logging in / reauthenticating.

I noticed while making this change that there was an unused branch in setClient, so I cleaned it up rather than making myself update it.
2025-03-05 09:12:18 -05:00
Robin
4919410ff0 Don't reset analytics ID when leaving calls
We shouldn't be calling PosthogAnalytics.instance.logout() when leaving the call in widget mode, because all this does is reset your analytics ID. In the big picture this is probably inflating our user count metrics.
2025-03-05 08:55:47 -05:00
165 changed files with 15073 additions and 9764 deletions

11
.githooks/post-commit Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/sh
FILE=.links.disabled.yaml
if test -f "$FILE"; then
# echo "$FILE exists. -> moving to .links.disabled.yaml"
mv .links.disabled.yaml .links.yaml
# echo "running yarn"
yarnLog=$(yarn)
echo "[yarn-linker] The post-commit hook has re-enabled .links.yaml."
exit 1
fi

12
.githooks/pre-commit Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/sh
FILE=".links.yaml"
if test -f "$FILE"; then
# echo "$FILE exists. -> moving to .links.disabled.yaml"
mv .links.yaml .links.disabled.yaml
# echo "running yarn"
x=$(yarn)
y=$(git add yarn.lock)
echo "[yarn-linker] The pre-commit hook has disabled .links.yaml and MODIFIED the yarn.lock file. Review the staged changes (the hook added yarn.lock, was this desired?) and run \`git commit \` again if they look okay. The post-commit hook will re-enable your links."
exit 1
fi

30
.github/realease.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
changelog:
categories:
- title: 🛠 Breaking Changes
labels:
- PR-Breaking-Change
- title: ✨ Features
labels:
- PR-Feature
- title: 🙌 Improvements
labels:
- PR-Improvement
- title: 📄 Documentation
labels:
- PR-Documentation
- title: 🐛 Bugfixes
labels:
- PR-Bug-Fix
- title: 💾 Developer Experience
labels:
- PR-Developer-Experience
- title: Others
labels:
- "*"
exclude:
labels:
- PR-Task
- dependencies
- title: 👒 Dependencies
labels:
- dependencies

View File

@@ -10,7 +10,7 @@ jobs:
pull-requests: read
steps:
- name: Add notice
uses: actions/github-script@v7
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
with:
script: |

View File

@@ -26,7 +26,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: 📥 Download artifact
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ inputs.artifact_run_id }}
@@ -34,7 +34,7 @@ jobs:
path: dist
- name: Log in to container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -28,13 +28,15 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Enable Corepack
run: corepack enable
- name: Yarn cache
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
cache: "yarn"
node-version-file: ".node-version"
- name: Install dependencies
run: "yarn install --frozen-lockfile"
run: "yarn install --immutable"
- name: Build full version
if: ${{ inputs.package == 'full' }}
run: "yarn run build:full"
@@ -58,7 +60,7 @@ jobs:
VITE_APP_VERSION: ${{ inputs.vite_app_version }}
NODE_OPTIONS: "--max-old-space-size=4096"
- name: Upload Artifact
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: build-output-${{ inputs.package }}
path: dist

View File

@@ -5,16 +5,8 @@ on:
- synchronize
- opened
- labeled
paths-ignore:
- ".github/ISSUE_TEMPLATE/**"
- ".github/CODEOWNERS"
- "docs/**"
push:
branches: [livekit, full-mesh]
paths-ignore:
- ".github/ISSUE_TEMPLATE/**"
- ".github/CODEOWNERS"
- "docs/**"
jobs:
build_full_element_call:
# Use the full package vite build

View File

@@ -46,7 +46,7 @@ jobs:
Exercise caution. Use test accounts.
- name: 📥 Download artifact
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
run-id: ${{ inputs.artifact_run_id }}

View File

@@ -8,13 +8,15 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Enable Corepack
run: corepack enable
- name: Yarn cache
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
cache: "yarn"
node-version-file: ".node-version"
- name: Install dependencies
run: "yarn install --frozen-lockfile"
run: "yarn install --immutable"
- name: Prettier
run: "yarn run prettier:check"
- name: i18n

View File

@@ -42,7 +42,7 @@ jobs:
- name: Determine filename
run: echo "FILENAME_PREFIX=element-call-embedded-${VERSION:1}" >> "$GITHUB_ENV"
- name: 📥 Download built element-call artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id || github.run_id }}
@@ -73,15 +73,16 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: 📥 Download built element-call artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id || github.run_id }}
name: build-output-embedded
path: embedded/web/dist
# n.b. We don't enable corepack here because we are using plain npm
- name: Setup node
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
node-version-file: .node-version
registry-url: "https://registry.npmjs.org"
@@ -107,7 +108,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: 📥 Download built element-call artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id || github.run_id }}
@@ -123,6 +124,9 @@ jobs:
- name: Get artifact version
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
- name: Set version string
run: sed -i "s/0.0.0/${{ env.ARTIFACT_VERSION }}/g" embedded/android/lib/src/main/kotlin/io/element/android/call/embedded/Version.kt
- name: Publish AAR
working-directory: embedded/android
env:
@@ -147,7 +151,7 @@ jobs:
path: element-call
- name: 📥 Download built element-call artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id || github.run_id }}
@@ -167,6 +171,13 @@ jobs:
- name: Get artifact version
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
- name: Set version string
run: sed -i "s/0.0.0/${{ env.ARTIFACT_VERSION }}/g" element-call-swift/Sources/EmbeddedElementCall/EmbeddedElementCall.swift
- name: Test build
working-directory: element-call-swift
run: swift build
- name: Commit and tag
working-directory: element-call-swift
run: |

View File

@@ -31,7 +31,7 @@ jobs:
- name: Determine filename
run: echo "FILENAME_PREFIX=element-call-${VERSION:1}" >> "$GITHUB_ENV"
- name: 📥 Download built element-call artifact
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id || github.run_id }}

View File

@@ -10,13 +10,15 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Enable Corepack
run: corepack enable
- name: Yarn cache
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
cache: "yarn"
node-version-file: ".node-version"
- name: Install dependencies
run: "yarn install --frozen-lockfile"
run: "yarn install --immutable"
- name: Vitest
run: "yarn run test:coverage"
- name: Upload to codecov
@@ -31,13 +33,15 @@ jobs:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
cache: "yarn"
node-version-file: ".node-version"
- name: Install dependencies
run: yarn install --frozen-lockfile
run: yarn install --immutable
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Run backend components
@@ -48,7 +52,7 @@ jobs:
run: cp config/config.devenv.json public/config.json
- name: Run Playwright tests
run: yarn playwright test
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: ${{ !cancelled() }}
with:
name: playwright-report

View File

@@ -15,13 +15,16 @@ jobs:
- name: Checkout the code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
cache: "yarn"
node-version-file: ".node-version"
- name: Install Deps
run: "yarn install --frozen-lockfile"
run: "yarn install --immutable"
- name: Prune i18n
run: "rm -R locales"
@@ -39,7 +42,7 @@ jobs:
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # v7.0.7
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
branch: actions/localazy-download

13
.gitignore vendored
View File

@@ -9,10 +9,21 @@ dist-ssr
public/config.json
backend/synapse_tmp/*
/coverage
# Yarn
yarn-error.log
/.pnp.*
/.yarn/*
!/.yarn/patches
!/.yarn/plugins
!/.yarn/releases
!/.yarn/sdks
!/.yarn/versions
/.links.yaml
/.links.disabled.yaml
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.cache/

91
.yarn/plugins/linker.cjs vendored Normal file
View File

@@ -0,0 +1,91 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
module.exports = {
name: "linker",
factory: (require) => ({
hooks: {
// Yarn's plugin system is very light on documentation. The best we have
// for this hook is simply the type definition in
// https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-core/sources/Plugin.ts
registerPackageExtensions: async (config, registerPackageExtension) => {
const { structUtils } = require("@yarnpkg/core");
const { parseSyml } = require("@yarnpkg/parsers");
const path = require("path");
const fs = require("fs");
const process = require("process");
// Create a descriptor that we can use to target our direct dependencies
const projectPath = config.projectCwd
.replace(/\\/g, "/")
.replace("/C:/", "C:/");
const manifestPath = path.join(projectPath, "package.json");
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
const selfDescriptor = structUtils.parseDescriptor(
`${manifest.name}@*`,
true,
);
// Load the list of linked packages
const linksPath = path.join(projectPath, ".links.yaml");
let linksFile;
try {
linksFile = fs.readFileSync(linksPath, "utf8");
} catch (e) {
return; // File doesn't exist, there's nothing to link
}
let links;
try {
links = parseSyml(linksFile);
} catch (e) {
console.error(".links.yaml has invalid syntax", e);
process.exit(1);
}
// Resolve paths and turn them into a Yarn package extension
const overrides = Object.fromEntries(
Object.entries(links).map(([name, link]) => [
name,
`portal:${path.resolve(config.projectCwd, link)}`,
]),
);
const overrideIdentHashes = new Set();
for (const name of Object.keys(overrides))
overrideIdentHashes.add(
structUtils.parseDescriptor(`${name}@*`, true).identHash,
);
// Extend our own package's dependencies with these local overrides
registerPackageExtension(selfDescriptor, { dependencies: overrides });
// Filter out the original dependencies from the package spec so Yarn
// actually respects the overrides
const filterDependencies = (original) => {
const pkg = structUtils.copyPackage(original);
pkg.dependencies = new Map(
Array.from(pkg.dependencies.entries()).filter(
([, value]) => !overrideIdentHashes.has(value.identHash),
),
);
return pkg;
};
// Patch Yarn's own normalizePackage method to use the above filter
const originalNormalizePackage = config.normalizePackage;
config.normalizePackage = function (pkg, extensions) {
return originalNormalizePackage.call(
this,
pkg.identHash === selfDescriptor.identHash
? filterDependencies(pkg)
: pkg,
extensions,
);
};
},
},
}),
};

3
.yarnrc.yml Normal file
View File

@@ -0,0 +1,3 @@
nodeLinker: node-modules
plugins:
- .yarn/plugins/linker.cjs

116
README.md
View File

@@ -45,30 +45,35 @@ organize the flow of the meeting.
**Emoji Reactions** Users can react with emojis 👍️ 🎉 👏 🤘, adding
engagement and interactivity to the conversation.
## 🚀 Deployment Options
## 🚀 Deployment & Packaging Options
Element Call can be packaged in two ways:
Element Call is developed using the
[Matrix js-sdk](https://github.com/matrix-org/matrix-js-sdk) with Matroska mode.
This allows the app to run either as a Standalone App directly connected to a
homeserver with login interfaces or it can be used as a widget within a Matrix
client.
**Full Package** Supports both **Standalone** and **Widget** mode. Hosted as
a static web page and accessed via a URL when used as a widget.
### 🖥️ Standalone Mode
**Embedded Package** Designed for **Widget mode** only. Bundled with a
messenger app for seamless integration. This is the recommended method for
embedding Element Call into a messenger app.
<p align="center">
<img src="./docs/element_call_standalone.drawio.png" alt="Element Call in Standalone Mode">
</p>
See the [here](./docs/embedded-standalone.md) for more information on the packages.
### Standalone mode
![Element Call in Standalone Mode](./docs/element_call_standalone.drawio.png)
In Standalone mode Element Call operates as an independent, full-featured video
conferencing web application, allowing users to join or host calls without
In Standalone mode, Element Call operates as an independent, full-featured video
conferencing web application, enabling users to join or host calls without
requiring a separate Matrix client.
### Widget mode embedded in Messenger Apps
### 📲 In-App Calling (Widget Mode in Messenger Apps)
![Element Call in Widget Mode](./docs/element_call_widget.drawio.png)
When used as a widget 🧩, Element Call is solely responsible on the core calling
functionality (MatrixRTC). Authentication, event handling, and room state
updates (via the Client-Server API) are handled by the hosting client.
Communication between Element Call and the client is managed through the widget
API.
<p align="center">
<img src="./docs/element_call_widget.drawio.png" alt="Element Call in Widget Mode">
</p>
Element Call can be embedded as a widget inside apps like
[**Element Web**](https://github.com/element-hq/element-web) or **Element X
@@ -80,6 +85,30 @@ and voice calls within Matrix rooms.
> [!IMPORTANT]
> Embedded packaging is recommended for Element Call in widget mode!
### 📦 Element Call Packaging
Element Call offers two packaging options: one for standalone or widget
deployment, and another for seamless widget-based integration into messenger
apps. Below is an overview of each option.
**Full Package** Supports both **Standalone** and **Widget** mode. It is
hosted as a static web page and can be accessed via a URL when used as a widget.
<p align="center">
<img src="./docs/full_package.drawio.png" alt="Element Call Full Package">
</p>
**Embedded Package** Designed specifically for **Widget mode** only. It is
bundled with a messenger app for seamless integration and this is the
recommended method for embedding Element Call.
<p align="center">
<img src="./docs/embedded_package.drawio.png" alt="Element Call Embedded Package">
</p>
For more details on the packages, see the
[Embedded vs. Standalone Guide](./docs/embedded-standalone.md).
## 🛠️ Self-Hosting
For operating and deploying Element Call on your own server, refer to the
@@ -91,20 +120,22 @@ For proper Element Call operation each site deployment needs a MatrixRTC backend
setup as outlined in the [Self-Hosting](#self-hosting). A typical federated site
deployment for three different sites A, B and C is depicted below.
![Element Call federated setup](./docs/Federated_Setup.drawio.png)
<p align="center">
<img src="./docs/Federated_Setup.drawio.png" alt="Element Call federated setup">
</p>
### Backend Discovery
MatrixRTC backend (according to
[MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143))
is announced by the homeserver's `.well-known/matrix/client` file and discovered
[MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)) is
announced by the Matrix site's `.well-known/matrix/client` file and discovered
via the `org.matrix.msc4143.rtc_foci` key, e.g.:
```json
"org.matrix.msc4143.rtc_foci": [
{
"type": "livekit",
"livekit_service_url": "https://someurl.com"
"livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt"
},
]
```
@@ -130,8 +161,11 @@ points them to a Matrix LiveKit JWT Auth Service via `livekit_service_url`.
The example below illustrates how backend selection works across **Matrix
federation**, using the setup from sites A, B, and C. It demonstrates backend
selection for **Matrix rooms 123 and 456**, which include users from different
homeservers.
![Element Call SFU selection over Matrix federation](./docs/SFU_selection.drawio.png)
homeservers.
<p align="center">
<img src="./docs/SFU_selection.drawio.png" alt="Element Call SFU selection over Matrix federation">
</p>
## 🌍 Translation
@@ -149,6 +183,7 @@ To get started clone and set up this project:
```sh
git clone https://github.com/element-hq/element-call.git
cd element-call
corepack enable
yarn
```
@@ -168,6 +203,10 @@ You're now ready to launch the development server:
yarn dev
```
See also:
- [Developing with linked packages](./linking.md)
### Backend
A docker compose file `dev-backend-docker-compose.yml` is provided to start the
@@ -193,21 +232,23 @@ yarn backend
### Playwright tests
Our Playwright tests run automatically as part of our CI along with our other tests,
on every pull request.
Our Playwright tests run automatically as part of our CI along with our other
tests, on every pull request.
You may need to follow instructions to set up your development environment for running
Playwright by following <https://playwright.dev/docs/browsers#install-browsers> and
You may need to follow instructions to set up your development environment for
running Playwright by following
<https://playwright.dev/docs/browsers#install-browsers> and
<https://playwright.dev/docs/browsers#install-system-dependencies>.
However the Playwright tests are run, an element-call instance must be running on
https://localhost:3000 (this is configured in `playwright.config.ts`) - this is what will
be tested.
However the Playwright tests are run, an element-call instance must be running
on https://localhost:3000 (this is configured in `playwright.config.ts`) - this
is what will be tested.
The local backend environment should be running for the test to work:
`yarn backend`
There are a few different ways to run the tests yourself. The simplest is to run:
There are a few different ways to run the tests yourself. The simplest is to
run:
```shell
yarn run test:playwright
@@ -227,13 +268,13 @@ The easiest way to develop new test is to use the codegen feature of Playwright:
npx playwright codegen
```
This will record your action and write the test code for you. Use the tool bar to test visibility, text content,
clicking.
This will record your action and write the test code for you. Use the tool bar
to test visibility, text content and clicking.
##### Investigate a failed test from the CI
In the failed action page, click on the failed job, then scroll down to the `upload-artifact` step.
You will find a link to download the zip report, as per:
In the failed action page, click on the failed job, then scroll down to the
`upload-artifact` step. You will find a link to download the zip report, as per:
```
Artifact playwright-report has been successfully uploaded! Final size is 1360358 bytes. Artifact ID is 2746265841
@@ -246,8 +287,9 @@ Unzip the report then use this command to open the report in your browser:
npx playwright show-report ~/Downloads/playwright-report/
```
Under the failed test there is a small icon looking like "3 columns" (next to test name file name),
click on it to see the live screenshots/console output.
Under the failed test there is a small icon looking like "3 columns" (next to
the test name file name), click on it to see the live screenshots/console
output.
### Test Coverage

28
WIDGET_TEST.md Normal file
View File

@@ -0,0 +1,28 @@
# Testing Element-Call in widget mode
When running `yarn backend` the latest element-web develop will be deployed and served on `http://localhost:8081`.
In a development environment, you might prefer to just use the `element-web` repo directly, but this setup is useful for CI/CD testing.
## Setup
The element-web configuration is modified to:
- Enable to use the local widget instance (`element_call.url` https://localhost:3000).
- Enable the labs features (`feature_group_calls`, `feature_element_call_video_rooms`).
The default configuration used by docker-compose is in `test-container/config.json`. There is a fixture for playwright
that uses
## Running the element-web instance
It is part of the existing backend setup. To start the backend, run:
```sh
yarn backend
```
Then open `http://localhost:8081` in your browser.
## Basic fixture
A base fixture is provided in `/playwright/fixtures/widget-user.ts` that will register two users that shares a room.

View File

@@ -0,0 +1,53 @@
{
"default_server_config": {
"m.homeserver": {
"base_url": "http://synapse.localhost:8008",
"server_name": "synapse.localhost"
}
},
"disable_custom_urls": false,
"disable_guests": false,
"disable_login_language_selector": false,
"disable_3pid_login": false,
"force_verification": false,
"brand": "Element",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
"integrations_widgets_urls": [
"https://scalar.vector.im/_matrix/integrations/v1",
"https://scalar.vector.im/api",
"https://scalar-staging.vector.im/_matrix/integrations/v1",
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"default_widget_container_height": 280,
"default_country_code": "GB",
"show_labs_settings": false,
"features": {
"feature_element_call_video_rooms": true,
"feature_video_rooms": true,
"feature_group_calls": true,
"feature_release_announcement": false
},
"default_federate": true,
"default_theme": "light",
"room_directory": {
"servers": ["matrix.org"]
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
},
"setting_defaults": {
"breadcrumbs": true,
"feature_group_calls": true
},
"jitsi": {
"preferred_domain": "meet.element.io"
},
"element_call": {
"participant_limit": 8,
"brand": "Element Call"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

View File

@@ -11,5 +11,5 @@
"features": {
"feature_use_device_session_member_events": true
},
"eula": "https://static.element.io/legal/online-EULA.pdf"
"ssla": "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf"
}

View File

@@ -11,5 +11,5 @@
"features": {
"feature_use_device_session_member_events": true
},
"eula": "https://static.element.io/legal/online-EULA.pdf"
"ssla": "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf"
}

View File

@@ -5,12 +5,6 @@
"server_name": "call-unstable.ems.host"
}
},
"livekit": {
"livekit_service_url": "https://livekit-jwt.call.element.dev"
},
"features": {
"feature_use_device_session_member_events": true
},
"posthog": {
"api_key": "phc_rXGHx9vDmyEvyRxPziYtdVIv0ahEv8A9uLWFcCi1WcU",
"api_host": "https://posthog-element-call.element.io"

View File

@@ -68,6 +68,18 @@ services:
networks:
- ecbackend
element-web:
image: ghcr.io/element-hq/element-web:develop
pull_policy: always
volumes:
- ./backend/ew.test.config.json:/app/config.json
environment:
ELEMENT_WEB_PORT: 81
ports:
- "8081:81"
networks:
- ecbackend
nginx:
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls_localhost_key.pem -out tls_localhost_cert.pem -subj "/C=GB/ST=London/L=London/O=Alros/OU=IT Department/CN=localhost"
hostname: synapse.localhost

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -1,8 +1,9 @@
## Element Call Docs
This folder contains documentation for Element Call setup and usage.
This folder contains documentation for setup, usage, and development of Element Call.
- [Embedded vs standalone mode](./embedded-standalone.md)
- [Url format and parameters](./url-params.md)
- [Global JS controls](./controls.md)
- [Self-Hosting](./self-hosting.md)
- [Developing with linked packages](./linking.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 909 KiB

After

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 KiB

After

Width:  |  Height:  |  Size: 886 KiB

View File

@@ -1,17 +1,32 @@
## Element Call packages
Element Call is available as two different packages: Full Package and Embedded Package. The Full Package is designed for standalone use, while the Embedded Package is designed for widget mode only. The table below provides a comparison of the two packages:
Element Call is available as two different packages: Full Package and Embedded Package.
| | Full Package | Embedded Package |
| ------------------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------- |
| **Supports use as standalone** | ✅ | ❌ |
| **Supports use as widget** | ✅ | ✅ |
| **Deployment mode** | Hosted as a static web page and accessed via a URL when used as a widget | Bundled within a messenger app for seamless integration |
| **Release artifacts** | Docker Image, Tarball | Tarball, NPM for Web, Android AAR, SwiftPM for iOS |
| **Recommended for** | Standalone/guest access usage | Embedding within messenger apps |
The Full Package is designed for standalone use, while the Embedded Package is designed for widget mode only.
For examples of how to use the platform specific release artifacts (e.g. Android AAR) see
the Element Messenger apps for: [Web](https://github.com/element-hq/element-web), [iOS](https://github.com/element-hq/element-x-ios) and [Android](https://github.com/element-hq/element-x-android).
The table below provides a comparison of the two packages:
| | Full Package | Embedded Package |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Supports use as standalone** | ✅ | ❌ |
| **Supports use as widget** | ✅ | ✅ |
| **Deployment mode** | Hosted as a static web page and accessed via a URL when used as a widget | Bundled within a messenger app for seamless integration |
| **Release artifacts** | Docker Image, Tarball | Tarball, NPM for Web, Android AAR, SwiftPM for iOS |
| **Recommended for** | Standalone/guest access usage | Embedding within messenger apps |
| **Responsibility for regulatory compliance** | The administrator that is deploying the app is responsible for compliance with any applicable regulations (e.g. privacy) | The developer of the messenger app is responsible for compliance |
| **Analytics consent** | Element Call will show a consent UI. | Element Call will not show a consent UI. The messenger app should only provide the embedded Element Call with the [analytics URL parameters](./url-params.md#embedded-only-parameters) if consent has been granted. |
| **Analytics data** | Element Call will send data to the Posthog, Sentry and Open Telemetry targets specified by the administrator in the `config.json` | Element Call will send data to the Posthog and Sentry targets specified in the URL parameters by the messenger app |
### Using the embedded package within a messenger app
Currently the best way to understand the necessary steps is to look at the implementations in the Element Messenger apps: [Web](https://github.com/element-hq/element-web/pull/29309), [iOS](https://github.com/element-hq/element-x-ios/pull/3939) and [Android](https://github.com/element-hq/element-x-android/pull/4470).
The basics are:
1. Add the appropriate platform dependency as given for a [release](https://github.com/element-hq/element-call/releases), or use the embedded tarball. e.g. `npm install @element-hq/element-call-embedded@0.9.0`
2. Include the assets from the platform dependency in the build process. e.g. copy the assets during a [Webpack](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/webpack.config.js#L677-L682) build.
3. Use the `index.html` entrypointof the imported assets when you are constructing the WebView or iframe. e.g. using a [relative path in a webapp](https://github.com/element-hq/element-web/blob/247cd8d56d832d006d7dfb919d1042529d712b59/src/models/Call.ts#L680), or on the the Android [WebViewAssetLoader](https://github.com/element-hq/element-x-android/blob/fe5aab6588ecdcf9354a3bfbd9e97c1b31175a8f/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt#L20)
4. Set any of the [embedded-only URL parameters](./url-params.md#embedded-only-parameters) that you need.
## Widget vs standalone mode

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

39
docs/linking.md Normal file
View File

@@ -0,0 +1,39 @@
# Developing with linked packages
If you want to make changes to a package that Element Call depends on and see those changes applied in real time, you can create a link to a local copy of the package. Yarn has a command for this (`yarn link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment.
Instead, you can use our little 'linker' plugin. Create a file named `.links.yaml` in the Element Call project directory, listing the names and paths of any dependencies you want to link. For example:
```yaml
matrix-js-sdk: ../path/to/matrix-js-sdk
"@vector-im/compound-web": /home/alice/path/to/compound-web
```
Then run `yarn install`.
## Hooks
Changes in `.links.yaml` will also update `yarn.lock` when `yarn` is executed. The lockfile will then contain the local
version of the package which would not work on others dev setups or the github CI.
One always needs to run:
```bash
mv .links.yaml .links.disabled.yaml
yarn
```
before committing a change.
To make it more convenient to work with this linking system we added git hooks for your conviniece.
A `pre-commit` hook will run `mv .links.yaml .links.disabled.yaml`, `yarn` and `git add yarn.lock` if it detects
a `.links.yaml` file and abort the commit.
You will than need to check if the resulting changes are appropriate and commit again.
A `post-commit` hook will setup the linking as it was
before if a `.links.disabled.yaml` is present. It runs `mv .links.disabled.yaml .links.yaml` and `yarn`.
To activate the hooks automatically configure git with
```bash
git config --local core.hooksPath .githooks/
```

View File

@@ -1,5 +1,9 @@
# Self-Hosting Element Call
> [!NOTE]
> For In-App calling (Element X, Element Web, Element Desktop) use-case only
> section [Prerequisites](#Prerequisites) is required.
## Prerequisites
> [!IMPORTANT]
@@ -30,8 +34,9 @@ required for Element Call to work properly:
sync v2 API that allows them to correctly track the state of the room. This is
required by Element Call to track room state reliably.
If you're using [Synapse](https://github.com/element-hq/synapse/) as your homeserver, you'll need
to additionally add the following config items to `homeserver.yaml` to comply with Element Call:
If you're using [Synapse](https://github.com/element-hq/synapse/) as your
homeserver, you'll need to additionally add the following config items to
`homeserver.yaml` to comply with Element Call:
```yaml
experimental_features:
@@ -50,9 +55,10 @@ rc_message:
# Note key sharing events are bursty
per_second: 0.5
burst_count: 30
rc_delayed_event_mgmt:
# This needs to match at least the heart-beat frequency plus a bit of headroom
# Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s
rc_delayed_event_mgmt:
per_second: 1
burst_count: 20
```
@@ -64,35 +70,99 @@ required for each site deployment.
![MSC4195 compatible setup](MSC4195_setup.drawio.png)
As depicted above, Element Call requires a
As depicted above in the `example.com` site deployment, Element Call requires a
[Livekit SFU](https://github.com/livekit/livekit) alongside a
[Matrix Livekit JWT auth service](https://github.com/element-hq/lk-jwt-service)
to implement
[MSC4195: MatrixRTC using LiveKit backend](https://github.com/hughns/matrix-spec-proposals/blob/hughns/matrixrtc-livekit/proposals/4195-matrixrtc-livekit.md).
#### Matrix site endpoint routing
In the context of MatrixRTC, we suggest using a single hostname for backend
communication by implementing endpoint routing within a reverse proxy setup. For
the example above, this results in:
| Service | Endpoint | Example |
| -------- | ------- | ------- |
| [Livekit SFU](https://github.com/livekit/livekit) WebSocket signalling connection | `/livekit/sfu` | `matrix-rtc.example.com/livekit/sfu` |
| [Matrix Livekit JWT auth service](https://github.com/element-hq/lk-jwt-service) | `/livekit/jwt` | `matrix-rtc.example.com/livekit/jwt` |
Using Nginx, you can achieve this by:
```jsonc
server {
...
location ^~ /livekit/jwt/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# JWT Service running at port 8080
proxy_pass http://localhost:8080/;
}
location ^~ /livekit/sfu/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_buffering off;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# LiveKit SFU websocket connection running at port 7880
proxy_pass http://localhost:7880/;
}
}
```
#### MatrixRTC backend announcement
> [!IMPORTANT]
> As defined in
> [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
> MatrixRTC backend must be announced to the client via your **homeserver's
> `.well-known/matrix/client`**. The configuration is a list of Foci configs:
> MatrixRTC backend must be announced to the client via your **Matrix site's
> `.well-known/matrix/client`** file (e.g.
> `example.com/.well-known/matrix/client` matching the site deployment example
> from above). The configuration is a list of Foci configs:
```json
"org.matrix.msc4143.rtc_foci": [
{
"type": "livekit",
"livekit_service_url": "https://someurl.com"
},
{
"type": "livekit",
"livekit_service_url": "https://livekit2.com"
"livekit_service_url": "https://matrix-rtc.example.com/livekit/jwt"
},
{
"type": "another_foci",
"props_for_another_foci": "val"
"type": "livekit",
"livekit_service_url": "https://matrix-rtc-2.example.com/livekit/jwt"
},
{
"type": "nextgen_new_foci_type",
"props_for_nextgen_foci": "val"
}
]
```
Make sure this file is served with the correct MIME type (`application/json`).
Additionally, ensure the appropriate CORS headers are set to allow web clients
to access it across origins. For more details, refer to the
[Matrix Client-Server API: 2. Web Browser Clients](https://spec.matrix.org/latest/client-server-api/#web-browser-clients).
```
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization
```
> [!NOTE]
> Most `org.matrix.msc4143.rtc_foci` configurations will only have one entry in
> the array
## Building Element Call
> [!NOTE]
@@ -105,6 +175,7 @@ source. First, clone and install the package:
```sh
git clone https://github.com/element-hq/element-call.git
cd element-call
corepack enable
yarn
yarn build
```
@@ -164,3 +235,30 @@ federation, so as to prevent spam registrations (if you keep registrations open)
and to ensure Element Call continues to work in case any user decides to log in
to their Element Call account using the standard Element app and joins normal
rooms that Element Call cannot handle.
# 📚 Community Guides & How-Tos
Looking for real-world tips, tutorials, and experiences from the community?
Below is a collection of blog posts, walkthroughs, and how-tos created by other
self-hosters and developers working with Element Call.
> [!NOTE]
> These resources are community-created and may reflect different setups or
> versions. Use them alongside the official documentation for best results.
## 🌐 Blog Posts & Articles
- [How to resolve stuck MatrixRTC calls](https://sspaeth.de/2025/02/how-to-resolve-stuck-matrixrtc-calls/)
## 🛠️ How-Tos & Tutorials
- [MatrixRTC aka Element-call setup (Geek warning)](https://sspaeth.de/2024/11/sfu/)
- [MatrixRTC with Synology Container Manager (Docker)](https://ztfr.de/matrixrtc-with-synology-container-manager-docker/)
- [Encrypted & Scalable Video Calls: How to deploy an Element Call backend with Synapse Using Docker-Compose](https://willlewis.co.uk/blog/posts/deploy-element-call-backend-with-synapse-and-docker-compose/)
- [Element Call einrichten: Verschlüsselte Videoanrufe mit Element X und Matrix Synapse](https://www.cleveradmin.de/blog/2025/04/matrixrtc-element-call-backend-einrichten/)
## 🤝 Want to Contribute?
Have a guide or blog post you'd like to share? Open a
[PR](https://github.com/element-hq/element-call/pulls) to add it here, or drop a
link in the [#webrtc:matrix.org](https://matrix.to/#/#webrtc:matrix.org) room.

View File

@@ -0,0 +1,8 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
const val VERSION = "0.0.0"

View File

@@ -5,7 +5,7 @@ import PackageDescription
let package = Package(
name: "EmbeddedElementCall",
platforms: [.iOS(.v17_6)],
platforms: [.iOS(.v17)],
products: [
.library(
name: "EmbeddedElementCall",

View File

@@ -1,5 +1,14 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Foundation
public let appURL = Bundle.module.url(forResource: "index", withExtension: "html", subdirectory: "dist")
public let bundle = Bundle.module
public let version = "0.0.0"

View File

@@ -65,12 +65,14 @@
"debug_tile_layout_label": "Kachel-Layout debuggen",
"device_id": "Geräte-ID: {{id}}",
"duplicate_tiles_label": "Anzahl zusätzlicher Kachelkopien pro Teilnehmer",
"environment_variables": "Umgebungsvariablen",
"hostname": "Hostname: {{hostname}}",
"livekit_server_info": "LiveKit-Server Informationen",
"livekit_sfu": "LiveKit SFU: {{url}}",
"matrix_id": "Matrix-ID: {{id}}",
"show_connection_stats": "Verbindungsstatistiken anzeigen",
"show_non_member_tiles": "Kacheln für Nicht-Mitgliedermedien anzeigen",
"url_params": "URL-Parameter",
"use_new_membership_manager": "Neuen MembershipManager verwenden"
},
"disconnected_banner": "Die Verbindung zum Server wurde getrennt.",
@@ -142,9 +144,9 @@
"rageshake_sending": "Senden …",
"rageshake_sending_logs": "Sende Debug-Protokolle …",
"rageshake_sent": "Danke!",
"recaptcha_caption": "Diese Seite wird durch reCAPTCHA geschützt und es gelten Googles <2>Datenschutzerklärung</2> und <6>Nutzungsbedingungen</6>. <9></9>Mit einem Klick auf „Registrieren“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>",
"recaptcha_dismissed": "Recaptcha abgelehnt",
"recaptcha_not_loaded": "Recaptcha nicht geladen",
"recaptcha_ssla_caption": "Diese Website wird durch ReCAPTCHA geschützt, und es gelten die Google <2>Datenschutzbestimmungen</2> sowie die <6>Nutzungsbedingungen</6>.<9></9> Durch das Klicken auf \"Registrieren\" wird der <12>Software- und Dienstleistungslizenzvereinbarung (SSLA)</12> zugestimmt.",
"register": {
"passwords_must_match": "Passwörter müssen übereinstimmen",
"registering": "Registrierung …"
@@ -154,7 +156,7 @@
"register_heading": "Erstelle Dein Konto",
"return_home_button": "Zurück zur Startseite",
"room_auth_view_continue_button": "Weiter",
"room_auth_view_eula_caption": "Mit einem Klick auf „Weiter“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>",
"room_auth_view_ssla_caption": "Durch das Klicken auf \"Anruf jetzt beitreten\" wird dem <2>Software and Services License Agreement (SSLA)</2> zugestimmt.",
"screenshare_button_label": "Bildschirm teilen",
"settings": {
"audio_tab": {
@@ -200,8 +202,8 @@
"submitting": "Sende …",
"switch_camera": "Kamera wechseln",
"unauthenticated_view_body": "Noch nicht registriert? <2>Konto erstellen</2>",
"unauthenticated_view_eula_caption": "Mit einem Klick auf „Los gehts“ akzeptierst du unseren <2>Endbenutzer-Lizenzvertrag (EULA)</2>",
"unauthenticated_view_login_button": "Melde dich mit deinem Konto an",
"unauthenticated_view_ssla_caption": "Durch das Klicken auf \"Weiter\" wird dem <2>Software and Services License Agreement (SSLA)</2> zugestimmt.",
"unmute_microphone_button_label": "Mikrofon einschalten",
"version": "{{productName}} Version: {{version}}",
"video_tile": {

View File

@@ -65,12 +65,14 @@
"debug_tile_layout_label": "Debug tile layout",
"device_id": "Device ID: {{id}}",
"duplicate_tiles_label": "Number of additional tile copies per participant",
"environment_variables": "Environment variables",
"hostname": "Hostname: {{hostname}}",
"livekit_server_info": "LiveKit Server Info",
"livekit_sfu": "LiveKit SFU: {{url}}",
"matrix_id": "Matrix ID: {{id}}",
"show_connection_stats": "Show connection statistics",
"show_non_member_tiles": "Show tiles for non-member media",
"url_params": "URL parameters",
"use_new_membership_manager": "Use the new implementation of the call MembershipManager"
},
"disconnected_banner": "Connectivity to the server has been lost.",
@@ -142,9 +144,9 @@
"rageshake_sending": "Sending…",
"rageshake_sending_logs": "Sending debug logs…",
"rageshake_sent": "Thanks!",
"recaptcha_caption": "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>End User Licensing Agreement (EULA)</12>",
"recaptcha_dismissed": "Recaptcha dismissed",
"recaptcha_not_loaded": "Recaptcha not loaded",
"recaptcha_ssla_caption": "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Software and Services License Agreement (SSLA)</12>",
"register": {
"passwords_must_match": "Passwords must match",
"registering": "Registering…"
@@ -154,7 +156,7 @@
"register_heading": "Create your account",
"return_home_button": "Return to home screen",
"room_auth_view_continue_button": "Continue",
"room_auth_view_eula_caption": "By clicking \"Continue\", you agree to our <2>End User Licensing Agreement (EULA)</2>",
"room_auth_view_ssla_caption": "By clicking \"Join call now\", you agree to our <2>Software and Services License Agreement (SSLA)</2>",
"screenshare_button_label": "Share screen",
"settings": {
"audio_tab": {
@@ -200,8 +202,8 @@
"submitting": "Submitting…",
"switch_camera": "Switch camera",
"unauthenticated_view_body": "Not registered yet? <2>Create an account</2>",
"unauthenticated_view_eula_caption": "By clicking \"Go\", you agree to our <2>End User Licensing Agreement (EULA)</2>",
"unauthenticated_view_login_button": "Login to your account",
"unauthenticated_view_ssla_caption": "By clicking \"Go\", you agree to our <2>Software and Services License Agreement (SSLA)</2>",
"unmute_microphone_button_label": "Unmute microphone",
"version": "{{productName}} version: {{version}}",
"video_tile": {

View File

@@ -50,7 +50,6 @@
"rageshake_send_logs": "Enviar registros de depuración",
"rageshake_sending": "Enviando…",
"rageshake_sending_logs": "Enviando registros de depuración…",
"recaptcha_caption": "Este sitio está protegido por ReCAPTCHA y se aplican la <2>Política de Privacidad</2> y los <6>Términos de Servicio de Google.<9></9>Al hacer clic en \"Registrar\", aceptas nuestro <12>Contrato de Licencia de Usuario Final (CLUF)</12>",
"recaptcha_dismissed": "Recaptcha cancelado",
"recaptcha_not_loaded": "No se ha cargado el Recaptcha",
"register": {
@@ -60,7 +59,6 @@
"register_auth_links": "<0>¿Ya tienes una cuenta?</0><1><0>Iniciar sesión</0> o <2>Acceder como invitado</2></1>",
"register_confirm_password_label": "Confirmar contraseña",
"return_home_button": "Volver a la pantalla de inicio",
"room_auth_view_eula_caption": "Al hacer clic en \"Unirse a la llamada ahora\", aceptas nuestro <2>Contrato de Licencia de Usuario Final (CLUF)</2>",
"screenshare_button_label": "Compartir pantalla",
"settings": {
"developer_tab_title": "Desarrollador",
@@ -76,7 +74,6 @@
"star_rating_input_label_other": "{{count}} estrellas",
"submitting": "Enviando…",
"unauthenticated_view_body": "¿No estás registrado todavía? <2>Crear una cuenta</2>",
"unauthenticated_view_eula_caption": "Al hacer clic en \"Comenzar\", aceptas nuestro <2>Contrato de Licencia de Usuario Final (CLUF)</2>",
"unauthenticated_view_login_button": "Iniciar sesión en tu cuenta",
"version": "Versión: {{version}}"
}

View File

@@ -78,7 +78,6 @@
"rageshake_sending": "Saatmine…",
"rageshake_sending_logs": "Veaotsingulogide saatmine…",
"rageshake_sent": "Tänud!",
"recaptcha_caption": "Selles saidis on kasutusel ReCAPTCHA ja kehtivad Google'i <2>Privaatsuspoliitika</2> ning <6>Teenusetingimused</6>.<9></9>Klõpsides „Registreeru“, sa nõustud meie <12>Lõppkasutaja litsentsilepingu (EULA) tingimustega</12>",
"recaptcha_dismissed": "Robotilõks on vahele jäetud",
"recaptcha_not_loaded": "Robotilõks pole laetud",
"register": {
@@ -88,7 +87,6 @@
"register_auth_links": "<0>On sul juba konto?</0><1><0>Logi sisse</0> Või <2>Logi sisse külalisena</2></1>",
"register_confirm_password_label": "Kinnita salasõna",
"return_home_button": "Tagasi avalehele",
"room_auth_view_eula_caption": "Klõpsides „Liitu kõnega kohe“, nõustud sa meie <2>Lõppkasutaja litsentsilepinguga (EULA)</2>",
"screenshare_button_label": "Jaga ekraani",
"settings": {
"developer_tab_title": "Arendaja",
@@ -108,7 +106,6 @@
"stop_video_button_label": "Peata videovoog",
"submitting": "Saadan…",
"unauthenticated_view_body": "Sa pole veel registreerunud? <2>Loo kasutajakonto</2>",
"unauthenticated_view_eula_caption": "Klõpsides „Jätka“, nõustud sa meie <2>Lõppkasutaja litsentsilepinguga (EULA)</2>",
"unauthenticated_view_login_button": "Logi oma kontosse sisse",
"unmute_microphone_button_label": "Lülita mikrofon sisse",
"version": "Versioon: {{version}}"

View File

@@ -77,7 +77,6 @@
"rageshake_sending": "Envoi…",
"rageshake_sending_logs": "Envoi des journaux de débogage…",
"rageshake_sent": "Merci !",
"recaptcha_caption": "Ce site est protégé par ReCAPTCHA, la <2>politique de confidentialité</2> et les <6>conditions dutilisation</6> de Google sappliquent.<9></9>En cliquant sur « Senregistrer » vous acceptez également notre <12>Contrat de Licence Utilisateur Final (CLUF)</12>",
"recaptcha_dismissed": "Recaptcha refusé",
"recaptcha_not_loaded": "Recaptcha non chargé",
"register": {
@@ -87,7 +86,6 @@
"register_auth_links": "<0>Vous avez déjà un compte ?</0><1><0>Se connecter</0> Ou <2>Accès invité</2></1>",
"register_confirm_password_label": "Confirmer le mot de passe",
"return_home_button": "Retour à laccueil",
"room_auth_view_eula_caption": "En cliquant sur « Rejoindre lappel maintenant », vous acceptez notre <2>Contrat de Licence Utilisateur Final (CLUF)</2>",
"screenshare_button_label": "Partage décran",
"settings": {
"developer_tab_title": "Développeur",
@@ -107,7 +105,6 @@
"stop_video_button_label": "Arrêter la vidéo",
"submitting": "Envoi…",
"unauthenticated_view_body": "Pas encore de compte ? <2>En créer un</2>",
"unauthenticated_view_eula_caption": "En cliquant sur « Commencer », vous acceptez notre <2>Contrat de Licence Utilisateur Final (CLUF)</2>",
"unauthenticated_view_login_button": "Connectez vous à votre compte",
"unmute_microphone_button_label": "Allumer le microphone",
"version": "Version : {{version}}"

View File

@@ -77,7 +77,6 @@
"rageshake_sending": "Mengirimkan…",
"rageshake_sending_logs": "Mengirimkan catatan pengawakutuan…",
"rageshake_sent": "Terima kasih!",
"recaptcha_caption": "Situs ini dilindungi oleh reCAPTCHA dan <2>Kebijakan Privasi</2> dan <6>Ketentuan Layanan</6> Google berlaku.<9></9>Dengan mengeklik \"Daftar\", Anda menyetujui <12>Perjanjian Lisensi Pengguna Akhir (EULA)</12> kami",
"recaptcha_dismissed": "Recaptcha ditutup",
"recaptcha_not_loaded": "Recaptcha tidak dimuat",
"register": {
@@ -87,7 +86,6 @@
"register_auth_links": "<0>Sudah punya akun?</0><1><0>Masuk</0> Atau <2>Akses sebagai tamu</2></1>",
"register_confirm_password_label": "Konfirmasi kata sandi",
"return_home_button": "Kembali ke layar beranda",
"room_auth_view_eula_caption": "Dengan mengeklik \"Bergabung ke panggilan sekarang\", Anda menyetujui <2>Perjanjian Lisensi Pengguna Akhir (EULA)</2> kami",
"screenshare_button_label": "Bagikan layar",
"settings": {
"developer_tab_title": "Pengembang",
@@ -107,7 +105,6 @@
"stop_video_button_label": "Matikan video",
"submitting": "Mengirim…",
"unauthenticated_view_body": "Belum terdaftar? <2>Buat sebuah akun</2>",
"unauthenticated_view_eula_caption": "Dengan mengeklik \"Bergabung\", Anda menyetujui <2>Perjanjian Lisensi Pengguna Akhir (EULA)</2>",
"unauthenticated_view_login_button": "Masuk ke akun Anda",
"unmute_microphone_button_label": "Nyalakan mikrofon",
"version": "Versi: {{version}}"

View File

@@ -75,7 +75,6 @@
"rageshake_sending": "Invio…",
"rageshake_sending_logs": "Invio dei registri di debug…",
"rageshake_sent": "Grazie!",
"recaptcha_caption": "Questo sito è protetto da ReCAPTCHA e si applicano l'<2>informativa sulla privacy</2> e i <6>termini di servizio</6> di Google.<9></9>Cliccando \"Registra\", accetti il nostro <12>accordo di licenza con l'utente finale (EULA)</12>",
"recaptcha_dismissed": "Recaptcha annullato",
"recaptcha_not_loaded": "Recaptcha non caricato",
"register": {
@@ -85,7 +84,6 @@
"register_auth_links": "<0>Hai già un profilo?</0><1><0>Accedi</0> o <2>Accedi come ospite</2></1>",
"register_confirm_password_label": "Conferma password",
"return_home_button": "Torna alla schermata di iniziale",
"room_auth_view_eula_caption": "Cliccando \"Entra in chiamata ora\", accetti il nostro <2>accordo di licenza con l'utente finale (EULA)</2>",
"screenshare_button_label": "Condividi schermo",
"settings": {
"developer_tab_title": "Sviluppatore",
@@ -104,7 +102,6 @@
"stop_video_button_label": "Ferma video",
"submitting": "Invio…",
"unauthenticated_view_body": "Non hai ancora un profilo? <2>Creane uno</2>",
"unauthenticated_view_eula_caption": "Cliccando \"Vai\", accetti il nostro <2>accordo di licenza con l'utente finale (EULA)</2>",
"unauthenticated_view_login_button": "Accedi al tuo profilo",
"unmute_microphone_button_label": "Riaccendi il microfono",
"version": "Versione: {{version}}"

View File

@@ -57,7 +57,6 @@
"rageshake_sending": "Nosūta…",
"rageshake_sending_logs": "Nosūta atkļūdošanas žurnāla ierakstus…",
"rageshake_sent": "Paldies!",
"recaptcha_caption": "Šo vietni aizsargā ReCAPTCHA, un ir attiecināmi Google <2>privātuma nosacījumi</2> un <6>pakalpojuma noteikumi</6>.<9></9>Klikšķināšana uz \"Reģistrēties\" sniedz piekrišanu mūsu <12>galalietotāja licencēšanas nolīgumam (GLLN)</12>",
"recaptcha_dismissed": "ReCaptcha atmesta",
"recaptcha_not_loaded": "ReCaptcha nav ielādēta",
"register": {
@@ -67,7 +66,6 @@
"register_auth_links": "<0>Jau ir konts?</0><1><0>Pieteikties</0> vai <2>Piekļūt kā viesim</2></1>",
"register_confirm_password_label": "Apstiprināt paroli",
"return_home_button": "Atgriezties sākuma ekrānā",
"room_auth_view_eula_caption": "Klikšķināšana uz \"Pievienoties zvanam tagad\" apliecina piekrišanu mūsu <2>galalietotāja licencēšanas nolīgumam (GLLN)</2>",
"screenshare_button_label": "Kopīgot ekrānu",
"settings": {
"developer_tab_title": "Izstrādātājs",
@@ -83,7 +81,6 @@
"star_rating_input_label_other": "{{count}} zvaigznes",
"submitting": "Iesniedz…",
"unauthenticated_view_body": "Vēl neesi reģistrējies? <2>Izveidot kontu</2>",
"unauthenticated_view_eula_caption": "Klikšķināšana uz \"Aiziet\" apliecina piekrišanu mūsu <2>galalietotāja licencēšanas nolīgumam (GLLN)</2>",
"unauthenticated_view_login_button": "Pieteikties kontā",
"version": "Versija: {{version}}"
}

View File

@@ -80,7 +80,6 @@
"rageshake_sending": "Wysyłanie…",
"rageshake_sending_logs": "Wysyłanie dzienników debugowania…",
"rageshake_sent": "Dziękujemy!",
"recaptcha_caption": "Ta witryna jest chroniona przez ReCAPTCHA, więc obowiązują <2>Polityka prywatności</2> i <6>Warunki usług</6> Google. Klikając \"Zarejestruj\", zgadzasz się na naszą <12>Umowę licencyjną (EULA)</12>",
"recaptcha_dismissed": "Recaptcha odrzucona",
"recaptcha_not_loaded": "Recaptcha nie została załadowana",
"register": {
@@ -90,7 +89,6 @@
"register_auth_links": "<0>Masz już konto?</0><1><0>Zaloguj się</0> lub <2>Dołącz jako gość</2></1>",
"register_confirm_password_label": "Potwierdź hasło",
"return_home_button": "Powróć do strony głównej",
"room_auth_view_eula_caption": "Klikając \"Dołącz teraz do rozmowy\", zgadzasz się na naszą <2>Umowę licencyjną (EULA)</2>",
"screenshare_button_label": "Udostępnij ekran",
"settings": {
"developer_tab_title": "Programista",
@@ -110,7 +108,6 @@
"stop_video_button_label": "Zakończ wideo",
"submitting": "Wysyłanie…",
"unauthenticated_view_body": "Nie masz konta? <2>Utwórz je</2>",
"unauthenticated_view_eula_caption": "Klikając \"Przejdź\", zgadzasz się na naszą <2>Umowę licencyjną (EULA)</2>",
"unauthenticated_view_login_button": "Zaloguj się do swojego konta",
"unmute_microphone_button_label": "Odcisz mikrofon",
"version": "Wersja: {{version}}"

View File

@@ -117,7 +117,6 @@
"rageshake_sending": "Trimiterea...",
"rageshake_sending_logs": "Trimiterea jurnalelor de depanare...",
"rageshake_sent": "Multumesc!",
"recaptcha_caption": "Acest site este protejat de reCAPTCHA și se aplică Politica de <2> confidențialitate Google </2> și <6> Termenii și condițiile. </6> <9></9>Făcând clic pe „Înregistrare”, sunteți de acord cu Acordul nostru de licențiere pentru utilizatorul <12> final (EULA) </12>",
"recaptcha_dismissed": "Recaptcha a fost respins",
"recaptcha_not_loaded": "Recaptcha nu a fost încărcat",
"register": {
@@ -129,7 +128,6 @@
"register_heading": "Creează-ți contul",
"return_home_button": "Reveniți la ecranul de pornire",
"room_auth_view_continue_button": "Continuă",
"room_auth_view_eula_caption": "Făcând clic pe „Continuați”, sunteți de acord cu Acordul nostru de licențiere pentru utilizatorul <2> final (EULA) </2>",
"screenshare_button_label": "Partajare ecran",
"settings": {
"audio_tab": {
@@ -158,7 +156,6 @@
"submitting": "Trimiterea...",
"switch_camera": "Comutați camera",
"unauthenticated_view_body": "Nu sunteți încă înregistrat? <2>Creați un cont </2>",
"unauthenticated_view_eula_caption": "Făcând clic pe „Go”, sunteți de acord cu Acordul nostru de licențiere pentru utilizatorul <2> final (EULA) </2>",
"unauthenticated_view_login_button": "Conectați-vă la contul dvs.",
"unmute_microphone_button_label": "Anulează microfonul",
"version": "{{productName}}Versiune: {{version}}",

View File

@@ -78,7 +78,6 @@
"rageshake_sending": "Odosielanie…",
"rageshake_sending_logs": "Odosielanie záznamov o ladení…",
"rageshake_sent": "Ďakujeme!",
"recaptcha_caption": "Táto stránka je chránená systémom ReCAPTCHA a platia na ňu <2>Pravidlá ochrany osobných údajov spoločnosti Google</2> a <6>Podmienky poskytovania služieb</6>.<9></9>Kliknutím na tlačidlo \"Registrovať sa\" súhlasíte s našou <12>Licenčnou zmluvou s koncovým používateľom (EULA)</12>",
"recaptcha_dismissed": "Recaptcha zamietnutá",
"recaptcha_not_loaded": "Recaptcha sa nenačítala",
"register": {
@@ -88,7 +87,6 @@
"register_auth_links": "<0>Už máte konto?</0><1><0>Prihláste sa</0> Alebo <2>Prihlásiť sa ako hosť</2></1>",
"register_confirm_password_label": "Potvrdiť heslo",
"return_home_button": "Návrat na domovskú obrazovku",
"room_auth_view_eula_caption": "Kliknutím na \"Pripojiť sa k hovoru teraz\" súhlasíte s našou <2>Licenčnou zmluvou s koncovým používateľom (EULA)</2>",
"screenshare_button_label": "Zdieľať obrazovku",
"settings": {
"developer_tab_title": "Vývojár",
@@ -108,7 +106,6 @@
"stop_video_button_label": "Zastaviť video",
"submitting": "Odosielanie…",
"unauthenticated_view_body": "Ešte nie ste zaregistrovaný? <2>Vytvorte si účet</2>",
"unauthenticated_view_eula_caption": "Kliknutím na tlačidlo \"Prejsť\" vyjadrujete súhlas s našou <2>Licenčnou zmluvou s koncovým používateľom (EULA)</2>",
"unauthenticated_view_login_button": "Prihláste sa do svojho konta",
"unmute_microphone_button_label": "Zrušiť stlmenie mikrofónu",
"version": "Verzia: {{version}}"

View File

@@ -80,7 +80,6 @@
"rageshake_sending": "Надсилання…",
"rageshake_sending_logs": "Надсилання журналу налагодження…",
"rageshake_sent": "Дякуємо!",
"recaptcha_caption": "Цей сайт захищений ReCAPTCHA і до нього застосовується <2>Політика приватності</2> і <6>Умови надання послуг</6> Google.<9></9>Натискаючи \"Зареєструватися\", ви погоджуєтеся з нашою <12>Ліцензійною угодою з кінцевим користувачем (EULA)</12>",
"recaptcha_dismissed": "Recaptcha не пройдено",
"recaptcha_not_loaded": "Recaptcha не завантажено",
"register": {
@@ -90,7 +89,6 @@
"register_auth_links": "<0>Уже маєте обліковий запис?</0><1><0>Увійти</0> Or <2>Отримати доступ як гість</2></1>",
"register_confirm_password_label": "Підтвердити пароль",
"return_home_button": "Повернутися на екран домівки",
"room_auth_view_eula_caption": "Натискаючи \"Приєднатися до виклику зараз\", ви погоджуєтеся з нашою <2>Ліцензійною угодою з кінцевим користувачем (EULA)</2>",
"screenshare_button_label": "Поділитися екраном",
"settings": {
"developer_tab_title": "Розробнику",
@@ -110,7 +108,6 @@
"stop_video_button_label": "Зупинити відео",
"submitting": "Надсилання…",
"unauthenticated_view_body": "Ще не зареєстровані? <2>Створіть обліковий запис</2>",
"unauthenticated_view_eula_caption": "Натискаючи \"Далі\", ви погоджуєтеся з нашою <2>Ліцензійною угодою з кінцевим користувачем (EULA)</2>",
"unauthenticated_view_login_button": "Увійдіть до свого облікового запису",
"unmute_microphone_button_label": "Увімкнути мікрофон",
"version": "Версія: {{version}}"

View File

@@ -73,7 +73,6 @@
"rageshake_sending": "正在发送……",
"rageshake_sending_logs": "正在发送调试日志……",
"rageshake_sent": "谢谢!",
"recaptcha_caption": "该站点受 ReCAPTCHA 保护适用于Google的 <2>隐私政策</2>和 <6>服务条款</6>。 <9></9>点击 \"注册\",即表示您同意我们的 <12>最终用户许可协议 (EULA)</12>",
"recaptcha_dismissed": "人机验证失败",
"recaptcha_not_loaded": "recaptcha未加载",
"register": {
@@ -83,7 +82,6 @@
"register_auth_links": "<0>已有账户?</0><1><0>登录</0> Or <2>以访客身份继续</2></1>",
"register_confirm_password_label": "确认密码",
"return_home_button": "返回主页",
"room_auth_view_eula_caption": "点击 \"加入通话\",即表示您同意我们的<2>最终用户许可协议 (EULA)</2>",
"screenshare_button_label": "屏幕共享",
"settings": {
"developer_tab_title": "开发者",
@@ -103,7 +101,6 @@
"stop_video_button_label": "停止视频",
"submitting": "提交中…",
"unauthenticated_view_body": "还没有注册? <2>创建账户<2>",
"unauthenticated_view_eula_caption": "点击 \"开始\",即表示您同意我们的<2>最终用户许可协议 (EULA)</2>",
"unauthenticated_view_login_button": "登录你的账户",
"unmute_microphone_button_label": "取消麦克风静音",
"version": "版本:{{version}}"

View File

@@ -80,7 +80,6 @@
"rageshake_sending": "傳送中…",
"rageshake_sending_logs": "傳送除錯記錄檔中…",
"rageshake_sent": "感謝!",
"recaptcha_caption": "此網站被 ReCAPTCHA 保護,並適用 Google 的<2>隱私權政策</2>與<6>服務條款</6>。<9></9>點擊「註冊」即表示您同意我們的<12>終端使用者授權協議 (EULA)</12>",
"recaptcha_dismissed": "略過驗證碼",
"recaptcha_not_loaded": "驗證碼未載入",
"register": {
@@ -90,7 +89,6 @@
"register_auth_links": "<0>已經有帳號?</0><1><0>登入</0> 或<2>以訪客身份登入</2></1>",
"register_confirm_password_label": "確認密碼",
"return_home_button": "回到首頁",
"room_auth_view_eula_caption": "點擊「立刻加入通話」即表示您同意我們的<2>終端使用者授權協議 (EULA)</2>",
"screenshare_button_label": "分享畫面",
"settings": {
"developer_tab_title": "開發者",
@@ -110,7 +108,6 @@
"stop_video_button_label": "停止影片",
"submitting": "正在遞交……",
"unauthenticated_view_body": "還沒註冊嗎?<2>建立帳號</2>",
"unauthenticated_view_eula_caption": "點擊「前往」即表示您同意我們的<2>終端使用者授權協議 (EULA)</2>",
"unauthenticated_view_login_button": "登入您的帳號",
"unmute_microphone_button_label": "將麥克風取消靜音",
"version": "版本: {{version}}"

View File

@@ -23,7 +23,9 @@
"test:coverage": "vitest --coverage",
"backend": "docker-compose -f dev-backend-docker-compose.yml up",
"test:playwright": "playwright test",
"test:playwright:open": "yarn test:playwright --ui"
"test:playwright:open": "yarn test:playwright --ui",
"links:enable": "mv .links.disabled.yaml .links.yaml & touch .links.yaml",
"links:disable": "mv .links.yaml .links.disabled.yaml"
},
"devDependencies": {
"@babel/core": "^7.16.5",
@@ -95,7 +97,7 @@
"i18next-parser": "^9.1.0",
"jsdom": "^26.0.0",
"knip": "^5.27.2",
"livekit-client": "2.9.1",
"livekit-client": "2.10.0",
"lodash-es": "^4.17.21",
"loglevel": "^1.9.1",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686",
@@ -130,5 +132,6 @@
"resolutions": {
"@livekit/components-core/rxjs": "^7.8.1",
"matrix-widget-api": "1.11.0"
}
},
"packageManager": "yarn@4.7.0"
}

View File

@@ -51,6 +51,17 @@ services:
networks:
- ecbackend
element-web:
image: ghcr.io/element-hq/element-web:develop
volumes:
- ./backend/ew.test.config.json:/app/config.json
environment:
ELEMENT_WEB_PORT: 81
ports:
- "8081:81"
networks:
- ecbackend
synapse:
hostname: homeserver
image: docker.io/matrixdotorg/synapse:latest

View File

@@ -0,0 +1,185 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type Page, test, expect, type JSHandle } from "@playwright/test";
import type { MatrixClient } from "matrix-js-sdk";
export type UserBaseFixture = {
mxId: string;
page: Page;
clientHandle: JSHandle<MatrixClient>;
};
export type BaseWidgetSetup = {
brooks: UserBaseFixture;
whistler: UserBaseFixture;
};
export interface MyFixtures {
asWidget: BaseWidgetSetup;
}
const PASSWORD = "foobarbaz1!";
// Minimal config.json for the local element-web instance
const CONFIG_JSON = {
default_server_config: {
"m.homeserver": {
base_url: "http://synapse.localhost:8008",
server_name: "synapse.localhost",
},
},
element_call: {
participant_limit: 8,
brand: "Element Call",
},
// The default language is set here for test consistency
setting_defaults: {
language: "en-GB",
feature_group_calls: true,
},
// the location tests want a map style url.
map_style_url:
"https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
features: {
// We don't want to go through the feature announcement during the e2e test
feature_release_announcement: false,
feature_element_call_video_rooms: true,
feature_video_rooms: true,
feature_group_calls: true,
},
};
/**
* Set the Element Call URL in the dev tool settings using `window.mxSettingsStore` via `page.evaluate`.
* @param page
*/
async function setDevToolElementCallDevUrl(page: Page): Promise<void> {
await page.evaluate(() => {
window.mxSettingsStore.setValue(
"Developer.elementCallUrl",
null,
"device",
"https://localhost:3000/room",
);
});
}
export const widgetTest = test.extend<MyFixtures>({
asWidget: async ({ browser, context }, pUse) => {
await context.route(`http://localhost:8081/config.json*`, async (route) => {
await route.fulfill({ json: CONFIG_JSON });
});
const userA = `brooks_${Date.now()}`;
const userB = `whistler_${Date.now()}`;
const user1Context = await browser.newContext({
reducedMotion: "reduce",
});
const ewPage1 = await user1Context.newPage();
// Register the first user
await ewPage1.goto("http://localhost:8081/#/welcome");
await ewPage1.getByRole("link", { name: "Create Account" }).click();
await ewPage1.getByRole("textbox", { name: "Username" }).fill(userA);
await ewPage1
.getByRole("textbox", { name: "Password", exact: true })
.fill(PASSWORD);
await ewPage1.getByRole("textbox", { name: "Confirm password" }).click();
await ewPage1
.getByRole("textbox", { name: "Confirm password" })
.fill(PASSWORD);
await ewPage1.getByRole("button", { name: "Register" }).click();
await expect(
ewPage1.getByRole("heading", { name: `Welcome ${userA}` }),
).toBeVisible();
await setDevToolElementCallDevUrl(ewPage1);
const brooksClientHandle = await ewPage1.evaluateHandle(() =>
window.mxMatrixClientPeg.get(),
);
const brooksMxId = (await brooksClientHandle.evaluate((cli) => {
return cli.getUserId();
}, brooksClientHandle))!;
const user2Context = await browser.newContext({
reducedMotion: "reduce",
});
const ewPage2 = await user2Context.newPage();
// Register the second user
await ewPage2.goto("http://localhost:8081/#/welcome");
await ewPage2.getByRole("link", { name: "Create Account" }).click();
await ewPage2.getByRole("textbox", { name: "Username" }).fill(userB);
await ewPage2
.getByRole("textbox", { name: "Password", exact: true })
.fill(PASSWORD);
await ewPage2.getByRole("textbox", { name: "Confirm password" }).click();
await ewPage2
.getByRole("textbox", { name: "Confirm password" })
.fill(PASSWORD);
await ewPage2.getByRole("button", { name: "Register" }).click();
await expect(
ewPage2.getByRole("heading", { name: `Welcome ${userB}` }),
).toBeVisible();
await setDevToolElementCallDevUrl(ewPage2);
const whistlerClientHandle = await ewPage2.evaluateHandle(() =>
window.mxMatrixClientPeg.get(),
);
const whistlerMxId = (await whistlerClientHandle.evaluate((cli) => {
return cli.getUserId();
}, whistlerClientHandle))!;
// Invite the second user
await ewPage1.getByRole("button", { name: "Add room" }).click();
await ewPage1.getByText("New room").click();
await ewPage1.getByRole("textbox", { name: "Name" }).fill("Welcome Room");
await ewPage1.getByRole("button", { name: "Create room" }).click();
await expect(ewPage1.getByText("You created this room.")).toBeVisible();
await expect(ewPage1.getByText("Encryption enabled")).toBeVisible();
await ewPage1
.getByRole("button", { name: "Invite to this room", exact: true })
.click();
await expect(
ewPage1.getByRole("heading", { name: "Invite to Welcome Room" }),
).toBeVisible();
await ewPage1.getByRole("textbox").fill(whistlerMxId);
await ewPage1.getByRole("textbox").click();
await ewPage1.getByRole("button", { name: "Invite" }).click();
// Accept the invite
await expect(
ewPage2.getByRole("treeitem", { name: "Welcome Room" }),
).toBeVisible();
await ewPage2.getByRole("treeitem", { name: "Welcome Room" }).click();
await ewPage2.getByRole("button", { name: "Accept" }).click();
await expect(
ewPage2.getByRole("main").getByRole("heading", { name: "Welcome Room" }),
).toBeVisible();
// Renamed use to pUse, as a workaround for eslint error that was thinking this use was a react use.
await pUse({
brooks: {
mxId: brooksMxId,
page: ewPage1,
clientHandle: brooksClientHandle,
},
whistler: {
mxId: whistlerMxId,
page: ewPage2,
clientHandle: whistlerClientHandle,
},
});
},
});

24
playwright/global.d.ts vendored Normal file
View File

@@ -0,0 +1,24 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import type * as Matrix from "matrix-js-sdk";
declare global {
interface Window {
mxMatrixClientPeg: {
get(): Matrix.MatrixClient;
};
mxSettingsStore: {
setValue: (
settingKey: string,
room: string | null,
level: string,
setting: string,
) => void;
};
}
}

View File

@@ -0,0 +1,97 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { expect, test } from "@playwright/test";
import { widgetTest } from "../fixtures/widget-user.ts";
widgetTest("Start a new call as widget", async ({ asWidget, browserName }) => {
test.skip(
browserName === "firefox",
"This test is not working on firefox, after hangup brooks is locked in a strange state with a blank widget",
);
const { brooks, whistler } = asWidget;
await expect(
brooks.page.getByRole("button", { name: "Video call" }),
).toBeVisible();
await brooks.page.getByRole("button", { name: "Video call" }).click();
await expect(
brooks.page.getByRole("menuitem", { name: "Legacy Call" }),
).toBeVisible();
await expect(
brooks.page.getByRole("menuitem", { name: "Element Call" }),
).toBeVisible();
await brooks.page.getByRole("menuitem", { name: "Element Call" }).click();
await expect(
brooks.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("lobby_joinCall"),
).toBeVisible();
await brooks.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("lobby_joinCall")
.click();
// Check the join indicator on the room list
await expect(
brooks.page.locator("div").filter({ hasText: /^Joined • 1$/ }),
).toBeVisible();
// Join from the other side
await expect(whistler.page.getByText("Video call started")).toBeVisible();
await expect(
whistler.page.getByRole("button", { name: "Join" }),
).toBeVisible();
await whistler.page.getByRole("button", { name: "Join" }).click();
await expect(
whistler.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("lobby_joinCall"),
).toBeVisible();
await whistler.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("lobby_joinCall")
.click();
await expect(
whistler.page.locator("div").filter({ hasText: /^Joined • 2$/ }),
).toBeVisible();
await expect(
brooks.page.locator("div").filter({ hasText: /^Joined • 2$/ }),
).toBeVisible();
// Whistler leaves
await whistler.page.waitForTimeout(1000);
await whistler.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("incall_leave")
.click();
// Brooks leaves
await brooks.page
.locator('iframe[title="Element Call"]')
.contentFrame()
.getByTestId("incall_leave")
.click();
await expect(whistler.page.locator(".mx_BasicMessageComposer")).toBeVisible();
await expect(brooks.page.locator(".mx_BasicMessageComposer")).toBeVisible();
});

View File

@@ -48,6 +48,20 @@
"groupName": "Vaul",
"matchDepNames": ["vaul"],
"prHeader": "Please review modals on mobile for visual regressions."
},
{
"groupName": "bundled element-call dependencies",
"matchPackageNames": [
"com.vanniktech.maven.publish",
"com.android.library",
"com.android.tools.build",
"gradle"
]
},
{
"groupName": "Yarn",
"matchPackageNames": ["yarn"],
"extends": ["schedule:weekly"]
}
],
"semanticCommits": "disabled",

View File

@@ -4,5 +4,6 @@ set -ex
export VITE_APP_VERSION=$(git describe --tags --abbrev=0)
corepack enable
yarn install
yarn run build

View File

@@ -5,7 +5,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import "matrix-js-sdk/src/@types/global";
import { type setLogLevel as setLKLogLevel } from "livekit-client";
import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat";

View File

@@ -11,7 +11,7 @@ import {
} from "../reactions";
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
declare module "matrix-js-sdk/src/types" {
declare module "matrix-js-sdk/lib/types" {
export interface TimelineEvents {
[ElementCallReactionEventType]: ECallReactionEventContent;
}

View File

@@ -9,7 +9,7 @@ import { type FC, type JSX, Suspense, useEffect, useState } from "react";
import { BrowserRouter, Route, useLocation, Routes } from "react-router-dom";
import * as Sentry from "@sentry/react";
import { TooltipProvider } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { HomePage } from "./home/HomePage";
import { LoginPage } from "./auth/LoginPage";

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { afterEach, expect, test, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type MatrixClient } from "matrix-js-sdk";
import { type FC, type PropsWithChildren } from "react";
import { ClientContextProvider } from "./ClientContext";

View File

@@ -13,7 +13,7 @@ import {
useEffect,
} from "react";
import { Avatar as CompoundAvatar } from "@vector-im/compound-web";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type MatrixClient } from "matrix-js-sdk";
import { useClientState } from "./ClientContext";

View File

@@ -17,9 +17,9 @@ import {
type JSX,
} from "react";
import { useNavigate } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger";
import { type ISyncStateData, type SyncState } from "matrix-js-sdk/src/sync";
import { ClientEvent, type MatrixClient } from "matrix-js-sdk/src/client";
import { logger } from "matrix-js-sdk/lib/logger";
import { type ISyncStateData, type SyncState } from "matrix-js-sdk/lib/sync";
import { ClientEvent, type MatrixClient } from "matrix-js-sdk";
import type { WidgetApi } from "matrix-widget-api";
import { ErrorPage } from "./FullScreenView";
@@ -50,7 +50,7 @@ export type ValidClientState = {
reactions: boolean;
thumbnails: boolean;
};
setClient: (params?: SetClientParams) => void;
setClient: (client: MatrixClient, session: Session) => void;
};
export type AuthenticatedClient = {
@@ -65,11 +65,6 @@ export type ErrorState = {
error: Error;
};
export type SetClientParams = {
client: MatrixClient;
session: Session;
};
const ClientContext = createContext<ClientState | undefined>(undefined);
export const ClientContextProvider = ClientContext.Provider;
@@ -79,7 +74,7 @@ export const useClientState = (): ClientState | undefined =>
export function useClient(): {
client?: MatrixClient;
setClient?: (params?: SetClientParams) => void;
setClient?: (client: MatrixClient, session: Session) => void;
} {
let client;
let setClient;
@@ -96,7 +91,7 @@ export function useClient(): {
// Plain representation of the `ClientContext` as a helper for old components that expected an object with multiple fields.
export function useClientLegacy(): {
client?: MatrixClient;
setClient?: (params?: SetClientParams) => void;
setClient?: (client: MatrixClient, session: Session) => void;
passwordlessUser: boolean;
loading: boolean;
authenticated: boolean;
@@ -160,7 +155,11 @@ export const ClientProvider: FC<Props> = ({ children }) => {
initializing.current = true;
loadClient()
.then(setInitClientState)
.then((initResult) => {
setInitClientState(initResult);
if (PosthogAnalytics.instance.isEnabled())
PosthogAnalytics.instance.startListeningToSettingsChanges();
})
.catch((err) => logger.error(err))
.finally(() => (initializing.current = false));
}, []);
@@ -196,24 +195,20 @@ export const ClientProvider: FC<Props> = ({ children }) => {
);
const setClient = useCallback(
(clientParams?: SetClientParams) => {
(client: MatrixClient, session: Session) => {
const oldClient = initClientState?.client;
const newClient = clientParams?.client;
if (oldClient && oldClient !== newClient) {
if (oldClient && oldClient !== client) {
oldClient.stopClient();
}
if (clientParams) {
saveSession(clientParams.session);
setInitClientState({
widgetApi: null,
client: clientParams.client,
passwordlessUser: clientParams.session.passwordlessUser,
});
} else {
clearSession();
setInitClientState(null);
}
saveSession(session);
setInitClientState({
widgetApi: null,
client,
passwordlessUser: session.passwordlessUser,
});
if (PosthogAnalytics.instance.isEnabled())
PosthogAnalytics.instance.startListeningToSettingsChanges();
},
[initClientState?.client],
);
@@ -229,6 +224,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
clearSession();
setInitClientState(null);
await navigate("/");
PosthogAnalytics.instance.logout();
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Guest);
}, [navigate, initClientState?.client]);

View File

@@ -15,7 +15,7 @@ import {
type ReactElement,
} from "react";
import { useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { RageshakeButton } from "./settings/RageshakeButton";
import styles from "./ErrorView.module.css";

View File

@@ -9,7 +9,7 @@ import { type FC, type ReactElement, type ReactNode, useEffect } from "react";
import classNames from "classnames";
import { useTranslation } from "react-i18next";
import * as Sentry from "@sentry/react";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { Header, HeaderLogo, LeftNav, RightNav } from "./Header";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { IndexedDBStoreWorker } from "matrix-js-sdk/src/indexeddb-worker";
import { IndexedDBStoreWorker } from "matrix-js-sdk/lib/indexeddb-worker";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const remoteWorker = new IndexedDBStoreWorker((self as any).postMessage);

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { useMemo } from "react";
import { useLocation } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { Config } from "./config/Config";
import { type EncryptionSystem } from "./e2ee/sharedKeyManagement";

View File

@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { type FC, useCallback, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { useClientLegacy } from "./ClientContext";
import { useProfile } from "./profile/useProfile";

View File

@@ -10,9 +10,9 @@ import posthog, {
type PostHog,
type Properties,
} from "posthog-js";
import { logger } from "matrix-js-sdk/src/logger";
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Buffer } from "buffer";
import { logger } from "matrix-js-sdk/lib/logger";
import { type MatrixClient } from "matrix-js-sdk";
import { type Subscription } from "rxjs";
import { widget } from "../widget";
import {
@@ -96,6 +96,7 @@ export class PosthogAnalytics {
private anonymity = Anonymity.Disabled;
private platformSuperProperties = {};
private registrationType: RegistrationType = RegistrationType.Guest;
private optInListener: Subscription | null = null;
public static hasInstance(): boolean {
return Boolean(this.internalInstance);
@@ -144,7 +145,6 @@ export class PosthogAnalytics {
);
this.enabled = false;
}
this.startListeningToSettingsChanges(); // Triggers maybeIdentifyUser
}
private sanitizeProperties = (
@@ -295,7 +295,7 @@ export class PosthogAnalytics {
const posthogIdMaterial = "ec" + accountAnalyticsId + client.getUserId();
const bufferForPosthogId = await crypto.subtle.digest(
"sha-256",
Buffer.from(posthogIdMaterial, "utf-8"),
new TextEncoder().encode(posthogIdMaterial),
);
const view = new Int32Array(bufferForPosthogId);
return Array.from(view)
@@ -326,6 +326,8 @@ export class PosthogAnalytics {
if (this.enabled) {
this.posthog.reset();
}
this.optInListener?.unsubscribe();
this.optInListener = null;
this.setAnonymity(Anonymity.Disabled);
}
@@ -404,7 +406,7 @@ export class PosthogAnalytics {
}
}
private startListeningToSettingsChanges(): void {
public startListeningToSettingsChanges(): void {
// Listen to account data changes from sync so we can observe changes to relevant flags and update.
// This is called -
// * On page load, when the account data is first received by sync
@@ -413,7 +415,7 @@ export class PosthogAnalytics {
// * When the user changes their preferences on this device
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
optInAnalytics.value$.subscribe((optIn) => {
this.optInListener ??= optInAnalytics.value$.subscribe((optIn) => {
this.setAnonymity(optIn ? Anonymity.Pseudonymous : Anonymity.Disabled);
this.maybeIdentifyUser().catch(() =>
logger.log("Could not identify user"),

View File

@@ -6,8 +6,8 @@ Please see LICENSE in the repository root for full details.
*/
import { type DisconnectReason } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
import { logger } from "matrix-js-sdk/lib/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
import {
type IPosthogEvent,

View File

@@ -11,7 +11,7 @@ import {
type Span,
} from "@opentelemetry/sdk-trace-base";
import { hrTimeToMilliseconds } from "@opentelemetry/core";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { PosthogAnalytics } from "./PosthogAnalytics";

View File

@@ -53,7 +53,7 @@ export const LoginPage: FC = () => {
return;
}
setClient({ client, session });
setClient(client, session);
const locationState = location.state;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@@ -16,9 +16,9 @@ import {
} from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { captureException } from "@sentry/react";
import { sleep } from "matrix-js-sdk/src/utils";
import { sleep } from "matrix-js-sdk/lib/utils";
import { Trans, useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { Button, Text } from "@vector-im/compound-web";
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
@@ -95,7 +95,7 @@ export const RegisterPage: FC = () => {
}
}
setClient?.({ client: newClient, session });
setClient?.(newClient, session);
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
};
@@ -204,7 +204,7 @@ export const RegisterPage: FC = () => {
/>
</FieldRow>
<Text size="sm">
<Trans i18nKey="recaptcha_caption">
<Trans i18nKey="recaptcha_ssla_caption">
This site is protected by ReCAPTCHA and the Google{" "}
<ExternalLink href="https://www.google.com/policies/privacy/">
Privacy Policy
@@ -216,8 +216,8 @@ export const RegisterPage: FC = () => {
apply.
<br />
By clicking "Register", you agree to our{" "}
<ExternalLink href={Config.get().eula}>
End User Licensing Agreement (EULA)
<ExternalLink href={Config.get().ssla}>
Software and Services License Agreement (SSLA)
</ExternalLink>
</Trans>
</Text>

View File

@@ -6,12 +6,12 @@ Please see LICENSE in the repository root for full details.
*/
import { useCallback } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { InteractiveAuth } from "matrix-js-sdk";
import {
createClient,
type LoginResponse,
type MatrixClient,
} from "matrix-js-sdk/src/matrix";
} from "matrix-js-sdk";
import { initClient } from "../utils/matrix";
import { type Session } from "../ClientContext";

View File

@@ -6,13 +6,13 @@ Please see LICENSE in the repository root for full details.
*/
import { useState, useEffect, useCallback, useRef } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { InteractiveAuth } from "matrix-js-sdk";
import {
createClient,
type MatrixClient,
type RegisterResponse,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
} from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/lib/logger";
import { initClient } from "../utils/matrix";
import { type Session } from "../ClientContext";

View File

@@ -6,9 +6,9 @@ Please see LICENSE in the repository root for full details.
*/
import { useEffect, useCallback, useRef, useState } from "react";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/lib/randomstring";
import { useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { translatedError } from "../TranslatedError";
declare global {

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/
import { useCallback } from "react";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/lib/randomstring";
import { useClient } from "../ClientContext";
import { useInteractiveRegistration } from "../auth/useInteractiveRegistration";
@@ -47,7 +47,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
recaptchaResponse,
true,
);
setClient({ client, session });
setClient(client, session);
} catch (e) {
reset();
throw e;

View File

@@ -10,7 +10,7 @@ import { expect, test } from "vitest";
import { TooltipProvider } from "@vector-im/compound-web";
import { userEvent } from "@testing-library/user-event";
import { type ReactNode } from "react";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
import { ReactionToggleButton } from "./ReactionToggleButton";
import { ElementCallReactionEventType } from "../reactions";

View File

@@ -22,7 +22,7 @@ import {
useState,
} from "react";
import { useTranslation } from "react-i18next";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import classNames from "classnames";
import { useObservableState } from "observable-hooks";
import { map } from "rxjs";

View File

@@ -77,9 +77,9 @@ export interface ConfigOptions {
};
/**
* A link to the end-user license agreement (EULA)
* A link to the software and services license agreement (SSLA)
*/
eula?: string;
ssla?: string;
media_devices?: {
/**
@@ -134,7 +134,7 @@ export interface ResolvedConfigOptions extends ConfigOptions {
server_name: string;
};
};
eula: string;
ssla: string;
media_devices: {
enable_audio: boolean;
enable_video: boolean;
@@ -152,7 +152,7 @@ export const DEFAULT_CONFIG: ResolvedConfigOptions = {
features: {
feature_use_device_session_member_events: true,
},
eula: "https://static.element.io/legal/online-EULA.pdf",
ssla: "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf",
media_devices: {
enable_audio: true,
enable_video: true,

View File

@@ -9,7 +9,7 @@ import { describe, expect, test, vi } from "vitest";
import {
type MatrixRTCSession,
MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc";
} from "matrix-js-sdk/lib/matrixrtc";
import { KeyProviderEvent } from "livekit-client";
import { MatrixKeyProvider } from "./matrixKeyProvider";

View File

@@ -6,11 +6,11 @@ Please see LICENSE in the repository root for full details.
*/
import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import {
type MatrixRTCSession,
MatrixRTCSessionEvent,
} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
} from "matrix-js-sdk/lib/matrixrtc";
export class MatrixKeyProvider extends BaseKeyProvider {
private rtcSession?: MatrixRTCSession;

View File

@@ -32,7 +32,7 @@ import {
} from "react";
import useMeasure from "react-use-measure";
import classNames from "classnames";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { useObservableEagerState } from "observable-hooks";
import { fromEvent, map, startWith } from "rxjs";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/
import { render, type RenderResult } from "@testing-library/react";
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { type MatrixClient } from "matrix-js-sdk";
import { MemoryRouter } from "react-router-dom";
import { describe, expect, it } from "vitest";

View File

@@ -6,9 +6,7 @@ Please see LICENSE in the repository root for full details.
*/
import { Link } from "react-router-dom";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import { type Room } from "matrix-js-sdk/src/models/room";
import { type RoomMember, type Room, type MatrixClient } from "matrix-js-sdk";
import { type FC, useCallback, type MouseEvent, useState } from "react";
import { useTranslation } from "react-i18next";
import { IconButton, Text } from "@vector-im/compound-web";

View File

@@ -12,10 +12,10 @@ import {
type FormEventHandler,
type FC,
} from "react";
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type MatrixClient } from "matrix-js-sdk";
import { useTranslation } from "react-i18next";
import { Heading, Text } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { Button } from "@vector-im/compound-web";
import { useNavigate } from "react-router-dom";

View File

@@ -6,10 +6,10 @@ Please see LICENSE in the repository root for full details.
*/
import { type FC, useCallback, useState, type FormEventHandler } from "react";
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
import { secureRandomString } from "matrix-js-sdk/lib/randomstring";
import { Trans, useTranslation } from "react-i18next";
import { Button, Heading, Text } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { useNavigate } from "react-router-dom";
import { useClient } from "../ClientContext";
@@ -89,7 +89,7 @@ export const UnauthenticatedView: FC = () => {
// @ts-ignore
if (error.errcode === "M_ROOM_IN_USE") {
setOnFinished(() => {
setClient({ client, session });
setClient(client, session);
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
navigate(`/${aliasLocalpart}`)?.catch((error) => {
logger.error("Failed to navigate to alias localpart", error);
@@ -111,7 +111,7 @@ export const UnauthenticatedView: FC = () => {
if (!createRoomResult.password)
throw new Error("Failed to create room with shared secret");
setClient({ client, session });
setClient(client, session);
await navigate(
getRelativeRoomUrl(
createRoomResult.roomId,
@@ -185,10 +185,10 @@ export const UnauthenticatedView: FC = () => {
</Text>
)}
<Text size="sm" className={styles.notice}>
<Trans i18nKey="unauthenticated_view_eula_caption">
<Trans i18nKey="unauthenticated_view_ssla_caption">
By clicking "Go", you agree to our{" "}
<ExternalLink href={Config.get().eula}>
End User Licensing Agreement (EULA)
<ExternalLink href={Config.get().ssla}>
Software and Services License Agreement (SSLA)
</ExternalLink>
</Trans>
</Text>

View File

@@ -5,14 +5,21 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type MatrixClient } from "matrix-js-sdk/src/client";
import { type Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { type RoomMember } from "matrix-js-sdk/src/models/room-member";
import {
type MatrixClient,
type RoomMember,
type Room,
RoomEvent,
EventTimeline,
EventType,
JoinRule,
KnownMembership,
} from "matrix-js-sdk";
import { useState, useEffect } from "react";
import { EventTimeline, EventType, JoinRule } from "matrix-js-sdk/src/matrix";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { MatrixRTCSessionManagerEvents } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSessionManager";
import { KnownMembership } from "matrix-js-sdk/src/types";
import {
MatrixRTCSessionManagerEvents,
type MatrixRTCSession,
} from "matrix-js-sdk/lib/matrixrtc";
import { getKeyForRoom } from "../e2ee/sharedKeyManagement";

View File

@@ -14,7 +14,7 @@ import i18n, {
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import * as Sentry from "@sentry/react";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import { shouldPolyfill as shouldPolyfillSegmenter } from "@formatjs/intl-segmenter/should-polyfill";
import { shouldPolyfill as shouldPolyfillDurationFormat } from "@formatjs/intl-durationformat/should-polyfill";
import {

View File

@@ -19,7 +19,7 @@ import {
import { createMediaDeviceObserver } from "@livekit/components-core";
import { map, startWith } from "rxjs";
import { useObservableEagerState } from "observable-hooks";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import {
useSetting,

View File

@@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type IOpenIDToken, type MatrixClient } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { type IOpenIDToken, type MatrixClient } from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/lib/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
import { useEffect, useState } from "react";
import { type LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus";
import { type LivekitFocus } from "matrix-js-sdk/lib/matrixrtc";
import { useActiveLivekitFocus } from "../room/useActiveFocus";
import { useErrorBoundary } from "../useErrorBoundary";

View File

@@ -15,7 +15,7 @@ import {
Track,
} from "livekit-client";
import { useCallback, useEffect, useRef, useState } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import * as Sentry from "@sentry/react";
import { type SFUConfig, sfuConfigEquals } from "./openIDSFU";

View File

@@ -15,8 +15,8 @@ import {
} from "livekit-client";
import { useEffect, useMemo, useRef } from "react";
import E2EEWorker from "livekit-client/e2ee-worker?worker";
import { logger } from "matrix-js-sdk/src/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { logger } from "matrix-js-sdk/lib/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
import { defaultLiveKitOptions } from "./options";
import { type SFUConfig } from "./openIDSFU";

View File

@@ -9,12 +9,12 @@ Please see LICENSE in the repository root for full details.
// function gets set. It needs to be not in the same file as we use
// createClient, or the typescript transpiler gets confused about
// dependency references.
import "matrix-js-sdk/src/browser-index";
import "matrix-js-sdk/lib/browser-index";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { logger } from "matrix-js-sdk/src/logger";
import { logger } from "matrix-js-sdk/lib/logger";
import {
setLogExtension as setLKLogExtension,
setLogLevel as setLKLogLevel,

View File

@@ -6,12 +6,12 @@ Please see LICENSE in the repository root for full details.
*/
import { type Span } from "@opentelemetry/api";
import { type MatrixCall } from "matrix-js-sdk/src/matrix";
import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
import { type MatrixCall } from "matrix-js-sdk";
import { CallEvent } from "matrix-js-sdk/lib/webrtc/call";
import {
type TransceiverStats,
type CallFeedStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport";
} from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { ObjectFlattener } from "./ObjectFlattener";
import { ElementCallOpenTelemetry } from "./otel";

View File

@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
*/
import opentelemetry, { type Span } from "@opentelemetry/api";
import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { type TrackStats } from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan";

View File

@@ -9,7 +9,7 @@ import { type Span } from "@opentelemetry/api";
import {
type CallFeedStats,
type TrackStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport";
} from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport";
import { type TrackStats } from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import opentelemetry, { type Span } from "@opentelemetry/api";
import { type ElementCallOpenTelemetry } from "./otel";

View File

@@ -9,7 +9,7 @@ import { type Span } from "@opentelemetry/api";
import {
type TrackStats,
type TransceiverStats,
} from "matrix-js-sdk/src/webrtc/stats/statsReport";
} from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { type ElementCallOpenTelemetry } from "./otel";
import { OTelCallAbstractMediaStreamSpan } from "./OTelCallAbstractMediaStreamSpan";

View File

@@ -15,26 +15,26 @@ import {
type MatrixClient,
type MatrixEvent,
type RoomMember,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
} from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/lib/logger";
import {
type CallError,
type CallState,
type MatrixCall,
type VoipEvent,
} from "matrix-js-sdk/src/webrtc/call";
} from "matrix-js-sdk/lib/webrtc/call";
import {
type CallsByUserAndDevice,
type GroupCallError,
GroupCallEvent,
type GroupCallStatsReport,
} from "matrix-js-sdk/src/webrtc/groupCall";
} from "matrix-js-sdk/lib/webrtc/groupCall";
import {
type ConnectionStatsReport,
type ByteSentStatsReport,
type SummaryStatsReport,
type CallFeedReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport";
} from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { ElementCallOpenTelemetry } from "./otel";
import { ObjectFlattener } from "./ObjectFlattener";

View File

@@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { type GroupCallStatsReport } from "matrix-js-sdk/src/webrtc/groupCall";
import { type GroupCallStatsReport } from "matrix-js-sdk/lib/webrtc/groupCall";
import {
type AudioConcealment,
type ByteSentStatsReport,
type ConnectionStatsReport,
} from "matrix-js-sdk/src/webrtc/stats/statsReport";
} from "matrix-js-sdk/lib/webrtc/stats/statsReport";
import { describe, expect, it } from "vitest";
import { ObjectFlattener } from "../../src/otel/ObjectFlattener";

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