UNPKG

list-dependents

Version:

Lists all dependents of a project, using npm or ecosyste.ms

123 lines (101 loc) 3 kB
import { setTimeout as setTimeoutPromise } from 'node:timers/promises'; import { Sema } from 'async-sema'; import got from 'got'; /** * @param {{ concurrency?: number, logger?: import('bunyan-adaptor').BunyanLite | undefined }} [options] * @returns {import('got').Got} */ export function gotQueue ({ concurrency = 10, logger } = {}) { /** * Is initialized to a truthy value 1 to ensure that we start out in non-parallel mode * * Once the first successful requests has resolved, then the parallel fetches will * start to be allowed to happen * * @type {number|undefined} */ let retryAt = 1; const retry = new Sema(1); const parallel = new Sema(concurrency); return got.extend({ retry: { backoffLimit: 5000, limit: 5, }, hooks: { beforeRequest: [ async ({ isStream }) => { if (isStream) { throw new Error('Streams are not supported by gotQueue()'); } await parallel.acquire(); if (retryAt) { await retry.acquire(); /** @type {number} */ let waitTime = retryAt - Date.now(); while (waitTime > 0) { logger && logger.warn(`Waiting for ${waitTime} ms before sending next request`); await setTimeoutPromise(waitTime); waitTime = retryAt - Date.now(); } } }, ], afterResponse: [ (response) => { const isRetry = !retry.tryAcquire(); retry.release(); parallel.release(); if (response.statusCode === 429 || response.statusCode === 503) { const retryAfter = getRetryAfter(response); if (retryAfter) { retryAt = Math.max(Date.now() + retryAfter, retryAt || 0); } delete response.headers['retry-after']; } else if (isRetry) { retryAt = undefined; } return response; }, ], beforeRetry: [ error => { if (!error.response) { retry.release(); parallel.release(); } }, ], beforeError: [ error => { if (!error.response) { retry.release(); parallel.release(); } return error; }, ], }, }); } /** * Largely copied from https://github.com/sindresorhus/got/blob/4a44fc40439003e94975e6425b021545b0faaa9a/source/core/index.ts#L357 * * @param {import('got').Response} response * @returns {number | undefined} */ function getRetryAfter (response) { if (!('retry-after' in response.headers) || !response.headers['retry-after']) { return; } let retryAfter = Number(response.headers['retry-after']); if (Number.isNaN(retryAfter)) { retryAfter = Date.parse(response.headers['retry-after']) - Date.now(); } else { retryAfter *= 1000; } if (retryAfter <= 0) { retryAfter = 1; } return retryAfter; }