@@ -2,6 +2,29 @@ import axios from "axios";
22
33const sleep = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
44
5+ /**
6+ * Fetch with retry logic.
7+ * @param {function } fetchFn - Async function to execute
8+ * @param {number } maxRetries - Maximum number of retries (default 3)
9+ * @param {number } baseDelay - Base delay in ms for exponential backoff (default 1000)
10+ * @returns {Promise<*> } - Result of the fetch function
11+ */
12+ const fetchWithRetry = async ( fetchFn , maxRetries = 3 , baseDelay = 1000 ) => {
13+ let lastError ;
14+ for ( let attempt = 0 ; attempt <= maxRetries ; attempt ++ ) {
15+ try {
16+ return await fetchFn ( ) ;
17+ } catch ( error ) {
18+ lastError = error ;
19+ if ( attempt < maxRetries ) {
20+ const delay = baseDelay * Math . pow ( 2 , attempt ) ;
21+ await sleep ( delay ) ;
22+ }
23+ }
24+ }
25+ throw lastError ;
26+ } ;
27+
528/**
629 * Paginated fetch helper that handles limit/offset pagination.
730 * Stops when items.length < limit or offset >= total_count.
@@ -11,21 +34,25 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1134 * @param {object } params - Query parameters (limit will be set automatically)
1235 * @param {string } itemsKey - The key in response.data containing the items array
1336 * @param {number } limit - Page size (default 1000)
37+ * @param {function } onProgress - Optional callback for progress updates (called with items count)
1438 * @returns {Promise<{items: Array, wasClipped: boolean}> }
1539 */
16- export const paginatedFetch = async ( url , params , itemsKey , limit = 1000 ) => {
40+ export const paginatedFetch = async ( url , params , itemsKey , limit = 1000 , onProgress = null ) => {
1741 let items = [ ] ;
1842 let offset = 0 ;
1943 let wasClipped = false ;
44+ let pageNum = 1 ;
2045
2146 while ( true ) {
22- const response = await axios . get ( url , {
23- params : {
24- ...params ,
25- limit,
26- offset,
27- } ,
28- } ) ;
47+ const response = await fetchWithRetry ( ( ) =>
48+ axios . get ( url , {
49+ params : {
50+ ...params ,
51+ limit,
52+ offset,
53+ } ,
54+ } )
55+ ) ;
2956
3057 const pageItems = response . data [ itemsKey ] || [ ] ;
3158 items = [ ...items , ...pageItems ] ;
@@ -35,6 +62,11 @@ export const paginatedFetch = async (url, params, itemsKey, limit = 1000) => {
3562 wasClipped = true ;
3663 }
3764
65+ // Report progress if callback provided
66+ if ( onProgress ) {
67+ onProgress ( items . length , pageNum ) ;
68+ }
69+
3870 // Break if we got fewer than the limit (last page)
3971 // Note: When is_total_count_clipped is true, total_count is capped (often at 1000),
4072 // so we can't rely on offset >= total_count to know we're done.
@@ -44,6 +76,7 @@ export const paginatedFetch = async (url, params, itemsKey, limit = 1000) => {
4476 }
4577
4678 offset += pageItems . length ;
79+ pageNum ++ ;
4780 await sleep ( 100 ) ;
4881 }
4982
0 commit comments