@@ -104,27 +104,32 @@ type BulkEvent =
104104 **/
105105export class BucketClient {
106106 private _config : {
107- logger ?: Logger ;
108107 apiBaseUrl : string ;
109- httpClient : HttpClient ;
110108 refetchInterval : number ;
111109 staleWarningInterval : number ;
112110 headers : Record < string , string > ;
113111 fallbackFeatures ?: Record < keyof TypedFeatures , RawFeature > ;
114- featuresCache : Cache < FeaturesAPIResponse > ;
115- batchBuffer : BatchBuffer < BulkEvent > ;
116112 featureOverrides : FeatureOverridesFn ;
117- rateLimiter : ReturnType < typeof newRateLimiter > ;
118113 offline : boolean ;
119114 fetchFeatures : boolean ;
120115 configFile ?: string ;
121116 } ;
117+ httpClient : HttpClient ;
118+
119+ private featuresCache : Cache < FeaturesAPIResponse > ;
120+ private batchBuffer : BatchBuffer < BulkEvent > ;
121+ private rateLimiter : ReturnType < typeof newRateLimiter > ;
122+
123+ /**
124+ * Gets the logger associated with the client.
125+ */
126+ public readonly logger : Logger ;
122127
123128 private _initialize = once ( async ( ) => {
124129 if ( ! this . _config . offline && this . _config . fetchFeatures ) {
125- await this . _config . featuresCache . refresh ( ) ;
130+ await this . featuresCache . refresh ( ) ;
126131 }
127- this . _config . logger ? .info ( "Bucket initialized" ) ;
132+ this . logger . info ( "Bucket initialized" ) ;
128133 } ) ;
129134
130135 /**
@@ -202,7 +207,7 @@ export class BucketClient {
202207 }
203208
204209 // use the supplied logger or apply the log level to the console logger
205- const logger = options . logger
210+ this . logger = options . logger
206211 ? options . logger
207212 : applyLogLevel (
208213 decorateLogger ( BUCKET_LOG_PREFIX , console ) ,
@@ -245,26 +250,28 @@ export class BucketClient {
245250 )
246251 : undefined ;
247252
253+ this . rateLimiter = newRateLimiter (
254+ FEATURE_EVENT_RATE_LIMITER_WINDOW_SIZE_MS ,
255+ ) ;
256+ this . httpClient = options . httpClient || fetchClient ;
257+ this . batchBuffer = new BatchBuffer < BulkEvent > ( {
258+ ...options ?. batchOptions ,
259+ flushHandler : ( items ) => this . sendBulkEvents ( items ) ,
260+ logger : this . logger ,
261+ } ) ;
262+
248263 this . _config = {
249- logger,
250264 offline,
251265 apiBaseUrl : ( config . apiBaseUrl ?? config . host ) || API_BASE_URL ,
252266 headers : {
253267 "Content-Type" : "application/json" ,
254268 [ SDK_VERSION_HEADER_NAME ] : SDK_VERSION ,
255269 [ "Authorization" ] : `Bearer ${ config . secretKey } ` ,
256270 } ,
257- rateLimiter : newRateLimiter ( FEATURE_EVENT_RATE_LIMITER_WINDOW_SIZE_MS ) ,
258- httpClient : options . httpClient || fetchClient ,
259271 refetchInterval : FEATURES_REFETCH_MS ,
260272 fetchFeatures : options . fetchFeatures ?? true ,
261273 staleWarningInterval : FEATURES_REFETCH_MS * 5 ,
262274 fallbackFeatures : fallbackFeatures ,
263- batchBuffer : new BatchBuffer < BulkEvent > ( {
264- ...options ?. batchOptions ,
265- flushHandler : ( items ) => this . sendBulkEvents ( items ) ,
266- logger,
267- } ) ,
268275 featureOverrides :
269276 typeof config . featureOverrides === "function"
270277 ? config . featureOverrides
@@ -279,10 +286,10 @@ export class BucketClient {
279286 this . _config . apiBaseUrl += "/" ;
280287 }
281288
282- this . _config . featuresCache = cache < FeaturesAPIResponse > (
289+ this . featuresCache = cache < FeaturesAPIResponse > (
283290 this . _config . refetchInterval ,
284291 this . _config . staleWarningInterval ,
285- this . _config . logger ,
292+ this . logger ,
286293 async ( ) => {
287294 const res = await this . get < FeaturesAPIResponse > ( "features" ) ;
288295
@@ -295,15 +302,6 @@ export class BucketClient {
295302 ) ;
296303 }
297304
298- /**
299- * Gets the logger associated with the client.
300- *
301- * @returns The logger or `undefined` if it is not set.
302- **/
303- public get logger ( ) {
304- return this . _config . logger ;
305- }
306-
307305 /**
308306 * Sets the feature overrides.
309307 *
@@ -369,10 +367,8 @@ export class BucketClient {
369367 return ;
370368 }
371369
372- if (
373- this . _config . rateLimiter . isAllowed ( hashObject ( { ...options , userId } ) )
374- ) {
375- await this . _config . batchBuffer . add ( {
370+ if ( this . rateLimiter . isAllowed ( hashObject ( { ...options , userId } ) ) ) {
371+ await this . batchBuffer . add ( {
376372 type : "user" ,
377373 userId,
378374 attributes : options ?. attributes ,
@@ -415,10 +411,8 @@ export class BucketClient {
415411 return ;
416412 }
417413
418- if (
419- this . _config . rateLimiter . isAllowed ( hashObject ( { ...options , companyId } ) )
420- ) {
421- await this . _config . batchBuffer . add ( {
414+ if ( this . rateLimiter . isAllowed ( hashObject ( { ...options , companyId } ) ) ) {
415+ await this . batchBuffer . add ( {
422416 type : "company" ,
423417 companyId,
424418 userId : options ?. userId ,
@@ -461,7 +455,7 @@ export class BucketClient {
461455 return ;
462456 }
463457
464- await this . _config . batchBuffer . add ( {
458+ await this . batchBuffer . add ( {
465459 type : "event" ,
466460 event,
467461 companyId : options ?. companyId ,
@@ -480,7 +474,8 @@ export class BucketClient {
480474 * Useful when loading feature definitions from a file or other source.
481475 **/
482476 public bootstrapFeatureDefinitions ( features : FeaturesAPIResponse ) {
483- this . _config . featuresCache . set ( features ) ;
477+ this . featuresCache . set ( features ) ;
478+ this . logger . info ( "Bootstrapped feature definitions" ) ;
484479 }
485480
486481 /**
@@ -509,7 +504,7 @@ export class BucketClient {
509504 return ;
510505 }
511506
512- await this . _config . batchBuffer . flush ( ) ;
507+ await this . batchBuffer . flush ( ) ;
513508 }
514509
515510 /**
@@ -519,7 +514,7 @@ export class BucketClient {
519514 * @returns The features definitions.
520515 */
521516 public async getFeatureDefinitions ( ) : Promise < FeatureDefinition [ ] > {
522- const features = this . getFeaturesCache ( ) . get ( ) ?. features || [ ] ;
517+ const features = this . featuresCache . get ( ) ?. features || [ ] ;
523518 return features . map ( ( f ) => ( {
524519 key : f . key ,
525520 description : f . description ,
@@ -661,26 +656,24 @@ export class BucketClient {
661656
662657 const url = this . buildUrl ( path ) ;
663658 try {
664- const response = await this . _config . httpClient . post <
665- TBody ,
666- { success : boolean }
667- > ( url , this . _config . headers , body ) ;
659+ const response = await this . httpClient . post < TBody , { success : boolean } > (
660+ url ,
661+ this . _config . headers ,
662+ body ,
663+ ) ;
668664
669- this . _config . logger ? .debug ( `post request to "${ url } "` , response ) ;
665+ this . logger . debug ( `post request to "${ url } "` , response ) ;
670666
671667 if ( ! response . ok || ! isObject ( response . body ) || ! response . body . success ) {
672- this . _config . logger ? .warn (
668+ this . logger . warn (
673669 `invalid response received from server for "${ url } "` ,
674670 response ,
675671 ) ;
676672 return false ;
677673 }
678674 return true ;
679675 } catch ( error ) {
680- this . _config . logger ?. error (
681- `post request to "${ url } " failed with error` ,
682- error ,
683- ) ;
676+ this . logger . error ( `post request to "${ url } " failed with error` , error ) ;
684677 return false ;
685678 }
686679 }
@@ -698,14 +691,14 @@ export class BucketClient {
698691
699692 try {
700693 const url = this . buildUrl ( path ) ;
701- const response = await this . _config . httpClient . get <
694+ const response = await this . httpClient . get <
702695 TResponse & { success : boolean }
703696 > ( url , this . _config . headers ) ;
704697
705- this . _config . logger ? .debug ( `get request to "${ url } "` , response ) ;
698+ this . logger . debug ( `get request to "${ url } "` , response ) ;
706699
707700 if ( ! response . ok || ! isObject ( response . body ) || ! response . body . success ) {
708- this . _config . logger ? .warn (
701+ this . logger . warn (
709702 `invalid response received from server for "${ url } "` ,
710703 response ,
711704 ) ;
@@ -716,10 +709,7 @@ export class BucketClient {
716709 const { success : _ , ...result } = response . body ;
717710 return result as TResponse ;
718711 } catch ( error ) {
719- this . _config . logger ?. error (
720- `get request to "${ path } " failed with error` ,
721- error ,
722- ) ;
712+ this . logger . error ( `get request to "${ path } " failed with error` , error ) ;
723713 return undefined ;
724714 }
725715 }
@@ -812,7 +802,7 @@ export class BucketClient {
812802 }
813803
814804 if (
815- ! this . _config . rateLimiter . isAllowed (
805+ ! this . rateLimiter . isAllowed (
816806 hashObject ( {
817807 action : event . action ,
818808 key : event . key ,
@@ -825,7 +815,7 @@ export class BucketClient {
825815 return ;
826816 }
827817
828- await this . _config . batchBuffer . add ( {
818+ await this . batchBuffer . add ( {
829819 type : "feature-flag-event" ,
830820 action : event . action ,
831821 key : event . key ,
@@ -850,9 +840,7 @@ export class BucketClient {
850840 */
851841 private async syncContext ( options : ContextWithTracking ) {
852842 if ( ! options . enableTracking ) {
853- this . _config . logger ?. debug (
854- "tracking disabled, not updating user/company" ,
855- ) ;
843+ this . logger . debug ( "tracking disabled, not updating user/company" ) ;
856844
857845 return ;
858846 }
@@ -904,7 +892,7 @@ export class BucketClient {
904892 ( acc , { config, ...feature } ) => {
905893 if (
906894 feature . missingContextFields ?. length &&
907- this . _config . rateLimiter . isAllowed (
895+ this . rateLimiter . isAllowed (
908896 hashObject ( {
909897 featureKey : feature . key ,
910898 missingContextFields : feature . missingContextFields ,
@@ -917,7 +905,7 @@ export class BucketClient {
917905
918906 if (
919907 config ?. missingContextFields ?. length &&
920- this . _config . rateLimiter . isAllowed (
908+ this . rateLimiter . isAllowed (
921909 hashObject ( {
922910 featureKey : feature . key ,
923911 configKey : config . key ,
@@ -935,7 +923,7 @@ export class BucketClient {
935923 ) ;
936924
937925 if ( Object . keys ( report ) . length > 0 ) {
938- this . _config . logger ? .warn (
926+ this . logger . warn (
939927 `feature/remote config targeting rules might not be correctly evaluated due to missing context fields.` ,
940928 report ,
941929 ) ;
@@ -953,9 +941,9 @@ export class BucketClient {
953941 if ( this . _config . offline ) {
954942 featureDefinitions = [ ] ;
955943 } else {
956- const fetchedFeatures = this . getFeaturesCache ( ) . get ( ) ;
944+ const fetchedFeatures = this . featuresCache . get ( ) ;
957945 if ( ! fetchedFeatures ) {
958- this . _config . logger ? .warn (
946+ this . logger . warn (
959947 "failed to use feature definitions, there are none cached yet. Using fallback features." ,
960948 ) ;
961949 return this . _config . fallbackFeatures || { } ;
@@ -1059,7 +1047,7 @@ export class BucketClient {
10591047 )
10601048 . filter ( Boolean ) ;
10611049 if ( failed . length > 0 ) {
1062- this . _config . logger ? .error ( `failed to queue some evaluate events.` , {
1050+ this . logger . error ( `failed to queue some evaluate events.` , {
10631051 errors : failed ,
10641052 } ) ;
10651053 }
@@ -1129,7 +1117,7 @@ export class BucketClient {
11291117 evalMissingFields : feature . missingContextFields ,
11301118 } )
11311119 . catch ( ( err ) => {
1132- client . _config . logger ?. error (
1120+ client . logger ?. error (
11331121 `failed to send check event for "${ feature . key } ": ${ err } ` ,
11341122 err ,
11351123 ) ;
@@ -1150,7 +1138,7 @@ export class BucketClient {
11501138 evalMissingFields : config ?. missingContextFields ,
11511139 } )
11521140 . catch ( ( err ) => {
1153- client . _config . logger ?. error (
1141+ client . logger ?. error (
11541142 `failed to send check event for "${ feature . key } ": ${ err } ` ,
11551143 err ,
11561144 ) ;
@@ -1161,7 +1149,7 @@ export class BucketClient {
11611149 key : feature . key ,
11621150 track : async ( ) => {
11631151 if ( typeof context . user ?. id === "undefined" ) {
1164- this . _config . logger ? .warn ( "no user set, cannot track event" ) ;
1152+ this . logger . warn ( "no user set, cannot track event" ) ;
11651153 return ;
11661154 }
11671155
@@ -1170,7 +1158,7 @@ export class BucketClient {
11701158 companyId : context . company ?. id ,
11711159 } ) ;
11721160 } else {
1173- this . _config . logger ? .debug ( "tracking disabled, not tracking event" ) ;
1161+ this . logger . debug ( "tracking disabled, not tracking event" ) ;
11741162 }
11751163 } ,
11761164 } ;
@@ -1224,7 +1212,7 @@ export class BucketClient {
12241212 } ) || [ ] ,
12251213 ) ;
12261214 } else {
1227- this . _config . logger ? .error ( "failed to fetch evaluated features" ) ;
1215+ this . logger . error ( "failed to fetch evaluated features" ) ;
12281216 return { } ;
12291217 }
12301218 }
0 commit comments