diff --git a/keyserver/src/responders/redux-state-responders.js b/keyserver/src/responders/redux-state-responders.js index b7181d2b6..8d991d4af 100644 --- a/keyserver/src/responders/redux-state-responders.js +++ b/keyserver/src/responders/redux-state-responders.js @@ -1,375 +1,372 @@ // @flow import _keyBy from 'lodash/fp/keyBy.js'; import t, { type TInterface } from 'tcomb'; import { baseLegalPolicies } from 'lib/facts/policies.js'; import { daysToEntriesFromEntryInfos } from 'lib/reducers/entry-reducer.js'; import { freshMessageStore } from 'lib/reducers/message-reducer.js'; import { mostRecentlyReadThread } from 'lib/selectors/thread-selectors.js'; import { mostRecentMessageTimestamp } from 'lib/shared/message-utils.js'; import { threadHasPermission, threadIsPending, parsePendingThreadID, createPendingThread, } from 'lib/shared/thread-utils.js'; -import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js'; import { defaultCalendarFilters } from 'lib/types/filter-types.js'; import { type CommunityLinks, type InviteLinkWithHolder, } from 'lib/types/link-types.js'; import { defaultNumberPerThread, type MessageStore, } from 'lib/types/message-types.js'; import type { ServerWebInitialReduxStateResponse } from 'lib/types/redux-types.js'; import { threadPermissions } from 'lib/types/thread-permission-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; import { type GlobalAccountUserInfo } from 'lib/types/user-types.js'; import { currentDateInTimeZone } from 'lib/utils/date-utils.js'; import { ServerError } from 'lib/utils/errors.js'; import { promiseAll } from 'lib/utils/promises.js'; import { urlInfoValidator } from 'lib/utils/url-utils.js'; import { tShape } from 'lib/utils/validation-utils.js'; import type { InitialReduxStateRequest, ExcludedData, } from 'web/types/redux-types.js'; import { navInfoFromURL } from 'web/url-utils.js'; import { fetchEntryInfos } from '../fetchers/entry-fetchers.js'; import { fetchPrimaryInviteLinks } from '../fetchers/link-fetchers.js'; import { fetchMessageInfos } from '../fetchers/message-fetchers.js'; import { hasAnyNotAcknowledgedPolicies } from '../fetchers/policy-acknowledgment-fetchers.js'; import { fetchThreadInfos } from '../fetchers/thread-fetchers.js'; import { fetchCurrentUserInfo, fetchKnownUserInfos, fetchUserInfos, } from '../fetchers/user-fetchers.js'; import { getWebPushConfig } from '../push/providers.js'; import { setNewSession } from '../session/cookies.js'; import { Viewer } from '../session/viewer.js'; import { thisKeyserverID } from '../user/identity.js'; const excludedDataValidator: TInterface = tShape({ userStore: t.maybe(t.Bool), messageStore: t.maybe(t.Bool), threadStore: t.maybe(t.Bool), entryStore: t.maybe(t.Bool), }); export const initialReduxStateRequestValidator: TInterface = tShape({ urlInfo: urlInfoValidator, excludedData: excludedDataValidator, clientUpdatesCurrentAsOf: t.Number, }); async function getInitialReduxStateResponder( viewer: Viewer, request: InitialReduxStateRequest, ): Promise { const { urlInfo, excludedData, clientUpdatesCurrentAsOf } = request; - const useDatabase = viewer.loggedIn && canUseDatabaseOnWeb(viewer.userID); const hasNotAcknowledgedPoliciesPromise = hasAnyNotAcknowledgedPolicies( viewer.id, baseLegalPolicies, ); const initialNavInfoPromise = (async () => { try { let backupInfo = { now: currentDateInTimeZone(viewer.timeZone), }; // Some user ids in selectedUserList might not exist in the userInfos // (e.g. they were included in the results of the user search endpoint) // Because of that we keep their userInfos inside the navInfo. if (urlInfo.selectedUserList) { const fetchedUserInfos = await fetchUserInfos(urlInfo.selectedUserList); const userInfos: { [string]: GlobalAccountUserInfo } = {}; for (const userID in fetchedUserInfos) { const userInfo = fetchedUserInfos[userID]; if (userInfo.username) { userInfos[userID] = { ...userInfo, username: userInfo.username, }; } } backupInfo = { userInfos, ...backupInfo }; } return navInfoFromURL(urlInfo, backupInfo); } catch (e) { throw new ServerError(e.message); } })(); const calendarQueryPromise = (async () => { const initialNavInfo = await initialNavInfoPromise; return { startDate: initialNavInfo.startDate, endDate: initialNavInfo.endDate, filters: defaultCalendarFilters, }; })(); const messageSelectionCriteria = { joinedThreads: true }; - const serverUpdatesCurrentAsOf = - useDatabase && clientUpdatesCurrentAsOf - ? clientUpdatesCurrentAsOf - : Date.now(); + const serverUpdatesCurrentAsOf = clientUpdatesCurrentAsOf + ? clientUpdatesCurrentAsOf + : Date.now(); const threadInfoPromise = fetchThreadInfos(viewer); const messageInfoPromise = fetchMessageInfos( viewer, messageSelectionCriteria, defaultNumberPerThread, ); const entryInfoPromise = (async () => { const calendarQuery = await calendarQueryPromise; return await fetchEntryInfos(viewer, [calendarQuery]); })(); const currentUserInfoPromise = fetchCurrentUserInfo(viewer); const userInfoPromise = fetchKnownUserInfos(viewer); const sessionIDPromise = (async () => { const calendarQuery = await calendarQueryPromise; if (viewer.loggedIn) { await setNewSession(viewer, calendarQuery, serverUpdatesCurrentAsOf); } return viewer.sessionID; })(); const threadStorePromise = (async () => { - if (excludedData.threadStore && useDatabase) { + if (excludedData.threadStore) { return { threadInfos: {} }; } const [{ threadInfos }, hasNotAcknowledgedPolicies] = await Promise.all([ threadInfoPromise, hasNotAcknowledgedPoliciesPromise, ]); return { threadInfos: hasNotAcknowledgedPolicies ? {} : threadInfos }; })(); const messageStorePromise: Promise = (async () => { const [ { threadInfos }, { rawMessageInfos, truncationStatuses }, hasNotAcknowledgedPolicies, keyserverID, ] = await Promise.all([ threadInfoPromise, messageInfoPromise, hasNotAcknowledgedPoliciesPromise, thisKeyserverID(), ]); if (hasNotAcknowledgedPolicies) { return { messages: {}, threads: {}, local: {}, currentAsOf: { [keyserverID]: 0 }, }; } const { messageStore: freshStore } = freshMessageStore( rawMessageInfos, truncationStatuses, { [keyserverID]: mostRecentMessageTimestamp( rawMessageInfos, serverUpdatesCurrentAsOf, ), }, threadInfos, ); return freshStore; })(); const finalMessageStorePromise: Promise = (async () => { - if (excludedData.messageStore && useDatabase) { + if (excludedData.messageStore) { return { messages: {}, threads: {}, local: {}, currentAsOf: {}, }; } return await messageStorePromise; })(); const entryStorePromise = (async () => { const [{ rawEntryInfos }, hasNotAcknowledgedPolicies] = await Promise.all([ entryInfoPromise, hasNotAcknowledgedPoliciesPromise, ]); if (hasNotAcknowledgedPolicies) { return { entryInfos: {}, daysToEntries: {}, lastUserInteractionCalendar: 0, }; } return { entryInfos: _keyBy('id')(rawEntryInfos), daysToEntries: daysToEntriesFromEntryInfos(rawEntryInfos), lastUserInteractionCalendar: serverUpdatesCurrentAsOf, }; })(); const finalEntryStorePromise = (async () => { - if (excludedData.entryStore && useDatabase) { + if (excludedData.entryStore) { return { entryInfos: {}, daysToEntries: {}, lastUserInteractionCalendar: 0, }; } return await entryStorePromise; })(); const userInfosPromise = (async () => { const [userInfos, hasNotAcknowledgedPolicies] = await Promise.all([ userInfoPromise, hasNotAcknowledgedPoliciesPromise, ]); return hasNotAcknowledgedPolicies ? {} : userInfos; })(); const finalUserInfosPromise = (async () => { - if (excludedData.userStore && useDatabase) { + if (excludedData.userStore) { return {}; } return await userInfosPromise; })(); const navInfoPromise = (async () => { const [ { threadInfos }, messageStore, currentUserInfo, userInfos, finalNavInfo, ] = await Promise.all([ threadInfoPromise, messageStorePromise, currentUserInfoPromise, userInfosPromise, initialNavInfoPromise, ]); const requestedActiveChatThreadID = finalNavInfo.activeChatThreadID; if ( requestedActiveChatThreadID && !threadIsPending(requestedActiveChatThreadID) && !threadHasPermission( threadInfos[requestedActiveChatThreadID], threadPermissions.VISIBLE, ) ) { finalNavInfo.activeChatThreadID = null; } if (!finalNavInfo.activeChatThreadID) { const mostRecentThread = mostRecentlyReadThread( messageStore, threadInfos, ); if (mostRecentThread) { finalNavInfo.activeChatThreadID = mostRecentThread; } } const curActiveChatThreadID = finalNavInfo.activeChatThreadID; if ( curActiveChatThreadID && threadIsPending(curActiveChatThreadID) && finalNavInfo.pendingThread?.id !== curActiveChatThreadID ) { const pendingThreadData = parsePendingThreadID(curActiveChatThreadID); if ( pendingThreadData && pendingThreadData.threadType !== threadTypes.SIDEBAR && currentUserInfo.id ) { const members = [...pendingThreadData.memberIDs, currentUserInfo.id] .map(id => { const userInfo = userInfos[id]; if (!userInfo || !userInfo.username) { return undefined; } const { username } = userInfo; return { id, username }; }) .filter(Boolean); const newPendingThread = createPendingThread({ viewerID: currentUserInfo.id, threadType: pendingThreadData.threadType, members, }); finalNavInfo.activeChatThreadID = newPendingThread.id; finalNavInfo.pendingThread = newPendingThread; } } return finalNavInfo; })(); const currentAsOfPromise = (async () => { const hasNotAcknowledgedPolicies = await hasNotAcknowledgedPoliciesPromise; return hasNotAcknowledgedPolicies ? 0 : serverUpdatesCurrentAsOf; })(); const pushApiPublicKeyPromise: Promise = (async () => { const pushConfig = await getWebPushConfig(); if (!pushConfig) { if (process.env.NODE_ENV !== 'development') { console.warn('keyserver/secrets/web_push_config.json should exist'); } return null; } return pushConfig.publicKey; })(); const inviteLinksStorePromise = (async () => { const primaryInviteLinks = await fetchPrimaryInviteLinks(viewer); const links: { [string]: CommunityLinks } = {}; for (const { blobHolder, ...link }: InviteLinkWithHolder of primaryInviteLinks) { if (link.primary) { links[link.communityID] = { primaryLink: link, }; } } return { links, }; })(); const keyserverInfoPromise = (async () => { const { sessionID, updatesCurrentAsOf } = await promiseAll({ sessionID: sessionIDPromise, updatesCurrentAsOf: currentAsOfPromise, }); return { sessionID, updatesCurrentAsOf, }; })(); const initialReduxState: ServerWebInitialReduxStateResponse = await promiseAll({ navInfo: navInfoPromise, currentUserInfo: currentUserInfoPromise, entryStore: finalEntryStorePromise, threadStore: threadStorePromise, userInfos: finalUserInfosPromise, messageStore: finalMessageStorePromise, pushApiPublicKey: pushApiPublicKeyPromise, inviteLinksStore: inviteLinksStorePromise, keyserverInfo: keyserverInfoPromise, }); return initialReduxState; } export { getInitialReduxStateResponder }; diff --git a/lib/shared/web-database.js b/lib/shared/web-database.js deleted file mode 100644 index 5d653d80f..000000000 --- a/lib/shared/web-database.js +++ /dev/null @@ -1,13 +0,0 @@ -// @flow - -import { isStaff } from './staff-utils.js'; -import { isDev } from '../utils/dev-utils.js'; - -function canUseDatabaseOnWeb(userID: ?string): boolean { - if (!userID) { - return false; - } - return isDev || isStaff(userID); -} - -export { canUseDatabaseOnWeb }; diff --git a/web/components/db-ops-handler.react.js b/web/components/db-ops-handler.react.js index cfb319bdd..22406c5cb 100644 --- a/web/components/db-ops-handler.react.js +++ b/web/components/db-ops-handler.react.js @@ -1,20 +1,18 @@ // @flow import * as React from 'react'; import { DBOpsHandler as BaseHandler } from 'lib/handlers/db-ops-handler.react.js'; import type { StoreOperations } from 'lib/types/store-ops-types.js'; -import { useSelector } from '../redux/redux-utils.js'; import { processDBStoreOperations } from '../shared-worker/utils/store.js'; function DBOpsHandler(): React.Node { - const currentUserID = useSelector(state => state.currentUserInfo?.id ?? null); const processOperations = React.useCallback( - (ops: StoreOperations) => processDBStoreOperations(ops, currentUserID), - [currentUserID], + (ops: StoreOperations) => processDBStoreOperations(ops), + [], ); return ; } export { DBOpsHandler }; diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js index f7fc89eca..20866f8ef 100644 --- a/web/redux/initial-state-gate.js +++ b/web/redux/initial-state-gate.js @@ -1,219 +1,214 @@ // @flow import * as React from 'react'; import { PersistGate } from 'redux-persist/es/integration/react.js'; import type { Persistor } from 'redux-persist/es/types'; import { setClientDBStoreActionType } from 'lib/actions/client-db-store-actions.js'; import type { EntryStoreOperation } from 'lib/ops/entries-store-ops.js'; import type { MessageStoreOperation } from 'lib/ops/message-store-ops.js'; import type { ThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; import type { UserStoreOperation } from 'lib/ops/user-store-ops.js'; import { getMessageSearchStoreOps } from 'lib/reducers/db-ops-reducer.js'; import { allUpdatesCurrentAsOfSelector } from 'lib/selectors/keyserver-selectors.js'; -import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js'; import type { RawThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { convertIDToNewSchema } from 'lib/utils/migration-utils.js'; import { entries, values } from 'lib/utils/objects.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; import { infoFromURL } from 'lib/utils/url-utils.js'; import { setInitialReduxState, useGetInitialReduxState, } from './action-types.js'; import { useSelector } from './redux-utils.js'; import { authoritativeKeyserverID } from '../authoritative-keyserver.js'; import Loading from '../loading.react.js'; import { getClientDBStore, processDBStoreOperations, } from '../shared-worker/utils/store.js'; import type { InitialReduxStateActionPayload } from '../types/redux-types.js'; type Props = { +persistor: Persistor, +children: React.Node, }; function InitialReduxStateGate(props: Props): React.Node { const { children, persistor } = props; const callGetInitialReduxState = useGetInitialReduxState(); const dispatch = useDispatch(); const [initError, setInitError] = React.useState(null); React.useEffect(() => { if (initError) { throw initError; } }, [initError]); const isRehydrated = useSelector(state => !!state._persist?.rehydrated); const allUpdatesCurrentAsOf = useSelector(allUpdatesCurrentAsOfSelector); const prevIsRehydrated = React.useRef(false); React.useEffect(() => { if (prevIsRehydrated.current || !isRehydrated) { return; } prevIsRehydrated.current = isRehydrated; void (async () => { try { let urlInfo = infoFromURL(decodeURI(window.location.href)); // Handle older links if (urlInfo.thread) { urlInfo = { ...urlInfo, thread: convertIDToNewSchema( urlInfo.thread, authoritativeKeyserverID, ), }; } const clientDBStore = await getClientDBStore(); dispatch({ type: setClientDBStoreActionType, payload: clientDBStore, }); const payload = await callGetInitialReduxState({ urlInfo, excludedData: { threadStore: !!clientDBStore.threadStore, messageStore: !!clientDBStore.messages, userStore: !!clientDBStore.users, entryStore: !!clientDBStore.entries, }, allUpdatesCurrentAsOf, }); const currentLoggedInUserID = payload.currentUserInfo?.anonymous ? null : payload.currentUserInfo?.id; - const useDatabase = canUseDatabaseOnWeb(currentLoggedInUserID); - if (!currentLoggedInUserID || !useDatabase) { + if (!currentLoggedInUserID) { dispatch({ type: setInitialReduxState, payload }); return; } let initialReduxState: InitialReduxStateActionPayload = payload; let threadStoreOperations: ThreadStoreOperation[] = []; if (clientDBStore.threadStore) { const { threadStore, ...rest } = initialReduxState; initialReduxState = rest; } else { // When there is no data in the DB, it's necessary to migrate data // from the keyserver payload to the DB threadStoreOperations = entries(payload.threadStore.threadInfos).map( ([id, threadInfo]: [string, RawThreadInfo]) => ({ type: 'replace', payload: { id, threadInfo, }, }), ); } let userStoreOperations: UserStoreOperation[] = []; if (clientDBStore.users) { const { userInfos, ...rest } = initialReduxState; initialReduxState = rest; } else { userStoreOperations = values(payload.userInfos).map(userInfo => ({ type: 'replace_user', payload: userInfo, })); } let messageStoreOperations: MessageStoreOperation[] = []; if (clientDBStore.messages) { const { messageStore, ...rest } = initialReduxState; initialReduxState = rest; } else { const { messages, threads } = payload.messageStore; messageStoreOperations = [ ...entries(messages).map(([id, messageInfo]) => ({ type: 'replace', payload: { id, messageInfo }, })), { type: 'replace_threads', payload: { threads }, }, ]; } let entryStoreOperations: Array = []; if (clientDBStore.entries) { const { entryStore, ...rest } = initialReduxState; initialReduxState = rest; } else { entryStoreOperations = entries(payload.entryStore.entryInfos).map( ([id, entry]) => ({ type: 'replace_entry', payload: { id, entry }, }), ); } if ( threadStoreOperations.length > 0 || userStoreOperations.length > 0 || messageStoreOperations.length > 0 || entryStoreOperations.length > 0 ) { const messageSearchStoreOperations = getMessageSearchStoreOps( messageStoreOperations, ); - await processDBStoreOperations( - { - threadStoreOperations, - draftStoreOperations: [], - messageStoreOperations, - reportStoreOperations: [], - userStoreOperations, - keyserverStoreOperations: [], - communityStoreOperations: [], - integrityStoreOperations: [], - syncedMetadataStoreOperations: [], - auxUserStoreOperations: [], - threadActivityStoreOperations: [], - entryStoreOperations, - messageSearchStoreOperations, - }, - currentLoggedInUserID, - ); + await processDBStoreOperations({ + threadStoreOperations, + draftStoreOperations: [], + messageStoreOperations, + reportStoreOperations: [], + userStoreOperations, + keyserverStoreOperations: [], + communityStoreOperations: [], + integrityStoreOperations: [], + syncedMetadataStoreOperations: [], + auxUserStoreOperations: [], + threadActivityStoreOperations: [], + entryStoreOperations, + messageSearchStoreOperations, + }); } dispatch({ type: setInitialReduxState, payload: initialReduxState, }); } catch (err) { setInitError(err); } })(); }, [callGetInitialReduxState, dispatch, isRehydrated, allUpdatesCurrentAsOf]); const initialStateLoaded = useSelector(state => state.initialStateLoaded); const childFunction = React.useCallback( // This argument is passed from `PersistGate`. It means that the state is // rehydrated and we can start fetching the initial info. (bootstrapped: boolean) => { if (bootstrapped && initialStateLoaded) { return children; } else { return ; } }, [children, initialStateLoaded], ); return {childFunction}; } export default InitialReduxStateGate; diff --git a/web/shared-worker/utils/store.js b/web/shared-worker/utils/store.js index 6ad474064..c53fa2454 100644 --- a/web/shared-worker/utils/store.js +++ b/web/shared-worker/utils/store.js @@ -1,277 +1,269 @@ // @flow import { auxUserStoreOpsHandlers } from 'lib/ops/aux-user-store-ops.js'; import { communityStoreOpsHandlers } from 'lib/ops/community-store-ops.js'; import { entryStoreOpsHandlers } from 'lib/ops/entries-store-ops.js'; import { integrityStoreOpsHandlers } from 'lib/ops/integrity-store-ops.js'; import { keyserverStoreOpsHandlers } from 'lib/ops/keyserver-store-ops.js'; import { messageStoreOpsHandlers } from 'lib/ops/message-store-ops.js'; import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js'; import { syncedMetadataStoreOpsHandlers } from 'lib/ops/synced-metadata-store-ops.js'; import { threadActivityStoreOpsHandlers } from 'lib/ops/thread-activity-store-ops.js'; import { threadStoreOpsHandlers } from 'lib/ops/thread-store-ops.js'; import { userStoreOpsHandlers } from 'lib/ops/user-store-ops.js'; -import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js'; import type { ClientStore, StoreOperations, } from 'lib/types/store-ops-types.js'; import { translateClientDBLocalMessageInfos } from 'lib/utils/message-ops-utils.js'; import { entries } from 'lib/utils/objects.js'; import { defaultWebState } from '../../redux/default-state.js'; import { workerRequestMessageTypes } from '../../types/worker-types.js'; import { getCommSharedWorker } from '../shared-worker-provider.js'; async function getClientDBStore(): Promise { const sharedWorker = await getCommSharedWorker(); let result: ClientStore = { currentUserID: null, drafts: [], messages: null, threadStore: null, messageStoreThreads: null, reports: null, users: null, keyserverInfos: defaultWebState.keyserverStore.keyserverInfos, communityInfos: null, threadHashes: null, syncedMetadata: null, auxUserInfos: null, threadActivityStore: null, entries: null, messageStoreLocalMessageInfos: null, }; const data = await sharedWorker.schedule({ type: workerRequestMessageTypes.GET_CLIENT_STORE, }); if (data?.store?.drafts) { result = { ...result, drafts: data.store.drafts, }; } if (data?.store?.reports) { result = { ...result, reports: reportStoreOpsHandlers.translateClientDBData(data.store.reports), }; } if (data?.store?.threads && data.store.threads.length > 0) { result = { ...result, threadStore: { threadInfos: threadStoreOpsHandlers.translateClientDBData( data.store.threads, ), }, }; } if (data?.store?.keyservers?.length) { result = { ...result, keyserverInfos: keyserverStoreOpsHandlers.translateClientDBData( data.store.keyservers, ), }; } if (data?.store?.communities) { result = { ...result, communityInfos: communityStoreOpsHandlers.translateClientDBData( data.store.communities, ), }; } if (data?.store?.integrityThreadHashes) { result = { ...result, threadHashes: integrityStoreOpsHandlers.translateClientDBData( data.store.integrityThreadHashes, ), }; } if (data?.store?.syncedMetadata) { result = { ...result, syncedMetadata: syncedMetadataStoreOpsHandlers.translateClientDBData( data.store.syncedMetadata, ), }; } if (data?.store?.auxUserInfos) { result = { ...result, auxUserInfos: auxUserStoreOpsHandlers.translateClientDBData( data.store.auxUserInfos, ), }; } if (data?.store?.users && data.store.users.length > 0) { result = { ...result, users: userStoreOpsHandlers.translateClientDBData(data.store.users), }; } if (data?.store?.messages && data.store.messages.length > 0) { result = { ...result, messages: data.store.messages, }; } if ( data?.store?.messageStoreThreads && data.store.messageStoreThreads.length > 0 ) { result = { ...result, messageStoreThreads: data.store.messageStoreThreads, }; } if ( data?.store?.threadActivityEntries && data.store.threadActivityEntries.length > 0 ) { result = { ...result, threadActivityStore: threadActivityStoreOpsHandlers.translateClientDBData( data.store.threadActivityEntries, ), }; } if (data?.store?.entries && data.store.entries.length > 0) { result = { ...result, entries: entryStoreOpsHandlers.translateClientDBData(data.store.entries), }; } if ( data?.store?.messageStoreLocalMessageInfos && data.store.messageStoreLocalMessageInfos.length > 0 ) { result = { ...result, messageStoreLocalMessageInfos: translateClientDBLocalMessageInfos( data.store.messageStoreLocalMessageInfos, ), }; } return result; } async function processDBStoreOperations( storeOperations: StoreOperations, - userID?: ?string, ): Promise { const { draftStoreOperations, threadStoreOperations, reportStoreOperations, keyserverStoreOperations, communityStoreOperations, integrityStoreOperations, syncedMetadataStoreOperations, auxUserStoreOperations, userStoreOperations, messageStoreOperations, threadActivityStoreOperations, outboundP2PMessages, entryStoreOperations, messageSearchStoreOperations, } = storeOperations; - const canUseDatabase = canUseDatabaseOnWeb(userID); - - const convertedThreadStoreOperations = canUseDatabase - ? threadStoreOpsHandlers.convertOpsToClientDBOps(threadStoreOperations) - : []; + const convertedThreadStoreOperations = + threadStoreOpsHandlers.convertOpsToClientDBOps(threadStoreOperations); const convertedReportStoreOperations = reportStoreOpsHandlers.convertOpsToClientDBOps(reportStoreOperations); const convertedKeyserverStoreOperations = keyserverStoreOpsHandlers.convertOpsToClientDBOps(keyserverStoreOperations); const convertedCommunityStoreOperations = communityStoreOpsHandlers.convertOpsToClientDBOps(communityStoreOperations); const convertedIntegrityStoreOperations = integrityStoreOpsHandlers.convertOpsToClientDBOps(integrityStoreOperations); const convertedSyncedMetadataStoreOperations = syncedMetadataStoreOpsHandlers.convertOpsToClientDBOps( syncedMetadataStoreOperations, ); const convertedAuxUserStoreOperations = auxUserStoreOpsHandlers.convertOpsToClientDBOps(auxUserStoreOperations); const convertedUserStoreOperations = userStoreOpsHandlers.convertOpsToClientDBOps(userStoreOperations); const convertedMessageStoreOperations = messageStoreOpsHandlers.convertOpsToClientDBOps(messageStoreOperations); const convertedThreadActivityStoreOperations = threadActivityStoreOpsHandlers.convertOpsToClientDBOps( threadActivityStoreOperations, ); const convertedEntryStoreOperations = entryStoreOpsHandlers.convertOpsToClientDBOps(entryStoreOperations); if ( convertedThreadStoreOperations.length === 0 && convertedReportStoreOperations.length === 0 && (!draftStoreOperations || draftStoreOperations.length === 0) && convertedKeyserverStoreOperations.length === 0 && convertedCommunityStoreOperations.length === 0 && convertedIntegrityStoreOperations.length === 0 && convertedSyncedMetadataStoreOperations.length === 0 && convertedAuxUserStoreOperations.length === 0 && convertedUserStoreOperations.length === 0 && convertedMessageStoreOperations.length === 0 && convertedThreadActivityStoreOperations.length === 0 && convertedEntryStoreOperations.length === 0 && outboundP2PMessages?.length === 0 ) { return; } const sharedWorker = await getCommSharedWorker(); const isSupported = await sharedWorker.isSupported(); if (!isSupported) { return; } try { await sharedWorker.schedule({ type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, storeOperations: { draftStoreOperations, reportStoreOperations: convertedReportStoreOperations, threadStoreOperations: convertedThreadStoreOperations, keyserverStoreOperations: convertedKeyserverStoreOperations, communityStoreOperations: convertedCommunityStoreOperations, integrityStoreOperations: convertedIntegrityStoreOperations, syncedMetadataStoreOperations: convertedSyncedMetadataStoreOperations, auxUserStoreOperations: convertedAuxUserStoreOperations, userStoreOperations: convertedUserStoreOperations, messageStoreOperations: convertedMessageStoreOperations, threadActivityStoreOperations: convertedThreadActivityStoreOperations, outboundP2PMessages, entryStoreOperations: convertedEntryStoreOperations, messageSearchStoreOperations, }, }); } catch (e) { console.log(e); - if (canUseDatabase) { - window.alert(e.message); - if ( - entries(storeOperations).some( - ([key, ops]) => - key !== 'draftStoreOperations' && - key !== 'reportStoreOperations' && - ops.length > 0, - ) - ) { - await sharedWorker.init({ clearDatabase: true, markAsCorrupted: true }); - location.reload(); - } + if ( + entries(storeOperations).some( + ([key, ops]) => + key !== 'draftStoreOperations' && + key !== 'reportStoreOperations' && + ops.length > 0, + ) + ) { + await sharedWorker.init({ clearDatabase: true, markAsCorrupted: true }); + location.reload(); } } } export { getClientDBStore, processDBStoreOperations };