@@ -41,6 +41,8 @@ export default class RemoteConfig<T = Record<string, string>> extends EventEmitt
4141 private readonly options : RemoteConfigOptions < T >
4242 private readonly storage : StorageInterface < RemoteConfigStore < T > >
4343 private readonly request : AxiosInstance
44+ private refreshTimer : NodeJS . Timer
45+ private semaphoreFetch : Promise < void >
4446
4547 constructor ( app : FirebaseApp , options : RemoteConfigOptions < T > = { } ) {
4648 super ( )
@@ -69,12 +71,9 @@ export default class RemoteConfig<T = Record<string, string>> extends EventEmitt
6971 set : ( key , value ) => this . app . storage . set ( storagePrefix + key , value ) ,
7072 } as StorageInterface < RemoteConfigStore < T > >
7173
72- this . on ( 'fetch' , ( ) => console . log ( 'Constructor - fetch' ) )
73- this . on ( 'activate' , ( ) => console . log ( 'Constructor - activate' ) )
74- }
74+ this . fetchAndActivate ( )
7575
76- get defaultConfig ( ) {
77- return this . options . defaultConfig
76+ this . refreshTimer = setInterval ( this . fetchAndActivate , this . options . cacheMaxAge + 1000 )
7877 }
7978
8079 get isCacheValid ( ) {
@@ -83,68 +82,75 @@ export default class RemoteConfig<T = Record<string, string>> extends EventEmitt
8382 return this . storage . get ( 'config' ) && cacheAge < this . options . cacheMaxAge
8483 }
8584
86- getActiveConfig ( ) : T {
85+ get defaultConfig ( ) {
86+ return this . options . defaultConfig
87+ }
88+
89+ private get activeConfig ( ) {
8790 return this . storage . get ( 'config' )
8891 }
8992
90- getDefaultConfig ( ) : T {
91- return this . options . defaultConfig
93+ set defaultConfig ( defaultConfig : RemoteConfigOptions < T > [ 'defaultConfig' ] ) {
94+ this . options . defaultConfig = defaultConfig
9295 }
9396
9497 getValue < K extends keyof T > ( key : K ) : Value {
95- const config = this . getActiveConfig ( )
98+ const config = this . activeConfig
9699
100+ // Has remote version
97101 if ( config && config [ key ] !== undefined ) {
98- return new Value ( 'remote' , String ( config [ key ] ) )
102+ return new Value ( 'remote' , config [ key ] as string )
99103 }
100104
101- const defaultConfig = this . getDefaultConfig ( )
105+ const defaultConfig = this . defaultConfig
102106
107+ // Has default version
103108 if ( defaultConfig && defaultConfig [ key ] !== undefined ) {
104- return new Value ( 'default' , String ( defaultConfig [ key ] ) )
109+ return new Value ( 'default' , defaultConfig [ key ] as string )
105110 }
106111
112+ // Not found, return static
107113 return new Value ( 'static' )
108114 }
109115
110- getAll ( ) {
116+ getAll ( ) : Record < string , Value > {
111117 const config = {
112- ...( this . getActiveConfig ( ) || { } ) ,
113- ...( this . getDefaultConfig ( ) || { } )
118+ ...( this . activeConfig || { } ) ,
119+ ...( this . defaultConfig || { } )
114120 }
115121
116122 return Object . keys ( config ) . reduce ( ( result , key ) => {
117123 result [ key ] = this . getValue ( key as keyof T )
124+
118125 return result
119126 } , { } )
120127 }
121128
122- getBoolean < K extends keyof T > ( key : K ) : boolean {
123- return this . getValue ( key ) . asBoolean ( )
124- }
125-
126- getNumber < K extends keyof T > ( key : K ) : number {
127- return this . getValue ( key ) . asNumber ( )
128- }
129+ getAllConverted ( ) : T {
130+ const config = this . getAll ( )
129131
130- getString < K extends keyof T > ( key : K ) : string {
131- return this . getValue ( key ) . asString ( )
132- }
132+ Object . keys ( config ) . forEach ( ( key ) => {
133+ config [ key ] = config [ key ] . asConverted ( )
134+ } )
133135
134- getJSON < K extends keyof T , V = Record < string , unknown > > ( key : K ) : V {
135- return this . getValue ( key ) . asJSON < V > ( )
136+ return config as T
136137 }
137138
138139 async fetchAndActivate ( ignoreCache = false ) : Promise < void > {
139140 const etag = this . storage . get ( 'etag' )
140141
141-
142142 if ( ! ignoreCache && this . isCacheValid ) {
143143 this . emit ( 'fetch' )
144- console . log ( 'config cache is valid' )
145144 return Promise . resolve ( )
146145 }
147146
147+ if ( this . semaphoreFetch ) {
148+ return this . semaphoreFetch ;
149+ }
150+
151+ let resolveSemaphore = null
152+ this . semaphoreFetch = new Promise ( ( res ) => { resolveSemaphore = res } )
153+
148154 const installation = await this . installations . getInstallation ( )
149155
150156 const response = await this . request . post ( `:fetch` , {
@@ -212,5 +218,9 @@ export default class RemoteConfig<T = Record<string, string>> extends EventEmitt
212218 throw new Error ( `Failed to fetch RemoteConfig status: ${ status } ` )
213219
214220 }
221+
222+ this . semaphoreFetch = null
223+
224+ resolveSemaphore ?.( )
215225 }
216226}
0 commit comments