diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 164afa07..908981c5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -15,6 +15,7 @@ module.exports = { "plugin:matrix-org/typescript", "prettier", "plugin:rxjs/recommended", + "plugin:storybook/recommended", ], parserOptions: { ecmaVersion: "latest", diff --git a/.githooks/post-commit b/.githooks/post-commit deleted file mode 100755 index 467799bd..00000000 --- a/.githooks/post-commit +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/sh - -FILE=.links.temp-disabled.yaml -if test -f "$FILE"; then - # Only do the post-commit hook if the file was temp-disabled by the pre-commit hook. - # Otherwise linking was actively (`yarn links:disable`) disabled and this hook should noop. - mv .links.temp-disabled.yaml .links.yaml - yarnLog=$(yarn) - echo "[yarn-linker] The post-commit hook has re-enabled .links.yaml." - exit 1 -fi diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 435d75f1..2656c9b9 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,11 +1,9 @@ -#!/usr/bin/sh +#!/usr/bin/env bash -FILE=".links.yaml" -if test -f "$FILE"; then - mv .links.yaml .links.temp-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." +# Checks if there currently is linking configured. Informs the user to disable linking before committing. + +PNPMFILE=.pnpmfile.cjs +if test -f "$PNPMFILE"; then + echo "[pnpm-linker] The pre-commit hook detected $PNPMFILE which implies you have linked packages in your pnpm-lock.yaml. Run pnpm links:off and commit again. See also linking.md." exit 1 fi diff --git a/.github/workflows/build-element-call.yaml b/.github/workflows/build-element-call.yaml index 3ddabb0b..f4071975 100644 --- a/.github/workflows/build-element-call.yaml +++ b/.github/workflows/build-element-call.yaml @@ -37,15 +37,16 @@ jobs: persist-credentials: false - name: Enable Corepack run: corepack enable - - name: Yarn cache + - name: pnpm cache uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - cache: "yarn" + cache: "pnpm" node-version-file: ".node-version" - name: Install dependencies - run: "yarn install --immutable" + # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) + run: "pnpm install --frozen-lockfile --ignore-pnpmfile" - name: Build Element Call - run: yarn run build:"$PACKAGE":"$BUILD_MODE" + run: pnpm run build:"$PACKAGE":"$BUILD_MODE" env: SENTRY_ORG: ${{ secrets.SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 32ce25c9..ba7cde51 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -85,3 +85,31 @@ jobs: SENTRY_URL: ${{ secrets.SENTRY_URL }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + build_storybook: + name: Build Storybook + if: contains(github.event.pull_request.labels.*.name, 'storybook build') + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + - name: Enable Corepack + run: corepack enable + - name: pnpm cache + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + cache: "pnpm" + node-version-file: ".node-version" + - name: Install dependencies + run: "pnpm install --frozen-lockfile --ignore-pnpmfile" + - name: Build Storybook + run: pnpm run build-storybook + - name: Upload Artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: build-output-storybook + path: storybook-static + # We'll only use this in a triggered job, then we're done with it + retention-days: 1 diff --git a/.github/workflows/changelog-label.yml b/.github/workflows/changelog-label.yml index f11d3130..84c53cdb 100644 --- a/.github/workflows/changelog-label.yml +++ b/.github/workflows/changelog-label.yml @@ -5,7 +5,7 @@ on: # This is safe because we do not use actions/checkout or execute untrusted code. # Using pull_request_target is necessary to allow status writes for PRs from forks. pull_request_target: - types: [labeled, unlabeled, opened] + types: [labeled, unlabeled, opened, synchronize] permissions: pull-requests: read diff --git a/.github/workflows/deploy-to-netlify.yaml b/.github/workflows/deploy-to-netlify.yaml index 76609328..554e384b 100644 --- a/.github/workflows/deploy-to-netlify.yaml +++ b/.github/workflows/deploy-to-netlify.yaml @@ -17,7 +17,7 @@ on: package: required: true type: string - description: Which package to deploy - 'full', 'embedded', or 'sdk' + description: Which package to deploy - 'full', 'embedded', 'sdk', or 'storybook' artifact_run_id: required: false type: string @@ -43,7 +43,7 @@ jobs: with: step: start token: ${{ secrets.GITHUB_TOKEN }} - env: Netlify + env: ${{ inputs.package}} ref: ${{ inputs.deployment_ref }} desc: | Do you trust the author of this PR? Maybe this build will steal your keys or give you malware. @@ -59,9 +59,13 @@ jobs: - name: Add redirects file # We fetch from github directly as we don't bother checking out the repo + # Not needed for storybook deployments + if: inputs.package != 'storybook' run: curl -s https://raw.githubusercontent.com/element-hq/element-call/main/config/netlify_redirects > webapp/_redirects - name: Add config file + # Not needed for storybook deployments + if: inputs.package != 'storybook' run: | if [ "${INPUTS_PACKAGE}" = "full" ]; then curl -s "https://raw.githubusercontent.com/${INPUTS_PR_HEAD_FULL_NAME}/${INPUTS_PR_HEAD_REF}/config/config_netlify_preview.json" > webapp/config.json @@ -78,7 +82,7 @@ jobs: with: publish-dir: webapp deploy-message: "Deploy from GitHub Actions" - alias: ${{ inputs.package == 'sdk' && format('pr{0}-sdk', inputs.pr_number) || format('pr{0}', inputs.pr_number) }} + alias: ${{ inputs.package == 'sdk' && format('pr{0}-sdk', inputs.pr_number) || inputs.package == 'storybook' && format('pr{0}-storybook', inputs.pr_number) || format('pr{0}', inputs.pr_number) }} env: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 763d2eac..0638eca6 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,20 +12,21 @@ jobs: persist-credentials: false - name: Enable Corepack run: corepack enable - - name: Yarn cache + - name: pnpm cache uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - cache: "yarn" + cache: "pnpm" node-version-file: ".node-version" - name: Install dependencies - run: "yarn install --immutable" + # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) + run: "pnpm install --frozen-lockfile --ignore-pnpmfile" - name: Prettier - run: "yarn run prettier:check" + run: "pnpm run prettier:check" - name: i18n - run: "yarn run i18n:check" + run: "pnpm run i18n:check" - name: ESLint - run: "yarn run lint:eslint" + run: "pnpm run lint:eslint" - name: Type check - run: "yarn run lint:types" + run: "pnpm run lint:types" - name: Dead code analysis - run: "yarn run lint:knip" + run: "pnpm run lint:knip" diff --git a/.github/workflows/pr-deploy.yaml b/.github/workflows/pr-deploy.yaml index 0084b76b..3d88b083 100644 --- a/.github/workflows/pr-deploy.yaml +++ b/.github/workflows/pr-deploy.yaml @@ -14,7 +14,7 @@ jobs: # 2. Event must be a pull_request # 3. Head repository must be the SAME as the base repository (No Forks!) if: > - github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.head_repository.full_name == github.repository runs-on: ubuntu-latest @@ -63,6 +63,24 @@ jobs: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + netlify-storybook: + needs: prdetails + if: ${{ needs.prdetails.outputs.pr_data_json && contains(fromJSON(needs.prdetails.outputs.pr_data_json).labels.*.name, 'storybook build') }} + permissions: + deployments: write + uses: ./.github/workflows/deploy-to-netlify.yaml + with: + artifact_run_id: ${{ github.event.workflow_run.id || github.run_id }} + pr_number: ${{ needs.prdetails.outputs.pr_number }} + pr_head_full_name: ${{ github.event.workflow_run.head_repository.full_name }} + pr_head_ref: ${{ needs.prdetails.outputs.pr_data_json && fromJSON(needs.prdetails.outputs.pr_data_json).head.ref }} + deployment_ref: ${{ needs.prdetails.outputs.pr_data_json && fromJSON(needs.prdetails.outputs.pr_data_json).head.sha || github.ref || github.head_ref }} + package: storybook + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + docker: if: ${{ needs.prdetails.outputs.pr_data_json && contains(fromJSON(needs.prdetails.outputs.pr_data_json).labels.*.name, 'docker build') }} needs: prdetails diff --git a/.github/workflows/publish-embedded-packages.yaml b/.github/workflows/publish-embedded-packages.yaml index 3ab275a5..88d59947 100644 --- a/.github/workflows/publish-embedded-packages.yaml +++ b/.github/workflows/publish-embedded-packages.yaml @@ -97,7 +97,7 @@ jobs: run: find ${FILENAME_PREFIX} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${FILENAME_PREFIX}.sha256 - name: Upload if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }} - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: files: | ${{ env.FILENAME_PREFIX }}.tar.gz @@ -297,7 +297,7 @@ jobs: NEEDS_PUBLISH_IOS_OUTPUTS_ARTIFACT_VERSION: ${{ needs.publish_ios.outputs.ARTIFACT_VERSION }} - name: Add release notes if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }} - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: append_body: true body: | diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 0675b1b1..40b94e26 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -42,7 +42,7 @@ jobs: - name: Create Checksum run: find ${FILENAME_PREFIX} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${FILENAME_PREFIX}.sha256 - name: Upload - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: files: | ${{ env.FILENAME_PREFIX }}.tar.gz @@ -71,7 +71,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Add release note - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: append_body: true body: | diff --git a/.github/workflows/test-netlify.yaml b/.github/workflows/test-netlify.yaml new file mode 100644 index 00000000..bccde445 --- /dev/null +++ b/.github/workflows/test-netlify.yaml @@ -0,0 +1,48 @@ +# Triggers after the playwright tests have finished, +# taking the artifact and uploading it to Netlify for easier viewing +name: Upload End to End Test report to Netlify +on: + # Privilege escalation necessary to publish to Netlify + # 🚨 We must not execute any checked out code here. + workflow_run: # zizmor: ignore[dangerous-triggers] + workflows: ["Test"] + types: + - completed + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }} + cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }} + +permissions: {} + +jobs: + report: + if: github.event.workflow_run.conclusion != 'cancelled' + name: Report results + runs-on: ubuntu-24.04 + environment: Netlify + permissions: + statuses: write + deployments: write + actions: read + steps: + - name: Download HTML report + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: html-report + path: playwright-report + + - name: 📤 Deploy to Netlify + uses: matrix-org/netlify-pr-preview@9805cd123fc9a7e421e35340a05e1ebc5dee46b5 # v3 + with: + path: playwright-report + owner: ${{ github.event.workflow_run.head_repository.owner.login }} + branch: ${{ github.event.workflow_run.head_branch }} + revision: ${{ github.event.workflow_run.head_sha }} + token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + site_id: ${{ secrets.NETLIFY_SITE_ID }} + desc: Playwright Report + deployment_env: EndToEndTests + prefix: "e2e-" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cd1c94c5..d8af6f92 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -14,17 +14,18 @@ jobs: persist-credentials: false - name: Enable Corepack run: corepack enable - - name: Yarn cache + - name: pnpm cache uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - cache: "yarn" + cache: "pnpm" node-version-file: ".node-version" - name: Install dependencies - run: "yarn install --immutable" + # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) + run: "pnpm install --frozen-lockfile --ignore-pnpmfile" - name: Vitest - run: "yarn run test:coverage" + run: "pnpm run test:coverage" - name: Upload to codecov - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5 + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: @@ -42,12 +43,13 @@ jobs: run: corepack enable - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - cache: "yarn" + cache: "pnpm" node-version-file: ".node-version" - name: Install dependencies - run: yarn install --immutable + # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) + run: pnpm install --frozen-lockfile --ignore-pnpmfile - name: Install Playwright Browsers - run: yarn playwright install --with-deps + run: pnpm exec playwright install --with-deps - name: Run backend components run: | docker compose -f playwright-backend-docker-compose.yml -f playwright-backend-docker-compose.override.yml pull @@ -56,10 +58,11 @@ jobs: - name: Run Playwright tests env: USE_DOCKER: 1 - run: yarn playwright test - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + run: pnpm exec playwright test + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: ${{ !cancelled() }} with: - name: playwright-report - path: playwright-report/ - retention-days: 3 + name: html-report + path: playwright-report + if-no-files-found: error + retention-days: 4 diff --git a/.github/workflows/translations-download.yaml b/.github/workflows/translations-download.yaml index ad9f4652..08260a5a 100644 --- a/.github/workflows/translations-download.yaml +++ b/.github/workflows/translations-download.yaml @@ -22,11 +22,12 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: - cache: "yarn" + cache: "pnpm" node-version-file: ".node-version" - name: Install Deps - run: "yarn install --immutable" + # ignore-pnpmfile should never be commited. Make CI crash if it happened (`pnpmfileChecksum` is present) + run: "pnpm install --frozen-lockfile --ignore-pnpmfile" - name: Prune i18n run: "rm -R locales" @@ -40,7 +41,7 @@ jobs: run: "sudo chown runner:docker -R locales" - name: Prettier - run: yarn prettier:format + run: pnpm prettier:format - name: Create Pull Request id: cpr diff --git a/.gitignore b/.gitignore index 5751844a..e9225072 100644 --- a/.gitignore +++ b/.gitignore @@ -21,12 +21,20 @@ yarn-error.log !/.yarn/releases !/.yarn/sdks !/.yarn/versions +# old yarn based linking /.links.yaml /.links.disabled.yaml /.links.temp-disabled.yaml +# pnpm based linking +/.links.cjs +/.links.disabled.cjs +/.links.temp-disabled.cjs # Playwright /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ + +*storybook.log +storybook-static diff --git a/.prettierignore b/.prettierignore index f06235c4..31e6cd83 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ +pnpm-lock.yaml node_modules dist diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 00000000..977eca73 --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,15 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import type { StorybookConfig } from "@storybook/react-vite"; + +const config: StorybookConfig = { + stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], + addons: ["@storybook/addon-docs"], + framework: "@storybook/react-vite", +}; +export default config; diff --git a/.storybook/manager.ts b/.storybook/manager.ts new file mode 100644 index 00000000..1177be2f --- /dev/null +++ b/.storybook/manager.ts @@ -0,0 +1,31 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { create } from "storybook/theming"; +import { addons } from "storybook/manager-api"; + +addons.setConfig({ + theme: create({ + base: "light", + colorPrimary: "#1b1d22", + colorSecondary: "#0467dd", + + // Typography + fontBase: '"Inter", sans-serif', + fontCode: '"Inconsolata", monospace', + + // Text colors + textColor: "#1b1d22", + appBg: "#ffffff", + barBg: "#ffffff", + + brandTitle: "Element Call", + brandUrl: "https://element.io/", + brandImage: "/src/icons/Logo.svg", + brandTarget: "_self", + }), +}); diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx new file mode 100644 index 00000000..757c1f8a --- /dev/null +++ b/.storybook/preview.tsx @@ -0,0 +1,56 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import type { Preview } from "@storybook/react-vite"; +import { TooltipProvider } from "@vector-im/compound-web"; +import i18n from "i18next"; +import { logger } from "matrix-js-sdk/lib/logger"; + +import EN from "../locales/en/app.json"; +import { initReactI18next } from "react-i18next"; +import "../src/index.css"; + +// Bare-minimum i18n config +i18n + .use(initReactI18next) + .init({ + lng: "en", + fallbackLng: "en", + supportedLngs: ["en"], + // We embed the translations, so that it never needs to fetch + resources: { + en: { + translation: EN, + }, + }, + interpolation: { + escapeValue: false, // React has built-in XSS protections + }, + }) + .catch((e) => logger.warn("Failed to init i18n for stories", e)); + +const preview: Preview = { + parameters: { + layout: "centered", + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, + tags: ["autodocs"], + decorators: [ + (Story) => ( + + + + ), + ], +}; + +export default preview; diff --git a/.yarn/plugins/linker.cjs b/.yarn/plugins/linker.cjs deleted file mode 100644 index cf7181f9..00000000 --- a/.yarn/plugins/linker.cjs +++ /dev/null @@ -1,91 +0,0 @@ -/* -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, - ); - }; - }, - }, - }), -}; diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 538de0e7..00000000 --- a/.yarnrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -nodeLinker: node-modules -plugins: - - .yarn/plugins/linker.cjs diff --git a/README.md b/README.md index 688a7a7f..0c82e4b0 100644 --- a/README.md +++ b/README.md @@ -108,17 +108,17 @@ recommended method for embedding Element Call.

For more details on the packages, see the -[Embedded vs. Standalone Guide](./docs/embedded-standalone.md). +[Embedded vs. Standalone Guide](./docs/embedded_standalone.md). ## 🛠️ Self-Hosting For operating and deploying Element Call on your own server, refer to the -[**Self-Hosting Guide**](./docs/self-hosting.md). +[**Self-Hosting Guide**](./docs/self_hosting.md). ## 🧭 MatrixRTC Backend Discovery and Selection 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 +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.

@@ -186,7 +186,7 @@ To get started clone and set up this project: git clone https://github.com/element-hq/element-call.git cd element-call corepack enable -yarn +pnpm install ``` To use it, create a local config by, e.g., @@ -197,7 +197,7 @@ environment as outlined in the next section out of box. You're now ready to launch the development server: ```sh -yarn dev +pnpm dev ``` See also: @@ -230,7 +230,7 @@ only for local development and **_never be exposed to the public Internet._** Run backend components: ```sh -yarn backend +pnpm backend # or for podman-compose # podman-compose -f dev-backend-docker-compose.yml up ``` @@ -260,13 +260,13 @@ 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` +`pnpm backend` There are a few different ways to run the tests yourself. The simplest is to run: ```shell -yarn run test:playwright +pnpm run test:playwright ``` This will run the Playwright tests once, non-interactively. @@ -274,7 +274,7 @@ This will run the Playwright tests once, non-interactively. There is a more user-friendly way to run the tests in interactive mode: ```shell -yarn run test:playwright:open +pnpm run test:playwright:open ``` The easiest way to develop new test is to use the codegen feature of Playwright: @@ -316,7 +316,7 @@ To add a new translation key you can do these steps: 1. Add the new key entry to the code where the new key is used: `t("some_new_key")` -1. Run `yarn i18n` to extract the new key and update the translation files. This +1. Run `pnpm i18n` to extract the new key and update the translation files. This will add a skeleton entry to the `locales/en/app.json` file: ```jsonc diff --git a/WIDGET_TEST.md b/WIDGET_TEST.md index 53e26a29..fbad026a 100644 --- a/WIDGET_TEST.md +++ b/WIDGET_TEST.md @@ -1,6 +1,6 @@ # Testing Element-Call in widget mode -When running `yarn backend` the latest element-web develop will be deployed and served on `http://localhost:8081`. +When running `pnpm 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 @@ -18,7 +18,7 @@ that uses It is part of the existing backend setup. To start the backend, run: ```sh -yarn backend +pnpm backend ``` Then open `http://localhost:8081` in your browser. diff --git a/backend/dev_homeserver-othersite.yaml b/backend/dev_homeserver-othersite.yaml index 81e775ca..7eb8f294 100644 --- a/backend/dev_homeserver-othersite.yaml +++ b/backend/dev_homeserver-othersite.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/dev_homeserver.yaml b/backend/dev_homeserver.yaml index dc7b42c8..0aea2ece 100644 --- a/backend/dev_homeserver.yaml +++ b/backend/dev_homeserver.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/dev_livekit-othersite.yaml b/backend/dev_livekit-othersite.yaml index 0ae98c24..53fc9ce9 100644 --- a/backend/dev_livekit-othersite.yaml +++ b/backend/dev_livekit-othersite.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.othersite.m.localhost/livekit/jwt/sfu_webhook diff --git a/backend/dev_livekit.yaml b/backend/dev_livekit.yaml index 157e4d04..6cef4241 100644 --- a/backend/dev_livekit.yaml +++ b/backend/dev_livekit.yaml @@ -18,3 +18,7 @@ keys: devkey: secret room: auto_create: false +webhook: + api_key: devkey + urls: + - https://matrix-rtc.m.localhost/livekit/jwt/sfu_webhook diff --git a/backend/dev_nginx.conf b/backend/dev_nginx.conf index d3ddbc53..6ec0d701 100644 --- a/backend/dev_nginx.conf +++ b/backend/dev_nginx.conf @@ -28,14 +28,19 @@ server { # Reason: the lk-jwt-service uses the federation API for the openid token # verification, which requires TLS location ~ ^(/_matrix|/_synapse/client) { - proxy_pass "http://homeserver:8008"; + proxy_pass "http://homeserver:8008"; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; + proxy_set_header Host $host; + } + location ~ ^(/_matrix|/_synapse/admin) { + proxy_pass "http://homeserver:8008"; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; } - - error_page 500 502 503 504 /50x.html; } @@ -73,10 +78,16 @@ server { proxy_http_version 1.1; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; + proxy_set_header Host $host; } - error_page 500 502 503 504 /50x.html; + location ~ ^(/_matrix|/_synapse/admin) { + proxy_pass "http://homeserver-1:18008"; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + } } @@ -108,7 +119,7 @@ server { # JWT Service running at port 6080 proxy_pass http://jwt-auth-services/; - + } location ^~ /livekit/sfu/ { @@ -128,8 +139,6 @@ server { # LiveKit SFU websocket connection running at port 7880 proxy_pass http://livekit-sfu:7880/; } - - error_page 500 502 503 504 /50x.html; } @@ -156,7 +165,7 @@ server { # JWT Service running at port 16080 proxy_pass http://auth-service-1:16080/; - + } location ^~ /livekit/sfu/ { @@ -176,14 +185,12 @@ server { # LiveKit SFU websocket connection running at port 17880 proxy_pass http://livekit-sfu-1:17880/; } - - error_page 500 502 503 504 /50x.html; } # Convenience reverse proxy for the call.m.localhost domain to element call # running on the host either via -# - yarn dev --host or +# - pnpm dev --host or # - falling back to http (the element call docker container) server { listen 80; @@ -228,7 +235,6 @@ server { proxy_pass http://host.docker.internal:8080; } - error_page 500 502 503 504 /50x.html; } @@ -260,8 +266,6 @@ server { proxy_ssl_verify off; } - - error_page 500 502 503 504 /50x.html; } @@ -293,7 +297,5 @@ server { proxy_ssl_verify off; } - - error_page 500 502 503 504 /50x.html; } diff --git a/backend/playwright_homeserver-othersite.yaml b/backend/playwright_homeserver-othersite.yaml index 35640ae9..86c77b35 100644 --- a/backend/playwright_homeserver-othersite.yaml +++ b/backend/playwright_homeserver-othersite.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/backend/playwright_homeserver.yaml b/backend/playwright_homeserver.yaml index a83247cd..8f437524 100644 --- a/backend/playwright_homeserver.yaml +++ b/backend/playwright_homeserver.yaml @@ -50,6 +50,9 @@ max_event_delay_duration: 24h enable_registration: true enable_registration_without_verification: true +# Shared secret for admin user registration via API (for testing only!) +registration_shared_secret: "test_shared_secret_for_local_dev_only" + report_stats: false serve_server_wellknown: true diff --git a/dev-backend-docker-compose.yml b/dev-backend-docker-compose.yml index 8d885399..702aef39 100644 --- a/dev-backend-docker-compose.yml +++ b/dev-backend-docker-compose.yml @@ -3,7 +3,7 @@ networks: services: auth-service: - image: ghcr.io/element-hq/lk-jwt-service:sha-f8ddd00 + image: ghcr.io/element-hq/lk-jwt-service:0.4.4 pull_policy: always hostname: auth-server environment: @@ -25,7 +25,7 @@ services: - ecbackend auth-service-1: - image: ghcr.io/element-hq/lk-jwt-service:sha-f8ddd00 + image: ghcr.io/element-hq/lk-jwt-service:0.4.4 pull_policy: always hostname: auth-server-1 environment: @@ -47,7 +47,7 @@ services: - ecbackend livekit: - image: livekit/livekit-server:v1.9.11 + image: livekit/livekit-server:v1.10.1 pull_policy: always hostname: livekit-sfu command: --dev --config /etc/livekit.yaml @@ -62,12 +62,15 @@ services: - 7882:7882/tcp - 50100-50200:50100-50200/udp volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z - ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem networks: - ecbackend livekit-1: - image: livekit/livekit-server:v1.9.11 + image: livekit/livekit-server:v1.10.1 pull_policy: always hostname: livekit-sfu-1 command: --dev --config /etc/livekit.yaml @@ -82,7 +85,10 @@ services: - 17882:17882/tcp - 50300-50400:50300-50400/udp volumes: + - ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z - ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z + environment: + - SSL_CERT_FILE=/local_cert.pem networks: - ecbackend @@ -164,6 +170,8 @@ services: - "8448:8448" extra_hosts: - "host.docker.internal:host-gateway" + - "auth-server:127.0.0.1" + - "auth-server-1:127.0.0.1" depends_on: - synapse networks: diff --git a/docs/README.md b/docs/README.md index d97e8d56..e5a5d08a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,8 +2,8 @@ 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) +- [Embedded vs standalone mode](./embedded_standalone.md) +- [Url format and parameters](./url_params.md) - [Global JS controls](./controls.md) -- [Self-Hosting](./self-hosting.md) +- [Self-Hosting](./self_hosting.md) - [Developing with linked packages](./linking.md) diff --git a/docs/embedded-standalone.md b/docs/embedded_standalone.md similarity index 97% rename from docs/embedded-standalone.md rename to docs/embedded_standalone.md index 440dfac0..24ad2a7d 100644 --- a/docs/embedded-standalone.md +++ b/docs/embedded_standalone.md @@ -14,7 +14,7 @@ The table below provides a comparison of the two packages: | **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 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 @@ -26,7 +26,7 @@ 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. +4. Set any of the [embedded-only URL parameters](./url_params.md#embedded-only-parameters) that you need. ## Widget vs standalone mode @@ -36,4 +36,4 @@ As a widget, the app only uses the core calling (MatrixRTC) parts. The rest (aut Element Call and the hosting client are connected via the widget API. Element Call detects that it is run as a widget if a widgetId is defined in the url parameters. If `widgetId` is present then Element Call will try to connect to the client via the widget postMessage API using the parameters provided in [Url Format and parameters -](./url-params.md). +](./url_params.md). diff --git a/docs/linking.md b/docs/linking.md index 0abbc73e..1016fffb 100644 --- a/docs/linking.md +++ b/docs/linking.md @@ -1,39 +1,65 @@ -# Developing with linked packages +## Quickstart guide -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. +run -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 +```bash +./scripts/setup-linking.sh ``` -Then run `yarn install`. +Read the script output: + +``` +Setup complete. +Update: .links.cjs to your liking +Run: 'pnpm links:on' to test your .links.cjs +Run: 'git commit' with links enabled to test the git pre-commit hook. +Run: 'pnpm links:off' to be able to commit again +Run: 'git config --local core.hooksPath ""' to allow committing with linking (not recommended) +Run: 'rm links.cjs' & 'git config --local core.hooksPath ""' to fully revert what this script did +``` + +# 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. `pnpm` has a command for this (`pnpm link`), but it's not recommended to use it as it ends up modifying package.json with details specific to your development environment. + +Instead, create a file named `.links.cjs` in the Element Call project directory (or run `./scripts/setup-linking.sh` to create a template), listing the names and paths of any dependencies you want to link. For example: + +```cjs +// Packages to link to local checkouts +module.exports = { + "matrix-js-sdk": "../your/path/matrix-js-sdk", + "matrix-widget-api": "../your/path/matrix-widget-api", +}; +``` + +Then run `pnpm links:on`. (this will activate the pnpm file + run `pnpm install` to setup the linking) ## Hooks -Changes in `.links.yaml` will also update `yarn.lock` when `yarn` is executed. The lockfile will then contain the local +Changes in `.links.cjs` will also update `pnpm-lock.yaml` when `pnpm install` 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: + +One always needs to remove the pnpm `readPackage` script (the `.pnpmfile.cjs`) and run: ```bash -mv .links.yaml .links.disabled.yaml -yarn +pnpm install ``` 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. +To make this less of a foot gun we added a git hook. +A `pre-commit` hook will check if linking is currently used. If it detects +a `.pnpmfile.cjs` file it will abort the commit with an explanatory message. +You will than need to run `pnpm links:off` 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 +To activate the hooks configure git with (when using the setup script (`./scripts/setup-linking.sh`) this is already done): ```bash -git config --local core.hooksPath .githooks/ +git config --local core.hooksPath .githooks ``` + +This will add the hook path for this repository only to .gihooks. which is a tracked (by git) folder containing the pre-commit hook. + +## Background + +Information, why this approach is used can be found in the [linking concept reasoning](./linking_concept_reasoning.md) document. diff --git a/docs/linking_concept_reasoning.md b/docs/linking_concept_reasoning.md new file mode 100644 index 00000000..7c135a96 --- /dev/null +++ b/docs/linking_concept_reasoning.md @@ -0,0 +1,30 @@ +### Why do we not enable .pnpmfile.cjs by default + +Background: The presence of the `.pnpmfile.cjs` adds a field to the `pnpm-lock.yaml` called: `pnpmfileChecksum`. This field is a checksum of the content of the `.pnpmfile.cjs` file. +`pnpm install --frozen-lockfile` **fails** if there is a `.pnpmfile.cjs` but no `pnpmfileChecksum` or vice versa (or on mismatch). + +_TLDR: running with `--ignore-pnpmfile` will fail if `pnpmfileChecksum` is present._ + +#### `pnpmfileChecksum` + renovate bot + +When the renovate bot creates a PR it runs `pnpm install --ignore-pnpmfile`. This means that the `pnpmfileChecksum` in the lockfile will be **empty**. +This breaks builds that **don't** ignore the `.pnpmfile.cjs`-file. (CI that runs on the renovate PR) +From here we have two possible paths: + +- ignore `.pnpmfile.cjs` in all CI builds CI will also fail if we accidently add it locally. +- fixup the `pnpm-lock.yaml` in the renovate PR to contain the correct `pnpmfileChecksum`. + +Ignoring in all CI builds means that CI will always fail if we enable the linking system. +This is annoying but can be worked around with the git hook we provide that at least lets us know that we are +commiting with enabled linking. +Only if we remember setting it back/disbale linking (or let ourselves remember by the git hook) the CI will work. + +#### Summary + +- We will always run into conflicts with the `pnpmfileChecksum` because in renovate prs it will be empty (`--ignore-pnpmfile`) +- To keep it simple we set `--ignore-pnpmfile` in all of ours CI to see issues immediately. +- The only solution is to never have a `.pnpmfile.cjs` in the repository when pushing. + - This way there will never be a commit with `pnpmfileChecksum` in the lockfile. + - renovate (which uses `--ignore-pnpmfile` which we cannot disable) and other CI will work +- We are able to use the linking system locally if we `cp` this file from the scripts folder into `./` on demand. +- `pnpm links:on` and `pnpm links:off` + `./scripts/setup-linking.sh` will help us with this. diff --git a/docs/self-hosting.md b/docs/self_hosting.md similarity index 99% rename from docs/self-hosting.md rename to docs/self_hosting.md index d6d46421..dc1dd687 100644 --- a/docs/self-hosting.md +++ b/docs/self_hosting.md @@ -237,8 +237,8 @@ source. First, clone and install the package: git clone https://github.com/element-hq/element-call.git cd element-call corepack enable -yarn -yarn build +pnpm install +pnpm build ``` If all went well, you can now find the build output under `dist` as a series of diff --git a/docs/url-params.md b/docs/url_params.md similarity index 62% rename from docs/url-params.md rename to docs/url_params.md index e24e9823..e88e7095 100644 --- a/docs/url-params.md +++ b/docs/url_params.md @@ -4,7 +4,7 @@ There are two formats for Element Call URLs. ## Link for sharing -Requires Element Call to be deployed in [standalone](./embedded-standalone.md) mode. +Requires Element Call to be deployed in [standalone](./embedded_standalone.md) mode. ```text https://element_call.domain/room/# @@ -36,46 +36,45 @@ possible to support encryption. | Package | Deployment | URL | | ------------------------------------ | ----------------------------- | ----------------------------------------------------------------------------- | -| [Full](./embedded-standalone.md) | All | `https://element_call.domain/room` | -| [Embedded](./embedded-standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part | -| [Embedded](./embedded-standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part | +| [Full](./embedded_standalone.md) | All | `https://element_call.domain/room` | +| [Embedded](./embedded_standalone.md) | Remote URL | `https://element_call.domain/` n.b. no `/room` part | +| [Embedded](./embedded_standalone.md) | Embedded within messenger app | Platform dependent, but you load the `index.html` file without a `/room` part | ## Parameters ### Common Parameters -These parameters are relevant to both [widget](./embedded-standalone.md) and [standalone](./embedded-standalone.md) modes: +These parameters are relevant to both [widget](./embedded_standalone.md) and [standalone](./embedded_standalone.md) modes: -| Name | Values | Required for widget | Required for SPA | Description | -| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `intent` | `start_call`, `join_existing`, `start_call_dm`, `join_existing_dm. | No, defaults to `start_call` | No, defaults to `start_call` | The intent is a special url parameter that defines the defaults for all the other parameters. In most cases it should be enough to only set the intent to setup element-call. | -| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. | -| `posthogUserId` | Posthog analytics ID | No | No | Available only with user's consent for sharing telemetry in Element Web. | -| `appPrompt` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Prompts the user to launch the native mobile app upon entering a room, applicable only on Android and iOS, and must be enabled in config. | -| `confineToRoom` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. | -| `displayName` | | No | No | Display name used for auto-registration. | -| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. | -| `fontScale` | A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. | -| `fonts` | | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. | -| `header` | `none`, `standard` or `app_bar` | No, defaults to `standard` | No, defaults to `standard` | The style of headers to show. `standard` is the default arrangement, `none` hides the header entirely, and `app_bar` produces a header with a back button like you might see in mobile apps. The callback for the back button is `window.controls.onBackButtonPressed`. | -| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. | -| `homeserver` | | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. | -| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. | -| `password` | | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) | -| `perParticipantE2EE` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables per participant encryption with Keys exchanged over encrypted matrix room messages. | -| `controlledAudioDevices` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the [global JS controls for audio devices](./controls.md#audio-devices) should be enabled, allowing the list of audio devices to be controlled by the app hosting Element Call. | -| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. | -| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. | -| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) | -| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. | -| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. | -| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. | -| `autoLeaveWhenOthersLeft` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. | -| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. | +| Name | Values | Required for widget | Required for SPA | Description | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `intent` | `start_call`, `join_existing`, `start_call_voice`, `join_existing_voice`, `start_call_dm`, `join_existing_dm`, `start_call_dm_voice`, or `join_existing_dm_voice`. | No, defaults to `start_call` | No, defaults to `start_call` | The intent is a special url parameter that defines the defaults for all the other parameters. In most cases it should be enough to only set the intent to setup element-call. | +| `allowIceFallback` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Allows use of fallback STUN servers for ICE if the user's homeserver doesn’t provide any. | +| `posthogUserId` | Posthog analytics ID | No | No | Available only with user's consent for sharing telemetry in Element Web. | +| `confineToRoom` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Keeps the user confined to the current call/room. | +| `displayName` | | No | No | Display name used for auto-registration. | +| `enableE2EE` (deprecated) | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Legacy flag to enable end-to-end encryption, not used in the `livekit` branch. | +| `fontScale` | A decimal number such as `0.9` | No, defaults to `1.0` | No, defaults to `1.0` | Factor by which to scale the interface's font size. | +| `fonts` | | No | No | Defines the font(s) used by the interface. Multiple font parameters can be specified: `?font=font-one&font=font-two...`. | +| `header` | `none`, `standard` or `app_bar` | No, defaults to `standard` | No, defaults to `standard` | The style of headers to show. `standard` is the default arrangement, `none` hides the header entirely, and `app_bar` produces a header with a back button like you might see in mobile apps. The callback for the back button is `window.controls.onBackButtonPressed`. | +| `hideScreensharing` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Hides the screen-sharing button. | +| `homeserver` | | Not applicable | No | Homeserver for registering a new (guest) user, configures non-default guest user server when creating a spa link. | +| `lang` | [BCP 47](https://www.rfc-editor.org/info/bcp47) code | No | No | The language the app should use. | +| `password` | | No | No | E2EE password when using a shared secret. (For individual sender keys in embedded mode this is not required.) | +| `perParticipantE2EE` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Enables per participant encryption with Keys exchanged over encrypted matrix room messages. | +| `controlledAudioDevices` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the [global JS controls for audio devices](./controls.md#audio-devices) should be enabled, allowing the list of audio devices to be controlled by the app hosting Element Call. | +| `roomId` | [Matrix Room ID](https://spec.matrix.org/v1.12/appendices/#room-ids) | Yes | No | Anything about what room we're pointed to should be from useRoomIdentifier which parses the path and resolves alias with respect to the default server name, however roomId is an exception as we need the room ID in embedded widget mode, and not the room alias (or even the via params because we are not trying to join it). This is also not validated, where it is in `useRoomIdentifier()`. | +| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. | +| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) | +| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. | +| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. | +| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. | +| `autoLeaveWhenOthersLeft` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. | +| `waitForCallPickup` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | When sending a notification, show UI that the app is awaiting an answer, play a dial tone, and (in widget mode) auto-close the widget once the notification expires. | ### Widget-only parameters -These parameters are only supported in [widget](./embedded-standalone.md) mode. +These parameters are only supported in [widget](./embedded_standalone.md) mode. | Name | Values | Required | Description | | --------------- | ----------------------------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -90,7 +89,7 @@ These parameters are only supported in [widget](./embedded-standalone.md) mode. ### Embedded-only parameters -These parameters are only supported in the [embedded](./embedded-standalone.md) package of Element Call and will be ignored in the [full](./embedded-standalone.md) package. +These parameters are only supported in the [embedded](./embedded_standalone.md) package of Element Call and will be ignored in the [full](./embedded_standalone.md) package. | Name | Values | Required | Description | | -------------------- | -------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- | diff --git a/embedded/android/publish_android_package.sh b/embedded/android/publish_android_package.sh index 8c310c9b..31693317 100755 --- a/embedded/android/publish_android_package.sh +++ b/embedded/android/publish_android_package.sh @@ -11,7 +11,7 @@ pushd $CURRENT_DIR > /dev/null function build_assets() { echo "Generating Element Call assets..." pushd ../.. > /dev/null - yarn build + pnpm build popd > /dev/null } @@ -26,7 +26,7 @@ function copy_assets() { } getopts :sh opt -case $opt in +case $opt in s) SKIP=1 ;; @@ -41,7 +41,7 @@ if [ ! $SKIP ]; then echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then build_assets - else + else echo "Using existing assets from ../../dist" fi copy_assets @@ -56,4 +56,4 @@ echo "Publishing the Android project" ./gradlew publishAndReleaseToMavenCentral --no-daemon -popd > /dev/null \ No newline at end of file +popd > /dev/null diff --git a/index.html b/index.html index f17c73c0..f3177a48 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ <%- brand %>