diff --git a/keyserver/src/creators/message-creator.js b/keyserver/src/creators/message-creator.js --- a/keyserver/src/creators/message-creator.js +++ b/keyserver/src/creators/message-creator.js @@ -39,7 +39,7 @@ } from '../fetchers/message-fetchers.js'; import { fetchOtherSessionsForViewer } from '../fetchers/session-fetchers.js'; import { fetchServerThreadInfos } from '../fetchers/thread-fetchers.js'; -import type { Device } from '../push/send'; +import type { Device, PushUserInfo } from '../push/send.js'; import { sendPushNotifs, sendRescindNotifs } from '../push/send.js'; import { handleAsyncPromise } from '../responders/handlers.js'; import type { Viewer } from '../session/viewer.js'; @@ -393,10 +393,12 @@ } } - const messageInfosPerUser = {}; + const messageInfosPerUser: { + [userID: string]: $ReadOnlyArray, + } = {}; const latestMessagesPerUser: LatestMessagesPerUser = new Map(); - const userPushInfoPromises = {}; - const userRescindInfoPromises = {}; + const userPushInfoPromises: { [string]: Promise } = {}; + const userRescindInfoPromises: { [string]: Promise } = {}; for (const pair of perUserInfo) { const [userID, preUserPushInfo] = pair; @@ -431,7 +433,12 @@ } const generateNotifUserInfoPromise = async (pushType: PushType) => { - const promises = []; + const promises: Array< + Promise, + > = []; for (const threadID of preUserPushInfo.notFocusedThreadIDs) { const messageIndices = threadsToMessageIndices.get(threadID); diff --git a/keyserver/src/creators/role-creator.js b/keyserver/src/creators/role-creator.js --- a/keyserver/src/creators/role-creator.js +++ b/keyserver/src/creators/role-creator.js @@ -42,7 +42,7 @@ const time = Date.now(); const newRows = []; - const namesToIDs = {}; + const namesToIDs: { [string]: string } = {}; for (const name in rolePermissions) { const id = ids.shift(); namesToIDs[name] = id; diff --git a/keyserver/src/creators/thread-creator.js b/keyserver/src/creators/thread-creator.js --- a/keyserver/src/creators/thread-creator.js +++ b/keyserver/src/creators/thread-creator.js @@ -13,6 +13,7 @@ import { getThreadTypeParentRequirement } from 'lib/shared/thread-utils.js'; import type { Shape } from 'lib/types/core.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; +import type { RawMessageInfo, MessageData } from 'lib/types/message-types.js'; import { threadPermissions } from 'lib/types/thread-permission-types.js'; import { threadTypes, @@ -22,6 +23,7 @@ type ServerNewThreadRequest, type NewThreadResponse, } from 'lib/types/thread-types.js'; +import type { ServerUpdateInfo } from 'lib/types/update-types.js'; import type { UserInfos } from 'lib/types/user-types.js'; import { pushAll } from 'lib/utils/array.js'; import { ServerError } from 'lib/utils/errors.js'; @@ -289,9 +291,9 @@ ], }; - let joinUpdateInfos = []; + let joinUpdateInfos: $ReadOnlyArray = []; let userInfos: UserInfos = {}; - let newMessageInfos = []; + let newMessageInfos: $ReadOnlyArray = []; if (threadType !== threadTypes.PERSONAL) { const joinThreadResult = await joinThread(viewer, { threadID: existingThreadID, @@ -396,7 +398,7 @@ const initialMemberAndCreatorIDs = initialMemberIDs ? [...initialMemberIDs, viewer.userID] : [viewer.userID]; - const messageDatas = []; + const messageDatas: Array = []; if (threadType !== threadTypes.SIDEBAR) { messageDatas.push({ type: messageTypes.CREATE_THREAD, diff --git a/keyserver/src/creators/update-creator.js b/keyserver/src/creators/update-creator.js --- a/keyserver/src/creators/update-creator.js +++ b/keyserver/src/creators/update-creator.js @@ -16,10 +16,12 @@ import { type CalendarQuery, defaultCalendarQuery, + type RawEntryInfo, } from 'lib/types/entry-types.js'; import { defaultNumberPerThread, type MessageSelectionCriteria, + type RawMessageInfo, } from 'lib/types/message-types.js'; import { type UpdateTarget, @@ -500,7 +502,7 @@ ): Promise { const { messageInfosResult, calendarResult, userInfosResult } = rawData; - const rawEntryInfosByThreadID = {}; + const rawEntryInfosByThreadID: { [string]: Array } = {}; for (const entryInfo of calendarResult?.rawEntryInfos ?? []) { if (!rawEntryInfosByThreadID[entryInfo.threadID]) { rawEntryInfosByThreadID[entryInfo.threadID] = []; @@ -508,7 +510,7 @@ rawEntryInfosByThreadID[entryInfo.threadID].push(entryInfo); } - const rawMessageInfosByThreadID = {}; + const rawMessageInfosByThreadID: { [string]: Array } = {}; for (const messageInfo of messageInfosResult?.rawMessageInfos ?? []) { if (!rawMessageInfosByThreadID[messageInfo.threadID]) { rawMessageInfosByThreadID[messageInfo.threadID] = []; diff --git a/keyserver/src/fetchers/entry-fetchers.js b/keyserver/src/fetchers/entry-fetchers.js --- a/keyserver/src/fetchers/entry-fetchers.js +++ b/keyserver/src/fetchers/entry-fetchers.js @@ -267,7 +267,7 @@ !rawEntryInfoWithinCalendarQuery(rawEntryInfo, oldCalendarQuery), ); let filteredRawEntryInfos = entryInfosNotInOldQuery; - let deletedEntryIDs = []; + let deletedEntryIDs: $ReadOnlyArray = []; if (filterDeleted) { filteredRawEntryInfos = entryInfosNotInOldQuery.filter( rawEntryInfo => !rawEntryInfo.deleted, diff --git a/keyserver/src/fetchers/message-fetchers.js b/keyserver/src/fetchers/message-fetchers.js --- a/keyserver/src/fetchers/message-fetchers.js +++ b/keyserver/src/fetchers/message-fetchers.js @@ -30,6 +30,7 @@ type FetchPinnedMessagesRequest, type FetchPinnedMessagesResult, type SearchMessagesResponse, + type MessageTruncationStatuses, } from 'lib/types/message-types.js'; import { defaultNumberPerThread } from 'lib/types/message-types.js'; import { threadPermissions } from 'lib/types/thread-permission-types.js'; @@ -72,8 +73,11 @@ pushInfo: PushInfo, ): Promise { // First, we need to fetch any notifications that should be collapsed - const usersToCollapseKeysToInfo = {}; - const usersToCollapsableNotifInfo = {}; + const usersToCollapseKeysToInfo: { + [string]: { [string]: CollapsableNotifInfo }, + } = {}; + const usersToCollapsableNotifInfo: { [string]: Array } = + {}; for (const userID in pushInfo) { usersToCollapseKeysToInfo[userID] = {}; usersToCollapsableNotifInfo[userID] = []; @@ -82,7 +86,7 @@ const messageData = pushInfo[userID].messageDatas[i]; const collapseKey = getNotifCollapseKey(rawMessageInfo, messageData); if (!collapseKey) { - const collapsableNotifInfo = { + const collapsableNotifInfo: CollapsableNotifInfo = { collapseKey, existingMessageInfos: [], newMessageInfos: [rawMessageInfo], @@ -91,11 +95,11 @@ continue; } if (!usersToCollapseKeysToInfo[userID][collapseKey]) { - usersToCollapseKeysToInfo[userID][collapseKey] = { + usersToCollapseKeysToInfo[userID][collapseKey] = ({ collapseKey, existingMessageInfos: [], newMessageInfos: [], - }; + }: CollapsableNotifInfo); } usersToCollapseKeysToInfo[userID][collapseKey].newMessageInfos.push( rawMessageInfo, @@ -309,7 +313,7 @@ ): Promise { const { sqlClause: selectionClause, timeFilterData } = parseMessageSelectionCriteria(viewer, criteria); - const truncationStatuses = {}; + const truncationStatuses: MessageTruncationStatuses = {}; const viewerID = viewer.id; const query = SQL` @@ -522,7 +526,7 @@ criteria: MessageSelectionCriteria, defaultTruncationStatus: MessageTruncationStatus, ) { - const truncationStatuses = {}; + const truncationStatuses: MessageTruncationStatuses = {}; if (criteria.threadCursors) { for (const threadID in criteria.threadCursors) { truncationStatuses[threadID] = defaultTruncationStatus; @@ -605,7 +609,7 @@ viewer: Viewer, rawMessageInfos: $ReadOnlyArray, ): FetchMessageInfosResult { - const truncationStatuses = {}; + const truncationStatuses: MessageTruncationStatuses = {}; for (const rawMessageInfo of rawMessageInfos) { truncationStatuses[rawMessageInfo.threadID] = messageTruncationStatus.UNCHANGED; diff --git a/keyserver/src/fetchers/role-fetchers.js b/keyserver/src/fetchers/role-fetchers.js --- a/keyserver/src/fetchers/role-fetchers.js +++ b/keyserver/src/fetchers/role-fetchers.js @@ -13,7 +13,7 @@ `; const [result] = await dbQuery(query); - const roles = []; + const roles: Array = []; for (const row of result) { roles.push({ id: row.id.toString(), diff --git a/keyserver/src/fetchers/thread-fetchers.js b/keyserver/src/fetchers/thread-fetchers.js --- a/keyserver/src/fetchers/thread-fetchers.js +++ b/keyserver/src/fetchers/thread-fetchers.js @@ -15,6 +15,7 @@ import { type RawThreadInfos, type ServerThreadInfo, + type RawThreadInfo, } from 'lib/types/thread-types.js'; import { ServerError } from 'lib/utils/errors.js'; @@ -272,7 +273,7 @@ native: 221, }); - const threadInfos = {}; + const threadInfos: { [string]: RawThreadInfo } = {}; for (const threadID in serverResult.threadInfos) { const serverThreadInfo = serverResult.threadInfos[threadID]; const threadInfo = rawThreadInfoFromServerThreadInfo( diff --git a/keyserver/src/fetchers/user-fetchers.js b/keyserver/src/fetchers/user-fetchers.js --- a/keyserver/src/fetchers/user-fetchers.js +++ b/keyserver/src/fetchers/user-fetchers.js @@ -43,7 +43,7 @@ `; const [result] = await dbQuery(query); - const userInfos = {}; + const userInfos: { [id: string]: GlobalUserInfo } = {}; for (const row of result) { const id = row.id.toString(); const avatar: ?AvatarDBContent = row.avatar ? JSON.parse(row.avatar) : null; diff --git a/keyserver/src/push/rescind.js b/keyserver/src/push/rescind.js --- a/keyserver/src/push/rescind.js +++ b/keyserver/src/push/rescind.js @@ -1,6 +1,8 @@ // @flow import apn from '@parse/node-apn'; +import type { ResponseFailure } from '@parse/node-apn'; +import type { FirebaseError } from 'firebase-admin'; import invariant from 'invariant'; import type { PlatformDetails } from 'lib/types/device-types.js'; @@ -19,7 +21,12 @@ TargetedAndroidNotification, TargetedAPNsNotification, } from './types.js'; -import { apnPush, fcmPush } from './utils.js'; +import { + apnPush, + fcmPush, + type APNPushResult, + type FCMPushResult, +} from './utils.js'; import createIDs from '../creators/id-creator.js'; import { dbQuery, SQL } from '../database/database.js'; import type { SQLStatementType } from '../database/types.js'; @@ -33,7 +40,13 @@ +deviceTokens: $ReadOnlyArray, }; -type ParsedDeliveries = { +[id: string]: $ReadOnlyArray }; +type RescindDelivery = { + source: 'rescind', + rescindedID: string, + errors?: + | $ReadOnlyArray + | $ReadOnlyArray, +}; async function rescindPushNotifs( notifCondition: SQLStatementType, @@ -60,7 +73,7 @@ const [fetchResult] = await dbQuery(fetchQuery); const allDeviceTokens = new Set(); - const parsedDeliveries: ParsedDeliveries = {}; + const parsedDeliveries: { [string]: $ReadOnlyArray } = {}; for (const row of fetchResult) { const rawDelivery = JSON.parse(row.delivery); @@ -101,7 +114,9 @@ } const deviceTokenToCookieID = await getDeviceTokenToCookieID(allDeviceTokens); - const deliveryPromises = {}; + const deliveryPromises: { + [string]: Promise | Promise, + } = {}; const notifInfo = {}; const rescindedIDs = []; @@ -177,25 +192,36 @@ } const numRescinds = Object.keys(deliveryPromises).length; - const promises = [promiseAll(deliveryPromises)]; - if (numRescinds > 0) { - promises.push(createIDs('notifications', numRescinds)); - } - if (rescindedIDs.length > 0) { + const dbIDsPromise: Promise> = (async () => { + if (numRescinds === 0) { + return undefined; + } + return await createIDs('notifications', numRescinds); + })(); + const rescindPromise: Promise = (async () => { + if (rescindedIDs.length === 0) { + return undefined; + } const rescindQuery = SQL` UPDATE notifications SET rescinded = 1 WHERE id IN (${rescindedIDs}) `; - promises.push(dbQuery(rescindQuery)); - } + return await dbQuery(rescindQuery); + })(); + + const [deliveryResults, dbIDs] = await Promise.all([ + promiseAll(deliveryPromises), + dbIDsPromise, + rescindPromise, + ]); - const [deliveryResults, dbIDs] = await Promise.all(promises); const newNotifRows = []; if (numRescinds > 0) { invariant(dbIDs, 'dbIDs should be set'); for (const rescindedID in deliveryResults) { - const delivery = {}; - delivery.source = 'rescind'; - delivery.rescindedID = rescindedID; + const delivery: RescindDelivery = { + source: 'rescind', + rescindedID, + }; const { errors } = deliveryResults[rescindedID]; if (errors) { delivery.errors = errors; diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js --- a/keyserver/src/push/send.js +++ b/keyserver/src/push/send.js @@ -84,7 +84,7 @@ +stateVersion: ?number, }; -type PushUserInfo = { +export type PushUserInfo = { +devices: Device[], // messageInfos and messageDatas have the same key +messageInfos: RawMessageInfo[], @@ -529,7 +529,7 @@ ]); } - const dbPromises = []; + const dbPromises: Array> = []; if (allInvalidTokens.length > 0) { dbPromises.push(removeInvalidTokens(allInvalidTokens)); } @@ -719,11 +719,13 @@ codeVersion, stateVersion, }); - let innerMostArray = innerMap.get(versionKey); - if (!innerMostArray) { - innerMostArray = []; - innerMap.set(versionKey, innerMostArray); + let innerMostArrayTmp: ?Array = + innerMap.get(versionKey); + if (!innerMostArrayTmp) { + innerMostArrayTmp = []; + innerMap.set(versionKey, innerMostArrayTmp); } + const innerMostArray = innerMostArrayTmp; innerMostArray.push({ cookieID: device.cookieID, @@ -1181,7 +1183,7 @@ }; } - const deviceTokensToPayloadHash = {}; + const deviceTokensToPayloadHash: { [string]: string } = {}; for (const targetedNotification of targetedNotifications) { if (targetedNotification.encryptedPayloadHash) { deviceTokensToPayloadHash[targetedNotification.deviceToken] = @@ -1383,7 +1385,7 @@ } const time = Date.now(); - const promises = []; + const promises: Array> = []; for (const entry of userCookiePairsToInvalidDeviceTokens) { const [userCookiePair, deviceTokens] = entry; const [userID, cookieID] = userCookiePair.split('|'); diff --git a/keyserver/src/push/utils.js b/keyserver/src/push/utils.js --- a/keyserver/src/push/utils.js +++ b/keyserver/src/push/utils.js @@ -40,7 +40,7 @@ const wnsInvalidTokenErrorCodes = [404, 410]; const wnsMaxNotificationPayloadByteSize = 5000; -type APNPushResult = +export type APNPushResult = | { +success: true } | { +errors: $ReadOnlyArray, diff --git a/keyserver/src/responders/landing-handler.js b/keyserver/src/responders/landing-handler.js --- a/keyserver/src/responders/landing-handler.js +++ b/keyserver/src/responders/landing-handler.js @@ -57,11 +57,11 @@ } if (process.env.NODE_ENV === 'development') { const fontURLs = await getDevFontURLs(); - assetInfo = { + assetInfo = ({ jsURL: 'http://localhost:8082/dev.build.js', fontURLs, cssInclude: '', - }; + }: AssetInfo); return assetInfo; } try { @@ -70,7 +70,7 @@ 'utf8', ); const manifest = JSON.parse(manifestString); - assetInfo = { + assetInfo = ({ jsURL: `compiled/${manifest['browser.js']}`, fontURLs: [googleFontsURL, iaDuoFontsURL], cssInclude: html` @@ -80,7 +80,7 @@ href="compiled/${manifest['browser.css']}" /> `, - }; + }: AssetInfo); return assetInfo; } catch { throw new Error( diff --git a/keyserver/src/responders/redux-state-responders.js b/keyserver/src/responders/redux-state-responders.js --- a/keyserver/src/responders/redux-state-responders.js +++ b/keyserver/src/responders/redux-state-responders.js @@ -16,7 +16,10 @@ } from 'lib/shared/thread-utils.js'; import { entryStoreValidator } from 'lib/types/entry-types.js'; import { defaultCalendarFilters } from 'lib/types/filter-types.js'; -import { inviteLinksStoreValidator } from 'lib/types/link-types.js'; +import { + inviteLinksStoreValidator, + type CommunityLinks, +} from 'lib/types/link-types.js'; import { defaultNumberPerThread, messageStoreValidator, @@ -27,6 +30,7 @@ import { currentUserInfoValidator, userInfosValidator, + type GlobalAccountUserInfo, } from 'lib/types/user-types.js'; import { currentDateInTimeZone } from 'lib/utils/date-utils.js'; import { ServerError } from 'lib/utils/errors.js'; @@ -92,11 +96,14 @@ // Because of that we keep their userInfos inside the navInfo. if (urlInfo.selectedUserList) { const fetchedUserInfos = await fetchUserInfos(urlInfo.selectedUserList); - const userInfos = {}; + const userInfos: { [string]: GlobalAccountUserInfo } = {}; for (const userID in fetchedUserInfos) { const userInfo = fetchedUserInfos[userID]; if (userInfo.username) { - userInfos[userID] = userInfo; + userInfos[userID] = { + ...userInfo, + username: userInfo.username, + }; } } backupInfo = { userInfos, ...backupInfo }; @@ -288,7 +295,7 @@ const inviteLinksStorePromise = (async () => { const primaryInviteLinks = await fetchPrimaryInviteLinks(viewer); - const links = {}; + const links: { [string]: CommunityLinks } = {}; for (const link of primaryInviteLinks) { if (link.primary) { links[link.communityID] = { diff --git a/keyserver/src/responders/user-responders.js b/keyserver/src/responders/user-responders.js --- a/keyserver/src/responders/user-responders.js +++ b/keyserver/src/responders/user-responders.js @@ -356,7 +356,7 @@ } })(); - const threadCursors = {}; + const threadCursors: { [string]: null } = {}; for (const watchedThreadID of request.watchedIDs) { threadCursors[watchedThreadID] = null; } diff --git a/keyserver/src/scripts/generate-converter-from-validator.js b/keyserver/src/scripts/generate-converter-from-validator.js --- a/keyserver/src/scripts/generate-converter-from-validator.js +++ b/keyserver/src/scripts/generate-converter-from-validator.js @@ -25,7 +25,7 @@ function flattenInnerUnionValidators( innerValidators: $ReadOnlyArray>, ): TInterface<{ +[string]: mixed }>[] { - let result = []; + let result: TInterface<{ +[string]: mixed }>[] = []; for (const innerValidator of innerValidators) { if (innerValidator.meta.kind === 'interface') { // In flow, union refinement only works if every variant has a key diff --git a/keyserver/src/scripts/merge-users.js b/keyserver/src/scripts/merge-users.js --- a/keyserver/src/scripts/merge-users.js +++ b/keyserver/src/scripts/merge-users.js @@ -15,6 +15,7 @@ import { changeRole, commitMembershipChangeset, + type MembershipRow, } from '../updaters/thread-permission-updaters.js'; import RelationshipChangeset from '../utils/relationship-changeset.js'; @@ -37,8 +38,8 @@ toUserID: string, replaceUserInfo?: ReplaceUserInfo, ) { - let updateUserRowQuery = null; - let updateDatas = []; + let updateUserRowQuery: ?SQLStatementType = null; + let updateDatas: UpdateData[] = []; if (replaceUserInfo) { const replaceUserResult = await replaceUser( fromUserID, @@ -122,7 +123,7 @@ changeRole(threadID, [toUserID], role), ), ); - const membershipRows = []; + const membershipRows: Array = []; const relationshipChangeset = new RelationshipChangeset(); for (const currentChangeset of changesets) { const { @@ -166,7 +167,7 @@ throw new Error(`couldn't fetch fromUserID ${fromUserID}`); } - const changedFields = {}; + const changedFields: { [string]: string } = {}; if (replaceUserInfo.username) { changedFields.username = firstResult.username; } @@ -178,7 +179,7 @@ UPDATE users SET ${changedFields} WHERE id = ${toUserID} `; - const updateDatas = []; + const updateDatas: UpdateData[] = []; if (replaceUserInfo.username) { updateDatas.push({ type: updateTypes.UPDATE_CURRENT_USER, diff --git a/keyserver/src/search/users.js b/keyserver/src/search/users.js --- a/keyserver/src/search/users.js +++ b/keyserver/src/search/users.js @@ -17,7 +17,7 @@ const [result] = await dbQuery(sqlQuery); - const userInfos = []; + const userInfos: GlobalAccountUserInfo[] = []; for (const row of result) { userInfos.push({ id: row.id.toString(), diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js --- a/keyserver/src/session/cookies.js +++ b/keyserver/src/session/cookies.js @@ -508,7 +508,7 @@ return result.viewer; } - let platformDetails = inputPlatformDetails; + let platformDetails: ?PlatformDetails = inputPlatformDetails; if (!platformDetails && result.type === 'invalidated') { platformDetails = result.platformDetails; } @@ -735,7 +735,7 @@ const time = Date.now(); const { cookieID, cookieHash, cookiePassword } = viewer; - const updateObj = {}; + const updateObj: { [string]: string | number } = {}; updateObj.last_used = time; if (isBcryptHash(cookieHash)) { updateObj.hash = getCookieHash(cookiePassword); diff --git a/keyserver/src/socket/socket.js b/keyserver/src/socket/socket.js --- a/keyserver/src/socket/socket.js +++ b/keyserver/src/socket/socket.js @@ -472,7 +472,7 @@ const { viewer } = this; invariant(viewer, 'should be set'); - const responses = []; + const responses: Array = []; const { sessionState, clientResponses } = message.payload; const { @@ -489,7 +489,7 @@ oldUpdatesCurrentAsOf, ); - const threadCursors = {}; + const threadCursors: { [string]: null } = {}; for (const watchedThreadID of watchedIDs) { threadCursors[watchedThreadID] = null; } diff --git a/keyserver/src/updaters/device-token-updaters.js b/keyserver/src/updaters/device-token-updaters.js --- a/keyserver/src/updaters/device-token-updaters.js +++ b/keyserver/src/updaters/device-token-updaters.js @@ -21,7 +21,7 @@ await clearDeviceToken(deviceToken); } - const setColumns = {}; + const setColumns: { [string]: ?string } = {}; setColumns.device_token = deviceToken; setColumns.platform = deviceType; if (update.platformDetails) { diff --git a/keyserver/src/updaters/olm-session-updater.js b/keyserver/src/updaters/olm-session-updater.js --- a/keyserver/src/updaters/olm-session-updater.js +++ b/keyserver/src/updaters/olm-session-updater.js @@ -46,7 +46,7 @@ const [{ version, pickled_olm_session: pickledSession }] = olmSessionResult; const session = await unpickleOlmSession(pickledSession, picklingKey); - const encryptedMessages = {}; + const encryptedMessages: { [string]: EncryptResult } = {}; for (const messageName in messagesToEncrypt) { encryptedMessages[messageName] = session.encrypt( messagesToEncrypt[messageName], diff --git a/keyserver/src/updaters/relationship-updaters.js b/keyserver/src/updaters/relationship-updaters.js --- a/keyserver/src/updaters/relationship-updaters.js +++ b/keyserver/src/updaters/relationship-updaters.js @@ -41,7 +41,7 @@ const uniqueUserIDs = [...new Set(request.userIDs)]; const users = await fetchUserInfos(uniqueUserIDs); - let errors = {}; + let errors: RelationshipErrors = {}; const userIDs: string[] = []; for (const userID of uniqueUserIDs) { if (userID === viewer.userID || !users[userID].username) { @@ -116,7 +116,9 @@ } } - const promises = [updateUndirectedRelationships(undirectedInsertRows)]; + const promises: Array> = [ + updateUndirectedRelationships(undirectedInsertRows), + ]; if (directedInsertRows.length) { const directedInsertQuery = SQL` INSERT INTO relationships_directed (user1, user2, status) @@ -211,7 +213,7 @@ userPairs: $ReadOnlyArray<[string, string]>, ): UpdateData[] { const time = Date.now(); - const updateDatas = []; + const updateDatas: Array = []; for (const [user1, user2] of userPairs) { updateDatas.push({ type: updateTypes.UPDATE_USER, @@ -316,7 +318,7 @@ `but we tried to do that for ${request.action}`, ); - const threadIDPerUser = {}; + const threadIDPerUser: { [string]: string } = {}; const personalThreadsQuery = SQL` SELECT t.id AS threadID, m2.user AS user2 diff --git a/keyserver/src/updaters/role-updaters.js b/keyserver/src/updaters/role-updaters.js --- a/keyserver/src/updaters/role-updaters.js +++ b/keyserver/src/updaters/role-updaters.js @@ -4,6 +4,7 @@ import _isEqual from 'lodash/fp/isEqual.js'; import { getRolePermissionBlobs } from 'lib/permissions/thread-permissions.js'; +import type { ThreadRolePermissionsBlob } from 'lib/types/thread-permission-types.js'; import type { ThreadType } from 'lib/types/thread-types-enum.js'; import createIDs from '../creators/id-creator.js'; @@ -18,8 +19,8 @@ ): Promise { const currentRoles = await fetchRoles(threadID); - const currentRolePermissions = {}; - const currentRoleIDs = {}; + const currentRolePermissions: { [string]: ThreadRolePermissionsBlob } = {}; + const currentRoleIDs: { [string]: string } = {}; for (const roleInfo of currentRoles) { currentRolePermissions[roleInfo.name] = roleInfo.permissions; currentRoleIDs[roleInfo.name] = roleInfo.id; @@ -76,7 +77,7 @@ promises.push(dbQuery(updateMembershipsQuery)); } - const updatePermissions = {}; + const updatePermissions: { [string]: ThreadRolePermissionsBlob } = {}; for (const name in currentRoleIDs) { const currentPermissions = currentRolePermissions[name]; const permissions = rolePermissions[name]; diff --git a/keyserver/src/updaters/session-updaters.js b/keyserver/src/updaters/session-updaters.js --- a/keyserver/src/updaters/session-updaters.js +++ b/keyserver/src/updaters/session-updaters.js @@ -15,7 +15,7 @@ viewer: Viewer, sessionUpdate: SessionUpdate, ): Promise { - const sqlUpdate = {}; + const sqlUpdate: { [string]: string | number } = {}; if (sessionUpdate.query) { sqlUpdate.query = JSON.stringify(sessionUpdate.query); } diff --git a/keyserver/src/updaters/thread-permission-updaters.js b/keyserver/src/updaters/thread-permission-updaters.js --- a/keyserver/src/updaters/thread-permission-updaters.js +++ b/keyserver/src/updaters/thread-permission-updaters.js @@ -25,6 +25,7 @@ import { type ServerUpdateInfo, type CreateUpdatesResult, + type UpdateData, } from 'lib/types/update-types.js'; import { pushAll } from 'lib/utils/array.js'; import { ServerError } from 'lib/utils/errors.js'; @@ -66,7 +67,7 @@ +threadID: string, +oldRole: string, }; -type MembershipRow = MembershipRowToSave | MembershipRowToDelete; +export type MembershipRow = MembershipRowToSave | MembershipRowToDelete; export type MembershipChangeset = { +membershipRows: MembershipRow[], +relationshipChangeset: RelationshipChangeset, @@ -193,7 +194,7 @@ relationshipChangeset.setAllRelationshipsExist(parentMemberIDs); } - const membershipRows = []; + const membershipRows: Array = []; const toUpdateDescendants = new Map(); for (const userID of userIDs) { const existingMembership = existingMembershipInfo.get(userID); @@ -414,7 +415,7 @@ async function updateDescendantPermissions( initialChangedAncestor: ChangedAncestor, ): Promise { - const membershipRows = []; + const membershipRows: Array = []; const relationshipChangeset = new RelationshipChangeset(); const initialDescendants = await fetchDescendantsForUpdate([ @@ -580,7 +581,20 @@ ): Promise { const threadIDs = ancestors.map(ancestor => ancestor.threadID); - const rows = []; + const rows: Array<{ + +id: number, + +user: number, + +type: number, + +depth: number, + +parent_thread_id: number, + +containing_thread_id: number, + +role_permissions: string, + +permissions: string, + +permissions_for_children: string, + +role: number, + +permissions_from_parent: string | null, + +containing_role: ?number, + }> = []; while (threadIDs.length > 0) { const batch = threadIDs.splice(0, fetchDescendantsBatchSize); const query = SQL` @@ -627,8 +641,11 @@ curRolePermissions: JSON.parse(row.role_permissions), curPermissions: JSON.parse(row.permissions), curPermissionsForChildren: JSON.parse(row.permissions_for_children), - curPermissionsFromParent: JSON.parse(row.permissions_from_parent), - curMemberOfContainingThread: row.containing_role > 0, + curPermissionsFromParent: row.permissions_from_parent + ? JSON.parse(row.permissions_from_parent) + : null, + curMemberOfContainingThread: + !!row.containing_role && row.containing_role > 0, }); } @@ -641,9 +658,9 @@ if (threadID !== parentThreadID && threadID !== containingThreadID) { continue; } - let user = users.get(userID); + let user: ?DescendantUserInfo = users.get(userID); if (!user) { - user = {}; + user = ({}: DescendantUserInfo); users.set(userID, user); } if (threadID === parentThreadID) { @@ -783,7 +800,7 @@ relationshipChangeset.setAllRelationshipsExist(parentMemberIDs); } - const membershipRows = []; + const membershipRows: Array = []; const toUpdateDescendants = new Map(); for (const [userID, membership] of membershipInfo) { const { rolePermissions: intendedRolePermissions, permissionsFromParent } = @@ -1244,7 +1261,7 @@ } const time = Date.now(); - const updateDatas = [ + const updateDatas: Array = [ { type: updateTypes.JOIN_THREAD, userID: viewer.userID, @@ -1345,7 +1362,7 @@ console.log(`recalculating permissions for threads with depth ${depth}`); while (threads.length > 0) { const batch = threads.splice(0, batchSize); - const membershipRows = []; + const membershipRows: Array = []; const relationshipChangeset = new RelationshipChangeset(); await Promise.all( batch.map(async thread => { diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js --- a/keyserver/src/updaters/thread-updaters.js +++ b/keyserver/src/updaters/thread-updaters.js @@ -11,6 +11,7 @@ } from 'lib/shared/thread-utils.js'; import type { Shape } from 'lib/types/core.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; +import type { RawMessageInfo, MessageData } from 'lib/types/message-types.js'; import { threadPermissions } from 'lib/types/thread-permission-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import { @@ -38,6 +39,7 @@ changeRole, recalculateThreadPermissions, commitMembershipChangeset, + type MembershipRow, } from './thread-permission-updaters.js'; import createMessages from '../creators/message-creator.js'; import { createUpdates } from '../creators/update-creator.js'; @@ -163,7 +165,7 @@ : undefined, ); - let newMessageInfos = []; + let newMessageInfos: Array = []; if (!silenceNewMessages) { const messageData = { type: messageTypes.CHANGE_ROLE, @@ -341,8 +343,8 @@ (options?.ignorePermissions && viewer.isScriptViewer) ?? false; const validationPromises = {}; - const changedFields = {}; - const sqlUpdate = {}; + const changedFields: { [string]: string | number } = {}; + const sqlUpdate: { [string]: ?string | number } = {}; const untrimmedName = request.changes.name; if (untrimmedName !== undefined && untrimmedName !== null) { const name = firstLine(untrimmedName); @@ -724,7 +726,7 @@ const { addMembersChangeset, recalculatePermissionsChangeset } = await promiseAll(intermediatePromises); - const membershipRows = []; + const membershipRows: Array = []; const relationshipChangeset = new RelationshipChangeset(); if (recalculatePermissionsChangeset) { const { @@ -765,10 +767,10 @@ updateMembershipsLastMessage: silenceMessages, }); - let newMessageInfos = []; + let newMessageInfos: Array = []; if (!silenceMessages) { const time = Date.now(); - const messageDatas = []; + const messageDatas: Array = []; for (const fieldName in changedFields) { const newValue = changedFields[fieldName]; messageDatas.push({ diff --git a/keyserver/src/updaters/user-subscription-updaters.js b/keyserver/src/updaters/user-subscription-updaters.js --- a/keyserver/src/updaters/user-subscription-updaters.js +++ b/keyserver/src/updaters/user-subscription-updaters.js @@ -29,7 +29,7 @@ throw new ServerError('not_member'); } - const promises = []; + const promises: Array> = []; const newSubscription = { ...threadInfo.currentUser.subscription, diff --git a/keyserver/src/utils/validation-utils.test.js b/keyserver/src/utils/validation-utils.test.js --- a/keyserver/src/utils/validation-utils.test.js +++ b/keyserver/src/utils/validation-utils.test.js @@ -49,7 +49,7 @@ it('should redact password dict key', () => { const validator = tShape({ passwords: t.dict(tPassword, t.Bool) }); const object = { passwords: { password1: true, password2: false } }; - const redacted = { passwords: {} }; + const redacted: { +passwords: { [string]: mixed } } = { passwords: {} }; redacted.passwords[redactedString] = false; expect(sanitizeInput(validator, object)).toStrictEqual(redacted); });