Created
July 25, 2024 12:36
-
-
Save ternavsky/41cb8c1cfc3f4cff31e911c26119f752 to your computer and use it in GitHub Desktop.
deprecated request-promise rewritten to use native "fetch" function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const FormData = require('form-data'); | |
const https = require('https'); | |
const zlib = require('zlib'); | |
async function rp(options) { | |
try { | |
// Check if options is a string URL | |
if (typeof options === 'string') { | |
options = { uri: options }; | |
} | |
const { | |
method = 'GET', // HTTP method | |
headers = {}, // Request headers | |
body, // Request body for POST, PUT, etc. | |
json, // JSON flag or JSON object | |
qs, // Query string parameters | |
form, // Form data object | |
auth, // Authentication object { user, username, pass, password, sendImmediately, bearer } | |
followAllRedirects = false, // Follow all redirects | |
resolveWithFullResponse = false, // Return full response (including headers) | |
simple = true, // Reject based on response status | |
timeout, // Request timeout | |
cert, // Client certificate | |
key, // Client private key | |
strictSSL = true, // Strict SSL certificate validation | |
transform, // Transform function for response | |
gzip = false, // Use gzip compression | |
} = options; | |
let url = new URL(options.uri || options.url); | |
// Append query string parameters | |
if (qs) { | |
Object.keys(qs).forEach(key => url.searchParams.append(key, qs[key])); | |
} | |
// Fetch options setup | |
const fetchOptions = { | |
method, | |
headers, | |
redirect: followAllRedirects ? 'follow' : 'manual', | |
}; | |
if (auth) { | |
const { user, username, pass, password, sendImmediately = true, bearer } = auth; | |
if (bearer) { | |
fetchOptions.headers['Authorization'] = `Bearer ${bearer}`; | |
} else { | |
const authUser = user || username; | |
const authPass = pass || password; | |
if (authUser && authPass) { | |
const encodedAuth = Buffer.from(`${authUser}:${authPass}`).toString('base64'); | |
fetchOptions.headers['Authorization'] = `Basic ${encodedAuth}`; | |
} else if (sendImmediately) { | |
throw new Error('Missing authentication credentials'); | |
} | |
} | |
} | |
if (json) { | |
fetchOptions.headers['Content-Type'] = 'application/json'; | |
if (body || (typeof json !== 'boolean')) { | |
fetchOptions.body = JSON.stringify(body || json); | |
} | |
} else if (body) { | |
fetchOptions.body = body; | |
} | |
if (form) { | |
const formData = new FormData(); | |
Object.keys(form).forEach(key => formData.append(key, form[key])); | |
fetchOptions.body = formData; | |
} | |
const agentOptions = {}; | |
if (cert) agentOptions.cert = cert; | |
if (key) agentOptions.key = key; | |
agentOptions.rejectUnauthorized = strictSSL; | |
const agent = new https.Agent(agentOptions); | |
fetchOptions.agent = agent; | |
if (gzip) { | |
fetchOptions.headers['Accept-Encoding'] = 'gzip, deflate'; | |
} | |
const controller = new AbortController(); | |
fetchOptions.signal = controller.signal; | |
let timeoutId; | |
if (timeout) { | |
timeoutId = setTimeout(() => controller.abort(), timeout); | |
} | |
const response = await fetch(url, fetchOptions); | |
let responseText; | |
if (gzip && response.headers.get('content-encoding') === 'gzip') { | |
const buffer = await response.arrayBuffer(); | |
const decompressed = zlib.gunzipSync(Buffer.from(buffer)); | |
responseText = decompressed.toString('utf-8'); | |
} else { | |
responseText = await response.text(); | |
} | |
// Handle JSON response | |
if (json && typeof json !== 'object') { | |
try { | |
responseText = JSON.parse(responseText); | |
} catch (error) { | |
clearTimeout(timeoutId); | |
throw new Error(`Failed to parse JSON response: ${responseText}`); | |
} | |
} | |
if (simple && !response.ok) { | |
clearTimeout(timeoutId); | |
throw responseText; | |
} | |
if (transform) { | |
responseText = transform(responseText, response); | |
} | |
clearTimeout(timeoutId); | |
return resolveWithFullResponse ? { ...response, body: responseText } : responseText; | |
} catch (error) { | |
if (error.name === 'AbortError') { | |
throw { | |
name: 'RequestError', | |
message: 'Error: ETIMEDOUT', | |
error: { | |
code: 'ETIMEDOUT', | |
connect: true, | |
message: 'ETIMEDOUT' | |
} | |
}; | |
} | |
throw new Error(`Request failed: ${error.message}`); | |
} | |
} | |
module.exports = rp; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment