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 @@ -1,6 +1,9 @@ // @flow -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { + extractKeyserverIDFromID, + extractKeyserverIDFromIDOptional, +} from '../keyserver-conn/keyserver-call-utils.js'; import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import type { @@ -27,7 +30,13 @@ const { activityUpdates } = input; const requests: { [string]: { +updates: ActivityUpdate[] } } = {}; for (const update of activityUpdates) { - const keyserverID = extractKeyserverIDFromID(update.threadID); + const optionalKeyserverID = extractKeyserverIDFromIDOptional( + update.threadID, + ); + if (!optionalKeyserverID) { + continue; + } + const keyserverID: string = optionalKeyserverID; if (!requests[keyserverID]) { requests[keyserverID] = { updates: [] }; } 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 @@ -1,4 +1,5 @@ // @flow + import * as React from 'react'; import type { CallSingleKeyserverEndpoint } from '../keyserver-conn/call-single-keyserver-endpoint.js'; diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js --- a/lib/actions/upload-actions.js +++ b/lib/actions/upload-actions.js @@ -6,7 +6,7 @@ import blobService from '../facts/blob-service.js'; import type { CallSingleKeyserverEndpoint } from '../keyserver-conn/call-single-keyserver-endpoint.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import { type PerformHTTPMultipartUpload } from '../keyserver-conn/multipart-upload.js'; @@ -115,7 +115,9 @@ ): ((input: DeleteUploadInput) => Promise) => async input => { const { id, keyserverOrThreadID } = input; - const keyserverID = extractKeyserverIDFromID(keyserverOrThreadID); + const keyserverID: string = + extractKeyserverIDFromIDOptional(keyserverOrThreadID) ?? + keyserverOrThreadID; const requests = { [keyserverID]: { id } }; await callKeyserverEndpoint('delete_upload', requests); }; @@ -224,7 +226,9 @@ } // 3. Upload metadata to keyserver - const keyserverID = extractKeyserverIDFromID(keyserverOrThreadID); + const keyserverID: string = + extractKeyserverIDFromIDOptional(keyserverOrThreadID) ?? + keyserverOrThreadID; const requests = { [keyserverID]: { blobHash, diff --git a/lib/keyserver-conn/keyserver-auth.js b/lib/keyserver-conn/keyserver-auth.js --- a/lib/keyserver-conn/keyserver-auth.js +++ b/lib/keyserver-conn/keyserver-auth.js @@ -4,7 +4,7 @@ import * as React from 'react'; import { useCallKeyserverEndpointContext } from './call-keyserver-endpoint-provider.react.js'; -import { extractKeyserverIDFromID } from './keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from './keyserver-call-utils.js'; import { CANCELLED_ERROR, type CallKeyserverEndpoint, @@ -46,7 +46,8 @@ const calendarQuery = React.useMemo(() => { const filters = filterThreadIDsInFilterList( calendarFilters, - (threadID: string) => extractKeyserverIDFromID(threadID) === keyserverID, + (threadID: string) => + extractKeyserverIDFromIDOptional(threadID) === keyserverID, ); return { startDate: navInfo.startDate, diff --git a/lib/keyserver-conn/keyserver-call-utils.js b/lib/keyserver-conn/keyserver-call-utils.js --- a/lib/keyserver-conn/keyserver-call-utils.js +++ b/lib/keyserver-conn/keyserver-call-utils.js @@ -5,17 +5,29 @@ import type { CalendarQuery } from '../types/entry-types.js'; import type { NotDeletedFilter } from '../types/filter-types.js'; -function extractKeyserverIDFromID(id: string): string { +function extractKeyserverIDFromIDOptional(id: string): ?string { + if (!id.includes('|')) { + return null; + } return id.split('|')[0]; } +function extractKeyserverIDFromID(id: string): string { + const keyserverID = extractKeyserverIDFromIDOptional(id); + invariant(keyserverID, 'Keyserver ID should be present'); + return keyserverID; +} + function sortThreadIDsPerKeyserver(threadIDs: $ReadOnlyArray): { +[keyserverID: string]: $ReadOnlyArray, } { const results: { [string]: string[] } = {}; for (const threadID of threadIDs) { - const keyserverID = extractKeyserverIDFromID(threadID); - invariant(keyserverID, 'keyserver data missing from thread id'); + const optionalKeyserverID = extractKeyserverIDFromIDOptional(threadID); + if (!optionalKeyserverID) { + continue; + } + const keyserverID: string = optionalKeyserverID; if (results[keyserverID] === undefined) { results[keyserverID] = []; } @@ -60,8 +72,8 @@ } } else if (filter.type === 'threads') { for (const threadID of filter.threadIDs) { - const keyserverID = extractKeyserverIDFromID(threadID); - if (results[keyserverID] === undefined) { + const keyserverID = extractKeyserverIDFromIDOptional(threadID); + if (!keyserverID || results[keyserverID] === undefined) { continue; } let threadFilter = results[keyserverID].filters.find( @@ -94,12 +106,14 @@ return []; } const keyserverIDsSet = new Set(keyserverIDs); - return threadIDs.filter(threadID => - keyserverIDsSet.has(extractKeyserverIDFromID(threadID)), - ); + return threadIDs.filter(threadID => { + const keyserverID = extractKeyserverIDFromIDOptional(threadID); + return keyserverID && keyserverIDsSet.has(keyserverID); + }); } export { + extractKeyserverIDFromIDOptional, extractKeyserverIDFromID, sortThreadIDsPerKeyserver, sortCalendarQueryPerKeyserver, diff --git a/lib/keyserver-conn/keyserver-call-utils.test.js b/lib/keyserver-conn/keyserver-call-utils.test.js --- a/lib/keyserver-conn/keyserver-call-utils.test.js +++ b/lib/keyserver-conn/keyserver-call-utils.test.js @@ -4,6 +4,7 @@ extractKeyserverIDFromID, sortCalendarQueryPerKeyserver, getThreadIDsForKeyservers, + extractKeyserverIDFromIDOptional, } from './keyserver-call-utils.js'; import type { CalendarQuery } from '../types/entry-types'; @@ -14,9 +15,22 @@ expect(extractKeyserverIDFromID(id)).toBe(keyserverID); }); - it('should return for ', () => { + it('should throw for non-keyserver ID', () => { + const id = '404'; + expect(() => extractKeyserverIDFromID(id)).toThrow(); + }); +}); + +describe('extractKeyserverIDFromIDOptional', () => { + it('should return for |', () => { const keyserverID = '404'; - expect(extractKeyserverIDFromID(keyserverID)).toBe(keyserverID); + const id = keyserverID + '|1234'; + expect(extractKeyserverIDFromIDOptional(id)).toBe(keyserverID); + }); + + it('should return null for non-keyserver ID', () => { + const id = '404'; + expect(extractKeyserverIDFromIDOptional(id)).toBe(null); }); }); diff --git a/lib/reducers/calendar-filters-reducer.js b/lib/reducers/calendar-filters-reducer.js --- a/lib/reducers/calendar-filters-reducer.js +++ b/lib/reducers/calendar-filters-reducer.js @@ -18,7 +18,7 @@ legacyLogInActionTypes, legacyKeyserverRegisterActionTypes, } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js'; import { filteredThreadIDs, @@ -220,8 +220,10 @@ keyserverIDs: $ReadOnlyArray, ): $ReadOnlyArray { const keyserverIDsSet = new Set(keyserverIDs); - const filterCondition = (threadID: string) => - !keyserverIDsSet.has(extractKeyserverIDFromID(threadID)); + const filterCondition = (threadID: string) => { + const keyserverID = extractKeyserverIDFromIDOptional(threadID); + return !keyserverID || !keyserverIDsSet.has(keyserverID); + }; return filterThreadIDsInFilterList(state, filterCondition); } diff --git a/lib/reducers/draft-reducer.js b/lib/reducers/draft-reducer.js --- a/lib/reducers/draft-reducer.js +++ b/lib/reducers/draft-reducer.js @@ -6,7 +6,7 @@ updateDraftActionType, } from '../actions/draft-actions.js'; import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js'; import type { DraftStore, DraftStoreOperation } from '../types/draft-types.js'; import type { BaseAction } from '../types/redux-types.js'; @@ -25,7 +25,8 @@ const drafts: { [key: string]: string } = {}; const ids: string[] = []; for (const key in draftStore.drafts) { - if (keyserverIDsSet.has(extractKeyserverIDFromID(key))) { + const keyserverID = extractKeyserverIDFromIDOptional(key); + if (keyserverID && keyserverIDsSet.has(keyserverID)) { ids.push(key); } else { drafts[key] = draftStore.drafts[key]; diff --git a/lib/reducers/invite-links-reducer.js b/lib/reducers/invite-links-reducer.js --- a/lib/reducers/invite-links-reducer.js +++ b/lib/reducers/invite-links-reducer.js @@ -6,7 +6,7 @@ fetchPrimaryInviteLinkActionTypes, } from '../actions/link-actions.js'; import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js'; import type { InviteLinksStore, CommunityLinks } from '../types/link-types.js'; import type { BaseAction } from '../types/redux-types.js'; @@ -60,7 +60,8 @@ const keyserverIDsSet = new Set(action.payload.keyserverIDs); const newLinks: { [communityID: string]: CommunityLinks } = {}; for (const linkID in state.links) { - if (!keyserverIDsSet.has(extractKeyserverIDFromID(linkID))) { + const keyserverID = extractKeyserverIDFromIDOptional(linkID); + if (!keyserverID || !keyserverIDsSet.has(keyserverID)) { newLinks[linkID] = state.links[linkID]; } } @@ -75,7 +76,7 @@ const { keyserverID } = action.payload; const newLinks: { [communityID: string]: CommunityLinks } = {}; for (const linkID in state.links) { - if (extractKeyserverIDFromID(linkID) !== keyserverID) { + if (extractKeyserverIDFromIDOptional(linkID) !== keyserverID) { newLinks[linkID] = state.links[linkID]; } } diff --git a/lib/reducers/keyserver-reducer.js b/lib/reducers/keyserver-reducer.js --- a/lib/reducers/keyserver-reducer.js +++ b/lib/reducers/keyserver-reducer.js @@ -25,7 +25,7 @@ legacyKeyserverRegisterActionTypes, legacyLogInActionTypes, } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType, updateConnectionStatusActionType, @@ -222,7 +222,7 @@ const calendarFilters = filterThreadIDsInFilterList( action.payload.calendarResult.calendarQuery.filters, (threadID: string) => - extractKeyserverIDFromID(threadID) === keyserverID, + extractKeyserverIDFromIDOptional(threadID) === keyserverID, ); operations.push({ type: 'replace_keyserver', @@ -729,7 +729,7 @@ filters: filterThreadIDsInFilterList( action.payload.calendarQuery.filters, (threadID: string) => - extractKeyserverIDFromID(threadID) === keyserverID, + extractKeyserverIDFromIDOptional(threadID) === keyserverID, ), }, }, diff --git a/lib/reducers/thread-activity-reducer.js b/lib/reducers/thread-activity-reducer.js --- a/lib/reducers/thread-activity-reducer.js +++ b/lib/reducers/thread-activity-reducer.js @@ -17,7 +17,7 @@ } from '../actions/thread-actions.js'; import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js'; import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js'; import { threadActivityStoreOpsHandlers, @@ -183,7 +183,8 @@ const keyserverIDsSet = new Set(action.payload.keyserverIDs); for (const threadID in state) { - if (!keyserverIDsSet.has(extractKeyserverIDFromID(threadID))) { + const keyserverID = extractKeyserverIDFromIDOptional(threadID); + if (!keyserverID || !keyserverIDsSet.has(keyserverID)) { continue; } threadIDsToRemove.push(threadID); @@ -208,7 +209,7 @@ const { keyserverID } = action.payload; for (const threadID in state) { - if (extractKeyserverIDFromID(threadID) !== keyserverID) { + if (extractKeyserverIDFromIDOptional(threadID) !== keyserverID) { continue; } threadIDsToRemove.push(threadID); diff --git a/lib/reducers/user-reducer.js b/lib/reducers/user-reducer.js --- a/lib/reducers/user-reducer.js +++ b/lib/reducers/user-reducer.js @@ -23,7 +23,7 @@ setUserSettingsActionTypes, updateUserAvatarActionTypes, } from '../actions/user-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js'; import { convertUserInfosToReplaceUserOps, @@ -310,7 +310,9 @@ if (action.type === joinThreadActionTypes.success) { keyserverID = action.payload.keyserverID; } else { - keyserverID = extractKeyserverIDFromID(action.payload.newThreadID); + keyserverID = extractKeyserverIDFromIDOptional( + action.payload.newThreadID, + ); } if (keyserverID !== authoritativeKeyserverID()) { return [state, [], []]; diff --git a/lib/selectors/thread-selectors.js b/lib/selectors/thread-selectors.js --- a/lib/selectors/thread-selectors.js +++ b/lib/selectors/thread-selectors.js @@ -18,7 +18,7 @@ } from './calendar-filter-selectors.js'; import { relativeMemberInfoSelectorForMembersOfThread } from './user-selectors.js'; import genesis from '../facts/genesis.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { getAvatarForThread, getRandomDefaultEmojiAvatar, @@ -251,7 +251,7 @@ (state: BaseAppState<>) => state.threadStore.threadInfos, (threadInfos: RawThreadInfos): { +[keyserverID: string]: number } => { const keyserverToThreads = _groupBy(threadInfo => - extractKeyserverIDFromID(threadInfo.id), + extractKeyserverIDFromIDOptional(threadInfo.id), )( values(threadInfos).filter(threadInfo => threadInHomeChatList(threadInfo), diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js --- a/lib/shared/message-utils.js +++ b/lib/shared/message-utils.js @@ -11,7 +11,7 @@ import { messageSpecs } from './messages/message-specs.js'; import { threadIsGroupChat } from './thread-utils.js'; import { useStringForUser } from '../hooks/ens-cache.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { contentStringForMediaArray } from '../media/media-utils.js'; import type { ChatMessageInfoItem } from '../selectors/chat-selectors.js'; import { threadInfoSelector } from '../selectors/thread-selectors.js'; @@ -661,11 +661,12 @@ const timePerKeyserver: { [keyserverID: string]: number } = {}; for (const messageInfo of messageInfos) { - const keyserverID = extractKeyserverIDFromID(messageInfo.threadID); + const keyserverID = extractKeyserverIDFromIDOptional(messageInfo.threadID); if ( - !timePerKeyserver[keyserverID] || - timePerKeyserver[keyserverID] < messageInfo.time + keyserverID && + (!timePerKeyserver[keyserverID] || + timePerKeyserver[keyserverID] < messageInfo.time) ) { timePerKeyserver[keyserverID] = messageInfo.time; } diff --git a/lib/shared/state-sync/entries-state-sync-spec.js b/lib/shared/state-sync/entries-state-sync-spec.js --- a/lib/shared/state-sync/entries-state-sync-spec.js +++ b/lib/shared/state-sync/entries-state-sync-spec.js @@ -4,7 +4,7 @@ import { createSelector } from 'reselect'; import type { StateSyncSpec, BoundStateSyncSpec } from './state-sync-spec.js'; -import { extractKeyserverIDFromID } from '../../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../../keyserver-conn/keyserver-call-utils.js'; import { type CalendarQuery, type RawEntryInfos, @@ -64,10 +64,12 @@ ) { const keyserverID = action.payload.keyserverID; const filteredBeforeStateCheck = values(beforeStateCheck).filter( - entry => entry.id && extractKeyserverIDFromID(entry.id) === keyserverID, + entry => + entry.id && extractKeyserverIDFromIDOptional(entry.id) === keyserverID, ); const filteredAfterStateCheck = values(afterStateCheck).filter( - entry => entry.id && extractKeyserverIDFromID(entry.id) === keyserverID, + entry => + entry.id && extractKeyserverIDFromIDOptional(entry.id) === keyserverID, ); const calendarQuery = action.payload.calendarQuery; @@ -111,7 +113,8 @@ keyserverID: string, ) { const filteredEntries = values(entryInfos).filter( - entry => entry.id && extractKeyserverIDFromID(entry.id) === keyserverID, + entry => + entry.id && extractKeyserverIDFromIDOptional(entry.id) === keyserverID, ); const filteredEntryInfos = filterRawEntryInfosByCalendarQuery( serverEntryInfosObject(filteredEntries), @@ -127,7 +130,8 @@ keyserverID: string, ) { const filteredEntries = values(entryInfos).filter( - entry => entry.id && extractKeyserverIDFromID(entry.id) === keyserverID, + entry => + entry.id && extractKeyserverIDFromIDOptional(entry.id) === keyserverID, ); const filteredEntryInfos = filterRawEntryInfosByCalendarQuery( serverEntryInfosObject(filteredEntries), diff --git a/lib/shared/state-sync/threads-state-sync-spec.js b/lib/shared/state-sync/threads-state-sync-spec.js --- a/lib/shared/state-sync/threads-state-sync-spec.js +++ b/lib/shared/state-sync/threads-state-sync-spec.js @@ -5,7 +5,7 @@ import { createSelector } from 'reselect'; import type { StateSyncSpec, BoundStateSyncSpec } from './state-sync-spec.js'; -import { extractKeyserverIDFromID } from '../../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../../keyserver-conn/keyserver-call-utils.js'; import type { CalendarQuery } from '../../types/entry-types.js'; import type { RawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; import type { AppState } from '../../types/redux-types.js'; @@ -41,14 +41,16 @@ ? (query: CalendarQuery, keyserverID: string) => combineUnorderedHashes( entries(threadHashes) - .filter(([id]) => extractKeyserverIDFromID(id) === keyserverID) + .filter( + ([id]) => extractKeyserverIDFromIDOptional(id) === keyserverID, + ) .map(([, threadHash]) => threadHash), ) : () => null, getIDs: threadHashingComplete ? (query: CalendarQuery, keyserverID: string) => Object.keys(threadHashes) - .filter(id => extractKeyserverIDFromID(id) === keyserverID) + .filter(id => extractKeyserverIDFromIDOptional(id) === keyserverID) .map(id => id.split('|')[1]) : () => null, canSyncState: () => threadHashingComplete, @@ -73,7 +75,7 @@ ) { const keyserverID = action.payload.keyserverID; const filter = _pickBy( - thread => extractKeyserverIDFromID(thread.id) === keyserverID, + thread => extractKeyserverIDFromIDOptional(thread.id) === keyserverID, ); const filteredBeforeStateCheck = filter(beforeStateCheck); const filteredAfterStateCheck = filter(afterStateCheck); diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -15,7 +15,7 @@ import ashoat from '../facts/ashoat.js'; import genesis from '../facts/genesis.js'; import { useLoggedInUserInfo } from '../hooks/account-hooks.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { hasPermission, permissionsToBitmaskHex, @@ -349,7 +349,7 @@ if (threadInfo.community !== genesis().id) { return threadInfo.members; } - const adminID = extractKeyserverIDFromID(threadInfo.id); + const adminID = extractKeyserverIDFromIDOptional(threadInfo.id); return threadInfo.members.filter( member => member.id !== adminID || member.role, diff --git a/lib/socket/activity-handler.react.js b/lib/socket/activity-handler.react.js --- a/lib/socket/activity-handler.react.js +++ b/lib/socket/activity-handler.react.js @@ -7,7 +7,7 @@ updateActivityActionTypes, useUpdateActivity, } from '../actions/activity-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { connectionSelector } from '../selectors/keyserver-selectors.js'; import { getMostRecentNonLocalMessageID } from '../shared/message-utils.js'; import { threadIsPending } from '../shared/thread-utils.js'; @@ -76,7 +76,7 @@ if ( prevActiveThread && !isPrevActiveThreadPending && - extractKeyserverIDFromID(prevActiveThread) === keyserverID + extractKeyserverIDFromIDOptional(prevActiveThread) === keyserverID ) { activityUpdates.push({ focus: false, @@ -87,7 +87,7 @@ if ( activeThread && !isActiveThreadPending && - extractKeyserverIDFromID(activeThread) === keyserverID + extractKeyserverIDFromIDOptional(activeThread) === keyserverID ) { activityUpdates.push({ focus: true, @@ -103,7 +103,7 @@ prevConnectionStatus === 'connected' && activeThread && !isActiveThreadPending && - extractKeyserverIDFromID(activeThread) === keyserverID + extractKeyserverIDFromIDOptional(activeThread) === keyserverID ) { // When the server closes a socket it also deletes any activity rows // associated with that socket's session. If that activity is still diff --git a/lib/socket/calendar-query-handler.react.js b/lib/socket/calendar-query-handler.react.js --- a/lib/socket/calendar-query-handler.react.js +++ b/lib/socket/calendar-query-handler.react.js @@ -9,7 +9,7 @@ useUpdateCalendarQuery, } from '../actions/entry-actions.js'; import type { UpdateCalendarQueryInput } from '../actions/entry-actions.js'; -import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { filterThreadIDsInFilterList } from '../reducers/calendar-filters-reducer.js'; import { timeUntilCalendarRangeExpiration } from '../selectors/nav-selectors.js'; import { useIsAppForegrounded } from '../shared/lifecycle-utils.js'; @@ -150,7 +150,7 @@ filters: filterThreadIDsInFilterList( query.filters, (threadID: string) => - extractKeyserverIDFromID(threadID) === keyserverID, + extractKeyserverIDFromIDOptional(threadID) === keyserverID, ), }; }, [currentCalendarQuery, keyserverID]); diff --git a/native/calendar/entry.react.js b/native/calendar/entry.react.js --- a/native/calendar/entry.react.js +++ b/native/calendar/entry.react.js @@ -26,7 +26,7 @@ useDeleteEntry, useSaveEntry, } from 'lib/actions/entry-actions.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js'; import { registerFetchKey } from 'lib/reducers/loading-reducer.js'; import { connectionSelector } from 'lib/selectors/keyserver-selectors.js'; import { colorIsDark } from 'lib/shared/color-utils.js'; @@ -809,11 +809,18 @@ const { threadInfo: unresolvedThreadInfo, ...restProps } = props; const threadInfo = useResolvedThreadInfo(unresolvedThreadInfo); - const keyserverID = extractKeyserverIDFromID(threadInfo.id); - const connection = useSelector(connectionSelector(keyserverID)); + const keyserverID = extractKeyserverIDFromIDOptional(threadInfo.id); + const connection = useSelector(state => { + if (!keyserverID) { + return { + status: 'connected', + }; + } + return connectionSelector(keyserverID)(state); + }); invariant( connection, - `keyserver ${keyserverID} missing from keyserverStore`, + `keyserver ${keyserverID ?? 'null'} missing from keyserverStore`, ); const online = connection.status === 'connected'; diff --git a/native/chat/settings/thread-settings-push-notifs.react.js b/native/chat/settings/thread-settings-push-notifs.react.js --- a/native/chat/settings/thread-settings-push-notifs.react.js +++ b/native/chat/settings/thread-settings-push-notifs.react.js @@ -4,7 +4,7 @@ import { Platform, TouchableOpacity, View } from 'react-native'; import Linking from 'react-native/Libraries/Linking/Linking.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js'; import { deviceTokenSelector } from 'lib/selectors/keyserver-selectors.js'; import { threadSettingsNotificationsCopy } from 'lib/shared/thread-settings-notifications-utils.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; @@ -143,8 +143,13 @@ React.memo(function ConnectedThreadSettingsPushNotifs( props: BaseProps, ) { - const keyserverID = extractKeyserverIDFromID(props.threadInfo.id); - const deviceToken = useSelector(deviceTokenSelector(keyserverID)); + const keyserverID = extractKeyserverIDFromIDOptional(props.threadInfo.id); + const deviceToken = useSelector(state => { + if (!keyserverID) { + return state.tunnelbrokerDeviceToken; + } + return deviceTokenSelector(keyserverID)(state); + }); const hasPushPermissions = deviceToken !== null && deviceToken !== undefined; const styles = useStyles(unboundStyles); diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js --- a/native/push/push-handler.react.js +++ b/native/push/push-handler.react.js @@ -17,7 +17,10 @@ useSetDeviceTokenFanout, } from 'lib/actions/device-actions.js'; import { saveMessagesActionType } from 'lib/actions/message-actions.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; +import { + extractKeyserverIDFromID, + extractKeyserverIDFromIDOptional, +} from 'lib/keyserver-conn/keyserver-call-utils.js'; import { deviceTokensSelector, allUpdatesCurrentAsOfSelector, @@ -624,7 +627,7 @@ } const keyserverIDToMessageInfos = _groupBy(messageInfos => - extractKeyserverIDFromID(messageInfos.threadID), + extractKeyserverIDFromIDOptional(messageInfos.threadID), )(rawMessageInfos); for (const keyserverID in keyserverIDToMessageInfos) { diff --git a/web/calendar/entry.react.js b/web/calendar/entry.react.js --- a/web/calendar/entry.react.js +++ b/web/calendar/entry.react.js @@ -17,7 +17,7 @@ type PushModal, useModalContext, } from 'lib/components/modal-provider.react.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; +import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js'; import { connectionSelector } from 'lib/selectors/keyserver-selectors.js'; import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; import { colorIsDark } from 'lib/shared/color-utils.js'; @@ -473,13 +473,13 @@ threadPermissions.EDIT_ENTRIES, ); const calendarQuery = useSelector(nonThreadCalendarQuery); - const keyserverID = extractKeyserverIDFromID(threadID); - const connection = useSelector(connectionSelector(keyserverID)); - invariant( - connection, - `keyserver ${keyserverID} missing from keyserverStore`, - ); - const online = connection.status === 'connected'; + const keyserverID = extractKeyserverIDFromIDOptional(threadID); + const online = useSelector(state => { + if (!keyserverID) { + return true; + } + return connectionSelector(keyserverID)(state) === 'connected'; + }); const callCreateEntry = useCreateEntry(); const callSaveEntry = useSaveEntry(); const callDeleteEntry = useDeleteEntry();