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..b9f5ea989 --- /dev/null +++ b/src/messaging/messaging.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; +import { AngularFireModule, FirebaseApp } from 'angularfire2'; +import { AngularFireMessaging } from './messaging'; +import 'firebase/messaging'; + +@NgModule({ + providers: [ AngularFireMessaging ] +}) +export class AngularFireMessagingModule { } diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts new file mode 100644 index 000000000..2d49710fe --- /dev/null +++ b/src/messaging/messaging.ts @@ -0,0 +1,75 @@ +import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; +import { messaging } from 'firebase'; +import { requestPermission } from './observable/request-permission'; +import { Observable, empty, from, of, throwError } from 'rxjs'; +import { mergeMap, catchError } from 'rxjs/operators'; +import { FirebaseOptions, FirebaseAppConfig } from 'angularfire2'; +import { FirebaseOptionsToken, FirebaseNameOrConfigToken, _firebaseAppFactory, FirebaseZoneScheduler } from 'angularfire2'; + +@Injectable() +export class AngularFireMessaging { + messaging: messaging.Messaging; + requestPermission: Observable; + getToken: Observable; + tokenChanges: Observable; + messages: Observable<{}>; + requestToken: Observable; + deleteToken: (string) => Observable; + + constructor( + @Inject(FirebaseOptionsToken) options:FirebaseOptions, + @Optional() @Inject(FirebaseNameOrConfigToken) nameOrConfig:string|FirebaseAppConfig|undefined, + @Inject(PLATFORM_ID) platformId: Object, + zone: NgZone + ) { + const scheduler = new FirebaseZoneScheduler(zone, platformId); + this.messaging = zone.runOutsideAngular(() => { + const app = _firebaseAppFactory(options, nameOrConfig); + return app.messaging(); + }); + + if (isPlatformBrowser(platformId)) { + + this.requestPermission = scheduler.runOutsideAngular( + requestPermission(this.messaging) + ); + + this.getToken = scheduler.runOutsideAngular( + from(this.messaging.getToken()) + ); + + this.tokenChanges = scheduler.runOutsideAngular( + new Observable(subscriber => { + this.messaging.getToken().then(t => subscriber.next(t)); + this.messaging.onTokenRefresh(subscriber.next); + }) + ); + + this.messages = scheduler.runOutsideAngular( + new Observable(subscriber => { + this.messaging.onMessage(subscriber.next); + }) + ); + + this.requestToken = this.requestPermission.pipe( + catchError(() => of(null)), + mergeMap(() => this.tokenChanges), + ); + + } else { + + this.requestPermission = throwError('Not available on server platform.'); + this.getToken = of(null); + this.tokenChanges = of(null); + this.messages = empty(); + this.requestToken = of(null); + + } + + this.deleteToken = (token: string) => scheduler.runOutsideAngular( + 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..d869b2c1d --- /dev/null +++ b/src/messaging/observable/request-permission.ts @@ -0,0 +1,6 @@ +import { Observable, from } from 'rxjs'; +import { messaging } from 'firebase'; + +export function requestPermission(messaging: messaging.Messaging): 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 476e302b2..27cfec26b 100644 --- a/src/root.spec.js +++ b/src/root.spec.js @@ -13,6 +13,7 @@ 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'; // // 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 35fa29c65..241f63939 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -16,6 +16,7 @@ "angularfire2/firestore": ["./firestore"], "angularfire2/functions": ["./functions"], "angularfire2/storage": ["./storage"], + "angularfire2/messaging": ["./messaging"], "angularfire2/database-deprecated": ["./database-deprecated"] }, "rootDir": ".", diff --git a/tools/build.js b/tools/build.js index ce8069736..466dc6548 100644 --- a/tools/build.js +++ b/tools/build.js @@ -20,6 +20,7 @@ const GLOBALS = { 'firebase/app': 'firebase', 'firebase/auth': 'firebase', 'firebase/database': 'firebase', + 'firebase/messaging': 'firebase', 'firebase/firestore': 'firebase', 'firebase/functions': 'firebase', 'firebase/storage': 'firebase', @@ -29,7 +30,8 @@ const GLOBALS = { 'angularfire2/database-deprecated': 'angularfire2.database_deprecated', 'angularfire2/firestore': 'angularfire2.firestore', 'angularfire2/functions': 'angularfire2.functions', - 'angularfire2/storage': 'angularfire2.storage' + 'angularfire2/storage': 'angularfire2.storage', + 'angularfire2/messaging': 'angularfire2.messaging', }; // Map of dependency versions across all packages @@ -53,7 +55,8 @@ const MODULE_NAMES = { "database-deprecated": 'angularfire2.database_deprecated', firestore: 'angularfire2.firestore', functions: 'angularfire2.functions', - storage: 'angularfire2.storage' + storage: 'angularfire2.storage', + messaging: 'angularfire2.messaging', }; const ENTRIES = { @@ -63,7 +66,8 @@ const ENTRIES = { "database-deprecated": `${process.cwd()}/dist/packages-dist/database-deprecated/index.js`, firestore: `${process.cwd()}/dist/packages-dist/firestore/index.js`, functions: `${process.cwd()}/dist/packages-dist/functions/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 = { @@ -74,7 +78,8 @@ const SRC_PKG_PATHS = { firestore: `${process.cwd()}/src/firestore/package.json`, "firebase-node": `${process.cwd()}/src/firebase-node/package.json`, functions: `${process.cwd()}/src/functions/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 = { @@ -85,7 +90,8 @@ const DEST_PKG_PATHS = { firestore: `${process.cwd()}/dist/packages-dist/firestore/package.json`, "firebase-node": `${process.cwd()}/dist/packages-dist/firebase-node/package.json`, functions: `${process.cwd()}/dist/packages-dist/functions/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`, }; // Constants for running typescript commands @@ -246,6 +252,7 @@ function getVersions() { getDestPackageFile('firebase-node'), getDestPackageFile('functions'), getDestPackageFile('storage'), + getDestPackageFile('messaging'), getDestPackageFile('database-deprecated') ]; return paths @@ -285,6 +292,7 @@ function buildModules(globals) { const firestore$ = buildModule('firestore', globals); const functions$ = buildModule('functions', globals); const storage$ = buildModule('storage', globals); + const messaging$ = buildModule('messaging', globals); const dbdep$ = buildModule('database-deprecated', globals); return forkJoin(core$, from(copyRootTest())).pipe( switchMapTo(auth$), @@ -292,7 +300,8 @@ function buildModules(globals) { switchMapTo(firestore$), switchMapTo(functions$), switchMapTo(storage$), - switchMapTo(dbdep$) + switchMapTo(messaging$), + switchMapTo(dbdep$), ); } @@ -312,6 +321,7 @@ function buildLibrary(globals) { const fsStats = measure('firestore'); const functionsStats = measure('functions'); const storageStats = measure('storage'); + const messagingStats = measure('messaging'); const dbdepStats = measure('database-deprecated'); console.log(` core.umd.js - ${coreStats.size}, ${coreStats.gzip} @@ -320,6 +330,7 @@ function buildLibrary(globals) { firestore.umd.js - ${fsStats.size}, ${fsStats.gzip} functions.umd.js - ${functionsStats.size}, ${functionsStats.gzip} storage.umd.js - ${storageStats.size}, ${storageStats.gzip} + messaging.umd.js - ${messagingStats.size}, ${messagingStats.gzip} database-deprecated.umd.js - ${dbdepStats.size}, ${dbdepStats.gzip} `); verifyVersions();