diff --git a/firebase-messaging-sw.js b/firebase-messaging-sw.js new file mode 100644 index 000000000..eaf06c7c2 --- /dev/null +++ b/firebase-messaging-sw.js @@ -0,0 +1,8 @@ +importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js'); +importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging.js'); + +firebase.initializeApp({ + 'messagingSenderId': '920323787688' +}); + +const messaging = firebase.messaging(); diff --git a/karma.conf.js b/karma.conf.js index 6244a67db..03fec0de6 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -27,13 +27,22 @@ module.exports = function(config) { 'karma-test-shim.js', 'node_modules/firebase/firebase.js', 'node_modules/firebase/firebase-firestore.js', + + // This service worker is loaded by a service worker registration + { + pattern: 'firebase-messaging-sw.js', + included: false + }, + 'dist/packages-dist/bundles/core.umd.{js,map}', 'dist/packages-dist/bundles/auth.umd.{js,map}', 'dist/packages-dist/bundles/database.umd.{js,map}', 'dist/packages-dist/bundles/firestore.umd.{js,map}', 'dist/packages-dist/bundles/storage.umd.{js,map}', + 'dist/packages-dist/bundles/messaging.umd.{js,map}', 'dist/packages-dist/bundles/database-deprecated.umd.{js,map}', 'dist/packages-dist/bundles/test.umd.{js,map}', + ], port: 9876, diff --git a/package.json b/package.json index 75370c6f7..a43132183 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angularfire2", - "version": "5.0.0-rc.6", + "version": "5.0.0-rc.7", "description": "The official library of Firebase and Angular.", "private": true, "scripts": { diff --git a/src/messaging/index.spec.ts b/src/messaging/index.spec.ts new file mode 100644 index 000000000..d37e336c9 --- /dev/null +++ b/src/messaging/index.spec.ts @@ -0,0 +1 @@ +export * from './messaging.spec'; diff --git a/src/messaging/index.ts b/src/messaging/index.ts new file mode 100644 index 000000000..4aaf8f92e --- /dev/null +++ b/src/messaging/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/src/messaging/messaging.module.ts b/src/messaging/messaging.module.ts new file mode 100644 index 000000000..8ceb24766 --- /dev/null +++ b/src/messaging/messaging.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { AngularFireModule, FirebaseApp } from 'angularfire2'; +import { AngularFireMessaging } from './messaging'; +import '@firebase/messaging'; + +export function _getAngularFireMessaging(app: FirebaseApp) { + return new AngularFireMessaging(app); +} + +export const AngularFireMessagingProvider = { + provide: AngularFireMessaging, + useFactory: _getAngularFireMessaging, + deps: [ FirebaseApp ] +}; + +export const STORAGE_PROVIDERS = [ + AngularFireMessagingProvider, +]; + +@NgModule({ + imports: [ AngularFireModule ], + providers: [ STORAGE_PROVIDERS ] +}) +export class AngularFireMessagingModule { } diff --git a/src/messaging/messaging.spec.ts b/src/messaging/messaging.spec.ts new file mode 100644 index 000000000..1f354202a --- /dev/null +++ b/src/messaging/messaging.spec.ts @@ -0,0 +1,51 @@ +import { COMMON_CONFIG } from './test-config'; +import { FirebaseApp as FBApp } from '@firebase/app-types'; +import { Observable } from 'rxjs/Observable' +import { forkJoin } from 'rxjs/observable/forkJoin'; +import { TestBed, inject } from '@angular/core/testing'; +import { FirebaseApp, FirebaseAppConfig, AngularFireModule } from 'angularfire2'; +import { AngularFireMessaging, AngularFireMessagingModule } from 'angularfire2/messaging'; +import * as firebase from 'firebase/app'; +import 'firebase/messaging'; + +xdescribe('AngularFireMessaging', () => { + let app: firebase.app.App; + let afMessaging: AngularFireMessaging; + + beforeAll((done: any) => { + navigator.serviceWorker.register('/base/firebase-messaging-sw.js') + .then((registration) => { + app = firebase.initializeApp(COMMON_CONFIG, 'SW-REG'); + app.messaging!().useServiceWorker(registration); + afMessaging = new AngularFireMessaging(app as any); + done(); + }) + .catch(e => { + console.error(e); + done.fail(); + }) + }); + + it('should exist', () => { + expect(afMessaging instanceof AngularFireMessaging).toBe(true); + }); + + it('should have the Firebase messaging instance', () => { + expect(afMessaging.messaging).toBeDefined(); + }); + + it('should get request permission and get a token', (done) => { + afMessaging.requestToken.subscribe(token => { + expect(typeof token === 'string').toBe(true); + done(); + }, done.fail); + }); + + it('should give me a token', (done) => { + afMessaging.getToken.subscribe(token => { + expect(typeof token === 'string').toBe(true); + done(); + }, done.fail); + }); + +}); diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts new file mode 100644 index 000000000..c8e573ed0 --- /dev/null +++ b/src/messaging/messaging.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { FirebaseApp } from 'angularfire2'; +import { FirebaseMessaging } from '@firebase/messaging-types'; +import { requestPermission } from './observable/request-permission'; +import { from } from 'rxjs/observable/from'; +import { mergeMap } from 'rxjs/operators'; + +@Injectable() +export class AngularFireMessaging { + messaging: FirebaseMessaging; + requestPermission: Observable; + getToken: Observable; + tokenChanges: Observable; + messages: Observable<{}>; + requestToken: Observable; + + constructor(public app: FirebaseApp) { + this.messaging = app.messaging(); + + this.requestPermission = requestPermission(this.messaging); + + this.getToken = from(this.messaging.getToken()!); + + this.tokenChanges = new Observable(subscriber => { + this.messaging.getToken()!.then(t => subscriber.next(t)); + this.messaging.onTokenRefresh(subscriber); + }); + + this.messages = new Observable(subscriber => { + this.messaging.onMessage(subscriber); + }); + + this.requestToken = this.requestPermission.pipe( + mergeMap(() => this.tokenChanges) + ); + + } + + deleteToken(token: string) { + return from(this.messaging.deleteToken(token)!); + } + +} \ No newline at end of file diff --git a/src/messaging/observable/request-permission.ts b/src/messaging/observable/request-permission.ts new file mode 100644 index 000000000..c4f5c5ff5 --- /dev/null +++ b/src/messaging/observable/request-permission.ts @@ -0,0 +1,7 @@ +import { Observable } from 'rxjs'; +import { from } from 'rxjs/observable/from'; +import { FirebaseMessaging } from '@firebase/messaging-types'; + +export function requestPermission(messaging: FirebaseMessaging): Observable { + return from(messaging.requestPermission()!); +} diff --git a/src/messaging/package.json b/src/messaging/package.json new file mode 100644 index 000000000..360fc5520 --- /dev/null +++ b/src/messaging/package.json @@ -0,0 +1,31 @@ +{ + "name": "angularfire2/messaging", + "version": "ANGULARFIRE2_VERSION", + "description": "The messaging module", + "main": "../bundles/messaging.umd.js", + "module": "index.js", + "es2015": "./es2015/index.js", + "keywords": [ + "angular", + "firebase", + "rxjs" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/angular/angularfire2.git" + }, + "author": "angular,firebase", + "license": "MIT", + "peerDependencies": { + "angularfire2": "ANGULARFIRE2_VERSION", + "@angular/common": "ANGULAR_VERSION", + "@angular/core": "ANGULAR_VERSION", + "@angular/platform-browser": "ANGULAR_VERSION", + "@angular/platform-browser-dynamic": "ANGULAR_VERSION", + "@firebase/app": "FIREBASE_APP_VERSION", + "@firebase/messaging": "FIREBASE_MESSAGING_VERSION", + "rxjs": "RXJS_VERSION", + "zone.js": "ZONEJS_VERSION" + }, + "typings": "index.d.ts" +} diff --git a/src/messaging/public_api.ts b/src/messaging/public_api.ts new file mode 100644 index 000000000..0c09cbd56 --- /dev/null +++ b/src/messaging/public_api.ts @@ -0,0 +1,3 @@ +export * from './observable/request-permission'; +export * from './messaging'; +export * from './messaging.module'; diff --git a/src/messaging/test-config.ts b/src/messaging/test-config.ts new file mode 100644 index 000000000..58f9efc32 --- /dev/null +++ b/src/messaging/test-config.ts @@ -0,0 +1,8 @@ + +export const COMMON_CONFIG = { + apiKey: "AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA", + authDomain: "angularfire2-test.firebaseapp.com", + databaseURL: "https://angularfire2-test.firebaseio.com", + storageBucket: "angularfire2-test.appspot.com", + messagingSenderId: "920323787688" +}; diff --git a/src/messaging/tsconfig-build.json b/src/messaging/tsconfig-build.json new file mode 100644 index 000000000..749fa92b6 --- /dev/null +++ b/src/messaging/tsconfig-build.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "module": "es2015", + "target": "es2015", + "noImplicitAny": false, + "outDir": "../../dist/packages-dist/messaging/es2015", + "rootDir": ".", + "sourceMap": true, + "inlineSources": true, + "declaration": false, + "removeComments": true, + "strictNullChecks": true, + "lib": ["es2015", "dom", "es2015.promise", "es2015.collection", "es2015.iterable"], + "skipLibCheck": true, + "moduleResolution": "node", + "paths": { + "angularfire2": ["../../dist/packages-dist"] + } + }, + "files": [ + "index.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "enableSummariesForJit": false + } +} + diff --git a/src/messaging/tsconfig-esm.json b/src/messaging/tsconfig-esm.json new file mode 100644 index 000000000..0b3d05820 --- /dev/null +++ b/src/messaging/tsconfig-esm.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig-build.json", + "compilerOptions": { + "target": "es5", + "outDir": "../../dist/packages-dist/messaging", + "declaration": true + }, + "files": [ + "public_api.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "enableSummariesForJit": false, + "flatModuleOutFile": "index.js", + "flatModuleId": "angularfire2/messaging" + } +} diff --git a/src/messaging/tsconfig-test.json b/src/messaging/tsconfig-test.json new file mode 100644 index 000000000..fc0dc883b --- /dev/null +++ b/src/messaging/tsconfig-test.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig-esm.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "angularfire2": ["../../dist/packages-dist"] + } + }, + "files": [ + "index.spec.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ] +} diff --git a/src/root.spec.js b/src/root.spec.js index b60264afb..12f4a8c9d 100644 --- a/src/root.spec.js +++ b/src/root.spec.js @@ -12,6 +12,19 @@ export * from './packages-dist/database/list/snapshot-changes.spec'; export * from './packages-dist/database/list/state-changes.spec'; export * from './packages-dist/database/list/audit-trail.spec'; export * from './packages-dist/storage/storage.spec'; +export * from './packages-dist/messaging/messaging.spec'; + +// navigator.serviceWorker.register('http://localhost:9876/base/firebase-messaging-sw.js') +// .then(registration => { +// debugger; +// const app = firebase.initializeApp({ +// 'messagingSenderId': '920323787688' +// }, 'MESSAGING'); +// app.messaging().useServiceWorker(registration); +// }) +// .catch(e => { +// console.error(e); +// }) // // Since this a deprecated API, we run on it on manual tests only // // It needs a network connection to run which makes it flaky on Travis diff --git a/src/tsconfig.json b/src/tsconfig.json index 2a0a351e4..6027275dc 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -15,6 +15,7 @@ "angularfire2/database": ["./database"], "angularfire2/firestore": ["./firestore"], "angularfire2/storage": ["./storage"], + "angularfire2/messaging": ["./messaging"], "angularfire2/database-deprecated": ["./database-deprecated"] }, "rootDir": ".", diff --git a/tools/build.js b/tools/build.js index 92f01a0fd..b6c6bdf79 100644 --- a/tools/build.js +++ b/tools/build.js @@ -76,6 +76,7 @@ const GLOBALS = { 'angularfire2/database-deprecated': 'angularfire2.database_deprecated', 'angularfire2/firestore': 'angularfire2.firestore', 'angularfire2/storage': 'angularfire2.storage', + 'angularfire2/messaging': 'angularfire2.messaging', 'zone.js': 'Zone' }; @@ -87,6 +88,7 @@ const VERSIONS = { FIREBASE_FIRESTORE_VERSION: pkg.dependencies['@firebase/firestore'], FIREBASE_AUTH_VERSION: pkg.dependencies['@firebase/auth'], FIREBASE_STORAGE_VERSION: pkg.dependencies['@firebase/storage'], + FIREBASE_MESSAGING_VERSION: pkg.dependencies['@firebase/messaging'], RXJS_VERSION: pkg.dependencies['rxjs'], ZONEJS_VERSION: pkg.dependencies['zone.js'], ANGULARFIRE2_VERSION: pkg.version, @@ -103,7 +105,8 @@ const MODULE_NAMES = { database: 'angularfire2.database', "database-deprecated": 'angularfire2.database_deprecated', firestore: 'angularfire2.firestore', - storage: 'angularfire2.storage' + storage: 'angularfire2.storage', + messaging: 'angularfire2.messaging' }; const ENTRIES = { @@ -112,7 +115,8 @@ const ENTRIES = { database: `${process.cwd()}/dist/packages-dist/database/index.js`, "database-deprecated": `${process.cwd()}/dist/packages-dist/database-deprecated/index.js`, firestore: `${process.cwd()}/dist/packages-dist/firestore/index.js`, - storage: `${process.cwd()}/dist/packages-dist/storage/index.js` + storage: `${process.cwd()}/dist/packages-dist/storage/index.js`, + messaging: `${process.cwd()}/dist/packages-dist/messaging/index.js` }; const SRC_PKG_PATHS = { @@ -122,7 +126,8 @@ const SRC_PKG_PATHS = { "database-deprecated": `${process.cwd()}/src/database-deprecated/package.json`, firestore: `${process.cwd()}/src/firestore/package.json`, "firebase-node": `${process.cwd()}/src/firebase-node/package.json`, - storage: `${process.cwd()}/src/storage/package.json` + storage: `${process.cwd()}/src/storage/package.json`, + messaging: `${process.cwd()}/src/messaging/package.json`, }; const DEST_PKG_PATHS = { @@ -132,7 +137,8 @@ const DEST_PKG_PATHS = { "database-deprecated": `${process.cwd()}/dist/packages-dist/database-deprecated/package.json`, firestore: `${process.cwd()}/dist/packages-dist/firestore/package.json`, "firebase-node": `${process.cwd()}/dist/packages-dist/firebase-node/package.json`, - storage: `${process.cwd()}/dist/packages-dist/storage/package.json` + storage: `${process.cwd()}/dist/packages-dist/storage/package.json`, + messaging: `${process.cwd()}/dist/packages-dist/messaging/package.json`, }; const FIREBASE_FEATURE_MODULES = { @@ -141,6 +147,7 @@ const FIREBASE_FEATURE_MODULES = { database: `${process.cwd()}/node_modules/@firebase/database/dist/esm/index.js`, firestore: `${process.cwd()}/node_modules/@firebase/firestore/dist/esm/index.js`, storage: `${process.cwd()}/node_modules/@firebase/storage/dist/esm/index.js`, + messaging: `${process.cwd()}/node_modules/@firebase/messaging/dist/esm/index.js`, util: `${process.cwd()}/node_modules/@firebase/util/dist/esm/index.js`, }; @@ -301,6 +308,7 @@ function getVersions() { getDestPackageFile('firestore'), getDestPackageFile('firebase-node'), getDestPackageFile('storage'), + getDestPackageFile('messaging'), getDestPackageFile('database-deprecated') ]; return paths @@ -339,6 +347,7 @@ function buildModules(globals) { const db$ = buildModule('database', globals); const firestore$ = buildModule('firestore', globals); const storage$ = buildModule('storage', globals); + const messaging$ = buildModule('messaging', globals); const dbdep$ = buildModule('database-deprecated', globals); return Observable .forkJoin(core$, Observable.from(copyRootTest())) @@ -346,6 +355,7 @@ function buildModules(globals) { .switchMapTo(db$) .switchMapTo(firestore$) .switchMapTo(storage$) + .switchMapTo(messaging$) .switchMapTo(dbdep$); } @@ -365,6 +375,7 @@ function buildLibrary(globals) { const dbStats = measure('database'); const fsStats = measure('firestore'); const storageStats = measure('storage'); + const messagingStats = measure('messaging'); const dbdepStats = measure('database-deprecated'); console.log(` core.umd.js - ${coreStats.size}, ${coreStats.gzip} @@ -372,6 +383,7 @@ function buildLibrary(globals) { database.umd.js - ${dbStats.size}, ${dbStats.gzip} firestore.umd.js - ${fsStats.size}, ${fsStats.gzip} storage.umd.js - ${storageStats.size}, ${storageStats.gzip} + messaging.umd.js - ${messagingStats.size}, ${messagingStats.gzip} database-deprecated.umd.js - ${dbdepStats.size}, ${dbdepStats.gzip} `); verifyVersions();