@parse/push-adapter 6.2.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -41
- package/package.json +19 -24
- package/src/APNS.js +323 -0
- package/src/EXPO.js +107 -0
- package/{lib → src}/FCM.js +147 -140
- package/{lib → src}/GCM.js +57 -85
- package/src/ParsePushAdapter.js +96 -0
- package/src/PushAdapterUtils.js +45 -0
- package/src/WEB.js +106 -0
- package/src/index.js +20 -0
- package/lib/APNS.js +0 -400
- package/lib/EXPO.js +0 -204
- package/lib/ParsePushAdapter.js +0 -167
- package/lib/PushAdapterUtils.js +0 -95
- package/lib/WEB.js +0 -204
- package/lib/index.js +0 -52
package/src/EXPO.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import Parse from 'parse';
|
|
4
|
+
import log from 'npmlog';
|
|
5
|
+
import { Expo } from 'expo-server-sdk';
|
|
6
|
+
|
|
7
|
+
const LOG_PREFIX = 'parse-server-push-adapter EXPO';
|
|
8
|
+
|
|
9
|
+
function expoResultToParseResponse(result) {
|
|
10
|
+
if (result.status === 'ok') {
|
|
11
|
+
return result;
|
|
12
|
+
} else {
|
|
13
|
+
// ParseServer looks for "error", and supports ceratin codes like 'NotRegistered' for
|
|
14
|
+
// cleanup. Expo returns slighyly different ones so changing to match what is expected
|
|
15
|
+
// This can be taken out if the responsibility gets moved to the adapter itself.
|
|
16
|
+
const error = result.message === 'DeviceNotRegistered' ?
|
|
17
|
+
'NotRegistered' : result.message;
|
|
18
|
+
return {
|
|
19
|
+
error,
|
|
20
|
+
...result
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class EXPO {
|
|
26
|
+
expo = undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Create a new EXPO push adapter. Based on Web Adapter.
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} args https://github.com/expo/expo-server-sdk-node / https://docs.expo.dev/push-notifications/sending-notifications/
|
|
31
|
+
*/
|
|
32
|
+
constructor(args) {
|
|
33
|
+
if (typeof args !== 'object') {
|
|
34
|
+
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED, 'EXPO Push Configuration is invalid');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.expo = new Expo(args)
|
|
38
|
+
this.options = args;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Send Expo push notification request.
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} data The data we need to send, the format is the same with api request body
|
|
45
|
+
* @param {Array} devices An array of devices
|
|
46
|
+
* @returns {Object} A promise which is resolved immediately
|
|
47
|
+
*/
|
|
48
|
+
async send(data, devices) {
|
|
49
|
+
const coreData = data && data.data;
|
|
50
|
+
|
|
51
|
+
if (!coreData || !devices || !Array.isArray(devices)) {
|
|
52
|
+
log.warn(LOG_PREFIX, 'invalid push payload');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const devicesMap = devices.reduce((memo, device) => {
|
|
56
|
+
memo[device.deviceToken] = device;
|
|
57
|
+
return memo;
|
|
58
|
+
}, {});
|
|
59
|
+
const deviceTokens = Object.keys(devicesMap);
|
|
60
|
+
|
|
61
|
+
const resolvers = [];
|
|
62
|
+
const promises = deviceTokens.map(() => new Promise(resolve => resolvers.push(resolve)));
|
|
63
|
+
let length = deviceTokens.length;
|
|
64
|
+
|
|
65
|
+
log.verbose(LOG_PREFIX, `sending to ${length} ${length > 1 ? 'devices' : 'device'}`);
|
|
66
|
+
|
|
67
|
+
const response = await this.sendNotifications(coreData, deviceTokens);
|
|
68
|
+
|
|
69
|
+
log.verbose(LOG_PREFIX, `EXPO Response: %d sent`, response.length);
|
|
70
|
+
|
|
71
|
+
deviceTokens.forEach((token, index) => {
|
|
72
|
+
const resolve = resolvers[index];
|
|
73
|
+
const result = response[index];
|
|
74
|
+
const device = devicesMap[token];
|
|
75
|
+
const resolution = {
|
|
76
|
+
transmitted: result.status === 'ok',
|
|
77
|
+
device: {
|
|
78
|
+
...device,
|
|
79
|
+
pushType: 'expo'
|
|
80
|
+
},
|
|
81
|
+
response: expoResultToParseResponse(result),
|
|
82
|
+
};
|
|
83
|
+
resolve(resolution);
|
|
84
|
+
});
|
|
85
|
+
return Promise.all(promises);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Send multiple Expo push notification request.
|
|
90
|
+
*
|
|
91
|
+
* @param {Object} payload The data we need to send, the format is the same with api request body
|
|
92
|
+
* @param {Array} deviceTokens An array of devicesTokens
|
|
93
|
+
* @param {Object} options The options for the request
|
|
94
|
+
* @returns {Object} A promise which is resolved immediately
|
|
95
|
+
*/
|
|
96
|
+
async sendNotifications({alert, body, ...payload}, deviceTokens) {
|
|
97
|
+
const messages = deviceTokens.map((token) => ({
|
|
98
|
+
to: token,
|
|
99
|
+
body: body || alert,
|
|
100
|
+
...payload
|
|
101
|
+
}));
|
|
102
|
+
|
|
103
|
+
return await this.expo.sendPushNotificationsAsync(messages);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default EXPO;
|
package/{lib → src}/FCM.js
RENAMED
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
|
-
|
|
29
|
-
var LOG_PREFIX = 'parse-server-push-adapter FCM';
|
|
30
|
-
var FCMRegistrationTokensMax = 500;
|
|
31
|
-
var FCMTimeToLiveMax = 4 * 7 * 24 * 60 * 60; // FCM allows a max of 4 weeks
|
|
32
|
-
var apnsIntegerDataKeys = ['badge', 'content-available', 'mutable-content', 'priority', 'expiration_time'];
|
|
33
|
-
|
|
34
|
-
function FCM(args, pushType) {
|
|
35
|
-
if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) !== 'object' || !args.firebaseServiceAccount) {
|
|
36
|
-
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'FCM Configuration is invalid');
|
|
3
|
+
import Parse from 'parse';
|
|
4
|
+
import log from 'npmlog';
|
|
5
|
+
import { initializeApp, cert, getApps, getApp } from 'firebase-admin/app';
|
|
6
|
+
import { getMessaging } from 'firebase-admin/messaging';
|
|
7
|
+
import { randomString } from './PushAdapterUtils.js';
|
|
8
|
+
|
|
9
|
+
const LOG_PREFIX = 'parse-server-push-adapter FCM';
|
|
10
|
+
const FCMRegistrationTokensMax = 500;
|
|
11
|
+
const FCMTimeToLiveMax = 4 * 7 * 24 * 60 * 60; // FCM allows a max of 4 weeks
|
|
12
|
+
const apnsIntegerDataKeys = [
|
|
13
|
+
'badge',
|
|
14
|
+
'content-available',
|
|
15
|
+
'mutable-content',
|
|
16
|
+
'priority',
|
|
17
|
+
'expiration_time',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
export default function FCM(args, pushType) {
|
|
21
|
+
if (typeof args !== 'object' || !args.firebaseServiceAccount) {
|
|
22
|
+
throw new Parse.Error(
|
|
23
|
+
Parse.Error.PUSH_MISCONFIGURED,
|
|
24
|
+
'FCM Configuration is invalid',
|
|
25
|
+
);
|
|
37
26
|
}
|
|
38
27
|
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
app =
|
|
28
|
+
let app;
|
|
29
|
+
if (getApps().length === 0) {
|
|
30
|
+
app = initializeApp({ credential: cert(args.firebaseServiceAccount) });
|
|
42
31
|
} else {
|
|
43
|
-
app =
|
|
32
|
+
app = getApp();
|
|
44
33
|
}
|
|
45
|
-
this.sender =
|
|
34
|
+
this.sender = getMessaging(app);
|
|
46
35
|
this.pushType = pushType; // Push type is only used to remain backwards compatible with APNS and GCM
|
|
47
36
|
}
|
|
48
37
|
|
|
@@ -56,84 +45,111 @@ FCM.FCMRegistrationTokensMax = FCMRegistrationTokensMax;
|
|
|
56
45
|
*/
|
|
57
46
|
|
|
58
47
|
FCM.prototype.send = function (data, devices) {
|
|
59
|
-
var _this = this;
|
|
60
|
-
|
|
61
48
|
if (!data || !devices || !Array.isArray(devices)) {
|
|
62
|
-
|
|
49
|
+
log.warn(LOG_PREFIX, 'invalid push payload');
|
|
63
50
|
return;
|
|
64
51
|
}
|
|
65
52
|
|
|
66
53
|
// We can only have 500 recepients per send, so we need to slice devices to
|
|
67
54
|
// chunk if necessary
|
|
68
|
-
|
|
55
|
+
const slices = sliceDevices(devices, FCM.FCMRegistrationTokensMax);
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
const sendToDeviceSlice = (deviceSlice, pushType) => {
|
|
58
|
+
const pushId = randomString(10);
|
|
59
|
+
const timestamp = Date.now();
|
|
73
60
|
|
|
74
61
|
// Build a device map
|
|
75
|
-
|
|
62
|
+
const devicesMap = deviceSlice.reduce((memo, device) => {
|
|
76
63
|
memo[device.deviceToken] = device;
|
|
77
64
|
return memo;
|
|
78
65
|
}, {});
|
|
79
66
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
67
|
+
const deviceTokens = Object.keys(devicesMap);
|
|
68
|
+
|
|
69
|
+
const fcmPayload = generateFCMPayload(
|
|
70
|
+
data,
|
|
71
|
+
pushId,
|
|
72
|
+
timestamp,
|
|
73
|
+
deviceTokens,
|
|
74
|
+
pushType,
|
|
75
|
+
);
|
|
76
|
+
const length = deviceTokens.length;
|
|
77
|
+
log.info(LOG_PREFIX, `sending push to ${length} devices`);
|
|
78
|
+
|
|
79
|
+
return this.sender
|
|
80
|
+
.sendEachForMulticast(fcmPayload.data)
|
|
81
|
+
.then((response) => {
|
|
82
|
+
const promises = [];
|
|
83
|
+
const failedTokens = [];
|
|
84
|
+
const successfulTokens = [];
|
|
85
|
+
|
|
86
|
+
response.responses.forEach((resp, idx) => {
|
|
87
|
+
if (resp.success) {
|
|
88
|
+
successfulTokens.push(deviceTokens[idx]);
|
|
89
|
+
promises.push(
|
|
90
|
+
createSuccessfulPromise(
|
|
91
|
+
deviceTokens[idx],
|
|
92
|
+
devicesMap[deviceTokens[idx]].deviceType,
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
failedTokens.push(deviceTokens[idx]);
|
|
97
|
+
promises.push(
|
|
98
|
+
createErrorPromise(
|
|
99
|
+
deviceTokens[idx],
|
|
100
|
+
devicesMap[deviceTokens[idx]].deviceType,
|
|
101
|
+
resp.error,
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
log.error(
|
|
105
|
+
LOG_PREFIX,
|
|
106
|
+
`failed to send to ${deviceTokens[idx]} with error: ${JSON.stringify(resp.error)}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (failedTokens.length) {
|
|
112
|
+
log.error(
|
|
113
|
+
LOG_PREFIX,
|
|
114
|
+
`tokens with failed pushes: ${JSON.stringify(failedTokens)}`,
|
|
115
|
+
);
|
|
99
116
|
}
|
|
100
|
-
});
|
|
101
117
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
118
|
+
if (successfulTokens.length) {
|
|
119
|
+
log.verbose(
|
|
120
|
+
LOG_PREFIX,
|
|
121
|
+
`tokens with successful pushes: ${JSON.stringify(successfulTokens)}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
109
124
|
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
return Promise.all(promises);
|
|
126
|
+
});
|
|
112
127
|
};
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
const allPromises = Promise.all(
|
|
130
|
+
slices.map((slice) => sendToDeviceSlice(slice, this.pushType)),
|
|
131
|
+
).catch((err) => {
|
|
132
|
+
log.error(LOG_PREFIX, `error sending push: ${err}`);
|
|
118
133
|
});
|
|
119
134
|
|
|
120
135
|
return allPromises;
|
|
121
136
|
};
|
|
122
137
|
|
|
123
138
|
function _APNSToFCMPayload(requestData) {
|
|
124
|
-
|
|
139
|
+
let coreData = requestData;
|
|
125
140
|
|
|
126
141
|
if (requestData.hasOwnProperty('data')) {
|
|
127
142
|
coreData = requestData.data;
|
|
128
143
|
}
|
|
129
144
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
let expirationTime =
|
|
146
|
+
requestData['expiration_time'] || coreData['expiration_time'];
|
|
147
|
+
let collapseId = requestData['collapse_id'] || coreData['collapse_id'];
|
|
148
|
+
let pushType = requestData['push_type'] || coreData['push_type'];
|
|
149
|
+
let priority = requestData['priority'] || coreData['priority'];
|
|
134
150
|
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
let apnsPayload = { apns: { payload: { aps: {} } } };
|
|
152
|
+
let headers = {};
|
|
137
153
|
|
|
138
154
|
// Set to alert by default if not set explicitly
|
|
139
155
|
headers['apns-push-type'] = 'alert';
|
|
@@ -156,13 +172,13 @@ function _APNSToFCMPayload(requestData) {
|
|
|
156
172
|
apnsPayload.apns.headers = headers;
|
|
157
173
|
}
|
|
158
174
|
|
|
159
|
-
for (
|
|
175
|
+
for (let key in coreData) {
|
|
160
176
|
switch (key) {
|
|
161
177
|
case 'aps':
|
|
162
178
|
apnsPayload['apns']['payload']['aps'] = coreData.aps;
|
|
163
179
|
break;
|
|
164
180
|
case 'alert':
|
|
165
|
-
if (
|
|
181
|
+
if (typeof coreData.alert == 'object') {
|
|
166
182
|
// When we receive a dictionary, use as is to remain
|
|
167
183
|
// compatible with how the APNS.js + node-apn work
|
|
168
184
|
apnsPayload['apns']['payload']['aps']['alert'] = coreData.alert;
|
|
@@ -188,16 +204,20 @@ function _APNSToFCMPayload(requestData) {
|
|
|
188
204
|
apnsPayload['apns']['payload']['aps']['sound'] = coreData.sound;
|
|
189
205
|
break;
|
|
190
206
|
case 'content-available':
|
|
191
|
-
apnsPayload['apns']['payload']['aps']['content-available'] =
|
|
207
|
+
apnsPayload['apns']['payload']['aps']['content-available'] =
|
|
208
|
+
coreData['content-available'];
|
|
192
209
|
break;
|
|
193
210
|
case 'mutable-content':
|
|
194
|
-
apnsPayload['apns']['payload']['aps']['mutable-content'] =
|
|
211
|
+
apnsPayload['apns']['payload']['aps']['mutable-content'] =
|
|
212
|
+
coreData['mutable-content'];
|
|
195
213
|
break;
|
|
196
214
|
case 'targetContentIdentifier':
|
|
197
|
-
apnsPayload['apns']['payload']['aps']['target-content-id'] =
|
|
215
|
+
apnsPayload['apns']['payload']['aps']['target-content-id'] =
|
|
216
|
+
coreData.targetContentIdentifier;
|
|
198
217
|
break;
|
|
199
218
|
case 'interruptionLevel':
|
|
200
|
-
apnsPayload['apns']['payload']['aps']['interruption-level'] =
|
|
219
|
+
apnsPayload['apns']['payload']['aps']['interruption-level'] =
|
|
220
|
+
coreData.interruptionLevel;
|
|
201
221
|
break;
|
|
202
222
|
case 'category':
|
|
203
223
|
apnsPayload['apns']['payload']['aps']['category'] = coreData.category;
|
|
@@ -205,8 +225,7 @@ function _APNSToFCMPayload(requestData) {
|
|
|
205
225
|
case 'threadId':
|
|
206
226
|
apnsPayload['apns']['payload']['aps']['thread-id'] = coreData.threadId;
|
|
207
227
|
break;
|
|
208
|
-
case 'expiration_time':
|
|
209
|
-
// Exclude header-related fields as these are set above
|
|
228
|
+
case 'expiration_time': // Exclude header-related fields as these are set above
|
|
210
229
|
break;
|
|
211
230
|
case 'collapse_id':
|
|
212
231
|
break;
|
|
@@ -224,10 +243,10 @@ function _APNSToFCMPayload(requestData) {
|
|
|
224
243
|
|
|
225
244
|
function _GCMToFCMPayload(requestData, pushId, timeStamp) {
|
|
226
245
|
|
|
227
|
-
|
|
246
|
+
const androidPayload = {
|
|
228
247
|
android: {
|
|
229
|
-
priority: 'high'
|
|
230
|
-
}
|
|
248
|
+
priority: 'high',
|
|
249
|
+
},
|
|
231
250
|
};
|
|
232
251
|
|
|
233
252
|
if (requestData.hasOwnProperty('notification')) {
|
|
@@ -236,44 +255,22 @@ function _GCMToFCMPayload(requestData, pushId, timeStamp) {
|
|
|
236
255
|
|
|
237
256
|
if (requestData.hasOwnProperty('data')) {
|
|
238
257
|
// FCM gives an error on send if we have apns keys that should have integer values
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
for (var _iterator = apnsIntegerDataKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
245
|
-
var key = _step.value;
|
|
246
|
-
|
|
247
|
-
if (requestData.data.hasOwnProperty(key)) {
|
|
248
|
-
delete requestData.data[key];
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} catch (err) {
|
|
252
|
-
_didIteratorError = true;
|
|
253
|
-
_iteratorError = err;
|
|
254
|
-
} finally {
|
|
255
|
-
try {
|
|
256
|
-
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
257
|
-
_iterator.return();
|
|
258
|
-
}
|
|
259
|
-
} finally {
|
|
260
|
-
if (_didIteratorError) {
|
|
261
|
-
throw _iteratorError;
|
|
262
|
-
}
|
|
258
|
+
for (const key of apnsIntegerDataKeys) {
|
|
259
|
+
if (requestData.data.hasOwnProperty(key)) {
|
|
260
|
+
delete requestData.data[key]
|
|
263
261
|
}
|
|
264
262
|
}
|
|
265
|
-
|
|
266
263
|
androidPayload.android.data = {
|
|
267
264
|
push_id: pushId,
|
|
268
265
|
time: new Date(timeStamp).toISOString(),
|
|
269
|
-
data: JSON.stringify(requestData.data)
|
|
270
|
-
}
|
|
266
|
+
data: JSON.stringify(requestData.data),
|
|
267
|
+
}
|
|
271
268
|
}
|
|
272
269
|
|
|
273
270
|
if (requestData['expiration_time']) {
|
|
274
|
-
|
|
271
|
+
const expirationTime = requestData['expiration_time'];
|
|
275
272
|
// Convert to seconds
|
|
276
|
-
|
|
273
|
+
let timeToLive = Math.floor((expirationTime - timeStamp) / 1000);
|
|
277
274
|
if (timeToLive < 0) {
|
|
278
275
|
timeToLive = 0;
|
|
279
276
|
}
|
|
@@ -307,7 +304,10 @@ function payloadConverter(requestData, pushType, pushId, timeStamp) {
|
|
|
307
304
|
} else if (pushType === 'android') {
|
|
308
305
|
return _GCMToFCMPayload(requestData, pushId, timeStamp);
|
|
309
306
|
} else {
|
|
310
|
-
throw new
|
|
307
|
+
throw new Parse.Error(
|
|
308
|
+
Parse.Error.PUSH_MISCONFIGURED,
|
|
309
|
+
'Unsupported push type, apple or android only.',
|
|
310
|
+
);
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
|
|
@@ -320,17 +320,24 @@ function payloadConverter(requestData, pushType, pushId, timeStamp) {
|
|
|
320
320
|
* @param {String} pushType Either apple or android
|
|
321
321
|
* @returns {Object} A payload for FCM
|
|
322
322
|
*/
|
|
323
|
-
function generateFCMPayload(
|
|
323
|
+
function generateFCMPayload(
|
|
324
|
+
requestData,
|
|
325
|
+
pushId,
|
|
326
|
+
timeStamp,
|
|
327
|
+
deviceTokens,
|
|
328
|
+
pushType,
|
|
329
|
+
) {
|
|
324
330
|
delete requestData['where'];
|
|
325
331
|
|
|
326
|
-
|
|
332
|
+
const payloadToUse = {
|
|
327
333
|
data: {}
|
|
328
334
|
};
|
|
329
335
|
|
|
330
|
-
|
|
331
|
-
payloadToUse.data =
|
|
332
|
-
|
|
333
|
-
|
|
336
|
+
const fcmPayload = payloadConverter(requestData, pushType, pushId, timeStamp);
|
|
337
|
+
payloadToUse.data = {
|
|
338
|
+
...fcmPayload,
|
|
339
|
+
tokens: deviceTokens,
|
|
340
|
+
};
|
|
334
341
|
|
|
335
342
|
return payloadToUse;
|
|
336
343
|
}
|
|
@@ -342,7 +349,7 @@ function generateFCMPayload(requestData, pushId, timeStamp, deviceTokens, pushTy
|
|
|
342
349
|
* @returns {Array} An array which contains several arrays of devices with fixed chunk size
|
|
343
350
|
*/
|
|
344
351
|
function sliceDevices(devices, chunkSize) {
|
|
345
|
-
|
|
352
|
+
const chunkDevices = [];
|
|
346
353
|
while (devices.length > 0) {
|
|
347
354
|
chunkDevices.push(devices.splice(0, chunkSize));
|
|
348
355
|
}
|
|
@@ -361,9 +368,9 @@ function createErrorPromise(token, deviceType, errorMessage) {
|
|
|
361
368
|
transmitted: false,
|
|
362
369
|
device: {
|
|
363
370
|
deviceToken: token,
|
|
364
|
-
deviceType: deviceType
|
|
371
|
+
deviceType: deviceType,
|
|
365
372
|
},
|
|
366
|
-
response: { error: errorMessage }
|
|
373
|
+
response: { error: errorMessage },
|
|
367
374
|
});
|
|
368
375
|
}
|
|
369
376
|
|
|
@@ -378,8 +385,8 @@ function createSuccessfulPromise(token, deviceType) {
|
|
|
378
385
|
transmitted: true,
|
|
379
386
|
device: {
|
|
380
387
|
deviceToken: token,
|
|
381
|
-
deviceType: deviceType
|
|
382
|
-
}
|
|
388
|
+
deviceType: deviceType,
|
|
389
|
+
},
|
|
383
390
|
});
|
|
384
391
|
}
|
|
385
392
|
|
|
@@ -388,4 +395,4 @@ FCM.generateFCMPayload = generateFCMPayload;
|
|
|
388
395
|
/* istanbul ignore else */
|
|
389
396
|
if (process.env.TESTING) {
|
|
390
397
|
FCM.sliceDevices = sliceDevices;
|
|
391
|
-
}
|
|
398
|
+
}
|