UNPKG

2.54 kBJavaScriptView Raw
1import isString from 'lodash/isString.js';
2import pThrottle from 'p-throttle';
3import { noop } from './utils.js';
4const PERCENTAGE_REGEX = /(?<value>\d+)(%)/;
5function calculateLimit(type, max = 7) {
6 let limit = max;
7 if (PERCENTAGE_REGEX.test(type)) {
8 const groups = type.match(PERCENTAGE_REGEX)?.groups;
9 if (groups && groups.value) {
10 const percentage = parseInt(groups.value) / 100;
11 limit = Math.round(max * percentage);
12 }
13 }
14 return Math.min(30, Math.max(1, limit));
15}
16function createThrottle(limit, logger) {
17 logger('info', `Throttle request to ${limit}/s`);
18 return pThrottle({
19 limit,
20 interval: 1000,
21 strict: false,
22 });
23}
24export default (axiosInstance, type = 'auto') => {
25 const { logHandler = noop } = axiosInstance.defaults;
26 let limit = isString(type) ? calculateLimit(type) : calculateLimit('auto', type);
27 let throttle = createThrottle(limit, logHandler);
28 let isCalculated = false;
29 let requestInterceptorId = axiosInstance.interceptors.request.use((config) => {
30 return throttle(() => config)();
31 }, function (error) {
32 return Promise.reject(error);
33 });
34 const responseInterceptorId = axiosInstance.interceptors.response.use((response) => {
35 if (!isCalculated &&
36 isString(type) &&
37 (type === 'auto' || PERCENTAGE_REGEX.test(type)) &&
38 response.headers &&
39 response.headers['x-contentful-ratelimit-second-limit']) {
40 const rawLimit = parseInt(response.headers['x-contentful-ratelimit-second-limit']);
41 const nextLimit = calculateLimit(type, rawLimit);
42 if (nextLimit !== limit) {
43 if (requestInterceptorId) {
44 axiosInstance.interceptors.request.eject(requestInterceptorId);
45 }
46 limit = nextLimit;
47 throttle = createThrottle(nextLimit, logHandler);
48 requestInterceptorId = axiosInstance.interceptors.request.use((config) => {
49 return throttle(() => config)();
50 }, function (error) {
51 return Promise.reject(error);
52 });
53 }
54 isCalculated = true;
55 }
56 return response;
57 }, function (error) {
58 return Promise.reject(error);
59 });
60 return () => {
61 axiosInstance.interceptors.request.eject(requestInterceptorId);
62 axiosInstance.interceptors.response.eject(responseInterceptorId);
63 };
64};