@angular/fire
Version:
Angular + Firebase = ❤️
202 lines (197 loc) • 8.78 kB
JavaScript
import * as i0 from '@angular/core';
import { Version, isDevMode, inject, NgZone, Injectable, runInInjectionContext, PendingTasks, EnvironmentInjector } from '@angular/core';
import { getApps } from 'firebase/app';
import { pendingUntilEvent } from '@angular/core/rxjs-interop';
import { queueScheduler, asyncScheduler, Observable } from 'rxjs';
import { subscribeOn, observeOn } from 'rxjs/operators';
const VERSION = new Version('ANGULARFIRE2_VERSION');
const ɵisSupportedError = (module) => `The APP_INITIALIZER that is "making" isSupported() sync for the sake of convenient DI has not resolved in this
context. Rather than injecting ${module} in the constructor, first ensure that ${module} is supported by calling
\`await isSupported()\`, then retrieve the instance from the injector manually \`injector.get(${module})\`.`;
function ɵgetDefaultInstanceOf(identifier, provided, defaultApp) {
if (provided) {
// Was provide* only called once? If so grab that
if (provided.length === 1) {
return provided[0];
}
const providedUsingDefaultApp = provided.filter((it) => it.app === defaultApp);
// Was provide* only called once, using the default app? If so use that
if (providedUsingDefaultApp.length === 1) {
return providedUsingDefaultApp[0];
}
}
// Grab the default instance from the defaultApp
const defaultAppWithContainer = defaultApp;
const provider = defaultAppWithContainer.container.getProvider(identifier);
return provider.getImmediate({ optional: true });
}
const ɵgetAllInstancesOf = (identifier, app) => {
const apps = app ? [app] : getApps();
const instances = [];
apps.forEach((app) => {
const provider = app.container.getProvider(identifier);
provider.instances.forEach((instance) => {
if (!instances.includes(instance)) {
instances.push(instance);
}
});
});
return instances;
};
/* eslint-disable @typescript-eslint/ban-ts-comment */
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["SILENT"] = 0] = "SILENT";
LogLevel[LogLevel["WARN"] = 1] = "WARN";
LogLevel[LogLevel["VERBOSE"] = 2] = "VERBOSE";
})(LogLevel || (LogLevel = {}));
var currentLogLevel = (isDevMode() && typeof Zone !== "undefined") ? LogLevel.WARN : LogLevel.SILENT;
const setLogLevel = (logLevel) => currentLogLevel = logLevel;
/**
* Schedules tasks so that they are invoked inside the Zone that is passed in the constructor.
*/
class ɵZoneScheduler {
zone;
delegate;
constructor(zone, delegate = queueScheduler) {
this.zone = zone;
this.delegate = delegate;
}
now() {
return this.delegate.now();
}
schedule(work, delay, state) {
const targetZone = this.zone;
// Wrap the specified work function to make sure that if nested scheduling takes place the
// work is executed in the correct zone
const workInZone = function (state) {
if (targetZone) {
targetZone.runGuarded(() => {
work.apply(this, [state]);
});
}
else {
work.apply(this, [state]);
}
};
// Scheduling itself needs to be run in zone to ensure setInterval calls for async scheduling are done
// inside the correct zone. This scheduler needs to schedule asynchronously always to ensure that
// firebase emissions are never synchronous. Specifying a delay causes issues with the queueScheduler delegate.
return this.delegate.schedule(workInZone, delay, state);
}
}
class ɵAngularFireSchedulers {
outsideAngular;
insideAngular;
constructor() {
const ngZone = inject(NgZone);
this.outsideAngular = ngZone.runOutsideAngular(() => new ɵZoneScheduler(typeof Zone === 'undefined' ? undefined : Zone.current));
this.insideAngular = ngZone.run(() => new ɵZoneScheduler(typeof Zone === 'undefined' ? undefined : Zone.current, asyncScheduler));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: ɵAngularFireSchedulers, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: ɵAngularFireSchedulers, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: ɵAngularFireSchedulers, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
var alreadyWarned = false;
function warnOutsideInjectionContext(original, logLevel) {
if (!alreadyWarned && (currentLogLevel > LogLevel.SILENT || isDevMode())) {
alreadyWarned = true;
console.warn("Calling Firebase APIs outside of an Injection context may destabilize your application leading to subtle change-detection and hydration bugs. Find more at https://github.com/angular/angularfire/blob/main/docs/zones.md");
}
if (currentLogLevel >= logLevel) {
console.warn(`Firebase API called outside injection context: ${original.name}`);
}
}
function runOutsideAngular(fn) {
const ngZone = inject(NgZone, { optional: true });
if (!ngZone) {
return fn();
}
return ngZone.runOutsideAngular(() => fn());
}
function run(fn) {
const ngZone = inject(NgZone, { optional: true });
if (!ngZone) {
return fn();
}
return ngZone.run(() => fn());
}
const zoneWrapFn = (it, taskDone, injector) => {
return (...args) => {
if (taskDone) {
setTimeout(taskDone, 0);
}
return runInInjectionContext(injector, () => run(() => it.apply(this, args)));
};
};
const ɵzoneWrap = (it, blockUntilFirst, logLevel) => {
logLevel ||= blockUntilFirst ? LogLevel.WARN : LogLevel.VERBOSE;
// function() is needed for the arguments object
return function () {
let taskDone;
const _arguments = arguments;
let schedulers;
let pendingTasks;
let injector;
try {
schedulers = inject(ɵAngularFireSchedulers);
pendingTasks = inject(PendingTasks);
injector = inject(EnvironmentInjector);
}
catch (e) {
warnOutsideInjectionContext(it, logLevel);
return it.apply(this, _arguments);
}
// if this is a callback function, e.g, onSnapshot, we should create a pending task and complete it
// only once one of the callback functions is tripped.
for (let i = 0; i < arguments.length; i++) {
if (typeof _arguments[i] === 'function') {
if (blockUntilFirst) {
taskDone ||= run(() => pendingTasks.add());
}
// TODO create a microtask to track callback functions
_arguments[i] = zoneWrapFn(_arguments[i], taskDone, injector);
}
}
const ret = runOutsideAngular(() => it.apply(this, _arguments));
if (!blockUntilFirst) {
if (ret instanceof Observable) {
return ret.pipe(subscribeOn(schedulers.outsideAngular), observeOn(schedulers.insideAngular));
}
else {
return run(() => ret);
}
}
if (ret instanceof Observable) {
return ret.pipe(subscribeOn(schedulers.outsideAngular), observeOn(schedulers.insideAngular), pendingUntilEvent(injector));
}
else if (ret instanceof Promise) {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
return run(() => new Promise((resolve, reject) => {
pendingTasks.run(() => ret).then((it) => runInInjectionContext(injector, () => run(() => resolve(it))), (reason) => runInInjectionContext(injector, () => run(() => reject(reason))));
}));
}
else if (typeof ret === 'function' && taskDone) {
// Handle unsubscribe
// function() is needed for the arguments object
return function () {
setTimeout(taskDone, 0);
return ret.apply(this, arguments);
};
}
else {
// TODO how do we handle storage uploads in Zone? and other stuff with cancel() etc?
return run(() => ret);
}
};
};
/**
* Generated bundle index. Do not edit.
*/
export { LogLevel, VERSION, setLogLevel, ɵAngularFireSchedulers, ɵZoneScheduler, ɵgetAllInstancesOf, ɵgetDefaultInstanceOf, ɵisSupportedError, ɵzoneWrap };
//# sourceMappingURL=angular-fire.mjs.map