mirror of
https://github.com/musix-org/musix-oss
synced 2025-07-01 10:43:38 +00:00
Updated
This commit is contained in:
124
node_modules/firebase-admin/lib/messaging/batch-request.js
generated
vendored
Normal file
124
node_modules/firebase-admin/lib/messaging/batch-request.js
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*! firebase-admin v8.5.0 */
|
||||
"use strict";
|
||||
/*!
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var api_request_1 = require("../utils/api-request");
|
||||
var PART_BOUNDARY = '__END_OF_PART__';
|
||||
var TEN_SECONDS_IN_MILLIS = 10000;
|
||||
/**
|
||||
* An HTTP client that can be used to make batch requests. This client is not tied to any service
|
||||
* (FCM or otherwise). Therefore it can be used to make batch requests to any service that allows
|
||||
* it. If this requirement ever arises we can move this implementation to the utils module
|
||||
* where it can be easily shared among other modules.
|
||||
*/
|
||||
var BatchRequestClient = /** @class */ (function () {
|
||||
/**
|
||||
* @param {HttpClient} httpClient The client that will be used to make HTTP calls.
|
||||
* @param {string} batchUrl The URL that accepts batch requests.
|
||||
* @param {object=} commonHeaders Optional headers that will be included in all requests.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function BatchRequestClient(httpClient, batchUrl, commonHeaders) {
|
||||
this.httpClient = httpClient;
|
||||
this.batchUrl = batchUrl;
|
||||
this.commonHeaders = commonHeaders;
|
||||
}
|
||||
/**
|
||||
* Sends the given array of sub requests as a single batch, and parses the results into an array
|
||||
* of HttpResponse objects.
|
||||
*
|
||||
* @param {SubRequest[]} requests An array of sub requests to send.
|
||||
* @return {Promise<HttpResponse[]>} A promise that resolves when the send operation is complete.
|
||||
*/
|
||||
BatchRequestClient.prototype.send = function (requests) {
|
||||
var _this = this;
|
||||
requests = requests.map(function (req) {
|
||||
req.headers = Object.assign({}, _this.commonHeaders, req.headers);
|
||||
return req;
|
||||
});
|
||||
var requestHeaders = {
|
||||
'Content-Type': "multipart/mixed; boundary=" + PART_BOUNDARY,
|
||||
};
|
||||
var request = {
|
||||
method: 'POST',
|
||||
url: this.batchUrl,
|
||||
data: this.getMultipartPayload(requests),
|
||||
headers: Object.assign({}, this.commonHeaders, requestHeaders),
|
||||
timeout: TEN_SECONDS_IN_MILLIS,
|
||||
};
|
||||
return this.httpClient.send(request).then(function (response) {
|
||||
return response.multipart.map(function (buff) {
|
||||
return api_request_1.parseHttpResponse(buff, request);
|
||||
});
|
||||
});
|
||||
};
|
||||
BatchRequestClient.prototype.getMultipartPayload = function (requests) {
|
||||
var buffer = '';
|
||||
requests.forEach(function (request, idx) {
|
||||
buffer += createPart(request, PART_BOUNDARY, idx);
|
||||
});
|
||||
buffer += "--" + PART_BOUNDARY + "--\r\n";
|
||||
return Buffer.from(buffer, 'utf-8');
|
||||
};
|
||||
return BatchRequestClient;
|
||||
}());
|
||||
exports.BatchRequestClient = BatchRequestClient;
|
||||
/**
|
||||
* Creates a single part in a multipart HTTP request body. The part consists of several headers
|
||||
* followed by the serialized sub request as the body. As per the requirements of the FCM batch
|
||||
* API, sets the content-type header to application/http, and the content-transfer-encoding to
|
||||
* binary.
|
||||
*
|
||||
* @param {SubRequest} request A sub request that will be used to populate the part.
|
||||
* @param {string} boundary Multipart boundary string.
|
||||
* @param {number} idx An index number that is used to set the content-id header.
|
||||
* @return {string} The part as a string that can be included in the HTTP body.
|
||||
*/
|
||||
function createPart(request, boundary, idx) {
|
||||
var serializedRequest = serializeSubRequest(request);
|
||||
var part = "--" + boundary + "\r\n";
|
||||
part += "Content-Length: " + serializedRequest.length + "\r\n";
|
||||
part += 'Content-Type: application/http\r\n';
|
||||
part += "content-id: " + (idx + 1) + "\r\n";
|
||||
part += 'content-transfer-encoding: binary\r\n';
|
||||
part += '\r\n';
|
||||
part += serializedRequest + "\r\n";
|
||||
return part;
|
||||
}
|
||||
/**
|
||||
* Serializes a sub request into a string that can be embedded in a multipart HTTP request. The
|
||||
* format of the string is the wire format of a typical HTTP request, consisting of a header and a
|
||||
* body.
|
||||
*
|
||||
* @param request {SubRequest} The sub request to be serialized.
|
||||
* @return {string} String representation of the SubRequest.
|
||||
*/
|
||||
function serializeSubRequest(request) {
|
||||
var requestBody = JSON.stringify(request.body);
|
||||
var messagePayload = "POST " + request.url + " HTTP/1.1\r\n";
|
||||
messagePayload += "Content-Length: " + requestBody.length + "\r\n";
|
||||
messagePayload += 'Content-Type: application/json; charset=UTF-8\r\n';
|
||||
if (request.headers) {
|
||||
Object.keys(request.headers).forEach(function (key) {
|
||||
messagePayload += key + ": " + request.headers[key] + "\r\n";
|
||||
});
|
||||
}
|
||||
messagePayload += '\r\n';
|
||||
messagePayload += requestBody;
|
||||
return messagePayload;
|
||||
}
|
125
node_modules/firebase-admin/lib/messaging/messaging-api-request.js
generated
vendored
Normal file
125
node_modules/firebase-admin/lib/messaging/messaging-api-request.js
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/*! firebase-admin v8.5.0 */
|
||||
"use strict";
|
||||
/*!
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var api_request_1 = require("../utils/api-request");
|
||||
var messaging_errors_1 = require("./messaging-errors");
|
||||
var batch_request_1 = require("./batch-request");
|
||||
// FCM backend constants
|
||||
var FIREBASE_MESSAGING_TIMEOUT = 10000;
|
||||
var FIREBASE_MESSAGING_BATCH_URL = 'https://fcm.googleapis.com/batch';
|
||||
var FIREBASE_MESSAGING_HTTP_METHOD = 'POST';
|
||||
var FIREBASE_MESSAGING_HEADERS = {
|
||||
'X-Firebase-Client': 'fire-admin-node/8.5.0',
|
||||
};
|
||||
var LEGACY_FIREBASE_MESSAGING_HEADERS = {
|
||||
'X-Firebase-Client': 'fire-admin-node/8.5.0',
|
||||
'access_token_auth': 'true',
|
||||
};
|
||||
/**
|
||||
* Class that provides a mechanism to send requests to the Firebase Cloud Messaging backend.
|
||||
*/
|
||||
var FirebaseMessagingRequestHandler = /** @class */ (function () {
|
||||
/**
|
||||
* @param {FirebaseApp} app The app used to fetch access tokens to sign API requests.
|
||||
* @constructor
|
||||
*/
|
||||
function FirebaseMessagingRequestHandler(app) {
|
||||
this.httpClient = new api_request_1.AuthorizedHttpClient(app);
|
||||
this.batchClient = new batch_request_1.BatchRequestClient(this.httpClient, FIREBASE_MESSAGING_BATCH_URL, FIREBASE_MESSAGING_HEADERS);
|
||||
}
|
||||
/**
|
||||
* Invokes the request handler with the provided request data.
|
||||
*
|
||||
* @param {string} host The host to which to send the request.
|
||||
* @param {string} path The path to which to send the request.
|
||||
* @param {object} requestData The request data.
|
||||
* @return {Promise<object>} A promise that resolves with the response.
|
||||
*/
|
||||
FirebaseMessagingRequestHandler.prototype.invokeRequestHandler = function (host, path, requestData) {
|
||||
var request = {
|
||||
method: FIREBASE_MESSAGING_HTTP_METHOD,
|
||||
url: "https://" + host + path,
|
||||
data: requestData,
|
||||
headers: LEGACY_FIREBASE_MESSAGING_HEADERS,
|
||||
timeout: FIREBASE_MESSAGING_TIMEOUT,
|
||||
};
|
||||
return this.httpClient.send(request).then(function (response) {
|
||||
// Send non-JSON responses to the catch() below where they will be treated as errors.
|
||||
if (!response.isJson()) {
|
||||
throw new api_request_1.HttpError(response);
|
||||
}
|
||||
// Check for backend errors in the response.
|
||||
var errorCode = messaging_errors_1.getErrorCode(response.data);
|
||||
if (errorCode) {
|
||||
throw new api_request_1.HttpError(response);
|
||||
}
|
||||
// Return entire response.
|
||||
return response.data;
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err instanceof api_request_1.HttpError) {
|
||||
throw messaging_errors_1.createFirebaseError(err);
|
||||
}
|
||||
// Re-throw the error if it already has the proper format.
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Sends the given array of sub requests as a single batch to FCM, and parses the result into
|
||||
* a BatchResponse object.
|
||||
*
|
||||
* @param {SubRequest[]} requests An array of sub requests to send.
|
||||
* @return {Promise<BatchResponse>} A promise that resolves when the send operation is complete.
|
||||
*/
|
||||
FirebaseMessagingRequestHandler.prototype.sendBatchRequest = function (requests) {
|
||||
var _this = this;
|
||||
return this.batchClient.send(requests)
|
||||
.then(function (responses) {
|
||||
return responses.map(function (part) {
|
||||
return _this.buildSendResponse(part);
|
||||
});
|
||||
}).then(function (responses) {
|
||||
var successCount = responses.filter(function (resp) { return resp.success; }).length;
|
||||
return {
|
||||
responses: responses,
|
||||
successCount: successCount,
|
||||
failureCount: responses.length - successCount,
|
||||
};
|
||||
}).catch(function (err) {
|
||||
if (err instanceof api_request_1.HttpError) {
|
||||
throw messaging_errors_1.createFirebaseError(err);
|
||||
}
|
||||
// Re-throw the error if it already has the proper format.
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
FirebaseMessagingRequestHandler.prototype.buildSendResponse = function (response) {
|
||||
var result = {
|
||||
success: response.status === 200,
|
||||
};
|
||||
if (result.success) {
|
||||
result.messageId = response.data.name;
|
||||
}
|
||||
else {
|
||||
result.error = messaging_errors_1.createFirebaseError(new api_request_1.HttpError(response));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return FirebaseMessagingRequestHandler;
|
||||
}());
|
||||
exports.FirebaseMessagingRequestHandler = FirebaseMessagingRequestHandler;
|
104
node_modules/firebase-admin/lib/messaging/messaging-errors.js
generated
vendored
Normal file
104
node_modules/firebase-admin/lib/messaging/messaging-errors.js
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*! firebase-admin v8.5.0 */
|
||||
"use strict";
|
||||
/*!
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var error_1 = require("../utils/error");
|
||||
var validator = require("../utils/validator");
|
||||
/**
|
||||
* Creates a new FirebaseMessagingError by extracting the error code, message and other relevant
|
||||
* details from an HTTP error response.
|
||||
*
|
||||
* @param {HttpError} err The HttpError to convert into a Firebase error
|
||||
* @return {FirebaseMessagingError} A Firebase error that can be returned to the user.
|
||||
*/
|
||||
function createFirebaseError(err) {
|
||||
if (err.response.isJson()) {
|
||||
// For JSON responses, map the server response to a client-side error.
|
||||
var json = err.response.data;
|
||||
var errorCode = getErrorCode(json);
|
||||
var errorMessage = getErrorMessage(json);
|
||||
return error_1.FirebaseMessagingError.fromServerError(errorCode, errorMessage, json);
|
||||
}
|
||||
// Non-JSON response
|
||||
var error;
|
||||
switch (err.response.status) {
|
||||
case 400:
|
||||
error = error_1.MessagingClientErrorCode.INVALID_ARGUMENT;
|
||||
break;
|
||||
case 401:
|
||||
case 403:
|
||||
error = error_1.MessagingClientErrorCode.AUTHENTICATION_ERROR;
|
||||
break;
|
||||
case 500:
|
||||
error = error_1.MessagingClientErrorCode.INTERNAL_ERROR;
|
||||
break;
|
||||
case 503:
|
||||
error = error_1.MessagingClientErrorCode.SERVER_UNAVAILABLE;
|
||||
break;
|
||||
default:
|
||||
// Treat non-JSON responses with unexpected status codes as unknown errors.
|
||||
error = error_1.MessagingClientErrorCode.UNKNOWN_ERROR;
|
||||
}
|
||||
return new error_1.FirebaseMessagingError({
|
||||
code: error.code,
|
||||
message: error.message + " Raw server response: \"" + err.response.text + "\". Status code: " +
|
||||
(err.response.status + "."),
|
||||
});
|
||||
}
|
||||
exports.createFirebaseError = createFirebaseError;
|
||||
/**
|
||||
* @param {object} response The response to check for errors.
|
||||
* @return {string|null} The error code if present; null otherwise.
|
||||
*/
|
||||
function getErrorCode(response) {
|
||||
if (validator.isNonNullObject(response) && 'error' in response) {
|
||||
if (validator.isString(response.error)) {
|
||||
return response.error;
|
||||
}
|
||||
if (validator.isArray(response.error.details)) {
|
||||
var fcmErrorType = 'type.googleapis.com/google.firebase.fcm.v1.FcmError';
|
||||
for (var _i = 0, _a = response.error.details; _i < _a.length; _i++) {
|
||||
var element = _a[_i];
|
||||
if (element['@type'] === fcmErrorType) {
|
||||
return element.errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('status' in response.error) {
|
||||
return response.error.status;
|
||||
}
|
||||
else {
|
||||
return response.error.message;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.getErrorCode = getErrorCode;
|
||||
/**
|
||||
* Extracts error message from the given response object.
|
||||
*
|
||||
* @param {object} response The response to check for errors.
|
||||
* @return {string|null} The error message if present; null otherwise.
|
||||
*/
|
||||
function getErrorMessage(response) {
|
||||
if (validator.isNonNullObject(response) &&
|
||||
'error' in response &&
|
||||
validator.isNonEmptyString(response.error.message)) {
|
||||
return response.error.message;
|
||||
}
|
||||
return null;
|
||||
}
|
359
node_modules/firebase-admin/lib/messaging/messaging-types.js
generated
vendored
Normal file
359
node_modules/firebase-admin/lib/messaging/messaging-types.js
generated
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
/*! firebase-admin v8.5.0 */
|
||||
"use strict";
|
||||
/*!
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var index_1 = require("../utils/index");
|
||||
var error_1 = require("../utils/error");
|
||||
var validator = require("../utils/validator");
|
||||
/**
|
||||
* Checks if the given Message object is valid. Recursively validates all the child objects
|
||||
* included in the message (android, apns, data etc.). If successful, transforms the message
|
||||
* in place by renaming the keys to what's expected by the remote FCM service.
|
||||
*
|
||||
* @param {Message} Message An object to be validated.
|
||||
*/
|
||||
function validateMessage(message) {
|
||||
if (!validator.isNonNullObject(message)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Message must be a non-null object');
|
||||
}
|
||||
var anyMessage = message;
|
||||
if (anyMessage.topic) {
|
||||
// If the topic name is prefixed, remove it.
|
||||
if (anyMessage.topic.startsWith('/topics/')) {
|
||||
anyMessage.topic = anyMessage.topic.replace(/^\/topics\//, '');
|
||||
}
|
||||
// Checks for illegal characters and empty string.
|
||||
if (!/^[a-zA-Z0-9-_.~%]+$/.test(anyMessage.topic)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Malformed topic name');
|
||||
}
|
||||
}
|
||||
var targets = [anyMessage.token, anyMessage.topic, anyMessage.condition];
|
||||
if (targets.filter(function (v) { return validator.isNonEmptyString(v); }).length !== 1) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Exactly one of topic, token or condition is required');
|
||||
}
|
||||
validateStringMap(message.data, 'data');
|
||||
validateAndroidConfig(message.android);
|
||||
validateWebpushConfig(message.webpush);
|
||||
validateApnsConfig(message.apns);
|
||||
validateFcmOptions(message.fcmOptions);
|
||||
}
|
||||
exports.validateMessage = validateMessage;
|
||||
/**
|
||||
* Checks if the given object only contains strings as child values.
|
||||
*
|
||||
* @param {object} map An object to be validated.
|
||||
* @param {string} label A label to be included in the errors thrown.
|
||||
*/
|
||||
function validateStringMap(map, label) {
|
||||
if (typeof map === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(map)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, label + " must be a non-null object");
|
||||
}
|
||||
Object.keys(map).forEach(function (key) {
|
||||
if (!validator.isString(map[key])) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, label + " must only contain string values");
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Checks if the given WebpushConfig object is valid. The object must have valid headers and data.
|
||||
*
|
||||
* @param {WebpushConfig} config An object to be validated.
|
||||
*/
|
||||
function validateWebpushConfig(config) {
|
||||
if (typeof config === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(config)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'webpush must be a non-null object');
|
||||
}
|
||||
validateStringMap(config.headers, 'webpush.headers');
|
||||
validateStringMap(config.data, 'webpush.data');
|
||||
}
|
||||
/**
|
||||
* Checks if the given ApnsConfig object is valid. The object must have valid headers and a
|
||||
* payload.
|
||||
*
|
||||
* @param {ApnsConfig} config An object to be validated.
|
||||
*/
|
||||
function validateApnsConfig(config) {
|
||||
if (typeof config === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(config)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns must be a non-null object');
|
||||
}
|
||||
validateStringMap(config.headers, 'apns.headers');
|
||||
validateApnsPayload(config.payload);
|
||||
validateApnsFcmOptions(config.fcmOptions);
|
||||
}
|
||||
/**
|
||||
* Checks if the given ApnsFcmOptions object is valid.
|
||||
*
|
||||
* @param {ApnsFcmOptions} fcmOptions An object to be validated.
|
||||
*/
|
||||
function validateApnsFcmOptions(fcmOptions) {
|
||||
if (typeof fcmOptions === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(fcmOptions)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||||
}
|
||||
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if the given FcmOptions object is valid.
|
||||
*
|
||||
* @param {FcmOptions} fcmOptions An object to be validated.
|
||||
*/
|
||||
function validateFcmOptions(fcmOptions) {
|
||||
if (typeof fcmOptions === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(fcmOptions)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||||
}
|
||||
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if the given ApnsPayload object is valid. The object must have a valid aps value.
|
||||
*
|
||||
* @param {ApnsPayload} payload An object to be validated.
|
||||
*/
|
||||
function validateApnsPayload(payload) {
|
||||
if (typeof payload === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(payload)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload must be a non-null object');
|
||||
}
|
||||
validateAps(payload.aps);
|
||||
}
|
||||
/**
|
||||
* Checks if the given Aps object is valid. The object must have a valid alert. If the validation
|
||||
* is successful, transforms the input object by renaming the keys to valid APNS payload keys.
|
||||
*
|
||||
* @param {Aps} aps An object to be validated.
|
||||
*/
|
||||
function validateAps(aps) {
|
||||
if (typeof aps === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(aps)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps must be a non-null object');
|
||||
}
|
||||
validateApsAlert(aps.alert);
|
||||
validateApsSound(aps.sound);
|
||||
var propertyMappings = {
|
||||
contentAvailable: 'content-available',
|
||||
mutableContent: 'mutable-content',
|
||||
threadId: 'thread-id',
|
||||
};
|
||||
Object.keys(propertyMappings).forEach(function (key) {
|
||||
if (key in aps && propertyMappings[key] in aps) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Multiple specifications for " + key + " in Aps");
|
||||
}
|
||||
});
|
||||
index_1.renameProperties(aps, propertyMappings);
|
||||
var contentAvailable = aps['content-available'];
|
||||
if (typeof contentAvailable !== 'undefined' && contentAvailable !== 1) {
|
||||
if (contentAvailable === true) {
|
||||
aps['content-available'] = 1;
|
||||
}
|
||||
else {
|
||||
delete aps['content-available'];
|
||||
}
|
||||
}
|
||||
var mutableContent = aps['mutable-content'];
|
||||
if (typeof mutableContent !== 'undefined' && mutableContent !== 1) {
|
||||
if (mutableContent === true) {
|
||||
aps['mutable-content'] = 1;
|
||||
}
|
||||
else {
|
||||
delete aps['mutable-content'];
|
||||
}
|
||||
}
|
||||
}
|
||||
function validateApsSound(sound) {
|
||||
if (typeof sound === 'undefined' || validator.isNonEmptyString(sound)) {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(sound)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound must be a non-empty string or a non-null object');
|
||||
}
|
||||
if (!validator.isNonEmptyString(sound.name)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.name must be a non-empty string');
|
||||
}
|
||||
var volume = sound.volume;
|
||||
if (typeof volume !== 'undefined') {
|
||||
if (!validator.isNumber(volume)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.volume must be a number');
|
||||
}
|
||||
if (volume < 0 || volume > 1) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.volume must be in the interval [0, 1]');
|
||||
}
|
||||
}
|
||||
var soundObject = sound;
|
||||
var key = 'critical';
|
||||
var critical = soundObject[key];
|
||||
if (typeof critical !== 'undefined' && critical !== 1) {
|
||||
if (critical === true) {
|
||||
soundObject[key] = 1;
|
||||
}
|
||||
else {
|
||||
delete soundObject[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if the given alert object is valid. Alert could be a string or a complex object.
|
||||
* If specified as an object, it must have valid localization parameters. If successful, transforms
|
||||
* the input object by renaming the keys to valid APNS payload keys.
|
||||
*
|
||||
* @param {string | ApsAlert} alert An alert string or an object to be validated.
|
||||
*/
|
||||
function validateApsAlert(alert) {
|
||||
if (typeof alert === 'undefined' || validator.isString(alert)) {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(alert)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert must be a string or a non-null object');
|
||||
}
|
||||
var apsAlert = alert;
|
||||
if (validator.isNonEmptyArray(apsAlert.locArgs) &&
|
||||
!validator.isNonEmptyString(apsAlert.locKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.locKey is required when specifying locArgs');
|
||||
}
|
||||
if (validator.isNonEmptyArray(apsAlert.titleLocArgs) &&
|
||||
!validator.isNonEmptyString(apsAlert.titleLocKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.titleLocKey is required when specifying titleLocArgs');
|
||||
}
|
||||
if (validator.isNonEmptyArray(apsAlert.subtitleLocArgs) &&
|
||||
!validator.isNonEmptyString(apsAlert.subtitleLocKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.subtitleLocKey is required when specifying subtitleLocArgs');
|
||||
}
|
||||
var propertyMappings = {
|
||||
locKey: 'loc-key',
|
||||
locArgs: 'loc-args',
|
||||
titleLocKey: 'title-loc-key',
|
||||
titleLocArgs: 'title-loc-args',
|
||||
subtitleLocKey: 'subtitle-loc-key',
|
||||
subtitleLocArgs: 'subtitle-loc-args',
|
||||
actionLocKey: 'action-loc-key',
|
||||
launchImage: 'launch-image',
|
||||
};
|
||||
index_1.renameProperties(apsAlert, propertyMappings);
|
||||
}
|
||||
/**
|
||||
* Checks if the given AndroidConfig object is valid. The object must have valid ttl, data,
|
||||
* and notification fields. If successful, transforms the input object by renaming keys to valid
|
||||
* Android keys. Also transforms the ttl value to the format expected by FCM service.
|
||||
*
|
||||
* @param {AndroidConfig} config An object to be validated.
|
||||
*/
|
||||
function validateAndroidConfig(config) {
|
||||
if (typeof config === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(config)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android must be a non-null object');
|
||||
}
|
||||
if (typeof config.ttl !== 'undefined') {
|
||||
if (!validator.isNumber(config.ttl) || config.ttl < 0) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'TTL must be a non-negative duration in milliseconds');
|
||||
}
|
||||
var seconds = Math.floor(config.ttl / 1000);
|
||||
var nanos = (config.ttl - seconds * 1000) * 1000000;
|
||||
var duration = void 0;
|
||||
if (nanos > 0) {
|
||||
var nanoString = nanos.toString();
|
||||
while (nanoString.length < 9) {
|
||||
nanoString = '0' + nanoString;
|
||||
}
|
||||
duration = seconds + "." + nanoString + "s";
|
||||
}
|
||||
else {
|
||||
duration = seconds + "s";
|
||||
}
|
||||
config.ttl = duration;
|
||||
}
|
||||
validateStringMap(config.data, 'android.data');
|
||||
validateAndroidNotification(config.notification);
|
||||
validateAndroidFcmOptions(config.fcmOptions);
|
||||
var propertyMappings = {
|
||||
collapseKey: 'collapse_key',
|
||||
restrictedPackageName: 'restricted_package_name',
|
||||
};
|
||||
index_1.renameProperties(config, propertyMappings);
|
||||
}
|
||||
/**
|
||||
* Checks if the given AndroidNotification object is valid. The object must have valid color and
|
||||
* localization parameters. If successful, transforms the input object by renaming keys to valid
|
||||
* Android keys.
|
||||
*
|
||||
* @param {AndroidNotification} notification An object to be validated.
|
||||
*/
|
||||
function validateAndroidNotification(notification) {
|
||||
if (typeof notification === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(notification)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification must be a non-null object');
|
||||
}
|
||||
if (typeof notification.color !== 'undefined' && !/^#[0-9a-fA-F]{6}$/.test(notification.color)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.color must be in the form #RRGGBB');
|
||||
}
|
||||
if (validator.isNonEmptyArray(notification.bodyLocArgs) &&
|
||||
!validator.isNonEmptyString(notification.bodyLocKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.bodyLocKey is required when specifying bodyLocArgs');
|
||||
}
|
||||
if (validator.isNonEmptyArray(notification.titleLocArgs) &&
|
||||
!validator.isNonEmptyString(notification.titleLocKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.titleLocKey is required when specifying titleLocArgs');
|
||||
}
|
||||
var propertyMappings = {
|
||||
clickAction: 'click_action',
|
||||
bodyLocKey: 'body_loc_key',
|
||||
bodyLocArgs: 'body_loc_args',
|
||||
titleLocKey: 'title_loc_key',
|
||||
titleLocArgs: 'title_loc_args',
|
||||
channelId: 'channel_id',
|
||||
};
|
||||
index_1.renameProperties(notification, propertyMappings);
|
||||
}
|
||||
/**
|
||||
* Checks if the given AndroidFcmOptions object is valid.
|
||||
*
|
||||
* @param {AndroidFcmOptions} fcmOptions An object to be validated.
|
||||
*/
|
||||
function validateAndroidFcmOptions(fcmOptions) {
|
||||
if (typeof fcmOptions === 'undefined') {
|
||||
return;
|
||||
}
|
||||
else if (!validator.isNonNullObject(fcmOptions)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||||
}
|
||||
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||||
}
|
||||
}
|
783
node_modules/firebase-admin/lib/messaging/messaging.js
generated
vendored
Normal file
783
node_modules/firebase-admin/lib/messaging/messaging.js
generated
vendored
Normal file
@ -0,0 +1,783 @@
|
||||
/*! firebase-admin v8.5.0 */
|
||||
"use strict";
|
||||
/*!
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var deep_copy_1 = require("../utils/deep-copy");
|
||||
var messaging_types_1 = require("./messaging-types");
|
||||
var messaging_api_request_1 = require("./messaging-api-request");
|
||||
var error_1 = require("../utils/error");
|
||||
var utils = require("../utils");
|
||||
var validator = require("../utils/validator");
|
||||
// FCM endpoints
|
||||
var FCM_SEND_HOST = 'fcm.googleapis.com';
|
||||
var FCM_SEND_PATH = '/fcm/send';
|
||||
var FCM_TOPIC_MANAGEMENT_HOST = 'iid.googleapis.com';
|
||||
var FCM_TOPIC_MANAGEMENT_ADD_PATH = '/iid/v1:batchAdd';
|
||||
var FCM_TOPIC_MANAGEMENT_REMOVE_PATH = '/iid/v1:batchRemove';
|
||||
// Maximum messages that can be included in a batch request.
|
||||
var FCM_MAX_BATCH_SIZE = 100;
|
||||
// Key renames for the messaging notification payload object.
|
||||
var CAMELCASED_NOTIFICATION_PAYLOAD_KEYS_MAP = {
|
||||
bodyLocArgs: 'body_loc_args',
|
||||
bodyLocKey: 'body_loc_key',
|
||||
clickAction: 'click_action',
|
||||
titleLocArgs: 'title_loc_args',
|
||||
titleLocKey: 'title_loc_key',
|
||||
};
|
||||
// Key renames for the messaging options object.
|
||||
var CAMELCASE_OPTIONS_KEYS_MAP = {
|
||||
dryRun: 'dry_run',
|
||||
timeToLive: 'time_to_live',
|
||||
collapseKey: 'collapse_key',
|
||||
mutableContent: 'mutable_content',
|
||||
contentAvailable: 'content_available',
|
||||
restrictedPackageName: 'restricted_package_name',
|
||||
};
|
||||
// Key renames for the MessagingDeviceResult object.
|
||||
var MESSAGING_DEVICE_RESULT_KEYS_MAP = {
|
||||
message_id: 'messageId',
|
||||
registration_id: 'canonicalRegistrationToken',
|
||||
};
|
||||
// Key renames for the MessagingDevicesResponse object.
|
||||
var MESSAGING_DEVICES_RESPONSE_KEYS_MAP = {
|
||||
canonical_ids: 'canonicalRegistrationTokenCount',
|
||||
failure: 'failureCount',
|
||||
success: 'successCount',
|
||||
multicast_id: 'multicastId',
|
||||
};
|
||||
// Key renames for the MessagingDeviceGroupResponse object.
|
||||
var MESSAGING_DEVICE_GROUP_RESPONSE_KEYS_MAP = {
|
||||
success: 'successCount',
|
||||
failure: 'failureCount',
|
||||
failed_registration_ids: 'failedRegistrationTokens',
|
||||
};
|
||||
// Key renames for the MessagingTopicResponse object.
|
||||
var MESSAGING_TOPIC_RESPONSE_KEYS_MAP = {
|
||||
message_id: 'messageId',
|
||||
};
|
||||
// Key renames for the MessagingConditionResponse object.
|
||||
var MESSAGING_CONDITION_RESPONSE_KEYS_MAP = {
|
||||
message_id: 'messageId',
|
||||
};
|
||||
// Keys which are not allowed in the messaging data payload object.
|
||||
exports.BLACKLISTED_DATA_PAYLOAD_KEYS = ['from'];
|
||||
// Keys which are not allowed in the messaging options object.
|
||||
exports.BLACKLISTED_OPTIONS_KEYS = [
|
||||
'condition', 'data', 'notification', 'registrationIds', 'registration_ids', 'to',
|
||||
];
|
||||
/**
|
||||
* Maps a raw FCM server response to a MessagingDevicesResponse object.
|
||||
*
|
||||
* @param {object} response The raw FCM server response to map.
|
||||
*
|
||||
* @return {MessagingDeviceGroupResponse} The mapped MessagingDevicesResponse object.
|
||||
*/
|
||||
function mapRawResponseToDevicesResponse(response) {
|
||||
// Rename properties on the server response
|
||||
utils.renameProperties(response, MESSAGING_DEVICES_RESPONSE_KEYS_MAP);
|
||||
if ('results' in response) {
|
||||
response.results.forEach(function (messagingDeviceResult) {
|
||||
utils.renameProperties(messagingDeviceResult, MESSAGING_DEVICE_RESULT_KEYS_MAP);
|
||||
// Map the FCM server's error strings to actual error objects.
|
||||
if ('error' in messagingDeviceResult) {
|
||||
var newError = error_1.FirebaseMessagingError.fromServerError(messagingDeviceResult.error, /* message */ undefined, messagingDeviceResult.error);
|
||||
messagingDeviceResult.error = newError;
|
||||
}
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Maps a raw FCM server response to a MessagingDeviceGroupResponse object.
|
||||
*
|
||||
* @param {object} response The raw FCM server response to map.
|
||||
*
|
||||
* @return {MessagingDeviceGroupResponse} The mapped MessagingDeviceGroupResponse object.
|
||||
*/
|
||||
function mapRawResponseToDeviceGroupResponse(response) {
|
||||
// Rename properties on the server response
|
||||
utils.renameProperties(response, MESSAGING_DEVICE_GROUP_RESPONSE_KEYS_MAP);
|
||||
// Add the 'failedRegistrationTokens' property if it does not exist on the response, which
|
||||
// it won't when the 'failureCount' property has a value of 0)
|
||||
response.failedRegistrationTokens = response.failedRegistrationTokens || [];
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Maps a raw FCM server response to a MessagingTopicManagementResponse object.
|
||||
*
|
||||
* @param {object} response The raw FCM server response to map.
|
||||
*
|
||||
* @return {MessagingTopicManagementResponse} The mapped MessagingTopicManagementResponse object.
|
||||
*/
|
||||
function mapRawResponseToTopicManagementResponse(response) {
|
||||
// Add the success and failure counts.
|
||||
var result = {
|
||||
successCount: 0,
|
||||
failureCount: 0,
|
||||
errors: [],
|
||||
};
|
||||
var errors = [];
|
||||
if ('results' in response) {
|
||||
response.results.forEach(function (tokenManagementResult, index) {
|
||||
// Map the FCM server's error strings to actual error objects.
|
||||
if ('error' in tokenManagementResult) {
|
||||
result.failureCount += 1;
|
||||
var newError = error_1.FirebaseMessagingError.fromTopicManagementServerError(tokenManagementResult.error, /* message */ undefined, tokenManagementResult.error);
|
||||
result.errors.push({
|
||||
index: index,
|
||||
error: newError,
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.successCount += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Internals of a Messaging instance.
|
||||
*/
|
||||
var MessagingInternals = /** @class */ (function () {
|
||||
function MessagingInternals() {
|
||||
}
|
||||
/**
|
||||
* Deletes the service and its associated resources.
|
||||
*
|
||||
* @return {Promise<()>} An empty Promise that will be fulfilled when the service is deleted.
|
||||
*/
|
||||
MessagingInternals.prototype.delete = function () {
|
||||
// There are no resources to clean up.
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
return MessagingInternals;
|
||||
}());
|
||||
/**
|
||||
* Messaging service bound to the provided app.
|
||||
*/
|
||||
var Messaging = /** @class */ (function () {
|
||||
/**
|
||||
* @param {FirebaseApp} app The app for this Messaging service.
|
||||
* @constructor
|
||||
*/
|
||||
function Messaging(app) {
|
||||
this.INTERNAL = new MessagingInternals();
|
||||
if (!validator.isNonNullObject(app) || !('options' in app)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'First argument passed to admin.messaging() must be a valid Firebase app instance.');
|
||||
}
|
||||
var projectId = utils.getProjectId(app);
|
||||
if (!validator.isNonEmptyString(projectId)) {
|
||||
// Assert for an explicit projct ID (either via AppOptions or the cert itself).
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'Failed to determine project ID for Messaging. Initialize the '
|
||||
+ 'SDK with service account credentials or set project ID as an app option. '
|
||||
+ 'Alternatively set the GOOGLE_CLOUD_PROJECT environment variable.');
|
||||
}
|
||||
this.urlPath = "/v1/projects/" + projectId + "/messages:send";
|
||||
this.appInternal = app;
|
||||
this.messagingRequestHandler = new messaging_api_request_1.FirebaseMessagingRequestHandler(app);
|
||||
}
|
||||
Object.defineProperty(Messaging.prototype, "app", {
|
||||
/**
|
||||
* Returns the app associated with this Messaging instance.
|
||||
*
|
||||
* @return {FirebaseApp} The app associated with this Messaging instance.
|
||||
*/
|
||||
get: function () {
|
||||
return this.appInternal;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
/**
|
||||
* Sends a message via Firebase Cloud Messaging (FCM).
|
||||
*
|
||||
* @param {Message} message The message to be sent.
|
||||
* @param {boolean=} dryRun Whether to send the message in the dry-run (validation only) mode.
|
||||
*
|
||||
* @return {Promise<string>} A Promise fulfilled with a message ID string.
|
||||
*/
|
||||
Messaging.prototype.send = function (message, dryRun) {
|
||||
var _this = this;
|
||||
var copy = deep_copy_1.deepCopy(message);
|
||||
messaging_types_1.validateMessage(copy);
|
||||
if (typeof dryRun !== 'undefined' && !validator.isBoolean(dryRun)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'dryRun must be a boolean');
|
||||
}
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
var request = { message: copy };
|
||||
if (dryRun) {
|
||||
request.validate_only = true;
|
||||
}
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, _this.urlPath, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
return response.name;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Sends all the messages in the given array via Firebase Cloud Messaging. Employs batching to
|
||||
* send the entire list as a single RPC call. Compared to the send() method, this method is a
|
||||
* significantly more efficient way to send multiple messages.
|
||||
*
|
||||
* The responses list obtained from the return value corresponds to the order of input messages.
|
||||
* An error from this method indicates a total failure -- i.e. none of the messages in the
|
||||
* list could be sent. Partial failures are indicated by a BatchResponse return value.
|
||||
*
|
||||
* @param {Message[]} messages A non-empty array containing up to 100 messages.
|
||||
* @param {boolean=} dryRun Whether to send the message in the dry-run (validation only) mode.
|
||||
*
|
||||
* @return {Promise<BatchResponse>} A Promise fulfilled with an object representing the result
|
||||
* of the send operation.
|
||||
*/
|
||||
Messaging.prototype.sendAll = function (messages, dryRun) {
|
||||
var _this = this;
|
||||
if (validator.isArray(messages) && messages.constructor !== Array) {
|
||||
// In more recent JS specs, an array-like object might have a constructor that is not of
|
||||
// Array type. Our deepCopy() method doesn't handle them properly. Convert such objects to
|
||||
// a regular array here before calling deepCopy(). See issue #566 for details.
|
||||
messages = Array.from(messages);
|
||||
}
|
||||
var copy = deep_copy_1.deepCopy(messages);
|
||||
if (!validator.isNonEmptyArray(copy)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'messages must be a non-empty array');
|
||||
}
|
||||
if (copy.length > FCM_MAX_BATCH_SIZE) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, "messages list must not contain more than " + FCM_MAX_BATCH_SIZE + " items");
|
||||
}
|
||||
if (typeof dryRun !== 'undefined' && !validator.isBoolean(dryRun)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'dryRun must be a boolean');
|
||||
}
|
||||
var requests = copy.map(function (message) {
|
||||
messaging_types_1.validateMessage(message);
|
||||
var request = { message: message };
|
||||
if (dryRun) {
|
||||
request.validate_only = true;
|
||||
}
|
||||
return {
|
||||
url: "https://" + FCM_SEND_HOST + _this.urlPath,
|
||||
body: request,
|
||||
};
|
||||
});
|
||||
return this.messagingRequestHandler.sendBatchRequest(requests);
|
||||
};
|
||||
/**
|
||||
* Sends the given multicast message to all the FCM registration tokens specified in it.
|
||||
*
|
||||
* This method uses the sendAll() API under the hood to send the given
|
||||
* message to all the target recipients. The responses list obtained from the return value
|
||||
* corresponds to the order of tokens in the MulticastMessage. An error from this method
|
||||
* indicates a total failure -- i.e. none of the tokens in the list could be sent to. Partial
|
||||
* failures are indicated by a BatchResponse return value.
|
||||
*
|
||||
* @param {MulticastMessage} message A multicast message containing up to 100 tokens.
|
||||
* @param {boolean=} dryRun Whether to send the message in the dry-run (validation only) mode.
|
||||
*
|
||||
* @return {Promise<BatchResponse>} A Promise fulfilled with an object representing the result
|
||||
* of the send operation.
|
||||
*/
|
||||
Messaging.prototype.sendMulticast = function (message, dryRun) {
|
||||
var copy = deep_copy_1.deepCopy(message);
|
||||
if (!validator.isNonNullObject(copy)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'MulticastMessage must be a non-null object');
|
||||
}
|
||||
if (!validator.isNonEmptyArray(copy.tokens)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'tokens must be a non-empty array');
|
||||
}
|
||||
if (copy.tokens.length > FCM_MAX_BATCH_SIZE) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, "tokens list must not contain more than " + FCM_MAX_BATCH_SIZE + " items");
|
||||
}
|
||||
var messages = copy.tokens.map(function (token) {
|
||||
return {
|
||||
token: token,
|
||||
android: copy.android,
|
||||
apns: copy.apns,
|
||||
data: copy.data,
|
||||
notification: copy.notification,
|
||||
webpush: copy.webpush,
|
||||
};
|
||||
});
|
||||
return this.sendAll(messages, dryRun);
|
||||
};
|
||||
/**
|
||||
* Sends an FCM message to a single device or an array of devices.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
||||
* registration tokens for the device(s) to which to send the message.
|
||||
* @param {MessagingPayload} payload The message payload.
|
||||
* @param {MessagingOptions} [options = {}] Optional options to alter the message.
|
||||
*
|
||||
* @return {Promise<MessagingDevicesResponse|MessagingDeviceGroupResponse>} A Promise fulfilled
|
||||
* with the server's response after the message has been sent.
|
||||
*/
|
||||
Messaging.prototype.sendToDevice = function (registrationTokenOrTokens, payload, options) {
|
||||
var _this = this;
|
||||
if (options === void 0) { options = {}; }
|
||||
// Validate the input argument types. Since these are common developer errors when getting
|
||||
// started, throw an error instead of returning a rejected promise.
|
||||
this.validateRegistrationTokensType(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
||||
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
||||
// error will cause this method to return a rejected promise.
|
||||
_this.validateRegistrationTokens(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
||||
var payloadCopy = _this.validateMessagingPayload(payload);
|
||||
var optionsCopy = _this.validateMessagingOptions(options);
|
||||
var request = deep_copy_1.deepCopy(payloadCopy);
|
||||
deep_copy_1.deepExtend(request, optionsCopy);
|
||||
if (validator.isString(registrationTokenOrTokens)) {
|
||||
request.to = registrationTokenOrTokens;
|
||||
}
|
||||
else {
|
||||
request.registration_ids = registrationTokenOrTokens;
|
||||
}
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
||||
// the underlying FCM request. If the provided registration token argument is actually a
|
||||
// valid notification key, the response from the FCM server will be a device group response.
|
||||
// If that is the case, we map the response to a MessagingDeviceGroupResponse.
|
||||
// See b/35394951 for more context.
|
||||
if ('multicast_id' in response) {
|
||||
return mapRawResponseToDevicesResponse(response);
|
||||
}
|
||||
else {
|
||||
return mapRawResponseToDeviceGroupResponse(response);
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Sends an FCM message to a device group.
|
||||
*
|
||||
* @param {string} notificationKey The notification key representing the device group to which to
|
||||
* send the message.
|
||||
* @param {MessagingPayload} payload The message payload.
|
||||
* @param {MessagingOptions} [options = {}] Optional options to alter the message.
|
||||
*
|
||||
* @return {Promise<MessagingDeviceGroupResponse|MessagingDevicesResponse>} A Promise fulfilled
|
||||
* with the server's response after the message has been sent.
|
||||
*/
|
||||
Messaging.prototype.sendToDeviceGroup = function (notificationKey, payload, options) {
|
||||
var _this = this;
|
||||
if (options === void 0) { options = {}; }
|
||||
if (!validator.isNonEmptyString(notificationKey)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() must be a non-empty string.');
|
||||
}
|
||||
else if (notificationKey.indexOf(':') !== -1) {
|
||||
// It is possible the developer provides a registration token instead of a notification key
|
||||
// to this method. We can detect some of those cases by checking to see if the string contains
|
||||
// a colon. Not all registration tokens will contain a colon (only newer ones will), but no
|
||||
// notification keys will contain a colon, so we can use it as a rough heuristic.
|
||||
// See b/35394951 for more context.
|
||||
return Promise.reject(new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() has the format of a registration token. ' +
|
||||
'You should use sendToDevice() instead.'));
|
||||
}
|
||||
// Validate the types of the payload and options arguments. Since these are common developer
|
||||
// errors, throw an error instead of returning a rejected promise.
|
||||
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
// Validate the contents of the payload and options objects. Because we are now in a
|
||||
// promise, any thrown error will cause this method to return a rejected promise.
|
||||
var payloadCopy = _this.validateMessagingPayload(payload);
|
||||
var optionsCopy = _this.validateMessagingOptions(options);
|
||||
var request = deep_copy_1.deepCopy(payloadCopy);
|
||||
deep_copy_1.deepExtend(request, optionsCopy);
|
||||
request.to = notificationKey;
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
||||
// the underlying FCM request. If the provided notification key argument has an invalid
|
||||
// format (that is, it is either a registration token or some random string), the response
|
||||
// from the FCM server will default to a devices response (which we detect by looking for
|
||||
// the `multicast_id` property). If that is the case, we either throw an error saying the
|
||||
// provided notification key is invalid (if the message failed to send) or map the response
|
||||
// to a MessagingDevicesResponse (if the message succeeded).
|
||||
// See b/35394951 for more context.
|
||||
if ('multicast_id' in response) {
|
||||
if (response.success === 0) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() is invalid.');
|
||||
}
|
||||
else {
|
||||
return mapRawResponseToDevicesResponse(response);
|
||||
}
|
||||
}
|
||||
return mapRawResponseToDeviceGroupResponse(response);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Sends an FCM message to a topic.
|
||||
*
|
||||
* @param {string} topic The name of the topic to which to send the message.
|
||||
* @param {MessagingPayload} payload The message payload.
|
||||
* @param {MessagingOptions} [options = {}] Optional options to alter the message.
|
||||
*
|
||||
* @return {Promise<MessagingTopicResponse>} A Promise fulfilled with the server's response after
|
||||
* the message has been sent.
|
||||
*/
|
||||
Messaging.prototype.sendToTopic = function (topic, payload, options) {
|
||||
var _this = this;
|
||||
if (options === void 0) { options = {}; }
|
||||
// Validate the input argument types. Since these are common developer errors when getting
|
||||
// started, throw an error instead of returning a rejected promise.
|
||||
this.validateTopicType(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
||||
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
||||
// Prepend the topic with /topics/ if necessary.
|
||||
topic = this.normalizeTopic(topic);
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
// Validate the contents of the payload and options objects. Because we are now in a
|
||||
// promise, any thrown error will cause this method to return a rejected promise.
|
||||
var payloadCopy = _this.validateMessagingPayload(payload);
|
||||
var optionsCopy = _this.validateMessagingOptions(options);
|
||||
_this.validateTopic(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
||||
var request = deep_copy_1.deepCopy(payloadCopy);
|
||||
deep_copy_1.deepExtend(request, optionsCopy);
|
||||
request.to = topic;
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
// Rename properties on the server response
|
||||
utils.renameProperties(response, MESSAGING_TOPIC_RESPONSE_KEYS_MAP);
|
||||
return response;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Sends an FCM message to a condition.
|
||||
*
|
||||
* @param {string} condition The condition to which to send the message.
|
||||
* @param {MessagingPayload} payload The message payload.
|
||||
* @param {MessagingOptions} [options = {}] Optional options to alter the message.
|
||||
*
|
||||
* @return {Promise<MessagingConditionResponse>} A Promise fulfilled with the server's response
|
||||
* after the message has been sent.
|
||||
*/
|
||||
Messaging.prototype.sendToCondition = function (condition, payload, options) {
|
||||
var _this = this;
|
||||
if (options === void 0) { options = {}; }
|
||||
if (!validator.isNonEmptyString(condition)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Condition provided to sendToCondition() must be a non-empty string.');
|
||||
}
|
||||
// Validate the types of the payload and options arguments. Since these are common developer
|
||||
// errors, throw an error instead of returning a rejected promise.
|
||||
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
||||
// The FCM server rejects conditions which are surrounded in single quotes. When the condition
|
||||
// is stringified over the wire, double quotes in it get converted to \" which the FCM server
|
||||
// does not properly handle. We can get around this by replacing internal double quotes with
|
||||
// single quotes.
|
||||
condition = condition.replace(/"/g, '\'');
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
// Validate the contents of the payload and options objects. Because we are now in a
|
||||
// promise, any thrown error will cause this method to return a rejected promise.
|
||||
var payloadCopy = _this.validateMessagingPayload(payload);
|
||||
var optionsCopy = _this.validateMessagingOptions(options);
|
||||
var request = deep_copy_1.deepCopy(payloadCopy);
|
||||
deep_copy_1.deepExtend(request, optionsCopy);
|
||||
request.condition = condition;
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
// Rename properties on the server response
|
||||
utils.renameProperties(response, MESSAGING_CONDITION_RESPONSE_KEYS_MAP);
|
||||
return response;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Subscribes a single device or an array of devices to a topic.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
||||
* registration tokens to subscribe to the topic.
|
||||
* @param {string} topic The topic to which to subscribe.
|
||||
*
|
||||
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed FCM
|
||||
* server response.
|
||||
*/
|
||||
Messaging.prototype.subscribeToTopic = function (registrationTokenOrTokens, topic) {
|
||||
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'subscribeToTopic', FCM_TOPIC_MANAGEMENT_ADD_PATH);
|
||||
};
|
||||
/**
|
||||
* Unsubscribes a single device or an array of devices from a topic.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
||||
* registration tokens to unsubscribe from the topic.
|
||||
* @param {string} topic The topic to which to subscribe.
|
||||
*
|
||||
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed FCM
|
||||
* server response.
|
||||
*/
|
||||
Messaging.prototype.unsubscribeFromTopic = function (registrationTokenOrTokens, topic) {
|
||||
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'unsubscribeFromTopic', FCM_TOPIC_MANAGEMENT_REMOVE_PATH);
|
||||
};
|
||||
/**
|
||||
* Helper method which sends and handles topic subscription management requests.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
||||
* registration tokens to unsubscribe from the topic.
|
||||
* @param {string} topic The topic to which to subscribe.
|
||||
* @param {string} methodName The name of the original method called.
|
||||
* @param {string} path The endpoint path to use for the request.
|
||||
*
|
||||
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed server
|
||||
* response.
|
||||
*/
|
||||
Messaging.prototype.sendTopicManagementRequest = function (registrationTokenOrTokens, topic, methodName, path) {
|
||||
var _this = this;
|
||||
this.validateRegistrationTokensType(registrationTokenOrTokens, methodName);
|
||||
this.validateTopicType(topic, methodName);
|
||||
// Prepend the topic with /topics/ if necessary.
|
||||
topic = this.normalizeTopic(topic);
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
||||
// error will cause this method to return a rejected promise.
|
||||
_this.validateRegistrationTokens(registrationTokenOrTokens, methodName);
|
||||
_this.validateTopic(topic, methodName);
|
||||
// Ensure the registration token(s) input argument is an array.
|
||||
var registrationTokensArray = registrationTokenOrTokens;
|
||||
if (validator.isString(registrationTokenOrTokens)) {
|
||||
registrationTokensArray = [registrationTokenOrTokens];
|
||||
}
|
||||
var request = {
|
||||
to: topic,
|
||||
registration_tokens: registrationTokensArray,
|
||||
};
|
||||
return _this.messagingRequestHandler.invokeRequestHandler(FCM_TOPIC_MANAGEMENT_HOST, path, request);
|
||||
})
|
||||
.then(function (response) {
|
||||
return mapRawResponseToTopicManagementResponse(response);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Validates the types of the messaging payload and options. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {MessagingPayload} payload The messaging payload to validate.
|
||||
* @param {MessagingOptions} options The messaging options to validate.
|
||||
*/
|
||||
Messaging.prototype.validateMessagingPayloadAndOptionsTypes = function (payload, options) {
|
||||
// Validate the payload is an object
|
||||
if (!validator.isNonNullObject(payload)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Messaging payload must be an object with at least one of the "data" or "notification" properties.');
|
||||
}
|
||||
// Validate the options argument is an object
|
||||
if (!validator.isNonNullObject(options)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, 'Messaging options must be an object.');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Validates the messaging payload. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {MessagingPayload} payload The messaging payload to validate.
|
||||
*
|
||||
* @return {MessagingPayload} A copy of the provided payload with whitelisted properties switched
|
||||
* from camelCase to underscore_case.
|
||||
*/
|
||||
Messaging.prototype.validateMessagingPayload = function (payload) {
|
||||
var payloadCopy = deep_copy_1.deepCopy(payload);
|
||||
var payloadKeys = Object.keys(payloadCopy);
|
||||
var validPayloadKeys = ['data', 'notification'];
|
||||
var containsDataOrNotificationKey = false;
|
||||
payloadKeys.forEach(function (payloadKey) {
|
||||
// Validate the payload does not contain any invalid keys
|
||||
if (validPayloadKeys.indexOf(payloadKey) === -1) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid \"" + payloadKey + "\" property. Valid properties are " +
|
||||
"\"data\" and \"notification\".");
|
||||
}
|
||||
else {
|
||||
containsDataOrNotificationKey = true;
|
||||
}
|
||||
});
|
||||
// Validate the payload contains at least one of the "data" and "notification" keys
|
||||
if (!containsDataOrNotificationKey) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Messaging payload must contain at least one of the "data" or "notification" properties.');
|
||||
}
|
||||
payloadKeys.forEach(function (payloadKey) {
|
||||
var value = payloadCopy[payloadKey];
|
||||
// Validate each top-level key in the payload is an object
|
||||
if (!validator.isNonNullObject(value)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid value for the \"" + payloadKey + "\" property. " +
|
||||
"Value must be an object.");
|
||||
}
|
||||
Object.keys(value).forEach(function (subKey) {
|
||||
if (!validator.isString(value[subKey])) {
|
||||
// Validate all sub-keys have a string value
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid value for the \"" + payloadKey + "." + subKey + "\" " +
|
||||
"property. Values must be strings.");
|
||||
}
|
||||
else if (payloadKey === 'data' && /^google\./.test(subKey)) {
|
||||
// Validate the data payload does not contain keys which start with 'google.'.
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains the blacklisted \"data." + subKey + "\" property.");
|
||||
}
|
||||
});
|
||||
});
|
||||
// Validate the data payload object does not contain blacklisted properties
|
||||
if ('data' in payloadCopy) {
|
||||
exports.BLACKLISTED_DATA_PAYLOAD_KEYS.forEach(function (blacklistedKey) {
|
||||
if (blacklistedKey in payloadCopy.data) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains the blacklisted \"data." + blacklistedKey + "\" property.");
|
||||
}
|
||||
});
|
||||
}
|
||||
// Convert whitelisted camelCase keys to underscore_case
|
||||
if ('notification' in payloadCopy) {
|
||||
utils.renameProperties(payloadCopy.notification, CAMELCASED_NOTIFICATION_PAYLOAD_KEYS_MAP);
|
||||
}
|
||||
return payloadCopy;
|
||||
};
|
||||
/**
|
||||
* Validates the messaging options. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {MessagingOptions} options The messaging options to validate.
|
||||
*
|
||||
* @return {MessagingOptions} A copy of the provided options with whitelisted properties switched
|
||||
* from camelCase to underscore_case.
|
||||
*/
|
||||
Messaging.prototype.validateMessagingOptions = function (options) {
|
||||
var optionsCopy = deep_copy_1.deepCopy(options);
|
||||
// Validate the options object does not contain blacklisted properties
|
||||
exports.BLACKLISTED_OPTIONS_KEYS.forEach(function (blacklistedKey) {
|
||||
if (blacklistedKey in optionsCopy) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains the blacklisted \"" + blacklistedKey + "\" property.");
|
||||
}
|
||||
});
|
||||
// Convert whitelisted camelCase keys to underscore_case
|
||||
utils.renameProperties(optionsCopy, CAMELCASE_OPTIONS_KEYS_MAP);
|
||||
// Validate the options object contains valid values for whitelisted properties
|
||||
if ('collapse_key' in optionsCopy && !validator.isNonEmptyString(optionsCopy.collapse_key)) {
|
||||
var keyName = ('collapseKey' in options) ? 'collapseKey' : 'collapse_key';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a non-empty string.');
|
||||
}
|
||||
else if ('dry_run' in optionsCopy && !validator.isBoolean(optionsCopy.dry_run)) {
|
||||
var keyName = ('dryRun' in options) ? 'dryRun' : 'dry_run';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a boolean.');
|
||||
}
|
||||
else if ('priority' in optionsCopy && !validator.isNonEmptyString(optionsCopy.priority)) {
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, 'Messaging options contains an invalid value for the "priority" property. Value must ' +
|
||||
'be a non-empty string.');
|
||||
}
|
||||
else if ('restricted_package_name' in optionsCopy &&
|
||||
!validator.isNonEmptyString(optionsCopy.restricted_package_name)) {
|
||||
var keyName = ('restrictedPackageName' in options) ? 'restrictedPackageName' : 'restricted_package_name';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a non-empty string.');
|
||||
}
|
||||
else if ('time_to_live' in optionsCopy && !validator.isNumber(optionsCopy.time_to_live)) {
|
||||
var keyName = ('timeToLive' in options) ? 'timeToLive' : 'time_to_live';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a number.');
|
||||
}
|
||||
else if ('content_available' in optionsCopy && !validator.isBoolean(optionsCopy.content_available)) {
|
||||
var keyName = ('contentAvailable' in options) ? 'contentAvailable' : 'content_available';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a boolean.');
|
||||
}
|
||||
else if ('mutable_content' in optionsCopy && !validator.isBoolean(optionsCopy.mutable_content)) {
|
||||
var keyName = ('mutableContent' in options) ? 'mutableContent' : 'mutable_content';
|
||||
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
||||
'be a boolean.');
|
||||
}
|
||||
return optionsCopy;
|
||||
};
|
||||
/**
|
||||
* Validates the type of the provided registration token(s). If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token(s) to validate.
|
||||
* @param {string} method The method name to use in error messages.
|
||||
* @param {ErrorInfo?} [errorInfo] The error info to use if the registration tokens are invalid.
|
||||
*/
|
||||
Messaging.prototype.validateRegistrationTokensType = function (registrationTokenOrTokens, methodName, errorInfo) {
|
||||
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
||||
if (!validator.isNonEmptyArray(registrationTokenOrTokens) &&
|
||||
!validator.isNonEmptyString(registrationTokenOrTokens)) {
|
||||
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token(s) provided to " + methodName + "() must be a non-empty string or a " +
|
||||
'non-empty array.');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Validates the provided registration tokens. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
||||
* registration tokens to validate.
|
||||
* @param {string} method The method name to use in error messages.
|
||||
* @param {errorInfo?} [ErrorInfo] The error info to use if the registration tokens are invalid.
|
||||
*/
|
||||
Messaging.prototype.validateRegistrationTokens = function (registrationTokenOrTokens, methodName, errorInfo) {
|
||||
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
||||
if (validator.isArray(registrationTokenOrTokens)) {
|
||||
// Validate the array contains no more than 1,000 registration tokens.
|
||||
if (registrationTokenOrTokens.length > 1000) {
|
||||
throw new error_1.FirebaseMessagingError(errorInfo, "Too many registration tokens provided in a single request to " + methodName + "(). Batch " +
|
||||
'your requests to contain no more than 1,000 registration tokens per request.');
|
||||
}
|
||||
// Validate the array contains registration tokens which are non-empty strings.
|
||||
registrationTokenOrTokens.forEach(function (registrationToken, index) {
|
||||
if (!validator.isNonEmptyString(registrationToken)) {
|
||||
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token provided to " + methodName + "() at index " + index + " must be a " +
|
||||
'non-empty string.');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Validates the type of the provided topic. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {string} topic The topic to validate.
|
||||
* @param {string} method The method name to use in error messages.
|
||||
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
||||
*/
|
||||
Messaging.prototype.validateTopicType = function (topic, methodName, errorInfo) {
|
||||
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
||||
if (!validator.isNonEmptyString(topic)) {
|
||||
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
||||
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Validates the provided topic. If invalid, an error will be thrown.
|
||||
*
|
||||
* @param {string} topic The topic to validate.
|
||||
* @param {string} method The method name to use in error messages.
|
||||
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
||||
*/
|
||||
Messaging.prototype.validateTopic = function (topic, methodName, errorInfo) {
|
||||
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
||||
if (!validator.isTopic(topic)) {
|
||||
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
||||
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Normalizes the provided topic name by prepending it with '/topics/', if necessary.
|
||||
*
|
||||
* @param {string} topic The topic name to normalize.
|
||||
*
|
||||
* @return {string} The normalized topic name.
|
||||
*/
|
||||
Messaging.prototype.normalizeTopic = function (topic) {
|
||||
if (!/^\/topics\//.test(topic)) {
|
||||
topic = "/topics/" + topic;
|
||||
}
|
||||
return topic;
|
||||
};
|
||||
return Messaging;
|
||||
}());
|
||||
exports.Messaging = Messaging;
|
Reference in New Issue
Block a user