@@ -8,117 +8,98 @@ const inFlightMap = new Map();
88 * Generate a signature for dedup if deduplicate is true
99 */
1010function makeSignature ( input , init ) {
11- // Basic approach:
12- const normalized = {
13- url : typeof input === "string" ? input : input . url ,
14- method : init ?. method ?? "GET" ,
15- headers : init ?. headers ?? { } ,
16- body : init ?. body ?? null ,
17- } ;
18- return JSON . stringify ( normalized ) ;
11+ // Basic approach:
12+ const normalized = {
13+ url : typeof input === "string" ? input : input . url ,
14+ method : init ?. method ?? "GET" ,
15+ headers : init ?. headers ?? { } ,
16+ body : init ?. body ?? null ,
17+ } ;
18+ return JSON . stringify ( normalized ) ;
1919}
2020/**
2121 * Sleep helper for retryDelay
2222 */
2323function sleep ( ms ) {
24- return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
24+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
2525}
2626/**
2727 * FastFetch main function
2828 * - Retries on error with exponential backoff
2929 * - Deduplicates in-flight requests if deduplicate = true
3030 */
3131export async function fastFetch ( input , init ) {
32- const {
33- retries = 0 ,
34- retryDelay = 1000 ,
35- deduplicate = true ,
36- shouldRetry,
37- } = init || { } ;
38- console . log ( "[FastFetch] Starting request for:" , input ) ;
39- // If deduplicating, check if a matching in-flight request exists
40- let signature = "" ;
41- if ( deduplicate ) {
42- signature = makeSignature ( input , init ) ;
43- if ( inFlightMap . has ( signature ) ) {
44- console . log (
45- "[FastFetch] Found in-flight request for signature:" ,
46- signature ,
47- ) ;
48- return inFlightMap . get ( signature ) ;
49- }
50- }
51- // Build a promise chain that tries up to retries + 1 times with exponential backoff
52- let attempt = 0 ;
53- let promise = ( async function fetchWithRetry ( ) {
54- while ( true ) {
55- try {
56- attempt ++ ;
57- console . log ( `[FastFetch] Attempt #${ attempt } for:` , input ) ;
58- const response = await fetch ( input , init ) ;
59- if ( ! response . ok && shouldRetry ) {
60- const doRetry = shouldRetry ( response , attempt ) ;
61- console . log (
62- `[FastFetch] Response not ok (status: ${ response . status } ). Retry decision: ${ doRetry } ` ,
63- ) ;
64- if ( doRetry && attempt <= retries ) {
65- const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
66- console . log (
67- `[FastFetch] Waiting ${ delay } ms (exponential backoff) before retrying...` ,
68- ) ;
69- await sleep ( delay ) ;
70- continue ; // try again
71- }
72- }
73- console . log ( `[FastFetch] Request succeeded on attempt #${ attempt } ` ) ;
74- return response ;
75- } catch ( error ) {
76- console . log ( `[FastFetch] Caught error on attempt #${ attempt } :` , error ) ;
77- if ( shouldRetry ) {
78- const doRetry = shouldRetry ( error , attempt ) ;
79- console . log ( `[FastFetch] Retry decision based on error: ${ doRetry } ` ) ;
80- if ( doRetry && attempt <= retries ) {
81- const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
82- console . log (
83- `[FastFetch] Waiting ${ delay } ms (exponential backoff) before retrying after error...` ,
84- ) ;
85- await sleep ( delay ) ;
86- continue ;
87- }
88- } else {
89- if ( attempt <= retries ) {
90- const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
91- console . log (
92- `[FastFetch] Retrying attempt #${ attempt } after error. Waiting ${ delay } ms...` ,
93- ) ;
94- await sleep ( delay ) ;
95- continue ;
96- }
32+ const { retries = 0 , retryDelay = 1000 , deduplicate = true , shouldRetry, } = init || { } ;
33+ console . log ( "[FastFetch] Starting request for:" , input ) ;
34+ // If deduplicating, check if a matching in-flight request exists
35+ let signature = "" ;
36+ if ( deduplicate ) {
37+ signature = makeSignature ( input , init ) ;
38+ if ( inFlightMap . has ( signature ) ) {
39+ console . log ( "[FastFetch] Found in-flight request for signature:" , signature ) ;
40+ return inFlightMap . get ( signature ) ;
9741 }
98- console . log ( "[FastFetch] No more retries. Throwing error." ) ;
99- throw error ;
100- }
10142 }
102- } ) ( ) ;
103- // If deduplicating, store in the map so subsequent calls get the same promise
104- if ( deduplicate ) {
105- inFlightMap . set ( signature , promise ) ;
106- console . log (
107- "[FastFetch] Stored in-flight request with signature:" ,
108- signature ,
109- ) ;
110- }
111- try {
112- const result = await promise ;
113- return result ;
114- } finally {
115- // Once done (success or fail), remove from inFlightMap
43+ // Build a promise chain that tries up to retries + 1 times with exponential backoff
44+ let attempt = 0 ;
45+ let promise = ( async function fetchWithRetry ( ) {
46+ while ( true ) {
47+ try {
48+ attempt ++ ;
49+ console . log ( `[FastFetch] Attempt #${ attempt } for:` , input ) ;
50+ const response = await fetch ( input , init ) ;
51+ if ( ! response . ok && shouldRetry ) {
52+ const doRetry = shouldRetry ( response , attempt ) ;
53+ console . log ( `[FastFetch] Response not ok (status: ${ response . status } ). Retry decision: ${ doRetry } ` ) ;
54+ if ( doRetry && attempt <= retries ) {
55+ const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
56+ console . log ( `[FastFetch] Waiting ${ delay } ms (exponential backoff) before retrying...` ) ;
57+ await sleep ( delay ) ;
58+ continue ; // try again
59+ }
60+ }
61+ console . log ( `[FastFetch] Request succeeded on attempt #${ attempt } ` ) ;
62+ return response ;
63+ }
64+ catch ( error ) {
65+ console . log ( `[FastFetch] Caught error on attempt #${ attempt } :` , error ) ;
66+ if ( shouldRetry ) {
67+ const doRetry = shouldRetry ( error , attempt ) ;
68+ console . log ( `[FastFetch] Retry decision based on error: ${ doRetry } ` ) ;
69+ if ( doRetry && attempt <= retries ) {
70+ const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
71+ console . log ( `[FastFetch] Waiting ${ delay } ms (exponential backoff) before retrying after error...` ) ;
72+ await sleep ( delay ) ;
73+ continue ;
74+ }
75+ }
76+ else {
77+ if ( attempt <= retries ) {
78+ const delay = retryDelay * Math . pow ( 2 , attempt - 1 ) ;
79+ console . log ( `[FastFetch] Retrying attempt #${ attempt } after error. Waiting ${ delay } ms...` ) ;
80+ await sleep ( delay ) ;
81+ continue ;
82+ }
83+ }
84+ console . log ( "[FastFetch] No more retries. Throwing error." ) ;
85+ throw error ;
86+ }
87+ }
88+ } ) ( ) ;
89+ // If deduplicating, store in the map so subsequent calls get the same promise
11690 if ( deduplicate ) {
117- inFlightMap . delete ( signature ) ;
118- console . log (
119- "[FastFetch] Removed in-flight record for signature:" ,
120- signature ,
121- ) ;
91+ inFlightMap . set ( signature , promise ) ;
92+ console . log ( "[FastFetch] Stored in-flight request with signature:" , signature ) ;
93+ }
94+ try {
95+ const result = await promise ;
96+ return result ;
97+ }
98+ finally {
99+ // Once done (success or fail), remove from inFlightMap
100+ if ( deduplicate ) {
101+ inFlightMap . delete ( signature ) ;
102+ console . log ( "[FastFetch] Removed in-flight record for signature:" , signature ) ;
103+ }
122104 }
123- }
124105}
0 commit comments