@elementor/http-client 4.1.0-730 → 4.1.0-731

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -44,6 +44,9 @@ var import_env = require("@elementor/env");
44
44
  var { env } = (0, import_env.parseEnv)("@elementor/http-client");
45
45
 
46
46
  // src/http.ts
47
+ var MAX_RETRIES = 3;
48
+ var BASE_DELAY_MS = 1e3;
49
+ var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["get", "head", "options", "put", "delete"]);
47
50
  var instance;
48
51
  var httpService = () => {
49
52
  if (!instance) {
@@ -55,9 +58,48 @@ var httpService = () => {
55
58
  ...env.headers
56
59
  }
57
60
  });
61
+ instance.interceptors.response.use(
62
+ (response) => response,
63
+ async (error) => {
64
+ const config = error.config;
65
+ if (!config || !shouldRetry(error)) {
66
+ return Promise.reject(error);
67
+ }
68
+ const retryCount = config.__retryCount ?? 0;
69
+ if (retryCount >= MAX_RETRIES) {
70
+ return Promise.reject(error);
71
+ }
72
+ const baseDelay = BASE_DELAY_MS * Math.pow(2, retryCount);
73
+ const jitter = Math.random() * BASE_DELAY_MS * 0.1;
74
+ await sleep(baseDelay + jitter);
75
+ const baseTimeout = config.__baseTimeout ?? config.timeout ?? 1e4;
76
+ return instance({
77
+ ...config,
78
+ __retryCount: retryCount + 1,
79
+ __baseTimeout: baseTimeout,
80
+ timeout: baseTimeout * (retryCount + 2)
81
+ });
82
+ }
83
+ );
58
84
  }
59
85
  return instance;
60
86
  };
87
+ function shouldRetry(error) {
88
+ const method = error.config?.method?.toLowerCase();
89
+ if (method && !RETRYABLE_METHODS.has(method)) {
90
+ return false;
91
+ }
92
+ if (!error.response) {
93
+ return true;
94
+ }
95
+ if (error.response.status === 429) {
96
+ return true;
97
+ }
98
+ return error.response.status >= 500;
99
+ }
100
+ function sleep(ms) {
101
+ return new Promise((resolve) => setTimeout(resolve, ms));
102
+ }
61
103
  // Annotate the CommonJS export names for ESM import in node:
62
104
  0 && (module.exports = {
63
105
  AxiosError,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/http.ts","../src/env.ts"],"sourcesContent":["export { type AxiosResponse, AxiosError } from 'axios';\nexport { type HttpResponse, httpService } from './http';\n","import axios, { type AxiosInstance } from 'axios';\n\nimport { env } from './env';\n\nexport type HttpResponse< TData, TMeta = Record< string, unknown > > = {\n\tdata: TData;\n\tmeta: TMeta;\n};\n\nlet instance: AxiosInstance;\n\nexport const httpService = () => {\n\tif ( ! instance ) {\n\t\tinstance = axios.create( {\n\t\t\tbaseURL: env.base_url,\n\t\t\ttimeout: 10000,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...env.headers,\n\t\t\t},\n\t\t} );\n\t}\n\n\treturn instance;\n};\n","import { parseEnv } from '@elementor/env';\n\nexport const { env } = parseEnv< {\n\tbase_url: string;\n\theaders: Record< string, string >;\n} >( '@elementor/http-client' );\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAA+C;;;ACA/C,mBAA0C;;;ACA1C,iBAAyB;AAElB,IAAM,EAAE,IAAI,QAAI,qBAGlB,wBAAyB;;;ADI9B,IAAI;AAEG,IAAM,cAAc,MAAM;AAChC,MAAK,CAAE,UAAW;AACjB,eAAW,aAAAC,QAAM,OAAQ;AAAA,MACxB,SAAS,IAAI;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,GAAG,IAAI;AAAA,MACR;AAAA,IACD,CAAE;AAAA,EACH;AAEA,SAAO;AACR;","names":["import_axios","axios"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/http.ts","../src/env.ts"],"sourcesContent":["export { type AxiosResponse, AxiosError } from 'axios';\nexport { type HttpResponse, httpService } from './http';\n","import axios, { type AxiosError, type AxiosInstance } from 'axios';\n\nimport { env } from './env';\n\nexport type HttpResponse< TData, TMeta = Record< string, unknown > > = {\n\tdata: TData;\n\tmeta: TMeta;\n};\n\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 1000;\n\n// Only idempotent / safe methods are retried. POST and PATCH are excluded because\n// a 500 may arrive after the server partially completed the operation, and retrying\n// could produce duplicates (e.g. create, lock, archive endpoints).\nconst RETRYABLE_METHODS = new Set( [ 'get', 'head', 'options', 'put', 'delete' ] );\n\nlet instance: AxiosInstance;\n\nexport const httpService = () => {\n\tif ( ! instance ) {\n\t\tinstance = axios.create( {\n\t\t\tbaseURL: env.base_url,\n\t\t\ttimeout: 10000,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...env.headers,\n\t\t\t},\n\t\t} );\n\n\t\tinstance.interceptors.response.use(\n\t\t\t( response ) => response,\n\t\t\tasync ( error: AxiosError ) => {\n\t\t\t\tconst config = error.config as typeof error.config & {\n\t\t\t\t\t__retryCount?: number;\n\t\t\t\t\t__baseTimeout?: number;\n\t\t\t\t};\n\n\t\t\t\tif ( ! config || ! shouldRetry( error ) ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\tconst retryCount = config.__retryCount ?? 0;\n\n\t\t\t\tif ( retryCount >= MAX_RETRIES ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\tconst baseDelay = BASE_DELAY_MS * Math.pow( 2, retryCount );\n\t\t\t\tconst jitter = Math.random() * BASE_DELAY_MS * 0.1;\n\t\t\t\tawait sleep( baseDelay + jitter );\n\n\t\t\t\tconst baseTimeout = config.__baseTimeout ?? config.timeout ?? 10000;\n\n\t\t\t\treturn instance( {\n\t\t\t\t\t...config,\n\t\t\t\t\t__retryCount: retryCount + 1,\n\t\t\t\t\t__baseTimeout: baseTimeout,\n\t\t\t\t\ttimeout: baseTimeout * ( retryCount + 2 ),\n\t\t\t\t} as typeof config );\n\t\t\t}\n\t\t);\n\t}\n\n\treturn instance;\n};\n\nfunction shouldRetry( error: AxiosError ): boolean {\n\tconst method = error.config?.method?.toLowerCase();\n\tif ( method && ! RETRYABLE_METHODS.has( method ) ) {\n\t\treturn false;\n\t}\n\n\tif ( ! error.response ) {\n\t\treturn true;\n\t}\n\t// 429 Too Many Requests: transient rate-limiting, backoff helps\n\tif ( error.response.status === 429 ) {\n\t\treturn true;\n\t}\n\treturn error.response.status >= 500;\n}\n\nfunction sleep( ms: number ): Promise< void > {\n\treturn new Promise( ( resolve ) => setTimeout( resolve, ms ) );\n}\n","import { parseEnv } from '@elementor/env';\n\nexport const { env } = parseEnv< {\n\tbase_url: string;\n\theaders: Record< string, string >;\n} >( '@elementor/http-client' );\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAA+C;;;ACA/C,mBAA2D;;;ACA3D,iBAAyB;AAElB,IAAM,EAAE,IAAI,QAAI,qBAGlB,wBAAyB;;;ADI9B,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAKtB,IAAM,oBAAoB,oBAAI,IAAK,CAAE,OAAO,QAAQ,WAAW,OAAO,QAAS,CAAE;AAEjF,IAAI;AAEG,IAAM,cAAc,MAAM;AAChC,MAAK,CAAE,UAAW;AACjB,eAAW,aAAAC,QAAM,OAAQ;AAAA,MACxB,SAAS,IAAI;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,GAAG,IAAI;AAAA,MACR;AAAA,IACD,CAAE;AAEF,aAAS,aAAa,SAAS;AAAA,MAC9B,CAAE,aAAc;AAAA,MAChB,OAAQ,UAAuB;AAC9B,cAAM,SAAS,MAAM;AAKrB,YAAK,CAAE,UAAU,CAAE,YAAa,KAAM,GAAI;AACzC,iBAAO,QAAQ,OAAQ,KAAM;AAAA,QAC9B;AAEA,cAAM,aAAa,OAAO,gBAAgB;AAE1C,YAAK,cAAc,aAAc;AAChC,iBAAO,QAAQ,OAAQ,KAAM;AAAA,QAC9B;AAEA,cAAM,YAAY,gBAAgB,KAAK,IAAK,GAAG,UAAW;AAC1D,cAAM,SAAS,KAAK,OAAO,IAAI,gBAAgB;AAC/C,cAAM,MAAO,YAAY,MAAO;AAEhC,cAAM,cAAc,OAAO,iBAAiB,OAAO,WAAW;AAE9D,eAAO,SAAU;AAAA,UAChB,GAAG;AAAA,UACH,cAAc,aAAa;AAAA,UAC3B,eAAe;AAAA,UACf,SAAS,eAAgB,aAAa;AAAA,QACvC,CAAmB;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAEA,SAAS,YAAa,OAA6B;AAClD,QAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY;AACjD,MAAK,UAAU,CAAE,kBAAkB,IAAK,MAAO,GAAI;AAClD,WAAO;AAAA,EACR;AAEA,MAAK,CAAE,MAAM,UAAW;AACvB,WAAO;AAAA,EACR;AAEA,MAAK,MAAM,SAAS,WAAW,KAAM;AACpC,WAAO;AAAA,EACR;AACA,SAAO,MAAM,SAAS,UAAU;AACjC;AAEA,SAAS,MAAO,IAA8B;AAC7C,SAAO,IAAI,QAAS,CAAE,YAAa,WAAY,SAAS,EAAG,CAAE;AAC9D;","names":["import_axios","axios"]}
package/dist/index.mjs CHANGED
@@ -9,6 +9,9 @@ import { parseEnv } from "@elementor/env";
9
9
  var { env } = parseEnv("@elementor/http-client");
10
10
 
11
11
  // src/http.ts
12
+ var MAX_RETRIES = 3;
13
+ var BASE_DELAY_MS = 1e3;
14
+ var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["get", "head", "options", "put", "delete"]);
12
15
  var instance;
13
16
  var httpService = () => {
14
17
  if (!instance) {
@@ -20,9 +23,48 @@ var httpService = () => {
20
23
  ...env.headers
21
24
  }
22
25
  });
26
+ instance.interceptors.response.use(
27
+ (response) => response,
28
+ async (error) => {
29
+ const config = error.config;
30
+ if (!config || !shouldRetry(error)) {
31
+ return Promise.reject(error);
32
+ }
33
+ const retryCount = config.__retryCount ?? 0;
34
+ if (retryCount >= MAX_RETRIES) {
35
+ return Promise.reject(error);
36
+ }
37
+ const baseDelay = BASE_DELAY_MS * Math.pow(2, retryCount);
38
+ const jitter = Math.random() * BASE_DELAY_MS * 0.1;
39
+ await sleep(baseDelay + jitter);
40
+ const baseTimeout = config.__baseTimeout ?? config.timeout ?? 1e4;
41
+ return instance({
42
+ ...config,
43
+ __retryCount: retryCount + 1,
44
+ __baseTimeout: baseTimeout,
45
+ timeout: baseTimeout * (retryCount + 2)
46
+ });
47
+ }
48
+ );
23
49
  }
24
50
  return instance;
25
51
  };
52
+ function shouldRetry(error) {
53
+ const method = error.config?.method?.toLowerCase();
54
+ if (method && !RETRYABLE_METHODS.has(method)) {
55
+ return false;
56
+ }
57
+ if (!error.response) {
58
+ return true;
59
+ }
60
+ if (error.response.status === 429) {
61
+ return true;
62
+ }
63
+ return error.response.status >= 500;
64
+ }
65
+ function sleep(ms) {
66
+ return new Promise((resolve) => setTimeout(resolve, ms));
67
+ }
26
68
  export {
27
69
  AxiosError,
28
70
  httpService
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/http.ts","../src/env.ts"],"sourcesContent":["export { type AxiosResponse, AxiosError } from 'axios';\nexport { type HttpResponse, httpService } from './http';\n","import axios, { type AxiosInstance } from 'axios';\n\nimport { env } from './env';\n\nexport type HttpResponse< TData, TMeta = Record< string, unknown > > = {\n\tdata: TData;\n\tmeta: TMeta;\n};\n\nlet instance: AxiosInstance;\n\nexport const httpService = () => {\n\tif ( ! instance ) {\n\t\tinstance = axios.create( {\n\t\t\tbaseURL: env.base_url,\n\t\t\ttimeout: 10000,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...env.headers,\n\t\t\t},\n\t\t} );\n\t}\n\n\treturn instance;\n};\n","import { parseEnv } from '@elementor/env';\n\nexport const { env } = parseEnv< {\n\tbase_url: string;\n\theaders: Record< string, string >;\n} >( '@elementor/http-client' );\n"],"mappings":";AAAA,SAA6B,kBAAkB;;;ACA/C,OAAO,WAAmC;;;ACA1C,SAAS,gBAAgB;AAElB,IAAM,EAAE,IAAI,IAAI,SAGlB,wBAAyB;;;ADI9B,IAAI;AAEG,IAAM,cAAc,MAAM;AAChC,MAAK,CAAE,UAAW;AACjB,eAAW,MAAM,OAAQ;AAAA,MACxB,SAAS,IAAI;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,GAAG,IAAI;AAAA,MACR;AAAA,IACD,CAAE;AAAA,EACH;AAEA,SAAO;AACR;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/http.ts","../src/env.ts"],"sourcesContent":["export { type AxiosResponse, AxiosError } from 'axios';\nexport { type HttpResponse, httpService } from './http';\n","import axios, { type AxiosError, type AxiosInstance } from 'axios';\n\nimport { env } from './env';\n\nexport type HttpResponse< TData, TMeta = Record< string, unknown > > = {\n\tdata: TData;\n\tmeta: TMeta;\n};\n\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 1000;\n\n// Only idempotent / safe methods are retried. POST and PATCH are excluded because\n// a 500 may arrive after the server partially completed the operation, and retrying\n// could produce duplicates (e.g. create, lock, archive endpoints).\nconst RETRYABLE_METHODS = new Set( [ 'get', 'head', 'options', 'put', 'delete' ] );\n\nlet instance: AxiosInstance;\n\nexport const httpService = () => {\n\tif ( ! instance ) {\n\t\tinstance = axios.create( {\n\t\t\tbaseURL: env.base_url,\n\t\t\ttimeout: 10000,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t...env.headers,\n\t\t\t},\n\t\t} );\n\n\t\tinstance.interceptors.response.use(\n\t\t\t( response ) => response,\n\t\t\tasync ( error: AxiosError ) => {\n\t\t\t\tconst config = error.config as typeof error.config & {\n\t\t\t\t\t__retryCount?: number;\n\t\t\t\t\t__baseTimeout?: number;\n\t\t\t\t};\n\n\t\t\t\tif ( ! config || ! shouldRetry( error ) ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\tconst retryCount = config.__retryCount ?? 0;\n\n\t\t\t\tif ( retryCount >= MAX_RETRIES ) {\n\t\t\t\t\treturn Promise.reject( error );\n\t\t\t\t}\n\n\t\t\t\tconst baseDelay = BASE_DELAY_MS * Math.pow( 2, retryCount );\n\t\t\t\tconst jitter = Math.random() * BASE_DELAY_MS * 0.1;\n\t\t\t\tawait sleep( baseDelay + jitter );\n\n\t\t\t\tconst baseTimeout = config.__baseTimeout ?? config.timeout ?? 10000;\n\n\t\t\t\treturn instance( {\n\t\t\t\t\t...config,\n\t\t\t\t\t__retryCount: retryCount + 1,\n\t\t\t\t\t__baseTimeout: baseTimeout,\n\t\t\t\t\ttimeout: baseTimeout * ( retryCount + 2 ),\n\t\t\t\t} as typeof config );\n\t\t\t}\n\t\t);\n\t}\n\n\treturn instance;\n};\n\nfunction shouldRetry( error: AxiosError ): boolean {\n\tconst method = error.config?.method?.toLowerCase();\n\tif ( method && ! RETRYABLE_METHODS.has( method ) ) {\n\t\treturn false;\n\t}\n\n\tif ( ! error.response ) {\n\t\treturn true;\n\t}\n\t// 429 Too Many Requests: transient rate-limiting, backoff helps\n\tif ( error.response.status === 429 ) {\n\t\treturn true;\n\t}\n\treturn error.response.status >= 500;\n}\n\nfunction sleep( ms: number ): Promise< void > {\n\treturn new Promise( ( resolve ) => setTimeout( resolve, ms ) );\n}\n","import { parseEnv } from '@elementor/env';\n\nexport const { env } = parseEnv< {\n\tbase_url: string;\n\theaders: Record< string, string >;\n} >( '@elementor/http-client' );\n"],"mappings":";AAAA,SAA6B,kBAAkB;;;ACA/C,OAAO,WAAoD;;;ACA3D,SAAS,gBAAgB;AAElB,IAAM,EAAE,IAAI,IAAI,SAGlB,wBAAyB;;;ADI9B,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAKtB,IAAM,oBAAoB,oBAAI,IAAK,CAAE,OAAO,QAAQ,WAAW,OAAO,QAAS,CAAE;AAEjF,IAAI;AAEG,IAAM,cAAc,MAAM;AAChC,MAAK,CAAE,UAAW;AACjB,eAAW,MAAM,OAAQ;AAAA,MACxB,SAAS,IAAI;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,GAAG,IAAI;AAAA,MACR;AAAA,IACD,CAAE;AAEF,aAAS,aAAa,SAAS;AAAA,MAC9B,CAAE,aAAc;AAAA,MAChB,OAAQ,UAAuB;AAC9B,cAAM,SAAS,MAAM;AAKrB,YAAK,CAAE,UAAU,CAAE,YAAa,KAAM,GAAI;AACzC,iBAAO,QAAQ,OAAQ,KAAM;AAAA,QAC9B;AAEA,cAAM,aAAa,OAAO,gBAAgB;AAE1C,YAAK,cAAc,aAAc;AAChC,iBAAO,QAAQ,OAAQ,KAAM;AAAA,QAC9B;AAEA,cAAM,YAAY,gBAAgB,KAAK,IAAK,GAAG,UAAW;AAC1D,cAAM,SAAS,KAAK,OAAO,IAAI,gBAAgB;AAC/C,cAAM,MAAO,YAAY,MAAO;AAEhC,cAAM,cAAc,OAAO,iBAAiB,OAAO,WAAW;AAE9D,eAAO,SAAU;AAAA,UAChB,GAAG;AAAA,UACH,cAAc,aAAa;AAAA,UAC3B,eAAe;AAAA,UACf,SAAS,eAAgB,aAAa;AAAA,QACvC,CAAmB;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAEA,SAAS,YAAa,OAA6B;AAClD,QAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY;AACjD,MAAK,UAAU,CAAE,kBAAkB,IAAK,MAAO,GAAI;AAClD,WAAO;AAAA,EACR;AAEA,MAAK,CAAE,MAAM,UAAW;AACvB,WAAO;AAAA,EACR;AAEA,MAAK,MAAM,SAAS,WAAW,KAAM;AACpC,WAAO;AAAA,EACR;AACA,SAAO,MAAM,SAAS,UAAU;AACjC;AAEA,SAAS,MAAO,IAA8B;AAC7C,SAAO,IAAI,QAAS,CAAE,YAAa,WAAY,SAAS,EAAG,CAAE;AAC9D;","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/http-client",
3
3
  "description": "Provides a simple way to make HTTP requests",
4
- "version": "4.1.0-730",
4
+ "version": "4.1.0-731",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,7 +40,7 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/env": "4.1.0-730",
43
+ "@elementor/env": "4.1.0-731",
44
44
  "axios": "^1.9.0"
45
45
  },
46
46
  "devDependencies": {
package/src/http.ts CHANGED
@@ -1,4 +1,4 @@
1
- import axios, { type AxiosInstance } from 'axios';
1
+ import axios, { type AxiosError, type AxiosInstance } from 'axios';
2
2
 
3
3
  import { env } from './env';
4
4
 
@@ -7,6 +7,14 @@ export type HttpResponse< TData, TMeta = Record< string, unknown > > = {
7
7
  meta: TMeta;
8
8
  };
9
9
 
10
+ const MAX_RETRIES = 3;
11
+ const BASE_DELAY_MS = 1000;
12
+
13
+ // Only idempotent / safe methods are retried. POST and PATCH are excluded because
14
+ // a 500 may arrive after the server partially completed the operation, and retrying
15
+ // could produce duplicates (e.g. create, lock, archive endpoints).
16
+ const RETRYABLE_METHODS = new Set( [ 'get', 'head', 'options', 'put', 'delete' ] );
17
+
10
18
  let instance: AxiosInstance;
11
19
 
12
20
  export const httpService = () => {
@@ -19,7 +27,60 @@ export const httpService = () => {
19
27
  ...env.headers,
20
28
  },
21
29
  } );
30
+
31
+ instance.interceptors.response.use(
32
+ ( response ) => response,
33
+ async ( error: AxiosError ) => {
34
+ const config = error.config as typeof error.config & {
35
+ __retryCount?: number;
36
+ __baseTimeout?: number;
37
+ };
38
+
39
+ if ( ! config || ! shouldRetry( error ) ) {
40
+ return Promise.reject( error );
41
+ }
42
+
43
+ const retryCount = config.__retryCount ?? 0;
44
+
45
+ if ( retryCount >= MAX_RETRIES ) {
46
+ return Promise.reject( error );
47
+ }
48
+
49
+ const baseDelay = BASE_DELAY_MS * Math.pow( 2, retryCount );
50
+ const jitter = Math.random() * BASE_DELAY_MS * 0.1;
51
+ await sleep( baseDelay + jitter );
52
+
53
+ const baseTimeout = config.__baseTimeout ?? config.timeout ?? 10000;
54
+
55
+ return instance( {
56
+ ...config,
57
+ __retryCount: retryCount + 1,
58
+ __baseTimeout: baseTimeout,
59
+ timeout: baseTimeout * ( retryCount + 2 ),
60
+ } as typeof config );
61
+ }
62
+ );
22
63
  }
23
64
 
24
65
  return instance;
25
66
  };
67
+
68
+ function shouldRetry( error: AxiosError ): boolean {
69
+ const method = error.config?.method?.toLowerCase();
70
+ if ( method && ! RETRYABLE_METHODS.has( method ) ) {
71
+ return false;
72
+ }
73
+
74
+ if ( ! error.response ) {
75
+ return true;
76
+ }
77
+ // 429 Too Many Requests: transient rate-limiting, backoff helps
78
+ if ( error.response.status === 429 ) {
79
+ return true;
80
+ }
81
+ return error.response.status >= 500;
82
+ }
83
+
84
+ function sleep( ms: number ): Promise< void > {
85
+ return new Promise( ( resolve ) => setTimeout( resolve, ms ) );
86
+ }