firebase-admin 9.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +90 -0
- package/lib/app-check/app-check-api-client-internal.js +197 -0
- package/lib/app-check/app-check.js +79 -0
- package/lib/app-check/index.d.ts +160 -0
- package/lib/app-check/index.js +19 -0
- package/lib/app-check/token-generator.js +161 -0
- package/lib/app-check/token-verifier.js +152 -0
- package/lib/auth/action-code-settings-builder.js +118 -0
- package/lib/auth/auth-api-request.js +1856 -0
- package/lib/auth/auth-config.js +636 -0
- package/lib/auth/auth.js +836 -0
- package/lib/auth/identifier.js +40 -0
- package/lib/auth/index.d.ts +1927 -0
- package/lib/auth/index.js +18 -0
- package/lib/auth/tenant-manager.js +140 -0
- package/lib/auth/tenant.js +171 -0
- package/lib/auth/token-generator.js +200 -0
- package/lib/auth/token-verifier.js +259 -0
- package/lib/auth/user-import-builder.js +387 -0
- package/lib/auth/user-record.js +346 -0
- package/lib/credential/credential-internal.js +391 -0
- package/lib/credential/credential.js +44 -0
- package/lib/credential/index.d.ts +169 -0
- package/lib/credential/index.js +23 -0
- package/lib/database/database-internal.js +266 -0
- package/lib/database/index.d.ts +89 -0
- package/lib/database/index.js +31 -0
- package/lib/default-namespace.js +31 -0
- package/lib/firebase-app.js +349 -0
- package/lib/firebase-namespace-api.d.ts +243 -0
- package/lib/firebase-namespace-api.js +18 -0
- package/lib/firebase-namespace.d.ts +31 -0
- package/lib/firebase-namespace.js +417 -0
- package/lib/firestore/firestore-internal.js +105 -0
- package/lib/firestore/index.d.ts +50 -0
- package/lib/firestore/index.js +47 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +27 -0
- package/lib/installations/index.d.ts +81 -0
- package/lib/installations/index.js +18 -0
- package/lib/installations/installations-request-handler.js +117 -0
- package/lib/installations/installations.js +62 -0
- package/lib/instance-id/index.d.ts +83 -0
- package/lib/instance-id/index.js +18 -0
- package/lib/instance-id/instance-id.js +87 -0
- package/lib/machine-learning/index.d.ts +249 -0
- package/lib/machine-learning/index.js +18 -0
- package/lib/machine-learning/machine-learning-api-client.js +304 -0
- package/lib/machine-learning/machine-learning-utils.js +62 -0
- package/lib/machine-learning/machine-learning.js +364 -0
- package/lib/messaging/batch-request-internal.js +129 -0
- package/lib/messaging/index.d.ts +1174 -0
- package/lib/messaging/index.js +18 -0
- package/lib/messaging/messaging-api-request-internal.js +128 -0
- package/lib/messaging/messaging-errors-internal.js +106 -0
- package/lib/messaging/messaging-internal.js +484 -0
- package/lib/messaging/messaging.js +846 -0
- package/lib/project-management/android-app.js +176 -0
- package/lib/project-management/index.d.ts +363 -0
- package/lib/project-management/index.js +41 -0
- package/lib/project-management/ios-app.js +88 -0
- package/lib/project-management/project-management-api-request-internal.js +273 -0
- package/lib/project-management/project-management.js +254 -0
- package/lib/remote-config/index.d.ts +369 -0
- package/lib/remote-config/index.js +18 -0
- package/lib/remote-config/remote-config-api-client-internal.js +407 -0
- package/lib/remote-config/remote-config.js +304 -0
- package/lib/security-rules/index.d.ts +216 -0
- package/lib/security-rules/index.js +18 -0
- package/lib/security-rules/security-rules-api-client-internal.js +237 -0
- package/lib/security-rules/security-rules-internal.js +41 -0
- package/lib/security-rules/security-rules.js +310 -0
- package/lib/storage/index.d.ts +60 -0
- package/lib/storage/index.js +18 -0
- package/lib/storage/storage.js +123 -0
- package/lib/utils/api-request.js +845 -0
- package/lib/utils/crypto-signer.js +237 -0
- package/lib/utils/deep-copy.js +78 -0
- package/lib/utils/error.js +1063 -0
- package/lib/utils/index.js +217 -0
- package/lib/utils/jwt.js +355 -0
- package/lib/utils/validator.js +271 -0
- package/package.json +122 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
/*! firebase-admin v9.12.0 */
|
|
2
|
+
"use strict";
|
|
3
|
+
/*!
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2017 Google Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
var __assign = (this && this.__assign) || function () {
|
|
20
|
+
__assign = Object.assign || function(t) {
|
|
21
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
22
|
+
s = arguments[i];
|
|
23
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
24
|
+
t[p] = s[p];
|
|
25
|
+
}
|
|
26
|
+
return t;
|
|
27
|
+
};
|
|
28
|
+
return __assign.apply(this, arguments);
|
|
29
|
+
};
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.Messaging = void 0;
|
|
32
|
+
var deep_copy_1 = require("../utils/deep-copy");
|
|
33
|
+
var messaging_internal_1 = require("./messaging-internal");
|
|
34
|
+
var messaging_api_request_internal_1 = require("./messaging-api-request-internal");
|
|
35
|
+
var error_1 = require("../utils/error");
|
|
36
|
+
var utils = require("../utils");
|
|
37
|
+
var validator = require("../utils/validator");
|
|
38
|
+
/* eslint-disable @typescript-eslint/camelcase */
|
|
39
|
+
// FCM endpoints
|
|
40
|
+
var FCM_SEND_HOST = 'fcm.googleapis.com';
|
|
41
|
+
var FCM_SEND_PATH = '/fcm/send';
|
|
42
|
+
var FCM_TOPIC_MANAGEMENT_HOST = 'iid.googleapis.com';
|
|
43
|
+
var FCM_TOPIC_MANAGEMENT_ADD_PATH = '/iid/v1:batchAdd';
|
|
44
|
+
var FCM_TOPIC_MANAGEMENT_REMOVE_PATH = '/iid/v1:batchRemove';
|
|
45
|
+
// Maximum messages that can be included in a batch request.
|
|
46
|
+
var FCM_MAX_BATCH_SIZE = 500;
|
|
47
|
+
// Key renames for the messaging notification payload object.
|
|
48
|
+
var CAMELCASED_NOTIFICATION_PAYLOAD_KEYS_MAP = {
|
|
49
|
+
bodyLocArgs: 'body_loc_args',
|
|
50
|
+
bodyLocKey: 'body_loc_key',
|
|
51
|
+
clickAction: 'click_action',
|
|
52
|
+
titleLocArgs: 'title_loc_args',
|
|
53
|
+
titleLocKey: 'title_loc_key',
|
|
54
|
+
};
|
|
55
|
+
// Key renames for the messaging options object.
|
|
56
|
+
var CAMELCASE_OPTIONS_KEYS_MAP = {
|
|
57
|
+
dryRun: 'dry_run',
|
|
58
|
+
timeToLive: 'time_to_live',
|
|
59
|
+
collapseKey: 'collapse_key',
|
|
60
|
+
mutableContent: 'mutable_content',
|
|
61
|
+
contentAvailable: 'content_available',
|
|
62
|
+
restrictedPackageName: 'restricted_package_name',
|
|
63
|
+
};
|
|
64
|
+
// Key renames for the MessagingDeviceResult object.
|
|
65
|
+
var MESSAGING_DEVICE_RESULT_KEYS_MAP = {
|
|
66
|
+
message_id: 'messageId',
|
|
67
|
+
registration_id: 'canonicalRegistrationToken',
|
|
68
|
+
};
|
|
69
|
+
// Key renames for the MessagingDevicesResponse object.
|
|
70
|
+
var MESSAGING_DEVICES_RESPONSE_KEYS_MAP = {
|
|
71
|
+
canonical_ids: 'canonicalRegistrationTokenCount',
|
|
72
|
+
failure: 'failureCount',
|
|
73
|
+
success: 'successCount',
|
|
74
|
+
multicast_id: 'multicastId',
|
|
75
|
+
};
|
|
76
|
+
// Key renames for the MessagingDeviceGroupResponse object.
|
|
77
|
+
var MESSAGING_DEVICE_GROUP_RESPONSE_KEYS_MAP = {
|
|
78
|
+
success: 'successCount',
|
|
79
|
+
failure: 'failureCount',
|
|
80
|
+
failed_registration_ids: 'failedRegistrationTokens',
|
|
81
|
+
};
|
|
82
|
+
// Key renames for the MessagingTopicResponse object.
|
|
83
|
+
var MESSAGING_TOPIC_RESPONSE_KEYS_MAP = {
|
|
84
|
+
message_id: 'messageId',
|
|
85
|
+
};
|
|
86
|
+
// Key renames for the MessagingConditionResponse object.
|
|
87
|
+
var MESSAGING_CONDITION_RESPONSE_KEYS_MAP = {
|
|
88
|
+
message_id: 'messageId',
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Maps a raw FCM server response to a MessagingDevicesResponse object.
|
|
92
|
+
*
|
|
93
|
+
* @param {object} response The raw FCM server response to map.
|
|
94
|
+
*
|
|
95
|
+
* @return {MessagingDeviceGroupResponse} The mapped MessagingDevicesResponse object.
|
|
96
|
+
*/
|
|
97
|
+
function mapRawResponseToDevicesResponse(response) {
|
|
98
|
+
// Rename properties on the server response
|
|
99
|
+
utils.renameProperties(response, MESSAGING_DEVICES_RESPONSE_KEYS_MAP);
|
|
100
|
+
if ('results' in response) {
|
|
101
|
+
response.results.forEach(function (messagingDeviceResult) {
|
|
102
|
+
utils.renameProperties(messagingDeviceResult, MESSAGING_DEVICE_RESULT_KEYS_MAP);
|
|
103
|
+
// Map the FCM server's error strings to actual error objects.
|
|
104
|
+
if ('error' in messagingDeviceResult) {
|
|
105
|
+
var newError = error_1.FirebaseMessagingError.fromServerError(messagingDeviceResult.error, /* message */ undefined, messagingDeviceResult.error);
|
|
106
|
+
messagingDeviceResult.error = newError;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return response;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Maps a raw FCM server response to a MessagingDeviceGroupResponse object.
|
|
114
|
+
*
|
|
115
|
+
* @param {object} response The raw FCM server response to map.
|
|
116
|
+
*
|
|
117
|
+
* @return {MessagingDeviceGroupResponse} The mapped MessagingDeviceGroupResponse object.
|
|
118
|
+
*/
|
|
119
|
+
function mapRawResponseToDeviceGroupResponse(response) {
|
|
120
|
+
// Rename properties on the server response
|
|
121
|
+
utils.renameProperties(response, MESSAGING_DEVICE_GROUP_RESPONSE_KEYS_MAP);
|
|
122
|
+
// Add the 'failedRegistrationTokens' property if it does not exist on the response, which
|
|
123
|
+
// it won't when the 'failureCount' property has a value of 0)
|
|
124
|
+
response.failedRegistrationTokens = response.failedRegistrationTokens || [];
|
|
125
|
+
return response;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Maps a raw FCM server response to a MessagingTopicManagementResponse object.
|
|
129
|
+
*
|
|
130
|
+
* @param {object} response The raw FCM server response to map.
|
|
131
|
+
*
|
|
132
|
+
* @return {MessagingTopicManagementResponse} The mapped MessagingTopicManagementResponse object.
|
|
133
|
+
*/
|
|
134
|
+
function mapRawResponseToTopicManagementResponse(response) {
|
|
135
|
+
// Add the success and failure counts.
|
|
136
|
+
var result = {
|
|
137
|
+
successCount: 0,
|
|
138
|
+
failureCount: 0,
|
|
139
|
+
errors: [],
|
|
140
|
+
};
|
|
141
|
+
if ('results' in response) {
|
|
142
|
+
response.results.forEach(function (tokenManagementResult, index) {
|
|
143
|
+
// Map the FCM server's error strings to actual error objects.
|
|
144
|
+
if ('error' in tokenManagementResult) {
|
|
145
|
+
result.failureCount += 1;
|
|
146
|
+
var newError = error_1.FirebaseMessagingError.fromTopicManagementServerError(tokenManagementResult.error, /* message */ undefined, tokenManagementResult.error);
|
|
147
|
+
result.errors.push({
|
|
148
|
+
index: index,
|
|
149
|
+
error: newError,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
result.successCount += 1;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Messaging service bound to the provided app.
|
|
161
|
+
*/
|
|
162
|
+
var Messaging = /** @class */ (function () {
|
|
163
|
+
/**
|
|
164
|
+
* Gets the {@link messaging.Messaging `Messaging`} service for the
|
|
165
|
+
* current app.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```javascript
|
|
169
|
+
* var messaging = app.messaging();
|
|
170
|
+
* // The above is shorthand for:
|
|
171
|
+
* // var messaging = admin.messaging(app);
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @return The `Messaging` service for the current app.
|
|
175
|
+
*/
|
|
176
|
+
function Messaging(app) {
|
|
177
|
+
if (!validator.isNonNullObject(app) || !('options' in app)) {
|
|
178
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'First argument passed to admin.messaging() must be a valid Firebase app instance.');
|
|
179
|
+
}
|
|
180
|
+
this.appInternal = app;
|
|
181
|
+
this.messagingRequestHandler = new messaging_api_request_internal_1.FirebaseMessagingRequestHandler(app);
|
|
182
|
+
}
|
|
183
|
+
Object.defineProperty(Messaging.prototype, "app", {
|
|
184
|
+
/**
|
|
185
|
+
* Returns the app associated with this Messaging instance.
|
|
186
|
+
*
|
|
187
|
+
* @return {FirebaseApp} The app associated with this Messaging instance.
|
|
188
|
+
*/
|
|
189
|
+
get: function () {
|
|
190
|
+
return this.appInternal;
|
|
191
|
+
},
|
|
192
|
+
enumerable: false,
|
|
193
|
+
configurable: true
|
|
194
|
+
});
|
|
195
|
+
/**
|
|
196
|
+
* Sends the given message via FCM.
|
|
197
|
+
*
|
|
198
|
+
* @param message The message payload.
|
|
199
|
+
* @param dryRun Whether to send the message in the dry-run
|
|
200
|
+
* (validation only) mode.
|
|
201
|
+
* @return A promise fulfilled with a unique message ID
|
|
202
|
+
* string after the message has been successfully handed off to the FCM
|
|
203
|
+
* service for delivery.
|
|
204
|
+
*/
|
|
205
|
+
Messaging.prototype.send = function (message, dryRun) {
|
|
206
|
+
var _this = this;
|
|
207
|
+
var copy = deep_copy_1.deepCopy(message);
|
|
208
|
+
messaging_internal_1.validateMessage(copy);
|
|
209
|
+
if (typeof dryRun !== 'undefined' && !validator.isBoolean(dryRun)) {
|
|
210
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'dryRun must be a boolean');
|
|
211
|
+
}
|
|
212
|
+
return this.getUrlPath()
|
|
213
|
+
.then(function (urlPath) {
|
|
214
|
+
var request = { message: copy };
|
|
215
|
+
if (dryRun) {
|
|
216
|
+
request.validate_only = true;
|
|
217
|
+
}
|
|
218
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, urlPath, request);
|
|
219
|
+
})
|
|
220
|
+
.then(function (response) {
|
|
221
|
+
return response.name;
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Sends all the messages in the given array via Firebase Cloud Messaging.
|
|
226
|
+
* Employs batching to send the entire list as a single RPC call. Compared
|
|
227
|
+
* to the `send()` method, this method is a significantly more efficient way
|
|
228
|
+
* to send multiple messages.
|
|
229
|
+
*
|
|
230
|
+
* The responses list obtained from the return value
|
|
231
|
+
* corresponds to the order of tokens in the `MulticastMessage`. An error
|
|
232
|
+
* from this method indicates a total failure -- i.e. none of the messages in
|
|
233
|
+
* the list could be sent. Partial failures are indicated by a `BatchResponse`
|
|
234
|
+
* return value.
|
|
235
|
+
*
|
|
236
|
+
* @param messages A non-empty array
|
|
237
|
+
* containing up to 500 messages.
|
|
238
|
+
* @param dryRun Whether to send the messages in the dry-run
|
|
239
|
+
* (validation only) mode.
|
|
240
|
+
* @return A Promise fulfilled with an object representing the result of the
|
|
241
|
+
* send operation.
|
|
242
|
+
*/
|
|
243
|
+
Messaging.prototype.sendAll = function (messages, dryRun) {
|
|
244
|
+
var _this = this;
|
|
245
|
+
if (validator.isArray(messages) && messages.constructor !== Array) {
|
|
246
|
+
// In more recent JS specs, an array-like object might have a constructor that is not of
|
|
247
|
+
// Array type. Our deepCopy() method doesn't handle them properly. Convert such objects to
|
|
248
|
+
// a regular array here before calling deepCopy(). See issue #566 for details.
|
|
249
|
+
messages = Array.from(messages);
|
|
250
|
+
}
|
|
251
|
+
var copy = deep_copy_1.deepCopy(messages);
|
|
252
|
+
if (!validator.isNonEmptyArray(copy)) {
|
|
253
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'messages must be a non-empty array');
|
|
254
|
+
}
|
|
255
|
+
if (copy.length > FCM_MAX_BATCH_SIZE) {
|
|
256
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, "messages list must not contain more than " + FCM_MAX_BATCH_SIZE + " items");
|
|
257
|
+
}
|
|
258
|
+
if (typeof dryRun !== 'undefined' && !validator.isBoolean(dryRun)) {
|
|
259
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'dryRun must be a boolean');
|
|
260
|
+
}
|
|
261
|
+
return this.getUrlPath()
|
|
262
|
+
.then(function (urlPath) {
|
|
263
|
+
var requests = copy.map(function (message) {
|
|
264
|
+
messaging_internal_1.validateMessage(message);
|
|
265
|
+
var request = { message: message };
|
|
266
|
+
if (dryRun) {
|
|
267
|
+
request.validate_only = true;
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
url: "https://" + FCM_SEND_HOST + urlPath,
|
|
271
|
+
body: request,
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
return _this.messagingRequestHandler.sendBatchRequest(requests);
|
|
275
|
+
});
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Sends the given multicast message to all the FCM registration tokens
|
|
279
|
+
* specified in it.
|
|
280
|
+
*
|
|
281
|
+
* This method uses the `sendAll()` API under the hood to send the given
|
|
282
|
+
* message to all the target recipients. The responses list obtained from the
|
|
283
|
+
* return value corresponds to the order of tokens in the `MulticastMessage`.
|
|
284
|
+
* An error from this method indicates a total failure -- i.e. the message was
|
|
285
|
+
* not sent to any of the tokens in the list. Partial failures are indicated by
|
|
286
|
+
* a `BatchResponse` return value.
|
|
287
|
+
*
|
|
288
|
+
* @param message A multicast message
|
|
289
|
+
* containing up to 500 tokens.
|
|
290
|
+
* @param dryRun Whether to send the message in the dry-run
|
|
291
|
+
* (validation only) mode.
|
|
292
|
+
* @return A Promise fulfilled with an object representing the result of the
|
|
293
|
+
* send operation.
|
|
294
|
+
*/
|
|
295
|
+
Messaging.prototype.sendMulticast = function (message, dryRun) {
|
|
296
|
+
var copy = deep_copy_1.deepCopy(message);
|
|
297
|
+
if (!validator.isNonNullObject(copy)) {
|
|
298
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'MulticastMessage must be a non-null object');
|
|
299
|
+
}
|
|
300
|
+
if (!validator.isNonEmptyArray(copy.tokens)) {
|
|
301
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'tokens must be a non-empty array');
|
|
302
|
+
}
|
|
303
|
+
if (copy.tokens.length > FCM_MAX_BATCH_SIZE) {
|
|
304
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, "tokens list must not contain more than " + FCM_MAX_BATCH_SIZE + " items");
|
|
305
|
+
}
|
|
306
|
+
var messages = copy.tokens.map(function (token) {
|
|
307
|
+
return {
|
|
308
|
+
token: token,
|
|
309
|
+
android: copy.android,
|
|
310
|
+
apns: copy.apns,
|
|
311
|
+
data: copy.data,
|
|
312
|
+
notification: copy.notification,
|
|
313
|
+
webpush: copy.webpush,
|
|
314
|
+
fcmOptions: copy.fcmOptions,
|
|
315
|
+
};
|
|
316
|
+
});
|
|
317
|
+
return this.sendAll(messages, dryRun);
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Sends an FCM message to a single device corresponding to the provided
|
|
321
|
+
* registration token.
|
|
322
|
+
*
|
|
323
|
+
* See
|
|
324
|
+
* [Send to individual devices](/docs/cloud-messaging/admin/legacy-fcm#send_to_individual_devices)
|
|
325
|
+
* for code samples and detailed documentation. Takes either a
|
|
326
|
+
* `registrationToken` to send to a single device or a
|
|
327
|
+
* `registrationTokens` parameter containing an array of tokens to send
|
|
328
|
+
* to multiple devices.
|
|
329
|
+
*
|
|
330
|
+
* @param registrationToken A device registration token or an array of
|
|
331
|
+
* device registration tokens to which the message should be sent.
|
|
332
|
+
* @param payload The message payload.
|
|
333
|
+
* @param options Optional options to
|
|
334
|
+
* alter the message.
|
|
335
|
+
*
|
|
336
|
+
* @return A promise fulfilled with the server's response after the message
|
|
337
|
+
* has been sent.
|
|
338
|
+
*/
|
|
339
|
+
Messaging.prototype.sendToDevice = function (registrationTokenOrTokens, payload, options) {
|
|
340
|
+
var _this = this;
|
|
341
|
+
if (options === void 0) { options = {}; }
|
|
342
|
+
// Validate the input argument types. Since these are common developer errors when getting
|
|
343
|
+
// started, throw an error instead of returning a rejected promise.
|
|
344
|
+
this.validateRegistrationTokensType(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
345
|
+
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
346
|
+
return Promise.resolve()
|
|
347
|
+
.then(function () {
|
|
348
|
+
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
|
349
|
+
// error will cause this method to return a rejected promise.
|
|
350
|
+
_this.validateRegistrationTokens(registrationTokenOrTokens, 'sendToDevice', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
351
|
+
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
352
|
+
var optionsCopy = _this.validateMessagingOptions(options);
|
|
353
|
+
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
354
|
+
deep_copy_1.deepExtend(request, optionsCopy);
|
|
355
|
+
if (validator.isString(registrationTokenOrTokens)) {
|
|
356
|
+
request.to = registrationTokenOrTokens;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
request.registration_ids = registrationTokenOrTokens;
|
|
360
|
+
}
|
|
361
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
362
|
+
})
|
|
363
|
+
.then(function (response) {
|
|
364
|
+
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
|
365
|
+
// the underlying FCM request. If the provided registration token argument is actually a
|
|
366
|
+
// valid notification key, the response from the FCM server will be a device group response.
|
|
367
|
+
// If that is the case, we map the response to a MessagingDeviceGroupResponse.
|
|
368
|
+
// See b/35394951 for more context.
|
|
369
|
+
if ('multicast_id' in response) {
|
|
370
|
+
return mapRawResponseToDevicesResponse(response);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
var groupResponse = mapRawResponseToDeviceGroupResponse(response);
|
|
374
|
+
return __assign(__assign({}, groupResponse), { canonicalRegistrationTokenCount: -1, multicastId: -1, results: [] });
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Sends an FCM message to a device group corresponding to the provided
|
|
380
|
+
* notification key.
|
|
381
|
+
*
|
|
382
|
+
* See
|
|
383
|
+
* [Send to a device group](/docs/cloud-messaging/admin/legacy-fcm#send_to_a_device_group)
|
|
384
|
+
* for code samples and detailed documentation.
|
|
385
|
+
*
|
|
386
|
+
* @param notificationKey The notification key for the device group to
|
|
387
|
+
* which to send the message.
|
|
388
|
+
* @param payload The message payload.
|
|
389
|
+
* @param options Optional options to
|
|
390
|
+
* alter the message.
|
|
391
|
+
*
|
|
392
|
+
* @return A promise fulfilled with the server's response after the message
|
|
393
|
+
* has been sent.
|
|
394
|
+
*/
|
|
395
|
+
Messaging.prototype.sendToDeviceGroup = function (notificationKey, payload, options) {
|
|
396
|
+
var _this = this;
|
|
397
|
+
if (options === void 0) { options = {}; }
|
|
398
|
+
if (!validator.isNonEmptyString(notificationKey)) {
|
|
399
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() must be a non-empty string.');
|
|
400
|
+
}
|
|
401
|
+
else if (notificationKey.indexOf(':') !== -1) {
|
|
402
|
+
// It is possible the developer provides a registration token instead of a notification key
|
|
403
|
+
// to this method. We can detect some of those cases by checking to see if the string contains
|
|
404
|
+
// a colon. Not all registration tokens will contain a colon (only newer ones will), but no
|
|
405
|
+
// notification keys will contain a colon, so we can use it as a rough heuristic.
|
|
406
|
+
// See b/35394951 for more context.
|
|
407
|
+
return Promise.reject(new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() has the format of a registration token. ' +
|
|
408
|
+
'You should use sendToDevice() instead.'));
|
|
409
|
+
}
|
|
410
|
+
// Validate the types of the payload and options arguments. Since these are common developer
|
|
411
|
+
// errors, throw an error instead of returning a rejected promise.
|
|
412
|
+
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
413
|
+
return Promise.resolve()
|
|
414
|
+
.then(function () {
|
|
415
|
+
// Validate the contents of the payload and options objects. Because we are now in a
|
|
416
|
+
// promise, any thrown error will cause this method to return a rejected promise.
|
|
417
|
+
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
418
|
+
var optionsCopy = _this.validateMessagingOptions(options);
|
|
419
|
+
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
420
|
+
deep_copy_1.deepExtend(request, optionsCopy);
|
|
421
|
+
request.to = notificationKey;
|
|
422
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
423
|
+
})
|
|
424
|
+
.then(function (response) {
|
|
425
|
+
// The sendToDevice() and sendToDeviceGroup() methods both set the `to` query parameter in
|
|
426
|
+
// the underlying FCM request. If the provided notification key argument has an invalid
|
|
427
|
+
// format (that is, it is either a registration token or some random string), the response
|
|
428
|
+
// from the FCM server will default to a devices response (which we detect by looking for
|
|
429
|
+
// the `multicast_id` property). If that is the case, we either throw an error saying the
|
|
430
|
+
// provided notification key is invalid (if the message failed to send) or map the response
|
|
431
|
+
// to a MessagingDevicesResponse (if the message succeeded).
|
|
432
|
+
// See b/35394951 for more context.
|
|
433
|
+
if ('multicast_id' in response) {
|
|
434
|
+
if (response.success === 0) {
|
|
435
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Notification key provided to sendToDeviceGroup() is invalid.');
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
var devicesResponse = mapRawResponseToDevicesResponse(response);
|
|
439
|
+
return __assign(__assign({}, devicesResponse), { failedRegistrationTokens: [] });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return mapRawResponseToDeviceGroupResponse(response);
|
|
443
|
+
});
|
|
444
|
+
};
|
|
445
|
+
/**
|
|
446
|
+
* Sends an FCM message to a topic.
|
|
447
|
+
*
|
|
448
|
+
* See
|
|
449
|
+
* [Send to a topic](/docs/cloud-messaging/admin/legacy-fcm#send_to_a_topic)
|
|
450
|
+
* for code samples and detailed documentation.
|
|
451
|
+
*
|
|
452
|
+
* @param topic The topic to which to send the message.
|
|
453
|
+
* @param payload The message payload.
|
|
454
|
+
* @param options Optional options to
|
|
455
|
+
* alter the message.
|
|
456
|
+
*
|
|
457
|
+
* @return A promise fulfilled with the server's response after the message
|
|
458
|
+
* has been sent.
|
|
459
|
+
*/
|
|
460
|
+
Messaging.prototype.sendToTopic = function (topic, payload, options) {
|
|
461
|
+
var _this = this;
|
|
462
|
+
if (options === void 0) { options = {}; }
|
|
463
|
+
// Validate the input argument types. Since these are common developer errors when getting
|
|
464
|
+
// started, throw an error instead of returning a rejected promise.
|
|
465
|
+
this.validateTopicType(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
466
|
+
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
467
|
+
// Prepend the topic with /topics/ if necessary.
|
|
468
|
+
topic = this.normalizeTopic(topic);
|
|
469
|
+
return Promise.resolve()
|
|
470
|
+
.then(function () {
|
|
471
|
+
// Validate the contents of the payload and options objects. Because we are now in a
|
|
472
|
+
// promise, any thrown error will cause this method to return a rejected promise.
|
|
473
|
+
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
474
|
+
var optionsCopy = _this.validateMessagingOptions(options);
|
|
475
|
+
_this.validateTopic(topic, 'sendToTopic', error_1.MessagingClientErrorCode.INVALID_RECIPIENT);
|
|
476
|
+
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
477
|
+
deep_copy_1.deepExtend(request, optionsCopy);
|
|
478
|
+
request.to = topic;
|
|
479
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
480
|
+
})
|
|
481
|
+
.then(function (response) {
|
|
482
|
+
// Rename properties on the server response
|
|
483
|
+
utils.renameProperties(response, MESSAGING_TOPIC_RESPONSE_KEYS_MAP);
|
|
484
|
+
return response;
|
|
485
|
+
});
|
|
486
|
+
};
|
|
487
|
+
/**
|
|
488
|
+
* Sends an FCM message to a condition.
|
|
489
|
+
*
|
|
490
|
+
* See
|
|
491
|
+
* [Send to a condition](/docs/cloud-messaging/admin/legacy-fcm#send_to_a_condition)
|
|
492
|
+
* for code samples and detailed documentation.
|
|
493
|
+
*
|
|
494
|
+
* @param condition The condition determining to which topics to send
|
|
495
|
+
* the message.
|
|
496
|
+
* @param payload The message payload.
|
|
497
|
+
* @param options Optional options to
|
|
498
|
+
* alter the message.
|
|
499
|
+
*
|
|
500
|
+
* @return A promise fulfilled with the server's response after the message
|
|
501
|
+
* has been sent.
|
|
502
|
+
*/
|
|
503
|
+
Messaging.prototype.sendToCondition = function (condition, payload, options) {
|
|
504
|
+
var _this = this;
|
|
505
|
+
if (options === void 0) { options = {}; }
|
|
506
|
+
if (!validator.isNonEmptyString(condition)) {
|
|
507
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_RECIPIENT, 'Condition provided to sendToCondition() must be a non-empty string.');
|
|
508
|
+
}
|
|
509
|
+
// Validate the types of the payload and options arguments. Since these are common developer
|
|
510
|
+
// errors, throw an error instead of returning a rejected promise.
|
|
511
|
+
this.validateMessagingPayloadAndOptionsTypes(payload, options);
|
|
512
|
+
// The FCM server rejects conditions which are surrounded in single quotes. When the condition
|
|
513
|
+
// is stringified over the wire, double quotes in it get converted to \" which the FCM server
|
|
514
|
+
// does not properly handle. We can get around this by replacing internal double quotes with
|
|
515
|
+
// single quotes.
|
|
516
|
+
condition = condition.replace(/"/g, '\'');
|
|
517
|
+
return Promise.resolve()
|
|
518
|
+
.then(function () {
|
|
519
|
+
// Validate the contents of the payload and options objects. Because we are now in a
|
|
520
|
+
// promise, any thrown error will cause this method to return a rejected promise.
|
|
521
|
+
var payloadCopy = _this.validateMessagingPayload(payload);
|
|
522
|
+
var optionsCopy = _this.validateMessagingOptions(options);
|
|
523
|
+
var request = deep_copy_1.deepCopy(payloadCopy);
|
|
524
|
+
deep_copy_1.deepExtend(request, optionsCopy);
|
|
525
|
+
request.condition = condition;
|
|
526
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_SEND_HOST, FCM_SEND_PATH, request);
|
|
527
|
+
})
|
|
528
|
+
.then(function (response) {
|
|
529
|
+
// Rename properties on the server response
|
|
530
|
+
utils.renameProperties(response, MESSAGING_CONDITION_RESPONSE_KEYS_MAP);
|
|
531
|
+
return response;
|
|
532
|
+
});
|
|
533
|
+
};
|
|
534
|
+
/**
|
|
535
|
+
* Subscribes a device to an FCM topic.
|
|
536
|
+
*
|
|
537
|
+
* See [Subscribe to a
|
|
538
|
+
* topic](/docs/cloud-messaging/manage-topics#suscribe_and_unsubscribe_using_the)
|
|
539
|
+
* for code samples and detailed documentation. Optionally, you can provide an
|
|
540
|
+
* array of tokens to subscribe multiple devices.
|
|
541
|
+
*
|
|
542
|
+
* @param registrationTokens A token or array of registration tokens
|
|
543
|
+
* for the devices to subscribe to the topic.
|
|
544
|
+
* @param topic The topic to which to subscribe.
|
|
545
|
+
*
|
|
546
|
+
* @return A promise fulfilled with the server's response after the device has been
|
|
547
|
+
* subscribed to the topic.
|
|
548
|
+
*/
|
|
549
|
+
Messaging.prototype.subscribeToTopic = function (registrationTokenOrTokens, topic) {
|
|
550
|
+
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'subscribeToTopic', FCM_TOPIC_MANAGEMENT_ADD_PATH);
|
|
551
|
+
};
|
|
552
|
+
/**
|
|
553
|
+
* Unsubscribes a device from an FCM topic.
|
|
554
|
+
*
|
|
555
|
+
* See [Unsubscribe from a
|
|
556
|
+
* topic](/docs/cloud-messaging/admin/manage-topic-subscriptions#unsubscribe_from_a_topic)
|
|
557
|
+
* for code samples and detailed documentation. Optionally, you can provide an
|
|
558
|
+
* array of tokens to unsubscribe multiple devices.
|
|
559
|
+
*
|
|
560
|
+
* @param registrationTokens A device registration token or an array of
|
|
561
|
+
* device registration tokens to unsubscribe from the topic.
|
|
562
|
+
* @param topic The topic from which to unsubscribe.
|
|
563
|
+
*
|
|
564
|
+
* @return A promise fulfilled with the server's response after the device has been
|
|
565
|
+
* unsubscribed from the topic.
|
|
566
|
+
*/
|
|
567
|
+
Messaging.prototype.unsubscribeFromTopic = function (registrationTokenOrTokens, topic) {
|
|
568
|
+
return this.sendTopicManagementRequest(registrationTokenOrTokens, topic, 'unsubscribeFromTopic', FCM_TOPIC_MANAGEMENT_REMOVE_PATH);
|
|
569
|
+
};
|
|
570
|
+
Messaging.prototype.getUrlPath = function () {
|
|
571
|
+
var _this = this;
|
|
572
|
+
if (this.urlPath) {
|
|
573
|
+
return Promise.resolve(this.urlPath);
|
|
574
|
+
}
|
|
575
|
+
return utils.findProjectId(this.app)
|
|
576
|
+
.then(function (projectId) {
|
|
577
|
+
if (!validator.isNonEmptyString(projectId)) {
|
|
578
|
+
// Assert for an explicit project ID (either via AppOptions or the cert itself).
|
|
579
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_ARGUMENT, 'Failed to determine project ID for Messaging. Initialize the '
|
|
580
|
+
+ 'SDK with service account credentials or set project ID as an app option. '
|
|
581
|
+
+ 'Alternatively set the GOOGLE_CLOUD_PROJECT environment variable.');
|
|
582
|
+
}
|
|
583
|
+
_this.urlPath = "/v1/projects/" + projectId + "/messages:send";
|
|
584
|
+
return _this.urlPath;
|
|
585
|
+
});
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Helper method which sends and handles topic subscription management requests.
|
|
589
|
+
*
|
|
590
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
591
|
+
* registration tokens to unsubscribe from the topic.
|
|
592
|
+
* @param {string} topic The topic to which to subscribe.
|
|
593
|
+
* @param {string} methodName The name of the original method called.
|
|
594
|
+
* @param {string} path The endpoint path to use for the request.
|
|
595
|
+
*
|
|
596
|
+
* @return {Promise<MessagingTopicManagementResponse>} A Promise fulfilled with the parsed server
|
|
597
|
+
* response.
|
|
598
|
+
*/
|
|
599
|
+
Messaging.prototype.sendTopicManagementRequest = function (registrationTokenOrTokens, topic, methodName, path) {
|
|
600
|
+
var _this = this;
|
|
601
|
+
this.validateRegistrationTokensType(registrationTokenOrTokens, methodName);
|
|
602
|
+
this.validateTopicType(topic, methodName);
|
|
603
|
+
// Prepend the topic with /topics/ if necessary.
|
|
604
|
+
topic = this.normalizeTopic(topic);
|
|
605
|
+
return Promise.resolve()
|
|
606
|
+
.then(function () {
|
|
607
|
+
// Validate the contents of the input arguments. Because we are now in a promise, any thrown
|
|
608
|
+
// error will cause this method to return a rejected promise.
|
|
609
|
+
_this.validateRegistrationTokens(registrationTokenOrTokens, methodName);
|
|
610
|
+
_this.validateTopic(topic, methodName);
|
|
611
|
+
// Ensure the registration token(s) input argument is an array.
|
|
612
|
+
var registrationTokensArray = registrationTokenOrTokens;
|
|
613
|
+
if (validator.isString(registrationTokenOrTokens)) {
|
|
614
|
+
registrationTokensArray = [registrationTokenOrTokens];
|
|
615
|
+
}
|
|
616
|
+
var request = {
|
|
617
|
+
to: topic,
|
|
618
|
+
registration_tokens: registrationTokensArray,
|
|
619
|
+
};
|
|
620
|
+
return _this.messagingRequestHandler.invokeRequestHandler(FCM_TOPIC_MANAGEMENT_HOST, path, request);
|
|
621
|
+
})
|
|
622
|
+
.then(function (response) {
|
|
623
|
+
return mapRawResponseToTopicManagementResponse(response);
|
|
624
|
+
});
|
|
625
|
+
};
|
|
626
|
+
/**
|
|
627
|
+
* Validates the types of the messaging payload and options. If invalid, an error will be thrown.
|
|
628
|
+
*
|
|
629
|
+
* @param {MessagingPayload} payload The messaging payload to validate.
|
|
630
|
+
* @param {MessagingOptions} options The messaging options to validate.
|
|
631
|
+
*/
|
|
632
|
+
Messaging.prototype.validateMessagingPayloadAndOptionsTypes = function (payload, options) {
|
|
633
|
+
// Validate the payload is an object
|
|
634
|
+
if (!validator.isNonNullObject(payload)) {
|
|
635
|
+
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.');
|
|
636
|
+
}
|
|
637
|
+
// Validate the options argument is an object
|
|
638
|
+
if (!validator.isNonNullObject(options)) {
|
|
639
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, 'Messaging options must be an object.');
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
/**
|
|
643
|
+
* Validates the messaging payload. If invalid, an error will be thrown.
|
|
644
|
+
*
|
|
645
|
+
* @param {MessagingPayload} payload The messaging payload to validate.
|
|
646
|
+
*
|
|
647
|
+
* @return {MessagingPayload} A copy of the provided payload with whitelisted properties switched
|
|
648
|
+
* from camelCase to underscore_case.
|
|
649
|
+
*/
|
|
650
|
+
Messaging.prototype.validateMessagingPayload = function (payload) {
|
|
651
|
+
var payloadCopy = deep_copy_1.deepCopy(payload);
|
|
652
|
+
var payloadKeys = Object.keys(payloadCopy);
|
|
653
|
+
var validPayloadKeys = ['data', 'notification'];
|
|
654
|
+
var containsDataOrNotificationKey = false;
|
|
655
|
+
payloadKeys.forEach(function (payloadKey) {
|
|
656
|
+
// Validate the payload does not contain any invalid keys
|
|
657
|
+
if (validPayloadKeys.indexOf(payloadKey) === -1) {
|
|
658
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid \"" + payloadKey + "\" property. Valid properties are " +
|
|
659
|
+
'"data" and "notification".');
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
containsDataOrNotificationKey = true;
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
// Validate the payload contains at least one of the "data" and "notification" keys
|
|
666
|
+
if (!containsDataOrNotificationKey) {
|
|
667
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Messaging payload must contain at least one of the "data" or "notification" properties.');
|
|
668
|
+
}
|
|
669
|
+
var validatePayload = function (payloadKey, value) {
|
|
670
|
+
// Validate each top-level key in the payload is an object
|
|
671
|
+
if (!validator.isNonNullObject(value)) {
|
|
672
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid value for the \"" + payloadKey + "\" property. " +
|
|
673
|
+
'Value must be an object.');
|
|
674
|
+
}
|
|
675
|
+
Object.keys(value).forEach(function (subKey) {
|
|
676
|
+
if (!validator.isString(value[subKey])) {
|
|
677
|
+
// Validate all sub-keys have a string value
|
|
678
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains an invalid value for the \"" + payloadKey + "." + subKey + "\" " +
|
|
679
|
+
'property. Values must be strings.');
|
|
680
|
+
}
|
|
681
|
+
else if (payloadKey === 'data' && /^google\./.test(subKey)) {
|
|
682
|
+
// Validate the data payload does not contain keys which start with 'google.'.
|
|
683
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains the blacklisted \"data." + subKey + "\" property.");
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
};
|
|
687
|
+
if (payloadCopy.data !== undefined) {
|
|
688
|
+
validatePayload('data', payloadCopy.data);
|
|
689
|
+
}
|
|
690
|
+
if (payloadCopy.notification !== undefined) {
|
|
691
|
+
validatePayload('notification', payloadCopy.notification);
|
|
692
|
+
}
|
|
693
|
+
// Validate the data payload object does not contain blacklisted properties
|
|
694
|
+
if ('data' in payloadCopy) {
|
|
695
|
+
messaging_internal_1.BLACKLISTED_DATA_PAYLOAD_KEYS.forEach(function (blacklistedKey) {
|
|
696
|
+
if (blacklistedKey in payloadCopy.data) {
|
|
697
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, "Messaging payload contains the blacklisted \"data." + blacklistedKey + "\" property.");
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
// Convert whitelisted camelCase keys to underscore_case
|
|
702
|
+
if (payloadCopy.notification) {
|
|
703
|
+
utils.renameProperties(payloadCopy.notification, CAMELCASED_NOTIFICATION_PAYLOAD_KEYS_MAP);
|
|
704
|
+
}
|
|
705
|
+
return payloadCopy;
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* Validates the messaging options. If invalid, an error will be thrown.
|
|
709
|
+
*
|
|
710
|
+
* @param {MessagingOptions} options The messaging options to validate.
|
|
711
|
+
*
|
|
712
|
+
* @return {MessagingOptions} A copy of the provided options with whitelisted properties switched
|
|
713
|
+
* from camelCase to underscore_case.
|
|
714
|
+
*/
|
|
715
|
+
Messaging.prototype.validateMessagingOptions = function (options) {
|
|
716
|
+
var optionsCopy = deep_copy_1.deepCopy(options);
|
|
717
|
+
// Validate the options object does not contain blacklisted properties
|
|
718
|
+
messaging_internal_1.BLACKLISTED_OPTIONS_KEYS.forEach(function (blacklistedKey) {
|
|
719
|
+
if (blacklistedKey in optionsCopy) {
|
|
720
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains the blacklisted \"" + blacklistedKey + "\" property.");
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
// Convert whitelisted camelCase keys to underscore_case
|
|
724
|
+
utils.renameProperties(optionsCopy, CAMELCASE_OPTIONS_KEYS_MAP);
|
|
725
|
+
// Validate the options object contains valid values for whitelisted properties
|
|
726
|
+
if ('collapse_key' in optionsCopy && !validator.isNonEmptyString(optionsCopy.collapse_key)) {
|
|
727
|
+
var keyName = ('collapseKey' in options) ? 'collapseKey' : 'collapse_key';
|
|
728
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
729
|
+
'be a non-empty string.');
|
|
730
|
+
}
|
|
731
|
+
else if ('dry_run' in optionsCopy && !validator.isBoolean(optionsCopy.dry_run)) {
|
|
732
|
+
var keyName = ('dryRun' in options) ? 'dryRun' : 'dry_run';
|
|
733
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
734
|
+
'be a boolean.');
|
|
735
|
+
}
|
|
736
|
+
else if ('priority' in optionsCopy && !validator.isNonEmptyString(optionsCopy.priority)) {
|
|
737
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, 'Messaging options contains an invalid value for the "priority" property. Value must ' +
|
|
738
|
+
'be a non-empty string.');
|
|
739
|
+
}
|
|
740
|
+
else if ('restricted_package_name' in optionsCopy &&
|
|
741
|
+
!validator.isNonEmptyString(optionsCopy.restricted_package_name)) {
|
|
742
|
+
var keyName = ('restrictedPackageName' in options) ? 'restrictedPackageName' : 'restricted_package_name';
|
|
743
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
744
|
+
'be a non-empty string.');
|
|
745
|
+
}
|
|
746
|
+
else if ('time_to_live' in optionsCopy && !validator.isNumber(optionsCopy.time_to_live)) {
|
|
747
|
+
var keyName = ('timeToLive' in options) ? 'timeToLive' : 'time_to_live';
|
|
748
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
749
|
+
'be a number.');
|
|
750
|
+
}
|
|
751
|
+
else if ('content_available' in optionsCopy && !validator.isBoolean(optionsCopy.content_available)) {
|
|
752
|
+
var keyName = ('contentAvailable' in options) ? 'contentAvailable' : 'content_available';
|
|
753
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
754
|
+
'be a boolean.');
|
|
755
|
+
}
|
|
756
|
+
else if ('mutable_content' in optionsCopy && !validator.isBoolean(optionsCopy.mutable_content)) {
|
|
757
|
+
var keyName = ('mutableContent' in options) ? 'mutableContent' : 'mutable_content';
|
|
758
|
+
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_OPTIONS, "Messaging options contains an invalid value for the \"" + keyName + "\" property. Value must " +
|
|
759
|
+
'be a boolean.');
|
|
760
|
+
}
|
|
761
|
+
return optionsCopy;
|
|
762
|
+
};
|
|
763
|
+
/**
|
|
764
|
+
* Validates the type of the provided registration token(s). If invalid, an error will be thrown.
|
|
765
|
+
*
|
|
766
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token(s) to validate.
|
|
767
|
+
* @param {string} method The method name to use in error messages.
|
|
768
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the registration tokens are invalid.
|
|
769
|
+
*/
|
|
770
|
+
Messaging.prototype.validateRegistrationTokensType = function (registrationTokenOrTokens, methodName, errorInfo) {
|
|
771
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
772
|
+
if (!validator.isNonEmptyArray(registrationTokenOrTokens) &&
|
|
773
|
+
!validator.isNonEmptyString(registrationTokenOrTokens)) {
|
|
774
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token(s) provided to " + methodName + "() must be a non-empty string or a " +
|
|
775
|
+
'non-empty array.');
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* Validates the provided registration tokens. If invalid, an error will be thrown.
|
|
780
|
+
*
|
|
781
|
+
* @param {string|string[]} registrationTokenOrTokens The registration token or an array of
|
|
782
|
+
* registration tokens to validate.
|
|
783
|
+
* @param {string} method The method name to use in error messages.
|
|
784
|
+
* @param {errorInfo?} [ErrorInfo] The error info to use if the registration tokens are invalid.
|
|
785
|
+
*/
|
|
786
|
+
Messaging.prototype.validateRegistrationTokens = function (registrationTokenOrTokens, methodName, errorInfo) {
|
|
787
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
788
|
+
if (validator.isArray(registrationTokenOrTokens)) {
|
|
789
|
+
// Validate the array contains no more than 1,000 registration tokens.
|
|
790
|
+
if (registrationTokenOrTokens.length > 1000) {
|
|
791
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Too many registration tokens provided in a single request to " + methodName + "(). Batch " +
|
|
792
|
+
'your requests to contain no more than 1,000 registration tokens per request.');
|
|
793
|
+
}
|
|
794
|
+
// Validate the array contains registration tokens which are non-empty strings.
|
|
795
|
+
registrationTokenOrTokens.forEach(function (registrationToken, index) {
|
|
796
|
+
if (!validator.isNonEmptyString(registrationToken)) {
|
|
797
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Registration token provided to " + methodName + "() at index " + index + " must be a " +
|
|
798
|
+
'non-empty string.');
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
/**
|
|
804
|
+
* Validates the type of the provided topic. If invalid, an error will be thrown.
|
|
805
|
+
*
|
|
806
|
+
* @param {string} topic The topic to validate.
|
|
807
|
+
* @param {string} method The method name to use in error messages.
|
|
808
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
|
809
|
+
*/
|
|
810
|
+
Messaging.prototype.validateTopicType = function (topic, methodName, errorInfo) {
|
|
811
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
812
|
+
if (!validator.isNonEmptyString(topic)) {
|
|
813
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
|
814
|
+
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
/**
|
|
818
|
+
* Validates the provided topic. If invalid, an error will be thrown.
|
|
819
|
+
*
|
|
820
|
+
* @param {string} topic The topic to validate.
|
|
821
|
+
* @param {string} method The method name to use in error messages.
|
|
822
|
+
* @param {ErrorInfo?} [errorInfo] The error info to use if the topic is invalid.
|
|
823
|
+
*/
|
|
824
|
+
Messaging.prototype.validateTopic = function (topic, methodName, errorInfo) {
|
|
825
|
+
if (errorInfo === void 0) { errorInfo = error_1.MessagingClientErrorCode.INVALID_ARGUMENT; }
|
|
826
|
+
if (!validator.isTopic(topic)) {
|
|
827
|
+
throw new error_1.FirebaseMessagingError(errorInfo, "Topic provided to " + methodName + "() must be a string which matches the format " +
|
|
828
|
+
'"/topics/[a-zA-Z0-9-_.~%]+".');
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Normalizes the provided topic name by prepending it with '/topics/', if necessary.
|
|
833
|
+
*
|
|
834
|
+
* @param {string} topic The topic name to normalize.
|
|
835
|
+
*
|
|
836
|
+
* @return {string} The normalized topic name.
|
|
837
|
+
*/
|
|
838
|
+
Messaging.prototype.normalizeTopic = function (topic) {
|
|
839
|
+
if (!/^\/topics\//.test(topic)) {
|
|
840
|
+
topic = "/topics/" + topic;
|
|
841
|
+
}
|
|
842
|
+
return topic;
|
|
843
|
+
};
|
|
844
|
+
return Messaging;
|
|
845
|
+
}());
|
|
846
|
+
exports.Messaging = Messaging;
|