diff --git a/lib/actions/activity-actions.js b/lib/actions/activity-actions.js --- a/lib/actions/activity-actions.js +++ b/lib/actions/activity-actions.js @@ -25,7 +25,7 @@ ): ((input: UpdateActivityInput) => Promise) => async input => { const { activityUpdates } = input; - const requests = {}; + const requests: { [string]: { +updates: ActivityUpdate[] } } = {}; for (const update of activityUpdates) { const keyserverID = extractKeyserverIDFromID(update.threadID); if (!requests[keyserverID]) { @@ -36,7 +36,7 @@ const responses = await callKeyserverEndpoint('update_activity', requests); - let unfocusedToUnread = []; + let unfocusedToUnread: $ReadOnlyArray = []; for (const keyserverID in responses) { unfocusedToUnread = unfocusedToUnread.concat( responses[keyserverID].unfocusedToUnread, diff --git a/lib/actions/device-actions.js b/lib/actions/device-actions.js --- a/lib/actions/device-actions.js +++ b/lib/actions/device-actions.js @@ -1,6 +1,9 @@ // @flow -import type { GetVersionActionPayload } from '../types/device-types'; +import type { + GetVersionActionPayload, + DeviceTokenUpdateRequest, +} from '../types/device-types'; import { getConfig } from '../utils/config.js'; import { useKeyserverCall } from '../utils/keyserver-call.js'; import type { @@ -25,7 +28,7 @@ callKeyserverEndpoint: CallKeyserverEndpoint, ): ((input: DeviceTokens) => Promise) => async input => { - const requests = {}; + const requests: { [string]: DeviceTokenUpdateRequest } = {}; for (const keyserverID in input) { requests[keyserverID] = { deviceToken: input[keyserverID], @@ -48,8 +51,8 @@ allKeyserverIDs: $ReadOnlyArray, ): ((input: ?string) => Promise) => async input => { - const requests = {}; - const deviceTokens = {}; + const requests: { [string]: DeviceTokenUpdateRequest } = {}; + const deviceTokens: { [string]: ?string } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = { deviceToken: input, @@ -84,7 +87,7 @@ allKeyserverIDs: $ReadOnlyArray, ): (() => Promise) => async () => { - const requests = {}; + const requests: { [string]: {} } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = {}; } diff --git a/lib/actions/entry-actions.js b/lib/actions/entry-actions.js --- a/lib/actions/entry-actions.js +++ b/lib/actions/entry-actions.js @@ -39,13 +39,13 @@ calendarQuery, allKeyserverIDs, ); - const requests = {}; + const requests: { [string]: CalendarQuery } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = calendarQueries[keyserverID]; } const responses = await callKeyserverEndpoint('fetch_entries', requests); - let rawEntryInfos = []; + let rawEntryInfos: $ReadOnlyArray = []; for (const keyserverID in responses) { rawEntryInfos = rawEntryInfos.concat( responses[keyserverID].rawEntryInfos, @@ -87,7 +87,7 @@ allKeyserverIDs, ); - const requests = {}; + const requests: { [string]: CalendarQuery } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = calendarQueries[keyserverID]; } @@ -96,8 +96,8 @@ 'update_calendar_query', requests, ); - let rawEntryInfos = []; - let deletedEntryIDs = []; + let rawEntryInfos: $ReadOnlyArray = []; + let deletedEntryIDs: $ReadOnlyArray = []; for (const keyserverID in responses) { rawEntryInfos = rawEntryInfos.concat( responses[keyserverID].rawEntryInfos, diff --git a/lib/actions/link-actions.js b/lib/actions/link-actions.js --- a/lib/actions/link-actions.js +++ b/lib/actions/link-actions.js @@ -49,7 +49,7 @@ allKeyserverIDs: $ReadOnlyArray, ): (() => Promise) => async () => { - const requests = {}; + const requests: { [string]: void } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = undefined; } @@ -57,7 +57,7 @@ 'fetch_primary_invite_links', requests, ); - let links = []; + let links: $ReadOnlyArray = []; for (const keyserverID in responses) { links = links.concat(responses[keyserverID].links); } diff --git a/lib/actions/message-actions.js b/lib/actions/message-actions.js --- a/lib/actions/message-actions.js +++ b/lib/actions/message-actions.js @@ -13,6 +13,9 @@ FetchPinnedMessagesResult, SearchMessagesRequest, SearchMessagesResponse, + FetchMessageInfosRequest, + RawMessageInfo, + MessageTruncationStatuses, } from '../types/message-types.js'; import type { MediaMessageServerDBContent } from '../types/messages/media.js'; import type { @@ -121,7 +124,7 @@ async threadIDs => { const sortedThreadIDs = sortThreadIDsPerKeyserver(threadIDs); - const requests = {}; + const requests: { [string]: FetchMessageInfosRequest } = {}; for (const keyserverID in sortedThreadIDs) { const cursors = Object.fromEntries( sortedThreadIDs[keyserverID].map(threadID => [threadID, null]), @@ -133,8 +136,8 @@ } const responses = await callKeyserverEndpoint('fetch_messages', requests); - let rawMessageInfos = []; - let truncationStatuses = {}; + let rawMessageInfos: $ReadOnlyArray = []; + let truncationStatuses: MessageTruncationStatuses = {}; for (const keyserverID in responses) { rawMessageInfos = rawMessageInfos.concat( responses[keyserverID].rawMessageInfos, diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js --- a/lib/actions/user-actions.js +++ b/lib/actions/user-actions.js @@ -11,11 +11,17 @@ PolicyAcknowledgmentRequest, ClaimUsernameResponse, LogInResponse, + LogInRequest, } from '../types/account-types.js'; import type { UpdateUserAvatarRequest, UpdateUserAvatarResponse, } from '../types/avatar-types.js'; +import type { RawEntryInfo, CalendarQuery } from '../types/entry-types.js'; +import type { + RawMessageInfo, + MessageTruncationStatuses, +} from '../types/message-types.js'; import type { GetSessionPublicKeysArgs, GetOlmSessionInitializationDataResponse, @@ -68,7 +74,7 @@ allKeyserverIDs: $ReadOnlyArray, ): ((input: PreRequestUserState) => Promise) => async preRequestUserState => { - const requests = {}; + const requests: { [string]: {} } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = {}; } @@ -128,7 +134,7 @@ allKeyserverIDs: $ReadOnlyArray, ): ((input: PreRequestUserState) => Promise) => async preRequestUserState => { - const requests = {}; + const requests: { [string]: {} } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = {}; } @@ -181,7 +187,9 @@ }; }; -function mergeUserInfos(...userInfoArrays: UserInfo[][]): UserInfo[] { +function mergeUserInfos( + ...userInfoArrays: Array<$ReadOnlyArray> +): UserInfo[] { const merged: { [string]: UserInfo } = {}; for (const userInfoArray of userInfoArrays) { for (const userInfo of userInfoArray) { @@ -195,6 +203,17 @@ return flattened; } +type WritableGenericMessagesResult = { + messageInfos: RawMessageInfo[], + truncationStatus: MessageTruncationStatuses, + watchedIDsAtRequestTime: string[], + currentAsOf: { [keyserverID: string]: number }, +}; +type WritableCalendarResult = { + rawEntryInfos: RawEntryInfo[], + calendarQuery: CalendarQuery, +}; + const logInActionTypes = Object.freeze({ started: 'LOG_IN_STARTED', success: 'LOG_IN_SUCCESS', @@ -224,7 +243,7 @@ keyserverIDs, ); - const requests = {}; + const requests: { [string]: LogInRequest } = {}; for (const keyserverID of keyserverIDs) { requests[keyserverID] = { ...restLogInInfo, @@ -246,11 +265,11 @@ const userInfosArrays = []; let threadInfos: RawThreadInfos = {}; - const calendarResult = { + const calendarResult: WritableCalendarResult = { calendarQuery: logInInfo.calendarQuery, rawEntryInfos: [], }; - const messagesResult = { + const messagesResult: WritableGenericMessagesResult = { messageInfos: [], truncationStatus: {}, watchedIDsAtRequestTime: watchedIDs, @@ -398,7 +417,7 @@ allKeyserverIDs: $ReadOnlyArray, ): ((input: UpdateUserSettingsRequest) => Promise) => async input => { - const requests = {}; + const requests: { [string]: UpdateUserSettingsRequest } = {}; for (const keyserverID of allKeyserverIDs) { requests[keyserverID] = input; } diff --git a/lib/selectors/account-selectors.js b/lib/selectors/account-selectors.js --- a/lib/selectors/account-selectors.js +++ b/lib/selectors/account-selectors.js @@ -9,7 +9,10 @@ deviceTokensSelector, } from './keyserver-selectors.js'; import { currentCalendarQuery } from './nav-selectors.js'; -import type { LogInExtraInfo } from '../types/account-types.js'; +import type { + LogInExtraInfo, + DeviceTokenUpdateRequest, +} from '../types/account-types.js'; import type { CalendarQuery } from '../types/entry-types.js'; import type { KeyserverInfos } from '../types/keyserver-types.js'; import type { AppState } from '../types/redux-types.js'; @@ -28,7 +31,7 @@ deviceTokens: { +[keyserverID: string]: ?string }, calendarQuery: (calendarActive: boolean) => CalendarQuery, ) => { - const deviceTokenUpdateRequest = {}; + const deviceTokenUpdateRequest: { [string]: DeviceTokenUpdateRequest } = {}; for (const keyserverID in deviceTokens) { if (deviceTokens[keyserverID]) { diff --git a/lib/selectors/keyserver-selectors.js b/lib/selectors/keyserver-selectors.js --- a/lib/selectors/keyserver-selectors.js +++ b/lib/selectors/keyserver-selectors.js @@ -119,7 +119,7 @@ } = createSelector( (state: AppState) => state.keyserverStore.keyserverInfos, (infos: { +[key: string]: KeyserverInfo }) => { - const deviceTokens = {}; + const deviceTokens: { [string]: ?string } = {}; for (const keyserverID in infos) { deviceTokens[keyserverID] = infos[keyserverID].deviceToken; } diff --git a/lib/types/account-types.js b/lib/types/account-types.js --- a/lib/types/account-types.js +++ b/lib/types/account-types.js @@ -44,7 +44,7 @@ +password: string, }; -type DeviceTokenUpdateRequest = { +export type DeviceTokenUpdateRequest = { +deviceToken: string, }; diff --git a/lib/types/filter-types.js b/lib/types/filter-types.js --- a/lib/types/filter-types.js +++ b/lib/types/filter-types.js @@ -17,7 +17,7 @@ +type: 'threads', +threadIDs: $ReadOnlyArray, }; -type NotDeletedFilter = { +type: 'not_deleted' }; +export type NotDeletedFilter = { +type: 'not_deleted' }; export type CalendarFilter = NotDeletedFilter | CalendarThreadFilter; export const calendarFilterValidator: TUnion = t.union([ diff --git a/lib/utils/action-utils.js b/lib/utils/action-utils.js --- a/lib/utils/action-utils.js +++ b/lib/utils/action-utils.js @@ -24,6 +24,7 @@ import type { PlatformDetails } from '../types/device-types.js'; import type { Endpoint, SocketAPIHandler } from '../types/endpoints.js'; import type { CalendarQuery } from '../types/entry-types.js'; +import type { NotDeletedFilter } from '../types/filter-types.js'; import type { LoadingOptions, LoadingInfo } from '../types/loading-types.js'; import type { ActionPayload, @@ -502,7 +503,7 @@ function sortThreadIDsPerKeyserver(threadIDs: $ReadOnlyArray): { +[keyserverID: string]: $ReadOnlyArray, } { - const results = {}; + const results: { [string]: string[] } = {}; for (const threadID of threadIDs) { const keyserverID = extractKeyserverIDFromID(threadID); invariant(keyserverID, 'keyserver data missing from thread id'); @@ -514,6 +515,18 @@ return results; } +type CalendarThreadFilterWithWritableThreadIDs = { + +type: 'threads', + +threadIDs: string[], +}; +type CalendarFilterWithWritableThreadIDs = + | NotDeletedFilter + | CalendarThreadFilterWithWritableThreadIDs; +type CalendarQueryWithWritableFilters = { + +startDate: string, + +endDate: string, + +filters: CalendarFilterWithWritableThreadIDs[], +}; function sortCalendarQueryPerKeyserver( calendarQuery: CalendarQuery, keyserverIDs: $ReadOnlyArray, @@ -521,7 +534,7 @@ +[keyserverID: string]: CalendarQuery, } { const { startDate, endDate, filters } = calendarQuery; - const results = {}; + const results: { [string]: CalendarQueryWithWritableFilters } = {}; for (const keyserverID of keyserverIDs) { results[keyserverID] = { @@ -545,6 +558,10 @@ let threadFilter = results[keyserverID].filters.find( flt => flt.type === 'threads', ); + invariant( + !threadFilter || threadFilter.type === 'threads', + 'should only match CalendarThreadFilter', + ); if (!threadFilter) { threadFilter = { type: 'threads', threadIDs: [] }; results[keyserverID].filters.push(threadFilter); diff --git a/lib/utils/keyserver-call.js b/lib/utils/keyserver-call.js --- a/lib/utils/keyserver-call.js +++ b/lib/utils/keyserver-call.js @@ -2,7 +2,6 @@ import _memoize from 'lodash/memoize.js'; import * as React from 'react'; -import { useDispatch } from 'react-redux'; import { createSelector } from 'reselect'; import { bindCookieAndUtilsIntoCallServerEndpoint } from './action-utils.js'; @@ -12,7 +11,7 @@ CallServerEndpointOptions, } from './call-server-endpoint.js'; import { promiseAll } from './promises.js'; -import { useSelector } from './redux-utils.js'; +import { useSelector, useDispatch } from './redux-utils.js'; import type { PlatformDetails } from '../types/device-types.js'; import type { Endpoint } from '../types/endpoints.js'; import type { KeyserverInfo } from '../types/keyserver-types.js'; @@ -83,7 +82,12 @@ +keyserverInfos: { +[keyserverID: string]: KeyserverInfoPartial }, }; -const bindCallKeyserverEndpointSelector = createSelector( +const bindCallKeyserverEndpointSelector: BindKeyserverCallParams => < + Args: mixed, + Return, +>( + keyserverCall: ActionFunc, +) => Args => Promise = createSelector( (state: BindKeyserverCallParams) => state.dispatch, (state: BindKeyserverCallParams) => state.currentUserInfo, (state: BindKeyserverCallParams) => state.keyserverInfos, @@ -130,7 +134,7 @@ ); }; - const promises = {}; + const promises: { [string]: Promise } = {}; for (const keyserverID in requests) { promises[keyserverID] = bindCallKeyserverEndpoint(keyserverID); }