ts-curl-impersonate
Version:
A typescript wrapper around cURL-impersonate.
169 lines (168 loc) • 5.46 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.RequestBuilder = void 0;
const node_child_process_1 = require("node:child_process");
const node_path_1 = __importDefault(require("node:path"));
const browsers_1 = require("./browsers");
const presets_1 = require("./presets");
class RequestBuilder {
_url = "";
_browser;
_preset;
_method = "GET";
_flags = [];
_headers = {};
url(url) {
this._url = url;
return this;
}
method(method) {
this._method = method;
return this;
}
/**
* Add a header to the request
* @param name The name of the header to set
* @param value The value of the header to set
* @returns The RequestBuilder instance
*/
header(name, value) {
this._headers[name] = value;
return this;
}
/**
* Add multiple headers to the request
* @param headers A record of headers to add to the request
* @returns The RequestBuilder instance
*/
headers(headers) {
this._headers = { ...this._headers, ...headers };
return this;
}
/**
* Add a flag to the request
* @param name The name of the flag to set
* @param value The value of the flag to set
* @returns The RequestBuilder instance
*/
flag(name, value) {
if (value !== undefined) {
this._flags.push(name, value);
}
else {
this._flags.push(name);
}
return this;
}
/**
* Follow redirects (sugar for this.flag("-L"))
* @returns The RequestBuilder instance
*/
follow() {
this.flag("-L");
return this;
}
body(body) {
this.flag("-d", JSON.stringify(body));
return this;
}
/**
* Add multiple flags to the request
* @param flags A record of flags to add to the request
* @returns The RequestBuilder instance
*/
flags(flags) {
for (const [flag, value] of Object.entries(flags)) {
this.flag(flag, value);
}
return this;
}
/**
* Set the browser and version preset for the request.
* Throws if the browser is not supported on the current platform.
* @param preset The preset to use for the request
* @returns The RequestBuilder instance
*/
preset(preset) {
this._browser = (0, browsers_1.resolveBrowser)(preset.name);
this._preset = presets_1.BrowserPresets[preset.name][preset.version];
return this;
}
/**
* Send the request
* @returns A promise that resolves with the response and details of the request
*/
async send() {
const browser = this._browser ?? (0, browsers_1.getDefaultPlatformBrowser)();
const preset = this._preset ?? Object.values(presets_1.BrowserPresets[browser.name])[0];
const headers = this.buildHeaderFlags({ ...this._headers, ...preset.headers });
const flags = this.buildFlags(this._flags);
const splitPresetFlag = (s) => {
const idx = s.indexOf(" ");
return idx === -1 ? [s] : [s.slice(0, idx), s.slice(idx + 1)];
};
const args = [
...flags,
...preset.flags.flatMap(splitPresetFlag),
...headers,
"-s",
"-w",
"\n%{json}",
"-X",
this._method,
this._url,
];
return new Promise((resolve, reject) => {
const child = (0, node_child_process_1.spawn)(node_path_1.default.join(browsers_1.BINARY_PATH, browser.binary), args, {
cwd: browsers_1.BINARY_PATH,
});
let stdout = "";
let stderr = "";
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stdout.on("data", (chunk) => {
stdout += chunk;
});
child.stderr.on("data", (chunk) => {
stderr += chunk;
});
child.once("error", reject);
child.once("close", () => {
if (stderr.trim().length > 0) {
resolve({ response: undefined, details: undefined, stderr });
return;
}
const result = stdout.split("\n");
const response = result.slice(0, result.length - 1).join("");
const details = JSON.parse(result.at(-1) ?? "{}");
resolve({ response, details, stderr: undefined });
});
});
}
buildFlags(flags) {
const flagBlacklist = [
"-w",
"-s",
"-v", // TODO: potentially add a way to parse stdout with flag included
"-X",
];
const out = [];
for (let i = 0; i < flags.length; i++) {
if (flagBlacklist.includes(flags[i])) {
if (i + 1 < flags.length && !flags[i + 1].startsWith("-")) {
i++;
}
continue;
}
out.push(flags[i]);
}
return out;
}
buildHeaderFlags(headers) {
return Object.entries(headers).flatMap(([key, value]) => ["-H", `${key}: ${value}`]);
}
}
exports.RequestBuilder = RequestBuilder;