@@ -7,12 +7,35 @@ import { type Article, type RemoteArticleData, type ArticleStats } from './model
77const debug = Debug ( 'devto' ) ;
88const apiUrl = 'https://dev.to/api' ;
99const paginationLimit = 1000 ;
10+ const maxRetries = 3 ;
11+ const retryDelay = 1000 ; // 1 second delay before retrying
1012
1113// There's a limit of 10 articles created each 30 seconds by the same user,
1214// so we need to throttle the API calls in that case.
1315// The insane type casting is due to typing issues with p-throttle.
1416const throttledPostForCreate = pThrottle ( { limit : 10 , interval : 30_500 } ) ( got . post ) as any as Got [ 'post' ] ;
1517
18+ // There's a limit of 30 requests each 30 seconds by the same user, so we need to throttle the API calls in that case too.
19+ const throttledPutForUpdate = pThrottle ( { limit : 30 , interval : 30_500 } ) (
20+ async ( url : string , options : any ) => got . put ( url , options )
21+ ) as any as Got [ 'put' ] ;
22+
23+ async function delay ( ms : number ) : Promise < void > {
24+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
25+ }
26+
27+ async function retryRequest ( fn : ( ) => Promise < RemoteArticleData > , retries : number ) : Promise < RemoteArticleData > {
28+ try {
29+ return await fn ( ) ;
30+ } catch ( error ) {
31+ if ( retries === 0 || ! ( error instanceof RequestError && error . response ?. statusCode === 429 ) ) {
32+ throw error ;
33+ }
34+ await delay ( retryDelay ) ;
35+ return retryRequest ( fn , retries - 1 ) ;
36+ }
37+ }
38+
1639export async function getAllArticles ( devtoKey : string ) : Promise < RemoteArticleData [ ] > {
1740 try {
1841 const articles = [ ] ;
@@ -69,22 +92,26 @@ export async function getLastArticlesStats(devtoKey: string, number: number): Pr
6992}
7093
7194export async function updateRemoteArticle ( article : Article , devtoKey : string ) : Promise < RemoteArticleData > {
72- try {
73- const markdown = matter . stringify ( article , article . data , { lineWidth : - 1 } as any ) ;
74- const { id } = article . data ;
75- // Throttle API calls in case of article creation
76- const get = id ? got . put : throttledPostForCreate ;
77- const result = await get ( `${ apiUrl } /articles${ id ? `/${ id } ` : '' } ` , {
78- headers : { 'api-key' : devtoKey } ,
79- json : { article : { title : article . data . title , body_markdown : markdown } } ,
80- responseType : 'json'
81- } ) ;
82- return result . body as RemoteArticleData ;
83- } catch ( error ) {
84- if ( error instanceof RequestError && error . response ) {
85- debug ( 'Debug infos: %O' , error . response . body ) ;
95+ const update = async ( ) : Promise < RemoteArticleData > => {
96+ try {
97+ const markdown = matter . stringify ( article , article . data , { lineWidth : - 1 } as any ) ;
98+ const { id } = article . data ;
99+ // Throttle API calls in case of article creation
100+ const get = id ? throttledPutForUpdate : throttledPostForCreate ;
101+ const result = await get ( `${ apiUrl } /articles${ id ? `/${ id } ` : '' } ` , {
102+ headers : { 'api-key' : devtoKey } ,
103+ json : { article : { title : article . data . title , body_markdown : markdown } } ,
104+ responseType : 'json'
105+ } ) ;
106+ return result . body as RemoteArticleData ;
107+ } catch ( error ) {
108+ if ( error instanceof RequestError && error . response ) {
109+ debug ( 'Debug infos: %O' , error . response . body ) ;
110+ }
111+
112+ throw error ;
86113 }
114+ } ;
87115
88- throw error ;
89- }
116+ return retryRequest ( update , maxRetries ) ;
90117}
0 commit comments