UNPKG

ts-curl-impersonate

Version:

A typescript wrapper around cURL-impersonate.

169 lines (168 loc) 5.46 kB
"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;