@@ -4,7 +4,7 @@ import { Applier, FlagResolution } from './FlagResolution';
44import { Telemetry , Meter } from './Telemetry' ;
55import { Value } from './Value' ;
66import { Context } from './context' ;
7- import { FetchBuilder , TimeUnit } from './fetch-util' ;
7+ import { FetchBuilder , InternalFetch , SimpleFetch , TimeUnit } from './fetch-util' ;
88import {
99 ResolveFlagsRequest ,
1010 ResolveFlagsResponse ,
@@ -18,7 +18,7 @@ import {
1818 Monitoring ,
1919} from './generated/confidence/telemetry/v1/telemetry' ;
2020import { Logger } from './logger' ;
21- import { SimpleFetch , WaitUntil } from './types' ;
21+ import { WaitUntil } from './types' ;
2222
2323const FLAG_PREFIX = 'flags/' ;
2424const retryCodes = new Set ( [ 408 , 502 , 503 , 504 ] ) ;
@@ -99,7 +99,7 @@ export type FlagResolverClientOptions = {
9999} ;
100100
101101export class FetchingFlagResolverClient implements FlagResolverClient {
102- private readonly fetchImplementation : SimpleFetch ;
102+ private readonly fetchImplementation : InternalFetch ;
103103 private readonly clientSecret : string ;
104104 private readonly sdk : Sdk ;
105105 private readonly applyDebounce : number ;
@@ -127,11 +127,14 @@ export class FetchingFlagResolverClient implements FlagResolverClient {
127127 version : sdk . version ,
128128 id : LibraryTraces_TraceId . TRACE_ID_RESOLVE_LATENCY ,
129129 } ) ;
130- const fetchBuilderWithTelemetry = withTelemetryData ( new FetchBuilder ( ) , telemetry ) ;
131- // TODO think about both resolve and apply request logic for backends
132- const fetchWithTelemetry = fetchBuilderWithTelemetry . build ( fetchImplementation ) ;
133- this . fetchImplementation =
134- environment === 'backend' ? fetchWithTelemetry : withRequestLogic ( fetchWithTelemetry , logger ) ;
130+
131+ const fetchBuilder = new FetchBuilder ( ) ;
132+ withTelemetryData ( fetchBuilder , telemetry ) ;
133+ if ( environment === 'client' ) {
134+ withRequestLogic ( fetchBuilder , logger ) ;
135+ }
136+
137+ this . fetchImplementation = fetchBuilder . build ( fetchImplementation ) ;
135138
136139 this . clientSecret = clientSecret ;
137140 this . sdk = sdk ;
@@ -214,31 +217,27 @@ export class FetchingFlagResolverClient implements FlagResolverClient {
214217 }
215218
216219 async apply ( request : ApplyFlagsRequest ) : Promise < void > {
217- const resp = await this . fetchImplementation (
218- new Request ( `${ this . baseUrl } /flags:apply` , {
219- method : 'POST' ,
220- headers : {
221- 'Content-Type' : 'application/json' ,
222- } ,
223- body : JSON . stringify ( ApplyFlagsRequest . toJSON ( request ) ) ,
224- } ) ,
225- ) ;
220+ const resp = await this . fetchImplementation ( `${ this . baseUrl } /flags:apply` , {
221+ method : 'POST' ,
222+ headers : {
223+ 'Content-Type' : 'application/json' ,
224+ } ,
225+ body : JSON . stringify ( ApplyFlagsRequest . toJSON ( request ) ) ,
226+ } ) ;
226227 if ( ! resp . ok ) {
227228 throw new Error ( `${ resp . status } : ${ resp . statusText } ` ) ;
228229 }
229230 }
230231
231232 async resolveFlagsJson ( request : ResolveFlagsRequest , signal : AbortSignal ) : Promise < ResolveFlagsResponse > {
232- const resp = await this . fetchImplementation (
233- new Request ( `${ this . baseUrl } /flags:resolve` , {
234- method : 'POST' ,
235- headers : {
236- 'Content-Type' : 'application/json' ,
237- } ,
238- body : JSON . stringify ( ResolveFlagsRequest . toJSON ( request ) ) ,
239- signal,
240- } ) ,
241- ) ;
233+ const resp = await this . fetchImplementation ( `${ this . baseUrl } /flags:resolve` , {
234+ method : 'POST' ,
235+ headers : {
236+ 'Content-Type' : 'application/json' ,
237+ } ,
238+ body : JSON . stringify ( ResolveFlagsRequest . toJSON ( request ) ) ,
239+ signal,
240+ } ) ;
242241 if ( ! resp . ok ) {
243242 throw new Error ( `${ resp . status } : ${ resp . statusText } ` ) ;
244243 }
@@ -315,24 +314,19 @@ export class CachingFlagResolverClient implements FlagResolverClient {
315314 }
316315}
317316
318- export function withTelemetryData ( fetchBuilder : FetchBuilder , telemetry : Telemetry ) : FetchBuilder {
319- return fetchBuilder . modifyRequest ( async request => {
317+ export function withTelemetryData ( fetchBuilder : FetchBuilder , telemetry : Telemetry ) {
318+ fetchBuilder . modifyRequest ( ( { headers } ) => {
320319 const monitoring = telemetry . getSnapshot ( ) ;
321320 if ( monitoring . libraryTraces . length > 0 ) {
322- const headers = new Headers ( request . headers ) ;
323321 const base64Message = btoa ( String . fromCharCode ( ...Monitoring . encode ( monitoring ) . finish ( ) ) ) ;
324322
325- headers . set ( 'X-CONFIDENCE-TELEMETRY' , base64Message ) ;
326- return new Request ( request , { headers } ) ;
323+ return { headers : { ...headers , [ 'X-CONFIDENCE-TELEMETRY' ] : base64Message } } ;
327324 }
328- return request ;
325+ return { } ;
329326 } ) ;
330327}
331328
332- export function withRequestLogic (
333- fetchImplementation : ( request : Request ) => Promise < Response > ,
334- logger : Logger ,
335- ) : typeof fetch {
329+ export function withRequestLogic ( fetchBuilder : FetchBuilder , logger : Logger ) {
336330 const fetchResolve = new FetchBuilder ( )
337331 // infinite retries without delay until aborted by timeout
338332 . compose ( next => async request => {
@@ -347,8 +341,7 @@ export function withRequestLogic(
347341 . rejectNotOk ( )
348342 . retry ( )
349343 . rejectOn ( response => retryCodes . has ( response . status ) )
350- . rateLimit ( 1 , { initialTokens : 3 , maxTokens : 2 } )
351- . build ( fetchImplementation ) ;
344+ . rateLimit ( 1 , { initialTokens : 3 , maxTokens : 2 } ) ;
352345
353346 const fetchApply = new FetchBuilder ( )
354347 . limitPending ( 1000 )
@@ -358,22 +351,17 @@ export function withRequestLogic(
358351 . rejectOn ( response => retryCodes . has ( response . status ) )
359352 . rateLimit ( 2 )
360353 // update send-time before sending
361- . modifyRequest ( async request => {
362- if ( request . method === 'POST' ) {
363- const body = JSON . stringify ( { ...( await request . clone ( ) . json ( ) ) , sendTime : new Date ( ) . toISOString ( ) } ) ;
364- return new Request ( request , { body } ) ;
354+ . modifyRequest ( ( { method , body } ) => {
355+ if ( method === 'POST' && body ) {
356+ body = JSON . stringify ( { ...JSON . parse ( body ) , sendTime : new Date ( ) . toISOString ( ) } ) ;
357+ return { body } ;
365358 }
366- return request ;
367- } )
368- . build ( fetchImplementation ) ;
369-
370- return (
371- new FetchBuilder ( )
372- . route ( url => url . endsWith ( 'flags:resolve' ) , fetchResolve )
373- . route ( url => url . endsWith ( 'flags:apply' ) , fetchApply )
374- // throw so we notice changes in endpoints that should be handled here
375- . build ( request => Promise . reject ( new Error ( `Unexpected url: ${ request . url } ` ) ) )
376- ) ;
359+ return { } ;
360+ } ) ;
361+
362+ fetchBuilder
363+ . route ( url => url . endsWith ( 'flags:resolve' ) , fetchResolve )
364+ . route ( url => url . endsWith ( 'flags:apply' ) , fetchApply ) ;
377365}
378366
379367function withTimeout ( signal : AbortSignal , timeout : number , reason ?: any ) : AbortSignal {
0 commit comments