@parse/push-adapter 6.0.0 → 6.1.1
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 +3 -0
- package/lib/FCM.js +22 -13
- package/lib/ParsePushAdapter.js +8 -1
- package/lib/WEB.js +204 -0
- package/lib/index.js +8 -3
- package/package.json +4 -3
package/README.md
CHANGED
package/lib/FCM.js
CHANGED
|
@@ -162,15 +162,20 @@ function _APNSToFCMPayload(requestData) {
|
|
|
162
162
|
apnsPayload['apns']['payload']['aps'] = coreData.aps;
|
|
163
163
|
break;
|
|
164
164
|
case 'alert':
|
|
165
|
-
if (
|
|
165
|
+
if (_typeof(coreData.alert) == 'object') {
|
|
166
|
+
// When we receive a dictionary, use as is to remain
|
|
167
|
+
// compatible with how the APNS.js + node-apn work
|
|
168
|
+
apnsPayload['apns']['payload']['aps']['alert'] = coreData.alert;
|
|
169
|
+
} else {
|
|
170
|
+
// When we receive a value, prepare `alert` dictionary
|
|
171
|
+
// and set its `body` property
|
|
166
172
|
apnsPayload['apns']['payload']['aps']['alert'] = {};
|
|
173
|
+
apnsPayload['apns']['payload']['aps']['alert']['body'] = coreData.alert;
|
|
167
174
|
}
|
|
168
|
-
// In APNS.js we set a body with the same value as alert in requestData.
|
|
169
|
-
// See L200 in APNS.spec.js
|
|
170
|
-
apnsPayload['apns']['payload']['aps']['alert']['body'] = coreData.alert;
|
|
171
175
|
break;
|
|
172
176
|
case 'title':
|
|
173
177
|
// Ensure the alert object exists before trying to assign the title
|
|
178
|
+
// title always goes into the nested `alert` dictionary
|
|
174
179
|
if (!apnsPayload['apns']['payload']['aps'].hasOwnProperty('alert')) {
|
|
175
180
|
apnsPayload['apns']['payload']['aps']['alert'] = {};
|
|
176
181
|
}
|
|
@@ -217,7 +222,8 @@ function _APNSToFCMPayload(requestData) {
|
|
|
217
222
|
return apnsPayload;
|
|
218
223
|
}
|
|
219
224
|
|
|
220
|
-
function _GCMToFCMPayload(requestData, timeStamp) {
|
|
225
|
+
function _GCMToFCMPayload(requestData, pushId, timeStamp) {
|
|
226
|
+
|
|
221
227
|
var androidPayload = {
|
|
222
228
|
android: {
|
|
223
229
|
priority: 'high'
|
|
@@ -257,7 +263,11 @@ function _GCMToFCMPayload(requestData, timeStamp) {
|
|
|
257
263
|
}
|
|
258
264
|
}
|
|
259
265
|
|
|
260
|
-
androidPayload.android.data =
|
|
266
|
+
androidPayload.android.data = {
|
|
267
|
+
push_id: pushId,
|
|
268
|
+
time: new Date(timeStamp).toISOString(),
|
|
269
|
+
data: JSON.stringify(requestData.data)
|
|
270
|
+
};
|
|
261
271
|
}
|
|
262
272
|
|
|
263
273
|
if (requestData['expiration_time']) {
|
|
@@ -283,10 +293,11 @@ function _GCMToFCMPayload(requestData, timeStamp) {
|
|
|
283
293
|
* If the key rawPayload is present in the requestData, a raw payload will be used. Otherwise, conversion is done.
|
|
284
294
|
* @param {Object} requestData The request body
|
|
285
295
|
* @param {String} pushType Either apple or android.
|
|
286
|
-
* @param {
|
|
296
|
+
* @param {String} pushId Used during GCM payload conversion, required by Parse Android SDK.
|
|
297
|
+
* @param {Number} timeStamp Used during GCM payload conversion for ttl, required by Parse Android SDK.
|
|
287
298
|
* @returns {Object} A FCMv1-compatible payload.
|
|
288
299
|
*/
|
|
289
|
-
function payloadConverter(requestData, pushType, timeStamp) {
|
|
300
|
+
function payloadConverter(requestData, pushType, pushId, timeStamp) {
|
|
290
301
|
if (requestData.hasOwnProperty('rawPayload')) {
|
|
291
302
|
return requestData.rawPayload;
|
|
292
303
|
}
|
|
@@ -294,7 +305,7 @@ function payloadConverter(requestData, pushType, timeStamp) {
|
|
|
294
305
|
if (pushType === 'apple') {
|
|
295
306
|
return _APNSToFCMPayload(requestData);
|
|
296
307
|
} else if (pushType === 'android') {
|
|
297
|
-
return _GCMToFCMPayload(requestData, timeStamp);
|
|
308
|
+
return _GCMToFCMPayload(requestData, pushId, timeStamp);
|
|
298
309
|
} else {
|
|
299
310
|
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'Unsupported push type, apple or android only.');
|
|
300
311
|
}
|
|
@@ -313,12 +324,10 @@ function generateFCMPayload(requestData, pushId, timeStamp, deviceTokens, pushTy
|
|
|
313
324
|
delete requestData['where'];
|
|
314
325
|
|
|
315
326
|
var payloadToUse = {
|
|
316
|
-
data: {}
|
|
317
|
-
push_id: pushId,
|
|
318
|
-
time: new Date(timeStamp).toISOString()
|
|
327
|
+
data: {}
|
|
319
328
|
};
|
|
320
329
|
|
|
321
|
-
var fcmPayload = payloadConverter(requestData, pushType, timeStamp);
|
|
330
|
+
var fcmPayload = payloadConverter(requestData, pushType, pushId, timeStamp);
|
|
322
331
|
payloadToUse.data = _extends({}, fcmPayload, {
|
|
323
332
|
tokens: deviceTokens
|
|
324
333
|
});
|
package/lib/ParsePushAdapter.js
CHANGED
|
@@ -26,6 +26,10 @@ var _FCM = require('./FCM');
|
|
|
26
26
|
|
|
27
27
|
var _FCM2 = _interopRequireDefault(_FCM);
|
|
28
28
|
|
|
29
|
+
var _WEB = require('./WEB');
|
|
30
|
+
|
|
31
|
+
var _WEB2 = _interopRequireDefault(_WEB);
|
|
32
|
+
|
|
29
33
|
var _PushAdapterUtils = require('./PushAdapterUtils');
|
|
30
34
|
|
|
31
35
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -42,7 +46,7 @@ var ParsePushAdapter = function () {
|
|
|
42
46
|
|
|
43
47
|
this.supportsPushTracking = true;
|
|
44
48
|
|
|
45
|
-
this.validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm'];
|
|
49
|
+
this.validPushTypes = ['ios', 'osx', 'tvos', 'android', 'fcm', 'web'];
|
|
46
50
|
this.senderMap = {};
|
|
47
51
|
// used in PushController for Dashboard Features
|
|
48
52
|
this.feature = {
|
|
@@ -72,6 +76,9 @@ var ParsePushAdapter = function () {
|
|
|
72
76
|
this.senderMap[pushType] = new _APNS2.default(pushConfig[pushType]);
|
|
73
77
|
}
|
|
74
78
|
break;
|
|
79
|
+
case 'web':
|
|
80
|
+
this.senderMap[pushType] = new _WEB2.default(pushConfig[pushType]);
|
|
81
|
+
break;
|
|
75
82
|
case 'android':
|
|
76
83
|
case 'fcm':
|
|
77
84
|
if (pushConfig[pushType].hasOwnProperty('firebaseServiceAccount')) {
|
package/lib/WEB.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.WEB = undefined;
|
|
7
|
+
|
|
8
|
+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
9
|
+
|
|
10
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
11
|
+
|
|
12
|
+
var _parse = require('parse');
|
|
13
|
+
|
|
14
|
+
var _parse2 = _interopRequireDefault(_parse);
|
|
15
|
+
|
|
16
|
+
var _npmlog = require('npmlog');
|
|
17
|
+
|
|
18
|
+
var _npmlog2 = _interopRequireDefault(_npmlog);
|
|
19
|
+
|
|
20
|
+
var _webPush = require('web-push');
|
|
21
|
+
|
|
22
|
+
var _webPush2 = _interopRequireDefault(_webPush);
|
|
23
|
+
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
|
|
26
|
+
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
|
27
|
+
|
|
28
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
29
|
+
|
|
30
|
+
var LOG_PREFIX = 'parse-server-push-adapter WEB';
|
|
31
|
+
|
|
32
|
+
var WEB = exports.WEB = function () {
|
|
33
|
+
/**
|
|
34
|
+
* Create a new WEB push adapter.
|
|
35
|
+
*
|
|
36
|
+
* @param {Object} args https://github.com/web-push-libs/web-push#api-reference
|
|
37
|
+
*/
|
|
38
|
+
function WEB(args) {
|
|
39
|
+
_classCallCheck(this, WEB);
|
|
40
|
+
|
|
41
|
+
if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) !== 'object' || !args.vapidDetails) {
|
|
42
|
+
throw new _parse2.default.Error(_parse2.default.Error.PUSH_MISCONFIGURED, 'WEB Push Configuration is invalid');
|
|
43
|
+
}
|
|
44
|
+
this.options = args;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Send web push notification request.
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} data The data we need to send, the format is the same with api request body
|
|
51
|
+
* @param {Array} devices An array of devices
|
|
52
|
+
* @returns {Object} A promise which is resolved immediately
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_createClass(WEB, [{
|
|
57
|
+
key: 'send',
|
|
58
|
+
value: function () {
|
|
59
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(data, devices) {
|
|
60
|
+
var coreData, devicesMap, deviceTokens, resolvers, promises, length, response, results, sent, failed;
|
|
61
|
+
return regeneratorRuntime.wrap(function _callee$(_context) {
|
|
62
|
+
while (1) {
|
|
63
|
+
switch (_context.prev = _context.next) {
|
|
64
|
+
case 0:
|
|
65
|
+
coreData = data && data.data;
|
|
66
|
+
|
|
67
|
+
if (!(!coreData || !devices || !Array.isArray(devices))) {
|
|
68
|
+
_context.next = 4;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_npmlog2.default.warn(LOG_PREFIX, 'invalid push payload');
|
|
73
|
+
return _context.abrupt('return');
|
|
74
|
+
|
|
75
|
+
case 4:
|
|
76
|
+
devicesMap = devices.reduce(function (memo, device) {
|
|
77
|
+
memo[device.deviceToken] = device;
|
|
78
|
+
return memo;
|
|
79
|
+
}, {});
|
|
80
|
+
deviceTokens = Object.keys(devicesMap);
|
|
81
|
+
resolvers = [];
|
|
82
|
+
promises = deviceTokens.map(function () {
|
|
83
|
+
return new Promise(function (resolve) {
|
|
84
|
+
return resolvers.push(resolve);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
length = deviceTokens.length;
|
|
88
|
+
|
|
89
|
+
_npmlog2.default.verbose(LOG_PREFIX, 'sending to ' + length + ' ' + (length > 1 ? 'devices' : 'device'));
|
|
90
|
+
|
|
91
|
+
_context.next = 12;
|
|
92
|
+
return WEB.sendNotifications(coreData, deviceTokens, this.options);
|
|
93
|
+
|
|
94
|
+
case 12:
|
|
95
|
+
response = _context.sent;
|
|
96
|
+
results = response.results, sent = response.sent, failed = response.failed;
|
|
97
|
+
|
|
98
|
+
if (sent) {
|
|
99
|
+
_npmlog2.default.verbose(LOG_PREFIX, 'WEB Response: %d out of %d sent successfully', sent, results.length);
|
|
100
|
+
}
|
|
101
|
+
if (failed) {
|
|
102
|
+
_npmlog2.default.error(LOG_PREFIX, 'send errored: %d out of %d failed with error %s', failed, results.length, 'push subscription has unsubscribed or expired.');
|
|
103
|
+
}
|
|
104
|
+
deviceTokens.forEach(function (token, index) {
|
|
105
|
+
var resolve = resolvers[index];
|
|
106
|
+
var _results$index = results[index],
|
|
107
|
+
result = _results$index.result,
|
|
108
|
+
error = _results$index.error;
|
|
109
|
+
|
|
110
|
+
var device = devicesMap[token];
|
|
111
|
+
device.deviceType = 'web';
|
|
112
|
+
var resolution = {
|
|
113
|
+
device: device,
|
|
114
|
+
response: error || result,
|
|
115
|
+
transmitted: !error
|
|
116
|
+
};
|
|
117
|
+
resolve(resolution);
|
|
118
|
+
});
|
|
119
|
+
return _context.abrupt('return', Promise.all(promises));
|
|
120
|
+
|
|
121
|
+
case 18:
|
|
122
|
+
case 'end':
|
|
123
|
+
return _context.stop();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}, _callee, this);
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
function send(_x, _x2) {
|
|
130
|
+
return _ref.apply(this, arguments);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return send;
|
|
134
|
+
}()
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Send multiple web push notification request.
|
|
138
|
+
*
|
|
139
|
+
* @param {Object} payload The data we need to send, the format is the same with api request body
|
|
140
|
+
* @param {Array} deviceTokens An array of devicesTokens
|
|
141
|
+
* @param {Object} options The options for the request
|
|
142
|
+
* @returns {Object} A promise which is resolved immediately
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
}], [{
|
|
146
|
+
key: 'sendNotifications',
|
|
147
|
+
value: function () {
|
|
148
|
+
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(payload, deviceTokens, options) {
|
|
149
|
+
var promises, allResults, response;
|
|
150
|
+
return regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
151
|
+
while (1) {
|
|
152
|
+
switch (_context2.prev = _context2.next) {
|
|
153
|
+
case 0:
|
|
154
|
+
promises = deviceTokens.map(function (deviceToken) {
|
|
155
|
+
if (typeof deviceToken === 'string') {
|
|
156
|
+
deviceToken = JSON.parse(deviceToken);
|
|
157
|
+
}
|
|
158
|
+
if ((typeof payload === 'undefined' ? 'undefined' : _typeof(payload)) === 'object') {
|
|
159
|
+
payload = JSON.stringify(payload);
|
|
160
|
+
}
|
|
161
|
+
return _webPush2.default.sendNotification(deviceToken, payload, options);
|
|
162
|
+
});
|
|
163
|
+
_context2.next = 3;
|
|
164
|
+
return Promise.allSettled(promises);
|
|
165
|
+
|
|
166
|
+
case 3:
|
|
167
|
+
allResults = _context2.sent;
|
|
168
|
+
response = {
|
|
169
|
+
sent: 0,
|
|
170
|
+
failed: 0,
|
|
171
|
+
results: []
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
allResults.forEach(function (result) {
|
|
175
|
+
if (result.status === 'fulfilled') {
|
|
176
|
+
response.sent += 1;
|
|
177
|
+
response.results.push({ result: result.value.statusCode });
|
|
178
|
+
} else {
|
|
179
|
+
response.failed += 1;
|
|
180
|
+
response.results.push({ error: result.reason.body });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return _context2.abrupt('return', response);
|
|
184
|
+
|
|
185
|
+
case 7:
|
|
186
|
+
case 'end':
|
|
187
|
+
return _context2.stop();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}, _callee2, this);
|
|
191
|
+
}));
|
|
192
|
+
|
|
193
|
+
function sendNotifications(_x3, _x4, _x5) {
|
|
194
|
+
return _ref2.apply(this, arguments);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return sendNotifications;
|
|
198
|
+
}()
|
|
199
|
+
}]);
|
|
200
|
+
|
|
201
|
+
return WEB;
|
|
202
|
+
}();
|
|
203
|
+
|
|
204
|
+
exports.default = WEB;
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ParsePushAdapter is the default implementation of
|
|
3
|
-
// PushAdapter, it uses GCM for android push
|
|
4
|
-
// for
|
|
3
|
+
// PushAdapter, it uses GCM for android push, APNS for ios push.
|
|
4
|
+
// WEB for web push.
|
|
5
5
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", {
|
|
7
7
|
value: true
|
|
8
8
|
});
|
|
9
|
-
exports.utils = exports.GCM = exports.APNS = exports.ParsePushAdapter = undefined;
|
|
9
|
+
exports.utils = exports.WEB = exports.GCM = exports.APNS = exports.ParsePushAdapter = undefined;
|
|
10
10
|
|
|
11
11
|
var _npmlog = require('npmlog');
|
|
12
12
|
|
|
@@ -24,6 +24,10 @@ var _APNS = require('./APNS');
|
|
|
24
24
|
|
|
25
25
|
var _APNS2 = _interopRequireDefault(_APNS);
|
|
26
26
|
|
|
27
|
+
var _WEB = require('./WEB');
|
|
28
|
+
|
|
29
|
+
var _WEB2 = _interopRequireDefault(_WEB);
|
|
30
|
+
|
|
27
31
|
var _PushAdapterUtils = require('./PushAdapterUtils');
|
|
28
32
|
|
|
29
33
|
var utils = _interopRequireWildcard(_PushAdapterUtils);
|
|
@@ -39,4 +43,5 @@ if (process.env.VERBOSE || process.env.VERBOSE_PARSE_SERVER_PUSH_ADAPTER) {
|
|
|
39
43
|
exports.ParsePushAdapter = _ParsePushAdapter2.default;
|
|
40
44
|
exports.APNS = _APNS2.default;
|
|
41
45
|
exports.GCM = _GCM2.default;
|
|
46
|
+
exports.WEB = _WEB2.default;
|
|
42
47
|
exports.utils = utils;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parse/push-adapter",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.1",
|
|
4
4
|
"description": "Base parse-server-push-adapter",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@parse/node-apn": "6.0.1",
|
|
27
27
|
"@parse/node-gcm": "1.0.2",
|
|
28
|
-
"firebase-admin": "12.
|
|
28
|
+
"firebase-admin": "12.1.0",
|
|
29
29
|
"npmlog": "7.0.1",
|
|
30
|
-
"parse": "5.0.0"
|
|
30
|
+
"parse": "5.0.0",
|
|
31
|
+
"web-push": "3.6.7"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@semantic-release/changelog": "5.0.1",
|