1279 lines
51 KiB
JavaScript
1279 lines
51 KiB
JavaScript
|
import '@firebase/installations';
|
||
|
import { Component } from '@firebase/component';
|
||
|
import { openDB, deleteDB } from 'idb';
|
||
|
import { ErrorFactory, isIndexedDBAvailable, validateIndexedDBOpenable, getModularInstance } from '@firebase/util';
|
||
|
import { _registerComponent, _getProvider, getApp } from '@firebase/app';
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
const DEFAULT_VAPID_KEY = 'BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoMj8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4';
|
||
|
const ENDPOINT = 'https://fcmregistrations.googleapis.com/v1';
|
||
|
/** Key of FCM Payload in Notification's data field. */
|
||
|
const FCM_MSG = 'FCM_MSG';
|
||
|
const CONSOLE_CAMPAIGN_ID = 'google.c.a.c_id';
|
||
|
// Defined as in proto/messaging_event.proto. Neglecting fields that are supported.
|
||
|
const SDK_PLATFORM_WEB = 3;
|
||
|
const EVENT_MESSAGE_DELIVERED = 1;
|
||
|
var MessageType$1;
|
||
|
(function (MessageType) {
|
||
|
MessageType[MessageType["DATA_MESSAGE"] = 1] = "DATA_MESSAGE";
|
||
|
MessageType[MessageType["DISPLAY_NOTIFICATION"] = 3] = "DISPLAY_NOTIFICATION";
|
||
|
})(MessageType$1 || (MessageType$1 = {}));
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2018 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
var MessageType;
|
||
|
(function (MessageType) {
|
||
|
MessageType["PUSH_RECEIVED"] = "push-received";
|
||
|
MessageType["NOTIFICATION_CLICKED"] = "notification-clicked";
|
||
|
})(MessageType || (MessageType = {}));
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2017 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function arrayToBase64(array) {
|
||
|
const uint8Array = new Uint8Array(array);
|
||
|
const base64String = btoa(String.fromCharCode(...uint8Array));
|
||
|
return base64String.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
||
|
}
|
||
|
function base64ToArray(base64String) {
|
||
|
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
||
|
const base64 = (base64String + padding)
|
||
|
.replace(/\-/g, '+')
|
||
|
.replace(/_/g, '/');
|
||
|
const rawData = atob(base64);
|
||
|
const outputArray = new Uint8Array(rawData.length);
|
||
|
for (let i = 0; i < rawData.length; ++i) {
|
||
|
outputArray[i] = rawData.charCodeAt(i);
|
||
|
}
|
||
|
return outputArray;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
const OLD_DB_NAME = 'fcm_token_details_db';
|
||
|
/**
|
||
|
* The last DB version of 'fcm_token_details_db' was 4. This is one higher, so that the upgrade
|
||
|
* callback is called for all versions of the old DB.
|
||
|
*/
|
||
|
const OLD_DB_VERSION = 5;
|
||
|
const OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store';
|
||
|
async function migrateOldDatabase(senderId) {
|
||
|
if ('databases' in indexedDB) {
|
||
|
// indexedDb.databases() is an IndexedDB v3 API and does not exist in all browsers. TODO: Remove
|
||
|
// typecast when it lands in TS types.
|
||
|
const databases = await indexedDB.databases();
|
||
|
const dbNames = databases.map(db => db.name);
|
||
|
if (!dbNames.includes(OLD_DB_NAME)) {
|
||
|
// old DB didn't exist, no need to open.
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
let tokenDetails = null;
|
||
|
const db = await openDB(OLD_DB_NAME, OLD_DB_VERSION, {
|
||
|
upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => {
|
||
|
var _a;
|
||
|
if (oldVersion < 2) {
|
||
|
// Database too old, skip migration.
|
||
|
return;
|
||
|
}
|
||
|
if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) {
|
||
|
// Database did not exist. Nothing to do.
|
||
|
return;
|
||
|
}
|
||
|
const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME);
|
||
|
const value = await objectStore.index('fcmSenderId').get(senderId);
|
||
|
await objectStore.clear();
|
||
|
if (!value) {
|
||
|
// No entry in the database, nothing to migrate.
|
||
|
return;
|
||
|
}
|
||
|
if (oldVersion === 2) {
|
||
|
const oldDetails = value;
|
||
|
if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) {
|
||
|
return;
|
||
|
}
|
||
|
tokenDetails = {
|
||
|
token: oldDetails.fcmToken,
|
||
|
createTime: (_a = oldDetails.createTime) !== null && _a !== void 0 ? _a : Date.now(),
|
||
|
subscriptionOptions: {
|
||
|
auth: oldDetails.auth,
|
||
|
p256dh: oldDetails.p256dh,
|
||
|
endpoint: oldDetails.endpoint,
|
||
|
swScope: oldDetails.swScope,
|
||
|
vapidKey: typeof oldDetails.vapidKey === 'string'
|
||
|
? oldDetails.vapidKey
|
||
|
: arrayToBase64(oldDetails.vapidKey)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
else if (oldVersion === 3) {
|
||
|
const oldDetails = value;
|
||
|
tokenDetails = {
|
||
|
token: oldDetails.fcmToken,
|
||
|
createTime: oldDetails.createTime,
|
||
|
subscriptionOptions: {
|
||
|
auth: arrayToBase64(oldDetails.auth),
|
||
|
p256dh: arrayToBase64(oldDetails.p256dh),
|
||
|
endpoint: oldDetails.endpoint,
|
||
|
swScope: oldDetails.swScope,
|
||
|
vapidKey: arrayToBase64(oldDetails.vapidKey)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
else if (oldVersion === 4) {
|
||
|
const oldDetails = value;
|
||
|
tokenDetails = {
|
||
|
token: oldDetails.fcmToken,
|
||
|
createTime: oldDetails.createTime,
|
||
|
subscriptionOptions: {
|
||
|
auth: arrayToBase64(oldDetails.auth),
|
||
|
p256dh: arrayToBase64(oldDetails.p256dh),
|
||
|
endpoint: oldDetails.endpoint,
|
||
|
swScope: oldDetails.swScope,
|
||
|
vapidKey: arrayToBase64(oldDetails.vapidKey)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
db.close();
|
||
|
// Delete all old databases.
|
||
|
await deleteDB(OLD_DB_NAME);
|
||
|
await deleteDB('fcm_vapid_details_db');
|
||
|
await deleteDB('undefined');
|
||
|
return checkTokenDetails(tokenDetails) ? tokenDetails : null;
|
||
|
}
|
||
|
function checkTokenDetails(tokenDetails) {
|
||
|
if (!tokenDetails || !tokenDetails.subscriptionOptions) {
|
||
|
return false;
|
||
|
}
|
||
|
const { subscriptionOptions } = tokenDetails;
|
||
|
return (typeof tokenDetails.createTime === 'number' &&
|
||
|
tokenDetails.createTime > 0 &&
|
||
|
typeof tokenDetails.token === 'string' &&
|
||
|
tokenDetails.token.length > 0 &&
|
||
|
typeof subscriptionOptions.auth === 'string' &&
|
||
|
subscriptionOptions.auth.length > 0 &&
|
||
|
typeof subscriptionOptions.p256dh === 'string' &&
|
||
|
subscriptionOptions.p256dh.length > 0 &&
|
||
|
typeof subscriptionOptions.endpoint === 'string' &&
|
||
|
subscriptionOptions.endpoint.length > 0 &&
|
||
|
typeof subscriptionOptions.swScope === 'string' &&
|
||
|
subscriptionOptions.swScope.length > 0 &&
|
||
|
typeof subscriptionOptions.vapidKey === 'string' &&
|
||
|
subscriptionOptions.vapidKey.length > 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
// Exported for tests.
|
||
|
const DATABASE_NAME = 'firebase-messaging-database';
|
||
|
const DATABASE_VERSION = 1;
|
||
|
const OBJECT_STORE_NAME = 'firebase-messaging-store';
|
||
|
let dbPromise = null;
|
||
|
function getDbPromise() {
|
||
|
if (!dbPromise) {
|
||
|
dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
|
||
|
upgrade: (upgradeDb, oldVersion) => {
|
||
|
// We don't use 'break' in this switch statement, the fall-through behavior is what we want,
|
||
|
// because if there are multiple versions between the old version and the current version, we
|
||
|
// want ALL the migrations that correspond to those versions to run, not only the last one.
|
||
|
// eslint-disable-next-line default-case
|
||
|
switch (oldVersion) {
|
||
|
case 0:
|
||
|
upgradeDb.createObjectStore(OBJECT_STORE_NAME);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return dbPromise;
|
||
|
}
|
||
|
/** Gets record(s) from the objectStore that match the given key. */
|
||
|
async function dbGet(firebaseDependencies) {
|
||
|
const key = getKey(firebaseDependencies);
|
||
|
const db = await getDbPromise();
|
||
|
const tokenDetails = (await db
|
||
|
.transaction(OBJECT_STORE_NAME)
|
||
|
.objectStore(OBJECT_STORE_NAME)
|
||
|
.get(key));
|
||
|
if (tokenDetails) {
|
||
|
return tokenDetails;
|
||
|
}
|
||
|
else {
|
||
|
// Check if there is a tokenDetails object in the old DB.
|
||
|
const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId);
|
||
|
if (oldTokenDetails) {
|
||
|
await dbSet(firebaseDependencies, oldTokenDetails);
|
||
|
return oldTokenDetails;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/** Assigns or overwrites the record for the given key with the given value. */
|
||
|
async function dbSet(firebaseDependencies, tokenDetails) {
|
||
|
const key = getKey(firebaseDependencies);
|
||
|
const db = await getDbPromise();
|
||
|
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
||
|
await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key);
|
||
|
await tx.done;
|
||
|
return tokenDetails;
|
||
|
}
|
||
|
/** Removes record(s) from the objectStore that match the given key. */
|
||
|
async function dbRemove(firebaseDependencies) {
|
||
|
const key = getKey(firebaseDependencies);
|
||
|
const db = await getDbPromise();
|
||
|
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
|
||
|
await tx.objectStore(OBJECT_STORE_NAME).delete(key);
|
||
|
await tx.done;
|
||
|
}
|
||
|
function getKey({ appConfig }) {
|
||
|
return appConfig.appId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2017 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
const ERROR_MAP = {
|
||
|
["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"',
|
||
|
["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.',
|
||
|
["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.',
|
||
|
["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.',
|
||
|
["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.',
|
||
|
["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.",
|
||
|
["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)",
|
||
|
["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}',
|
||
|
["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}',
|
||
|
["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.',
|
||
|
["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' +
|
||
|
'user from FCM: {$errorInfo}',
|
||
|
["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}',
|
||
|
["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.',
|
||
|
["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' +
|
||
|
'called before calling getToken() to ensure your service worker is used.',
|
||
|
["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.',
|
||
|
["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.',
|
||
|
["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.',
|
||
|
["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' +
|
||
|
'called before calling getToken() to ensure your VAPID key is used.'
|
||
|
};
|
||
|
const ERROR_FACTORY = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
async function requestGetToken(firebaseDependencies, subscriptionOptions) {
|
||
|
const headers = await getHeaders(firebaseDependencies);
|
||
|
const body = getBody(subscriptionOptions);
|
||
|
const subscribeOptions = {
|
||
|
method: 'POST',
|
||
|
headers,
|
||
|
body: JSON.stringify(body)
|
||
|
};
|
||
|
let responseData;
|
||
|
try {
|
||
|
const response = await fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions);
|
||
|
responseData = await response.json();
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, {
|
||
|
errorInfo: err === null || err === void 0 ? void 0 : err.toString()
|
||
|
});
|
||
|
}
|
||
|
if (responseData.error) {
|
||
|
const message = responseData.error.message;
|
||
|
throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, {
|
||
|
errorInfo: message
|
||
|
});
|
||
|
}
|
||
|
if (!responseData.token) {
|
||
|
throw ERROR_FACTORY.create("token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */);
|
||
|
}
|
||
|
return responseData.token;
|
||
|
}
|
||
|
async function requestUpdateToken(firebaseDependencies, tokenDetails) {
|
||
|
const headers = await getHeaders(firebaseDependencies);
|
||
|
const body = getBody(tokenDetails.subscriptionOptions);
|
||
|
const updateOptions = {
|
||
|
method: 'PATCH',
|
||
|
headers,
|
||
|
body: JSON.stringify(body)
|
||
|
};
|
||
|
let responseData;
|
||
|
try {
|
||
|
const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${tokenDetails.token}`, updateOptions);
|
||
|
responseData = await response.json();
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, {
|
||
|
errorInfo: err === null || err === void 0 ? void 0 : err.toString()
|
||
|
});
|
||
|
}
|
||
|
if (responseData.error) {
|
||
|
const message = responseData.error.message;
|
||
|
throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, {
|
||
|
errorInfo: message
|
||
|
});
|
||
|
}
|
||
|
if (!responseData.token) {
|
||
|
throw ERROR_FACTORY.create("token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */);
|
||
|
}
|
||
|
return responseData.token;
|
||
|
}
|
||
|
async function requestDeleteToken(firebaseDependencies, token) {
|
||
|
const headers = await getHeaders(firebaseDependencies);
|
||
|
const unsubscribeOptions = {
|
||
|
method: 'DELETE',
|
||
|
headers
|
||
|
};
|
||
|
try {
|
||
|
const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${token}`, unsubscribeOptions);
|
||
|
const responseData = await response.json();
|
||
|
if (responseData.error) {
|
||
|
const message = responseData.error.message;
|
||
|
throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, {
|
||
|
errorInfo: message
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, {
|
||
|
errorInfo: err === null || err === void 0 ? void 0 : err.toString()
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
function getEndpoint({ projectId }) {
|
||
|
return `${ENDPOINT}/projects/${projectId}/registrations`;
|
||
|
}
|
||
|
async function getHeaders({ appConfig, installations }) {
|
||
|
const authToken = await installations.getToken();
|
||
|
return new Headers({
|
||
|
'Content-Type': 'application/json',
|
||
|
Accept: 'application/json',
|
||
|
'x-goog-api-key': appConfig.apiKey,
|
||
|
'x-goog-firebase-installations-auth': `FIS ${authToken}`
|
||
|
});
|
||
|
}
|
||
|
function getBody({ p256dh, auth, endpoint, vapidKey }) {
|
||
|
const body = {
|
||
|
web: {
|
||
|
endpoint,
|
||
|
auth,
|
||
|
p256dh
|
||
|
}
|
||
|
};
|
||
|
if (vapidKey !== DEFAULT_VAPID_KEY) {
|
||
|
body.web.applicationPubKey = vapidKey;
|
||
|
}
|
||
|
return body;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
// UpdateRegistration will be called once every week.
|
||
|
const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||
|
async function getTokenInternal(messaging) {
|
||
|
const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey);
|
||
|
const subscriptionOptions = {
|
||
|
vapidKey: messaging.vapidKey,
|
||
|
swScope: messaging.swRegistration.scope,
|
||
|
endpoint: pushSubscription.endpoint,
|
||
|
auth: arrayToBase64(pushSubscription.getKey('auth')),
|
||
|
p256dh: arrayToBase64(pushSubscription.getKey('p256dh'))
|
||
|
};
|
||
|
const tokenDetails = await dbGet(messaging.firebaseDependencies);
|
||
|
if (!tokenDetails) {
|
||
|
// No token, get a new one.
|
||
|
return getNewToken(messaging.firebaseDependencies, subscriptionOptions);
|
||
|
}
|
||
|
else if (!isTokenValid(tokenDetails.subscriptionOptions, subscriptionOptions)) {
|
||
|
// Invalid token, get a new one.
|
||
|
try {
|
||
|
await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token);
|
||
|
}
|
||
|
catch (e) {
|
||
|
// Suppress errors because of #2364
|
||
|
console.warn(e);
|
||
|
}
|
||
|
return getNewToken(messaging.firebaseDependencies, subscriptionOptions);
|
||
|
}
|
||
|
else if (Date.now() >= tokenDetails.createTime + TOKEN_EXPIRATION_MS) {
|
||
|
// Weekly token refresh
|
||
|
return updateToken(messaging, {
|
||
|
token: tokenDetails.token,
|
||
|
createTime: Date.now(),
|
||
|
subscriptionOptions
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
// Valid token, nothing to do.
|
||
|
return tokenDetails.token;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* This method deletes the token from the database, unsubscribes the token from FCM, and unregisters
|
||
|
* the push subscription if it exists.
|
||
|
*/
|
||
|
async function deleteTokenInternal(messaging) {
|
||
|
const tokenDetails = await dbGet(messaging.firebaseDependencies);
|
||
|
if (tokenDetails) {
|
||
|
await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token);
|
||
|
await dbRemove(messaging.firebaseDependencies);
|
||
|
}
|
||
|
// Unsubscribe from the push subscription.
|
||
|
const pushSubscription = await messaging.swRegistration.pushManager.getSubscription();
|
||
|
if (pushSubscription) {
|
||
|
return pushSubscription.unsubscribe();
|
||
|
}
|
||
|
// If there's no SW, consider it a success.
|
||
|
return true;
|
||
|
}
|
||
|
async function updateToken(messaging, tokenDetails) {
|
||
|
try {
|
||
|
const updatedToken = await requestUpdateToken(messaging.firebaseDependencies, tokenDetails);
|
||
|
const updatedTokenDetails = Object.assign(Object.assign({}, tokenDetails), { token: updatedToken, createTime: Date.now() });
|
||
|
await dbSet(messaging.firebaseDependencies, updatedTokenDetails);
|
||
|
return updatedToken;
|
||
|
}
|
||
|
catch (e) {
|
||
|
await deleteTokenInternal(messaging);
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
async function getNewToken(firebaseDependencies, subscriptionOptions) {
|
||
|
const token = await requestGetToken(firebaseDependencies, subscriptionOptions);
|
||
|
const tokenDetails = {
|
||
|
token,
|
||
|
createTime: Date.now(),
|
||
|
subscriptionOptions
|
||
|
};
|
||
|
await dbSet(firebaseDependencies, tokenDetails);
|
||
|
return tokenDetails.token;
|
||
|
}
|
||
|
/**
|
||
|
* Gets a PushSubscription for the current user.
|
||
|
*/
|
||
|
async function getPushSubscription(swRegistration, vapidKey) {
|
||
|
const subscription = await swRegistration.pushManager.getSubscription();
|
||
|
if (subscription) {
|
||
|
return subscription;
|
||
|
}
|
||
|
return swRegistration.pushManager.subscribe({
|
||
|
userVisibleOnly: true,
|
||
|
// Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key
|
||
|
// submitted to pushManager#subscribe must be of type Uint8Array.
|
||
|
applicationServerKey: base64ToArray(vapidKey)
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the saved tokenDetails object matches the configuration provided.
|
||
|
*/
|
||
|
function isTokenValid(dbOptions, currentOptions) {
|
||
|
const isVapidKeyEqual = currentOptions.vapidKey === dbOptions.vapidKey;
|
||
|
const isEndpointEqual = currentOptions.endpoint === dbOptions.endpoint;
|
||
|
const isAuthEqual = currentOptions.auth === dbOptions.auth;
|
||
|
const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh;
|
||
|
return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function externalizePayload(internalPayload) {
|
||
|
const payload = {
|
||
|
from: internalPayload.from,
|
||
|
// eslint-disable-next-line camelcase
|
||
|
collapseKey: internalPayload.collapse_key,
|
||
|
// eslint-disable-next-line camelcase
|
||
|
messageId: internalPayload.fcmMessageId
|
||
|
};
|
||
|
propagateNotificationPayload(payload, internalPayload);
|
||
|
propagateDataPayload(payload, internalPayload);
|
||
|
propagateFcmOptions(payload, internalPayload);
|
||
|
return payload;
|
||
|
}
|
||
|
function propagateNotificationPayload(payload, messagePayloadInternal) {
|
||
|
if (!messagePayloadInternal.notification) {
|
||
|
return;
|
||
|
}
|
||
|
payload.notification = {};
|
||
|
const title = messagePayloadInternal.notification.title;
|
||
|
if (!!title) {
|
||
|
payload.notification.title = title;
|
||
|
}
|
||
|
const body = messagePayloadInternal.notification.body;
|
||
|
if (!!body) {
|
||
|
payload.notification.body = body;
|
||
|
}
|
||
|
const image = messagePayloadInternal.notification.image;
|
||
|
if (!!image) {
|
||
|
payload.notification.image = image;
|
||
|
}
|
||
|
const icon = messagePayloadInternal.notification.icon;
|
||
|
if (!!icon) {
|
||
|
payload.notification.icon = icon;
|
||
|
}
|
||
|
}
|
||
|
function propagateDataPayload(payload, messagePayloadInternal) {
|
||
|
if (!messagePayloadInternal.data) {
|
||
|
return;
|
||
|
}
|
||
|
payload.data = messagePayloadInternal.data;
|
||
|
}
|
||
|
function propagateFcmOptions(payload, messagePayloadInternal) {
|
||
|
var _a, _b, _c, _d, _e;
|
||
|
// fcmOptions.link value is written into notification.click_action. see more in b/232072111
|
||
|
if (!messagePayloadInternal.fcmOptions &&
|
||
|
!((_a = messagePayloadInternal.notification) === null || _a === void 0 ? void 0 : _a.click_action)) {
|
||
|
return;
|
||
|
}
|
||
|
payload.fcmOptions = {};
|
||
|
const link = (_c = (_b = messagePayloadInternal.fcmOptions) === null || _b === void 0 ? void 0 : _b.link) !== null && _c !== void 0 ? _c : (_d = messagePayloadInternal.notification) === null || _d === void 0 ? void 0 : _d.click_action;
|
||
|
if (!!link) {
|
||
|
payload.fcmOptions.link = link;
|
||
|
}
|
||
|
// eslint-disable-next-line camelcase
|
||
|
const analyticsLabel = (_e = messagePayloadInternal.fcmOptions) === null || _e === void 0 ? void 0 : _e.analytics_label;
|
||
|
if (!!analyticsLabel) {
|
||
|
payload.fcmOptions.analyticsLabel = analyticsLabel;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function isConsoleMessage(data) {
|
||
|
// This message has a campaign ID, meaning it was sent using the Firebase Console.
|
||
|
return typeof data === 'object' && !!data && CONSOLE_CAMPAIGN_ID in data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
/** Returns a promise that resolves after given time passes. */
|
||
|
function sleep(ms) {
|
||
|
return new Promise(resolve => {
|
||
|
setTimeout(resolve, ms);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
_mergeStrings('hts/frbslgigp.ogepscmv/ieo/eaylg', 'tp:/ieaeogn-agolai.o/1frlglgc/o');
|
||
|
_mergeStrings('AzSCbw63g1R0nCw85jG8', 'Iaya3yLKwmgvh7cF0q4');
|
||
|
async function stageLog(messaging, internalPayload) {
|
||
|
const fcmEvent = createFcmEvent(internalPayload, await messaging.firebaseDependencies.installations.getId());
|
||
|
createAndEnqueueLogEvent(messaging, fcmEvent, internalPayload.productId);
|
||
|
}
|
||
|
function createFcmEvent(internalPayload, fid) {
|
||
|
var _a, _b;
|
||
|
const fcmEvent = {};
|
||
|
/* eslint-disable camelcase */
|
||
|
// some fields should always be non-null. Still check to ensure.
|
||
|
if (!!internalPayload.from) {
|
||
|
fcmEvent.project_number = internalPayload.from;
|
||
|
}
|
||
|
if (!!internalPayload.fcmMessageId) {
|
||
|
fcmEvent.message_id = internalPayload.fcmMessageId;
|
||
|
}
|
||
|
fcmEvent.instance_id = fid;
|
||
|
if (!!internalPayload.notification) {
|
||
|
fcmEvent.message_type = MessageType$1.DISPLAY_NOTIFICATION.toString();
|
||
|
}
|
||
|
else {
|
||
|
fcmEvent.message_type = MessageType$1.DATA_MESSAGE.toString();
|
||
|
}
|
||
|
fcmEvent.sdk_platform = SDK_PLATFORM_WEB.toString();
|
||
|
fcmEvent.package_name = self.origin.replace(/(^\w+:|^)\/\//, '');
|
||
|
if (!!internalPayload.collapse_key) {
|
||
|
fcmEvent.collapse_key = internalPayload.collapse_key;
|
||
|
}
|
||
|
fcmEvent.event = EVENT_MESSAGE_DELIVERED.toString();
|
||
|
if (!!((_a = internalPayload.fcmOptions) === null || _a === void 0 ? void 0 : _a.analytics_label)) {
|
||
|
fcmEvent.analytics_label = (_b = internalPayload.fcmOptions) === null || _b === void 0 ? void 0 : _b.analytics_label;
|
||
|
}
|
||
|
/* eslint-enable camelcase */
|
||
|
return fcmEvent;
|
||
|
}
|
||
|
function createAndEnqueueLogEvent(messaging, fcmEvent, productId) {
|
||
|
const logEvent = {};
|
||
|
/* eslint-disable camelcase */
|
||
|
logEvent.event_time_ms = Math.floor(Date.now()).toString();
|
||
|
logEvent.source_extension_json_proto3 = JSON.stringify(fcmEvent);
|
||
|
if (!!productId) {
|
||
|
logEvent.compliance_data = buildComplianceData(productId);
|
||
|
}
|
||
|
// eslint-disable-next-line camelcase
|
||
|
messaging.logEvents.push(logEvent);
|
||
|
}
|
||
|
function buildComplianceData(productId) {
|
||
|
const complianceData = {
|
||
|
privacy_context: {
|
||
|
prequest: {
|
||
|
origin_associated_product_id: productId
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
return complianceData;
|
||
|
}
|
||
|
function _mergeStrings(s1, s2) {
|
||
|
const resultArray = [];
|
||
|
for (let i = 0; i < s1.length; i++) {
|
||
|
resultArray.push(s1.charAt(i));
|
||
|
if (i < s2.length) {
|
||
|
resultArray.push(s2.charAt(i));
|
||
|
}
|
||
|
}
|
||
|
return resultArray.join('');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2017 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
async function onSubChange(event, messaging) {
|
||
|
var _a, _b;
|
||
|
const { newSubscription } = event;
|
||
|
if (!newSubscription) {
|
||
|
// Subscription revoked, delete token
|
||
|
await deleteTokenInternal(messaging);
|
||
|
return;
|
||
|
}
|
||
|
const tokenDetails = await dbGet(messaging.firebaseDependencies);
|
||
|
await deleteTokenInternal(messaging);
|
||
|
messaging.vapidKey =
|
||
|
(_b = (_a = tokenDetails === null || tokenDetails === void 0 ? void 0 : tokenDetails.subscriptionOptions) === null || _a === void 0 ? void 0 : _a.vapidKey) !== null && _b !== void 0 ? _b : DEFAULT_VAPID_KEY;
|
||
|
await getTokenInternal(messaging);
|
||
|
}
|
||
|
async function onPush(event, messaging) {
|
||
|
const internalPayload = getMessagePayloadInternal(event);
|
||
|
if (!internalPayload) {
|
||
|
// Failed to get parsed MessagePayload from the PushEvent. Skip handling the push.
|
||
|
return;
|
||
|
}
|
||
|
// log to Firelog with user consent
|
||
|
if (messaging.deliveryMetricsExportedToBigQueryEnabled) {
|
||
|
await stageLog(messaging, internalPayload);
|
||
|
}
|
||
|
// foreground handling: eventually passed to onMessage hook
|
||
|
const clientList = await getClientList();
|
||
|
if (hasVisibleClients(clientList)) {
|
||
|
return sendMessagePayloadInternalToWindows(clientList, internalPayload);
|
||
|
}
|
||
|
// background handling: display if possible and pass to onBackgroundMessage hook
|
||
|
if (!!internalPayload.notification) {
|
||
|
await showNotification(wrapInternalPayload(internalPayload));
|
||
|
}
|
||
|
if (!messaging) {
|
||
|
return;
|
||
|
}
|
||
|
if (!!messaging.onBackgroundMessageHandler) {
|
||
|
const payload = externalizePayload(internalPayload);
|
||
|
if (typeof messaging.onBackgroundMessageHandler === 'function') {
|
||
|
await messaging.onBackgroundMessageHandler(payload);
|
||
|
}
|
||
|
else {
|
||
|
messaging.onBackgroundMessageHandler.next(payload);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
async function onNotificationClick(event) {
|
||
|
var _a, _b;
|
||
|
const internalPayload = (_b = (_a = event.notification) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[FCM_MSG];
|
||
|
if (!internalPayload) {
|
||
|
return;
|
||
|
}
|
||
|
else if (event.action) {
|
||
|
// User clicked on an action button. This will allow developers to act on action button clicks
|
||
|
// by using a custom onNotificationClick listener that they define.
|
||
|
return;
|
||
|
}
|
||
|
// Prevent other listeners from receiving the event
|
||
|
event.stopImmediatePropagation();
|
||
|
event.notification.close();
|
||
|
// Note clicking on a notification with no link set will focus the Chrome's current tab.
|
||
|
const link = getLink(internalPayload);
|
||
|
if (!link) {
|
||
|
return;
|
||
|
}
|
||
|
// FM should only open/focus links from app's origin.
|
||
|
const url = new URL(link, self.location.href);
|
||
|
const originUrl = new URL(self.location.origin);
|
||
|
if (url.host !== originUrl.host) {
|
||
|
return;
|
||
|
}
|
||
|
let client = await getWindowClient(url);
|
||
|
if (!client) {
|
||
|
client = await self.clients.openWindow(link);
|
||
|
// Wait three seconds for the client to initialize and set up the message handler so that it
|
||
|
// can receive the message.
|
||
|
await sleep(3000);
|
||
|
}
|
||
|
else {
|
||
|
client = await client.focus();
|
||
|
}
|
||
|
if (!client) {
|
||
|
// Window Client will not be returned if it's for a third party origin.
|
||
|
return;
|
||
|
}
|
||
|
internalPayload.messageType = MessageType.NOTIFICATION_CLICKED;
|
||
|
internalPayload.isFirebaseMessaging = true;
|
||
|
return client.postMessage(internalPayload);
|
||
|
}
|
||
|
function wrapInternalPayload(internalPayload) {
|
||
|
const wrappedInternalPayload = Object.assign({}, internalPayload.notification);
|
||
|
// Put the message payload under FCM_MSG name so we can identify the notification as being an FCM
|
||
|
// notification vs a notification from somewhere else (i.e. normal web push or developer generated
|
||
|
// notification).
|
||
|
wrappedInternalPayload.data = {
|
||
|
[FCM_MSG]: internalPayload
|
||
|
};
|
||
|
return wrappedInternalPayload;
|
||
|
}
|
||
|
function getMessagePayloadInternal({ data }) {
|
||
|
if (!data) {
|
||
|
return null;
|
||
|
}
|
||
|
try {
|
||
|
return data.json();
|
||
|
}
|
||
|
catch (err) {
|
||
|
// Not JSON so not an FCM message.
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* @param url The URL to look for when focusing a client.
|
||
|
* @return Returns an existing window client or a newly opened WindowClient.
|
||
|
*/
|
||
|
async function getWindowClient(url) {
|
||
|
const clientList = await getClientList();
|
||
|
for (const client of clientList) {
|
||
|
const clientUrl = new URL(client.url, self.location.href);
|
||
|
if (url.host === clientUrl.host) {
|
||
|
return client;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
/**
|
||
|
* @returns If there is currently a visible WindowClient, this method will resolve to true,
|
||
|
* otherwise false.
|
||
|
*/
|
||
|
function hasVisibleClients(clientList) {
|
||
|
return clientList.some(client => client.visibilityState === 'visible' &&
|
||
|
// Ignore chrome-extension clients as that matches the background pages of extensions, which
|
||
|
// are always considered visible for some reason.
|
||
|
!client.url.startsWith('chrome-extension://'));
|
||
|
}
|
||
|
function sendMessagePayloadInternalToWindows(clientList, internalPayload) {
|
||
|
internalPayload.isFirebaseMessaging = true;
|
||
|
internalPayload.messageType = MessageType.PUSH_RECEIVED;
|
||
|
for (const client of clientList) {
|
||
|
client.postMessage(internalPayload);
|
||
|
}
|
||
|
}
|
||
|
function getClientList() {
|
||
|
return self.clients.matchAll({
|
||
|
type: 'window',
|
||
|
includeUncontrolled: true
|
||
|
// TS doesn't know that "type: 'window'" means it'll return WindowClient[]
|
||
|
});
|
||
|
}
|
||
|
function showNotification(notificationPayloadInternal) {
|
||
|
var _a;
|
||
|
// Note: Firefox does not support the maxActions property.
|
||
|
// https://developer.mozilla.org/en-US/docs/Web/API/notification/maxActions
|
||
|
const { actions } = notificationPayloadInternal;
|
||
|
const { maxActions } = Notification;
|
||
|
if (actions && maxActions && actions.length > maxActions) {
|
||
|
console.warn(`This browser only supports ${maxActions} actions. The remaining actions will not be displayed.`);
|
||
|
}
|
||
|
return self.registration.showNotification(
|
||
|
/* title= */ (_a = notificationPayloadInternal.title) !== null && _a !== void 0 ? _a : '', notificationPayloadInternal);
|
||
|
}
|
||
|
function getLink(payload) {
|
||
|
var _a, _b, _c;
|
||
|
// eslint-disable-next-line camelcase
|
||
|
const link = (_b = (_a = payload.fcmOptions) === null || _a === void 0 ? void 0 : _a.link) !== null && _b !== void 0 ? _b : (_c = payload.notification) === null || _c === void 0 ? void 0 : _c.click_action;
|
||
|
if (link) {
|
||
|
return link;
|
||
|
}
|
||
|
if (isConsoleMessage(payload.data)) {
|
||
|
// Notification created in the Firebase Console. Redirect to origin.
|
||
|
return self.location.origin;
|
||
|
}
|
||
|
else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2019 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function extractAppConfig(app) {
|
||
|
if (!app || !app.options) {
|
||
|
throw getMissingValueError('App Configuration Object');
|
||
|
}
|
||
|
if (!app.name) {
|
||
|
throw getMissingValueError('App Name');
|
||
|
}
|
||
|
// Required app config keys
|
||
|
const configKeys = [
|
||
|
'projectId',
|
||
|
'apiKey',
|
||
|
'appId',
|
||
|
'messagingSenderId'
|
||
|
];
|
||
|
const { options } = app;
|
||
|
for (const keyName of configKeys) {
|
||
|
if (!options[keyName]) {
|
||
|
throw getMissingValueError(keyName);
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
appName: app.name,
|
||
|
projectId: options.projectId,
|
||
|
apiKey: options.apiKey,
|
||
|
appId: options.appId,
|
||
|
senderId: options.messagingSenderId
|
||
|
};
|
||
|
}
|
||
|
function getMissingValueError(valueName) {
|
||
|
return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, {
|
||
|
valueName
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
class MessagingService {
|
||
|
constructor(app, installations, analyticsProvider) {
|
||
|
// logging is only done with end user consent. Default to false.
|
||
|
this.deliveryMetricsExportedToBigQueryEnabled = false;
|
||
|
this.onBackgroundMessageHandler = null;
|
||
|
this.onMessageHandler = null;
|
||
|
this.logEvents = [];
|
||
|
this.isLogServiceStarted = false;
|
||
|
const appConfig = extractAppConfig(app);
|
||
|
this.firebaseDependencies = {
|
||
|
app,
|
||
|
appConfig,
|
||
|
installations,
|
||
|
analyticsProvider
|
||
|
};
|
||
|
}
|
||
|
_delete() {
|
||
|
return Promise.resolve();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
const SwMessagingFactory = (container) => {
|
||
|
const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal'));
|
||
|
self.addEventListener('push', e => {
|
||
|
e.waitUntil(onPush(e, messaging));
|
||
|
});
|
||
|
self.addEventListener('pushsubscriptionchange', e => {
|
||
|
e.waitUntil(onSubChange(e, messaging));
|
||
|
});
|
||
|
self.addEventListener('notificationclick', e => {
|
||
|
e.waitUntil(onNotificationClick(e));
|
||
|
});
|
||
|
return messaging;
|
||
|
};
|
||
|
/**
|
||
|
* The messaging instance registered in sw is named differently than that of in client. This is
|
||
|
* because both `registerMessagingInWindow` and `registerMessagingInSw` would be called in
|
||
|
* `messaging-compat` and component with the same name can only be registered once.
|
||
|
*/
|
||
|
function registerMessagingInSw() {
|
||
|
_registerComponent(new Component('messaging-sw', SwMessagingFactory, "PUBLIC" /* ComponentType.PUBLIC */));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
/**
|
||
|
* Checks whether all required APIs exist within SW Context
|
||
|
* @returns a Promise that resolves to a boolean.
|
||
|
*
|
||
|
* @public
|
||
|
*/
|
||
|
async function isSwSupported() {
|
||
|
// firebase-js-sdk/issues/2393 reveals that idb#open in Safari iframe and Firefox private browsing
|
||
|
// might be prohibited to run. In these contexts, an error would be thrown during the messaging
|
||
|
// instantiating phase, informing the developers to import/call isSupported for special handling.
|
||
|
return (isIndexedDBAvailable() &&
|
||
|
(await validateIndexedDBOpenable()) &&
|
||
|
'PushManager' in self &&
|
||
|
'Notification' in self &&
|
||
|
ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') &&
|
||
|
PushSubscription.prototype.hasOwnProperty('getKey'));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function onBackgroundMessage$1(messaging, nextOrObserver) {
|
||
|
if (self.document !== undefined) {
|
||
|
throw ERROR_FACTORY.create("only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */);
|
||
|
}
|
||
|
messaging.onBackgroundMessageHandler = nextOrObserver;
|
||
|
return () => {
|
||
|
messaging.onBackgroundMessageHandler = null;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
function _setDeliveryMetricsExportedToBigQueryEnabled(messaging, enable) {
|
||
|
messaging.deliveryMetricsExportedToBigQueryEnabled =
|
||
|
enable;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2017 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
/**
|
||
|
* Retrieves a Firebase Cloud Messaging instance.
|
||
|
*
|
||
|
* @returns The Firebase Cloud Messaging instance associated with the provided firebase app.
|
||
|
*
|
||
|
* @public
|
||
|
*/
|
||
|
function getMessagingInSw(app = getApp()) {
|
||
|
// Conscious decision to make this async check non-blocking during the messaging instance
|
||
|
// initialization phase for performance consideration. An error would be thrown latter for
|
||
|
// developer's information. Developers can then choose to import and call `isSupported` for
|
||
|
// special handling.
|
||
|
isSwSupported().then(isSupported => {
|
||
|
// If `isSwSupported()` resolved, but returned false.
|
||
|
if (!isSupported) {
|
||
|
throw ERROR_FACTORY.create("unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */);
|
||
|
}
|
||
|
}, _ => {
|
||
|
// If `isSwSupported()` rejected.
|
||
|
throw ERROR_FACTORY.create("indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */);
|
||
|
});
|
||
|
return _getProvider(getModularInstance(app), 'messaging-sw').getImmediate();
|
||
|
}
|
||
|
/**
|
||
|
* Called when a message is received while the app is in the background. An app is considered to be
|
||
|
* in the background if no active window is displayed.
|
||
|
*
|
||
|
* @param messaging - The {@link Messaging} instance.
|
||
|
* @param nextOrObserver - This function, or observer object with `next` defined, is called when a
|
||
|
* message is received and the app is currently in the background.
|
||
|
*
|
||
|
* @returns To stop listening for messages execute this returned function
|
||
|
*
|
||
|
* @public
|
||
|
*/
|
||
|
function onBackgroundMessage(messaging, nextOrObserver) {
|
||
|
messaging = getModularInstance(messaging);
|
||
|
return onBackgroundMessage$1(messaging, nextOrObserver);
|
||
|
}
|
||
|
/**
|
||
|
* Enables or disables Firebase Cloud Messaging message delivery metrics export to BigQuery. By
|
||
|
* default, message delivery metrics are not exported to BigQuery. Use this method to enable or
|
||
|
* disable the export at runtime.
|
||
|
*
|
||
|
* @param messaging - The `FirebaseMessaging` instance.
|
||
|
* @param enable - Whether Firebase Cloud Messaging should export message delivery metrics to
|
||
|
* BigQuery.
|
||
|
*
|
||
|
* @public
|
||
|
*/
|
||
|
function experimentalSetDeliveryMetricsExportedToBigQueryEnabled(messaging, enable) {
|
||
|
messaging = getModularInstance(messaging);
|
||
|
return _setDeliveryMetricsExportedToBigQueryEnabled(messaging, enable);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @license
|
||
|
* Copyright 2017 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
registerMessagingInSw();
|
||
|
|
||
|
export { experimentalSetDeliveryMetricsExportedToBigQueryEnabled, getMessagingInSw as getMessaging, isSwSupported as isSupported, onBackgroundMessage };
|
||
|
//# sourceMappingURL=index.sw.esm2017.js.map
|