UNPKG

10.9 kBJavaScriptView Raw
1import { queueScheduler, asyncScheduler } from 'rxjs';
2import { tap, subscribeOn, observeOn } from 'rxjs/operators';
3import { InjectionToken, Version, isDevMode, NgZone, Optional, VERSION as VERSION$1, NgModule, Inject, PLATFORM_ID } from '@angular/core';
4import firebase from 'firebase/app';
5
6function noop() {
7}
8/**
9 * Schedules tasks so that they are invoked inside the Zone that is passed in the constructor.
10 */
11// tslint:disable-next-line:class-name
12class ɵZoneScheduler {
13 constructor(zone, delegate = queueScheduler) {
14 this.zone = zone;
15 this.delegate = delegate;
16 }
17 now() {
18 return this.delegate.now();
19 }
20 schedule(work, delay, state) {
21 const targetZone = this.zone;
22 // Wrap the specified work function to make sure that if nested scheduling takes place the
23 // work is executed in the correct zone
24 const workInZone = function (state) {
25 targetZone.runGuarded(() => {
26 work.apply(this, [state]);
27 });
28 };
29 // Scheduling itself needs to be run in zone to ensure setInterval calls for async scheduling are done
30 // inside the correct zone. This scheduler needs to schedule asynchronously always to ensure that
31 // firebase emissions are never synchronous. Specifying a delay causes issues with the queueScheduler delegate.
32 return this.delegate.schedule(workInZone, delay, state);
33 }
34}
35// tslint:disable-next-line:class-name
36class ɵBlockUntilFirstOperator {
37 constructor(zone) {
38 this.zone = zone;
39 this.task = null;
40 }
41 call(subscriber, source) {
42 const unscheduleTask = this.unscheduleTask.bind(this);
43 this.task = this.zone.run(() => Zone.current.scheduleMacroTask('firebaseZoneBlock', noop, {}, noop, noop));
44 return source.pipe(tap({ next: unscheduleTask, complete: unscheduleTask, error: unscheduleTask })).subscribe(subscriber).add(unscheduleTask);
45 }
46 unscheduleTask() {
47 // maybe this is a race condition, invoke in a timeout
48 // hold for 10ms while I try to figure out what is going on
49 setTimeout(() => {
50 if (this.task != null && this.task.state === 'scheduled') {
51 this.task.invoke();
52 this.task = null;
53 }
54 }, 10);
55 }
56}
57// tslint:disable-next-line:class-name
58class ɵAngularFireSchedulers {
59 constructor(ngZone) {
60 this.ngZone = ngZone;
61 this.outsideAngular = ngZone.runOutsideAngular(() => new ɵZoneScheduler(Zone.current));
62 this.insideAngular = ngZone.run(() => new ɵZoneScheduler(Zone.current, asyncScheduler));
63 }
64}
65/**
66 * Operator to block the zone until the first value has been emitted or the observable
67 * has completed/errored. This is used to make sure that universal waits until the first
68 * value from firebase but doesn't block the zone forever since the firebase subscription
69 * is still alive.
70 */
71function ɵkeepUnstableUntilFirstFactory(schedulers) {
72 return function keepUnstableUntilFirst(obs$) {
73 obs$ = obs$.lift(new ɵBlockUntilFirstOperator(schedulers.ngZone));
74 return obs$.pipe(
75 // Run the subscribe body outside of Angular (e.g. calling Firebase SDK to add a listener to a change event)
76 subscribeOn(schedulers.outsideAngular),
77 // Run operators inside the angular zone (e.g. side effects via tap())
78 observeOn(schedulers.insideAngular)
79 // INVESTIGATE https://github.com/angular/angularfire/pull/2315
80 // share()
81 );
82 };
83}
84// DEBUG quick debugger function for inline logging that typescript doesn't complain about
85// wrote it for debugging the ɵlazySDKProxy, commenting out for now; should consider exposing a
86// verbose mode for AngularFire in a future release that uses something like this in multiple places
87// usage: () => log('something') || returnValue
88// const log = (...args: any[]): false => { console.log(...args); return false }
89// The problem here are things like ngOnDestroy are missing, then triggering the service
90// rather than dig too far; I'm capturing these as I go.
91const noopFunctions = ['ngOnDestroy'];
92// INVESTIGATE should we make the Proxy revokable and do some cleanup?
93// right now it's fairly simple but I'm sure this will grow in complexity
94const ɵlazySDKProxy = (klass, observable, zone, options = {}) => {
95 return new Proxy(klass, {
96 get: (_, name) => zone.runOutsideAngular(() => {
97 var _a;
98 if (klass[name]) {
99 if ((_a = options === null || options === void 0 ? void 0 : options.spy) === null || _a === void 0 ? void 0 : _a.get) {
100 options.spy.get(name, klass[name]);
101 }
102 return klass[name];
103 }
104 if (noopFunctions.indexOf(name) > -1) {
105 return () => {
106 };
107 }
108 const promise = observable.toPromise().then(mod => {
109 const ret = mod && mod[name];
110 // TODO move to proper type guards
111 if (typeof ret === 'function') {
112 return ret.bind(mod);
113 }
114 else if (ret && ret.then) {
115 return ret.then((res) => zone.run(() => res));
116 }
117 else {
118 return zone.run(() => ret);
119 }
120 });
121 // recurse the proxy
122 return new Proxy(() => { }, {
123 get: (_, name) => promise[name],
124 // TODO handle callbacks as transparently as I can
125 apply: (self, _, args) => promise.then(it => {
126 var _a;
127 const res = it && it(...args);
128 if ((_a = options === null || options === void 0 ? void 0 : options.spy) === null || _a === void 0 ? void 0 : _a.apply) {
129 options.spy.apply(name, args, res);
130 }
131 return res;
132 })
133 });
134 })
135 });
136};
137const ɵapplyMixins = (derivedCtor, constructors) => {
138 constructors.forEach((baseCtor) => {
139 Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => {
140 Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name));
141 });
142 });
143};
144
145const FIREBASE_OPTIONS = new InjectionToken('angularfire2.app.options');
146const FIREBASE_APP_NAME = new InjectionToken('angularfire2.app.nameOrConfig');
147// Have to implement as we need to return a class from the provider, we should consider exporting
148// this in the firebase/app types as this is our highest risk of breaks
149class FirebaseApp {
150}
151const VERSION = new Version('6.1.5');
152function ɵfirebaseAppFactory(options, zone, nameOrConfig) {
153 const name = typeof nameOrConfig === 'string' && nameOrConfig || '[DEFAULT]';
154 const config = typeof nameOrConfig === 'object' && nameOrConfig || {};
155 config.name = config.name || name;
156 // Added any due to some inconsistency between @firebase/app and firebase types
157 const existingApp = firebase.apps.filter(app => app && app.name === config.name)[0];
158 // We support FirebaseConfig, initializeApp's public type only accepts string; need to cast as any
159 // Could be solved with https://github.com/firebase/firebase-js-sdk/pull/1206
160 const app = (existingApp || zone.runOutsideAngular(() => firebase.initializeApp(options, config)));
161 try {
162 if (JSON.stringify(options) !== JSON.stringify(app.options)) {
163 const hmr = !!module.hot;
164 log('error', `${app.name} Firebase App already initialized with different options${hmr ? ', you may need to reload as Firebase is not HMR aware.' : '.'}`);
165 }
166 }
167 catch (e) { }
168 return app;
169}
170const ɵlogAuthEmulatorError = () => {
171 // TODO sort this out, https://github.com/angular/angularfire/issues/2656
172 log('warn', 'You may need to import \'firebase/auth\' manually in your component rather than rely on AngularFireAuth\'s dynamic import, when using the emulator suite https://github.com/angular/angularfire/issues/2656');
173};
174const log = (level, ...args) => {
175 if (isDevMode() && typeof console !== 'undefined') {
176 console[level](...args);
177 }
178};
179const ɵ0 = log;
180globalThis.ɵAngularfireInstanceCache || (globalThis.ɵAngularfireInstanceCache = new Map());
181function ɵfetchInstance(cacheKey, moduleName, app, fn, args) {
182 const [instance, ...cachedArgs] = globalThis.ɵAngularfireInstanceCache.get(cacheKey) || [];
183 if (instance) {
184 try {
185 if (args.some((arg, i) => {
186 const cachedArg = cachedArgs[i];
187 if (arg && typeof arg === 'object') {
188 return JSON.stringify(arg) !== JSON.stringify(cachedArg);
189 }
190 else {
191 return arg !== cachedArg;
192 }
193 })) {
194 const hmr = !!module.hot;
195 log('error', `${moduleName} was already initialized on the ${app.name} Firebase App instance with different settings.${hmr ? ' You may need to reload as Firebase is not HMR aware.' : ''}`);
196 }
197 }
198 catch (e) { }
199 return instance;
200 }
201 else {
202 const newInstance = fn();
203 globalThis.ɵAngularfireInstanceCache.set(cacheKey, [newInstance, ...args]);
204 return newInstance;
205 }
206}
207const FIREBASE_APP_PROVIDER = {
208 provide: FirebaseApp,
209 useFactory: ɵfirebaseAppFactory,
210 deps: [
211 FIREBASE_OPTIONS,
212 NgZone,
213 [new Optional(), FIREBASE_APP_NAME]
214 ]
215};
216class AngularFireModule {
217 // tslint:disable-next-line:ban-types
218 constructor(platformId) {
219 firebase.registerVersion('angularfire', VERSION.full, platformId.toString());
220 firebase.registerVersion('angular', VERSION$1.full);
221 }
222 static initializeApp(options, nameOrConfig) {
223 return {
224 ngModule: AngularFireModule,
225 providers: [
226 { provide: FIREBASE_OPTIONS, useValue: options },
227 { provide: FIREBASE_APP_NAME, useValue: nameOrConfig }
228 ]
229 };
230 }
231}
232AngularFireModule.decorators = [
233 { type: NgModule, args: [{
234 providers: [FIREBASE_APP_PROVIDER]
235 },] }
236];
237/** @nocollapse */
238AngularFireModule.ctorParameters = () => [
239 { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
240];
241
242/**
243 * Generated bundle index. Do not edit.
244 */
245
246export { AngularFireModule, FIREBASE_APP_NAME, FIREBASE_OPTIONS, FirebaseApp, VERSION, ɵ0, ɵAngularFireSchedulers, ɵBlockUntilFirstOperator, ɵZoneScheduler, ɵapplyMixins, ɵfetchInstance, ɵfirebaseAppFactory, ɵkeepUnstableUntilFirstFactory, ɵlazySDKProxy, ɵlogAuthEmulatorError };
247//# sourceMappingURL=angular-fire.js.map