firebase-admin 4.1.2 → 4.2.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 +0 -1
- package/lib/auth/auth-api-request.js +2 -2
- package/lib/auth/auth.js +1 -1
- package/lib/auth/credential.js +25 -16
- package/lib/auth/register-auth.js +1 -1
- package/lib/auth/token-generator.js +7 -8
- package/lib/auth/user-record.js +31 -149
- package/lib/database/database.js +81 -81
- package/lib/default-namespace.js +1 -1
- package/lib/firebase-app.js +84 -43
- package/lib/firebase-namespace.js +19 -14
- package/lib/firebase-service.js +1 -1
- package/lib/index.d.ts +76 -53
- package/lib/index.js +1 -1
- package/lib/messaging/messaging-api-request.js +10 -7
- package/lib/messaging/messaging.js +201 -42
- package/lib/messaging/register-messaging.js +1 -1
- package/lib/utils/api-request.js +5 -22
- package/lib/utils/deep-copy.js +1 -1
- package/lib/utils/error.js +62 -8
- package/lib/utils/index.js +22 -3
- package/lib/utils/validator.js +22 -2
- package/npm-shrinkwrap.json +7 -7
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -7,14 +7,12 @@ var api_request_1 = require("../utils/api-request");
|
|
|
7
7
|
var error_2 = require("../utils/error");
|
|
8
8
|
var validator = require("../utils/validator");
|
|
9
9
|
// FCM backend constants
|
|
10
|
-
var FIREBASE_MESSAGING_HOST = 'fcm.googleapis.com';
|
|
11
10
|
var FIREBASE_MESSAGING_PORT = 443;
|
|
12
|
-
var FIREBASE_MESSAGING_PATH = '/fcm/send';
|
|
13
11
|
var FIREBASE_MESSAGING_TIMEOUT = 10000;
|
|
14
12
|
var FIREBASE_MESSAGING_HTTP_METHOD = 'POST';
|
|
15
13
|
var FIREBASE_MESSAGING_HEADERS = {
|
|
16
14
|
'Content-Type': 'application/json',
|
|
17
|
-
'Sdk-Version': 'Node/Admin/4.1
|
|
15
|
+
'Sdk-Version': 'Node/Admin/4.2.1',
|
|
18
16
|
access_token_auth: 'true',
|
|
19
17
|
};
|
|
20
18
|
/**
|
|
@@ -46,11 +44,13 @@ var FirebaseMessagingRequestHandler = (function () {
|
|
|
46
44
|
/**
|
|
47
45
|
* Invokes the request handler with the provided request data.
|
|
48
46
|
*
|
|
47
|
+
* @param {string} host The host to which to send the request.
|
|
48
|
+
* @param {string} path The path to which to send the request.
|
|
49
49
|
* @param {Object} requestData The request data.
|
|
50
50
|
* @return {Promise<Object>} A promise that resolves with the response.
|
|
51
51
|
*/
|
|
52
|
-
FirebaseMessagingRequestHandler.prototype.invokeRequestHandler = function (requestData) {
|
|
53
|
-
return this.signedApiRequestHandler.sendRequest(
|
|
52
|
+
FirebaseMessagingRequestHandler.prototype.invokeRequestHandler = function (host, path, requestData) {
|
|
53
|
+
return this.signedApiRequestHandler.sendRequest(host, FIREBASE_MESSAGING_PORT, path, FIREBASE_MESSAGING_HTTP_METHOD, requestData, FIREBASE_MESSAGING_HEADERS, FIREBASE_MESSAGING_TIMEOUT).then(function (response) {
|
|
54
54
|
// Send non-JSON responses to the catch() below where they will be treated as errors.
|
|
55
55
|
if (typeof response === 'string') {
|
|
56
56
|
return Promise.reject({
|
|
@@ -71,7 +71,10 @@ var FirebaseMessagingRequestHandler = (function () {
|
|
|
71
71
|
})
|
|
72
72
|
.catch(function (response) {
|
|
73
73
|
// Re-throw the error if it already has the proper format.
|
|
74
|
-
if (response
|
|
74
|
+
if (response instanceof error_1.FirebaseError) {
|
|
75
|
+
throw response;
|
|
76
|
+
}
|
|
77
|
+
else if (response.error instanceof error_1.FirebaseError) {
|
|
75
78
|
throw response.error;
|
|
76
79
|
}
|
|
77
80
|
// Add special handling for non-JSON responses.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -7,6 +7,12 @@ var messaging_api_request_1 = require("./messaging-api-request");
|
|
|
7
7
|
var error_1 = require("../utils/error");
|
|
8
8
|
var utils = require("../utils");
|
|
9
9
|
var validator = require("../utils/validator");
|
|
10
|
+
// FCM endpoints
|
|
11
|
+
var FCM_SEND_HOST = 'fcm.googleapis.com';
|
|
12
|
+
var FCM_SEND_PATH = '/fcm/send';
|
|
13
|
+
var FCM_TOPIC_MANAGEMENT_HOST = 'iid.googleapis.com';
|
|
14
|
+
var FCM_TOPIC_MANAGEMENT_ADD_PATH = '/iid/v1:batchAdd';
|
|
15
|
+
var FCM_TOPIC_MANAGEMENT_REMOVE_PATH = '/iid/v1:batchRemove';
|
|
10
16
|
// Key renames for the messaging notification payload object.
|
|
11
17
|
var CAMELCASED_NOTIFICATION_PAYLOAD_KEYS_MAP = {
|
|
12
18
|
bodyLocArgs: 'body_loc_args',
|
|
@@ -93,6 +99,38 @@ function mapRawResponseToDeviceGroupResponse(response) {
|
|
|
93
99
|
response.failedRegistrationTokens = response.failedRegistrationTokens || [];
|
|
94
100
|
return response;
|
|
95
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Maps a raw FCM server response to a MessagingTopicManagementResponse object.
|
|
104
|
+
*
|
|
105
|
+
* @param {Object} response The raw FCM server response to map.
|
|
106
|
+
*
|
|
107
|
+
* @return {MessagingTopicManagementResponse} The mapped MessagingTopicManagementResponse object.
|
|
108
|
+
*/
|
|
109
|
+
function mapRawResponseToTopicManagementResponse(response) {
|
|
110
|
+
// Add the success and failure counts.
|
|
111
|
+
response.successCount = 0;
|
|
112
|
+
response.failureCount = 0;
|
|
113
|
+
var errors = [];
|
|
114
|
+
if ('results' in response) {
|
|
115
|
+
response.results.forEach(function (tokenManagementResult, index) {
|
|
116
|
+
// Map the FCM server's error strings to actual error objects.
|
|
117
|
+
if ('error' in tokenManagementResult) {
|
|
118
|
+
response.failureCount += 1;
|
|
119
|
+
var newError = error_1.FirebaseMessagingError.fromServerError(tokenManagementResult.error, /* message */ undefined, tokenManagementResult.error);
|
|
120
|
+
errors.push({
|
|
121
|
+
index: index,
|
|
122
|
+
error: newError,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
response.successCount += 1;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
delete response.results;
|
|
131
|
+
response.errors = errors;
|
|
132
|
+
return response;
|
|
133
|
+
}
|
|
96
134
|
/**
|
|
97
135
|
* Internals of a Messaging instance.
|
|
98
136
|
*/
|
|
@@ -154,34 +192,15 @@ var Messaging = (function () {
|
|
|
154
192
|
Messaging.prototype.sendToDevice = function (registrationTokenOrTokens, payload, options) {
|
|
155
193
|
var _this = this;
|
|
156
194
|
if (options === void 0) { options = {}; }
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return Promise.reject(new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Too many registration tokens provided in a single request. Batch your requests to ' +
|
|
161
|
-
'contain no more than 1,000 registration tokens per request.'));
|
|
162
|
-
}
|
|
163
|
-
// Validate the array contains registration tokens which are non-empty strings.
|
|
164
|
-
try {
|
|
165
|
-
registrationTokenOrTokens.forEach(function (registrationToken, index) {
|
|
166
|
-
if (!validator.isNonEmptyString(registrationToken)) {
|
|
167
|
-
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, "Registration token provided to sendToDevice() at index " + index + " must be a non-empty string.");
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
return Promise.reject(error);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
else if (!validator.isNonEmptyString(registrationTokenOrTokens)) {
|
|
176
|
-
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Registration token provided to sendToDevice() must be a non-empty string or a non-empty array.');
|
|
177
|
-
}
|
|
178
|
-
// Validate the types of the payload and options arguments. Since these are common developer
|
|
179
|
-
// errors, throw an error instead of returning a rejected promise.
|
|
195
|
+
// Validate the input argument types. Since these are common developer errors when getting
|
|
196
|
+
// started, throw an error instead of returning a rejected promise.
|
|
197
|
+
this.validateRegistrationTokensType(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
180
198
|
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
181
199
|
return Promise.resolve()
|
|
182
200
|
.then(function () {
|
|
183
|
-
// Validate the contents of the
|
|
184
|
-
//
|
|
201
|
+
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
|
202
|
+
// error will cause this method to return a rejected promise.
|
|
203
|
+
_this.validateRegistrationTokens(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
185
204
|
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
186
205
|
var optionsCopy = _this.validateMessagingOptions(options);
|
|
187
206
|
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
@@ -192,7 +211,7 @@ var Messaging = (function () {
|
|
|
192
211
|
else {
|
|
193
212
|
request.registration_ids = registrationTokenOrTokens;
|
|
194
213
|
}
|
|
195
|
-
return _this.messagingRequestHandler.invokeRequestHandler(request);
|
|
214
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
196
215
|
})
|
|
197
216
|
.then(function (response) {
|
|
198
217
|
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
|
@@ -246,7 +265,7 @@ var Messaging = (function () {
|
|
|
246
265
|
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
247
266
|
deep_copy_1.deepExtend(request, optionsCopy);
|
|
248
267
|
request.to = notificationKey;
|
|
249
|
-
return _this.messagingRequestHandler.invokeRequestHandler(request);
|
|
268
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
250
269
|
})
|
|
251
270
|
.then(function (response) {
|
|
252
271
|
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
|
@@ -281,29 +300,23 @@ var Messaging = (function () {
|
|
|
281
300
|
Messaging.prototype.sendToTopic = function (topic, payload, options) {
|
|
282
301
|
var _this = this;
|
|
283
302
|
if (options === void 0) { options = {}; }
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
else if (!validator.isTopic(topic)) {
|
|
288
|
-
return Promise.reject(new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Topic provided to sendToTopic() must be a string which matches the format "/topics/[a-zA-Z0-9-_.~%]+".'));
|
|
289
|
-
}
|
|
290
|
-
// Prepend the topic with /topics/ if necessary
|
|
291
|
-
if (!/^\/topics\//.test(topic)) {
|
|
292
|
-
topic = "/topics/" + topic;
|
|
293
|
-
}
|
|
294
|
-
// Validate the types of the payload and options arguments. Since these are common developer
|
|
295
|
-
// errors, throw an error instead of returning a rejected promise.
|
|
303
|
+
// Validate the input argument types. Since these are common developer errors when getting
|
|
304
|
+
// started, throw an error instead of returning a rejected promise.
|
|
305
|
+
this.validateTopicType(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
296
306
|
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
307
|
+
// Prepend the topic with /topics/ if necessary.
|
|
308
|
+
topic = this.normalizeTopic(topic);
|
|
297
309
|
return Promise.resolve()
|
|
298
310
|
.then(function () {
|
|
299
311
|
// Validate the contents of the payload and options objects. Because we are now in a
|
|
300
312
|
// promise, any thrown error will cause this method to return a rejected promise.
|
|
301
313
|
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
302
314
|
var optionsCopy = _this.validateMessagingOptions(options);
|
|
315
|
+
_this.validateTopic(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
303
316
|
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
304
317
|
deep_copy_1.deepExtend(request, optionsCopy);
|
|
305
318
|
request.to = topic;
|
|
306
|
-
return _this.messagingRequestHandler.invokeRequestHandler(request);
|
|
319
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
307
320
|
})
|
|
308
321
|
.then(function (response) {
|
|
309
322
|
// Rename properties on the server response
|
|
@@ -344,7 +357,7 @@ var Messaging = (function () {
|
|
|
344
357
|
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
345
358
|
deep_copy_1.deepExtend(request, optionsCopy);
|
|
346
359
|
request.condition = condition;
|
|
347
|
-
return _this.messagingRequestHandler.invokeRequestHandler(request);
|
|
360
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
348
361
|
})
|
|
349
362
|
.then(function (response) {
|
|
350
363
|
// Rename properties on the server response
|
|
@@ -352,6 +365,71 @@ var Messaging = (function () {
|
|
|
352
365
|
return response;
|
|
353
366
|
});
|
|
354
367
|
};
|
|
368
|
+
/**
|
|
369
|
+
* Subscribes a single device or an array of devices to a topic.
|
|
370
|
+
*
|
|
371
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
372
|
+
* registration tokens to subscribe to the topic.
|
|
373
|
+
* @param {string} topic The topic to which to subscribe.
|
|
374
|
+
*
|
|
375
|
+
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed FCM
|
|
376
|
+
* server response.
|
|
377
|
+
*/
|
|
378
|
+
Messaging.prototype.subscribeToTopic = function (registrationTokenOrTokens, topic) {
|
|
379
|
+
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'subscribeToTopic', FCM_TOPIC_MANAGEMENT_ADD_PATH);
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Unsubscribes a single device or an array of devices from a topic.
|
|
383
|
+
*
|
|
384
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
385
|
+
* registration tokens to unsubscribe from the topic.
|
|
386
|
+
* @param {string} topic The topic to which to subscribe.
|
|
387
|
+
*
|
|
388
|
+
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed FCM
|
|
389
|
+
* server response.
|
|
390
|
+
*/
|
|
391
|
+
Messaging.prototype.unsubscribeFromTopic = function (registrationTokenOrTokens, topic) {
|
|
392
|
+
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'unsubscribeFromTopic', FCM_TOPIC_MANAGEMENT_REMOVE_PATH);
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Helper method which sends and handles topic subscription management requests.
|
|
396
|
+
*
|
|
397
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
398
|
+
* registration tokens to unsubscribe from the topic.
|
|
399
|
+
* @param {string} topic The topic to which to subscribe.
|
|
400
|
+
* @param {string} methodName The name of the original method called.
|
|
401
|
+
* @param {string} path The endpoint path to use for the request.
|
|
402
|
+
*
|
|
403
|
+
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed server
|
|
404
|
+
* response.
|
|
405
|
+
*/
|
|
406
|
+
Messaging.prototype.sendTopicManagementRequest = function (registrationTokenOrTokens, topic, methodName, path) {
|
|
407
|
+
var _this = this;
|
|
408
|
+
this.validateRegistrationTokensType(registrationTokenOrTokens, methodName);
|
|
409
|
+
this.validateTopicType(topic, methodName);
|
|
410
|
+
// Prepend the topic with /topics/ if necessary.
|
|
411
|
+
topic = this.normalizeTopic(topic);
|
|
412
|
+
return Promise.resolve()
|
|
413
|
+
.then(function () {
|
|
414
|
+
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
|
415
|
+
// error will cause this method to return a rejected promise.
|
|
416
|
+
_this.validateRegistrationTokens(registrationTokenOrTokens, methodName);
|
|
417
|
+
_this.validateTopic(topic, methodName);
|
|
418
|
+
// Ensure the registration token(s) input argument is an array.
|
|
419
|
+
var registrationTokensArray = registrationTokenOrTokens;
|
|
420
|
+
if (validator.isString(registrationTokenOrTokens)) {
|
|
421
|
+
registrationTokensArray = [registrationTokenOrTokens];
|
|
422
|
+
}
|
|
423
|
+
var request = {
|
|
424
|
+
to: topic,
|
|
425
|
+
registration_tokens: registrationTokensArray,
|
|
426
|
+
};
|
|
427
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_TOPIC_MANAGEMENT_HOST, path, request);
|
|
428
|
+
})
|
|
429
|
+
.then(function (response) {
|
|
430
|
+
return mapRawResponseToTopicManagementResponse(response);
|
|
431
|
+
});
|
|
432
|
+
};
|
|
355
433
|
/**
|
|
356
434
|
* Validates the types of the messaging payload and options. If invalid, an error will be thrown.
|
|
357
435
|
*
|
|
@@ -484,6 +562,87 @@ var Messaging = (function () {
|
|
|
484
562
|
}
|
|
485
563
|
return optionsCopy;
|
|
486
564
|
};
|
|
565
|
+
/**
|
|
566
|
+
* Validates the type of the provided registration token(s). If invalid, an error will be thrown.
|
|
567
|
+
*
|
|
568
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token(s) to validate.
|
|
569
|
+
* @param {string} method The method name to use in error messages.
|
|
570
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the registration tokens are invalid.
|
|
571
|
+
*/
|
|
572
|
+
Messaging.prototype.validateRegistrationTokensType = function (registrationTokenOrTokens, methodName, errorInfo) {
|
|
573
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
574
|
+
if (!validator.isNonEmptyArray(registrationTokenOrTokens) &&
|
|
575
|
+
!validator.isNonEmptyString(registrationTokenOrTokens)) {
|
|
576
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token(s) provided to " + methodName + "() must be a non-empty string or a " +
|
|
577
|
+
'non-empty array.');
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Validates the provided registration tokens. If invalid, an error will be thrown.
|
|
582
|
+
*
|
|
583
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
584
|
+
* registration tokens to validate.
|
|
585
|
+
* @param {string} method The method name to use in error messages.
|
|
586
|
+
* @param {errorInfo?} [ErrorInfo] The error info to use if the registration tokens are invalid.
|
|
587
|
+
*/
|
|
588
|
+
Messaging.prototype.validateRegistrationTokens = function (registrationTokenOrTokens, methodName, errorInfo) {
|
|
589
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
590
|
+
if (validator.isArray(registrationTokenOrTokens)) {
|
|
591
|
+
// Validate the array contains no more than 1,000 registration tokens.
|
|
592
|
+
if (registrationTokenOrTokens.length > 1000) {
|
|
593
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Too many registration tokens provided in a single request to " + methodName + "(). Batch " +
|
|
594
|
+
'your requests to contain no more than 1,000 registration tokens per request.');
|
|
595
|
+
}
|
|
596
|
+
// Validate the array contains registration tokens which are non-empty strings.
|
|
597
|
+
registrationTokenOrTokens.forEach(function (registrationToken, index) {
|
|
598
|
+
if (!validator.isNonEmptyString(registrationToken)) {
|
|
599
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token provided to " + methodName + "() at index " + index + " must be a " +
|
|
600
|
+
'non-empty string.');
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
/**
|
|
606
|
+
* Validates the type of the provided topic. If invalid, an error will be thrown.
|
|
607
|
+
*
|
|
608
|
+
* @param {string} topic The topic to validate.
|
|
609
|
+
* @param {string} method The method name to use in error messages.
|
|
610
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
|
611
|
+
*/
|
|
612
|
+
Messaging.prototype.validateTopicType = function (topic, methodName, errorInfo) {
|
|
613
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
614
|
+
if (!validator.isNonEmptyString(topic)) {
|
|
615
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
|
616
|
+
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
/**
|
|
620
|
+
* Validates the provided topic. If invalid, an error will be thrown.
|
|
621
|
+
*
|
|
622
|
+
* @param {string} topic The topic to validate.
|
|
623
|
+
* @param {string} method The method name to use in error messages.
|
|
624
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
|
625
|
+
*/
|
|
626
|
+
Messaging.prototype.validateTopic = function (topic, methodName, errorInfo) {
|
|
627
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
628
|
+
if (!validator.isTopic(topic)) {
|
|
629
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
|
630
|
+
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
/**
|
|
634
|
+
* Normalizes the provided topic name by prepending it with '/topics/', if necessary.
|
|
635
|
+
*
|
|
636
|
+
* @param {string} topic The topic name to normalize.
|
|
637
|
+
*
|
|
638
|
+
* @return {string} The normalized topic name.
|
|
639
|
+
*/
|
|
640
|
+
Messaging.prototype.normalizeTopic = function (topic) {
|
|
641
|
+
if (!/^\/topics\//.test(topic)) {
|
|
642
|
+
topic = "/topics/" + topic;
|
|
643
|
+
}
|
|
644
|
+
return topic;
|
|
645
|
+
};
|
|
487
646
|
return Messaging;
|
|
488
647
|
}());
|
|
489
648
|
exports.Messaging = Messaging;
|
package/lib/utils/api-request.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
var __extends = (this && this.__extends) || (function () {
|
|
@@ -87,11 +87,8 @@ var HttpRequestHandler = (function () {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
catch (error) {
|
|
90
|
-
var parsingError = new error_1.
|
|
91
|
-
|
|
92
|
-
message: "Failed to parse response data: \"" + error.toString() + "\". Raw server " +
|
|
93
|
-
("response: \"" + response + ".\""),
|
|
94
|
-
});
|
|
90
|
+
var parsingError = new error_1.FirebaseAppError(error_1.AppErrorCodes.UNABLE_TO_PARSE_RESPONSE, "Failed to parse response data: \"" + error.toString() + "\". Raw server" +
|
|
91
|
+
("response: \"" + response + ".\""));
|
|
95
92
|
reject({
|
|
96
93
|
statusCode: statusCode,
|
|
97
94
|
error: parsingError,
|
|
@@ -106,10 +103,7 @@ var HttpRequestHandler = (function () {
|
|
|
106
103
|
socket.setTimeout(timeout);
|
|
107
104
|
socket.on('timeout', function () {
|
|
108
105
|
req.abort();
|
|
109
|
-
var networkTimeoutError = new error_1.
|
|
110
|
-
code: 'network-timeout',
|
|
111
|
-
message: host + " network timeout. Please try again.",
|
|
112
|
-
});
|
|
106
|
+
var networkTimeoutError = new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, host + " network timeout. Please try again.");
|
|
113
107
|
reject({
|
|
114
108
|
statusCode: 408,
|
|
115
109
|
error: networkTimeoutError,
|
|
@@ -118,10 +112,7 @@ var HttpRequestHandler = (function () {
|
|
|
118
112
|
});
|
|
119
113
|
}
|
|
120
114
|
req.on('error', function (error) {
|
|
121
|
-
var networkRequestError = new error_1.
|
|
122
|
-
code: 'network-error',
|
|
123
|
-
message: "A network request error has occurred: " + (error && error.message),
|
|
124
|
-
});
|
|
115
|
+
var networkRequestError = new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, "A network request error has occurred: " + (error && error.message));
|
|
125
116
|
reject({
|
|
126
117
|
statusCode: 502,
|
|
127
118
|
error: networkRequestError,
|
|
@@ -166,11 +157,6 @@ var SignedApiRequestHandler = (function (_super) {
|
|
|
166
157
|
SignedApiRequestHandler.prototype.sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
|
|
167
158
|
var ancestorSendRequest = _super.prototype.sendRequest;
|
|
168
159
|
return this.app_.INTERNAL.getToken().then(function (accessTokenObj) {
|
|
169
|
-
if (accessTokenObj == null) {
|
|
170
|
-
return Promise.reject('Unable to fetch Google OAuth2 access token. ' +
|
|
171
|
-
'Make sure you initialized the SDK with a credential that can f' +
|
|
172
|
-
'etch access tokens.');
|
|
173
|
-
}
|
|
174
160
|
var headersCopy = deep_copy_1.deepCopy(headers);
|
|
175
161
|
var authorizationHeaderKey = 'Authorization';
|
|
176
162
|
headersCopy[authorizationHeaderKey] = 'Bearer ' + accessTokenObj.accessToken;
|
|
@@ -192,9 +178,6 @@ var ApiSettings = (function () {
|
|
|
192
178
|
if (httpMethod === void 0) { httpMethod = 'POST'; }
|
|
193
179
|
this.endpoint = endpoint;
|
|
194
180
|
this.httpMethod = httpMethod;
|
|
195
|
-
if (!endpoint) {
|
|
196
|
-
throw new Error("INTERNAL ASSERT FAILED: Unspecified API settings endpoint: " + endpoint);
|
|
197
|
-
}
|
|
198
181
|
this.setRequestValidator(null)
|
|
199
182
|
.setResponseValidator(null);
|
|
200
183
|
}
|
package/lib/utils/deep-copy.js
CHANGED
package/lib/utils/error.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
var __extends = (this && this.__extends) || (function () {
|
|
@@ -57,6 +57,24 @@ var FirebaseError = (function (_super) {
|
|
|
57
57
|
return FirebaseError;
|
|
58
58
|
}(Error));
|
|
59
59
|
exports.FirebaseError = FirebaseError;
|
|
60
|
+
/**
|
|
61
|
+
* Firebase App error code structure. This extends FirebaseError.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} code The error code.
|
|
64
|
+
* @param {string} message The error message.
|
|
65
|
+
* @constructor
|
|
66
|
+
*/
|
|
67
|
+
var FirebaseAppError = (function (_super) {
|
|
68
|
+
__extends(FirebaseAppError, _super);
|
|
69
|
+
function FirebaseAppError(code, message) {
|
|
70
|
+
return _super.call(this, {
|
|
71
|
+
code: 'app/' + code,
|
|
72
|
+
message: message,
|
|
73
|
+
}) || this;
|
|
74
|
+
}
|
|
75
|
+
return FirebaseAppError;
|
|
76
|
+
}(FirebaseError));
|
|
77
|
+
exports.FirebaseAppError = FirebaseAppError;
|
|
60
78
|
/**
|
|
61
79
|
* Firebase Auth error code structure. This extends FirebaseError.
|
|
62
80
|
*
|
|
@@ -138,6 +156,26 @@ var FirebaseMessagingError = (function (_super) {
|
|
|
138
156
|
return FirebaseMessagingError;
|
|
139
157
|
}(FirebaseError));
|
|
140
158
|
exports.FirebaseMessagingError = FirebaseMessagingError;
|
|
159
|
+
/**
|
|
160
|
+
* App client error codes and their default messages.
|
|
161
|
+
*/
|
|
162
|
+
var AppErrorCodes = (function () {
|
|
163
|
+
function AppErrorCodes() {
|
|
164
|
+
}
|
|
165
|
+
return AppErrorCodes;
|
|
166
|
+
}());
|
|
167
|
+
AppErrorCodes.APP_DELETED = 'app-deleted';
|
|
168
|
+
AppErrorCodes.DUPLICATE_APP = 'duplicate-app';
|
|
169
|
+
AppErrorCodes.INTERNAL_ERROR = 'internal-error';
|
|
170
|
+
AppErrorCodes.INVALID_APP_NAME = 'invalid-app-name';
|
|
171
|
+
AppErrorCodes.INVALID_APP_OPTIONS = 'invalid-app-options';
|
|
172
|
+
AppErrorCodes.INVALID_CREDENTIAL = 'invalid-credential';
|
|
173
|
+
AppErrorCodes.NETWORK_ERROR = 'network-error';
|
|
174
|
+
AppErrorCodes.NETWORK_TIMEOUT = 'network-timeout';
|
|
175
|
+
AppErrorCodes.NO_APP = 'no-app';
|
|
176
|
+
AppErrorCodes.UNABLE_TO_PARSE_RESPONSE = 'unable-to-parse-response';
|
|
177
|
+
exports.AppErrorCodes = AppErrorCodes;
|
|
178
|
+
;
|
|
141
179
|
/**
|
|
142
180
|
* Auth client error codes and their default messages.
|
|
143
181
|
*/
|
|
@@ -293,6 +331,11 @@ MessagingClientErrorCode.INVALID_APNS_CREDENTIALS = {
|
|
|
293
331
|
'SSL certificate was not uploaded or has expired. Check the validity of your development ' +
|
|
294
332
|
'and production certificates.',
|
|
295
333
|
};
|
|
334
|
+
MessagingClientErrorCode.TOO_MANY_TOPICS = {
|
|
335
|
+
code: 'too-many-topics',
|
|
336
|
+
message: 'The maximum number of topics the provided registration token can be subscribed to ' +
|
|
337
|
+
'has been exceeded.',
|
|
338
|
+
};
|
|
296
339
|
MessagingClientErrorCode.AUTHENTICATION_ERROR = {
|
|
297
340
|
code: 'authentication-error',
|
|
298
341
|
message: 'An error occurred when trying to authenticate to the FCM servers. Make sure the ' +
|
|
@@ -306,7 +349,7 @@ MessagingClientErrorCode.SERVER_UNAVAILABLE = {
|
|
|
306
349
|
};
|
|
307
350
|
MessagingClientErrorCode.INTERNAL_ERROR = {
|
|
308
351
|
code: 'internal-error',
|
|
309
|
-
message: 'An internal error has occurred.',
|
|
352
|
+
message: 'An internal error has occurred. Please retry the request.',
|
|
310
353
|
};
|
|
311
354
|
MessagingClientErrorCode.UNKNOWN_ERROR = {
|
|
312
355
|
code: 'unknown-error',
|
|
@@ -345,14 +388,20 @@ var AUTH_SERVER_TO_CLIENT_CODE = {
|
|
|
345
388
|
};
|
|
346
389
|
/** @const {ServerToClientCode} Messaging server to client enum error codes. */
|
|
347
390
|
var MESSAGING_SERVER_TO_CLIENT_CODE = {
|
|
391
|
+
/* GENERIC ERRORS */
|
|
348
392
|
// Generic invalid message parameter provided.
|
|
349
393
|
InvalidParameters: 'INVALID_ARGUMENT',
|
|
394
|
+
// Mismatched sender ID.
|
|
395
|
+
MismatchSenderId: 'MISMATCHED_CREDENTIAL',
|
|
396
|
+
// FCM server unavailable.
|
|
397
|
+
Unavailable: 'SERVER_UNAVAILABLE',
|
|
398
|
+
// FCM server internal error.
|
|
399
|
+
InternalServerError: 'INTERNAL_ERROR',
|
|
400
|
+
/* SEND ERRORS */
|
|
350
401
|
// Invalid registration token format.
|
|
351
402
|
InvalidRegistration: 'INVALID_REGISTRATION_TOKEN',
|
|
352
403
|
// Registration token is not registered.
|
|
353
404
|
NotRegistered: 'REGISTRATION_TOKEN_NOT_REGISTERED',
|
|
354
|
-
// Mismatched sender ID.
|
|
355
|
-
MismatchSenderId: 'MISMATCHED_CREDENTIAL',
|
|
356
405
|
// Registration token does not match restricted package name.
|
|
357
406
|
InvalidPackageName: 'INVALID_PACKAGE_NAME',
|
|
358
407
|
// Message payload size limit exceeded.
|
|
@@ -367,8 +416,13 @@ var MESSAGING_SERVER_TO_CLIENT_CODE = {
|
|
|
367
416
|
TopicsMessageRateExceeded: 'TOPICS_MESSAGE_RATE_EXCEEDED',
|
|
368
417
|
// Invalid APNs credentials.
|
|
369
418
|
InvalidApnsCredential: 'INVALID_APNS_CREDENTIALS',
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
419
|
+
/* TOPIC SUBSCRIPTION MANAGEMENT ERRORS */
|
|
420
|
+
NOT_FOUND: 'REGISTRATION_TOKEN_NOT_REGISTERED',
|
|
421
|
+
INVALID_ARGUMENT: 'INVALID_REGISTRATION_TOKEN',
|
|
422
|
+
TOO_MANY_TOPICS: 'TOO_MANY_TOPICS',
|
|
423
|
+
RESOURCE_EXHAUSTED: 'TOO_MANY_TOPICS',
|
|
424
|
+
PERMISSION_DENIED: 'AUTHENTICATION_ERROR',
|
|
425
|
+
DEADLINE_EXCEEDED: 'SERVER_UNAVAILABLE',
|
|
426
|
+
INTERNAL: 'INTERNAL_ERROR',
|
|
427
|
+
UNKNOWN: 'UNKNOWN_ERROR',
|
|
374
428
|
};
|
package/lib/utils/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -7,8 +7,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
*
|
|
8
8
|
* For example, this can be used to map underscore_cased properties to camelCase.
|
|
9
9
|
*
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
10
|
+
* @param {Object} obj The object whose properties to rename.
|
|
11
|
+
* @param {Object} keyMap The mapping from old to new property names.
|
|
12
12
|
*/
|
|
13
13
|
function renameProperties(obj, keyMap) {
|
|
14
14
|
Object.keys(keyMap).forEach(function (oldKey) {
|
|
@@ -21,3 +21,22 @@ function renameProperties(obj, keyMap) {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
exports.renameProperties = renameProperties;
|
|
24
|
+
/**
|
|
25
|
+
* Defines a new read-only property directly on an object and returns the object.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} obj The object on which to define the property.
|
|
28
|
+
* @param {string} prop The name of the property to be defined or modified.
|
|
29
|
+
* @param {any} value The value associated with the property.
|
|
30
|
+
*
|
|
31
|
+
* @return {Object} The object that was passed to the function.
|
|
32
|
+
*/
|
|
33
|
+
function addReadonlyGetter(obj, prop, value) {
|
|
34
|
+
Object.defineProperty(obj, prop, {
|
|
35
|
+
value: value,
|
|
36
|
+
// Make this property read-only.
|
|
37
|
+
writable: false,
|
|
38
|
+
// Include this property during enumeration of obj's properties.
|
|
39
|
+
enumerable: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.addReadonlyGetter = addReadonlyGetter;
|
package/lib/utils/validator.js
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
|
-
/*! firebase-admin v4.1
|
|
1
|
+
/*! firebase-admin v4.2.1
|
|
2
2
|
https://firebase.google.com/terms/ */
|
|
3
3
|
"use strict";
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
var url = require("url");
|
|
6
|
+
/**
|
|
7
|
+
* Validates that a value is an array.
|
|
8
|
+
*
|
|
9
|
+
* @param {any} value The value to validate.
|
|
10
|
+
* @return {boolean} Whether the value is an array or not.
|
|
11
|
+
*/
|
|
12
|
+
function isArray(value) {
|
|
13
|
+
return value instanceof Array;
|
|
14
|
+
}
|
|
15
|
+
exports.isArray = isArray;
|
|
16
|
+
/**
|
|
17
|
+
* Validates that a value is a non-empty array.
|
|
18
|
+
*
|
|
19
|
+
* @param {any} value The value to validate.
|
|
20
|
+
* @return {boolean} Whether the value is a non-empty array or not.
|
|
21
|
+
*/
|
|
22
|
+
function isNonEmptyArray(value) {
|
|
23
|
+
return isArray(value) && value.length !== 0;
|
|
24
|
+
}
|
|
25
|
+
exports.isNonEmptyArray = isNonEmptyArray;
|
|
6
26
|
/**
|
|
7
27
|
* Validates that a value is a boolean.
|
|
8
28
|
*
|
|
@@ -40,7 +60,7 @@ exports.isString = isString;
|
|
|
40
60
|
* @return {boolean} Whether the value is a non-empty string or not.
|
|
41
61
|
*/
|
|
42
62
|
function isNonEmptyString(value) {
|
|
43
|
-
return
|
|
63
|
+
return isString(value) && value !== '';
|
|
44
64
|
}
|
|
45
65
|
exports.isNonEmptyString = isNonEmptyString;
|
|
46
66
|
/**
|