diff --git a/src/@types/PushRules.ts b/src/@types/PushRules.ts index 59af4906074..7cdfeee2e23 100644 --- a/src/@types/PushRules.ts +++ b/src/@types/PushRules.ts @@ -169,8 +169,8 @@ export interface IPusher { lang: string; profile_tag?: string; pushkey: string; - enabled?: boolean | null | undefined; - "org.matrix.msc3881.enabled"?: boolean | null | undefined; + enabled?: boolean | null; + "org.matrix.msc3881.enabled"?: boolean | null; device_id?: string | null; "org.matrix.msc3881.device_id"?: string | null; } diff --git a/src/client.ts b/src/client.ts index 341b2cbecd7..c1b1bb6fe77 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2930,7 +2930,7 @@ export class MatrixClient extends TypedEventEmitter rule.rule_id === roomId); } else { throw new Error( "SyncApi.sync() must be done before accessing to push rules.", @@ -6473,8 +6465,6 @@ export class MatrixClient extends TypedEventEmitter[] = []; - for (let i = 0; i < users.length; ++i) { - const userId = users[i]; + for (const userId of users) { const devices = this.crypto.getStoredDevicesForUser(userId) || []; - for (let j = 0; j < devices.length; ++j) { - const deviceInfo = devices[j]; + for (const deviceInfo of devices) { const key = deviceInfo.getIdentityKey(); if (key == this.olmDevice.deviceCurve25519Key) { // don't bother sending to ourself @@ -304,8 +302,7 @@ class OlmDecryption extends DecryptionAlgorithm { // try each session in turn. const decryptionErrors: Record = {}; - for (let i = 0; i < sessionIds.length; i++) { - const sessionId = sessionIds[i]; + for (const sessionId of sessionIds) { try { const payload = await this.olmDevice.decryptMessage( theirDeviceIdentityKey, sessionId, message.type, message.body, diff --git a/src/crypto/backup.ts b/src/crypto/backup.ts index fd4377e148c..d9c1ba4587c 100644 --- a/src/crypto/backup.ts +++ b/src/crypto/backup.ts @@ -680,8 +680,7 @@ export class Curve25519 implements BackupAlgorithm { const backupPubKey = decryption.init_with_private_key(privKey); if (backupPubKey !== this.authData.public_key) { - // eslint-disable-next-line no-throw-literal - throw { errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY }; + throw new MatrixError({ errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY }); } const keys: IMegolmSessionData[] = []; diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 0a13837e1ac..e0e8c01290f 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -2379,9 +2379,8 @@ export class Crypto extends TypedEventEmitter> { const devices = this.getStoredDevicesForUser(userId) || []; - const result = {}; - for (let j = 0; j < devices.length; ++j) { - const device = devices[j]; + const result: { [deviceId: string]: IUserOlmSession } = {}; + for (const device of devices) { const deviceKey = device.getIdentityKey(); const sessions = await this.olmDevice.getSessionInfoForDevice(deviceKey); @@ -2682,14 +2681,11 @@ export class Crypto extends TypedEventEmitter>> { const devicesByUser: Record = {}; - for (let i = 0; i < users.length; ++i) { - const userId = users[i]; + for (const userId of users) { devicesByUser[userId] = []; const devices = this.getStoredDevicesForUser(userId) || []; - for (let j = 0; j < devices.length; ++j) { - const deviceInfo = devices[j]; - + for (const deviceInfo of devices) { const key = deviceInfo.getIdentityKey(); if (key == this.olmDevice.deviceCurve25519Key) { // don't bother setting up session to ourself diff --git a/src/crypto/olmlib.ts b/src/crypto/olmlib.ts index c7448691f53..02777ccc7f6 100644 --- a/src/crypto/olmlib.ts +++ b/src/crypto/olmlib.ts @@ -335,8 +335,7 @@ export async function ensureOlmSessionsForDevices( const promises: Promise[] = []; for (const [userId, devices] of Object.entries(devicesByUser)) { const userRes = otkResult[userId] || {}; - for (let j = 0; j < devices.length; j++) { - const deviceInfo = devices[j]; + for (const deviceInfo of devices) { const deviceId = deviceInfo.deviceId; const key = deviceInfo.getIdentityKey(); diff --git a/src/filter-component.ts b/src/filter-component.ts index fd90358b259..759c979216e 100644 --- a/src/filter-component.ts +++ b/src/filter-component.ts @@ -150,8 +150,7 @@ export class FilterComponent { }, }; - for (let n = 0; n < Object.keys(literalKeys).length; n++) { - const name = Object.keys(literalKeys)[n]; + for (const name in literalKeys) { const matchFunc = literalKeys[name]; const notName = "not_" + name; const disallowedValues: string[] = this.filterJson[notName]; diff --git a/src/interactive-auth.ts b/src/interactive-auth.ts index 5ba5956695e..80f3e95cf40 100644 --- a/src/interactive-auth.ts +++ b/src/interactive-auth.ts @@ -631,11 +631,6 @@ export class InteractiveAuth { */ private firstUncompletedStage(flow: IFlow): AuthType | undefined { const completed = this.data.completed || []; - for (let i = 0; i < flow.stages.length; ++i) { - const stageType = flow.stages[i]; - if (completed.indexOf(stageType) === -1) { - return stageType; - } - } + return flow.stages.find(stageType => !completed.includes(stageType)); } } diff --git a/src/models/event-timeline-set.ts b/src/models/event-timeline-set.ts index e41eec15881..d51fb0dbd92 100644 --- a/src/models/event-timeline-set.ts +++ b/src/models/event-timeline-set.ts @@ -457,8 +457,7 @@ export class EventTimelineSet extends TypedEventEmitter { * Removing just the old live timeline whilst preserving previous ones is not supported. */ public resetLiveTimeline(backPaginationToken?: string | null, forwardPaginationToken?: string | null): void { - for (let i = 0; i < this.timelineSets.length; i++) { - this.timelineSets[i].resetLiveTimeline( + for (const timelineSet of this.timelineSets) { + timelineSet.resetLiveTimeline( backPaginationToken ?? undefined, forwardPaginationToken ?? undefined, ); @@ -2128,8 +2128,8 @@ export class Room extends ReadReceipt { const { duplicateStrategy, timelineWasEmpty, fromCache } = addLiveEventOptions; // add to our timeline sets - for (let i = 0; i < this.timelineSets.length; i++) { - this.timelineSets[i].addLiveEvent(event, { + for (const timelineSet of this.timelineSets) { + timelineSet.addLiveEvent(event, { duplicateStrategy, fromCache, timelineWasEmpty, @@ -2214,8 +2214,7 @@ export class Room extends ReadReceipt { } } } else { - for (let i = 0; i < this.timelineSets.length; i++) { - const timelineSet = this.timelineSets[i]; + for (const timelineSet of this.timelineSets) { if (timelineSet.getFilter()) { if (timelineSet.getFilter()!.filterRoomTimeline([event]).length) { timelineSet.addEventToTimeline(event, @@ -2322,9 +2321,7 @@ export class Room extends ReadReceipt { thread?.timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId); if (shouldLiveInRoom) { - for (let i = 0; i < this.timelineSets.length; i++) { - const timelineSet = this.timelineSets[i]; - + for (const timelineSet of this.timelineSets) { // if it's already in the timeline, update the timeline map. If it's not, add it. timelineSet.handleRemoteEcho(localEvent, oldEventId, newEventId); } @@ -2407,8 +2404,8 @@ export class Room extends ReadReceipt { // if the event was already in the timeline (which will be the case if // opts.pendingEventOrdering==chronological), we need to update the // timeline map. - for (let i = 0; i < this.timelineSets.length; i++) { - this.timelineSets[i].replaceEventId(oldEventId, newEventId!); + for (const timelineSet of this.timelineSets) { + timelineSet.replaceEventId(oldEventId, newEventId!); } } } else if (newStatus == EventStatus.CANCELLED) { @@ -2643,8 +2640,8 @@ export class Room extends ReadReceipt { * @param {String[]} eventIds A list of eventIds to remove. */ public removeEvents(eventIds: string[]): void { - for (let i = 0; i < eventIds.length; ++i) { - this.removeEvent(eventIds[i]); + for (const eventId of eventIds) { + this.removeEvent(eventId); } } @@ -2657,8 +2654,8 @@ export class Room extends ReadReceipt { */ public removeEvent(eventId: string): boolean { let removedAny = false; - for (let i = 0; i < this.timelineSets.length; i++) { - const removed = this.timelineSets[i].removeEvent(eventId); + for (const timelineSet of this.timelineSets) { + const removed = timelineSet.removeEvent(eventId); if (removed) { if (removed.isRedaction()) { this.revertRedactionLocalEcho(removed); @@ -2740,8 +2737,7 @@ export class Room extends ReadReceipt { * @param {Array} events an array of account_data events to add */ public addAccountData(events: MatrixEvent[]): void { - for (let i = 0; i < events.length; i++) { - const event = events[i]; + for (const event of events) { if (event.getType() === "m.tag") { this.addTags(event); } diff --git a/src/models/user.ts b/src/models/user.ts index ed1b0f01d41..31d113dbe72 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -134,8 +134,8 @@ export class User extends TypedEventEmitter { this.updateModifiedTime(); - for (let i = 0; i < eventsToFire.length; i++) { - this.emit(eventsToFire[i], event, this); + for (const eventToFire of eventsToFire) { + this.emit(eventToFire, event, this); } } diff --git a/src/pushprocessor.ts b/src/pushprocessor.ts index e979032d89b..065eab19218 100644 --- a/src/pushprocessor.ts +++ b/src/pushprocessor.ts @@ -135,8 +135,7 @@ export class PushProcessor { */ public static actionListToActionsObject(actionList: PushRuleAction[]): IActionsObject { const actionObj: IActionsObject = { notify: false, tweaks: {} }; - for (let i = 0; i < actionList.length; ++i) { - const action = actionList[i]; + for (const action of actionList) { if (action === PushRuleActionName.Notify) { actionObj.notify = true; } else if (typeof action === 'object') { @@ -190,15 +189,13 @@ export class PushProcessor { private static cachedGlobToRegex: Record = {}; // $glob: RegExp private matchingRuleFromKindSet(ev: MatrixEvent, kindset: PushRuleSet): IAnnotatedPushRule | null { - for (let ruleKindIndex = 0; ruleKindIndex < RULEKINDS_IN_ORDER.length; ++ruleKindIndex) { - const kind = RULEKINDS_IN_ORDER[ruleKindIndex]; + for (const kind of RULEKINDS_IN_ORDER) { const ruleset = kindset[kind]; if (!ruleset) { continue; } - for (let ruleIndex = 0; ruleIndex < ruleset.length; ++ruleIndex) { - const rule = ruleset[ruleIndex]; + for (const rule of ruleset) { if (!rule.enabled) { continue; } @@ -478,16 +475,7 @@ export class PushProcessor { } public ruleMatchesEvent(rule: Partial & Pick, ev: MatrixEvent): boolean { - if (!rule.conditions?.length) return true; - - let ret = true; - for (let i = 0; i < rule.conditions.length; ++i) { - const cond = rule.conditions[i]; - // @ts-ignore - ret &= this.eventFulfillsCondition(cond, ev); - } - //console.log("Rule "+rule.rule_id+(ret ? " matches" : " doesn't match")); - return ret; + return !rule.conditions?.some(cond => !this.eventFulfillsCondition(cond, ev)); } /** diff --git a/src/realtime-callbacks.ts b/src/realtime-callbacks.ts index 7c3218ce028..222c9476390 100644 --- a/src/realtime-callbacks.ts +++ b/src/realtime-callbacks.ts @@ -101,7 +101,7 @@ export function clearTimeout(key: number): void { } // remove the element from the list - let i; + let i: number; for (i = 0; i < callbackList.length; i++) { const cb = callbackList[i]; if (cb.key == key) { @@ -137,7 +137,6 @@ function scheduleRealCallback(): void { } function runCallbacks(): void { - let cb: Callback; const timestamp = Date.now(); debuglog("runCallbacks: now:", timestamp); @@ -149,7 +148,7 @@ function runCallbacks(): void { if (!first || first.runAt > timestamp) { break; } - cb = callbackList.shift()!; + const cb = callbackList.shift()!; debuglog("runCallbacks: popping", cb.key); callbacksToRun.push(cb); } @@ -159,8 +158,7 @@ function runCallbacks(): void { // register their own setTimeouts. scheduleRealCallback(); - for (let i = 0; i < callbacksToRun.length; i++) { - cb = callbacksToRun[i]; + for (const cb of callbacksToRun) { try { cb.func.apply(global, cb.params); } catch (e) { diff --git a/src/rendezvous/MSC3906Rendezvous.ts b/src/rendezvous/MSC3906Rendezvous.ts index e275a3a0ad0..c18af591268 100644 --- a/src/rendezvous/MSC3906Rendezvous.ts +++ b/src/rendezvous/MSC3906Rendezvous.ts @@ -16,14 +16,13 @@ limitations under the License. import { UnstableValue } from "matrix-events-sdk"; -import { RendezvousChannel } from "."; +import { RendezvousChannel, RendezvousFailureListener, RendezvousFailureReason, RendezvousIntent } from "."; import { MatrixClient } from "../client"; import { CrossSigningInfo } from "../crypto/CrossSigning"; import { DeviceInfo } from "../crypto/deviceinfo"; import { buildFeatureSupportMap, Feature, ServerSupport } from "../feature"; import { logger } from "../logger"; import { sleep } from "../utils"; -import { RendezvousFailureListener, RendezvousFailureReason, RendezvousIntent } from "."; enum PayloadType { Start = 'm.login.start', diff --git a/src/store/indexeddb-local-backend.ts b/src/store/indexeddb-local-backend.ts index a2b4448440c..597ed511741 100644 --- a/src/store/indexeddb-local-backend.ts +++ b/src/store/indexeddb-local-backend.ts @@ -454,8 +454,8 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend { return utils.promiseTry(() => { const txn = this.db!.transaction(["accountData"], "readwrite"); const store = txn.objectStore("accountData"); - for (let i = 0; i < accountData.length; i++) { - store.put(accountData[i]); // put == UPSERT + for (const event of accountData) { + store.put(event); // put == UPSERT } return txnAsPromise(txn).then(); }); diff --git a/src/sync-accumulator.ts b/src/sync-accumulator.ts index ebb9fb21994..e67ce9e6360 100644 --- a/src/sync-accumulator.ts +++ b/src/sync-accumulator.ts @@ -400,47 +400,51 @@ export class SyncAccumulator { acc[INVITED_COUNT_KEY] = sum[INVITED_COUNT_KEY] || acc[INVITED_COUNT_KEY]; } - if (data.ephemeral && data.ephemeral.events) { - data.ephemeral.events.forEach((e) => { - // We purposefully do not persist m.typing events. - // Technically you could refresh a browser before the timer on a - // typing event is up, so it'll look like you aren't typing when - // you really still are. However, the alternative is worse. If - // we do persist typing events, it will look like people are - // typing forever until someone really does start typing (which - // will prompt Synapse to send down an actual m.typing event to - // clobber the one we persisted). - if (e.type !== EventType.Receipt || !e.content) { - // This means we'll drop unknown ephemeral events but that - // seems okay. - return; - } - // Handle m.receipt events. They clobber based on: - // (user_id, receipt_type) - // but they are keyed in the event as: - // content:{ $event_id: { $receipt_type: { $user_id: {json} }}} - // so store them in the former so we can accumulate receipt deltas - // quickly and efficiently (we expect a lot of them). Fold the - // receipt type into the key name since we only have 1 at the - // moment (m.read) and nested JSON objects are slower and more - // of a hassle to work with. We'll inflate this back out when - // getJSON() is called. - Object.keys(e.content).forEach((eventId) => { - Object.entries(e.content[eventId]).forEach(([key, value]) => { - if (!isSupportedReceiptType(key)) return; - - Object.keys(value!).forEach((userId) => { - // clobber on user ID - currentData._readReceipts[userId] = { - data: e.content[eventId][key][userId], - type: key as ReceiptType, - eventId: eventId, - }; - }); + data.ephemeral?.events?.forEach((e) => { + // We purposefully do not persist m.typing events. + // Technically you could refresh a browser before the timer on a + // typing event is up, so it'll look like you aren't typing when + // you really still are. However, the alternative is worse. If + // we do persist typing events, it will look like people are + // typing forever until someone really does start typing (which + // will prompt Synapse to send down an actual m.typing event to + // clobber the one we persisted). + if (e.type !== EventType.Receipt || !e.content) { + // This means we'll drop unknown ephemeral events but that + // seems okay. + return; + } + // Handle m.receipt events. They clobber based on: + // (user_id, receipt_type) + // but they are keyed in the event as: + // content:{ $event_id: { $receipt_type: { $user_id: {json} }}} + // so store them in the former so we can accumulate receipt deltas + // quickly and efficiently (we expect a lot of them). Fold the + // receipt type into the key name since we only have 1 at the + // moment (m.read) and nested JSON objects are slower and more + // of a hassle to work with. We'll inflate this back out when + // getJSON() is called. + Object.keys(e.content).forEach((eventId) => { + Object.entries<{ + [eventId: string]: { + [receiptType: string]: { + [userId: string]: IMinimalEvent; + }; + }; + }>(e.content[eventId]).forEach(([key, value]) => { + if (!isSupportedReceiptType(key)) return; + + Object.keys(value).forEach((userId) => { + // clobber on user ID + currentData._readReceipts[userId] = { + data: e.content[eventId][key][userId], + type: key as ReceiptType, + eventId: eventId, + }; }); }); }); - } + }); // if we got a limited sync, we need to remove all timeline entries or else // we will have gaps in the timeline. @@ -551,7 +555,7 @@ export class SyncAccumulator { }; // Add account data Object.keys(roomData._accountData).forEach((evType) => { - roomJson.account_data.events.push(roomData._accountData[evType] as IMinimalEvent); + roomJson.account_data.events.push(roomData._accountData[evType]); }); // Add receipt data diff --git a/src/sync.ts b/src/sync.ts index 5f5e2e13ae4..183e74a613e 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -821,7 +821,6 @@ export class SyncApi { let data: ISyncResponse; try { - //debuglog('Starting sync since=' + syncToken); if (!this.currentSyncRequest) { this.currentSyncRequest = this.doSyncRequest(syncOptions, syncToken); } @@ -834,8 +833,6 @@ export class SyncApi { this.currentSyncRequest = undefined; } - //debuglog('Completed sync, next_batch=' + data.next_batch); - // set the sync token NOW *before* processing the events. We do this so // if something barfs on an event we can skip it rather than constantly // polling with the same token. @@ -1747,11 +1744,10 @@ export class SyncApi { private processEventsForNotifs(room: Room, timelineEventList: MatrixEvent[]): void { // gather our notifications into this.notifEvents if (this.client.getNotifTimelineSet()) { - for (let i = 0; i < timelineEventList.length; i++) { - const pushActions = this.client.getPushActionsForEvent(timelineEventList[i]); - if (pushActions && pushActions.notify && - pushActions.tweaks && pushActions.tweaks.highlight) { - this.notifEvents.push(timelineEventList[i]); + for (const event of timelineEventList) { + const pushActions = this.client.getPushActionsForEvent(event); + if (pushActions?.notify && pushActions.tweaks?.highlight) { + this.notifEvents.push(event); } } } diff --git a/src/utils.ts b/src/utils.ts index 23ee1d36ac6..d4364f18a54 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -190,9 +190,9 @@ export function isFunction(value: any) { */ // note using 'keys' here would shadow the 'keys' function defined above export function checkObjectHasKeys(obj: object, keys: string[]) { - for (let i = 0; i < keys.length; i++) { - if (!obj.hasOwnProperty(keys[i])) { - throw new Error("Missing required key: " + keys[i]); + for (const key of keys) { + if (!obj.hasOwnProperty(key)) { + throw new Error("Missing required key: " + key); } } } diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index 93f5e18a89f..2a11de5756b 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -2237,8 +2237,8 @@ export class MatrixCall extends TypedEventEmitter, enabled: boolean): void { - for (let i = 0; i < tracks.length; i++) { - tracks[i].enabled = enabled; + for (const track of tracks) { + track.enabled = enabled; } } diff --git a/src/webrtc/callEventHandler.ts b/src/webrtc/callEventHandler.ts index 9b6a339f39b..cb132e8fef6 100644 --- a/src/webrtc/callEventHandler.ts +++ b/src/webrtc/callEventHandler.ts @@ -140,7 +140,6 @@ export class CallEventHandler { const type = event.getType() as EventType; const weSentTheEvent = event.getSender() === this.client.credentials.userId; let call = content.call_id ? this.calls.get(content.call_id) : undefined; - //console.info("RECV %s content=%s", type, JSON.stringify(content)); if (type === EventType.CallInvite) { // ignore invites you send diff --git a/src/webrtc/callFeed.ts b/src/webrtc/callFeed.ts index 14cf794e86c..5718d4e8d6a 100644 --- a/src/webrtc/callFeed.ts +++ b/src/webrtc/callFeed.ts @@ -220,9 +220,9 @@ export class CallFeed extends TypedEventEmitter this.analyser.getFloatFrequencyData(this.frequencyBinCount!); let maxVolume = -Infinity; - for (let i = 0; i < this.frequencyBinCount!.length; i++) { - if (this.frequencyBinCount![i] > maxVolume) { - maxVolume = this.frequencyBinCount![i]; + for (const volume of this.frequencyBinCount!) { + if (volume > maxVolume) { + maxVolume = volume; } } @@ -233,9 +233,7 @@ export class CallFeed extends TypedEventEmitter let newSpeaking = false; - for (let i = 0; i < this.speakingVolumeSamples.length; i++) { - const volume = this.speakingVolumeSamples[i]; - + for (const volume of this.speakingVolumeSamples) { if (volume > this.speakingThreshold) { newSpeaking = true; break;