diff --git a/__mocks__/@ua/react-native-airship.js b/__mocks__/@ua/react-native-airship.js index 1672c064f9be..29be662e96a1 100644 --- a/__mocks__/@ua/react-native-airship.js +++ b/__mocks__/@ua/react-native-airship.js @@ -31,7 +31,7 @@ const Airship = { }, contact: { identify: jest.fn(), - getNamedUserId: jest.fn(), + getNamedUserId: () => Promise.resolve(undefined), reset: jest.fn(), }, }; diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.ts similarity index 77% rename from src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js rename to src/libs/Notification/PushNotification/ForegroundNotifications/index.android.ts index b36c0d0c7d18..5eef0b44a7d1 100644 --- a/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js +++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.ts @@ -1,5 +1,6 @@ import Airship from '@ua/react-native-airship'; import shouldShowPushNotification from '@libs/Notification/PushNotification/shouldShowPushNotification'; +import ForegroundNotificationsModule from './types'; function configureForegroundNotifications() { Airship.push.android.setForegroundDisplayPredicate((pushPayload) => Promise.resolve(shouldShowPushNotification(pushPayload))); @@ -9,7 +10,9 @@ function disableForegroundNotifications() { Airship.push.android.setForegroundDisplayPredicate(() => Promise.resolve(false)); } -export default { +const ForegroundNotifications: ForegroundNotificationsModule = { configureForegroundNotifications, disableForegroundNotifications, }; + +export default ForegroundNotifications; diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.ts similarity index 88% rename from src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js rename to src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.ts index 0f0929951a90..e5e5665d1ea2 100644 --- a/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js +++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.ts @@ -1,5 +1,6 @@ import Airship, {iOS} from '@ua/react-native-airship'; import shouldShowPushNotification from '@libs/Notification/PushNotification/shouldShowPushNotification'; +import ForegroundNotificationsModule from './types'; function configureForegroundNotifications() { // Set our default iOS foreground presentation to be loud with a banner @@ -20,7 +21,9 @@ function disableForegroundNotifications() { Airship.push.iOS.setForegroundPresentationOptionsCallback(() => Promise.resolve([])); } -export default { +const ForegroundNotifications: ForegroundNotificationsModule = { configureForegroundNotifications, disableForegroundNotifications, }; + +export default ForegroundNotifications; diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ts similarity index 58% rename from src/libs/Notification/PushNotification/ForegroundNotifications/index.js rename to src/libs/Notification/PushNotification/ForegroundNotifications/index.ts index acb116f7bc43..25baa34099b6 100644 --- a/src/libs/Notification/PushNotification/ForegroundNotifications/index.js +++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ts @@ -1,7 +1,11 @@ +import ForegroundNotificationsModule from './types'; + /** * Configures notification handling while in the foreground on iOS and Android. This is a no-op on other platforms. */ -export default { +const ForegroundNotifications: ForegroundNotificationsModule = { configureForegroundNotifications: () => {}, disableForegroundNotifications: () => {}, }; + +export default ForegroundNotifications; diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/types.ts b/src/libs/Notification/PushNotification/ForegroundNotifications/types.ts new file mode 100644 index 000000000000..f84934651259 --- /dev/null +++ b/src/libs/Notification/PushNotification/ForegroundNotifications/types.ts @@ -0,0 +1,6 @@ +type ForegroundNotificationsModule = { + configureForegroundNotifications: () => void; + disableForegroundNotifications: () => void; +}; + +export default ForegroundNotificationsModule; diff --git a/src/libs/Notification/PushNotification/NotificationType.js b/src/libs/Notification/PushNotification/NotificationType.js deleted file mode 100644 index 092a48fe7815..000000000000 --- a/src/libs/Notification/PushNotification/NotificationType.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * See https://github.com/Expensify/Web-Expensify/blob/main/lib/MobilePushNotifications.php for the various - * types of push notifications sent by our API. - */ -export default { - REPORT_COMMENT: 'reportComment', -}; diff --git a/src/libs/Notification/PushNotification/NotificationType.ts b/src/libs/Notification/PushNotification/NotificationType.ts new file mode 100644 index 000000000000..91eec6895394 --- /dev/null +++ b/src/libs/Notification/PushNotification/NotificationType.ts @@ -0,0 +1,28 @@ +import {OnyxServerUpdate} from '@src/types/onyx/OnyxUpdatesFromServer'; + +const NotificationType = { + REPORT_COMMENT: 'reportComment', +} as const; + +type NotificationDataMap = { + [NotificationType.REPORT_COMMENT]: ReportCommentNotificationData; +}; + +type NotificationData = ReportCommentNotificationData; + +type ReportCommentNotificationData = { + title: string; + type: typeof NotificationType.REPORT_COMMENT; + reportID: number; + reportActionID: string; + shouldScrollToLastUnread?: boolean; + roomName?: string; + onyxData?: OnyxServerUpdate[]; +}; + +/** + * See https://github.com/Expensify/Web-Expensify/blob/main/lib/MobilePushNotifications.php for the various + * types of push notifications sent by our API. + */ +export default NotificationType; +export type {NotificationDataMap, NotificationData, ReportCommentNotificationData}; diff --git a/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js b/src/libs/Notification/PushNotification/backgroundRefresh/index.android.ts similarity index 86% rename from src/libs/Notification/PushNotification/backgroundRefresh/index.android.js rename to src/libs/Notification/PushNotification/backgroundRefresh/index.android.ts index 4502011b459e..2b3c6ebf21b4 100644 --- a/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js +++ b/src/libs/Notification/PushNotification/backgroundRefresh/index.android.ts @@ -4,8 +4,9 @@ import Visibility from '@libs/Visibility'; import * as App from '@userActions/App'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import BackgroundRefresh from './types'; -function getLastOnyxUpdateID() { +function getLastOnyxUpdateID(): Promise { return new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, @@ -23,7 +24,7 @@ function getLastOnyxUpdateID() { * We use this to refresh the app in the background after receiving a push notification (native only). Since the full app * wakes on iOS and by extension runs reconnectApp already, this is a no-op on everything but Android. */ -export default function backgroundRefresh() { +const backgroundRefresh: BackgroundRefresh = () => { if (Visibility.isVisible()) { return; } @@ -38,9 +39,11 @@ export default function backgroundRefresh() { * See more here: https://reactnative.dev/docs/headless-js-android */ App.confirmReadyToOpenApp(); - App.reconnectApp(lastUpdateIDAppliedToClient); + App.reconnectApp(lastUpdateIDAppliedToClient ?? undefined); }) .catch((error) => { Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} [PushNotification] backgroundRefresh failed. This should never happen.`, {error}); }); -} +}; + +export default backgroundRefresh; diff --git a/src/libs/Notification/PushNotification/backgroundRefresh/index.js b/src/libs/Notification/PushNotification/backgroundRefresh/index.ts similarity index 69% rename from src/libs/Notification/PushNotification/backgroundRefresh/index.js rename to src/libs/Notification/PushNotification/backgroundRefresh/index.ts index 657fb15ee429..c7f47a532d89 100644 --- a/src/libs/Notification/PushNotification/backgroundRefresh/index.js +++ b/src/libs/Notification/PushNotification/backgroundRefresh/index.ts @@ -1,7 +1,11 @@ +import BackgroundRefresh from './types'; + /** * Runs our reconnectApp action if the app is in the background. * * We use this to refresh the app in the background after receiving a push notification (native only). Since the full app * wakes on iOS and by extension runs reconnectApp already, this is a no-op on everything but Android. */ -export default function backgroundRefresh() {} +const backgroundRefresh: BackgroundRefresh = () => {}; + +export default backgroundRefresh; diff --git a/src/libs/Notification/PushNotification/backgroundRefresh/types.ts b/src/libs/Notification/PushNotification/backgroundRefresh/types.ts new file mode 100644 index 000000000000..d3d1ee44a1fd --- /dev/null +++ b/src/libs/Notification/PushNotification/backgroundRefresh/types.ts @@ -0,0 +1,3 @@ +type BackgroundRefresh = () => void; + +export default BackgroundRefresh; diff --git a/src/libs/Notification/PushNotification/index.native.js b/src/libs/Notification/PushNotification/index.native.ts similarity index 57% rename from src/libs/Notification/PushNotification/index.native.js rename to src/libs/Notification/PushNotification/index.native.ts index 8513a88e46d3..7b2571eea368 100644 --- a/src/libs/Notification/PushNotification/index.native.js +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -1,57 +1,59 @@ -import Airship, {EventType} from '@ua/react-native-airship'; -import lodashGet from 'lodash/get'; +import Airship, {EventType, PushPayload} from '@ua/react-native-airship'; import Onyx from 'react-native-onyx'; -import _ from 'underscore'; import Log from '@libs/Log'; -import * as PushNotification from '@userActions/PushNotification'; +import * as PushNotificationActions from '@userActions/PushNotification'; import ONYXKEYS from '@src/ONYXKEYS'; import ForegroundNotifications from './ForegroundNotifications'; -import NotificationType from './NotificationType'; +import NotificationType, {NotificationData} from './NotificationType'; +import PushNotificationType, {ClearNotifications, Deregister, Init, OnReceived, OnSelected, Register} from './types'; + +type NotificationEventActionCallback = (data: NotificationData) => void; + +type NotificationEventActionMap = Partial>>; let isUserOptedInToPushNotifications = false; Onyx.connect({ key: ONYXKEYS.PUSH_NOTIFICATIONS_ENABLED, - callback: (val) => (isUserOptedInToPushNotifications = val), + callback: (value) => (isUserOptedInToPushNotifications = value ?? false), }); -const notificationEventActionMap = {}; +const notificationEventActionMap: NotificationEventActionMap = {}; /** * Handle a push notification event, and trigger and bound actions. - * - * @param {String} eventType - * @param {Object} notification */ -function pushNotificationEventCallback(eventType, notification) { - const actionMap = notificationEventActionMap[eventType] || {}; - let payload = lodashGet(notification, 'extras.payload'); +function pushNotificationEventCallback(eventType: EventType, notification: PushPayload) { + const actionMap = notificationEventActionMap[eventType] ?? {}; + let payload = notification.extras.payload; // On Android, some notification payloads are sent as a JSON string rather than an object - if (_.isString(payload)) { + if (typeof payload === 'string') { payload = JSON.parse(payload); } + const data = payload as NotificationData; + Log.info(`[PushNotification] Callback triggered for ${eventType}`); - if (!payload) { + if (!data) { Log.warn('[PushNotification] Notification has null or undefined payload, not executing any callback.'); return; } - if (!payload.type) { + if (!data.type) { Log.warn('[PushNotification] No type value provided in payload, not executing any callback.'); return; } - const action = actionMap[payload.type]; + const action = actionMap[data.type]; if (!action) { Log.warn('[PushNotification] No callback set up: ', { event: eventType, - notificationType: payload.type, + notificationType: data.type, }); return; } - action(payload); + action(data); } /** @@ -65,7 +67,7 @@ function refreshNotificationOptInStatus() { } Log.info('[PushNotification] Push notification opt-in status changed.', false, {isOptedIn}); - PushNotification.setPushNotificationOptInStatus(isOptedIn); + PushNotificationActions.setPushNotificationOptInStatus(isOptedIn); }); } @@ -76,12 +78,12 @@ function refreshNotificationOptInStatus() { * WARNING: Moving or changing this code could break Push Notification processing in non-obvious ways. * DO NOT ALTER UNLESS YOU KNOW WHAT YOU'RE DOING. See this PR for details: https://github.com/Expensify/App/pull/3877 */ -function init() { +const init: Init = () => { // Setup event listeners Airship.addListener(EventType.PushReceived, (notification) => { // By default, refresh notification opt-in status to true if we receive a notification if (!isUserOptedInToPushNotifications) { - PushNotification.setPushNotificationOptInStatus(true); + PushNotificationActions.setPushNotificationOptInStatus(true); } pushNotificationEventCallback(EventType.PushReceived, notification.pushPayload); @@ -97,47 +99,52 @@ function init() { Airship.addListener(EventType.NotificationOptInStatus, refreshNotificationOptInStatus); ForegroundNotifications.configureForegroundNotifications(); -} +}; /** * Register this device for push notifications for the given notificationID. - * - * @param {String|Number} notificationID */ -function register(notificationID) { - if (Airship.contact.getNamedUserId() === notificationID.toString()) { - // No need to register again for this notificationID. - return; - } - - // Get permissions to display push notifications (prompts user on iOS, but not Android) - Airship.push.enableUserNotifications().then((isEnabled) => { - if (isEnabled) { - return; - } - - Log.info('[PushNotification] User has disabled visible push notifications for this app.'); - }); - - // Register this device as a named user in AirshipAPI. - // Regardless of the user's opt-in status, we still want to receive silent push notifications. - Log.info(`[PushNotification] Subscribing to notifications`); - Airship.contact.identify(notificationID.toString()); - - // Refresh notification opt-in status NVP for the new user. - refreshNotificationOptInStatus(); -} +const register: Register = (notificationID) => { + Airship.contact + .getNamedUserId() + .then((userID) => { + if (userID === notificationID.toString()) { + // No need to register again for this notificationID. + return; + } + + // Get permissions to display push notifications (prompts user on iOS, but not Android) + Airship.push.enableUserNotifications().then((isEnabled) => { + if (isEnabled) { + return; + } + + Log.info('[PushNotification] User has disabled visible push notifications for this app.'); + }); + + // Register this device as a named user in AirshipAPI. + // Regardless of the user's opt-in status, we still want to receive silent push notifications. + Log.info(`[PushNotification] Subscribing to notifications`); + Airship.contact.identify(notificationID.toString()); + + // Refresh notification opt-in status NVP for the new user. + refreshNotificationOptInStatus(); + }) + .catch((error) => { + Log.warn('[PushNotification] Failed to register for push notifications! Reason: ', error); + }); +}; /** * Deregister this device from push notifications. */ -function deregister() { +const deregister: Deregister = () => { Log.info('[PushNotification] Unsubscribing from push notifications.'); Airship.contact.reset(); Airship.removeAllListeners(EventType.PushReceived); Airship.removeAllListeners(EventType.NotificationResponse); ForegroundNotifications.disableForegroundNotifications(); -} +}; /** * Bind a callback to a push notification of a given type. @@ -148,45 +155,41 @@ function deregister() { * if we attempt to bind two callbacks to the PushReceived event for reportComment notifications, * the second will overwrite the first. * - * @param {String} notificationType - * @param {Function} callback - * @param {String} [triggerEvent] - The event that should trigger this callback. Should be one of UrbanAirship.EventType + * @param triggerEvent - The event that should trigger this callback. Should be one of UrbanAirship.EventType */ -function bind(notificationType, callback, triggerEvent) { - if (!notificationEventActionMap[triggerEvent]) { - notificationEventActionMap[triggerEvent] = {}; +function bind(notificationType: string, callback: NotificationEventActionCallback, triggerEvent: EventType) { + let actionMap = notificationEventActionMap[triggerEvent]; + + if (!actionMap) { + actionMap = {}; } - notificationEventActionMap[triggerEvent][notificationType] = callback; + + actionMap[notificationType] = callback; + notificationEventActionMap[triggerEvent] = actionMap; } /** * Bind a callback to be executed when a push notification of a given type is received. - * - * @param {String} notificationType - * @param {Function} callback */ -function onReceived(notificationType, callback) { +const onReceived: OnReceived = (notificationType, callback) => { bind(notificationType, callback, EventType.PushReceived); -} +}; /** * Bind a callback to be executed when a push notification of a given type is tapped by the user. - * - * @param {String} notificationType - * @param {Function} callback */ -function onSelected(notificationType, callback) { +const onSelected: OnSelected = (notificationType, callback) => { bind(notificationType, callback, EventType.NotificationResponse); -} +}; /** * Clear all push notifications */ -function clearNotifications() { +const clearNotifications: ClearNotifications = () => { Airship.push.clearNotifications(); -} +}; -export default { +const PushNotification: PushNotificationType = { init, register, deregister, @@ -195,3 +198,5 @@ export default { TYPE: NotificationType, clearNotifications, }; + +export default PushNotification; diff --git a/src/libs/Notification/PushNotification/index.js b/src/libs/Notification/PushNotification/index.ts similarity index 71% rename from src/libs/Notification/PushNotification/index.js rename to src/libs/Notification/PushNotification/index.ts index 88136ff5dc72..1e5499d1fe7d 100644 --- a/src/libs/Notification/PushNotification/index.js +++ b/src/libs/Notification/PushNotification/index.ts @@ -1,7 +1,8 @@ import NotificationType from './NotificationType'; +import PushNotificationType from './types'; // Push notifications are only supported on mobile, so we'll just noop here -export default { +const PushNotification: PushNotificationType = { init: () => {}, register: () => {}, deregister: () => {}, @@ -10,3 +11,5 @@ export default { TYPE: NotificationType, clearNotifications: () => {}, }; + +export default PushNotification; diff --git a/src/libs/Notification/PushNotification/shouldShowPushNotification.js b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts similarity index 61% rename from src/libs/Notification/PushNotification/shouldShowPushNotification.js rename to src/libs/Notification/PushNotification/shouldShowPushNotification.ts index f25d452a77d5..46f99fcc9271 100644 --- a/src/libs/Notification/PushNotification/shouldShowPushNotification.js +++ b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts @@ -1,30 +1,31 @@ -import _ from 'underscore'; +import {PushPayload} from '@ua/react-native-airship'; import Log from '@libs/Log'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; import * as Report from '@userActions/Report'; +import {NotificationData} from './NotificationType'; /** * Returns whether the given Airship notification should be shown depending on the current state of the app - * @param {PushPayload} pushPayload - * @returns {Boolean} */ -export default function shouldShowPushNotification(pushPayload) { +export default function shouldShowPushNotification(pushPayload: PushPayload): boolean { Log.info('[PushNotification] push notification received', false, {pushPayload}); - let pushData = pushPayload.extras.payload; + let payload = pushPayload.extras.payload; // The payload is string encoded on Android - if (_.isString(pushData)) { - pushData = JSON.parse(pushData); + if (typeof payload === 'string') { + payload = JSON.parse(payload); } - if (!pushData.reportID) { + const data = payload as NotificationData; + + if (!data.reportID) { Log.info('[PushNotification] Not a report action notification. Showing notification'); return true; } - const reportAction = ReportActionUtils.getLatestReportActionFromOnyxData(pushData.onyxData); - const shouldShow = Report.shouldShowReportActionNotification(String(pushData.reportID), reportAction, true); + const reportAction = ReportActionUtils.getLatestReportActionFromOnyxData(data.onyxData ?? null); + const shouldShow = Report.shouldShowReportActionNotification(String(data.reportID), reportAction, true); Log.info(`[PushNotification] ${shouldShow ? 'Showing' : 'Not showing'} notification`); return shouldShow; } diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.js b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts similarity index 100% rename from src/libs/Notification/PushNotification/subscribePushNotification/index.js rename to src/libs/Notification/PushNotification/subscribePushNotification/index.ts diff --git a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.ts similarity index 86% rename from src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js rename to src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.ts index ede873f79c6e..547ecb1de5b2 100644 --- a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js +++ b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.ts @@ -12,7 +12,7 @@ import PushNotification from './index'; export default function subscribeToReportCommentPushNotifications() { PushNotification.onReceived(PushNotification.TYPE.REPORT_COMMENT, ({reportID, reportActionID, onyxData}) => { Log.info(`[PushNotification] received report comment notification in the ${Visibility.isVisible() ? 'foreground' : 'background'}`, false, {reportID, reportActionID}); - Onyx.update(onyxData); + Onyx.update(onyxData ?? []); backgroundRefresh(); }); @@ -33,9 +33,14 @@ export default function subscribeToReportCommentPushNotifications() { } Log.info('[PushNotification] onSelected() - Navigation is ready. Navigating...', false, {reportID, reportActionID}); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(String(reportID))); } catch (error) { - Log.alert('[PushNotification] onSelected() - failed', {reportID, reportActionID, error: error.message}); + let errorMessage = String(error); + if (error instanceof Error) { + errorMessage = error.message; + } + + Log.alert('[PushNotification] onSelected() - failed', {reportID, reportActionID, error: errorMessage}); } }); }); diff --git a/src/libs/Notification/PushNotification/types.ts b/src/libs/Notification/PushNotification/types.ts new file mode 100644 index 000000000000..f72ee1af887a --- /dev/null +++ b/src/libs/Notification/PushNotification/types.ts @@ -0,0 +1,22 @@ +import {ValueOf} from 'type-fest'; +import NotificationType, {NotificationDataMap} from './NotificationType'; + +type Init = () => void; +type Register = (notificationID: string | number) => void; +type Deregister = () => void; +type OnReceived = >(notificationType: T, callback: (data: NotificationDataMap[T]) => void) => void; +type OnSelected = >(notificationType: T, callback: (data: NotificationDataMap[T]) => void) => void; +type ClearNotifications = () => void; + +type PushNotification = { + init: Init; + register: Register; + deregister: Deregister; + onReceived: OnReceived; + onSelected: OnSelected; + TYPE: typeof NotificationType; + clearNotifications: ClearNotifications; +}; + +export default PushNotification; +export type {ClearNotifications, Deregister, Init, OnReceived, OnSelected, Register}; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 1233bcd5d707..6161fd2066ff 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1743,7 +1743,7 @@ function setIsComposerFullSize(reportID, isComposerFullSize) { /** * @param {String} reportID - * @param {Object} action the associated report action (optional) + * @param {Object|null} action the associated report action (optional) * @param {Boolean} isRemote whether or not this notification is a remote push notification * @returns {Boolean} */ diff --git a/src/types/onyx/OnyxUpdatesFromServer.ts b/src/types/onyx/OnyxUpdatesFromServer.ts index 50b1503b90bd..843d3ae86e46 100644 --- a/src/types/onyx/OnyxUpdatesFromServer.ts +++ b/src/types/onyx/OnyxUpdatesFromServer.ts @@ -2,9 +2,11 @@ import {OnyxUpdate} from 'react-native-onyx'; import Request from './Request'; import Response from './Response'; +type OnyxServerUpdate = OnyxUpdate & {shouldNotify?: boolean}; + type OnyxUpdateEvent = { eventType: string; - data: OnyxUpdate[]; + data: OnyxServerUpdate[]; }; type OnyxUpdatesFromServer = { @@ -16,4 +18,4 @@ type OnyxUpdatesFromServer = { updates?: OnyxUpdateEvent[]; }; -export type {OnyxUpdatesFromServer, OnyxUpdateEvent}; +export type {OnyxUpdatesFromServer, OnyxUpdateEvent, OnyxServerUpdate};