-
Notifications
You must be signed in to change notification settings - Fork 168
Expand file tree
/
Copy pathfetch.js
More file actions
58 lines (55 loc) · 1.53 KB
/
fetch.js
File metadata and controls
58 lines (55 loc) · 1.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import fetch from '@web-std/fetch'
import retry from 'p-retry'
import debug from 'debug'
import { hasOwnProperty } from './utils.js'
const log = debug('fetchJSON')
const REQUEST_TIMEOUT = 60000
const RETRY_INTERVAL = 60000
const RETRY_ATTEMPTS = 5
/**
* @param {import('limiter').RateLimiter} limiter
* @param {string} url
* @param {RequestInit} [init]
* @returns {Promise<unknown>}
*/
export async function fetchJSON(limiter, url, init) {
await limiter.removeTokens(1)
const res = await retry(
async () => {
const controller = new AbortController()
const abortID = setTimeout(() => controller.abort(), REQUEST_TIMEOUT)
init = init || {}
init.signal = controller.signal
try {
const res = await fetch(url, init)
const text = await res.text()
if (!res.ok) {
throw Object.assign(
new Error(`${res.status} ${res.statusText}: ${text}`),
{ response: res }
)
}
return text === '' ? null : /** @type {unknown} */ (JSON.parse(text))
} finally {
clearTimeout(abortID)
}
},
{
onFailedAttempt: async (err) => {
if (
hasOwnProperty(err, 'response') &&
hasOwnProperty(err.response, 'status') &&
err.response.status === 429
) {
log(`🚦 rate limited ${url}`)
} else {
log(`💥 fetch ${url}`, err)
}
await limiter.removeTokens(1)
},
retries: RETRY_ATTEMPTS,
minTimeout: RETRY_INTERVAL,
}
)
return res
}