diff --git a/src/App.tsx b/src/App.tsx index 285a48ef..e6df0846 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -77,9 +77,7 @@ export const App: FC = ({ history }) => { setLoaded(true); await widget?.api.sendContentLoaded(); }) - .catch((e) => { - logger.error(e); - }); + .catch(logger.error); }); const errorPage = ; diff --git a/src/analytics/PosthogAnalytics.ts b/src/analytics/PosthogAnalytics.ts index 8d39d344..10437d4b 100644 --- a/src/analytics/PosthogAnalytics.ts +++ b/src/analytics/PosthogAnalytics.ts @@ -399,7 +399,7 @@ export class PosthogAnalytics { if (this.identificationPromise) { // only make calls to posthog after the identification is done - this.identificationPromise.then(doCapture).catch((e) => { + this.identificationPromise.then(doCapture, (e) => { logger.error("Failed to identify user for tracking", e); }); } else { diff --git a/src/analytics/PosthogSpanProcessor.ts b/src/analytics/PosthogSpanProcessor.ts index cdc8e4ae..8967c3d3 100644 --- a/src/analytics/PosthogSpanProcessor.ts +++ b/src/analytics/PosthogSpanProcessor.ts @@ -43,20 +43,19 @@ export class PosthogSpanProcessor implements SpanProcessor { public onStart(span: Span): void { // Hack: Yield to allow attributes to be set before processing - Promise.resolve() - .then(() => { - switch (span.name) { - case "matrix.groupCallMembership": - this.onGroupCallMembershipStart(span); - return; - case "matrix.groupCallMembership.summaryReport": - this.onSummaryReportStart(span); - return; - } - }) - .catch((e) => { - // noop - }); + try { + switch (span.name) { + case "matrix.groupCallMembership": + this.onGroupCallMembershipStart(span); + return; + case "matrix.groupCallMembership.summaryReport": + this.onSummaryReportStart(span); + return; + } + } catch (e) { + // log to avoid tripping @typescript-eslint/no-unused-vars + logger.debug(e); + } } public onEnd(span: ReadableSpan): void { diff --git a/src/auth/useInteractiveLogin.ts b/src/auth/useInteractiveLogin.ts index e2ecb438..5836df6d 100644 --- a/src/auth/useInteractiveLogin.ts +++ b/src/auth/useInteractiveLogin.ts @@ -58,9 +58,8 @@ export function useInteractiveLogin( password, }), stateUpdated: (): void => {}, - requestEmailToken: async (): Promise<{ sid: string }> => { - return Promise.resolve({ sid: "" }); - }, + requestEmailToken: async (): Promise<{ sid: string }> => + Promise.resolve({ sid: "" }), }); // XXX: This claims to return an IAuthData which contains none of these diff --git a/src/auth/useInteractiveRegistration.ts b/src/auth/useInteractiveRegistration.ts index d8eaf6e7..4a191913 100644 --- a/src/auth/useInteractiveRegistration.ts +++ b/src/auth/useInteractiveRegistration.ts @@ -106,9 +106,8 @@ export const useInteractiveRegistration = ( }); } }, - requestEmailToken: async (): Promise<{ sid: string }> => { - return Promise.resolve({ sid: "dummy" }); - }, + requestEmailToken: async (): Promise<{ sid: string }> => + Promise.resolve({ sid: "dummy" }), }); // XXX: This claims to return an IAuthData which contains none of these diff --git a/src/config/Config.ts b/src/config/Config.ts index 97e7d203..d8c6770a 100644 --- a/src/config/Config.ts +++ b/src/config/Config.ts @@ -22,7 +22,7 @@ import { } from "./ConfigOptions"; export class Config { - private static internalInstance: Config; + private static internalInstance: Config | undefined; public static get(): ConfigOptions { if (!this.internalInstance?.config) @@ -31,22 +31,22 @@ export class Config { } public static async init(): Promise { - if (Config.internalInstance?.initPromise) { - return Config.internalInstance.initPromise; - } - Config.internalInstance = new Config(); + if (!Config.internalInstance?.initPromise) { + const internalInstance = new Config(); + Config.internalInstance = internalInstance; - Config.internalInstance.initPromise = downloadConfig("../config.json").then( - (config) => { - Config.internalInstance.config = { ...DEFAULT_CONFIG, ...config }; - }, - ); + Config.internalInstance.initPromise = downloadConfig( + "../config.json", + ).then((config) => { + internalInstance.config = { ...DEFAULT_CONFIG, ...config }; + }); + } return Config.internalInstance.initPromise; } /** * This is a alternative initializer that does not load anything - * from a hosted config file but instead just initializes the conifg using the + * from a hosted config file but instead just initializes the config using the * default config. * * It is supposed to only be used in tests. (It is executed in `vite.setup.js`) diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts index d8b8b1a7..e5bbed80 100644 --- a/src/e2ee/matrixKeyProvider.ts +++ b/src/e2ee/matrixKeyProvider.ts @@ -60,19 +60,20 @@ export class MatrixKeyProvider extends BaseKeyProvider { encryptionKeyIndex: number, participantId: string, ): void => { - createKeyMaterialFromBuffer(encryptionKey) - .then((keyMaterial) => { + createKeyMaterialFromBuffer(encryptionKey).then( + (keyMaterial) => { this.onSetEncryptionKey(keyMaterial, participantId, encryptionKeyIndex); logger.debug( `Sent new key to livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, ); - }) - .catch((e) => { + }, + (e) => { logger.error( `Failed to create key material from buffer for livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, e, ); - }); + }, + ); }; } diff --git a/src/grid/Grid.tsx b/src/grid/Grid.tsx index 801ba064..22ac36b3 100644 --- a/src/grid/Grid.tsx +++ b/src/grid/Grid.tsx @@ -41,6 +41,7 @@ import { } from "react"; import useMeasure from "react-use-measure"; import classNames from "classnames"; +import { logger } from "matrix-js-sdk/src/logger"; import styles from "./Grid.module.css"; import { useMergedRefs } from "../useMergedRefs"; @@ -362,7 +363,7 @@ export function Grid< // Because we're using react-spring in imperative mode, we're responsible for // firing animations manually whenever the tiles array updates useEffect(() => { - void springRef.start(); + springRef.start().forEach((p) => void p.catch(logger.error)); }, [placedTiles, springRef]); const animateDraggedTile = ( @@ -372,7 +373,7 @@ export function Grid< const { tileId, tileX, tileY } = dragState.current!; const tile = placedTiles.find((t) => t.id === tileId)!; - void springRef.current + springRef.current .find((c) => (c.item as Tile).id === tileId) ?.start( endOfGesture @@ -399,7 +400,8 @@ export function Grid< ((key): boolean => key === "zIndex" || key === "x" || key === "y"), }, - ); + ) + .catch(logger.error); if (endOfGesture) callback({ diff --git a/src/initializer.tsx b/src/initializer.tsx index 22aa5ded..ed98c2af 100644 --- a/src/initializer.tsx +++ b/src/initializer.tsx @@ -133,14 +133,15 @@ export class Initializer { // config if (this.loadStates.config === LoadState.None) { this.loadStates.config = LoadState.Loading; - Config.init() - .then(() => { + Config.init().then( + () => { this.loadStates.config = LoadState.Loaded; this.initStep(resolve); - }) - .catch((e) => { + }, + (e) => { logger.error("Failed to load config", e); - }); + }, + ); } //sentry (only initialize after the config is ready) diff --git a/src/livekit/openIDSFU.ts b/src/livekit/openIDSFU.ts index 2ebf4cd3..00861cf1 100644 --- a/src/livekit/openIDSFU.ts +++ b/src/livekit/openIDSFU.ts @@ -49,14 +49,18 @@ export function useOpenIDSFU( const activeFocus = useActiveLivekitFocus(rtcSession); useEffect(() => { - (async (): Promise => { - const sfuConfig = activeFocus - ? await getSFUConfigWithOpenID(client, activeFocus) - : undefined; - setSFUConfig(sfuConfig); - })().catch((e) => { - logger.error("Failed to get SFU config", e); - }); + if (activeFocus) { + getSFUConfigWithOpenID(client, activeFocus).then( + (sfuConfig) => { + setSFUConfig(sfuConfig); + }, + (e) => { + logger.error("Failed to get SFU config", e); + }, + ); + } else { + setSFUConfig(undefined); + } }, [client, activeFocus]); return sfuConfig; diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 49f2cd85..598eec2c 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -180,15 +180,13 @@ export const GroupCallView: FC = ({ if (widget && preload && skipLobby) { // In preload mode without lobby we wait for a join action before entering const onJoin = (ev: CustomEvent): void => { - defaultDeviceSetup(ev.detail.data as unknown as JoinCallData) - .catch((e) => { - logger.error("Error setting up default devices", e); - }) - .then(async () => enterRTCSession(rtcSession, perParticipantE2EE)) - .then(() => widget!.api.transport.reply(ev.detail, {})) - .catch((e) => { - logger.error("Error entering RTC session", e); - }); + (async (): Promise => { + await defaultDeviceSetup(ev.detail.data as unknown as JoinCallData); + await enterRTCSession(rtcSession, perParticipantE2EE); + widget!.api.transport.reply(ev.detail, {}); + })().catch((e) => { + logger.error("Error joining RTC session", e); + }); }; widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); return (): void => { @@ -196,14 +194,12 @@ export const GroupCallView: FC = ({ }; } else if (widget && !preload && skipLobby) { // No lobby and no preload: we enter the rtc session right away - defaultDeviceSetup({ audioInput: null, videoInput: null }) - .catch((e) => { - logger.error("Error setting up default devices", e); - }) - .then(async () => enterRTCSession(rtcSession, perParticipantE2EE)) - .catch((e) => { - logger.error("Error entering RTC session", e); - }); + (async (): Promise => { + await defaultDeviceSetup({ audioInput: null, videoInput: null }); + await enterRTCSession(rtcSession, perParticipantE2EE); + })().catch((e) => { + logger.error("Error joining RTC session", e); + }); } }, [rtcSession, preload, skipLobby, perParticipantE2EE]); diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index f9083e06..80bd427f 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -478,12 +478,14 @@ export const InCallView: FC = ({ ); const toggleScreensharing = useCallback(() => { - void localParticipant.setScreenShareEnabled(!isScreenShareEnabled, { - audio: true, - selfBrowserSurface: "include", - surfaceSwitching: "include", - systemAudio: "include", - }); + localParticipant + .setScreenShareEnabled(!isScreenShareEnabled, { + audio: true, + selfBrowserSurface: "include", + surfaceSwitching: "include", + systemAudio: "include", + }) + .catch(logger.error); }, [localParticipant, isScreenShareEnabled]); let footer: JSX.Element | null; diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index 69bdabbd..9fa51498 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -69,11 +69,11 @@ export const RoomPage: FC = () => { if (!loading && !authenticated && displayName && !widget) { setIsRegistering(true); registerPasswordlessUser(displayName) - .finally(() => { - setIsRegistering(false); - }) .catch((e) => { logger.error("Failed to register passwordless user", e); + }) + .finally(() => { + setIsRegistering(false); }); } }, [ diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index e0ac4b89..1000beb1 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -159,10 +159,9 @@ export const useLoadGroupCall = ( viaServers: string[], onKnockSent: () => void, ): Promise => { - let joinedRoom: Room | null = null; await client.knockRoom(roomId, { viaServers }); onKnockSent(); - const invitePromise = new Promise((resolve, reject) => { + return await new Promise((resolve, reject) => { client.on( RoomEvent.MyMembership, (room, membership, prevMembership): void => { @@ -172,14 +171,10 @@ export const useLoadGroupCall = ( membership === KnownMembership.Invite && prevMembership === KnownMembership.Knock ) { - client - .joinRoom(room.roomId, { viaServers }) - .then((room) => { - joinedRoom = room; - logger.log("Auto-joined %s", room.roomId); - resolve(); - }) - .catch((e) => reject(e)); + client.joinRoom(room.roomId, { viaServers }).then((room) => { + logger.log("Auto-joined %s", room.roomId); + resolve(room); + }, reject); } if (membership === KnownMembership.Ban) reject(bannedError()); if (membership === KnownMembership.Leave) @@ -187,11 +182,6 @@ export const useLoadGroupCall = ( }, ); }); - await invitePromise; - if (!joinedRoom) { - throw new Error("Failed to join room after knocking."); - } - return joinedRoom; }; const fetchOrCreateRoom = async (): Promise => { diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index 5fdd3c48..018f1eef 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -127,9 +127,14 @@ const widgetPostHangupProcedure = async ( // we need to wait until the callEnded event is tracked on posthog. // Otherwise the iFrame gets killed before the callEnded event got tracked. await new Promise((resolve) => window.setTimeout(resolve, 10)); // 10ms - await widget.api.setAlwaysOnScreen(false); PosthogAnalytics.instance.logout(); + try { + await widget.api.setAlwaysOnScreen(false); + } catch (e) { + logger.error("Failed to set call widget `alwaysOnScreen` to false", e); + } + // We send the hangup event after the memberships have been updated // calling leaveRTCSession. // We need to wait because this makes the client hosting this widget killing the IFrame. diff --git a/src/settings/rageshake.ts b/src/settings/rageshake.ts index 03d631d8..af6dbb9c 100644 --- a/src/settings/rageshake.ts +++ b/src/settings/rageshake.ts @@ -236,13 +236,9 @@ class IndexedDBLogStore { return this.flushAgainPromise; } // queue up a flush to occur immediately after the pending one completes. - this.flushAgainPromise = this.flushPromise - .then(async () => { - return this.flush(); - }) - .then(() => { - this.flushAgainPromise = undefined; - }); + this.flushAgainPromise = this.flushPromise.then(this.flush).then(() => { + this.flushAgainPromise = undefined; + }); return this.flushAgainPromise; } // there is no flush promise or there was but it has finished, so do diff --git a/src/useWakeLock.ts b/src/useWakeLock.ts index ff1f5e0a..debaa282 100644 --- a/src/useWakeLock.ts +++ b/src/useWakeLock.ts @@ -30,9 +30,8 @@ export function useWakeLock(): void { // so we need to reacquire it on visibility changes const onVisibilityChange = (): void => { if (document.visibilityState === "visible") { - navigator.wakeLock - .request("screen") - .then((newLock) => { + navigator.wakeLock.request("screen").then( + (newLock) => { lock = newLock; // Handle the edge case where this component unmounts before the // promise resolves @@ -40,10 +39,11 @@ export function useWakeLock(): void { lock .release() .catch((e) => logger.warn("Can't release wake lock", e)); - }) - .catch((e) => { + }, + (e) => { logger.warn("Can't acquire wake lock", e); - }); + }, + ); } }; diff --git a/src/utils/matrix.ts b/src/utils/matrix.ts index 612a7f4d..1c472046 100644 --- a/src/utils/matrix.ts +++ b/src/utils/matrix.ts @@ -269,40 +269,40 @@ export async function createRoom( }); // Wait for the room to arrive - await new Promise((resolve, reject) => { - const onRoom = (room: Room): void => { - createPromise - .then((result) => { - if (room.roomId === result.room_id) { - resolve(); - cleanUp(); - } - }) - .catch((e) => { - logger.error("Failed to wait for the room to arrive", e); - }); - }; + const roomId = await new Promise((resolve, reject) => { createPromise.catch((e) => { reject(e); cleanUp(); }); + const onRoom = (room: Room): void => { + createPromise.then( + (result) => { + if (room.roomId === result.room_id) { + resolve(room.roomId); + cleanUp(); + } + }, + (e) => { + logger.error("Failed to wait for the room to arrive", e); + }, + ); + }; + const cleanUp = (): void => { client.off(ClientEvent.Room, onRoom); }; client.on(ClientEvent.Room, onRoom); }); - const result = await createPromise; - - let password; + let password: string | undefined; if (e2ee == E2eeType.SHARED_KEY) { password = secureRandomBase64Url(16); - saveKeyForRoom(result.room_id, password); + saveKeyForRoom(roomId, password); } return { - roomId: result.room_id, + roomId, alias: e2ee ? undefined : fullAliasFromRoomName(name, client), password, };