File tree Expand file tree Collapse file tree 4 files changed +56
-4
lines changed
clerk-js/src/core/resources Expand file tree Collapse file tree 4 files changed +56
-4
lines changed Original file line number Diff line number Diff line change @@ -169,6 +169,25 @@ describe('api.client', () => {
169169 expect ( errResponse . retryAfter ) . toBe ( 123 ) ;
170170 } ) ;
171171
172+ it ( 'executes a failed backend API request and includes Retry-After header RFC1123 date' , async ( ) => {
173+ server . use (
174+ http . get (
175+ `https://api.clerk.test/v1/users/user_deadbeef` ,
176+ validateHeaders ( ( ) => {
177+ return HttpResponse . json (
178+ { errors : [ ] } ,
179+ { status : 503 , headers : { 'retry-after' : new Date ( new Date ( ) . getTime ( ) + 60000 ) . toUTCString ( ) } } ,
180+ ) ;
181+ } ) ,
182+ ) ,
183+ ) ;
184+
185+ const errResponse = await apiClient . users . getUser ( 'user_deadbeef' ) . catch ( err => err ) ;
186+
187+ expect ( errResponse . status ) . toBe ( 503 ) ;
188+ expect ( errResponse . retryAfter ) . not . toBeNaN ( ) ;
189+ } ) ;
190+
172191 it ( 'executes a failed backend API request and ignores invalid Retry-After header' , async ( ) => {
173192 server . use (
174193 http . get (
Original file line number Diff line number Diff line change @@ -250,11 +250,17 @@ function getRetryAfter(headers?: Headers): number | undefined {
250250 }
251251
252252 const value = parseInt ( retryAfter , 10 ) ;
253- if ( isNaN ( value ) ) {
254- return ;
253+ if ( ! isNaN ( value ) ) {
254+ return value ;
255+ }
256+
257+ const date = new Date ( retryAfter ) ;
258+ if ( ! isNaN ( date . getTime ( ) ) ) {
259+ const value = date . getTime ( ) - Date . now ( ) ;
260+ return value > 0 ? value : 0 ;
255261 }
256262
257- return value ;
263+ return ;
258264}
259265
260266function parseErrors ( data : unknown ) : ClerkAPIError [ ] {
Original file line number Diff line number Diff line change @@ -146,13 +146,19 @@ export abstract class BaseResource {
146146 assertProductionKeysOnDev ( status , errors ) ;
147147
148148 const apiResponseOptions : ConstructorParameters < typeof ClerkAPIResponseError > [ 1 ] = { data : errors , status } ;
149- if ( status === 429 && headers ) {
149+ if ( ( status === 429 || status == 503 ) && headers ) {
150150 const retryAfter = headers . get ( 'retry-after' ) ;
151151 if ( retryAfter ) {
152152 const value = parseInt ( retryAfter , 10 ) ;
153153 if ( ! isNaN ( value ) ) {
154154 apiResponseOptions . retryAfter = value ;
155155 }
156+
157+ const date = new Date ( retryAfter ) ;
158+ if ( ! isNaN ( date . getTime ( ) ) ) {
159+ const value = date . getTime ( ) - Date . now ( ) ;
160+ apiResponseOptions . retryAfter = value > 0 ? value : 0 ;
161+ }
156162 }
157163 }
158164
Original file line number Diff line number Diff line change @@ -38,6 +38,27 @@ describe('BaseResource', () => {
3838 expect ( errResponse . retryAfter ) . toBe ( 60 ) ;
3939 } ) ;
4040
41+ it ( 'populates retryAfter on 503 error responses' , async ( ) => {
42+ BaseResource . clerk = {
43+ // @ts -expect-error - We're not about to mock the entire FapiClient
44+ getFapiClient : ( ) => {
45+ return {
46+ request : vi . fn ( ) . mockResolvedValue ( {
47+ payload : { } ,
48+ status : 503 ,
49+ statusText : 'Service Unavailable' ,
50+ headers : new Headers ( { 'Retry-After' : new Date ( new Date ( ) . getTime ( ) + 60000 ) . toUTCString ( ) } ) ,
51+ } ) ,
52+ } ;
53+ } ,
54+ __internal_setCountry : vi . fn ( ) ,
55+ } ;
56+ const resource = new TestResource ( ) ;
57+ const errResponse = await resource . fetch ( ) . catch ( err => err ) ;
58+ console . dir ( errResponse ) ;
59+ expect ( errResponse . retryAfter ) . toBe ( 60 ) ;
60+ } ) ;
61+
4162 it ( 'does not populate retryAfter on invalid header' , async ( ) => {
4263 BaseResource . clerk = {
4364 // @ts -expect-error - We're not about to mock the entire FapiClient
You can’t perform that action at this time.
0 commit comments