@shaivpidadi/trends-js
Version:
Google Trends API for Node.js
105 lines (104 loc) • 4.34 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.request = void 0;
const https_1 = __importDefault(require("https"));
const querystring_1 = __importDefault(require("querystring"));
let cookieVal;
const MAX_RETRIES = 3;
const BASE_DELAY_MS = 750;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function runRequest(options, body, attempt) {
return new Promise((resolve, reject) => {
const req = https_1.default.request(options, (res) => {
let chunk = '';
res.on('data', (data) => { chunk += data; });
res.on('end', async () => {
const hasSetCookie = !!res.headers['set-cookie']?.length;
if (hasSetCookie) {
// Only keep the name=value part of the cookie, discard attributes like Expires, Path, etc.
const newCookie = res.headers['set-cookie'][0].split(';')[0];
cookieVal = newCookie;
if (options.headers) {
options.headers['cookie'] = cookieVal;
}
}
const isRateLimited = res.statusCode === 429 ||
chunk.includes('Error 429') ||
chunk.includes('Too Many Requests');
const isUnauthorized = res.statusCode === 401;
const isMovedPermanentlyOrRedirect = res.statusCode === 302;
if (isMovedPermanentlyOrRedirect) {
cookieVal = undefined;
if (options.headers) {
delete options.headers['cookie'];
}
if (attempt < MAX_RETRIES) {
const retryResponse = await runRequest(options, body, attempt + 1);
resolve(retryResponse);
return;
}
}
if (isRateLimited || isUnauthorized) {
if (attempt < MAX_RETRIES) {
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.floor(Math.random() * 250);
await sleep(delay);
try {
const retryResponse = await runRequest(options, body, attempt + 1);
resolve(retryResponse);
return;
}
catch (err) {
reject(err);
return;
}
}
}
resolve(chunk);
});
});
req.on('error', reject);
if (body)
req.write(body);
req.end();
});
}
const request = async (url, options, enableBackoff = false) => {
const parsedUrl = new URL(url);
const method = options.method || 'POST';
// Prepare body
let bodyString = '';
const contentType = options.contentType || 'json';
if (typeof options.body === 'string') {
bodyString = options.body;
}
else if (contentType === 'form') {
bodyString = querystring_1.default.stringify(options.body || {});
}
else if (options.body) {
bodyString = JSON.stringify(options.body);
}
const requestOptions = {
hostname: parsedUrl.hostname,
port: parsedUrl.port || 443,
path: `${parsedUrl.pathname}${options.qs ? '?' + querystring_1.default.stringify(options.qs) : ''}`,
method,
headers: {
...(options.headers || {}),
...(contentType === 'form'
? { 'Content-Type': 'application/x-www-form-urlencoded' }
: { 'Content-Type': 'application/json' }),
...(bodyString ? { 'Content-Length': Buffer.byteLength(bodyString).toString() } : {}),
...(cookieVal ? { cookie: cookieVal } : {})
}
};
const response = enableBackoff
? await runRequest(requestOptions, bodyString, 0)
: await runRequest(requestOptions, bodyString, MAX_RETRIES);
return {
text: () => Promise.resolve(response)
};
};
exports.request = request;