1 | import * as i0 from '@angular/core';
|
2 | import { InjectionToken, PLATFORM_ID, Injectable, Inject, Optional, NgModule } from '@angular/core';
|
3 | import { pipe, of, EMPTY, concat, Observable } from 'rxjs';
|
4 | import { map, distinctUntilChanged, filter, withLatestFrom, scan, observeOn, switchMap, startWith, shareReplay, groupBy, mergeMap, debounceTime } from 'rxjs/operators';
|
5 | import * as i1 from '@angular/fire';
|
6 | import { keepUnstableUntilFirst, VERSION } from '@angular/fire';
|
7 | import { ɵfirebaseAppFactory, ɵcacheInstance, ɵlazySDKProxy, FIREBASE_OPTIONS, FIREBASE_APP_NAME, ɵapplyMixins } from '@angular/fire/compat';
|
8 | import { isSupported } from 'firebase/remote-config';
|
9 | import firebase from 'firebase/compat/app';
|
10 |
|
11 |
|
12 |
|
13 | const proxyPolyfillCompat = {
|
14 | app: null,
|
15 | settings: null,
|
16 | defaultConfig: null,
|
17 | fetchTimeMillis: null,
|
18 | lastFetchStatus: null,
|
19 | activate: null,
|
20 | ensureInitialized: null,
|
21 | fetch: null,
|
22 | fetchAndActivate: null,
|
23 | getAll: null,
|
24 | getBoolean: null,
|
25 | getNumber: null,
|
26 | getString: null,
|
27 | getValue: null,
|
28 | setLogLevel: null,
|
29 | };
|
30 |
|
31 | const SETTINGS = new InjectionToken('angularfire2.remoteConfig.settings');
|
32 | const DEFAULTS = new InjectionToken('angularfire2.remoteConfig.defaultConfig');
|
33 | const AS_TO_FN = { strings: 'asString', numbers: 'asNumber', booleans: 'asBoolean' };
|
34 | const STATIC_VALUES = { numbers: 0, booleans: false, strings: undefined };
|
35 |
|
36 | const proxyAll = (observable, as) => new Proxy(observable.pipe(mapToObject(as)), {
|
37 | get: (self, name) => self[name] || observable.pipe(map(all => all.find(p => p.key === name)), map(param => param ? param[AS_TO_FN[as]]() : STATIC_VALUES[as]), distinctUntilChanged())
|
38 | });
|
39 | // TODO export as implements Partial<...> so minor doesn't break us
|
40 | class Value {
|
41 |
|
42 | constructor(_source, _value) {
|
43 | this._source = _source;
|
44 | this._value = _value;
|
45 | }
|
46 | asBoolean() {
|
47 | return ['1', 'true', 't', 'y', 'yes', 'on'].indexOf(this._value.toLowerCase()) > -1;
|
48 | }
|
49 | asString() {
|
50 | return this._value;
|
51 | }
|
52 | asNumber() {
|
53 | return Number(this._value) || 0;
|
54 | }
|
55 | getSource() {
|
56 | return this._source;
|
57 | }
|
58 | }
|
59 |
|
60 | class Parameter extends Value {
|
61 | constructor(key, fetchTimeMillis, source, value) {
|
62 | super(source, value);
|
63 | this.key = key;
|
64 | this.fetchTimeMillis = fetchTimeMillis;
|
65 | }
|
66 | }
|
67 |
|
68 | const filterTest = (fn) => filter(it => Array.isArray(it) ? it.some(fn) : fn(it));
|
69 |
|
70 |
|
71 | const filterRemote = () => filterTest(p => p.getSource() === 'remote');
|
72 |
|
73 | const filterFresh = (howRecentInMillis) => filterTest(p => p.fetchTimeMillis + howRecentInMillis >= new Date().getTime());
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | const scanToParametersArray = (remoteConfig) => pipe(withLatestFrom(remoteConfig), scan((existing, [all, rc]) => {
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | const allKeys = [...existing.map(p => p.key), ...Object.keys(all)].filter((v, i, a) => a.indexOf(v) === i);
|
84 | return allKeys.map(key => {
|
85 | const updatedValue = all[key];
|
86 | return updatedValue ? new Parameter(key, rc ? rc.fetchTimeMillis : -1, updatedValue.getSource(), updatedValue.asString())
|
87 | : existing.find(p => p.key === key);
|
88 | });
|
89 | }, []));
|
90 | class AngularFireRemoteConfig {
|
91 | constructor(options, name, settings, defaultConfig, zone, schedulers,
|
92 | // tslint:disable-next-line:ban-types
|
93 | platformId) {
|
94 | this.zone = zone;
|
95 | const remoteConfig$ = of(undefined).pipe(observeOn(schedulers.outsideAngular), switchMap(() => isSupported()), switchMap(isSupported => isSupported ? import('firebase/compat/remote-config') : EMPTY), map(() => ɵfirebaseAppFactory(options, zone, name)), map(app => ɵcacheInstance(`${app.name}.remote-config`, 'AngularFireRemoteConfig', app.name, () => {
|
96 | const rc = app.remoteConfig();
|
97 | if (settings) {
|
98 | rc.settings = settings;
|
99 | }
|
100 | if (defaultConfig) {
|
101 | rc.defaultConfig = defaultConfig;
|
102 | }
|
103 | return rc;
|
104 | }, [settings, defaultConfig])), startWith(undefined), shareReplay({ bufferSize: 1, refCount: false }));
|
105 | const loadedRemoteConfig$ = remoteConfig$.pipe(filter(rc => !!rc));
|
106 | const default$ = of(Object.keys(defaultConfig || {}).reduce((c, k) => (Object.assign(Object.assign({}, c), { [k]: new Value('default', defaultConfig[k].toString()) })), {}));
|
107 |
|
108 |
|
109 | const filterOutDefaults = map(all => Object.keys(all)
|
110 | .filter(key => all[key].getSource() !== 'default')
|
111 | .reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: all[key] })), {}));
|
112 | const existing$ = loadedRemoteConfig$.pipe(switchMap(rc => rc.activate()
|
113 | .then(() => rc.ensureInitialized())
|
114 | .then(() => rc.getAll())), filterOutDefaults);
|
115 | const fresh$ = loadedRemoteConfig$.pipe(switchMap(rc => zone.runOutsideAngular(() => rc.fetchAndActivate()
|
116 | .then(() => rc.ensureInitialized())
|
117 | .then(() => rc.getAll()))), filterOutDefaults);
|
118 | this.parameters = concat(default$, existing$, fresh$).pipe(scanToParametersArray(remoteConfig$), keepUnstableUntilFirst, shareReplay({ bufferSize: 1, refCount: true }));
|
119 | this.changes = this.parameters.pipe(switchMap(params => of(...params)), groupBy(param => param.key), mergeMap(group => group.pipe(distinctUntilChanged())));
|
120 | this.strings = proxyAll(this.parameters, 'strings');
|
121 | this.booleans = proxyAll(this.parameters, 'booleans');
|
122 | this.numbers = proxyAll(this.parameters, 'numbers');
|
123 | return ɵlazySDKProxy(this, loadedRemoteConfig$, zone);
|
124 | }
|
125 | }
|
126 | AngularFireRemoteConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfig, deps: [{ token: FIREBASE_OPTIONS }, { token: FIREBASE_APP_NAME, optional: true }, { token: SETTINGS, optional: true }, { token: DEFAULTS, optional: true }, { token: i0.NgZone }, { token: i1.ɵAngularFireSchedulers }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
|
127 | AngularFireRemoteConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfig, providedIn: 'any' });
|
128 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfig, decorators: [{
|
129 | type: Injectable,
|
130 | args: [{
|
131 | providedIn: 'any'
|
132 | }]
|
133 | }], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
134 | type: Inject,
|
135 | args: [FIREBASE_OPTIONS]
|
136 | }] }, { type: undefined, decorators: [{
|
137 | type: Optional
|
138 | }, {
|
139 | type: Inject,
|
140 | args: [FIREBASE_APP_NAME]
|
141 | }] }, { type: undefined, decorators: [{
|
142 | type: Optional
|
143 | }, {
|
144 | type: Inject,
|
145 | args: [SETTINGS]
|
146 | }] }, { type: undefined, decorators: [{
|
147 | type: Optional
|
148 | }, {
|
149 | type: Inject,
|
150 | args: [DEFAULTS]
|
151 | }] }, { type: i0.NgZone }, { type: i1.ɵAngularFireSchedulers }, { type: Object, decorators: [{
|
152 | type: Inject,
|
153 | args: [PLATFORM_ID]
|
154 | }] }]; } });
|
155 | const budget = (interval) => (source) => new Observable(observer => {
|
156 | let timedOut = false;
|
157 |
|
158 | const timeout = setTimeout(() => {
|
159 | observer.complete();
|
160 | timedOut = true;
|
161 | }, interval);
|
162 | return source.subscribe({
|
163 | next(val) {
|
164 | if (!timedOut) {
|
165 | observer.next(val);
|
166 | }
|
167 | },
|
168 | error(err) {
|
169 | if (!timedOut) {
|
170 | clearTimeout(timeout);
|
171 | observer.error(err);
|
172 | }
|
173 | },
|
174 | complete() {
|
175 | if (!timedOut) {
|
176 | clearTimeout(timeout);
|
177 | observer.complete();
|
178 | }
|
179 | }
|
180 | });
|
181 | });
|
182 | const typedMethod = (it) => {
|
183 | switch (typeof it) {
|
184 | case 'string':
|
185 | return 'asString';
|
186 | case 'boolean':
|
187 | return 'asBoolean';
|
188 | case 'number':
|
189 | return 'asNumber';
|
190 | default:
|
191 | return 'asString';
|
192 | }
|
193 | };
|
194 | function scanToObject(to = 'strings') {
|
195 | return pipe(
|
196 |
|
197 | scan((c, p) => (Object.assign(Object.assign({}, c), { [p.key]: typeof to === 'object' ?
|
198 | p[typedMethod(to[p.key])]() :
|
199 | p[AS_TO_FN[to]]() })), typeof to === 'object' ?
|
200 | to :
|
201 | {}), debounceTime(1), budget(10), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)));
|
202 | }
|
203 | function mapToObject(to = 'strings') {
|
204 | return pipe(
|
205 |
|
206 | map((params) => params.reduce((c, p) => (Object.assign(Object.assign({}, c), { [p.key]: typeof to === 'object' ?
|
207 | p[typedMethod(to[p.key])]() :
|
208 | p[AS_TO_FN[to]]() })), typeof to === 'object' ?
|
209 | to :
|
210 | {})), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)));
|
211 | }
|
212 | ɵapplyMixins(AngularFireRemoteConfig, [proxyPolyfillCompat]);
|
213 |
|
214 | class AngularFireRemoteConfigModule {
|
215 | constructor() {
|
216 | firebase.registerVersion('angularfire', VERSION.full, 'rc-compat');
|
217 | }
|
218 | }
|
219 | AngularFireRemoteConfigModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfigModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
220 | AngularFireRemoteConfigModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfigModule });
|
221 | AngularFireRemoteConfigModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfigModule, providers: [AngularFireRemoteConfig] });
|
222 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.3", ngImport: i0, type: AngularFireRemoteConfigModule, decorators: [{
|
223 | type: NgModule,
|
224 | args: [{
|
225 | providers: [AngularFireRemoteConfig]
|
226 | }]
|
227 | }], ctorParameters: function () { return []; } });
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 | export { AngularFireRemoteConfig, AngularFireRemoteConfigModule, DEFAULTS, Parameter, SETTINGS, Value, budget, filterFresh, filterRemote, mapToObject, scanToObject };
|
234 |
|