UNPKG

2.16 kBJavaScriptView Raw
1const {URL} = require('url');
2const {memoize, get} = require('lodash');
3const Octokit = require('@octokit/rest');
4const pRetry = require('p-retry');
5const Bottleneck = require('bottleneck');
6const urljoin = require('url-join');
7const HttpProxyAgent = require('http-proxy-agent');
8const HttpsProxyAgent = require('https-proxy-agent');
9
10const {RETRY_CONF, RATE_LIMITS, GLOBAL_RATE_LIMIT} = require('./definitions/rate-limit');
11
12/**
13 * Http error status for which to not retry.
14 */
15const SKIP_RETRY_CODES = [400, 401, 403];
16
17/**
18 * Create or retrieve the throttler function for a given rate limit group.
19 *
20 * @param {Array} rate The rate limit group.
21 * @param {String} limit The rate limits per API endpoints.
22 * @param {Bottleneck} globalThrottler The global throttler.
23 *
24 * @return {Bottleneck} The throller function for the given rate limit group.
25 */
26const getThrottler = memoize((rate, globalThrottler) =>
27 new Bottleneck({minTime: get(RATE_LIMITS, rate)}).chain(globalThrottler)
28);
29
30module.exports = ({githubToken, githubUrl, githubApiPathPrefix, proxy}) => {
31 const baseUrl = githubUrl && urljoin(githubUrl, githubApiPathPrefix);
32 const globalThrottler = new Bottleneck({minTime: GLOBAL_RATE_LIMIT});
33 const github = new Octokit({
34 auth: `token ${githubToken}`,
35 baseUrl,
36 request: {
37 agent: proxy
38 ? baseUrl && new URL(baseUrl).protocol.replace(':', '') === 'http'
39 ? new HttpProxyAgent(proxy)
40 : new HttpsProxyAgent(proxy)
41 : undefined,
42 },
43 });
44
45 github.hook.wrap('request', (request, options) => {
46 const access = options.method === 'GET' ? 'read' : 'write';
47 const rateCategory = options.url.startsWith('/search') ? 'search' : 'core';
48 const limitKey = [rateCategory, RATE_LIMITS[rateCategory][access] && access].filter(Boolean).join('.');
49
50 return pRetry(async () => {
51 try {
52 return await getThrottler(limitKey, globalThrottler).wrap(request)(options);
53 } catch (error) {
54 if (SKIP_RETRY_CODES.includes(error.status)) {
55 throw new pRetry.AbortError(error);
56 }
57
58 throw error;
59 }
60 }, RETRY_CONF);
61 });
62
63 return github;
64};