@pricething/curl
Version:
A typescript wrapper around cURL-impersonate.
135 lines (134 loc) • 4.55 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) {
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 command = [node_path_1.default.join(browsers_1.BINARY_PATH, browser.binary), ...flags, ...preset.flags, ...headers, "-s", `-w "\\n%{json}"`, `-X ${this._method}`, `"${this._url}"`].join(" ");
return new Promise((resolve, reject) => {
(0, node_child_process_1.exec)(command, { cwd: browsers_1.BINARY_PATH }, (err, stdout, stderr) => {
if (err) {
reject(err);
return;
}
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"
];
return flags.filter((flag) => !flagBlacklist.includes(flag));
}
buildHeaderFlags(headers) {
return Object.entries(headers).map(([key, value]) => `-H "${key}: ${value}"`);
}
}
exports.RequestBuilder = RequestBuilder;