diff --git a/keyserver/src/push/utils.js b/keyserver/src/push/utils.js --- a/keyserver/src/push/utils.js +++ b/keyserver/src/push/utils.js @@ -67,16 +67,13 @@ }), ); - const mergedResults = { sent: [], failed: [] }; + const errors: Array = []; for (const result of results) { - mergedResults.sent.push(...result.sent); - mergedResults.failed.push(...result.failed); + errors.push(...result.failed); } - const errors = []; - const invalidTokens = []; - for (const error of mergedResults.failed) { - errors.push(error); + const invalidTokens: Array = []; + for (const error of errors) { /* eslint-disable eqeqeq */ if ( error.status == apnTokenInvalidationErrorCode || @@ -96,12 +93,13 @@ } } -type FCMPushResult = { - +success?: true, - +fcmIDs?: $ReadOnlyArray, - +errors?: $ReadOnlyArray, - +invalidTokens?: $ReadOnlyArray, +type WritableFCMPushResult = { + success?: true, + fcmIDs?: $ReadOnlyArray, + errors?: $ReadOnlyArray, + invalidTokens?: $ReadOnlyArray, }; +export type FCMPushResult = $ReadOnly; async function fcmPush({ targetedNotifications, collapseKey, @@ -129,22 +127,28 @@ // multicast messages and one of the device tokens is invalid, the resultant // won't explain which of the device tokens is invalid. So we're forced to // avoid the multicast functionality and call it once per deviceToken. - const promises = []; - for (const { notification, deviceToken } of targetedNotifications) { - promises.push( - fcmSinglePush(fcmProvider, notification, deviceToken, options), - ); - } - const pushResults = await Promise.all(promises); + const results = await Promise.all( + targetedNotifications.map(({ notification, deviceToken }) => { + return fcmSinglePush(fcmProvider, notification, deviceToken, options); + }), + ); const errors = []; const ids = []; const invalidTokens = []; - for (let i = 0; i < pushResults.length; i++) { - const pushResult = pushResults[i]; + for (let i = 0; i < results.length; i++) { + const pushResult = results[i]; for (const error of pushResult.errors) { errors.push(error); - if (fcmTokenInvalidationErrors.has(error.errorInfo.code)) { + const errorCode = + error && + typeof error === 'object' && + error.errorInfo && + typeof error.errorInfo === 'object' && + typeof error.errorInfo.code === 'string' + ? error.errorInfo.code + : undefined; + if (errorCode && fcmTokenInvalidationErrors.has(errorCode)) { invalidTokens.push(targetedNotifications[i].deviceToken); } } @@ -153,7 +157,7 @@ } } - const result = {}; + const result: WritableFCMPushResult = {}; if (ids.length > 0) { result.fcmIDs = ids; } @@ -165,15 +169,19 @@ if (invalidTokens.length > 0) { result.invalidTokens = invalidTokens; } - return { ...result }; + return result; } +type FCMSinglePushResult = { + +fcmIDs: $ReadOnlyArray, + +errors: $ReadOnlyArray, +}; async function fcmSinglePush( provider: FirebaseApp, notification: Object, deviceToken: string, options: Object, -) { +): Promise { try { const deliveryResult = await provider .messaging() @@ -208,7 +216,7 @@ GROUP BY user `; const [result] = await dbQuery(query); - const usersToUnreadCounts = {}; + const usersToUnreadCounts: { [string]: number } = {}; for (const row of result) { usersToUnreadCounts[row.user.toString()] = row.unread_count; } @@ -225,10 +233,14 @@ +headers: { +[string]: string }, +body: string, }; -type WebPushResult = { - +success?: true, - +errors?: $ReadOnlyArray, - +invalidTokens?: $ReadOnlyArray, +type WritableWebPushResult = { + success?: true, + errors?: $ReadOnlyArray, + invalidTokens?: $ReadOnlyArray, +}; +type WebPushResult = $ReadOnly; +type WebPushAttempt = { + +error?: WebPushError, }; async function webPush({ notification, @@ -240,8 +252,8 @@ await ensureWebPushInitialized(); const notificationString = JSON.stringify(notification); - const pushResults = await Promise.all( - deviceTokens.map(async deviceTokenString => { + const pushResults: $ReadOnlyArray = await Promise.all( + deviceTokens.map(async (deviceTokenString): Promise => { const deviceToken: PushSubscriptionJSON = JSON.parse(deviceTokenString); try { await webpush.sendNotification(deviceToken, notificationString); @@ -256,15 +268,16 @@ const invalidTokens = []; for (let i = 0; i < pushResults.length; i++) { const pushResult = pushResults[i]; - if (pushResult.error) { - errors.push(pushResult.error); - if (webInvalidTokenErrorCodes.includes(pushResult.error.statusCode)) { + const { error } = pushResult; + if (error) { + errors.push(error); + if (webInvalidTokenErrorCodes.includes(error.statusCode)) { invalidTokens.push(deviceTokens[i]); } } } - const result = {}; + const result: WritableWebPushResult = {}; if (errors.length > 0) { result.errors = errors; } else { @@ -273,16 +286,17 @@ if (invalidTokens.length > 0) { result.invalidTokens = invalidTokens; } - return { ...result }; + return result; } export type WNSPushError = any | string | Response; -type WNSPushResult = { - +success?: true, - +wnsIDs?: $ReadOnlyArray, - +errors?: $ReadOnlyArray, - +invalidTokens?: $ReadOnlyArray, +type WritableWNSPushResult = { + success?: true, + wnsIDs?: $ReadOnlyArray, + errors?: $ReadOnlyArray, + invalidTokens?: $ReadOnlyArray, }; +type WNSPushResult = $ReadOnly; async function wnsPush({ notification, deviceTokens, @@ -325,7 +339,7 @@ } } - const result = {}; + const result: WritableWNSPushResult = {}; if (notifIDs.length > 0) { result.wnsIDs = notifIDs; } @@ -337,7 +351,7 @@ if (invalidTokens.length > 0) { result.invalidTokens = invalidTokens; } - return { ...result }; + return result; } async function wnsSinglePush(token: string, notification: string, url: string) {