@@ -5,12 +5,28 @@ export type AppPairingRequest =
55 | { status : "completed" ; requestId : string ; encryptedToken : string }
66 | { status : "expired" ; requestId : string } ;
77
8+ export class NetworkError extends Error {
9+ constructor ( message : string ) {
10+ super ( message ) ;
11+ this . name = "NetworkError" ;
12+ }
13+ }
14+
15+ export class ServerError extends Error {
16+ constructor ( message : string ) {
17+ super ( message ) ;
18+ this . name = "ServerError" ;
19+ }
20+ }
21+
822const PAIRING_API_URLS : Record < Environment , string > = {
923 prod : "https://auth.beeai-services.com" ,
1024 staging : "https://public-api.korshaks.people.amazon.dev" ,
1125} ;
1226
1327const PAIRING_PATH = "/apps/pairing/request" ;
28+ const MAX_RETRIES = 10 ;
29+ const MAX_BACKOFF_MS = 30000 ;
1430
1531export async function requestAppPairing (
1632 env : Environment ,
@@ -86,7 +102,74 @@ async function fetchPairing(
86102 init : RequestInit
87103) : Promise < Response > {
88104 const url = new URL ( PAIRING_PATH , PAIRING_API_URLS [ env ] ) ;
89- return fetch ( url , init ) ;
105+ return await fetchWithRetry ( url , init ) ;
106+ }
107+
108+ async function fetchWithRetry (
109+ url : URL ,
110+ init : RequestInit
111+ ) : Promise < Response > {
112+ let lastError : Error | null = null ;
113+ let lastErrorType : "network" | "server" | null = null ;
114+
115+ for ( let attempt = 1 ; attempt <= MAX_RETRIES ; attempt ++ ) {
116+ try {
117+ const response = await fetch ( url , init ) ;
118+
119+ if ( response . status >= 500 && response . status < 600 ) {
120+ lastErrorType = "server" ;
121+ lastError = new ServerError (
122+ `Server error: ${ response . status } `
123+ ) ;
124+ if ( attempt < MAX_RETRIES ) {
125+ console . log (
126+ `Server is temporarily unavailable, retrying... (attempt ${ attempt } of ${ MAX_RETRIES } )`
127+ ) ;
128+ await sleep ( getBackoffDelay ( attempt ) ) ;
129+ continue ;
130+ }
131+ }
132+
133+ return response ;
134+ } catch ( error ) {
135+ lastErrorType = "network" ;
136+ lastError =
137+ error instanceof Error
138+ ? new NetworkError ( error . message )
139+ : new NetworkError ( "Unknown network error" ) ;
140+
141+ if ( attempt < MAX_RETRIES ) {
142+ console . log (
143+ `Network connection issue, retrying... (attempt ${ attempt } of ${ MAX_RETRIES } )`
144+ ) ;
145+ await sleep ( getBackoffDelay ( attempt ) ) ;
146+ continue ;
147+ }
148+ }
149+ }
150+
151+ if ( lastErrorType === "network" ) {
152+ throw new NetworkError (
153+ "Unable to connect to Bee services. Please check your internet connection and try again."
154+ ) ;
155+ }
156+
157+ if ( lastErrorType === "server" ) {
158+ throw new ServerError (
159+ "Bee servers are currently experiencing issues. Please try again later."
160+ ) ;
161+ }
162+
163+ throw lastError ?? new Error ( "Request failed after multiple retries." ) ;
164+ }
165+
166+ function getBackoffDelay ( attempt : number ) : number {
167+ const delay = Math . min ( 1000 * Math . pow ( 2 , attempt - 1 ) , MAX_BACKOFF_MS ) ;
168+ return delay ;
169+ }
170+
171+ async function sleep ( ms : number ) : Promise < void > {
172+ await new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
90173}
91174
92175async function safeJson (
0 commit comments