@@ -344,13 +344,93 @@ const makeStreamRequestAsync: StreamFetchFn = async (
344344 ) ;
345345} ;
346346
347+ // Module-level mutable state for mock injection. These must NOT be private members
348+ // of WebClient because rush-sdk re-exports WebClient as a separate type declaration,
349+ // and TypeScript's structural typing treats private members nominally, causing type
350+ // incompatibility between the rush-lib and rush-sdk versions.
351+ let _requestFnAsync : FetchFn = makeRequestAsync ;
352+ let _streamRequestFnAsync : StreamFetchFn = makeStreamRequestAsync ;
353+
354+ function _mergeHeaders ( target : Record < string , string > , source : Record < string , string > ) : void {
355+ for ( const [ name , value ] of Object . entries ( source ) ) {
356+ target [ name ] = value ;
357+ }
358+ }
359+
360+ /**
361+ * Builds the low-level IRequestOptions from WebClient instance state and caller-provided options.
362+ * This is a module-level function (not a private method) to avoid the rush-sdk type mismatch.
363+ */
364+ function buildRequestOptions (
365+ webClient : WebClient ,
366+ options ?: IGetFetchOptions | IFetchOptionsWithBody
367+ ) : IRequestOptions {
368+ const {
369+ headers : optionsHeaders ,
370+ timeoutMs = 15 * 1000 ,
371+ verb,
372+ redirect,
373+ body,
374+ noDecode
375+ } = ( options as IFetchOptionsWithBody | undefined ) ?? { } ;
376+
377+ const headers : Record < string , string > = { } ;
378+
379+ const { standardHeaders, userAgent, accept, proxy } = webClient ;
380+
381+ _mergeHeaders ( headers , standardHeaders ) ;
382+
383+ if ( optionsHeaders ) {
384+ _mergeHeaders ( headers , optionsHeaders ) ;
385+ }
386+
387+ if ( userAgent ) {
388+ headers [ USER_AGENT_HEADER_NAME ] = userAgent ;
389+ }
390+
391+ if ( accept ) {
392+ headers [ ACCEPT_HEADER_NAME ] = accept ;
393+ }
394+
395+ let proxyUrl : string = '' ;
396+
397+ switch ( proxy ) {
398+ case WebClientProxy . Detect :
399+ if ( process . env . HTTPS_PROXY ) {
400+ proxyUrl = process . env . HTTPS_PROXY ;
401+ } else if ( process . env . HTTP_PROXY ) {
402+ proxyUrl = process . env . HTTP_PROXY ;
403+ }
404+ break ;
405+
406+ case WebClientProxy . Fiddler :
407+ // For debugging, disable cert validation
408+ // eslint-disable-next-line
409+ process . env [ 'NODE_TLS_REJECT_UNAUTHORIZED' ] = '0' ;
410+ proxyUrl = 'http://localhost:8888/' ;
411+ break ;
412+ }
413+
414+ let agent : HttpAgent | undefined = undefined ;
415+ if ( proxyUrl ) {
416+ agent = createHttpsProxyAgent ( proxyUrl ) ;
417+ }
418+
419+ return {
420+ method : verb ,
421+ headers,
422+ agent,
423+ timeout : timeoutMs ,
424+ redirect,
425+ body,
426+ noDecode
427+ } ;
428+ }
429+
347430/**
348431 * A helper for issuing HTTP requests.
349432 */
350433export class WebClient {
351- private static _requestFnAsync : FetchFn = makeRequestAsync ;
352- private static _streamRequestFnAsync : StreamFetchFn = makeStreamRequestAsync ;
353-
354434 public readonly standardHeaders : Record < string , string > = { } ;
355435
356436 public accept : string | undefined = '*/*' ;
@@ -359,25 +439,23 @@ export class WebClient {
359439 public proxy : WebClientProxy = WebClientProxy . Detect ;
360440
361441 public static mockRequestFn ( fn : FetchFn ) : void {
362- WebClient . _requestFnAsync = fn ;
442+ _requestFnAsync = fn ;
363443 }
364444
365445 public static resetMockRequestFn ( ) : void {
366- WebClient . _requestFnAsync = makeRequestAsync ;
446+ _requestFnAsync = makeRequestAsync ;
367447 }
368448
369449 public static mockStreamRequestFn ( fn : StreamFetchFn ) : void {
370- WebClient . _streamRequestFnAsync = fn ;
450+ _streamRequestFnAsync = fn ;
371451 }
372452
373453 public static resetMockStreamRequestFn ( ) : void {
374- WebClient . _streamRequestFnAsync = makeStreamRequestAsync ;
454+ _streamRequestFnAsync = makeStreamRequestAsync ;
375455 }
376456
377457 public static mergeHeaders ( target : Record < string , string > , source : Record < string , string > ) : void {
378- for ( const [ name , value ] of Object . entries ( source ) ) {
379- target [ name ] = value ;
380- }
458+ _mergeHeaders ( target , source ) ;
381459 }
382460
383461 public addBasicAuthHeader ( userName : string , password : string ) : void {
@@ -389,8 +467,8 @@ export class WebClient {
389467 url : string ,
390468 options ?: IGetFetchOptions | IFetchOptionsWithBody
391469 ) : Promise < IWebClientResponse > {
392- const requestInit : IRequestOptions = this . _buildRequestOptions ( options ) ;
393- return await WebClient . _requestFnAsync ( url , requestInit ) ;
470+ const requestInit : IRequestOptions = buildRequestOptions ( this , options ) ;
471+ return await _requestFnAsync ( url , requestInit ) ;
394472 }
395473
396474 /**
@@ -401,70 +479,7 @@ export class WebClient {
401479 url : string ,
402480 options ?: IGetFetchOptions | IFetchOptionsWithBody
403481 ) : Promise < IWebClientStreamResponse > {
404- const requestInit : IRequestOptions = this . _buildRequestOptions ( options ) ;
405- return await WebClient . _streamRequestFnAsync ( url , requestInit ) ;
406- }
407-
408- private _buildRequestOptions ( options ?: IGetFetchOptions | IFetchOptionsWithBody ) : IRequestOptions {
409- const {
410- headers : optionsHeaders ,
411- timeoutMs = 15 * 1000 ,
412- verb,
413- redirect,
414- body,
415- noDecode
416- } = ( options as IFetchOptionsWithBody | undefined ) ?? { } ;
417-
418- const headers : Record < string , string > = { } ;
419-
420- const { standardHeaders, userAgent, accept, proxy } = this ;
421-
422- WebClient . mergeHeaders ( headers , standardHeaders ) ;
423-
424- if ( optionsHeaders ) {
425- WebClient . mergeHeaders ( headers , optionsHeaders ) ;
426- }
427-
428- if ( userAgent ) {
429- headers [ USER_AGENT_HEADER_NAME ] = userAgent ;
430- }
431-
432- if ( accept ) {
433- headers [ ACCEPT_HEADER_NAME ] = accept ;
434- }
435-
436- let proxyUrl : string = '' ;
437-
438- switch ( proxy ) {
439- case WebClientProxy . Detect :
440- if ( process . env . HTTPS_PROXY ) {
441- proxyUrl = process . env . HTTPS_PROXY ;
442- } else if ( process . env . HTTP_PROXY ) {
443- proxyUrl = process . env . HTTP_PROXY ;
444- }
445- break ;
446-
447- case WebClientProxy . Fiddler :
448- // For debugging, disable cert validation
449- // eslint-disable-next-line
450- process . env [ 'NODE_TLS_REJECT_UNAUTHORIZED' ] = '0' ;
451- proxyUrl = 'http://localhost:8888/' ;
452- break ;
453- }
454-
455- let agent : HttpAgent | undefined = undefined ;
456- if ( proxyUrl ) {
457- agent = createHttpsProxyAgent ( proxyUrl ) ;
458- }
459-
460- return {
461- method : verb ,
462- headers,
463- agent,
464- timeout : timeoutMs ,
465- redirect,
466- body,
467- noDecode
468- } ;
482+ const requestInit : IRequestOptions = buildRequestOptions ( this , options ) ;
483+ return await _streamRequestFnAsync ( url , requestInit ) ;
469484 }
470485}
0 commit comments