@@ -37,7 +37,7 @@ type APIResponseProps = {
3737 controller : AbortController ;
3838} ;
3939
40- async function defaultParseResponse < T > ( props : APIResponseProps ) : Promise < T > {
40+ async function defaultParseResponse < T > ( props : APIResponseProps ) : Promise < WithRequestID < T > > {
4141 const { response } = props ;
4242 if ( props . options . stream ) {
4343 debug ( 'response' , response . status , response . url , response . headers , response . body ) ;
@@ -54,11 +54,11 @@ async function defaultParseResponse<T>(props: APIResponseProps): Promise<T> {
5454
5555 // fetch refuses to read the body when the status code is 204.
5656 if ( response . status === 204 ) {
57- return null as T ;
57+ return null as WithRequestID < T > ;
5858 }
5959
6060 if ( props . options . __binaryResponse ) {
61- return response as unknown as T ;
61+ return response as unknown as WithRequestID < T > ;
6262 }
6363
6464 const contentType = response . headers . get ( 'content-type' ) ;
@@ -69,26 +69,44 @@ async function defaultParseResponse<T>(props: APIResponseProps): Promise<T> {
6969
7070 debug ( 'response' , response . status , response . url , response . headers , json ) ;
7171
72- return json as T ;
72+ return _addRequestID ( json , response ) ;
7373 }
7474
7575 const text = await response . text ( ) ;
7676 debug ( 'response' , response . status , response . url , response . headers , text ) ;
7777
7878 // TODO handle blob, arraybuffer, other content types, etc.
79- return text as unknown as T ;
79+ return text as unknown as WithRequestID < T > ;
80+ }
81+
82+ type WithRequestID < T > =
83+ T extends Array < any > | Response | AbstractPage < any > ? T
84+ : T extends Record < string , any > ? T & { _request_id ?: string | null }
85+ : T ;
86+
87+ function _addRequestID < T > ( value : T , response : Response ) : WithRequestID < T > {
88+ if ( ! value || typeof value !== 'object' || Array . isArray ( value ) ) {
89+ return value as WithRequestID < T > ;
90+ }
91+
92+ return Object . defineProperty ( value , '_request_id' , {
93+ value : response . headers . get ( 'x-request-id' ) ,
94+ enumerable : false ,
95+ } ) as WithRequestID < T > ;
8096}
8197
8298/**
8399 * A subclass of `Promise` providing additional helper methods
84100 * for interacting with the SDK.
85101 */
86- export class APIPromise < T > extends Promise < T > {
87- private parsedPromise : Promise < T > | undefined ;
102+ export class APIPromise < T > extends Promise < WithRequestID < T > > {
103+ private parsedPromise : Promise < WithRequestID < T > > | undefined ;
88104
89105 constructor (
90106 private responsePromise : Promise < APIResponseProps > ,
91- private parseResponse : ( props : APIResponseProps ) => PromiseOrValue < T > = defaultParseResponse ,
107+ private parseResponse : (
108+ props : APIResponseProps ,
109+ ) => PromiseOrValue < WithRequestID < T > > = defaultParseResponse ,
92110 ) {
93111 super ( ( resolve ) => {
94112 // this is maybe a bit weird but this has to be a no-op to not implicitly
@@ -99,7 +117,9 @@ export class APIPromise<T> extends Promise<T> {
99117 }
100118
101119 _thenUnwrap < U > ( transform : ( data : T ) => U ) : APIPromise < U > {
102- return new APIPromise ( this . responsePromise , async ( props ) => transform ( await this . parseResponse ( props ) ) ) ;
120+ return new APIPromise ( this . responsePromise , async ( props ) =>
121+ _addRequestID ( transform ( await this . parseResponse ( props ) ) , props . response ) ,
122+ ) ;
103123 }
104124
105125 /**
@@ -136,27 +156,27 @@ export class APIPromise<T> extends Promise<T> {
136156 return { data, response } ;
137157 }
138158
139- private parse ( ) : Promise < T > {
159+ private parse ( ) : Promise < WithRequestID < T > > {
140160 if ( ! this . parsedPromise ) {
141- this . parsedPromise = this . responsePromise . then ( this . parseResponse ) ;
161+ this . parsedPromise = this . responsePromise . then ( this . parseResponse ) as any as Promise < WithRequestID < T > > ;
142162 }
143163 return this . parsedPromise ;
144164 }
145165
146- override then < TResult1 = T , TResult2 = never > (
147- onfulfilled ?: ( ( value : T ) => TResult1 | PromiseLike < TResult1 > ) | undefined | null ,
166+ override then < TResult1 = WithRequestID < T > , TResult2 = never > (
167+ onfulfilled ?: ( ( value : WithRequestID < T > ) => TResult1 | PromiseLike < TResult1 > ) | undefined | null ,
148168 onrejected ?: ( ( reason : any ) => TResult2 | PromiseLike < TResult2 > ) | undefined | null ,
149169 ) : Promise < TResult1 | TResult2 > {
150170 return this . parse ( ) . then ( onfulfilled , onrejected ) ;
151171 }
152172
153173 override catch < TResult = never > (
154174 onrejected ?: ( ( reason : any ) => TResult | PromiseLike < TResult > ) | undefined | null ,
155- ) : Promise < T | TResult > {
175+ ) : Promise < WithRequestID < T > | TResult > {
156176 return this . parse ( ) . catch ( onrejected ) ;
157177 }
158178
159- override finally ( onfinally ?: ( ( ) => void ) | undefined | null ) : Promise < T > {
179+ override finally ( onfinally ?: ( ( ) => void ) | undefined | null ) : Promise < WithRequestID < T > > {
160180 return this . parse ( ) . finally ( onfinally ) ;
161181 }
162182}
@@ -706,7 +726,13 @@ export class PagePromise<
706726 ) {
707727 super (
708728 request ,
709- async ( props ) => new Page ( client , props . response , await defaultParseResponse ( props ) , props . options ) ,
729+ async ( props ) =>
730+ new Page (
731+ client ,
732+ props . response ,
733+ await defaultParseResponse ( props ) ,
734+ props . options ,
735+ ) as WithRequestID < PageClass > ,
710736 ) ;
711737 }
712738
0 commit comments