feat(docs-infra): switch from GA to Firebase Analytics

- enable Firebase Performance

Fixes #6
This commit is contained in:
Michael Prentice
2020-08-16 01:52:18 -04:00
parent d42a09e9b6
commit faa17f8959
12 changed files with 388 additions and 217 deletions

View File

@ -93,6 +93,7 @@
"@angular/compiler": "10.0.2",
"@angular/core": "10.0.2",
"@angular/elements": "10.0.2",
"@angular/fire": "6.0.0",
"@angular/forms": "10.0.2",
"@angular/material": "10.0.1",
"@angular/platform-browser": "10.0.2",
@ -100,6 +101,9 @@
"@angular/router": "10.0.2",
"@angular/service-worker": "10.0.2",
"@webcomponents/custom-elements": "1.2.1",
"firebase": "~7.18.0",
"first-input-delay": "^0.1.3",
"proxy-polyfill": "^0.3.2",
"rxjs": "^6.5.3",
"tslib": "^1.10.0",
"zone.js": "~0.10.3"

View File

@ -13,7 +13,6 @@ import { NavigationNode, NavigationService } from 'app/navigation/navigation.ser
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
import { SearchService } from 'app/search/search.service';
import { Deployment } from 'app/shared/deployment.service';
import { GaService } from 'app/shared/ga.service';
import { LocationService } from 'app/shared/location.service';
import { Logger } from 'app/shared/logger.service';
import { ScrollService } from 'app/shared/scroll.service';
@ -1262,7 +1261,6 @@ function createTestingModule(initialUrl: string, mode: string = 'stable') {
providers: [
{ provide: APP_BASE_HREF, useValue: '/' },
{ provide: ElementsLoader, useClass: TestElementsLoader },
{ provide: GaService, useClass: TestGaService },
{ provide: HttpClient, useClass: TestHttpClient },
{ provide: LocationService, useFactory: () => mockLocationService },
{ provide: Logger, useClass: MockLogger },
@ -1284,10 +1282,6 @@ class TestElementsLoader {
.and.returnValue(Promise.resolve());
}
class TestGaService {
locationChanged = jasmine.createSpy('locationChanged');
}
class TestHttpClient {
static versionInfo = {

View File

@ -11,6 +11,9 @@ import { MatIconModule, MatIconRegistry } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
import { AngularFireModule } from '@angular/fire';
import { AngularFireAnalyticsModule, ScreenTrackingService, UserTrackingService } from '@angular/fire/analytics';
import { AngularFirePerformanceModule } from '@angular/fire/performance';
import { AppComponent } from 'app/app.component';
import { CustomIconRegistry, SVG_ICONS } from 'app/shared/custom-icon-registry';
@ -18,7 +21,6 @@ import { Deployment } from 'app/shared/deployment.service';
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
import { DtComponent } from 'app/layout/doc-viewer/dt.component';
import { ModeBannerComponent } from 'app/layout/mode-banner/mode-banner.component';
import { GaService } from 'app/shared/ga.service';
import { Logger } from 'app/shared/logger.service';
import { LocationService } from 'app/shared/location.service';
import { NavigationService } from 'app/navigation/navigation.service';
@ -143,6 +145,9 @@ export const svgIconProviders = [
MatToolbarModule,
SwUpdatesModule,
SharedModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireAnalyticsModule,
AngularFirePerformanceModule,
ServiceWorkerModule.register('/ngsw-worker.js', {enabled: environment.production}),
],
declarations: [
@ -161,7 +166,6 @@ export const svgIconProviders = [
Deployment,
DocumentService,
{ provide: ErrorHandler, useClass: ReportingErrorHandler },
GaService,
Logger,
Location,
{ provide: LocationStrategy, useClass: PathLocationStrategy },
@ -175,6 +179,8 @@ export const svgIconProviders = [
TocService,
{ provide: CurrentDateToken, useFactory: currentDateProvider },
{ provide: WindowToken, useFactory: windowProvider },
ScreenTrackingService,
UserTrackingService,
],
bootstrap: [ AppComponent ]
})

View File

@ -1,94 +0,0 @@
import { ReflectiveInjector } from '@angular/core';
import { GaService } from 'app/shared/ga.service';
import { WindowToken } from 'app/shared/window';
describe('GaService', () => {
let gaService: GaService;
let injector: ReflectiveInjector;
let gaSpy: jasmine.Spy;
let mockWindow: any;
beforeEach(() => {
gaSpy = jasmine.createSpy('ga');
mockWindow = { ga: gaSpy };
injector = ReflectiveInjector.resolveAndCreate([GaService, { provide: WindowToken, useFactory: () => mockWindow }]);
gaService = injector.get(GaService);
});
it('should initialize ga with "create" when constructed', () => {
const first = gaSpy.calls.first().args;
expect(first[0]).toBe('create');
});
describe('#locationChanged(url)', () => {
it('should send page to url w/ leading slash', () => {
gaService.locationChanged('testUrl');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
});
});
describe('#sendPage(url)', () => {
it('should set page to url w/ leading slash', () => {
gaService.sendPage('testUrl');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl');
});
it('should send "pageview" ', () => {
gaService.sendPage('testUrl');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
});
it('should not send twice with same URL, back-to-back', () => {
gaService.sendPage('testUrl');
gaSpy.calls.reset();
gaService.sendPage('testUrl');
expect(gaSpy).not.toHaveBeenCalled();
});
it('should send again even if only the hash changes', () => {
// Therefore it is up to caller NOT to call it when hash changes if this is unwanted.
// See LocationService and its specs
gaService.sendPage('testUrl#one');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl#one');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
gaSpy.calls.reset();
gaService.sendPage('testUrl#two');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl#two');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
});
it('should send same URL twice when other intervening URL', () => {
gaService.sendPage('testUrl');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
gaSpy.calls.reset();
gaService.sendPage('testUrl2');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl2');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
gaSpy.calls.reset();
gaService.sendPage('testUrl');
expect(gaSpy).toHaveBeenCalledWith('set', 'page', '/testUrl');
expect(gaSpy).toHaveBeenCalledWith('send', 'pageview');
});
});
describe('sendEvent', () => {
it('should send "event" with associated data', () => {
gaService.sendEvent('some source', 'some campaign', 'a label', 45);
expect(gaSpy).toHaveBeenCalledWith('send', 'event', 'some source', 'some campaign', 'a label', 45);
});
});
it('should support replacing the `window.ga` function', () => {
const gaSpy2 = jasmine.createSpy('new ga');
mockWindow.ga = gaSpy2;
gaSpy.calls.reset();
gaService.sendPage('testUrl');
expect(gaSpy).not.toHaveBeenCalled();
expect(gaSpy2).toHaveBeenCalledWith('set', 'page', '/testUrl');
expect(gaSpy2).toHaveBeenCalledWith('send', 'pageview');
});
});

View File

@ -1,42 +0,0 @@
import { Inject, Injectable } from '@angular/core';
import { environment } from '../../environments/environment';
import { WindowToken } from 'app/shared/window';
@Injectable()
/**
* Google Analytics Service - captures app behaviors and sends them to Google Analytics (GA).
* Presupposes that GA script has been loaded from a script on the host web page.
* Associates data with a GA "property" from the environment (`gaId`).
*/
export class GaService {
private previousUrl: string;
constructor(@Inject(WindowToken) private window: Window) {
this.ga('create', environment['gaId'] , 'auto');
}
locationChanged(url: string) {
this.sendPage(url);
}
sendPage(url: string) {
// Won't re-send if the url hasn't changed.
if (url === this.previousUrl) { return; }
this.previousUrl = url;
this.ga('set', 'page', '/' + url);
this.ga('send', 'pageview');
}
sendEvent(source: string, action: string, label?: string, value?: number) {
this.ga('send', 'event', source, action, label, value);
}
ga(...args: any[]) {
const gaFn = (this.window as any)['ga'];
if (gaFn) {
gaFn(...args);
}
}
}

View File

@ -3,7 +3,6 @@ import { Location, LocationStrategy, PlatformLocation } from '@angular/common';
import { MockLocationStrategy } from '@angular/common/testing';
import { Subject } from 'rxjs';
import { GaService } from 'app/shared/ga.service';
import { SwUpdatesService } from 'app/sw-updates/sw-updates.service';
import { LocationService } from './location.service';
import { ScrollService } from './scroll.service';
@ -19,7 +18,6 @@ describe('LocationService', () => {
injector = ReflectiveInjector.resolveAndCreate([
LocationService,
Location,
{ provide: GaService, useClass: TestGaService },
{ provide: LocationStrategy, useClass: MockLocationStrategy },
{ provide: PlatformLocation, useClass: MockPlatformLocation },
{ provide: SwUpdatesService, useClass: MockSwUpdatesService },
@ -571,55 +569,6 @@ describe('LocationService', () => {
});
});
});
describe('google analytics - GaService#locationChanged', () => {
let gaLocationChanged: jasmine.Spy;
beforeEach(() => {
const gaService = injector.get(GaService);
gaLocationChanged = gaService.locationChanged;
// execute currentPath observable so that gaLocationChanged is called
service.currentPath.subscribe();
});
it('should call locationChanged with initial URL', () => {
const initialUrl = location.path().replace(/^\/+/, ''); // strip leading slashes
expect(gaLocationChanged.calls.count()).toBe(1, 'gaService.locationChanged');
const args = gaLocationChanged.calls.first().args;
expect(args[0]).toBe(initialUrl);
});
it('should call locationChanged when `go` to a page', () => {
service.go('some-new-url');
expect(gaLocationChanged.calls.count()).toBe(2, 'gaService.locationChanged');
const args = gaLocationChanged.calls.argsFor(1);
expect(args[0]).toBe('some-new-url');
});
it('should call locationChanged with url stripped of hash or query', () => {
// Important to keep GA service from sending tracking event when the doc hasn't changed
// e.g., when the user navigates within the page via # fragments.
service.go('some-new-url#one');
service.go('some-new-url#two');
service.go('some-new-url/?foo="true"');
expect(gaLocationChanged.calls.count()).toBe(4, 'gaService.locationChanged called');
const args = gaLocationChanged.calls.allArgs();
expect(args[1]).toEqual(args[2], 'same url for hash calls');
expect(args[1]).toEqual(args[3], 'same url for query string call');
});
it('should call locationChanged when window history changes', () => {
location.simulatePopState('/next-url');
expect(gaLocationChanged.calls.count()).toBe(2, 'gaService.locationChanged');
const args = gaLocationChanged.calls.argsFor(1);
expect(args[0]).toBe('next-url');
});
});
});
/// Test Helpers ///
@ -635,7 +584,3 @@ class MockSwUpdatesService {
class MockScrollService {
removeStoredScrollInfo() { }
}
class TestGaService {
locationChanged = jasmine.createSpy('locationChanged');
}

View File

@ -2,9 +2,8 @@ import { Injectable } from '@angular/core';
import { Location, PlatformLocation } from '@angular/common';
import { ReplaySubject } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { map } from 'rxjs/operators';
import { GaService } from 'app/shared/ga.service';
import { SwUpdatesService } from 'app/sw-updates/sw-updates.service';
import { ScrollService } from './scroll.service';
@ -20,11 +19,9 @@ export class LocationService {
currentPath = this.currentUrl.pipe(
map(url => (url.match(/[^?#]*/) || [])[0]), // strip query and hash
tap(path => this.gaService.locationChanged(path)),
);
constructor(
private gaService: GaService,
private location: Location,
private scrollService: ScrollService,
private platformLocation: PlatformLocation,

View File

@ -1,6 +1,15 @@
// This is for the staging site, which is hosted at https://next.angular.io (and https://aio-staging.firebaseapp.org)
// This is for the staging site, which is hosted at https://angular-hispano-docs-staging.web.app/
export const environment = {
gaId: 'UA-8594346-15', // Production id (since it is linked from the main site)
firebase: {
apiKey: 'AIzaSyB6nIQPdT0LtGs7SZgWBrHf77cO-JsgDaE',
authDomain: 'angular-hispano-staging.firebaseapp.com',
databaseURL: 'https://angular-hispano-staging.firebaseio.com',
projectId: 'angular-hispano-staging',
storageBucket: 'angular-hispano-staging.appspot.com',
messagingSenderId: '589769577276',
appId: '1:589769577276:web:6e86185a9a0877586a0439',
measurementId: 'G-EZYJEBFTV7'
},
production: true,
mode: 'next'
};

View File

@ -1,6 +1,15 @@
// This is for the production site, which is hosted at https://angular.io
// This is for the production site, which is hosted at https://docs.angular.lat/
export const environment = {
gaId: 'UA-8594346-15', // Production id
firebase: {
apiKey: 'AIzaSyD2ofxXTZHHcsmaAt5H9Zd17vj2ne57mIQ',
authDomain: 'angular-latino.firebaseapp.com',
databaseURL: 'https://angular-latino.firebaseio.com',
projectId: 'angular-latino',
storageBucket: 'angular-latino.appspot.com',
messagingSenderId: '1050547922973',
appId: '1:1050547922973:web:0eb42eb1f83938c1317ef4',
measurementId: 'G-8EYEC7KL0R'
},
production: true,
mode: 'stable'
};

View File

@ -5,7 +5,16 @@
export const environment = {
gaId: 'UA-8594346-26', // Development id
firebase: {
apiKey: 'AIzaSyB6nIQPdT0LtGs7SZgWBrHf77cO-JsgDaE',
authDomain: 'angular-hispano-staging.firebaseapp.com',
databaseURL: 'https://angular-hispano-staging.firebaseio.com',
projectId: 'angular-hispano-staging',
storageBucket: 'angular-hispano-staging.appspot.com',
messagingSenderId: '589769577276',
appId: '1:589769577276:web:6e86185a9a0877586a0439',
measurementId: 'G-EZYJEBFTV7'
},
production: false,
mode: 'stable'
};

View File

@ -71,3 +71,7 @@ import '@webcomponents/custom-elements';
// - Samsung browser 5.0-8.1 (~0.43% global usage)
// - Opera 41-47 (~0.02% global usage)
import '@webcomponents/custom-elements/src/native-shim';
// Polyfill for browser performance API for tracking First Input Delay
import 'first-input-delay';
// Proxy polyfill is required to support IE11 with Angular Fire
import 'proxy-polyfill/proxy.min';

View File

@ -223,6 +223,11 @@
dependencies:
tslib "^2.0.0"
"@angular/fire@6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@angular/fire/-/fire-6.0.0.tgz#c1dbae9e78ed74af951fb7222108c444300a4d15"
integrity sha512-zWhaJaZPtfJKiNSb1I3WqqvopW0fN3S61w4PjPdsm5WME+9M9alP0zpRVclpbCU26LpBSLhrRrSLyn3ROlAOIw==
"@angular/forms@10.0.2":
version "10.0.2"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-10.0.2.tgz#fa443f73156640664a9e018aaeb42f85d6d20fcb"
@ -1344,6 +1349,230 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@firebase/analytics-types@0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.3.1.tgz#3c5f5d71129c88295e17e914e34b391ffda1723c"
integrity sha512-63vVJ5NIBh/JF8l9LuPrQYSzFimk7zYHySQB4Dk9rVdJ8kV/vGQoVTvRu1UW05sEc2Ug5PqtEChtTHU+9hvPcA==
"@firebase/analytics@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.4.2.tgz#b4869df9efc0334ae2fe3eba19b65b845a190012"
integrity sha512-WCoeUAO3lP6ikHJ3/XYptV90fpTidzTS9VpAfiVQK8gl9w1zvvKSavY9U3+EVG3frOPCFdE5DBO4MYrUw4gaqw==
dependencies:
"@firebase/analytics-types" "0.3.1"
"@firebase/component" "0.1.18"
"@firebase/installations" "0.4.16"
"@firebase/logger" "0.2.6"
"@firebase/util" "0.3.1"
tslib "^1.11.1"
"@firebase/app-types@0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.1.tgz#dcbd23030a71c0c74fc95d4a3f75ba81653850e9"
integrity sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg==
"@firebase/app@0.6.10":
version "0.6.10"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.10.tgz#520798f76906897284742b6eeb43257ec73f67a5"
integrity sha512-USg/AbgqBERhY0LayrKmmp7pka08WPa7OlFI46kaNW1pA2mUNf/ifTaxhCr2hGg/eWI0zPhpbEvtGQhSJ/QqWg==
dependencies:
"@firebase/app-types" "0.6.1"
"@firebase/component" "0.1.18"
"@firebase/logger" "0.2.6"
"@firebase/util" "0.3.1"
dom-storage "2.1.0"
tslib "^1.11.1"
xmlhttprequest "1.8.0"
"@firebase/auth-interop-types@0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.5.tgz#9fc9bd7c879f16b8d1bb08373a0f48c3a8b74557"
integrity sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==
"@firebase/auth-types@0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.1.tgz#7815e71c9c6f072034415524b29ca8f1d1770660"
integrity sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw==
"@firebase/auth@0.14.9":
version "0.14.9"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.14.9.tgz#481db24d5bd6eded8ac2e5aea6edb9307040229c"
integrity sha512-PxYa2r5qUEdheXTvqROFrMstK8W4uPiP7NVfp+2Bec+AjY5PxZapCx/YFDLkU0D7YBI82H74PtZrzdJZw7TJ4w==
dependencies:
"@firebase/auth-types" "0.10.1"
"@firebase/component@0.1.18":
version "0.1.18"
resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.1.18.tgz#28e69e54b79953376283464cb0543bde4c104140"
integrity sha512-c8gd1k/e0sbBTR0xkLIYUN8nVkA0zWxcXGIvdfYtGEsNw6n7kh5HkcxKXOPB8S7bcPpqZkGgBIfvd94IyG2gaQ==
dependencies:
"@firebase/util" "0.3.1"
tslib "^1.11.1"
"@firebase/database-types@0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.5.2.tgz#23bec8477f84f519727f165c687761e29958b63c"
integrity sha512-ap2WQOS3LKmGuVFKUghFft7RxXTyZTDr0Xd8y2aqmWsbJVjgozi0huL/EUMgTjGFrATAjcf2A7aNs8AKKZ2a8g==
dependencies:
"@firebase/app-types" "0.6.1"
"@firebase/database@0.6.11":
version "0.6.11"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.6.11.tgz#74a09d5f4769eb97c00bc2f7621f54efbccea6f2"
integrity sha512-QOHhB7+CdjVhEXG9CyX0roA9ARJcEuwbozz0Bix+ULuZqjQ58KUFHMH1apW6EEiUP22d/mYD7dNXsUGshjL9PA==
dependencies:
"@firebase/auth-interop-types" "0.1.5"
"@firebase/component" "0.1.18"
"@firebase/database-types" "0.5.2"
"@firebase/logger" "0.2.6"
"@firebase/util" "0.3.1"
faye-websocket "0.11.3"
tslib "^1.11.1"
"@firebase/firestore-types@1.12.0":
version "1.12.0"
resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-1.12.0.tgz#511e572e946b07f5a603c90e078f0cd714923fac"
integrity sha512-OqNxVb63wPZdUc7YnpacAW1WNIMSKERSewCRi+unCQ0YI0KNfrDSypyGCyel+S3GdOtKMk9KnvDknaGbnaFX4g==
"@firebase/firestore@1.16.4":
version "1.16.4"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.16.4.tgz#29cb121f5686cab6e310bf16a1094f06f3678385"
integrity sha512-Ur+I8a8RkkbbJRsebkYAUwKFkbh9FemDxTFD/2Vp01pAPM8S3MoIcVegAfTvnPlG/ObBq5O7wI4CRA6b/G/Iyg==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/firestore-types" "1.12.0"
"@firebase/logger" "0.2.6"
"@firebase/util" "0.3.1"
"@firebase/webchannel-wrapper" "0.3.0"
"@grpc/grpc-js" "^1.0.0"
"@grpc/proto-loader" "^0.5.0"
node-fetch "2.6.0"
tslib "^1.11.1"
"@firebase/functions-types@0.3.17":
version "0.3.17"
resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.3.17.tgz#348bf5528b238eeeeeae1d52e8ca547b21d33a94"
integrity sha512-DGR4i3VI55KnYk4IxrIw7+VG7Q3gA65azHnZxo98Il8IvYLr2UTBlSh72dTLlDf25NW51HqvJgYJDKvSaAeyHQ==
"@firebase/functions@0.4.50":
version "0.4.50"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.4.50.tgz#02ae1a2a42de9c4c73f13c00043dbba6546248a0"
integrity sha512-eBsNrUm/Jfc/xsQXmxQRSkEg6pwHlMd2hice8N90/EeqgwqS/SCvC+O9cJITLlXroAghb9jWDWRvAkDU/TOhpw==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/functions-types" "0.3.17"
"@firebase/messaging-types" "0.5.0"
isomorphic-fetch "2.2.1"
tslib "^1.11.1"
"@firebase/installations-types@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.3.4.tgz#589a941d713f4f64bf9f4feb7f463505bab1afa2"
integrity sha512-RfePJFovmdIXb6rYwtngyxuEcWnOrzdZd9m7xAW0gRxDIjBT20n3BOhjpmgRWXo/DAxRmS7bRjWAyTHY9cqN7Q==
"@firebase/installations@0.4.16":
version "0.4.16"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.16.tgz#5c3f2e542308f06439aeddb0f456f3f36ae808eb"
integrity sha512-gqv3IrBUmPWKpH8wLJ0fZcAH1NEXwQhqjqnK3cQXRcIkEARP430cmIAaj7CcPdgdemHX9HqwJG+So/yBHIYXPA==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/installations-types" "0.3.4"
"@firebase/util" "0.3.1"
idb "3.0.2"
tslib "^1.11.1"
"@firebase/logger@0.2.6":
version "0.2.6"
resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.2.6.tgz#3aa2ca4fe10327cabf7808bd3994e88db26d7989"
integrity sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==
"@firebase/messaging-types@0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@firebase/messaging-types/-/messaging-types-0.5.0.tgz#c5d0ef309ced1758fda93ef3ac70a786de2e73c4"
integrity sha512-QaaBswrU6umJYb/ZYvjR5JDSslCGOH6D9P136PhabFAHLTR4TWjsaACvbBXuvwrfCXu10DtcjMxqfhdNIB1Xfg==
"@firebase/messaging@0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.7.0.tgz#6932f6bfcc04148891751aecce426cafe76e0a06"
integrity sha512-PTD5pQw9QremOjiWWZYOkzcX6OKByMvlG+NQXdTnyL3kLbE01Bdp9iWhkH6ipNpHYMiwcK1RZD4TLkYVBviBsw==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/installations" "0.4.16"
"@firebase/messaging-types" "0.5.0"
"@firebase/util" "0.3.1"
idb "3.0.2"
tslib "^1.11.1"
"@firebase/performance-types@0.0.13":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.13.tgz#58ce5453f57e34b18186f74ef11550dfc558ede6"
integrity sha512-6fZfIGjQpwo9S5OzMpPyqgYAUZcFzZxHFqOyNtorDIgNXq33nlldTL/vtaUZA8iT9TT5cJlCrF/jthKU7X21EA==
"@firebase/performance@0.3.11":
version "0.3.11"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.3.11.tgz#833c8abe5f5554f25545c8d28b487d8ac3ff3f95"
integrity sha512-L00vBUa2zzoSSOq3StTN43fPxtJ+myF+t+2kP5bQGHN5WOmf22lIsuEjAy1FAscDjVjhL1k5rKMY332ZwEfblg==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/installations" "0.4.16"
"@firebase/logger" "0.2.6"
"@firebase/performance-types" "0.0.13"
"@firebase/util" "0.3.1"
tslib "^1.11.1"
"@firebase/polyfill@0.3.36":
version "0.3.36"
resolved "https://registry.yarnpkg.com/@firebase/polyfill/-/polyfill-0.3.36.tgz#c057cce6748170f36966b555749472b25efdb145"
integrity sha512-zMM9oSJgY6cT2jx3Ce9LYqb0eIpDE52meIzd/oe/y70F+v9u1LDqk5kUF5mf16zovGBWMNFmgzlsh6Wj0OsFtg==
dependencies:
core-js "3.6.5"
promise-polyfill "8.1.3"
whatwg-fetch "2.0.4"
"@firebase/remote-config-types@0.1.9":
version "0.1.9"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.1.9.tgz#fe6bbe4d08f3b6e92fce30e4b7a9f4d6a96d6965"
integrity sha512-G96qnF3RYGbZsTRut7NBX0sxyczxt1uyCgXQuH/eAfUCngxjEGcZQnBdy6mvSdqdJh5mC31rWPO4v9/s7HwtzA==
"@firebase/remote-config@0.1.27":
version "0.1.27"
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.27.tgz#b581cb7d870e7d32bac5967acbbb5d7ec593a2f3"
integrity sha512-BGjmQomRKNf+yGJ/3/5Kw6zNLM5jY9oTVjLmYsQXf6U+HMgz6J2H6EVGc1bZW7YSsvak8f6DomxegQtvfvwaMw==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/installations" "0.4.16"
"@firebase/logger" "0.2.6"
"@firebase/remote-config-types" "0.1.9"
"@firebase/util" "0.3.1"
tslib "^1.11.1"
"@firebase/storage-types@0.3.13":
version "0.3.13"
resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.3.13.tgz#cd43e939a2ab5742e109eb639a313673a48b5458"
integrity sha512-pL7b8d5kMNCCL0w9hF7pr16POyKkb3imOW7w0qYrhBnbyJTdVxMWZhb0HxCFyQWC0w3EiIFFmxoz8NTFZDEFog==
"@firebase/storage@0.3.42":
version "0.3.42"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.3.42.tgz#e2fe1aa54c004852a848b50f34c2f351e6e517e5"
integrity sha512-FqHDWZPhATQeOFBQUZPsQO7xhnGBxprYVDb9eIjCnh1yRl6WAv/OQGHOF+JU5+H+YkjsKTtr/5VjyDl3Y0UHxw==
dependencies:
"@firebase/component" "0.1.18"
"@firebase/storage-types" "0.3.13"
"@firebase/util" "0.3.1"
tslib "^1.11.1"
"@firebase/util@0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.3.1.tgz#8c95152a00121bd31fb7c1fc6520ca208976e384"
integrity sha512-zjVd9rfL08dRRdZILFn1RZTHb1euCcnD9N/9P56gdBcm2bvT5XsCC4G6t5toQBpE/H/jYe5h6MZMqfLu3EQLXw==
dependencies:
tslib "^1.11.1"
"@firebase/webchannel-wrapper@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.3.0.tgz#d1689566b94c25423d1fb2cb031c5c2ea4c9f939"
integrity sha512-VniCGPIgSGNEgOkh5phb3iKmSGIzcwrccy3IomMFRWPCMiCk2y98UQNJEoDs1yIHtZMstVjYWKYxnunIGzC5UQ==
"@google-cloud/paginator@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-2.0.3.tgz#c7987ad05d1c3ebcef554381be80e9e8da4e4882"
@ -1395,6 +1624,21 @@
dependencies:
semver "^6.2.0"
"@grpc/grpc-js@^1.0.0":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.1.3.tgz#0b91b166d744b6a43b00430dceff0f0ff88c98d5"
integrity sha512-HtOsk2YUofBcm1GkPqGzb6pwHhv+74eC2CUO229USIDKRtg30ycbZmqC+HdNtY3nHqoc9IgcRlntFgopyQoYCA==
dependencies:
semver "^6.2.0"
"@grpc/proto-loader@^0.5.0":
version "0.5.5"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.5.tgz#6725e7a1827bdf8e92e29fbf4e9ef0203c0906a9"
integrity sha512-WwN9jVNdHRQoOBo9FDH7qU+mgfjPc8GygPYms3M+y3fbQLfnCe/Kv/E01t7JRgnrsOHH8euvSbed3mIalXhwqQ==
dependencies:
lodash.camelcase "^4.3.0"
protobufjs "^6.8.6"
"@grpc/proto-loader@^0.5.1":
version "0.5.3"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.3.tgz#a233070720bf7560c4d70e29e7950c72549a132c"
@ -3889,6 +4133,11 @@ core-js@3.6.4:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647"
integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==
core-js@3.6.5:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -4620,6 +4869,11 @@ dom-serializer@0:
domelementtype "^2.0.1"
entities "^2.0.0"
dom-storage@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/dom-storage/-/dom-storage-2.1.0.tgz#00fb868bc9201357ea243c7bcfd3304c1e34ea39"
integrity sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@ -5411,6 +5665,13 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
faye-websocket@0.11.3, faye-websocket@~0.11.1:
version "0.11.3"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==
dependencies:
websocket-driver ">=0.5.1"
faye-websocket@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
@ -5418,13 +5679,6 @@ faye-websocket@^0.10.0:
dependencies:
websocket-driver ">=0.5.1"
faye-websocket@~0.11.1:
version "0.11.3"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==
dependencies:
websocket-driver ">=0.5.1"
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
@ -5632,6 +5886,31 @@ firebase-tools@^7.11.0:
uuid "^3.0.0"
winston "^1.0.1"
firebase@~7.18.0:
version "7.18.0"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.18.0.tgz#00e3967f5bc608f3e12c1a5f0192f559de87943e"
integrity sha512-RGq0rWX25EDsM21TjRe1FbnygJwHXL7yN4P0Zh2Z7dWrBcfJ8tQpDxgwMDtiJTuo9UYExK3py4wjgpGJBau6wg==
dependencies:
"@firebase/analytics" "0.4.2"
"@firebase/app" "0.6.10"
"@firebase/app-types" "0.6.1"
"@firebase/auth" "0.14.9"
"@firebase/database" "0.6.11"
"@firebase/firestore" "1.16.4"
"@firebase/functions" "0.4.50"
"@firebase/installations" "0.4.16"
"@firebase/messaging" "0.7.0"
"@firebase/performance" "0.3.11"
"@firebase/polyfill" "0.3.36"
"@firebase/remote-config" "0.1.27"
"@firebase/storage" "0.3.42"
"@firebase/util" "0.3.1"
first-input-delay@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/first-input-delay/-/first-input-delay-0.1.3.tgz#5506fb95a9537ba9706096b9c159bfd3f38f6f62"
integrity sha512-hZ1mI+BWYIBr8jlp2bDPnRvnmSICBxpZRwdc0nhiQn2uyMxSKZEBbkO8V0/s26AMeX8p/AD4g09+liRrhXvKKQ==
flat-arguments@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flat-arguments/-/flat-arguments-1.0.2.tgz#9baa780adf0501f282d726c9c6a038dba44ea76f"
@ -6645,6 +6924,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1:
dependencies:
postcss "^7.0.14"
idb@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/idb/-/idb-3.0.2.tgz#c8e9122d5ddd40f13b60ae665e4862f8b13fa384"
integrity sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw==
ieee754@^1.1.4:
version "1.1.13"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
@ -7296,7 +7580,7 @@ is-stream-ended@^0.1.4:
resolved "https://registry.yarnpkg.com/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda"
integrity sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==
is-stream@^1.0.0, is-stream@^1.1.0:
is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@ -7420,6 +7704,14 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
isomorphic-fetch@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isstream@0.1.x, isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@ -9071,11 +9363,19 @@ node-fetch-npm@^2.0.2:
json-parse-better-errors "^1.0.0"
safe-buffer "^5.1.1"
node-fetch@^2.3.0, node-fetch@^2.6.0:
node-fetch@2.6.0, node-fetch@^2.3.0, node-fetch@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
node-forge@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
@ -10486,6 +10786,11 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
promise-polyfill@8.1.3:
version "8.1.3"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116"
integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==
promise-retry@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d"
@ -10575,6 +10880,11 @@ proxy-from-env@^1.0.0:
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
proxy-polyfill@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.3.2.tgz#55f190054a3044e105d9de16e23719e1e9be0898"
integrity sha512-ENKSXOMCewnQTOyqrQXxEjIhzT6dy572mtehiItbDoIUF5Sv5UkmRUc8kowg2MFvr232Uo8rwRpNg3V5kgTKbA==
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -13027,6 +13337,11 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
tslib@^1.11.1:
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
tslint@~6.1.0:
version "6.1.2"
resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.2.tgz#2433c248512cc5a7b2ab88ad44a6b1b34c6911cf"
@ -13881,6 +14196,16 @@ whatwg-encoding@^1.0.1:
dependencies:
iconv-lite "0.4.24"
whatwg-fetch@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==
whatwg-fetch@>=0.10.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.0.tgz#e11de14f4878f773fbebcde8871b2c0699af8b30"
integrity sha512-rsum2ulz2iuZH08mJkT0Yi6JnKhwdw4oeyMjokgxd+mmqYSd9cPpOQf01TIWgjxG/U4+QR+AwKq6lSbXVxkyoQ==
whatwg-mimetype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
@ -14132,6 +14457,11 @@ xmlhttprequest-ssl@~1.5.4:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
xmlhttprequest@1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=
xregexp@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"