|
@@ -5,6 +5,12 @@ const fetch = require('node-fetch')
|
|
|
const http = require('node:http')
|
|
const http = require('node:http')
|
|
|
const https = require('node:https')
|
|
const https = require('node:https')
|
|
|
|
|
|
|
|
|
|
+let logger
|
|
|
|
|
+
|
|
|
|
|
+function setLogger(loggerInstance) {
|
|
|
|
|
+ logger = loggerInstance
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* @import { Response } from 'node-fetch'
|
|
* @import { Response } from 'node-fetch'
|
|
|
*/
|
|
*/
|
|
@@ -23,7 +29,7 @@ async function fetchJson(url, opts = {}) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function fetchJsonWithResponse(url, opts = {}) {
|
|
async function fetchJsonWithResponse(url, opts = {}) {
|
|
|
- const { fetchOpts, detachSignal } = parseOpts(opts)
|
|
|
|
|
|
|
+ const { fetchOpts, detachSignal } = parseOpts(opts, url)
|
|
|
fetchOpts.headers = fetchOpts.headers ?? {}
|
|
fetchOpts.headers = fetchOpts.headers ?? {}
|
|
|
fetchOpts.headers.Accept = fetchOpts.headers.Accept ?? 'application/json'
|
|
fetchOpts.headers.Accept = fetchOpts.headers.Accept ?? 'application/json'
|
|
|
|
|
|
|
@@ -53,7 +59,7 @@ async function fetchStream(url, opts = {}) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function fetchStreamWithResponse(url, opts = {}) {
|
|
async function fetchStreamWithResponse(url, opts = {}) {
|
|
|
- const { fetchOpts, abortController, detachSignal } = parseOpts(opts)
|
|
|
|
|
|
|
+ const { fetchOpts, abortController, detachSignal } = parseOpts(opts, url)
|
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
if (!response.ok) {
|
|
@@ -76,7 +82,7 @@ async function fetchStreamWithResponse(url, opts = {}) {
|
|
|
* @throws {RequestFailedError} if the response has a failure status code
|
|
* @throws {RequestFailedError} if the response has a failure status code
|
|
|
*/
|
|
*/
|
|
|
async function fetchNothing(url, opts = {}) {
|
|
async function fetchNothing(url, opts = {}) {
|
|
|
- const { fetchOpts, detachSignal } = parseOpts(opts)
|
|
|
|
|
|
|
+ const { fetchOpts, detachSignal } = parseOpts(opts, url)
|
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
|
if (!response.ok) {
|
|
if (!response.ok) {
|
|
|
const body = await maybeGetResponseBody(response)
|
|
const body = await maybeGetResponseBody(response)
|
|
@@ -108,7 +114,7 @@ async function fetchRedirect(url, opts = {}) {
|
|
|
* @throws {RequestFailedError} if the response has a non redirect status code or missing Location header
|
|
* @throws {RequestFailedError} if the response has a non redirect status code or missing Location header
|
|
|
*/
|
|
*/
|
|
|
async function fetchRedirectWithResponse(url, opts = {}) {
|
|
async function fetchRedirectWithResponse(url, opts = {}) {
|
|
|
- const { fetchOpts, detachSignal } = parseOpts(opts)
|
|
|
|
|
|
|
+ const { fetchOpts, detachSignal } = parseOpts(opts, url)
|
|
|
fetchOpts.redirect = 'manual'
|
|
fetchOpts.redirect = 'manual'
|
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
|
if (response.status < 300 || response.status >= 400) {
|
|
if (response.status < 300 || response.status >= 400) {
|
|
@@ -142,7 +148,7 @@ async function fetchString(url, opts = {}) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function fetchStringWithResponse(url, opts = {}) {
|
|
async function fetchStringWithResponse(url, opts = {}) {
|
|
|
- const { fetchOpts, detachSignal } = parseOpts(opts)
|
|
|
|
|
|
|
+ const { fetchOpts, detachSignal } = parseOpts(opts, url)
|
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
const response = await performRequest(url, fetchOpts, detachSignal)
|
|
|
if (!response.ok) {
|
|
if (!response.ok) {
|
|
|
const body = await maybeGetResponseBody(response)
|
|
const body = await maybeGetResponseBody(response)
|
|
@@ -167,7 +173,7 @@ class RequestFailedError extends OError {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function parseOpts(opts) {
|
|
|
|
|
|
|
+function parseOpts(opts, url) {
|
|
|
const fetchOpts = _.omit(opts, ['json', 'signal', 'basicAuth'])
|
|
const fetchOpts = _.omit(opts, ['json', 'signal', 'basicAuth'])
|
|
|
if (opts.json) {
|
|
if (opts.json) {
|
|
|
setupJsonBody(fetchOpts, opts.json)
|
|
setupJsonBody(fetchOpts, opts.json)
|
|
@@ -178,9 +184,21 @@ function parseOpts(opts) {
|
|
|
|
|
|
|
|
const abortController = new AbortController()
|
|
const abortController = new AbortController()
|
|
|
fetchOpts.signal = abortController.signal
|
|
fetchOpts.signal = abortController.signal
|
|
|
- let detachSignal = () => {}
|
|
|
|
|
|
|
+ let detachSignal
|
|
|
if (opts.signal) {
|
|
if (opts.signal) {
|
|
|
detachSignal = abortOnSignal(abortController, opts.signal)
|
|
detachSignal = abortOnSignal(abortController, opts.signal)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const timeout = setTimeout(() => {
|
|
|
|
|
+ if (logger) {
|
|
|
|
|
+ logger.warn(
|
|
|
|
|
+ { url, method: opts.method ?? 'GET' },
|
|
|
|
|
+ 'Fetch request did not complete within 120 seconds'
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 120000)
|
|
|
|
|
+ detachSignal = () => {
|
|
|
|
|
+ clearTimeout(timeout)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
if (opts.body instanceof Readable) {
|
|
if (opts.body instanceof Readable) {
|
|
|
abortOnDestroyedRequest(abortController, fetchOpts.body)
|
|
abortOnDestroyedRequest(abortController, fetchOpts.body)
|
|
@@ -323,4 +341,5 @@ module.exports = {
|
|
|
ConnectTimeoutError,
|
|
ConnectTimeoutError,
|
|
|
CustomHttpAgent,
|
|
CustomHttpAgent,
|
|
|
CustomHttpsAgent,
|
|
CustomHttpsAgent,
|
|
|
|
|
+ setLogger,
|
|
|
}
|
|
}
|