rezo 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/adapters/curl.cjs +143 -32
  2. package/dist/adapters/curl.js +143 -32
  3. package/dist/adapters/entries/curl.d.ts +65 -0
  4. package/dist/adapters/entries/fetch.d.ts +65 -0
  5. package/dist/adapters/entries/http.d.ts +65 -0
  6. package/dist/adapters/entries/http2.d.ts +65 -0
  7. package/dist/adapters/entries/react-native.d.ts +65 -0
  8. package/dist/adapters/entries/xhr.d.ts +65 -0
  9. package/dist/adapters/fetch.cjs +98 -12
  10. package/dist/adapters/fetch.js +98 -12
  11. package/dist/adapters/http.cjs +26 -14
  12. package/dist/adapters/http.js +26 -14
  13. package/dist/adapters/http2.cjs +756 -227
  14. package/dist/adapters/http2.js +756 -227
  15. package/dist/adapters/index.cjs +6 -6
  16. package/dist/adapters/xhr.cjs +94 -2
  17. package/dist/adapters/xhr.js +94 -2
  18. package/dist/cache/dns-cache.cjs +5 -3
  19. package/dist/cache/dns-cache.js +5 -3
  20. package/dist/cache/file-cacher.cjs +7 -1
  21. package/dist/cache/file-cacher.js +7 -1
  22. package/dist/cache/index.cjs +15 -13
  23. package/dist/cache/index.js +1 -0
  24. package/dist/cache/navigation-history.cjs +298 -0
  25. package/dist/cache/navigation-history.js +296 -0
  26. package/dist/cache/url-store.cjs +7 -1
  27. package/dist/cache/url-store.js +7 -1
  28. package/dist/core/rezo.cjs +7 -0
  29. package/dist/core/rezo.js +7 -0
  30. package/dist/crawler.d.ts +196 -11
  31. package/dist/entries/crawler.cjs +5 -5
  32. package/dist/index.cjs +27 -24
  33. package/dist/index.d.ts +73 -0
  34. package/dist/index.js +1 -0
  35. package/dist/internal/agents/base.cjs +113 -0
  36. package/dist/internal/agents/base.js +110 -0
  37. package/dist/internal/agents/http-proxy.cjs +89 -0
  38. package/dist/internal/agents/http-proxy.js +86 -0
  39. package/dist/internal/agents/https-proxy.cjs +176 -0
  40. package/dist/internal/agents/https-proxy.js +173 -0
  41. package/dist/internal/agents/index.cjs +10 -0
  42. package/dist/internal/agents/index.js +5 -0
  43. package/dist/internal/agents/socks-client.cjs +571 -0
  44. package/dist/internal/agents/socks-client.js +567 -0
  45. package/dist/internal/agents/socks-proxy.cjs +75 -0
  46. package/dist/internal/agents/socks-proxy.js +72 -0
  47. package/dist/platform/browser.d.ts +65 -0
  48. package/dist/platform/bun.d.ts +65 -0
  49. package/dist/platform/deno.d.ts +65 -0
  50. package/dist/platform/node.d.ts +65 -0
  51. package/dist/platform/react-native.d.ts +65 -0
  52. package/dist/platform/worker.d.ts +65 -0
  53. package/dist/plugin/crawler-options.cjs +1 -1
  54. package/dist/plugin/crawler-options.js +1 -1
  55. package/dist/plugin/crawler.cjs +192 -1
  56. package/dist/plugin/crawler.js +192 -1
  57. package/dist/plugin/index.cjs +36 -36
  58. package/dist/proxy/index.cjs +18 -16
  59. package/dist/proxy/index.js +17 -12
  60. package/dist/queue/index.cjs +8 -8
  61. package/dist/responses/buildError.cjs +11 -2
  62. package/dist/responses/buildError.js +11 -2
  63. package/dist/responses/universal/index.cjs +11 -11
  64. package/dist/utils/agent-pool.cjs +1 -17
  65. package/dist/utils/agent-pool.js +1 -17
  66. package/dist/utils/curl.cjs +317 -0
  67. package/dist/utils/curl.js +314 -0
  68. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1,27 +1,30 @@
1
- const _mod_0ynvco = require('./core/rezo.cjs');
2
- exports.Rezo = _mod_0ynvco.Rezo;
3
- exports.createRezoInstance = _mod_0ynvco.createRezoInstance;
4
- exports.createDefaultInstance = _mod_0ynvco.createDefaultInstance;;
5
- const _mod_bgvlss = require('./errors/rezo-error.cjs');
6
- exports.RezoError = _mod_bgvlss.RezoError;
7
- exports.RezoErrorCode = _mod_bgvlss.RezoErrorCode;;
8
- const _mod_z9q7ik = require('./utils/headers.cjs');
9
- exports.RezoHeaders = _mod_z9q7ik.RezoHeaders;;
10
- const _mod_dxoi53 = require('./utils/form-data.cjs');
11
- exports.RezoFormData = _mod_dxoi53.RezoFormData;;
12
- const _mod_axqg2d = require('./utils/cookies.cjs');
13
- exports.RezoCookieJar = _mod_axqg2d.RezoCookieJar;
14
- exports.Cookie = _mod_axqg2d.Cookie;;
15
- const _mod_0g7fzx = require('./core/hooks.cjs');
16
- exports.createDefaultHooks = _mod_0g7fzx.createDefaultHooks;
17
- exports.mergeHooks = _mod_0g7fzx.mergeHooks;;
18
- const _mod_ncim1p = require('./proxy/manager.cjs');
19
- exports.ProxyManager = _mod_ncim1p.ProxyManager;;
20
- const _mod_gcfuln = require('./queue/index.cjs');
21
- exports.RezoQueue = _mod_gcfuln.RezoQueue;
22
- exports.HttpQueue = _mod_gcfuln.HttpQueue;
23
- exports.Priority = _mod_gcfuln.Priority;
24
- exports.HttpMethodPriority = _mod_gcfuln.HttpMethodPriority;;
1
+ const _mod_ez6b8t = require('./core/rezo.cjs');
2
+ exports.Rezo = _mod_ez6b8t.Rezo;
3
+ exports.createRezoInstance = _mod_ez6b8t.createRezoInstance;
4
+ exports.createDefaultInstance = _mod_ez6b8t.createDefaultInstance;;
5
+ const _mod_3tc7ap = require('./errors/rezo-error.cjs');
6
+ exports.RezoError = _mod_3tc7ap.RezoError;
7
+ exports.RezoErrorCode = _mod_3tc7ap.RezoErrorCode;;
8
+ const _mod_43q7ms = require('./utils/headers.cjs');
9
+ exports.RezoHeaders = _mod_43q7ms.RezoHeaders;;
10
+ const _mod_g1j1lv = require('./utils/form-data.cjs');
11
+ exports.RezoFormData = _mod_g1j1lv.RezoFormData;;
12
+ const _mod_uvyhfd = require('./utils/cookies.cjs');
13
+ exports.RezoCookieJar = _mod_uvyhfd.RezoCookieJar;
14
+ exports.Cookie = _mod_uvyhfd.Cookie;;
15
+ const _mod_u7n5iq = require('./utils/curl.cjs');
16
+ exports.toCurl = _mod_u7n5iq.toCurl;
17
+ exports.fromCurl = _mod_u7n5iq.fromCurl;;
18
+ const _mod_dk9wem = require('./core/hooks.cjs');
19
+ exports.createDefaultHooks = _mod_dk9wem.createDefaultHooks;
20
+ exports.mergeHooks = _mod_dk9wem.mergeHooks;;
21
+ const _mod_pe26um = require('./proxy/manager.cjs');
22
+ exports.ProxyManager = _mod_pe26um.ProxyManager;;
23
+ const _mod_zl76ch = require('./queue/index.cjs');
24
+ exports.RezoQueue = _mod_zl76ch.RezoQueue;
25
+ exports.HttpQueue = _mod_zl76ch.HttpQueue;
26
+ exports.Priority = _mod_zl76ch.Priority;
27
+ exports.HttpMethodPriority = _mod_zl76ch.HttpMethodPriority;;
25
28
  const { RezoError } = require('./errors/rezo-error.cjs');
26
29
  const isRezoError = exports.isRezoError = RezoError.isRezoError;
27
30
  const Cancel = exports.Cancel = RezoError;
package/dist/index.d.ts CHANGED
@@ -4217,6 +4217,14 @@ export interface httpAdapterPutOverloads {
4217
4217
  responseType: "upload";
4218
4218
  }): Promise<RezoUploadResponse>;
4219
4219
  }
4220
+ /**
4221
+ * Convert a Rezo request configuration to a cURL command string.
4222
+ */
4223
+ export declare function toCurl(config: RezoRequestConfig | RezoRequestOptions): string;
4224
+ /**
4225
+ * Parse a cURL command string into a Rezo request configuration.
4226
+ */
4227
+ export declare function fromCurl(curlCommand: string): RezoRequestOptions;
4220
4228
  /**
4221
4229
  * Adapter function type - all adapters must implement this signature
4222
4230
  */
@@ -4500,6 +4508,71 @@ export declare class Rezo {
4500
4508
  * @see {@link cookieJar} - Access the underlying RezoCookieJar for more control
4501
4509
  */
4502
4510
  clearCookies(): void;
4511
+ /**
4512
+ * Convert a Rezo request configuration to a cURL command string.
4513
+ *
4514
+ * Generates a valid cURL command that can be executed in a terminal to
4515
+ * reproduce the same HTTP request. Useful for:
4516
+ * - Debugging and sharing requests
4517
+ * - Documentation and examples
4518
+ * - Testing requests outside of Node.js
4519
+ * - Exporting requests to other tools
4520
+ *
4521
+ * @param config - Request configuration object
4522
+ * @returns A cURL command string
4523
+ *
4524
+ * @example
4525
+ * ```typescript
4526
+ * const curl = Rezo.toCurl({
4527
+ * url: 'https://api.example.com/users',
4528
+ * method: 'POST',
4529
+ * headers: { 'Content-Type': 'application/json' },
4530
+ * body: { name: 'John', email: 'john@example.com' }
4531
+ * });
4532
+ * // Output: curl -X POST -H 'content-type: application/json' --data-raw '{"name":"John","email":"john@example.com"}' -L --compressed 'https://api.example.com/users'
4533
+ * ```
4534
+ */
4535
+ static toCurl(config: RezoRequestConfig | RezoRequestOptions): string;
4536
+ /**
4537
+ * Parse a cURL command string into a Rezo request configuration.
4538
+ *
4539
+ * Converts a cURL command into a configuration object that can be
4540
+ * passed directly to Rezo request methods. Useful for:
4541
+ * - Importing requests from browser DevTools
4542
+ * - Converting curl examples from API documentation
4543
+ * - Migrating scripts from curl to Rezo
4544
+ *
4545
+ * Supports common cURL options:
4546
+ * - `-X, --request` - HTTP method
4547
+ * - `-H, --header` - Request headers
4548
+ * - `-d, --data, --data-raw, --data-binary` - Request body
4549
+ * - `-u, --user` - Basic authentication
4550
+ * - `-x, --proxy` - Proxy configuration
4551
+ * - `--socks5, --socks4` - SOCKS proxy
4552
+ * - `-L, --location` - Follow redirects
4553
+ * - `--max-redirs` - Maximum redirects
4554
+ * - `--max-time` - Request timeout
4555
+ * - `-k, --insecure` - Skip TLS verification
4556
+ * - `-A, --user-agent` - User agent header
4557
+ *
4558
+ * @param curlCommand - A cURL command string
4559
+ * @returns A request configuration object
4560
+ *
4561
+ * @example
4562
+ * ```typescript
4563
+ * // From browser DevTools "Copy as cURL"
4564
+ * const config = Rezo.fromCurl(`
4565
+ * curl 'https://api.example.com/data' \\
4566
+ * -H 'Authorization: Bearer token123' \\
4567
+ * -H 'Content-Type: application/json'
4568
+ * `);
4569
+ *
4570
+ * // Use with Rezo
4571
+ * const rezo = new Rezo();
4572
+ * const response = await rezo.request(config);
4573
+ * ```
4574
+ */
4575
+ static fromCurl(curlCommand: string): RezoRequestOptions;
4503
4576
  }
4504
4577
  /**
4505
4578
  * Extended Rezo instance with Axios-compatible static helpers.
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export { RezoError, RezoErrorCode } from './errors/rezo-error.js';
7
7
  export { RezoHeaders } from './utils/headers.js';
8
8
  export { RezoFormData } from './utils/form-data.js';
9
9
  export { RezoCookieJar, Cookie } from './utils/cookies.js';
10
+ export { toCurl, fromCurl } from './utils/curl.js';
10
11
  export { createDefaultHooks, mergeHooks } from './core/hooks.js';
11
12
  export { ProxyManager } from './proxy/manager.js';
12
13
  export { RezoQueue, HttpQueue, Priority, HttpMethodPriority } from './queue/index.js';
@@ -0,0 +1,113 @@
1
+ const net = require("node:net");
2
+ const http = require("node:http");
3
+ const https = require("node:https");
4
+ const INTERNAL = Symbol("AgentBaseInternalState");
5
+
6
+ class Agent extends http.Agent {
7
+ [INTERNAL] = {};
8
+ constructor(opts) {
9
+ super(opts);
10
+ }
11
+ isSecureEndpoint(options) {
12
+ if (options) {
13
+ if (typeof options.secureEndpoint === "boolean") {
14
+ return options.secureEndpoint;
15
+ }
16
+ if (typeof options.protocol === "string") {
17
+ return options.protocol === "https:";
18
+ }
19
+ }
20
+ const { stack } = new Error;
21
+ if (typeof stack !== "string")
22
+ return false;
23
+ return stack.split(`
24
+ `).some((l) => l.indexOf("(https.js:") !== -1 || l.indexOf("node:https:") !== -1);
25
+ }
26
+ incrementSockets(name) {
27
+ if (this.maxSockets === 1 / 0 && this.maxTotalSockets === 1 / 0) {
28
+ return null;
29
+ }
30
+ if (!this.sockets[name]) {
31
+ this.sockets[name] = [];
32
+ }
33
+ const fakeSocket = new net.Socket({ writable: false });
34
+ this.sockets[name].push(fakeSocket);
35
+ this.totalSocketCount++;
36
+ return fakeSocket;
37
+ }
38
+ decrementSockets(name, socket) {
39
+ if (!this.sockets[name] || socket === null) {
40
+ return;
41
+ }
42
+ const sockets = this.sockets[name];
43
+ const index = sockets.indexOf(socket);
44
+ if (index !== -1) {
45
+ sockets.splice(index, 1);
46
+ this.totalSocketCount--;
47
+ if (sockets.length === 0) {
48
+ delete this.sockets[name];
49
+ }
50
+ }
51
+ }
52
+ getName(options) {
53
+ const secureEndpoint = this.isSecureEndpoint(options);
54
+ if (secureEndpoint) {
55
+ return https.Agent.prototype.getName.call(this, options);
56
+ }
57
+ return http.Agent.prototype.getName.call(this, options);
58
+ }
59
+ createSocket(req, options, cb) {
60
+ const connectOpts = {
61
+ ...options,
62
+ secureEndpoint: this.isSecureEndpoint(options)
63
+ };
64
+ const name = this.getName(connectOpts);
65
+ const fakeSocket = this.incrementSockets(name);
66
+ Promise.resolve().then(() => this.connect(req, connectOpts)).then((socket) => {
67
+ this.decrementSockets(name, fakeSocket);
68
+ if (socket instanceof http.Agent) {
69
+ try {
70
+ return socket.addRequest(req, connectOpts);
71
+ } catch (err) {
72
+ return cb(err);
73
+ }
74
+ }
75
+ this[INTERNAL].currentSocket = socket;
76
+ http.Agent.prototype.createSocket.call(this, req, options, cb);
77
+ }, (err) => {
78
+ this.decrementSockets(name, fakeSocket);
79
+ cb(err);
80
+ });
81
+ }
82
+ createConnection() {
83
+ const socket = this[INTERNAL].currentSocket;
84
+ this[INTERNAL].currentSocket = undefined;
85
+ if (!socket) {
86
+ throw new Error("No socket was returned in the `connect()` function");
87
+ }
88
+ return socket;
89
+ }
90
+ async connect(_req, _opts) {
91
+ throw new Error("`connect()` must be implemented by a subclass of `Agent`");
92
+ }
93
+ get defaultPort() {
94
+ return this[INTERNAL].defaultPort ?? (this.protocol === "https:" ? 443 : 80);
95
+ }
96
+ set defaultPort(v) {
97
+ if (this[INTERNAL]) {
98
+ this[INTERNAL].defaultPort = v;
99
+ }
100
+ }
101
+ get protocol() {
102
+ return this[INTERNAL].protocol ?? (this.isSecureEndpoint() ? "https:" : "http:");
103
+ }
104
+ set protocol(v) {
105
+ if (this[INTERNAL]) {
106
+ this[INTERNAL].protocol = v;
107
+ }
108
+ }
109
+ }
110
+
111
+ exports.Agent = Agent;
112
+ exports.default = Agent;
113
+ module.exports = Object.assign(Agent, exports);
@@ -0,0 +1,110 @@
1
+ import * as net from "node:net";
2
+ import * as http from "node:http";
3
+ import * as https from "node:https";
4
+ const INTERNAL = Symbol("AgentBaseInternalState");
5
+
6
+ export class Agent extends http.Agent {
7
+ [INTERNAL] = {};
8
+ constructor(opts) {
9
+ super(opts);
10
+ }
11
+ isSecureEndpoint(options) {
12
+ if (options) {
13
+ if (typeof options.secureEndpoint === "boolean") {
14
+ return options.secureEndpoint;
15
+ }
16
+ if (typeof options.protocol === "string") {
17
+ return options.protocol === "https:";
18
+ }
19
+ }
20
+ const { stack } = new Error;
21
+ if (typeof stack !== "string")
22
+ return false;
23
+ return stack.split(`
24
+ `).some((l) => l.indexOf("(https.js:") !== -1 || l.indexOf("node:https:") !== -1);
25
+ }
26
+ incrementSockets(name) {
27
+ if (this.maxSockets === 1 / 0 && this.maxTotalSockets === 1 / 0) {
28
+ return null;
29
+ }
30
+ if (!this.sockets[name]) {
31
+ this.sockets[name] = [];
32
+ }
33
+ const fakeSocket = new net.Socket({ writable: false });
34
+ this.sockets[name].push(fakeSocket);
35
+ this.totalSocketCount++;
36
+ return fakeSocket;
37
+ }
38
+ decrementSockets(name, socket) {
39
+ if (!this.sockets[name] || socket === null) {
40
+ return;
41
+ }
42
+ const sockets = this.sockets[name];
43
+ const index = sockets.indexOf(socket);
44
+ if (index !== -1) {
45
+ sockets.splice(index, 1);
46
+ this.totalSocketCount--;
47
+ if (sockets.length === 0) {
48
+ delete this.sockets[name];
49
+ }
50
+ }
51
+ }
52
+ getName(options) {
53
+ const secureEndpoint = this.isSecureEndpoint(options);
54
+ if (secureEndpoint) {
55
+ return https.Agent.prototype.getName.call(this, options);
56
+ }
57
+ return http.Agent.prototype.getName.call(this, options);
58
+ }
59
+ createSocket(req, options, cb) {
60
+ const connectOpts = {
61
+ ...options,
62
+ secureEndpoint: this.isSecureEndpoint(options)
63
+ };
64
+ const name = this.getName(connectOpts);
65
+ const fakeSocket = this.incrementSockets(name);
66
+ Promise.resolve().then(() => this.connect(req, connectOpts)).then((socket) => {
67
+ this.decrementSockets(name, fakeSocket);
68
+ if (socket instanceof http.Agent) {
69
+ try {
70
+ return socket.addRequest(req, connectOpts);
71
+ } catch (err) {
72
+ return cb(err);
73
+ }
74
+ }
75
+ this[INTERNAL].currentSocket = socket;
76
+ http.Agent.prototype.createSocket.call(this, req, options, cb);
77
+ }, (err) => {
78
+ this.decrementSockets(name, fakeSocket);
79
+ cb(err);
80
+ });
81
+ }
82
+ createConnection() {
83
+ const socket = this[INTERNAL].currentSocket;
84
+ this[INTERNAL].currentSocket = undefined;
85
+ if (!socket) {
86
+ throw new Error("No socket was returned in the `connect()` function");
87
+ }
88
+ return socket;
89
+ }
90
+ async connect(_req, _opts) {
91
+ throw new Error("`connect()` must be implemented by a subclass of `Agent`");
92
+ }
93
+ get defaultPort() {
94
+ return this[INTERNAL].defaultPort ?? (this.protocol === "https:" ? 443 : 80);
95
+ }
96
+ set defaultPort(v) {
97
+ if (this[INTERNAL]) {
98
+ this[INTERNAL].defaultPort = v;
99
+ }
100
+ }
101
+ get protocol() {
102
+ return this[INTERNAL].protocol ?? (this.isSecureEndpoint() ? "https:" : "http:");
103
+ }
104
+ set protocol(v) {
105
+ if (this[INTERNAL]) {
106
+ this[INTERNAL].protocol = v;
107
+ }
108
+ }
109
+ }
110
+ export default Agent;
@@ -0,0 +1,89 @@
1
+ const net = require("node:net");
2
+ const tls = require("node:tls");
3
+ const http = require("node:http");
4
+ const { once } = require("node:events");
5
+ const { Agent } = require('./base.cjs');
6
+ function omit(obj, ...keys) {
7
+ const ret = {};
8
+ for (const key in obj) {
9
+ if (!keys.includes(key)) {
10
+ ret[key] = obj[key];
11
+ }
12
+ }
13
+ return ret;
14
+ }
15
+
16
+ class HttpProxyAgent extends Agent {
17
+ static protocols = ["http", "https"];
18
+ proxy;
19
+ proxyHeaders;
20
+ connectOpts;
21
+ constructor(proxy, opts) {
22
+ super(opts);
23
+ this.proxy = typeof proxy === "string" ? new URL(proxy) : proxy;
24
+ this.proxyHeaders = opts?.headers ?? {};
25
+ const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, "");
26
+ const port = this.proxy.port ? parseInt(this.proxy.port, 10) : this.proxy.protocol === "https:" ? 443 : 80;
27
+ this.connectOpts = {
28
+ ...opts ? omit(opts, "headers") : {},
29
+ host,
30
+ port
31
+ };
32
+ }
33
+ addRequest(req, opts) {
34
+ req._header = null;
35
+ this.setRequestProps(req, opts);
36
+ http.Agent.prototype.addRequest.call(this, req, opts);
37
+ }
38
+ setRequestProps(req, opts) {
39
+ const { proxy } = this;
40
+ const protocol = opts.secureEndpoint ? "https:" : "http:";
41
+ const hostname = req.getHeader("host") || "localhost";
42
+ const base = `${protocol}//${hostname}`;
43
+ const url = new URL(req.path, base);
44
+ if (opts.port !== 80) {
45
+ url.port = String(opts.port);
46
+ }
47
+ req.path = String(url);
48
+ const headers = typeof this.proxyHeaders === "function" ? this.proxyHeaders() : { ...this.proxyHeaders };
49
+ if (proxy.username || proxy.password) {
50
+ const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`;
51
+ headers["Proxy-Authorization"] = `Basic ${Buffer.from(auth).toString("base64")}`;
52
+ }
53
+ if (!headers["Proxy-Connection"]) {
54
+ headers["Proxy-Connection"] = this.keepAlive ? "Keep-Alive" : "close";
55
+ }
56
+ for (const name of Object.keys(headers)) {
57
+ const value = headers[name];
58
+ if (value) {
59
+ req.setHeader(name, value);
60
+ }
61
+ }
62
+ }
63
+ async connect(req, opts) {
64
+ req._header = null;
65
+ if (!req.path.includes("://")) {
66
+ this.setRequestProps(req, opts);
67
+ }
68
+ req._implicitHeader();
69
+ if (req.outputData && req.outputData.length > 0) {
70
+ const first = req.outputData[0].data;
71
+ const endOfHeaders = first.indexOf(`\r
72
+ \r
73
+ `) + 4;
74
+ req.outputData[0].data = req._header + first.substring(endOfHeaders);
75
+ }
76
+ let socket;
77
+ if (this.proxy.protocol === "https:") {
78
+ socket = tls.connect(this.connectOpts);
79
+ } else {
80
+ socket = net.connect(this.connectOpts);
81
+ }
82
+ await once(socket, "connect");
83
+ return socket;
84
+ }
85
+ }
86
+
87
+ exports.HttpProxyAgent = HttpProxyAgent;
88
+ exports.default = HttpProxyAgent;
89
+ module.exports = Object.assign(HttpProxyAgent, exports);
@@ -0,0 +1,86 @@
1
+ import * as net from "node:net";
2
+ import * as tls from "node:tls";
3
+ import * as http from "node:http";
4
+ import { once } from "node:events";
5
+ import { Agent } from './base.js';
6
+ function omit(obj, ...keys) {
7
+ const ret = {};
8
+ for (const key in obj) {
9
+ if (!keys.includes(key)) {
10
+ ret[key] = obj[key];
11
+ }
12
+ }
13
+ return ret;
14
+ }
15
+
16
+ export class HttpProxyAgent extends Agent {
17
+ static protocols = ["http", "https"];
18
+ proxy;
19
+ proxyHeaders;
20
+ connectOpts;
21
+ constructor(proxy, opts) {
22
+ super(opts);
23
+ this.proxy = typeof proxy === "string" ? new URL(proxy) : proxy;
24
+ this.proxyHeaders = opts?.headers ?? {};
25
+ const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, "");
26
+ const port = this.proxy.port ? parseInt(this.proxy.port, 10) : this.proxy.protocol === "https:" ? 443 : 80;
27
+ this.connectOpts = {
28
+ ...opts ? omit(opts, "headers") : {},
29
+ host,
30
+ port
31
+ };
32
+ }
33
+ addRequest(req, opts) {
34
+ req._header = null;
35
+ this.setRequestProps(req, opts);
36
+ http.Agent.prototype.addRequest.call(this, req, opts);
37
+ }
38
+ setRequestProps(req, opts) {
39
+ const { proxy } = this;
40
+ const protocol = opts.secureEndpoint ? "https:" : "http:";
41
+ const hostname = req.getHeader("host") || "localhost";
42
+ const base = `${protocol}//${hostname}`;
43
+ const url = new URL(req.path, base);
44
+ if (opts.port !== 80) {
45
+ url.port = String(opts.port);
46
+ }
47
+ req.path = String(url);
48
+ const headers = typeof this.proxyHeaders === "function" ? this.proxyHeaders() : { ...this.proxyHeaders };
49
+ if (proxy.username || proxy.password) {
50
+ const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`;
51
+ headers["Proxy-Authorization"] = `Basic ${Buffer.from(auth).toString("base64")}`;
52
+ }
53
+ if (!headers["Proxy-Connection"]) {
54
+ headers["Proxy-Connection"] = this.keepAlive ? "Keep-Alive" : "close";
55
+ }
56
+ for (const name of Object.keys(headers)) {
57
+ const value = headers[name];
58
+ if (value) {
59
+ req.setHeader(name, value);
60
+ }
61
+ }
62
+ }
63
+ async connect(req, opts) {
64
+ req._header = null;
65
+ if (!req.path.includes("://")) {
66
+ this.setRequestProps(req, opts);
67
+ }
68
+ req._implicitHeader();
69
+ if (req.outputData && req.outputData.length > 0) {
70
+ const first = req.outputData[0].data;
71
+ const endOfHeaders = first.indexOf(`\r
72
+ \r
73
+ `) + 4;
74
+ req.outputData[0].data = req._header + first.substring(endOfHeaders);
75
+ }
76
+ let socket;
77
+ if (this.proxy.protocol === "https:") {
78
+ socket = tls.connect(this.connectOpts);
79
+ } else {
80
+ socket = net.connect(this.connectOpts);
81
+ }
82
+ await once(socket, "connect");
83
+ return socket;
84
+ }
85
+ }
86
+ export default HttpProxyAgent;