twitter-api-v2
Version:
Strongly typed, full-featured, light, versatile yet powerful Twitter API v1.1 and v2 client for Node.js.
144 lines (143 loc) • 6.37 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientRequestMaker = void 0;
const TweetStream_1 = __importDefault(require("../stream/TweetStream"));
const helpers_1 = require("../helpers");
const oauth1_helper_1 = __importDefault(require("./oauth1.helper"));
const request_handler_helper_1 = __importDefault(require("./request-handler.helper"));
const request_param_helper_1 = __importDefault(require("./request-param.helper"));
class ClientRequestMaker {
constructor() {
this._rateLimits = {};
}
saveRateLimit(originalUrl, rateLimit) {
this._rateLimits[originalUrl] = rateLimit;
}
/** Send a new request and returns a wrapped `Promise<TwitterResponse<T>`. */
send(requestParams) {
const args = this.getHttpRequestArgs(requestParams);
const options = { method: args.method, headers: args.headers, timeout: requestParams.timeout };
const enableRateLimitSave = requestParams.enableRateLimitSave !== false;
if (args.body) {
request_param_helper_1.default.setBodyLengthHeader(options, args.body);
}
return new request_handler_helper_1.default({
url: args.url,
options,
body: args.body,
rateLimitSaver: enableRateLimitSave ? this.saveRateLimit.bind(this, args.rawUrl) : undefined,
})
.makeRequest();
}
sendStream(requestParams) {
const args = this.getHttpRequestArgs(requestParams);
const options = { method: args.method, headers: args.headers };
const enableRateLimitSave = requestParams.enableRateLimitSave !== false;
const enableAutoConnect = requestParams.autoConnect !== false;
if (args.body) {
request_param_helper_1.default.setBodyLengthHeader(options, args.body);
}
const requestData = {
url: args.url,
options,
body: args.body,
rateLimitSaver: enableRateLimitSave ? this.saveRateLimit.bind(this, args.rawUrl) : undefined,
payloadIsError: requestParams.payloadIsError,
};
const stream = new TweetStream_1.default(requestData);
if (!enableAutoConnect) {
return stream;
}
return stream.connect();
}
/* Token helpers */
buildOAuth() {
if (!this._consumerSecret || !this._consumerToken)
throw new Error('Invalid consumer tokens');
return new oauth1_helper_1.default({
consumerKeys: { key: this._consumerToken, secret: this._consumerSecret },
});
}
getOAuthAccessTokens() {
if (!this._accessSecret || !this._accessToken)
return;
return {
key: this._accessToken,
secret: this._accessSecret,
};
}
/* Request helpers */
writeAuthHeaders({ headers, bodyInSignature, url, method, query, body }) {
headers = { ...headers };
if (this._bearerToken) {
headers.Authorization = 'Bearer ' + this._bearerToken;
}
else if (this._basicToken) {
// Basic auth, to request a bearer token
headers.Authorization = 'Basic ' + this._basicToken;
}
else if (this._consumerSecret && this._oauth) {
// Merge query and body
const data = bodyInSignature ? request_param_helper_1.default.mergeQueryAndBodyForOAuth(query, body) : query;
const auth = this._oauth.authorize({
url: url.toString(),
method,
data,
}, this.getOAuthAccessTokens());
headers = { ...headers, ...this._oauth.toHeader(auth) };
}
return headers;
}
getHttpRequestArgs({ url, method, query: rawQuery = {}, body: rawBody = {}, headers, forceBodyMode, enableAuth, params, }) {
let body = undefined;
method = method.toUpperCase();
headers = headers !== null && headers !== void 0 ? headers : {};
// Add user agent header (Twitter recommands it)
if (!headers['x-user-agent']) {
headers['x-user-agent'] = 'Node.twitter-api-v2';
}
// Add protocol to URL if needed
if (!url.startsWith('http')) {
url = 'https://' + url;
}
// Convert URL to object that will receive all URL modifications
const urlObject = new URL(url);
// URL without query string to save as endpoint name
const rawUrl = urlObject.origin + urlObject.pathname;
// Apply URL parameters
if (params) {
request_param_helper_1.default.applyRequestParametersToUrl(urlObject, params);
}
// Build an URL without anything in QS, and QSP in query
const query = request_param_helper_1.default.formatQueryToString(rawQuery);
request_param_helper_1.default.moveUrlQueryParamsIntoObject(urlObject, query);
// Delete undefined parameters
if (!(rawBody instanceof Buffer)) {
helpers_1.trimUndefinedProperties(rawBody);
}
// OAuth signature should not include parameters when using multipart.
const bodyType = forceBodyMode !== null && forceBodyMode !== void 0 ? forceBodyMode : request_param_helper_1.default.autoDetectBodyType(urlObject);
// If undefined or true, enable auth by headers
if (enableAuth !== false) {
// OAuth needs body signature only if body is URL encoded.
const bodyInSignature = ClientRequestMaker.BODY_METHODS.has(method) && bodyType === 'url';
headers = this.writeAuthHeaders({ headers, bodyInSignature, method, query, url: urlObject, body: rawBody });
}
if (ClientRequestMaker.BODY_METHODS.has(method)) {
body = request_param_helper_1.default.constructBodyParams(rawBody, headers, bodyType) || undefined;
}
request_param_helper_1.default.addQueryParamsToUrl(urlObject, query);
return {
rawUrl,
url: urlObject,
method,
headers,
body,
};
}
}
exports.ClientRequestMaker = ClientRequestMaker;
ClientRequestMaker.BODY_METHODS = new Set(['POST', 'PUT', 'PATCH']);