Compare commits

..

21 Commits

Author SHA1 Message Date
David Baker
f20fc78bd7 Use branch of js-sdk with Olm debugging
Pulls in changes from https://github.com/matrix-org/matrix-js-sdk/pull/3055

Not intended to stay long-term.
2023-01-12 11:28:15 +00:00
Robin
741233909d Merge pull request #829 from RiotTranslateBot/weblate-element-call-element-call
Translations update from Weblate
2023-01-09 13:35:43 -05:00
Robin
4e0f4a8dc7 Merge pull request #835 from robintown/unmuted-when-speaking
Work around mute state updates being slow
2023-01-09 13:35:05 -05:00
Šimon Brandner
0d151452ba Merge pull request #833 from vector-im/SimonBrandner/feat/hide-audio 2023-01-09 19:28:04 +01:00
Robin Townsend
4fd76f9599 Work around mute state updates being slow
Since the app already determines when someone is speaking, we can use that information to make it less obvious when to-device messages are being slow to deliver mute state updates.
2023-01-09 11:10:59 -05:00
Robin
d123793deb Merge pull request #832 from robintown/update-js-sdk
Update matrix-js-sdk
2023-01-09 10:52:19 -05:00
Robin Townsend
449c1c9d79 Try updating Olm to fix type errors 2023-01-09 10:49:01 -05:00
Robin Townsend
de5b58792e Update matrix-js-sdk 2023-01-09 10:32:05 -05:00
Robin Townsend
7769074410 Merge branch 'main' into update-js-sdk 2023-01-09 10:31:39 -05:00
Šimon Brandner
881054e265 Hide local volume controls for tiles with no audio
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2023-01-07 10:09:20 +01:00
Robin
767f9cdc4a Merge pull request #831 from robintown/no-video-mute
Leave audio elements unmuted regardless of mute state
2023-01-06 12:08:13 -05:00
Robin Townsend
946f564f84 Update matrix-js-sdk 2023-01-06 10:39:29 -05:00
Robin Townsend
468e389324 Leave audio elements unmuted regardless of mute state 2023-01-06 10:26:10 -05:00
Jozef Gaal
62e98f6c47 Translated using Weblate (Slovak)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/sk/
2023-01-06 09:33:22 +00:00
Priit Jõerüüt
de31c099e3 Translated using Weblate (Estonian)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/et/
2023-01-06 09:33:22 +00:00
Ihor Hordiichuk
49cae76387 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/uk/
2023-01-06 09:33:22 +00:00
Glandos
d45ea78ddb Translated using Weblate (French)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/fr/
2023-01-06 09:33:22 +00:00
Linerly
dcbc3ed865 Translated using Weblate (Indonesian)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/id/
2023-01-06 09:33:22 +00:00
Vri
ff19135d4e Translated using Weblate (German)
Currently translated at 100.0% (141 of 141 strings)

Translation: Element Call/element-call
Translate-URL: https://translate.element.io/projects/element-call/element-call/de/
2023-01-06 09:33:22 +00:00
Robin
de7343d16a Merge pull request #821 from robintown/save-lockfile
Save lockfile
2023-01-05 10:35:52 -05:00
Robin Townsend
c09fec5f88 Save lockfile 2023-01-04 08:25:26 -05:00
22 changed files with 250 additions and 319 deletions

View File

@@ -2,24 +2,9 @@ server {
listen 8080; listen 8080;
server_name localhost; server_name localhost;
root /app;
location / { location / {
# disable cache entriely by default (apart from Etag which is accurate enough) root /app;
add_header Cache-Control 'private no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires off;
# also turn off last-modified since they are just the timestamps of the file in the docker image
# and may or may not bear any resemblance to when the resource changed
add_header Last-Modified "";
try_files $uri /$uri /index.html; try_files $uri /$uri /index.html;
} }
# assets can be cached because they have hashed filenames
location /assets {
expires 1w;
add_header Cache-Control "public, no-transform";
}
} }

View File

@@ -18,7 +18,7 @@
}, },
"dependencies": { "dependencies": {
"@juggle/resize-observer": "^3.3.1", "@juggle/resize-observer": "^3.3.1",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz", "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz",
"@react-aria/button": "^3.3.4", "@react-aria/button": "^3.3.4",
"@react-aria/dialog": "^3.1.4", "@react-aria/dialog": "^3.1.4",
"@react-aria/focus": "^3.5.0", "@react-aria/focus": "^3.5.0",
@@ -45,8 +45,7 @@
"i18next": "^21.10.0", "i18next": "^21.10.0",
"i18next-browser-languagedetector": "^6.1.8", "i18next-browser-languagedetector": "^6.1.8",
"i18next-http-backend": "^1.4.4", "i18next-http-backend": "^1.4.4",
"lodash": "^4.17.21", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#79575ef3760bb6085b7b770f241b3d32756d5b96",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#a34d06c7c24c3523a77f70c01d4e31c45e92aa6b",
"matrix-widget-api": "^1.0.0", "matrix-widget-api": "^1.0.0",
"mermaid": "^8.13.8", "mermaid": "^8.13.8",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",

View File

@@ -137,5 +137,7 @@
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Ob Tastenkürzel mit nur einer Taste aktiviert sein sollen, z. B. „m“ um das Mikrofon stumm/aktiv zu schalten.", "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Ob Tastenkürzel mit nur einer Taste aktiviert sein sollen, z. B. „m“ um das Mikrofon stumm/aktiv zu schalten.",
"Single-key keyboard shortcuts": "Ein-Tasten-Tastenkürzel", "Single-key keyboard shortcuts": "Ein-Tasten-Tastenkürzel",
"{{name}} (Waiting for video...)": "{{name}} (Warte auf Video …)", "{{name}} (Waiting for video...)": "{{name}} (Warte auf Video …)",
"This feature is only supported on Firefox.": "Diese Funktion wird nur in Firefox unterstützt." "This feature is only supported on Firefox.": "Diese Funktion wird nur in Firefox unterstützt.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Übermittelte Problemberichte helfen uns, Fehler zu beheben.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Hoppla, etwas ist schiefgelaufen.</0>"
} }

View File

@@ -137,5 +137,7 @@
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Kas kasutame üheklahvilisi kiirklahve, näiteks „m“ mikrofoni sisse/välja lülitamiseks.", "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Kas kasutame üheklahvilisi kiirklahve, näiteks „m“ mikrofoni sisse/välja lülitamiseks.",
"Single-key keyboard shortcuts": "Üheklahvilised kiirklahvid", "Single-key keyboard shortcuts": "Üheklahvilised kiirklahvid",
"{{name}} (Waiting for video...)": "{{name}} (Ootame videovoo algust...)", "{{name}} (Waiting for video...)": "{{name}} (Ootame videovoo algust...)",
"This feature is only supported on Firefox.": "See funktsionaalsus on toetatud vaid Firefoxis." "This feature is only supported on Firefox.": "See funktsionaalsus on toetatud vaid Firefoxis.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Kui saadad meile vealogid, siis on lihtsam vea põhjust otsida.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Ohoo, midagi on nüüd katki.</0>"
} }

View File

@@ -137,5 +137,7 @@
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Bascule sur les raccourcis clavier à touche unique, par exemple « m » pour désactiver / activer le micro.", "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Bascule sur les raccourcis clavier à touche unique, par exemple « m » pour désactiver / activer le micro.",
"Single-key keyboard shortcuts": "Raccourcis clavier en une touche", "Single-key keyboard shortcuts": "Raccourcis clavier en une touche",
"{{name}} (Waiting for video...)": "{{name}} (En attente de vidéo…)", "{{name}} (Waiting for video...)": "{{name}} (En attente de vidéo…)",
"This feature is only supported on Firefox.": "Cette fonctionnalité est prise en charge dans Firefox uniquement." "This feature is only supported on Firefox.": "Cette fonctionnalité est prise en charge dans Firefox uniquement.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Soumettre les journaux de débogage nous aidera à déterminer le problème.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Oups, quelque chose sest mal passé.</0>"
} }

View File

@@ -137,5 +137,7 @@
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Apakah pintasan papan ketik seharusnya diaktifkan, mis. 'm' untuk membisukan/menyuarakan mikrofon.", "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Apakah pintasan papan ketik seharusnya diaktifkan, mis. 'm' untuk membisukan/menyuarakan mikrofon.",
"Single-key keyboard shortcuts": "Pintasan papan ketik satu tombol", "Single-key keyboard shortcuts": "Pintasan papan ketik satu tombol",
"{{name}} (Waiting for video...)": "{{name}} (Menunggu video...)", "{{name}} (Waiting for video...)": "{{name}} (Menunggu video...)",
"This feature is only supported on Firefox.": "Fitur ini hanya didukung di Firefox." "This feature is only supported on Firefox.": "Fitur ini hanya didukung di Firefox.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Mengirim catatan pengawakutuan akan membantu kami melacak masalahnya.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Aduh, ada yang salah.</0>"
} }

View File

@@ -137,5 +137,7 @@
"{{displayName}}, your call is now ended": "{{displayName}}, váš hovor je teraz ukončený", "{{displayName}}, your call is now ended": "{{displayName}}, váš hovor je teraz ukončený",
"{{count}} people connected|other": "{{count}} osôb pripojených", "{{count}} people connected|other": "{{count}} osôb pripojených",
"{{count}} people connected|one": "{{count}} osoba pripojená", "{{count}} people connected|one": "{{count}} osoba pripojená",
"This feature is only supported on Firefox.": "Táto funkcia je podporovaná len v prehliadači Firefox." "This feature is only supported on Firefox.": "Táto funkcia je podporovaná len v prehliadači Firefox.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Odoslanie záznamov ladenia nám pomôže nájsť problém.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Hups, niečo sa pokazilo.</0>"
} }

View File

@@ -137,5 +137,7 @@
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Чи вмикати/вимикати мікрофон однією клавішею, наприклад, «m» для ввімкнення/вимкнення мікрофона.", "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Чи вмикати/вимикати мікрофон однією клавішею, наприклад, «m» для ввімкнення/вимкнення мікрофона.",
"Single-key keyboard shortcuts": "Одноклавішні комбінації клавіш", "Single-key keyboard shortcuts": "Одноклавішні комбінації клавіш",
"{{name}} (Waiting for video...)": "{{name}} (Очікування на відео...)", "{{name}} (Waiting for video...)": "{{name}} (Очікування на відео...)",
"This feature is only supported on Firefox.": "Ця функція підтримується лише в браузері Firefox." "This feature is only supported on Firefox.": "Ця функція підтримується лише в браузері Firefox.",
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Надсилання журналів зневадження допоможе нам виявити проблему.</0>",
"<0>Oops, something's gone wrong.</0>": "<0>Йой, щось пішло не за планом.</0>"
} }

View File

@@ -28,7 +28,6 @@ import {
SignupTracker, SignupTracker,
MuteCameraTracker, MuteCameraTracker,
MuteMicrophoneTracker, MuteMicrophoneTracker,
UndecryptableToDeviceEventTracker,
} from "./PosthogEvents"; } from "./PosthogEvents";
import { Config } from "./config/Config"; import { Config } from "./config/Config";
import { getUrlParams } from "./UrlParams"; import { getUrlParams } from "./UrlParams";
@@ -416,5 +415,4 @@ export class PosthogAnalytics {
public eventLogin = new LoginTracker(); public eventLogin = new LoginTracker();
public eventMuteMicrophone = new MuteMicrophoneTracker(); public eventMuteMicrophone = new MuteMicrophoneTracker();
public eventMuteCamera = new MuteCameraTracker(); public eventMuteCamera = new MuteCameraTracker();
public eventUndecryptableToDevice = new UndecryptableToDeviceEventTracker();
} }

View File

@@ -149,17 +149,3 @@ export class MuteCameraTracker {
}); });
} }
} }
interface UndecryptableToDeviceEvent {
eventName: "UndecryptableToDeviceEvent";
callId: string;
}
export class UndecryptableToDeviceEventTracker {
track(callId: string) {
PosthogAnalytics.instance.trackEvent<UndecryptableToDeviceEvent>({
eventName: "UndecryptableToDeviceEvent",
callId,
});
}
}

View File

@@ -94,17 +94,12 @@ export async function initClient(
const storeOpts = {} as ICreateClientOpts; const storeOpts = {} as ICreateClientOpts;
if (indexedDB && localStorage) { if (indexedDB && localStorage && !import.meta.env.DEV) {
storeOpts.store = new IndexedDBStore({ storeOpts.store = new IndexedDBStore({
indexedDB: window.indexedDB, indexedDB: window.indexedDB,
localStorage, localStorage,
dbName: SYNC_STORE_NAME, dbName: SYNC_STORE_NAME,
// We can't use the worker in dev mode because Vite simply doesn't bundle workers workerFactory: () => new IndexedDBWorker(),
// in dev mode: it expects them to use native modules. Ours don't, and even then only
// Chrome supports it. (It bundles them fine in production mode.)
workerFactory: import.meta.env.DEV
? undefined
: () => new IndexedDBWorker(),
}); });
} else if (localStorage) { } else if (localStorage) {
storeOpts.store = new MemoryStore({ localStorage }); storeOpts.store = new MemoryStore({ localStorage });

View File

@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import * as Sentry from "@sentry/react";
import { Resizable } from "re-resizable"; import { Resizable } from "re-resizable";
import React, { import React, {
useEffect, useEffect,
@@ -35,7 +34,6 @@ import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
import styles from "./GroupCallInspector.module.css"; import styles from "./GroupCallInspector.module.css";
import { SelectInput } from "../input/SelectInput"; import { SelectInput } from "../input/SelectInput";
import { PosthogAnalytics } from "../PosthogAnalytics";
interface InspectorContextState { interface InspectorContextState {
eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] }; eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] };
@@ -110,19 +108,6 @@ function formatTimestamp(timestamp: number | Date) {
return dateFormatter.format(timestamp); return dateFormatter.format(timestamp);
} }
function formatType(event: SequenceDiagramMatrixEvent): string {
if (event.content.msgtype === "m.bad.encrypted") return "Undecryptable";
return event.type;
}
function lineForEvent(event: SequenceDiagramMatrixEvent): string {
return `${getUserName(event.from)} ${
event.ignored ? "-x" : "->>"
} ${getUserName(event.to)}: ${formatTimestamp(event.timestamp)} ${formatType(
event
)} ${formatContent(event.type, event.content)}`;
}
export const InspectorContext = export const InspectorContext =
createContext< createContext<
[ [
@@ -202,7 +187,21 @@ export function SequenceDiagramViewer({
participant ${getUserName(localUserId)} participant ${getUserName(localUserId)}
participant Room participant Room
participant ${selectedUserId ? getUserName(selectedUserId) : "unknown"} participant ${selectedUserId ? getUserName(selectedUserId) : "unknown"}
${events ? events.map(lineForEvent).join("\n ") : ""} ${
events
? events
.map(
({ to, from, timestamp, type, content, ignored }) =>
`${getUserName(from)} ${ignored ? "-x" : "->>"} ${getUserName(
to
)}: ${formatTimestamp(timestamp)} ${type} ${formatContent(
type,
content
)}`
)
.join("\n ")
: ""
}
`; `;
mermaid.mermaidAPI.render("mermaid", graphDefinition, (svgCode: string) => { mermaid.mermaidAPI.render("mermaid", graphDefinition, (svgCode: string) => {
@@ -390,23 +389,12 @@ function useGroupCallState(
function onSendVoipEvent(event: Record<string, unknown>) { function onSendVoipEvent(event: Record<string, unknown>) {
dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event }); dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event });
} }
function onUndecryptableToDevice(event: MatrixEvent) {
dispatch({ type: ClientEvent.ReceivedVoipEvent, event });
Sentry.captureMessage("Undecryptable to-device Event");
PosthogAnalytics.instance.eventUndecryptableToDevice.track(
groupCall.groupCallId
);
}
client.on(RoomStateEvent.Events, onUpdateRoomState); client.on(RoomStateEvent.Events, onUpdateRoomState);
//groupCall.on("calls_changed", onCallsChanged); //groupCall.on("calls_changed", onCallsChanged);
groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent); groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent);
//client.on("state", onCallsChanged); //client.on("state", onCallsChanged);
//client.on("hangup", onCallHangup); //client.on("hangup", onCallHangup);
client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
client.on(ClientEvent.UndecryptableToDeviceEvent, onUndecryptableToDevice);
onUpdateRoomState(); onUpdateRoomState();
@@ -417,10 +405,6 @@ function useGroupCallState(
//client.removeListener("state", onCallsChanged); //client.removeListener("state", onCallsChanged);
//client.removeListener("hangup", onCallHangup); //client.removeListener("hangup", onCallHangup);
client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent); client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
client.removeListener(
ClientEvent.UndecryptableToDeviceEvent,
onUndecryptableToDevice
);
}; };
}, [client, groupCall]); }, [client, groupCall]);

View File

@@ -75,7 +75,6 @@ export function GroupCallView({
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
toggleScreensharing, toggleScreensharing,
setMicrophoneMuted,
requestingScreenshare, requestingScreenshare,
isScreensharing, isScreensharing,
screenshareFeeds, screenshareFeeds,
@@ -252,7 +251,6 @@ export function GroupCallView({
localVideoMuted={localVideoMuted} localVideoMuted={localVideoMuted}
toggleLocalVideoMuted={toggleLocalVideoMuted} toggleLocalVideoMuted={toggleLocalVideoMuted}
toggleMicrophoneMuted={toggleMicrophoneMuted} toggleMicrophoneMuted={toggleMicrophoneMuted}
setMicrophoneMuted={setMicrophoneMuted}
userMediaFeeds={userMediaFeeds} userMediaFeeds={userMediaFeeds}
activeSpeaker={activeSpeaker} activeSpeaker={activeSpeaker}
onLeave={onLeave} onLeave={onLeave}

View File

@@ -63,7 +63,6 @@ import { usePrefersReducedMotion } from "../usePrefersReducedMotion";
import { ParticipantInfo } from "./useGroupCall"; import { ParticipantInfo } from "./useGroupCall";
import { TileDescriptor } from "../video-grid/TileDescriptor"; import { TileDescriptor } from "../video-grid/TileDescriptor";
import { AudioSink } from "../video-grid/AudioSink"; import { AudioSink } from "../video-grid/AudioSink";
import { useCallViewKeyboardShortcuts } from "../useCallViewKeyboardShortcuts";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
// There is currently a bug in Safari our our code with cloning and sending MediaStreams // There is currently a bug in Safari our our code with cloning and sending MediaStreams
@@ -82,7 +81,6 @@ interface Props {
toggleLocalVideoMuted: () => void; toggleLocalVideoMuted: () => void;
toggleMicrophoneMuted: () => void; toggleMicrophoneMuted: () => void;
toggleScreensharing: () => void; toggleScreensharing: () => void;
setMicrophoneMuted: (muted: boolean) => void;
userMediaFeeds: CallFeed[]; userMediaFeeds: CallFeed[];
activeSpeaker: CallFeed | null; activeSpeaker: CallFeed | null;
onLeave: () => void; onLeave: () => void;
@@ -103,7 +101,6 @@ export function InCallView({
localVideoMuted, localVideoMuted,
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
setMicrophoneMuted,
userMediaFeeds, userMediaFeeds,
activeSpeaker, activeSpeaker,
onLeave, onLeave,
@@ -144,13 +141,6 @@ export function InCallView({
const { hideScreensharing } = useUrlParams(); const { hideScreensharing } = useUrlParams();
useCallViewKeyboardShortcuts(
!feedbackModalState.isOpen,
toggleMicrophoneMuted,
toggleLocalVideoMuted,
setMicrophoneMuted
);
useEffect(() => { useEffect(() => {
widget?.api.transport.send( widget?.api.transport.send(
layout === "freedom" layout === "freedom"

View File

@@ -32,6 +32,8 @@ import { usePageUnload } from "./usePageUnload";
import { PosthogAnalytics } from "../PosthogAnalytics"; import { PosthogAnalytics } from "../PosthogAnalytics";
import { TranslatedError, translatedError } from "../TranslatedError"; import { TranslatedError, translatedError } from "../TranslatedError";
import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget"; import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget";
import { getSetting } from "../settings/useSetting";
import { useEventTarget } from "../useEvents";
export enum ConnectionState { export enum ConnectionState {
EstablishingCall = "establishing call", // call hasn't been established yet EstablishingCall = "establishing call", // call hasn't been established yet
@@ -58,7 +60,6 @@ export interface UseGroupCallReturnType {
toggleLocalVideoMuted: () => void; toggleLocalVideoMuted: () => void;
toggleMicrophoneMuted: () => void; toggleMicrophoneMuted: () => void;
toggleScreensharing: () => void; toggleScreensharing: () => void;
setMicrophoneMuted: (muted: boolean) => void;
requestingScreenshare: boolean; requestingScreenshare: boolean;
isScreensharing: boolean; isScreensharing: boolean;
screenshareFeeds: CallFeed[]; screenshareFeeds: CallFeed[];
@@ -471,6 +472,68 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
} }
}, [t, updateState]); }, [t, updateState]);
const [spacebarHeld, setSpacebarHeld] = useState(false);
useEventTarget(
window,
"keydown",
useCallback(
(event: KeyboardEvent) => {
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === "m") {
toggleMicrophoneMuted();
} else if (event.key == "v") {
toggleLocalVideoMuted();
} else if (event.key === " ") {
setSpacebarHeld(true);
setMicrophoneMuted(false);
}
},
[
toggleLocalVideoMuted,
toggleMicrophoneMuted,
setMicrophoneMuted,
setSpacebarHeld,
]
)
);
useEventTarget(
window,
"keyup",
useCallback(
(event: KeyboardEvent) => {
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === " ") {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
},
[setMicrophoneMuted, setSpacebarHeld]
)
);
useEventTarget(
window,
"blur",
useCallback(() => {
if (spacebarHeld) {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
}, [setMicrophoneMuted, setSpacebarHeld, spacebarHeld])
);
return { return {
state, state,
localCallFeed, localCallFeed,
@@ -485,7 +548,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
toggleScreensharing, toggleScreensharing,
setMicrophoneMuted,
requestingScreenshare, requestingScreenshare,
isScreensharing, isScreensharing,
screenshareFeeds, screenshareFeeds,

View File

@@ -1,4 +1,21 @@
/* /*
Copyright 2022 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* eslint-disable @typescript-eslint/ban-ts-comment */
/*
Copyright 2017 OpenMarket Ltd Copyright 2017 OpenMarket Ltd
Copyright 2018 New Vector Ltd Copyright 2018 New Vector Ltd
Copyright 2019 The New Vector Ltd Copyright 2019 The New Vector Ltd
@@ -37,23 +54,15 @@ limitations under the License.
// actually timestamps. We then purge the remaining logs. We also do this // actually timestamps. We then purge the remaining logs. We also do this
// purge on startup to prevent logs from accumulating. // purge on startup to prevent logs from accumulating.
import EventEmitter from "events";
import { throttle } from "lodash";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { randomString } from "matrix-js-sdk/src/randomstring"; import { randomString } from "matrix-js-sdk/src/randomstring";
// the frequency with which we flush to indexeddb
const FLUSH_RATE_MS = 30 * 1000;
// the length of log data we keep in indexeddb (and include in the reports) // the length of log data we keep in indexeddb (and include in the reports)
const MAX_LOG_SIZE = 1024 * 1024 * 5; // 5 MB const MAX_LOG_SIZE = 1024 * 1024 * 5; // 5 MB
// Shortest amount of time between flushes. We are just appending to an
// IndexedDB table so we don't expect flushing to be that expensive, but
// we can batch the writes a little.
const MAX_FLUSH_INTERVAL_MS = 2 * 1000;
enum ConsoleLoggerEvent {
Log = "log",
}
type LogFunction = ( type LogFunction = (
...args: (Error | DOMException | object | string)[] ...args: (Error | DOMException | object | string)[]
) => void; ) => void;
@@ -67,7 +76,7 @@ interface LogEntry {
index?: number; index?: number;
} }
export class ConsoleLogger extends EventEmitter { export class ConsoleLogger {
private logs = ""; private logs = "";
private originalFunctions: { [key in LogFunctionName]?: LogFunction } = {}; private originalFunctions: { [key in LogFunctionName]?: LogFunction } = {};
@@ -90,6 +99,13 @@ export class ConsoleLogger extends EventEmitter {
}); });
} }
public bypassRageshake(
fnName: LogFunctionName,
...args: (Error | DOMException | object | string)[]
): void {
this.originalFunctions[fnName](...args);
}
public log( public log(
level: string, level: string,
...args: (Error | DOMException | object | string)[] ...args: (Error | DOMException | object | string)[]
@@ -121,27 +137,23 @@ export class ConsoleLogger extends EventEmitter {
// Using + really is the quickest way in JS // Using + really is the quickest way in JS
// http://jsperf.com/concat-vs-plus-vs-join // http://jsperf.com/concat-vs-plus-vs-join
this.logs += line; this.logs += line;
this.emit(ConsoleLoggerEvent.Log);
} }
/** /**
* Returns the log lines to flush to disk and empties the internal log buffer * Retrieve log lines to flush to disk.
* @return {string} \n delimited log lines * @param {boolean} keepLogs True to not delete logs after flushing.
* @return {string} \n delimited log lines to flush.
*/ */
public popLogs(): string { public flush(keepLogs?: boolean): string {
// The ConsoleLogger doesn't care how these end up on disk, it just
// flushes them to the caller.
if (keepLogs) {
return this.logs;
}
const logsToFlush = this.logs; const logsToFlush = this.logs;
this.logs = ""; this.logs = "";
return logsToFlush; return logsToFlush;
} }
/**
* Returns lines currently in the log buffer without removing them
* @return {string} \n delimited log lines
*/
public peekLogs(): string {
return this.logs;
}
} }
// A class which stores log lines in an IndexedDB instance. // A class which stores log lines in an IndexedDB instance.
@@ -152,14 +164,8 @@ export class IndexedDBLogStore {
private flushAgainPromise: Promise<void> = null; private flushAgainPromise: Promise<void> = null;
private id: string; private id: string;
constructor( constructor(private indexedDB: IDBFactory, private logger: ConsoleLogger) {
private indexedDB: IDBFactory,
private loggerInstance: ConsoleLogger
) {
this.id = "instance-" + randomString(16); this.id = "instance-" + randomString(16);
loggerInstance.on(ConsoleLoggerEvent.Log, this.onLoggerLog);
window.addEventListener("beforeunload", this.flush);
} }
/** /**
@@ -168,31 +174,30 @@ export class IndexedDBLogStore {
public connect(): Promise<void> { public connect(): Promise<void> {
const req = this.indexedDB.open("logs"); const req = this.indexedDB.open("logs");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
req.onsuccess = () => { req.onsuccess = (event: Event) => {
this.db = req.result; // @ts-ignore
this.db = event.target.result;
// Periodically flush logs to local storage / indexeddb
setInterval(this.flush.bind(this), FLUSH_RATE_MS);
resolve(); resolve();
}; };
req.onerror = () => { req.onerror = (event) => {
const err = "Failed to open log database: " + req.error.name; const err =
// @ts-ignore
"Failed to open log database: " + event.target.error.name;
logger.error(err); logger.error(err);
reject(new Error(err)); reject(new Error(err));
}; };
// First time: Setup the object store // First time: Setup the object store
req.onupgradeneeded = () => { req.onupgradeneeded = (event) => {
const db = req.result; // @ts-ignore
// This is the log entries themselves. Each entry is a chunk of const db = event.target.result;
// logs (ie multiple lines). 'id' is the instance ID (so logs with
// the same instance ID are all from the same session) and 'index'
// is a sequence number for the chunk. The log lines live in the
// 'lines' key, which is a chunk of many newline-separated log lines.
const logObjStore = db.createObjectStore("logs", { const logObjStore = db.createObjectStore("logs", {
keyPath: ["id", "index"], keyPath: ["id", "index"],
}); });
// Keys in the database look like: [ "instance-148938490", 0 ] // Keys in the database look like: [ "instance-148938490", 0 ]
// (The instance ID plus the ID of each log chunk).
// Later on we need to query everything based on an instance id. // Later on we need to query everything based on an instance id.
// In order to do this, we need to set up indexes "id". // In order to do this, we need to set up indexes "id".
logObjStore.createIndex("id", "id", { unique: false }); logObjStore.createIndex("id", "id", { unique: false });
@@ -201,9 +206,6 @@ export class IndexedDBLogStore {
this.generateLogEntry(new Date() + " ::: Log database was created.") this.generateLogEntry(new Date() + " ::: Log database was created.")
); );
// This records the last time each instance ID generated a log message, such
// that the logs from each session can be collated in the order they last logged
// something.
const lastModifiedStore = db.createObjectStore("logslastmod", { const lastModifiedStore = db.createObjectStore("logslastmod", {
keyPath: "id", keyPath: "id",
}); });
@@ -212,26 +214,6 @@ export class IndexedDBLogStore {
}); });
} }
private onLoggerLog = () => {
if (!this.db) return;
this.throttledFlush();
};
// Throttled function to flush logs. We use throttle rather
// than debounce as we want logs to be written regularly, otherwise
// if there's a constant stream of logging, we'd never write anything.
private throttledFlush = throttle(
() => {
this.flush();
},
MAX_FLUSH_INTERVAL_MS,
{
leading: false,
trailing: true,
}
);
/** /**
* Flush logs to disk. * Flush logs to disk.
* *
@@ -251,7 +233,7 @@ export class IndexedDBLogStore {
* *
* @return {Promise} Resolved when the logs have been flushed. * @return {Promise} Resolved when the logs have been flushed.
*/ */
public flush = (): Promise<void> => { public flush(): Promise<void> {
// check if a flush() operation is ongoing // check if a flush() operation is ongoing
if (this.flushPromise) { if (this.flushPromise) {
if (this.flushAgainPromise) { if (this.flushAgainPromise) {
@@ -276,19 +258,20 @@ export class IndexedDBLogStore {
reject(new Error("No connected database")); reject(new Error("No connected database"));
return; return;
} }
const lines = this.loggerInstance.popLogs(); const lines = this.logger.flush();
if (lines.length === 0) { if (lines.length === 0) {
resolve(); resolve();
return; return;
} }
const txn = this.db.transaction(["logs", "logslastmod"], "readwrite"); const txn = this.db.transaction(["logs", "logslastmod"], "readwrite");
const objStore = txn.objectStore("logs"); const objStore = txn.objectStore("logs");
txn.oncomplete = () => { txn.oncomplete = (event) => {
resolve(); resolve();
}; };
txn.onerror = (event) => { txn.onerror = (event) => {
logger.error("Failed to flush logs : ", event); logger.error("Failed to flush logs : ", event);
reject(new Error("Failed to write logs: " + txn.error.message)); // @ts-ignore
reject(new Error("Failed to write logs: " + event.target.errorCode));
}; };
objStore.add(this.generateLogEntry(lines)); objStore.add(this.generateLogEntry(lines));
const lastModStore = txn.objectStore("logslastmod"); const lastModStore = txn.objectStore("logslastmod");
@@ -297,7 +280,7 @@ export class IndexedDBLogStore {
this.flushPromise = null; this.flushPromise = null;
}); });
return this.flushPromise; return this.flushPromise;
}; }
/** /**
* Consume the most recent logs and return them. Older logs which are not * Consume the most recent logs and return them. Older logs which are not
@@ -324,11 +307,13 @@ export class IndexedDBLogStore {
.index("id") .index("id")
.openCursor(IDBKeyRange.only(id), "prev"); .openCursor(IDBKeyRange.only(id), "prev");
let lines = ""; let lines = "";
query.onerror = () => { query.onerror = (event) => {
reject(new Error("Query failed: " + query.error.message)); // @ts-ignore
reject(new Error("Query failed: " + event.target.errorCode));
}; };
query.onsuccess = () => { query.onsuccess = (event) => {
const cursor = query.result; // @ts-ignore
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
resolve(lines); resolve(lines);
return; // end of results return; // end of results
@@ -370,8 +355,9 @@ export class IndexedDBLogStore {
const o = txn.objectStore("logs"); const o = txn.objectStore("logs");
// only load the key path, not the data which may be huge // only load the key path, not the data which may be huge
const query = o.index("id").openKeyCursor(IDBKeyRange.only(id)); const query = o.index("id").openKeyCursor(IDBKeyRange.only(id));
query.onsuccess = () => { query.onsuccess = (event) => {
const cursor = query.result; // @ts-ignore
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
return; return;
} }
@@ -381,10 +367,12 @@ export class IndexedDBLogStore {
txn.oncomplete = () => { txn.oncomplete = () => {
resolve(); resolve();
}; };
txn.onerror = () => { txn.onerror = (event) => {
reject( reject(
new Error( new Error(
"Failed to delete logs for " + `'${id}' : ${txn.error.message}` "Failed to delete logs for " +
// @ts-ignore
`'${id}' : ${event.target.errorCode}`
) )
); );
}; };
@@ -468,12 +456,14 @@ function selectQuery<T>(
const query = store.openCursor(keyRange); const query = store.openCursor(keyRange);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const results = []; const results = [];
query.onerror = () => { query.onerror = (event) => {
reject(new Error("Query failed: " + query.error.message)); // @ts-ignore
reject(new Error("Query failed: " + event.target.errorCode));
}; };
// collect results // collect results
query.onsuccess = () => { query.onsuccess = (event) => {
const cursor = query.result; // @ts-ignore
const cursor = event.target.result;
if (!cursor) { if (!cursor) {
resolve(results); resolve(results);
return; // end of results return; // end of results
@@ -489,6 +479,8 @@ declare global {
// eslint-disable-next-line no-var, camelcase // eslint-disable-next-line no-var, camelcase
var mx_rage_logger: ConsoleLogger; var mx_rage_logger: ConsoleLogger;
// eslint-disable-next-line no-var, camelcase // eslint-disable-next-line no-var, camelcase
var mx_rage_initPromise: Promise<void>;
// eslint-disable-next-line no-var, camelcase
var mx_rage_initStoragePromise: Promise<void>; var mx_rage_initStoragePromise: Promise<void>;
} }
@@ -499,11 +491,19 @@ declare global {
* be set up immediately for the logs. * be set up immediately for the logs.
* @return {Promise} Resolves when set up. * @return {Promise} Resolves when set up.
*/ */
export function init(): Promise<void> { export function init(setUpPersistence = true): Promise<void> {
if (global.mx_rage_initPromise) {
return global.mx_rage_initPromise;
}
global.mx_rage_logger = new ConsoleLogger(); global.mx_rage_logger = new ConsoleLogger();
global.mx_rage_logger.monkeyPatch(window.console); global.mx_rage_logger.monkeyPatch(window.console);
return tryInitStorage(); if (setUpPersistence) {
return tryInitStorage();
}
global.mx_rage_initPromise = Promise.resolve();
return global.mx_rage_initPromise;
} }
/** /**
@@ -573,7 +573,7 @@ export async function getLogsForReport(): Promise<LogEntry[]> {
} else { } else {
return [ return [
{ {
lines: global.mx_rage_logger.peekLogs(), lines: global.mx_rage_logger.flush(true),
id: "-", id: "-",
}, },
]; ];

View File

@@ -1,93 +0,0 @@
/*
Copyright 2022-2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { useCallback, useState } from "react";
import { getSetting } from "./settings/useSetting";
import { useEventTarget } from "./useEvents";
export function useCallViewKeyboardShortcuts(
enabled: boolean,
toggleMicrophoneMuted: () => void,
toggleLocalVideoMuted: () => void,
setMicrophoneMuted: (muted: boolean) => void
) {
const [spacebarHeld, setSpacebarHeld] = useState(false);
useEventTarget(
window,
"keydown",
useCallback(
(event: KeyboardEvent) => {
if (!enabled) return;
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === "m") {
toggleMicrophoneMuted();
} else if (event.key == "v") {
toggleLocalVideoMuted();
} else if (event.key === " " && !spacebarHeld) {
setSpacebarHeld(true);
setMicrophoneMuted(false);
}
},
[
enabled,
spacebarHeld,
toggleLocalVideoMuted,
toggleMicrophoneMuted,
setMicrophoneMuted,
setSpacebarHeld,
]
)
);
useEventTarget(
window,
"keyup",
useCallback(
(event: KeyboardEvent) => {
if (!enabled) return;
// Check if keyboard shortcuts are enabled
const keyboardShortcuts = getSetting("keyboard-shortcuts", true);
if (!keyboardShortcuts) {
return;
}
if (event.key === " ") {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
},
[enabled, setMicrophoneMuted, setSpacebarHeld]
)
);
useEventTarget(
window,
"blur",
useCallback(() => {
if (spacebarHeld) {
setSpacebarHeld(false);
setMicrophoneMuted(true);
}
}, [setMicrophoneMuted, setSpacebarHeld, spacebarHeld])
);
}

View File

@@ -31,14 +31,15 @@ export const AudioSink: React.FC<Props> = ({
tileDescriptor, tileDescriptor,
audioOutput, audioOutput,
}: Props) => { }: Props) => {
const { audioMuted, localVolume, stream } = useCallFeed( const { localVolume, stream } = useCallFeed(tileDescriptor.callFeed);
tileDescriptor.callFeed
);
const audioElementRef = useMediaStream( const audioElementRef = useMediaStream(
stream, stream,
audioOutput, audioOutput,
audioMuted, // We don't compare the audioMuted flag of useCallFeed here, since unmuting
// depends on to-device messages which may lag behind the audio actually
// starting to flow over the stream
tileDescriptor.isLocal,
localVolume localVolume
); );

View File

@@ -36,6 +36,7 @@ interface Props {
mediaRef?: React.RefObject<MediaElement>; mediaRef?: React.RefObject<MediaElement>;
onOptionsPress?: () => void; onOptionsPress?: () => void;
localVolume?: number; localVolume?: number;
hasAudio?: boolean;
maximised?: boolean; maximised?: boolean;
fullscreen?: boolean; fullscreen?: boolean;
onFullscreen?: () => void; onFullscreen?: () => void;
@@ -58,6 +59,7 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
mediaRef, mediaRef,
onOptionsPress, onOptionsPress,
localVolume, localVolume,
hasAudio,
maximised, maximised,
fullscreen, fullscreen,
onFullscreen, onFullscreen,
@@ -74,14 +76,16 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
const toolbarButtons: JSX.Element[] = []; const toolbarButtons: JSX.Element[] = [];
if (connectionState == ConnectionState.Connected && !isLocal) { if (connectionState == ConnectionState.Connected && !isLocal) {
toolbarButtons.push( if (hasAudio) {
<AudioButton toolbarButtons.push(
key="localVolume" <AudioButton
className={styles.button} key="localVolume"
volume={localVolume} className={styles.button}
onPress={onOptionsPress} volume={localVolume}
/> onPress={onOptionsPress}
); />
);
}
if (screenshare) { if (screenshare) {
toolbarButtons.push( toolbarButtons.push(
@@ -137,7 +141,13 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
</div> </div>
) : ( ) : (
<div className={classNames(styles.infoBubble, styles.memberName)}> <div className={classNames(styles.infoBubble, styles.memberName)}>
{audioMuted && !videoMuted && <MicMutedIcon />} {
/* If the user is speaking, it's safe to say they're unmuted.
Mute state is currently sent over to-device messages, which
aren't quite real-time, so this is an important kludge to make
sure no one appears muted when they've clearly begun talking. */
audioMuted && !videoMuted && !speaking && <MicMutedIcon />
}
{videoMuted && <VideoMutedIcon />} {videoMuted && <VideoMutedIcon />}
<span title={caption}>{caption}</span> <span title={caption}>{caption}</span>
</div> </div>

View File

@@ -62,6 +62,7 @@ export function VideoTileContainer({
audioMuted, audioMuted,
videoMuted, videoMuted,
localVolume, localVolume,
hasAudio,
speaking, speaking,
stream, stream,
purpose, purpose,
@@ -109,6 +110,7 @@ export function VideoTileContainer({
avatar={getAvatar && getAvatar(item.member, width, height)} avatar={getAvatar && getAvatar(item.member, width, height)}
onOptionsPress={onOptionsPress} onOptionsPress={onOptionsPress}
localVolume={localVolume} localVolume={localVolume}
hasAudio={hasAudio}
maximised={maximised} maximised={maximised}
fullscreen={fullscreen} fullscreen={fullscreen}
onFullscreen={onFullscreenCallback} onFullscreen={onFullscreenCallback}

View File

@@ -25,6 +25,7 @@ interface CallFeedState {
videoMuted: boolean; videoMuted: boolean;
audioMuted: boolean; audioMuted: boolean;
localVolume: number; localVolume: number;
hasAudio: boolean;
disposed: boolean | undefined; disposed: boolean | undefined;
stream: MediaStream | undefined; stream: MediaStream | undefined;
purpose: SDPStreamMetadataPurpose | undefined; purpose: SDPStreamMetadataPurpose | undefined;
@@ -38,6 +39,7 @@ function getCallFeedState(callFeed: CallFeed | undefined): CallFeedState {
videoMuted: callFeed ? callFeed.isVideoMuted() : true, videoMuted: callFeed ? callFeed.isVideoMuted() : true,
audioMuted: callFeed ? callFeed.isAudioMuted() : true, audioMuted: callFeed ? callFeed.isAudioMuted() : true,
localVolume: callFeed ? callFeed.getLocalVolume() : 0, localVolume: callFeed ? callFeed.getLocalVolume() : 0,
hasAudio: callFeed ? callFeed.stream.getAudioTracks().length >= 1 : false,
disposed: callFeed ? callFeed.disposed : undefined, disposed: callFeed ? callFeed.disposed : undefined,
stream: callFeed ? callFeed.stream : undefined, stream: callFeed ? callFeed.stream : undefined,
purpose: callFeed ? callFeed.purpose : undefined, purpose: callFeed ? callFeed.purpose : undefined,

View File

@@ -1826,9 +1826,9 @@
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.2.tgz#a09d0fea858e817da971a3c9f904632ef7b49eb6" resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.2.tgz#a09d0fea858e817da971a3c9f904632ef7b49eb6"
integrity sha512-oVkBCh9YP7H9i4gAoQbZzswniczfo/aIptNa4dxRi4Ff9lSvUCFv6Hvzi7C+90c0/PWZLXjIDTIAWZYmwyd2fA== integrity sha512-oVkBCh9YP7H9i4gAoQbZzswniczfo/aIptNa4dxRi4Ff9lSvUCFv6Hvzi7C+90c0/PWZLXjIDTIAWZYmwyd2fA==
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz": "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
version "3.2.8" version "3.2.14"
resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz#8d53636d045e1776e2a2ec6613e57330dd9ce856" resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz#acd96c00a881d0f462e1f97a56c73742c8dbc984"
"@mdx-js/mdx@^1.6.22": "@mdx-js/mdx@^1.6.22":
version "1.6.22" version "1.6.22"
@@ -2418,13 +2418,13 @@
"@sentry/utils" "6.19.7" "@sentry/utils" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/core@7.31.0": "@sentry/core@7.28.1":
version "7.31.0" version "7.28.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.31.0.tgz#2c1ec086cd86c097fc5c60703d33c848089597c7" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.28.1.tgz#c712ce17469b18b01606108817be24a99ed2116e"
integrity sha512-IZS1MZznyBOPw7UEpZwq3t3aaaVhFB+r3KM4JYFSJRr7Ky9TjldXA3hadNUTztjYGgEC3u8kB9jXoRvNXM2hqA== integrity sha512-7wvnuvn/mrAfcugWoCG/3pqDIrUgH5t+HisMJMGw0h9Tc33KqrmqMDCQVvjlrr2pWrw/vuUCFdm8CbUHJ832oQ==
dependencies: dependencies:
"@sentry/types" "7.31.0" "@sentry/types" "7.28.1"
"@sentry/utils" "7.31.0" "@sentry/utils" "7.28.1"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/hub@6.19.7": "@sentry/hub@6.19.7":
@@ -2446,13 +2446,13 @@
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/node@^7.19.0": "@sentry/node@^7.19.0":
version "7.31.0" version "7.28.1"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.31.0.tgz#d6b6776f7c1daee0a41e7f97fc15f058435f1b1c" resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.28.1.tgz#fc53675a048c29c86e5a8cd3ba570c454f492c18"
integrity sha512-DBjPfThZ5CIC2G9/CVFRlSOP/QqF1IoZXNpTUPZkhQ1cjShJeERT64jMkTdk+RAStSTpEfF6J0rUy1NIyHHEoQ== integrity sha512-n7AbpJqZJjWPpKNGc55mP7AdQ+XSomS9MZJuZ+Xt2AU52aVwGPI4z9aHUJFSDGaMHHiu/toyPnoUES+XZf6/hw==
dependencies: dependencies:
"@sentry/core" "7.31.0" "@sentry/core" "7.28.1"
"@sentry/types" "7.31.0" "@sentry/types" "7.28.1"
"@sentry/utils" "7.31.0" "@sentry/utils" "7.28.1"
cookie "^0.4.1" cookie "^0.4.1"
https-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0"
lru_map "^0.3.3" lru_map "^0.3.3"
@@ -2482,13 +2482,13 @@
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/tracing@^7.19.0": "@sentry/tracing@^7.19.0":
version "7.31.0" version "7.28.1"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.31.0.tgz#c37f1930aba05a4c461f655dc258eaa851e9a305" resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.28.1.tgz#d276e4d17a79190a88112696c73de12c209607a1"
integrity sha512-p/b9sOw2wwcDLp8p0bJ0oetgeEB1q/ueZaXDeBeSh+3GNKx6J4S3pcFpbMXDK8d2Ayd3P9Gvrm7y9Hc2ueJteg== integrity sha512-uWspnuz+7FyW8ES5lRaVA7O/YJSzMlSkvBFtgzaoKmdaueokU/sRLwlCsrdgwavG1wpm79df7R1iiSeqhaXDlw==
dependencies: dependencies:
"@sentry/core" "7.31.0" "@sentry/core" "7.28.1"
"@sentry/types" "7.31.0" "@sentry/types" "7.28.1"
"@sentry/utils" "7.31.0" "@sentry/utils" "7.28.1"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/types@6.19.7": "@sentry/types@6.19.7":
@@ -2496,10 +2496,10 @@
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
"@sentry/types@7.31.0": "@sentry/types@7.28.1":
version "7.31.0" version "7.28.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.31.0.tgz#c028519a660d76c4e8f18ba9e44ede45d314fcae" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.28.1.tgz#9018b4c152b475de9bedd267237393d3c9b1253d"
integrity sha512-nFqo7wyMnapdSEdw1MD+cavDtD9x5QQmh/bwLEOb/euM0cHFJHYyD7CveY/mQng4HyEVWY+DCtX/7E3GcQ7Bdw== integrity sha512-DvSplMVrVEmOzR2M161V5+B8Up3vR71xMqJOpWTzE9TqtFJRGPtqT/5OBsNJJw1+/j2ssMcnKwbEo9Q2EGeS6g==
"@sentry/types@^7.2.0": "@sentry/types@^7.2.0":
version "7.13.0" version "7.13.0"
@@ -2514,12 +2514,12 @@
"@sentry/types" "6.19.7" "@sentry/types" "6.19.7"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/utils@7.31.0": "@sentry/utils@7.28.1":
version "7.31.0" version "7.28.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.31.0.tgz#507290984c941fca8f5c2621a4b8b0aca8fbfc10" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.28.1.tgz#0a7b6aa4b09e91e4d1aded2a8c8dbaf818cee96e"
integrity sha512-B1KkvdfwlaqM7sDp3/yk2No7WsbMuLEywGRVOLzXeTqTLSBRBWyyYIudqPtx2LDds9anlUHj21zs9FKY+S3eiA== integrity sha512-75/jzLUO9HH09iC9TslNimGbxOP3jgn89P+q7uR+rp2fJfRExHVeKJZQdK0Ij4/SmE7TJ3Uh2r154N0INZEx1g==
dependencies: dependencies:
"@sentry/types" "7.31.0" "@sentry/types" "7.28.1"
tslib "^1.9.3" tslib "^1.9.3"
"@sentry/vite-plugin@^0.3.0": "@sentry/vite-plugin@^0.3.0":
@@ -10362,9 +10362,9 @@ matrix-events-sdk@0.0.1:
resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#a34d06c7c24c3523a77f70c01d4e31c45e92aa6b": "matrix-js-sdk@github:matrix-org/matrix-js-sdk#79575ef3760bb6085b7b770f241b3d32756d5b96":
version "23.0.0" version "23.0.0"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/a34d06c7c24c3523a77f70c01d4e31c45e92aa6b" resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/79575ef3760bb6085b7b770f241b3d32756d5b96"
dependencies: dependencies:
"@babel/runtime" "^7.12.5" "@babel/runtime" "^7.12.5"
"@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.2" "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.2"