mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
Add types (#637)
* Add types to @firebase/messaging This makes src/ compatible with --noImplicitAny. test/ still needs work. * [AUTOMATED]: License Headers * Remove casts
This commit is contained in:
committed by
GitHub
parent
684bf6ed82
commit
f6d5504196
@@ -17,11 +17,16 @@
|
||||
import { WindowController } from './src/controllers/window-controller';
|
||||
import { SWController } from './src/controllers/sw-controller';
|
||||
import { firebase } from '@firebase/app';
|
||||
import {
|
||||
_FirebaseNamespace,
|
||||
FirebaseServiceFactory
|
||||
} from '@firebase/app-types/private';
|
||||
|
||||
import * as types from '@firebase/messaging-types';
|
||||
|
||||
export function registerMessaging(instance) {
|
||||
export function registerMessaging(instance: _FirebaseNamespace) {
|
||||
const messagingName = 'messaging';
|
||||
const factoryMethod = app => {
|
||||
const factoryMethod: FirebaseServiceFactory = app => {
|
||||
if (self && 'ServiceWorkerGlobalScope' in self) {
|
||||
return new SWController(app);
|
||||
}
|
||||
@@ -42,7 +47,7 @@ export function registerMessaging(instance) {
|
||||
);
|
||||
}
|
||||
|
||||
registerMessaging(firebase);
|
||||
registerMessaging(firebase as _FirebaseNamespace);
|
||||
|
||||
/**
|
||||
* Define extension behavior of `registerMessaging`
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@firebase/app": "^0.1.0"
|
||||
"@firebase/app": "^0.1.0",
|
||||
"@firebase/app-types": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@firebase/messaging-types": "0.1.2",
|
||||
|
||||
@@ -18,18 +18,25 @@ import { ErrorFactory } from '@firebase/util';
|
||||
import { ERROR_CODES, ERROR_MAP } from '../models/errors';
|
||||
import { TokenDetailsModel } from '../models/token-details-model';
|
||||
import { VapidDetailsModel } from '../models/vapid-details-model';
|
||||
import { NotificationPermission } from '../models/notification-permission';
|
||||
import { IIDModel } from '../models/iid-model';
|
||||
import { arrayBufferToBase64 } from '../helpers/array-buffer-to-base64';
|
||||
import { FirebaseApp } from '@firebase/app-types';
|
||||
import { TokenDetails } from '../interfaces/token-details';
|
||||
import {
|
||||
createSubscribe,
|
||||
Observer,
|
||||
NextFn,
|
||||
PartialObserver
|
||||
} from '@firebase/util';
|
||||
|
||||
const SENDER_ID_OPTION_NAME = 'messagingSenderId';
|
||||
// Database cache should be invalidated once a week.
|
||||
export const TOKEN_EXPIRATION_MILLIS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||
|
||||
export class ControllerInterface {
|
||||
public app;
|
||||
public INTERNAL;
|
||||
protected errorFactory_;
|
||||
export abstract class ControllerInterface {
|
||||
public app: FirebaseApp;
|
||||
public INTERNAL: any;
|
||||
protected errorFactory_: ErrorFactory<string>;
|
||||
private messagingSenderId_: string;
|
||||
private tokenDetailsModel_: TokenDetailsModel;
|
||||
private vapidDetailsModel_: VapidDetailsModel;
|
||||
@@ -37,9 +44,8 @@ export class ControllerInterface {
|
||||
|
||||
/**
|
||||
* An interface of the Messaging Service API
|
||||
* @param {!firebase.app.App} app
|
||||
*/
|
||||
constructor(app) {
|
||||
constructor(app: FirebaseApp) {
|
||||
this.errorFactory_ = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
||||
|
||||
if (
|
||||
@@ -49,7 +55,7 @@ export class ControllerInterface {
|
||||
throw this.errorFactory_.create(ERROR_CODES.BAD_SENDER_ID);
|
||||
}
|
||||
|
||||
this.messagingSenderId_ = app.options[SENDER_ID_OPTION_NAME];
|
||||
this.messagingSenderId_ = app.options[SENDER_ID_OPTION_NAME]!;
|
||||
|
||||
this.tokenDetailsModel_ = new TokenDetailsModel();
|
||||
this.vapidDetailsModel_ = new VapidDetailsModel();
|
||||
@@ -66,8 +72,8 @@ export class ControllerInterface {
|
||||
async getToken(): Promise<string | null> {
|
||||
// Check with permissions
|
||||
const currentPermission = this.getNotificationPermission_();
|
||||
if (currentPermission !== NotificationPermission.GRANTED) {
|
||||
if (currentPermission === NotificationPermission.DENIED) {
|
||||
if (currentPermission !== 'granted') {
|
||||
if (currentPermission === 'denied') {
|
||||
return Promise.reject(
|
||||
this.errorFactory_.create(ERROR_CODES.NOTIFICATIONS_BLOCKED)
|
||||
);
|
||||
@@ -113,7 +119,7 @@ export class ControllerInterface {
|
||||
swReg: ServiceWorkerRegistration,
|
||||
pushSubscription: PushSubscription,
|
||||
publicVapidKey: Uint8Array,
|
||||
tokenDetails: Object
|
||||
tokenDetails: TokenDetails
|
||||
): Promise<string> {
|
||||
const isTokenValid = this.isTokenStillValid(
|
||||
pushSubscription,
|
||||
@@ -122,8 +128,8 @@ export class ControllerInterface {
|
||||
);
|
||||
if (isTokenValid) {
|
||||
const now = Date.now();
|
||||
if (now < tokenDetails['createTime'] + TOKEN_EXPIRATION_MILLIS) {
|
||||
return tokenDetails['fcmToken'];
|
||||
if (now < tokenDetails.createTime! + TOKEN_EXPIRATION_MILLIS) {
|
||||
return tokenDetails.fcmToken;
|
||||
} else {
|
||||
return this.updateToken(
|
||||
swReg,
|
||||
@@ -138,7 +144,7 @@ export class ControllerInterface {
|
||||
// have changed), delete the existing token from the FCM client and server
|
||||
// database. No need to unsubscribe from the Service Worker as we have a
|
||||
// good push subscription that we'd like to use in getNewToken.
|
||||
await this.deleteTokenFromDB(tokenDetails['fcmToken']);
|
||||
await this.deleteTokenFromDB(tokenDetails.fcmToken);
|
||||
return this.getNewToken(swReg, pushSubscription, publicVapidKey);
|
||||
}
|
||||
|
||||
@@ -148,20 +154,20 @@ export class ControllerInterface {
|
||||
private isTokenStillValid(
|
||||
pushSubscription: PushSubscription,
|
||||
publicVapidKey: Uint8Array,
|
||||
tokenDetails: Object
|
||||
): Boolean {
|
||||
if (arrayBufferToBase64(publicVapidKey) !== tokenDetails['vapidKey']) {
|
||||
tokenDetails: TokenDetails
|
||||
): boolean {
|
||||
if (arrayBufferToBase64(publicVapidKey) !== tokenDetails.vapidKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// getKey() isn't defined in the PushSubscription externs file, hence
|
||||
// subscription['getKey']('<key name>').
|
||||
// subscription.getKey('<key name>').
|
||||
return (
|
||||
pushSubscription.endpoint === tokenDetails['endpoint'] &&
|
||||
arrayBufferToBase64(pushSubscription['getKey']('auth')) ===
|
||||
tokenDetails['auth'] &&
|
||||
arrayBufferToBase64(pushSubscription['getKey']('p256dh')) ===
|
||||
tokenDetails['p256dh']
|
||||
pushSubscription.endpoint === tokenDetails.endpoint &&
|
||||
arrayBufferToBase64(pushSubscription.getKey('auth')!) ===
|
||||
tokenDetails.auth &&
|
||||
arrayBufferToBase64(pushSubscription.getKey('p256dh')!) ===
|
||||
tokenDetails.p256dh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -169,24 +175,24 @@ export class ControllerInterface {
|
||||
swReg: ServiceWorkerRegistration,
|
||||
pushSubscription: PushSubscription,
|
||||
publicVapidKey: Uint8Array,
|
||||
tokenDetails: Object
|
||||
tokenDetails: TokenDetails
|
||||
): Promise<string> {
|
||||
try {
|
||||
const updatedToken = await this.iidModel_.updateToken(
|
||||
this.messagingSenderId_,
|
||||
tokenDetails['fcmToken'],
|
||||
tokenDetails['fcmPushSet'],
|
||||
tokenDetails.fcmToken,
|
||||
tokenDetails.fcmPushSet,
|
||||
pushSubscription,
|
||||
publicVapidKey
|
||||
);
|
||||
|
||||
const allDetails = {
|
||||
const allDetails: TokenDetails = {
|
||||
swScope: swReg.scope,
|
||||
vapidKey: publicVapidKey,
|
||||
subscription: pushSubscription,
|
||||
fcmSenderId: this.messagingSenderId_,
|
||||
fcmToken: updatedToken,
|
||||
fcmPushSet: tokenDetails['fcmPushSet']
|
||||
fcmPushSet: tokenDetails.fcmPushSet
|
||||
};
|
||||
|
||||
await this.tokenDetailsModel_.saveTokenDetails(allDetails);
|
||||
@@ -196,7 +202,7 @@ export class ControllerInterface {
|
||||
);
|
||||
return updatedToken;
|
||||
} catch (e) {
|
||||
await this.deleteToken(tokenDetails['fcmToken']);
|
||||
await this.deleteToken(tokenDetails.fcmToken);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -211,17 +217,17 @@ export class ControllerInterface {
|
||||
pushSubscription,
|
||||
publicVapidKey
|
||||
);
|
||||
const allDetails = {
|
||||
const allDetails: TokenDetails = {
|
||||
swScope: swReg.scope,
|
||||
vapidKey: publicVapidKey,
|
||||
subscription: pushSubscription,
|
||||
fcmSenderId: this.messagingSenderId_,
|
||||
fcmToken: tokenDetails['token'],
|
||||
fcmPushSet: tokenDetails['pushSet']
|
||||
fcmToken: tokenDetails.token,
|
||||
fcmPushSet: tokenDetails.pushSet
|
||||
};
|
||||
await this.tokenDetailsModel_.saveTokenDetails(allDetails);
|
||||
await this.vapidDetailsModel_.saveVapidDetails(swReg.scope, publicVapidKey);
|
||||
return tokenDetails['token'];
|
||||
return tokenDetails.token;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,7 +237,7 @@ export class ControllerInterface {
|
||||
* whether or not the unsubscribe request was processed successfully.
|
||||
* @export
|
||||
*/
|
||||
async deleteToken(token: string): Promise<Boolean> {
|
||||
async deleteToken(token: string): Promise<boolean> {
|
||||
// Delete the token details from the database.
|
||||
await this.deleteTokenFromDB(token);
|
||||
// Unsubscribe from the SW.
|
||||
@@ -254,19 +260,19 @@ export class ControllerInterface {
|
||||
private async deleteTokenFromDB(token: string): Promise<void> {
|
||||
const details = await this.tokenDetailsModel_.deleteToken(token);
|
||||
await this.iidModel_.deleteToken(
|
||||
details['fcmSenderId'],
|
||||
details['fcmToken'],
|
||||
details['fcmPushSet']
|
||||
details.fcmSenderId,
|
||||
details.fcmToken,
|
||||
details.fcmPushSet
|
||||
);
|
||||
}
|
||||
|
||||
getSWRegistration_(): Promise<ServiceWorkerRegistration> {
|
||||
throw this.errorFactory_.create(ERROR_CODES.SHOULD_BE_INHERITED);
|
||||
}
|
||||
// Visible for testing
|
||||
// TODO: Make protected
|
||||
abstract getSWRegistration_(): Promise<ServiceWorkerRegistration>;
|
||||
|
||||
getPublicVapidKey_(): Promise<Uint8Array> {
|
||||
throw this.errorFactory_.create(ERROR_CODES.SHOULD_BE_INHERITED);
|
||||
}
|
||||
// Visible for testing
|
||||
// TODO: Make protected
|
||||
abstract getPublicVapidKey_(): Promise<Uint8Array>;
|
||||
|
||||
/**
|
||||
* Gets a PushSubscription for the current user.
|
||||
@@ -295,44 +301,27 @@ export class ControllerInterface {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!ServiceWorkerRegistration} registration
|
||||
*/
|
||||
useServiceWorker(registration) {
|
||||
useServiceWorker(registration: ServiceWorkerRegistration) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!string} b64PublicKey
|
||||
*/
|
||||
usePublicVapidKey(b64PublicKey) {
|
||||
usePublicVapidKey(b64PublicKey: string) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!firebase.Observer|function(*)} nextOrObserver
|
||||
* @param {function(!Error)=} optError
|
||||
* @param {function()=} optCompleted
|
||||
* @return {!function()}
|
||||
*/
|
||||
onMessage(nextOrObserver, optError, optCompleted) {
|
||||
onMessage(
|
||||
nextOrObserver: NextFn<{}> | PartialObserver<{}>,
|
||||
error?: (e: Error) => void,
|
||||
completed?: () => void
|
||||
) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!firebase.Observer|function()} nextOrObserver An observer object
|
||||
* or a function triggered on token refresh.
|
||||
* @param {function(!Error)=} optError Optional A function
|
||||
* triggered on token refresh error.
|
||||
* @param {function()=} optCompleted Optional function triggered when the
|
||||
* observer is removed.
|
||||
* @return {!function()} The unsubscribe function for the observer.
|
||||
*/
|
||||
onTokenRefresh(nextOrObserver, optError, optCompleted) {
|
||||
onTokenRefresh(
|
||||
nextOrObserver: NextFn<{}> | PartialObserver<{}>,
|
||||
error?: (e: Error) => void,
|
||||
completed?: () => void
|
||||
) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_WINDOW);
|
||||
}
|
||||
|
||||
@@ -340,11 +329,7 @@ export class ControllerInterface {
|
||||
// The following methods are used by the service worker only.
|
||||
//
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {function(Object)} callback
|
||||
*/
|
||||
setBackgroundMessageHandler(callback) {
|
||||
setBackgroundMessageHandler(callback: (a: any) => any) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.AVAILABLE_IN_SW);
|
||||
}
|
||||
|
||||
@@ -369,7 +354,7 @@ export class ControllerInterface {
|
||||
* @private
|
||||
* @return {string} The currenct permission state.
|
||||
*/
|
||||
getNotificationPermission_() {
|
||||
getNotificationPermission_(): NotificationPermission {
|
||||
return (Notification as any).permission;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,24 +18,37 @@ import { ControllerInterface } from './controller-interface';
|
||||
import { ERROR_CODES } from '../models/errors';
|
||||
import { DEFAULT_PUBLIC_VAPID_KEY } from '../models/fcm-details';
|
||||
import WorkerPageMessage from '../models/worker-page-message';
|
||||
import { FirebaseApp } from '@firebase/app-types';
|
||||
|
||||
const FCM_MSG = 'FCM_MSG';
|
||||
|
||||
export class SWController extends ControllerInterface {
|
||||
private bgMessageHandler_: ((input: Object) => Promise<any>) | null = null;
|
||||
export type BgMessageHandler = (input: any) => Promise<any>;
|
||||
|
||||
constructor(app) {
|
||||
export class SWController extends ControllerInterface {
|
||||
private bgMessageHandler_: BgMessageHandler | null = null;
|
||||
|
||||
constructor(app: FirebaseApp) {
|
||||
super(app);
|
||||
|
||||
self.addEventListener('push', e => this.onPush_(e), false);
|
||||
self.addEventListener(
|
||||
'push',
|
||||
(e: any) => {
|
||||
this.onPush_(e);
|
||||
},
|
||||
false
|
||||
);
|
||||
self.addEventListener(
|
||||
'pushsubscriptionchange',
|
||||
e => this.onSubChange_(e),
|
||||
(e: any) => {
|
||||
this.onSubChange_(e);
|
||||
},
|
||||
false
|
||||
);
|
||||
self.addEventListener(
|
||||
'notificationclick',
|
||||
e => this.onNotificationClick_(e),
|
||||
(e: any) => {
|
||||
this.onNotificationClick_(e);
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -51,12 +64,13 @@ export class SWController extends ControllerInterface {
|
||||
*
|
||||
* If there is no notification data in the payload then no notification will be
|
||||
* shown.
|
||||
* @private
|
||||
*/
|
||||
onPush_(event) {
|
||||
let msgPayload;
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
onPush_(event: any) {
|
||||
let msgPayload: any;
|
||||
try {
|
||||
msgPayload = event.data.json();
|
||||
msgPayload = event.data!.json();
|
||||
} catch (err) {
|
||||
// Not JSON so not an FCM message
|
||||
return;
|
||||
@@ -75,8 +89,8 @@ export class SWController extends ControllerInterface {
|
||||
|
||||
const notificationDetails = this.getNotificationData_(msgPayload);
|
||||
if (notificationDetails) {
|
||||
const notificationTitle = notificationDetails.title || '';
|
||||
return (this.getSWRegistration_() as any).then(reg => {
|
||||
const notificationTitle = (notificationDetails as any).title || '';
|
||||
return this.getSWRegistration_().then(reg => {
|
||||
return reg.showNotification(notificationTitle, notificationDetails);
|
||||
});
|
||||
} else if (this.bgMessageHandler_) {
|
||||
@@ -88,10 +102,9 @@ export class SWController extends ControllerInterface {
|
||||
event.waitUntil(handleMsgPromise);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onSubChange_(event) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
onSubChange_(event: any) {
|
||||
const promiseChain = this.getSWRegistration_()
|
||||
.then(registration => {
|
||||
return registration.pushManager
|
||||
@@ -129,10 +142,9 @@ export class SWController extends ControllerInterface {
|
||||
event.waitUntil(promiseChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onNotificationClick_(event) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
onNotificationClick_(event: any) {
|
||||
if (
|
||||
!(
|
||||
event.notification &&
|
||||
@@ -192,12 +204,9 @@ export class SWController extends ControllerInterface {
|
||||
event.waitUntil(promiseChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} msgPayload
|
||||
* @return {NotificationOptions|undefined}
|
||||
*/
|
||||
getNotificationData_(msgPayload) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
getNotificationData_(msgPayload: any): NotificationOptions | undefined {
|
||||
if (!msgPayload) {
|
||||
return;
|
||||
}
|
||||
@@ -228,12 +237,12 @@ export class SWController extends ControllerInterface {
|
||||
* and the promise it returns will be passed to event.waitUntil.
|
||||
* If you do not set this callback then all push messages will let and the
|
||||
* developer can handle them in a their own 'push' event callback
|
||||
* @export
|
||||
* @param {function(Object)} callback The callback to be called when a push
|
||||
* message is received and a notification must be shown. The callback will
|
||||
* be given the data from the push message.
|
||||
*
|
||||
* @param callback The callback to be called when a push message is received
|
||||
* and a notification must be shown. The callback will be given the data from
|
||||
* the push message.
|
||||
*/
|
||||
setBackgroundMessageHandler(callback) {
|
||||
setBackgroundMessageHandler(callback: BgMessageHandler) {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
throw this.errorFactory_.create(ERROR_CODES.BG_HANDLER_FUNCTION_EXPECTED);
|
||||
}
|
||||
@@ -242,12 +251,12 @@ export class SWController extends ControllerInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} url The URL to look for when focusing a client.
|
||||
* @return {Object} Returns an existing window client or a newly opened
|
||||
* WindowClient.
|
||||
* @param url The URL to look for when focusing a client.
|
||||
* @return Returns an existing window client or a newly opened WindowClient.
|
||||
*/
|
||||
getWindowClient_(url) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
getWindowClient_(url: string): Promise<any> {
|
||||
// Use URL to normalize the URL when comparing to windowClients.
|
||||
// This at least handles whether to include trailing slashes or not
|
||||
const parsedURL = new URL(url, (self as any).location).href;
|
||||
@@ -257,7 +266,7 @@ export class SWController extends ControllerInterface {
|
||||
type: 'window',
|
||||
includeUncontrolled: true
|
||||
})
|
||||
.then(clientList => {
|
||||
.then((clientList: any) => {
|
||||
let suitableClient = null;
|
||||
for (let i = 0; i < clientList.length; i++) {
|
||||
const parsedClientUrl = new URL(
|
||||
@@ -280,14 +289,14 @@ export class SWController extends ControllerInterface {
|
||||
|
||||
/**
|
||||
* This message will attempt to send the message to a window client.
|
||||
* @private
|
||||
* @param {Object} client The WindowClient to send the message to.
|
||||
* @param {Object} message The message to send to the client.
|
||||
* @returns {Promise} Returns a promise that resolves after sending the
|
||||
* message. This does not guarantee that the message was successfully
|
||||
* received.
|
||||
* @param client The WindowClient to send the message to.
|
||||
* @param message The message to send to the client.
|
||||
* @returns Returns a promise that resolves after sending the message. This
|
||||
* does not guarantee that the message was successfully received.
|
||||
*/
|
||||
async attemptToMessageClient_(client, message) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
async attemptToMessageClient_(client: any, message: any): Promise<void> {
|
||||
// NOTE: This returns a promise in case this API is abstracted later on to
|
||||
// do additional work
|
||||
if (!client) {
|
||||
@@ -300,42 +309,46 @@ export class SWController extends ControllerInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {Promise<boolean>} If there is currently a visible WindowClient,
|
||||
* this method will resolve to true, otherwise false.
|
||||
* @returns If there is currently a visible WindowClient, this method will
|
||||
* resolve to true, otherwise false.
|
||||
*/
|
||||
hasVisibleClients_() {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
hasVisibleClients_(): Promise<boolean> {
|
||||
return (self as any).clients
|
||||
.matchAll({
|
||||
type: 'window',
|
||||
includeUncontrolled: true
|
||||
})
|
||||
.then(clientList => {
|
||||
return clientList.some(client => client.visibilityState === 'visible');
|
||||
.then((clientList: any) => {
|
||||
return clientList.some(
|
||||
(client: any) => client.visibilityState === 'visible'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} msgPayload The data from the push event that should be sent
|
||||
* to all available pages.
|
||||
* @returns {Promise} Returns a promise that resolves once the message
|
||||
* has been sent to all WindowClients.
|
||||
* @param msgPayload The data from the push event that should be sent to all
|
||||
* available pages.
|
||||
* @returns Returns a promise that resolves once the message has been sent to
|
||||
* all WindowClients.
|
||||
*/
|
||||
sendMessageToWindowClients_(msgPayload) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
sendMessageToWindowClients_(msgPayload: any): Promise<void> {
|
||||
return (self as any).clients
|
||||
.matchAll({
|
||||
type: 'window',
|
||||
includeUncontrolled: true
|
||||
})
|
||||
.then(clientList => {
|
||||
.then((clientList: any) => {
|
||||
const internalMsg = WorkerPageMessage.createNewMsg(
|
||||
WorkerPageMessage.TYPES_OF_MSG.PUSH_MSG_RECEIVED,
|
||||
msgPayload
|
||||
);
|
||||
|
||||
return Promise.all(
|
||||
clientList.map(client => {
|
||||
clientList.map((client: any) => {
|
||||
return this.attemptToMessageClient_(client, internalMsg);
|
||||
})
|
||||
);
|
||||
@@ -344,11 +357,9 @@ export class SWController extends ControllerInterface {
|
||||
|
||||
/**
|
||||
* This will register the default service worker and return the registration.
|
||||
* @private
|
||||
* @return {Promise<!ServiceWorkerRegistration>} The service worker
|
||||
* registration to be used for the push service.
|
||||
* @return he service worker registration to be used for the push service.
|
||||
*/
|
||||
getSWRegistration_() {
|
||||
getSWRegistration_(): Promise<ServiceWorkerRegistration> {
|
||||
return Promise.resolve((self as any).registration);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,73 +15,42 @@
|
||||
*/
|
||||
|
||||
import { FirebaseMessaging } from '@firebase/messaging-types';
|
||||
import { FirebaseApp } from '@firebase/app-types';
|
||||
import { ControllerInterface } from './controller-interface';
|
||||
import { ERROR_CODES } from '../models/errors';
|
||||
import WorkerPageMessage from '../models/worker-page-message';
|
||||
import { DEFAULT_SW_PATH, DEFAULT_SW_SCOPE } from '../models/default-sw';
|
||||
import { NotificationPermission } from '../models/notification-permission';
|
||||
import { DEFAULT_PUBLIC_VAPID_KEY } from '../models/fcm-details';
|
||||
import { base64ToArrayBuffer } from '../helpers/base64-to-array-buffer';
|
||||
import { createSubscribe } from '@firebase/util';
|
||||
import {
|
||||
createSubscribe,
|
||||
Observer,
|
||||
NextFn,
|
||||
PartialObserver
|
||||
} from '@firebase/util';
|
||||
|
||||
declare const firebase: any;
|
||||
|
||||
export class WindowController extends ControllerInterface
|
||||
implements FirebaseMessaging {
|
||||
private registrationToUse_;
|
||||
private publicVapidKeyToUse_;
|
||||
private manifestCheckPromise_;
|
||||
private messageObserver_: any = null;
|
||||
private registrationToUse_: ServiceWorkerRegistration | null = null;
|
||||
private publicVapidKeyToUse_: Uint8Array | null = null;
|
||||
private manifestCheckPromise_: Promise<any> | null = null;
|
||||
private messageObserver_: Observer<{}, Error> | null = null;
|
||||
private onMessage_ = createSubscribe(observer => {
|
||||
this.messageObserver_ = observer;
|
||||
});
|
||||
private tokenRefreshObserver_: any = null;
|
||||
private tokenRefreshObserver_: Observer<{}, Error> | null = null;
|
||||
private onTokenRefresh_ = createSubscribe(observer => {
|
||||
this.tokenRefreshObserver_ = observer;
|
||||
});
|
||||
|
||||
/**
|
||||
* A service that provides a MessagingService instance.
|
||||
* @param {!firebase.app.App} app
|
||||
*/
|
||||
constructor(app) {
|
||||
constructor(app: FirebaseApp) {
|
||||
super(app);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ServiceWorkerRegistration}
|
||||
*/
|
||||
this.registrationToUse_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Promise}
|
||||
*/
|
||||
this.manifestCheckPromise_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {firebase.Observer}
|
||||
*/
|
||||
this.messageObserver_ = null;
|
||||
|
||||
/**
|
||||
* @private {!firebase.Subscribe} The subscribe function to the onMessage
|
||||
* observer.
|
||||
*/
|
||||
this.onMessage_ = createSubscribe(observer => {
|
||||
this.messageObserver_ = observer;
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {firebase.Observer}
|
||||
*/
|
||||
this.tokenRefreshObserver_ = null;
|
||||
this.onTokenRefresh_ = createSubscribe(observer => {
|
||||
this.tokenRefreshObserver_ = observer;
|
||||
});
|
||||
|
||||
this.setupSWMessageListener_();
|
||||
}
|
||||
|
||||
@@ -160,15 +129,17 @@ export class WindowController extends ControllerInterface
|
||||
* rejects
|
||||
*/
|
||||
async requestPermission() {
|
||||
if ((Notification as any).permission === NotificationPermission.GRANTED) {
|
||||
if (
|
||||
((Notification as any).permission as NotificationPermission) === 'granted'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const managePermissionResult = result => {
|
||||
if (result === NotificationPermission.GRANTED) {
|
||||
const managePermissionResult = (result: NotificationPermission) => {
|
||||
if (result === 'granted') {
|
||||
return resolve();
|
||||
} else if (result === NotificationPermission.DENIED) {
|
||||
} else if (result === 'denied') {
|
||||
return reject(
|
||||
this.errorFactory_.create(ERROR_CODES.PERMISSION_BLOCKED)
|
||||
);
|
||||
@@ -196,15 +167,15 @@ export class WindowController extends ControllerInterface
|
||||
* This method allows a developer to override the default service worker and
|
||||
* instead use a custom service worker.
|
||||
* @export
|
||||
* @param {!ServiceWorkerRegistration} registration The service worker
|
||||
* registration that should be used to receive the push messages.
|
||||
* @param registration The service worker registration that should be used to
|
||||
* receive the push messages.
|
||||
*/
|
||||
useServiceWorker(registration) {
|
||||
useServiceWorker(registration: ServiceWorkerRegistration) {
|
||||
if (!(registration instanceof ServiceWorkerRegistration)) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.SW_REGISTRATION_EXPECTED);
|
||||
}
|
||||
|
||||
if (typeof this.registrationToUse_ !== 'undefined') {
|
||||
if (this.registrationToUse_ != null) {
|
||||
throw this.errorFactory_.create(ERROR_CODES.USE_SW_BEFORE_GET_TOKEN);
|
||||
}
|
||||
|
||||
@@ -215,14 +186,14 @@ export class WindowController extends ControllerInterface
|
||||
* This method allows a developer to override the default vapid key
|
||||
* and instead use a custom VAPID public key.
|
||||
* @export
|
||||
* @param {!string} publicKey A URL safe base64 encoded string.
|
||||
* @param publicKey A URL safe base64 encoded string.
|
||||
*/
|
||||
usePublicVapidKey(publicKey) {
|
||||
usePublicVapidKey(publicKey: string) {
|
||||
if (typeof publicKey !== 'string') {
|
||||
throw this.errorFactory_.create(ERROR_CODES.INVALID_PUBLIC_VAPID_KEY);
|
||||
}
|
||||
|
||||
if (typeof this.publicVapidKeyToUse_ !== 'undefined') {
|
||||
if (this.publicVapidKeyToUse_ != null) {
|
||||
throw this.errorFactory_.create(
|
||||
ERROR_CODES.USE_PUBLIC_KEY_BEFORE_GET_TOKEN
|
||||
);
|
||||
@@ -239,42 +210,55 @@ export class WindowController extends ControllerInterface
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!firebase.Observer|function(*)} nextOrObserver An observer object
|
||||
* or a function triggered on message.
|
||||
* @param {function(!Error)=} optError Optional A function triggered on
|
||||
* message error.
|
||||
* @param {function()=} optCompleted Optional function triggered when the
|
||||
* observer is removed.
|
||||
* @return {!function()} The unsubscribe function for the observer.
|
||||
* @param nextOrObserver An observer object or a function triggered on
|
||||
* message.
|
||||
* @param error A function triggered on message error.
|
||||
* @param completed function triggered when the observer is removed.
|
||||
* @return The unsubscribe function for the observer.
|
||||
*/
|
||||
onMessage(nextOrObserver, optError?, optCompleted?) {
|
||||
return this.onMessage_(nextOrObserver, optError, optCompleted);
|
||||
onMessage(
|
||||
nextOrObserver: NextFn<{}> | PartialObserver<{}>,
|
||||
error?: (e: Error) => void,
|
||||
completed?: () => void
|
||||
) {
|
||||
if (typeof nextOrObserver === 'function') {
|
||||
return this.onMessage_(nextOrObserver, error, completed);
|
||||
} else {
|
||||
return this.onMessage_(nextOrObserver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @param {!firebase.Observer|function()} nextOrObserver An observer object
|
||||
* or a function triggered on token refresh.
|
||||
* @param {function(!Error)=} optError Optional A function
|
||||
* triggered on token refresh error.
|
||||
* @param {function()=} optCompleted Optional function triggered when the
|
||||
* observer is removed.
|
||||
* @return {!function()} The unsubscribe function for the observer.
|
||||
* @param nextOrObserver An observer object or a function triggered on token
|
||||
* refresh.
|
||||
* @param error A function triggered on token refresh error.
|
||||
* @param completed function triggered when the observer is removed.
|
||||
* @return The unsubscribe function for the observer.
|
||||
*/
|
||||
onTokenRefresh(nextOrObserver, optError, optCompleted) {
|
||||
return this.onTokenRefresh_(nextOrObserver, optError, optCompleted);
|
||||
onTokenRefresh(
|
||||
nextOrObserver: NextFn<{}> | PartialObserver<{}>,
|
||||
error?: (e: Error) => void,
|
||||
completed?: () => void
|
||||
) {
|
||||
if (typeof nextOrObserver === 'function') {
|
||||
return this.onTokenRefresh_(nextOrObserver, error, completed);
|
||||
} else {
|
||||
return this.onTokenRefresh_(nextOrObserver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a registration, wait for the service worker it relates to
|
||||
* become activer
|
||||
* @private
|
||||
* @param {ServiceWorkerRegistration} registration Registration to wait
|
||||
* for service worker to become active
|
||||
* @return {Promise<!ServiceWorkerRegistration>} Wait for service worker
|
||||
* registration to become active
|
||||
* @param registration Registration to wait for service worker to become active
|
||||
* @return Wait for service worker registration to become active
|
||||
*/
|
||||
waitForRegistrationToActivate_(registration) {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
waitForRegistrationToActivate_(
|
||||
registration: ServiceWorkerRegistration
|
||||
): Promise<ServiceWorkerRegistration> {
|
||||
const serviceWorker =
|
||||
registration.installing || registration.waiting || registration.active;
|
||||
|
||||
@@ -312,12 +296,10 @@ export class WindowController extends ControllerInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* This will regiater the default service worker and return the registration
|
||||
* @private
|
||||
* @return {Promise<!ServiceWorkerRegistration>} The service worker
|
||||
* registration to be used for the push service.
|
||||
* This will register the default service worker and return the registration
|
||||
* @return The service worker registration to be used for the push service.
|
||||
*/
|
||||
getSWRegistration_() {
|
||||
getSWRegistration_(): Promise<ServiceWorkerRegistration> {
|
||||
if (this.registrationToUse_) {
|
||||
return this.waitForRegistrationToActivate_(this.registrationToUse_);
|
||||
}
|
||||
@@ -326,11 +308,11 @@ export class WindowController extends ControllerInterface
|
||||
// use a new service worker as registrationToUse_ is no longer undefined
|
||||
this.registrationToUse_ = null;
|
||||
|
||||
return navigator.serviceWorker
|
||||
return (navigator as any).serviceWorker
|
||||
.register(DEFAULT_SW_PATH, {
|
||||
scope: DEFAULT_SW_SCOPE
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err: Error) => {
|
||||
throw this.errorFactory_.create(
|
||||
ERROR_CODES.FAILED_DEFAULT_REGISTRATION,
|
||||
{
|
||||
@@ -338,7 +320,7 @@ export class WindowController extends ControllerInterface
|
||||
}
|
||||
);
|
||||
})
|
||||
.then(registration => {
|
||||
.then((registration: ServiceWorkerRegistration) => {
|
||||
return this.waitForRegistrationToActivate_(registration).then(() => {
|
||||
this.registrationToUse_ = registration;
|
||||
|
||||
@@ -355,7 +337,6 @@ export class WindowController extends ControllerInterface
|
||||
/**
|
||||
* This will return the default VAPID key or the uint8array version of the public VAPID key
|
||||
* provided by the developer.
|
||||
* @private
|
||||
*/
|
||||
getPublicVapidKey_(): Promise<Uint8Array> {
|
||||
if (this.publicVapidKeyToUse_) {
|
||||
@@ -369,17 +350,17 @@ export class WindowController extends ControllerInterface
|
||||
* This method will set up a message listener to handle
|
||||
* events from the service worker that should trigger
|
||||
* events in the page.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
setupSWMessageListener_() {
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.serviceWorker.addEventListener(
|
||||
(navigator as any).serviceWorker.addEventListener(
|
||||
'message',
|
||||
event => {
|
||||
(event: MessageEvent) => {
|
||||
if (!event.data || !event.data[WorkerPageMessage.PARAMS.TYPE_OF_MSG]) {
|
||||
// Not a message from FCM
|
||||
return;
|
||||
@@ -406,10 +387,11 @@ export class WindowController extends ControllerInterface
|
||||
|
||||
/**
|
||||
* Checks to see if the required API's are valid or not.
|
||||
* @private
|
||||
* @return {boolean} Returns true if the desired APIs are available.
|
||||
* @return Returns true if the desired APIs are available.
|
||||
*/
|
||||
isSupported_() {
|
||||
// Visible for testing
|
||||
// TODO: Make private
|
||||
isSupported_(): boolean {
|
||||
return (
|
||||
'serviceWorker' in navigator &&
|
||||
'PushManager' in window &&
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function toBase64(arrayBuffer) {
|
||||
function toBase64(arrayBuffer: ArrayBuffer | Uint8Array) {
|
||||
const uint8Version = new Uint8Array(arrayBuffer);
|
||||
return btoa(String.fromCharCode.apply(null, uint8Version));
|
||||
}
|
||||
|
||||
export function arrayBufferToBase64(arrayBuffer) {
|
||||
export function arrayBufferToBase64(arrayBuffer: ArrayBuffer | Uint8Array) {
|
||||
const base64String = toBase64(arrayBuffer);
|
||||
return base64String
|
||||
.replace(/=/g, '')
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export function base64ToArrayBuffer(base64String) {
|
||||
export function base64ToArrayBuffer(base64String: string) {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/\-/g, '+')
|
||||
|
||||
+13
-5
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2017 Google Inc.
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,8 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export enum NotificationPermission {
|
||||
DEFAULT = 'default',
|
||||
GRANTED = 'granted',
|
||||
DENIED = 'denied'
|
||||
export interface TokenDetails {
|
||||
fcmToken: string;
|
||||
swScope: string;
|
||||
vapidKey: string | Uint8Array;
|
||||
subscription: PushSubscription;
|
||||
fcmSenderId: string;
|
||||
fcmPushSet: string;
|
||||
|
||||
createTime?: number;
|
||||
endpoint?: string;
|
||||
auth?: string;
|
||||
p256dh?: string;
|
||||
}
|
||||
@@ -25,11 +25,7 @@ export class DBInterface {
|
||||
protected errorFactory_: ErrorFactory<string>;
|
||||
protected TRANSACTION_READ_WRITE: IDBTransactionMode;
|
||||
|
||||
/**
|
||||
* @param {string} dbName
|
||||
* @param {number} dbVersion
|
||||
*/
|
||||
constructor(dbName, dbVersion) {
|
||||
constructor(dbName: string, dbVersion: number) {
|
||||
this.errorFactory_ = new ErrorFactory('messaging', 'Messaging', ERROR_MAP);
|
||||
this.DB_NAME_ = dbName;
|
||||
this.dbVersion_ = dbVersion;
|
||||
@@ -38,11 +34,11 @@ export class DBInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the indexedDB as a promsie.
|
||||
* @protected
|
||||
* @return {!Promise<!IDBDatabase>} The IndexedDB database
|
||||
* Get the indexedDB as a promise.
|
||||
*/
|
||||
openDatabase() {
|
||||
// Visible for testing
|
||||
// TODO: Make protected
|
||||
openDatabase(): Promise<IDBDatabase> {
|
||||
if (this.openDbPromise_) {
|
||||
return this.openDbPromise_;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ErrorFactory, base64 } from '@firebase/util';
|
||||
import { ERROR_CODES, ERROR_MAP } from './errors';
|
||||
import { arrayBufferToBase64 } from '../helpers/array-buffer-to-base64';
|
||||
import { DEFAULT_PUBLIC_VAPID_KEY, ENDPOINT } from './fcm-details';
|
||||
import { TokenDetails } from '../interfaces/token-details';
|
||||
|
||||
export interface IIDDetails {
|
||||
token: string;
|
||||
@@ -37,8 +38,8 @@ export class IIDModel {
|
||||
subscription: PushSubscription,
|
||||
publicVapidKey: Uint8Array
|
||||
): Promise<IIDDetails> {
|
||||
const p256dh = arrayBufferToBase64(subscription['getKey']('p256dh'));
|
||||
const auth = arrayBufferToBase64(subscription['getKey']('auth'));
|
||||
const p256dh = arrayBufferToBase64(subscription.getKey('p256dh')!);
|
||||
const auth = arrayBufferToBase64(subscription.getKey('auth')!);
|
||||
|
||||
let fcmSubscribeBody =
|
||||
`authorized_entity=${senderId}&` +
|
||||
@@ -60,7 +61,7 @@ export class IIDModel {
|
||||
body: fcmSubscribeBody
|
||||
};
|
||||
|
||||
let responseData: Object | null = null;
|
||||
let responseData: any = null;
|
||||
try {
|
||||
const response = await fetch(
|
||||
ENDPOINT + '/fcm/connect/subscribe',
|
||||
@@ -72,8 +73,6 @@ export class IIDModel {
|
||||
throw this.errorFactory_.create(ERROR_CODES.TOKEN_SUBSCRIBE_FAILED);
|
||||
}
|
||||
|
||||
responseData = responseData as Object;
|
||||
|
||||
if (responseData['error']) {
|
||||
const message = responseData['error']['message'];
|
||||
throw this.errorFactory_.create(ERROR_CODES.TOKEN_SUBSCRIBE_FAILED, {
|
||||
@@ -105,8 +104,8 @@ export class IIDModel {
|
||||
subscription: PushSubscription,
|
||||
publicVapidKey: Uint8Array
|
||||
): Promise<string> {
|
||||
const p256dh = arrayBufferToBase64(subscription['getKey']('p256dh'));
|
||||
const auth = arrayBufferToBase64(subscription['getKey']('auth'));
|
||||
const p256dh = arrayBufferToBase64(subscription.getKey('p256dh')!);
|
||||
const auth = arrayBufferToBase64(subscription.getKey('auth')!);
|
||||
|
||||
let fcmUpdateBody =
|
||||
`push_set=${fcmPushSet}&` +
|
||||
@@ -130,7 +129,7 @@ export class IIDModel {
|
||||
body: fcmUpdateBody
|
||||
};
|
||||
|
||||
let responseData: Object | null = null;
|
||||
let responseData: any = null;
|
||||
try {
|
||||
const response = await fetch(
|
||||
ENDPOINT + '/fcm/connect/subscribe',
|
||||
@@ -141,8 +140,6 @@ export class IIDModel {
|
||||
throw this.errorFactory_.create(ERROR_CODES.TOKEN_UPDATE_FAILED);
|
||||
}
|
||||
|
||||
responseData = responseData as Object;
|
||||
|
||||
if (responseData['error']) {
|
||||
const message = responseData['error']['message'];
|
||||
throw this.errorFactory_.create(ERROR_CODES.TOKEN_UPDATE_FAILED, {
|
||||
|
||||
@@ -18,26 +18,12 @@ import { DBInterface } from './db-interface';
|
||||
import { ERROR_CODES } from './errors';
|
||||
import { arrayBufferToBase64 } from '../helpers/array-buffer-to-base64';
|
||||
import { cleanV1 } from './clean-v1-undefined';
|
||||
import { TokenDetails } from '../interfaces/token-details';
|
||||
|
||||
const FCM_TOKEN_OBJ_STORE = 'fcm_token_object_Store';
|
||||
const DB_NAME = 'fcm_token_details_db';
|
||||
const DB_VERSION = 2;
|
||||
|
||||
/** @record */
|
||||
function ValidateInput() {}
|
||||
/** @type {string|undefined} */
|
||||
ValidateInput.prototype.fcmToken;
|
||||
/** @type {string|undefined} */
|
||||
ValidateInput.prototype.swScope;
|
||||
/** @type {string|undefined} */
|
||||
ValidateInput.prototype.vapidKey;
|
||||
/** @type {PushSubscription|undefined} */
|
||||
ValidateInput.prototype.subscription;
|
||||
/** @type {string|undefined} */
|
||||
ValidateInput.prototype.fcmSenderId;
|
||||
/** @type {string|undefined} */
|
||||
ValidateInput.prototype.fcmPushSet;
|
||||
|
||||
export class TokenDetailsModel extends DBInterface {
|
||||
constructor() {
|
||||
super(DB_NAME, DB_VERSION);
|
||||
@@ -71,12 +57,9 @@ export class TokenDetailsModel extends DBInterface {
|
||||
/**
|
||||
* This method takes an object and will check for known arguments and
|
||||
* validate the input.
|
||||
* @private
|
||||
* @param {!ValidateInput} input
|
||||
* @return {!Promise} Returns promise that resolves if input is valid,
|
||||
* rejects otherwise.
|
||||
* @return Promise that resolves if input is valid, rejects otherwise.
|
||||
*/
|
||||
async validateInputs_(input) {
|
||||
private async validateInputs_(input: Partial<TokenDetails>): Promise<void> {
|
||||
if (input.fcmToken) {
|
||||
if (typeof input.fcmToken !== 'string' || input.fcmToken.length === 0) {
|
||||
return Promise.reject(this.errorFactory_.create(ERROR_CODES.BAD_TOKEN));
|
||||
@@ -134,19 +117,17 @@ export class TokenDetailsModel extends DBInterface {
|
||||
/**
|
||||
* Given a token, this method will look up the details in indexedDB.
|
||||
* @param {string} fcmToken
|
||||
* @return {Promise<Object>} The details associated with that token.
|
||||
* @return {Promise<TokenDetails>} The details associated with that token.
|
||||
*/
|
||||
getTokenDetailsFromToken(fcmToken) {
|
||||
getTokenDetailsFromToken(fcmToken: string): Promise<TokenDetails> {
|
||||
if (!fcmToken) {
|
||||
return Promise.reject(this.errorFactory_.create(ERROR_CODES.BAD_TOKEN));
|
||||
}
|
||||
|
||||
return this.validateInputs_({ fcmToken })
|
||||
.then(() => {
|
||||
return this.openDatabase();
|
||||
})
|
||||
.then(() => this.openDatabase())
|
||||
.then(db => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<TokenDetails>((resolve, reject) => {
|
||||
const transaction = db.transaction([FCM_TOKEN_OBJ_STORE]);
|
||||
const objectStore = transaction.objectStore(FCM_TOKEN_OBJ_STORE);
|
||||
const index = objectStore.index('fcmToken');
|
||||
@@ -155,10 +136,9 @@ export class TokenDetailsModel extends DBInterface {
|
||||
reject((<IDBRequest>event.target).error);
|
||||
};
|
||||
request.onsuccess = function(event) {
|
||||
const result = (<IDBRequest>event.target).result
|
||||
? (<IDBRequest>event.target).result
|
||||
: null;
|
||||
resolve(result);
|
||||
const result: TokenDetails | null = (<IDBRequest>event.target)
|
||||
.result;
|
||||
resolve(result!);
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -167,11 +147,9 @@ export class TokenDetailsModel extends DBInterface {
|
||||
/**
|
||||
* Given a service worker scope, this method will look up the details in
|
||||
* indexedDB.
|
||||
* @public
|
||||
* @param {string} swScope
|
||||
* @return {Promise<Object>} The details associated with that token.
|
||||
* @return The details associated with that token.
|
||||
*/
|
||||
getTokenDetailsFromSWScope(swScope) {
|
||||
getTokenDetailsFromSWScope(swScope: string): Promise<TokenDetails> {
|
||||
if (!swScope) {
|
||||
return Promise.reject(this.errorFactory_.create(ERROR_CODES.BAD_SCOPE));
|
||||
}
|
||||
@@ -181,7 +159,7 @@ export class TokenDetailsModel extends DBInterface {
|
||||
return this.openDatabase();
|
||||
})
|
||||
.then(db => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<TokenDetails>((resolve, reject) => {
|
||||
const transaction = db.transaction([FCM_TOKEN_OBJ_STORE]);
|
||||
const objectStore = transaction.objectStore(FCM_TOKEN_OBJ_STORE);
|
||||
const scopeRequest = objectStore.get(swScope);
|
||||
@@ -190,10 +168,9 @@ export class TokenDetailsModel extends DBInterface {
|
||||
};
|
||||
|
||||
scopeRequest.onsuccess = event => {
|
||||
const result = (<IDBRequest>event.target).result
|
||||
? (<IDBRequest>event.target).result
|
||||
: null;
|
||||
resolve(result);
|
||||
const result: TokenDetails | null = (<IDBRequest>event.target)
|
||||
.result;
|
||||
resolve(result!);
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -201,10 +178,7 @@ export class TokenDetailsModel extends DBInterface {
|
||||
|
||||
/**
|
||||
* Save the details for the fcm token for re-use at a later date.
|
||||
* @param {{swScope: !string, vapidKey: !string,
|
||||
* subscription: !PushSubscription, fcmSenderId: !string, fcmToken: !string,
|
||||
* fcmPushSet: !string}} input A plain js object containing args to save.
|
||||
* @return {Promise<void>}
|
||||
* @param input A plain js object containing args to save.
|
||||
*/
|
||||
saveTokenDetails({
|
||||
swScope,
|
||||
@@ -213,7 +187,7 @@ export class TokenDetailsModel extends DBInterface {
|
||||
fcmSenderId,
|
||||
fcmToken,
|
||||
fcmPushSet
|
||||
}) {
|
||||
}: TokenDetails): Promise<void> {
|
||||
if (!swScope) {
|
||||
return Promise.reject(this.errorFactory_.create(ERROR_CODES.BAD_SCOPE));
|
||||
}
|
||||
@@ -258,22 +232,19 @@ export class TokenDetailsModel extends DBInterface {
|
||||
return this.openDatabase();
|
||||
})
|
||||
.then(db => {
|
||||
/**
|
||||
* @dict
|
||||
*/
|
||||
const details = {
|
||||
swScope: swScope,
|
||||
vapidKey: arrayBufferToBase64(vapidKey),
|
||||
vapidKey: arrayBufferToBase64(vapidKey as Uint8Array),
|
||||
endpoint: subscription.endpoint,
|
||||
auth: arrayBufferToBase64(subscription['getKey']('auth')),
|
||||
p256dh: arrayBufferToBase64(subscription['getKey']('p256dh')),
|
||||
auth: arrayBufferToBase64(subscription.getKey('auth')!),
|
||||
p256dh: arrayBufferToBase64(subscription.getKey('p256dh')!),
|
||||
fcmSenderId: fcmSenderId,
|
||||
fcmToken: fcmToken,
|
||||
fcmPushSet: fcmPushSet,
|
||||
createTime: Date.now()
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const transaction = db.transaction(
|
||||
[FCM_TOKEN_OBJ_STORE],
|
||||
this.TRANSACTION_READ_WRITE
|
||||
@@ -297,7 +268,7 @@ export class TokenDetailsModel extends DBInterface {
|
||||
* @return {Promise<Object>} Resolves once the FCM token details have been
|
||||
* deleted and returns the deleted details.
|
||||
*/
|
||||
deleteToken(token: string) {
|
||||
deleteToken(token: string): Promise<TokenDetails> {
|
||||
if (typeof token !== 'string' || token.length === 0) {
|
||||
return Promise.reject(
|
||||
this.errorFactory_.create(ERROR_CODES.INVALID_DELETE_TOKEN)
|
||||
@@ -310,13 +281,13 @@ export class TokenDetailsModel extends DBInterface {
|
||||
}
|
||||
|
||||
return this.openDatabase().then(db => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<TokenDetails>((resolve, reject) => {
|
||||
const transaction = db.transaction(
|
||||
[FCM_TOKEN_OBJ_STORE],
|
||||
this.TRANSACTION_READ_WRITE
|
||||
);
|
||||
const objectStore = transaction.objectStore(FCM_TOKEN_OBJ_STORE);
|
||||
const request = objectStore.delete(details['swScope']);
|
||||
const request = objectStore.delete(details.swScope);
|
||||
request.onerror = event => {
|
||||
reject((<IDBRequest>event.target).error);
|
||||
};
|
||||
|
||||
@@ -27,11 +27,7 @@ export class VapidDetailsModel extends DBInterface {
|
||||
super(DB_NAME, DB_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {IDBDatabase} db
|
||||
*/
|
||||
onDBUpgrade(db) {
|
||||
onDBUpgrade(db: IDBDatabase) {
|
||||
db.createObjectStore(FCM_VAPID_OBJ_STORE, {
|
||||
keyPath: 'swScope'
|
||||
});
|
||||
|
||||
@@ -28,13 +28,13 @@ const msgType = {
|
||||
NOTIFICATION_CLICKED: 'notification-clicked'
|
||||
};
|
||||
|
||||
const createNewMsg = (msgType, msgData) => {
|
||||
function createNewMsg(msgType: any, msgData: any) {
|
||||
const message = {
|
||||
[PARAMS.TYPE_OF_MSG]: msgType,
|
||||
[PARAMS.DATA]: msgData
|
||||
};
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
PARAMS,
|
||||
|
||||
@@ -26,7 +26,6 @@ import { DEFAULT_PUBLIC_VAPID_KEY } from '../src/models/fcm-details';
|
||||
import { TokenDetailsModel } from '../src/models/token-details-model';
|
||||
import { VapidDetailsModel } from '../src/models/vapid-details-model';
|
||||
import { IIDModel } from '../src/models/iid-model';
|
||||
import { NotificationPermission } from '../src/models/notification-permission';
|
||||
import { arrayBufferToBase64 } from '../src/helpers/array-buffer-to-base64';
|
||||
import { base64ToArrayBuffer } from '../src/helpers/base64-to-array-buffer';
|
||||
import { TOKEN_EXPIRATION_MILLIS } from '../src/controllers/controller-interface';
|
||||
@@ -151,7 +150,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
it('should handle a failure to get registration', function() {
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(navigator.serviceWorker, 'register')
|
||||
@@ -181,10 +180,10 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
ControllerInterface.prototype,
|
||||
'getNotificationPermission_'
|
||||
);
|
||||
notificationStub.onCall(0).returns(NotificationPermission.DENIED);
|
||||
notificationStub.onCall(1).returns(NotificationPermission.DEFAULT);
|
||||
notificationStub.onCall(2).returns(NotificationPermission.DENIED);
|
||||
notificationStub.onCall(3).returns(NotificationPermission.DEFAULT);
|
||||
notificationStub.onCall(0).returns('denied');
|
||||
notificationStub.onCall(1).returns('default');
|
||||
notificationStub.onCall(2).returns('denied');
|
||||
notificationStub.onCall(3).returns('default');
|
||||
|
||||
return servicesToTest.reduce((chain, ServiceClass) => {
|
||||
const serviceInstance = new ServiceClass(app);
|
||||
@@ -238,7 +237,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(TokenDetailsModel.prototype, 'getTokenDetailsFromSWScope')
|
||||
@@ -269,7 +268,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(TokenDetailsModel.prototype, 'getTokenDetailsFromSWScope')
|
||||
@@ -290,7 +289,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(TokenDetailsModel.prototype, 'getTokenDetailsFromSWScope')
|
||||
@@ -339,7 +338,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(ServiceClass.prototype, 'getPushSubscription')
|
||||
@@ -422,7 +421,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
const existingTokenDetails = VapidSetup['details'];
|
||||
let vapidKeyToUse = DEFAULT_PUBLIC_VAPID_KEY;
|
||||
@@ -497,7 +496,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
// start with using the deault key.
|
||||
const getPublicVapidKeyStub = sandbox.stub(
|
||||
@@ -584,7 +583,7 @@ describe('Firebase Messaging > *Controller.getToken()', function() {
|
||||
|
||||
sandbox
|
||||
.stub(ControllerInterface.prototype, 'getNotificationPermission_')
|
||||
.callsFake(() => NotificationPermission.GRANTED);
|
||||
.callsFake(() => 'granted');
|
||||
|
||||
sandbox
|
||||
.stub(TokenDetailsModel.prototype, 'getTokenDetailsFromSWScope')
|
||||
|
||||
@@ -28,6 +28,20 @@ import { IIDModel } from '../src/models/iid-model';
|
||||
|
||||
const controllersToTest = [WindowController, SWController];
|
||||
|
||||
/**
|
||||
* As ControllerInterface is an abstract class, we need a concrete
|
||||
* implementation that can be initialized for testing
|
||||
*/
|
||||
class MockControllerInterface extends ControllerInterface {
|
||||
async getSWRegistration_() {
|
||||
return await new ServiceWorkerRegistration();
|
||||
}
|
||||
|
||||
async getPublicVapidKey_() {
|
||||
return await new Uint8Array(0);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
const sandbox = sinon.sandbox.create();
|
||||
const app = makeFakeApp({
|
||||
@@ -48,44 +62,16 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('INTERNAL.delete()', function() {
|
||||
it('should call delete()', function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
sandbox.spy(controller, 'delete');
|
||||
controller.INTERNAL.delete();
|
||||
expect(controller.delete['callCount']).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSWRegistration_()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.getSWRegistration_();
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
expect(thrownError).to.exist;
|
||||
expect(thrownError.code).to.equal('messaging/should-be-overriden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPublicVapidKey_()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.getPublicVapidKey_();
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
expect(thrownError).to.exist;
|
||||
expect(thrownError.code).to.equal('messaging/should-be-overriden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestPermission()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.requestPermission();
|
||||
@@ -163,10 +149,10 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('useServiceWorker()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.useServiceWorker(null);
|
||||
controller.useServiceWorker(null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -177,10 +163,10 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('usePublicVapidKey()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.usePublicVapidKey(null);
|
||||
controller.usePublicVapidKey(null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -191,10 +177,10 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('onMessage()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.onMessage(null, null, null);
|
||||
controller.onMessage(null as any, null as any, null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -205,10 +191,10 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('onTokenRefresh()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.onTokenRefresh(null, null, null);
|
||||
controller.onTokenRefresh(null as any, null as any, null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -219,10 +205,10 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('setBackgroundMessageHandler()', function() {
|
||||
it(`should throw`, function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.setBackgroundMessageHandler(null);
|
||||
controller.setBackgroundMessageHandler(null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -234,7 +220,7 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
describe('getNotificationPermission_', function() {
|
||||
it('should return current permission', function() {
|
||||
sandbox.stub(Notification as any, 'permission').value('test');
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
const result = controller.getNotificationPermission_();
|
||||
expect(result).to.equal('test');
|
||||
});
|
||||
@@ -242,7 +228,7 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('getTokenDetailsModel', function() {
|
||||
it('should return an instance of TokenDetailsModel', function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
const result = controller.getTokenDetailsModel();
|
||||
expect(result).to.be.instanceof(TokenDetailsModel);
|
||||
});
|
||||
@@ -250,7 +236,7 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('getVapidDetailsModel', function() {
|
||||
it('should return an instance of VapidDetailsModel', function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
const result = controller.getVapidDetailsModel();
|
||||
expect(result).to.be.instanceof(VapidDetailsModel);
|
||||
});
|
||||
@@ -258,7 +244,7 @@ describe('Firebase Messaging > *ControllerInterface', function() {
|
||||
|
||||
describe('getIIDModel', function() {
|
||||
it('should return an instance of IIDModel', function() {
|
||||
const controller = new ControllerInterface(app);
|
||||
const controller = new MockControllerInterface(app);
|
||||
const result = controller.getIIDModel();
|
||||
expect(result).to.be.instanceof(IIDModel);
|
||||
});
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export function makeFakeApp(options = {}) {
|
||||
import { FirebaseApp } from '@firebase/app-types';
|
||||
|
||||
export function makeFakeApp(options = {}): FirebaseApp {
|
||||
window['firebase'] = window['firebase'] || {};
|
||||
let app /** @type {!firebase.app.App} */ = {};
|
||||
(app as any).INTERNAL = window['firebase'].INTERNAL;
|
||||
(app as any).options = options;
|
||||
return app;
|
||||
const app: any = {};
|
||||
app.INTERNAL = window['firebase'].INTERNAL;
|
||||
app.options = options;
|
||||
return app as FirebaseApp;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ describe('Firebase Messaging > *SWController', function() {
|
||||
.callsFake(() => Promise.resolve(true));
|
||||
|
||||
const swController = new SWController(app);
|
||||
swController.setBackgroundMessageHandler(() => {});
|
||||
swController.setBackgroundMessageHandler((() => {}) as any);
|
||||
swController.onPush_({
|
||||
waitUntil: waitUntilSpy,
|
||||
data: {
|
||||
@@ -281,7 +281,7 @@ describe('Firebase Messaging > *SWController', function() {
|
||||
const swController = new SWController(app);
|
||||
let thrownError;
|
||||
try {
|
||||
swController.setBackgroundMessageHandler('');
|
||||
swController.setBackgroundMessageHandler('' as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ export function compareDetails(
|
||||
const subscriptionKeys = ['endpoint', 'auth', 'p256dh'];
|
||||
const subscriptionValues = {
|
||||
endpoint: input.subscription.endpoint,
|
||||
auth: arrayBufferToBase64(input.subscription.getKey('auth')),
|
||||
p256dh: arrayBufferToBase64(input.subscription.getKey('p256dh'))
|
||||
auth: arrayBufferToBase64(input.subscription.getKey('auth')!),
|
||||
p256dh: arrayBufferToBase64(input.subscription.getKey('p256dh')!)
|
||||
};
|
||||
|
||||
subscriptionKeys.forEach(keyName => {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
export const fetchMock = {
|
||||
jsonOk: function(body: string): Promise<Response> {
|
||||
var mockResponse = new (window as any).Response(body, {
|
||||
jsonOk(body: string): Promise<Response> {
|
||||
const mockResponse = new (window as any).Response(body, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
@@ -24,18 +24,21 @@ export const fetchMock = {
|
||||
});
|
||||
return Promise.resolve(mockResponse);
|
||||
},
|
||||
jsonError: function(status: number, msg: string): Promise<Response> {
|
||||
jsonError(status: number, msg: string): Promise<Response> {
|
||||
const errorMsg = { error: { message: msg } };
|
||||
var mockResponse = new (window as any).Response(JSON.stringify(errorMsg), {
|
||||
status: status,
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
const mockResponse = new (window as any).Response(
|
||||
JSON.stringify(errorMsg),
|
||||
{
|
||||
status: status,
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
return Promise.resolve(mockResponse);
|
||||
},
|
||||
htmlError: function(status: number, msg: string): Promise<Response> {
|
||||
var mockResponse = new (window as any).Response(msg, {
|
||||
htmlError(status: number, msg: string): Promise<Response> {
|
||||
const mockResponse = new (window as any).Response(msg, {
|
||||
status: status,
|
||||
headers: {
|
||||
'Content-type': 'text/html'
|
||||
|
||||
@@ -220,14 +220,12 @@ describe('Firebase Messaging > *WindowController', function() {
|
||||
const controller = new WindowController(app);
|
||||
let thrownError;
|
||||
try {
|
||||
controller.useServiceWorker(null);
|
||||
controller.useServiceWorker(null as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
expect(thrownError).to.exist;
|
||||
expect(thrownError.code).to.deep.equal(
|
||||
'messaging/sw-registration-expected'
|
||||
);
|
||||
expect(thrownError.code).to.equal('messaging/sw-registration-expected');
|
||||
});
|
||||
|
||||
it(`should only be callable once`, function() {
|
||||
@@ -287,7 +285,7 @@ describe('Firebase Messaging > *WindowController', function() {
|
||||
|
||||
let thrownError;
|
||||
try {
|
||||
controller.usePublicVapidKey({});
|
||||
controller.usePublicVapidKey({} as any);
|
||||
} catch (err) {
|
||||
thrownError = err;
|
||||
}
|
||||
@@ -375,7 +373,7 @@ describe('Firebase Messaging > *WindowController', function() {
|
||||
});
|
||||
|
||||
const controller = new WindowController(app);
|
||||
controller.onMessage(onMessageSpy, null, null);
|
||||
controller.onMessage(onMessageSpy, null as any, null as any);
|
||||
controller.setupSWMessageListener_();
|
||||
|
||||
const callback = spy.args[0][1];
|
||||
|
||||
Reference in New Issue
Block a user