httpcloak 1.5.1 → 1.5.2

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.
package/README.md CHANGED
@@ -99,13 +99,123 @@ session.postCb(
99
99
  );
100
100
  ```
101
101
 
102
- ### With Proxy
102
+ ## Proxy Support
103
+
104
+ HTTPCloak supports HTTP, SOCKS5, and HTTP/3 (MASQUE) proxies with full fingerprint preservation.
105
+
106
+ ### HTTP Proxy
103
107
 
104
108
  ```javascript
109
+ const { Session } = require("httpcloak");
110
+
111
+ // Basic HTTP proxy
105
112
  const session = new Session({
113
+ preset: "chrome-143",
114
+ proxy: "http://host:port",
115
+ });
116
+
117
+ // With authentication
118
+ const sessionAuth = new Session({
106
119
  preset: "chrome-143",
107
120
  proxy: "http://user:pass@host:port",
108
121
  });
122
+
123
+ // HTTPS proxy
124
+ const sessionHttps = new Session({
125
+ preset: "chrome-143",
126
+ proxy: "https://user:pass@host:port",
127
+ });
128
+ ```
129
+
130
+ ### SOCKS5 Proxy
131
+
132
+ ```javascript
133
+ const { Session } = require("httpcloak");
134
+
135
+ // SOCKS5 proxy (with DNS resolution on proxy)
136
+ const session = new Session({
137
+ preset: "chrome-143",
138
+ proxy: "socks5h://host:port",
139
+ });
140
+
141
+ // With authentication
142
+ const sessionAuth = new Session({
143
+ preset: "chrome-143",
144
+ proxy: "socks5h://user:pass@host:port",
145
+ });
146
+
147
+ const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
148
+ console.log(response.protocol); // h3 (HTTP/3 through SOCKS5!)
149
+ ```
150
+
151
+ ### HTTP/3 MASQUE Proxy
152
+
153
+ MASQUE (RFC 9484) enables HTTP/3 connections through compatible proxies:
154
+
155
+ ```javascript
156
+ const { Session } = require("httpcloak");
157
+
158
+ // MASQUE proxy (auto-detected for known providers like Bright Data)
159
+ const session = new Session({
160
+ preset: "chrome-143",
161
+ proxy: "https://user:pass@brd.superproxy.io:10001",
162
+ });
163
+
164
+ const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
165
+ console.log(response.protocol); // h3
166
+ ```
167
+
168
+ ## Advanced Features
169
+
170
+ ### Encrypted Client Hello (ECH)
171
+
172
+ ECH encrypts the SNI (Server Name Indication) to prevent traffic analysis. Works with all Cloudflare domains:
173
+
174
+ ```javascript
175
+ const { Session } = require("httpcloak");
176
+
177
+ // Enable ECH for Cloudflare domains
178
+ const session = new Session({
179
+ preset: "chrome-143",
180
+ echConfigDomain: "cloudflare-ech.com",
181
+ });
182
+
183
+ const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
184
+ console.log(response.text);
185
+ // Output includes: sni=encrypted, http=http/3
186
+ ```
187
+
188
+ ### Domain Fronting (Connect-To)
189
+
190
+ Connect to one server while requesting a different domain:
191
+
192
+ ```javascript
193
+ const { Session } = require("httpcloak");
194
+
195
+ // Connect to claude.ai's IP but request www.cloudflare.com
196
+ const session = new Session({
197
+ preset: "chrome-143",
198
+ connectTo: { "www.cloudflare.com": "claude.ai" },
199
+ });
200
+
201
+ const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
202
+ ```
203
+
204
+ ### Combined: SOCKS5 + ECH
205
+
206
+ Get HTTP/3 with encrypted SNI through a SOCKS5 proxy:
207
+
208
+ ```javascript
209
+ const { Session } = require("httpcloak");
210
+
211
+ const session = new Session({
212
+ preset: "chrome-143",
213
+ proxy: "socks5h://user:pass@host:port",
214
+ echConfigDomain: "cloudflare-ech.com",
215
+ });
216
+
217
+ const response = await session.get("https://www.cloudflare.com/cdn-cgi/trace");
218
+ // Response shows: http=http/3, sni=encrypted
109
219
  ```
110
220
 
111
221
  ## Cookie Management
package/lib/index.d.ts CHANGED
@@ -6,6 +6,22 @@ export class HTTPCloakError extends Error {
6
6
  name: "HTTPCloakError";
7
7
  }
8
8
 
9
+ export class Cookie {
10
+ /** Cookie name */
11
+ name: string;
12
+ /** Cookie value */
13
+ value: string;
14
+ }
15
+
16
+ export class RedirectInfo {
17
+ /** HTTP status code */
18
+ statusCode: number;
19
+ /** Request URL */
20
+ url: string;
21
+ /** Response headers */
22
+ headers: Record<string, string>;
23
+ }
24
+
9
25
  export class Response {
10
26
  /** HTTP status code */
11
27
  statusCode: number;
@@ -13,21 +29,40 @@ export class Response {
13
29
  headers: Record<string, string>;
14
30
  /** Raw response body as Buffer */
15
31
  body: Buffer;
32
+ /** Response body as Buffer (alias for body) */
33
+ content: Buffer;
16
34
  /** Response body as string */
17
35
  text: string;
18
36
  /** Final URL after redirects */
19
37
  finalUrl: string;
38
+ /** Final URL after redirects (alias for finalUrl) */
39
+ url: string;
20
40
  /** Protocol used (http/1.1, h2, h3) */
21
41
  protocol: string;
42
+ /** Elapsed time in milliseconds */
43
+ elapsed: number;
44
+ /** Cookies set by this response */
45
+ cookies: Cookie[];
46
+ /** Redirect history */
47
+ history: RedirectInfo[];
48
+ /** True if status code < 400 */
49
+ ok: boolean;
50
+ /** HTTP status reason phrase (e.g., 'OK', 'Not Found') */
51
+ reason: string;
52
+ /** Response encoding from Content-Type header */
53
+ encoding: string | null;
22
54
 
23
55
  /** Parse response body as JSON */
24
56
  json<T = any>(): T;
57
+
58
+ /** Raise error if status >= 400 */
59
+ raiseForStatus(): void;
25
60
  }
26
61
 
27
62
  export interface SessionOptions {
28
63
  /** Browser preset to use (default: "chrome-143") */
29
64
  preset?: string;
30
- /** Proxy URL (e.g., "http://user:pass@host:port") */
65
+ /** Proxy URL (e.g., "http://user:pass@host:port" or "socks5://host:port") */
31
66
  proxy?: string;
32
67
  /** Request timeout in seconds (default: 30) */
33
68
  timeout?: number;
@@ -43,17 +78,33 @@ export interface SessionOptions {
43
78
  retry?: number;
44
79
  /** Status codes to retry on (default: [429, 500, 502, 503, 504]) */
45
80
  retryOnStatus?: number[];
81
+ /** Prefer IPv4 addresses over IPv6 (default: false) */
82
+ preferIpv4?: boolean;
83
+ /** Default basic auth [username, password] */
84
+ auth?: [string, string];
85
+ /** Domain fronting map {requestHost: connectHost} - DNS resolves connectHost but SNI/Host uses requestHost */
86
+ connectTo?: Record<string, string>;
87
+ /** Domain to fetch ECH config from (e.g., "cloudflare-ech.com" for any Cloudflare domain) */
88
+ echConfigDomain?: string;
46
89
  }
47
90
 
48
91
  export interface RequestOptions {
49
- /** HTTP method */
50
- method: string;
51
- /** Request URL */
52
- url: string;
53
92
  /** Optional custom headers */
54
93
  headers?: Record<string, string>;
55
- /** Optional request body */
94
+ /** Optional request body (for POST, PUT, PATCH) */
56
95
  body?: string | Buffer | Record<string, any>;
96
+ /** JSON body (will be serialized) */
97
+ json?: Record<string, any>;
98
+ /** Form data (will be URL encoded) */
99
+ data?: Record<string, any>;
100
+ /** Files to upload as multipart/form-data */
101
+ files?: Record<string, Buffer | { filename: string; content: Buffer; contentType?: string }>;
102
+ /** Query parameters */
103
+ params?: Record<string, string | number | boolean>;
104
+ /** Cookies to send with this request */
105
+ cookies?: Record<string, string>;
106
+ /** Basic auth [username, password] */
107
+ auth?: [string, string];
57
108
  /** Optional request timeout in seconds */
58
109
  timeout?: number;
59
110
  }
@@ -61,67 +112,66 @@ export interface RequestOptions {
61
112
  export class Session {
62
113
  constructor(options?: SessionOptions);
63
114
 
115
+ /** Default headers for all requests */
116
+ headers: Record<string, string>;
117
+
118
+ /** Default auth for all requests [username, password] */
119
+ auth: [string, string] | null;
120
+
64
121
  /** Close the session and release resources */
65
122
  close(): void;
66
123
 
67
124
  // Synchronous methods
68
125
  /** Perform a synchronous GET request */
69
- getSync(url: string, headers?: Record<string, string>): Response;
126
+ getSync(url: string, options?: RequestOptions): Response;
70
127
 
71
128
  /** Perform a synchronous POST request */
72
- postSync(
73
- url: string,
74
- body?: string | Buffer | Record<string, any>,
75
- headers?: Record<string, string>
76
- ): Response;
129
+ postSync(url: string, options?: RequestOptions): Response;
77
130
 
78
131
  /** Perform a synchronous custom HTTP request */
79
- requestSync(options: RequestOptions): Response;
132
+ requestSync(method: string, url: string, options?: RequestOptions): Response;
80
133
 
81
134
  // Promise-based methods
82
135
  /** Perform an async GET request */
83
- get(url: string, headers?: Record<string, string>): Promise<Response>;
136
+ get(url: string, options?: RequestOptions): Promise<Response>;
84
137
 
85
138
  /** Perform an async POST request */
86
- post(
87
- url: string,
88
- body?: string | Buffer | Record<string, any>,
89
- headers?: Record<string, string>
90
- ): Promise<Response>;
139
+ post(url: string, options?: RequestOptions): Promise<Response>;
91
140
 
92
141
  /** Perform an async custom HTTP request */
93
- request(options: RequestOptions): Promise<Response>;
142
+ request(method: string, url: string, options?: RequestOptions): Promise<Response>;
94
143
 
95
144
  /** Perform an async PUT request */
96
- put(
97
- url: string,
98
- body?: string | Buffer | Record<string, any>,
99
- headers?: Record<string, string>
100
- ): Promise<Response>;
145
+ put(url: string, options?: RequestOptions): Promise<Response>;
101
146
 
102
147
  /** Perform an async DELETE request */
103
- delete(url: string, headers?: Record<string, string>): Promise<Response>;
148
+ delete(url: string, options?: RequestOptions): Promise<Response>;
104
149
 
105
150
  /** Perform an async PATCH request */
106
- patch(
107
- url: string,
108
- body?: string | Buffer | Record<string, any>,
109
- headers?: Record<string, string>
110
- ): Promise<Response>;
151
+ patch(url: string, options?: RequestOptions): Promise<Response>;
111
152
 
112
153
  /** Perform an async HEAD request */
113
- head(url: string, headers?: Record<string, string>): Promise<Response>;
154
+ head(url: string, options?: RequestOptions): Promise<Response>;
114
155
 
115
156
  /** Perform an async OPTIONS request */
116
- options(url: string, headers?: Record<string, string>): Promise<Response>;
157
+ options(url: string, options?: RequestOptions): Promise<Response>;
117
158
 
118
159
  // Cookie management
119
160
  /** Get all cookies from the session */
120
161
  getCookies(): Record<string, string>;
121
162
 
163
+ /** Get a specific cookie by name */
164
+ getCookie(name: string): string | null;
165
+
122
166
  /** Set a cookie in the session */
123
167
  setCookie(name: string, value: string): void;
124
168
 
169
+ /** Delete a specific cookie by name */
170
+ deleteCookie(name: string): void;
171
+
172
+ /** Clear all cookies from the session */
173
+ clearCookies(): void;
174
+
125
175
  /** Get cookies as a property */
126
176
  readonly cookies: Record<string, string>;
127
177
  }
@@ -162,7 +212,8 @@ export function patch(url: string, options?: RequestOptions): Promise<Response>;
162
212
  export function head(url: string, options?: RequestOptions): Promise<Response>;
163
213
 
164
214
  /** Perform an OPTIONS request */
165
- export function options(url: string, options?: RequestOptions): Promise<Response>;
215
+ declare function opts(url: string, options?: RequestOptions): Promise<Response>;
216
+ export { opts as options };
166
217
 
167
218
  /** Perform a custom HTTP request */
168
219
  export function request(method: string, url: string, options?: RequestOptions): Promise<Response>;
package/lib/index.js CHANGED
@@ -674,7 +674,7 @@ class Session {
674
674
  * Create a new session
675
675
  * @param {Object} options - Session options
676
676
  * @param {string} [options.preset="chrome-143"] - Browser preset to use
677
- * @param {string} [options.proxy] - Proxy URL (e.g., "http://user:pass@host:port")
677
+ * @param {string} [options.proxy] - Proxy URL (e.g., "http://user:pass@host:port" or "socks5://host:port")
678
678
  * @param {number} [options.timeout=30] - Request timeout in seconds
679
679
  * @param {string} [options.httpVersion="auto"] - HTTP version: "auto", "h1", "h2", "h3"
680
680
  * @param {boolean} [options.verify=true] - SSL certificate verification
@@ -683,6 +683,8 @@ class Session {
683
683
  * @param {number} [options.retry=3] - Number of retries on failure (set to 0 to disable)
684
684
  * @param {number[]} [options.retryOnStatus] - Status codes to retry on
685
685
  * @param {Array} [options.auth] - Default auth [username, password] for all requests
686
+ * @param {Object} [options.connectTo] - Domain fronting map {requestHost: connectHost}
687
+ * @param {string} [options.echConfigDomain] - Domain to fetch ECH config from (e.g., "cloudflare-ech.com")
686
688
  */
687
689
  constructor(options = {}) {
688
690
  const {
@@ -697,6 +699,8 @@ class Session {
697
699
  retryOnStatus = null,
698
700
  preferIpv4 = false,
699
701
  auth = null,
702
+ connectTo = null,
703
+ echConfigDomain = null,
700
704
  } = options;
701
705
 
702
706
  this._lib = getLib();
@@ -727,6 +731,12 @@ class Session {
727
731
  if (preferIpv4) {
728
732
  config.prefer_ipv4 = true;
729
733
  }
734
+ if (connectTo) {
735
+ config.connect_to = connectTo;
736
+ }
737
+ if (echConfigDomain) {
738
+ config.ech_config_domain = echConfigDomain;
739
+ }
730
740
 
731
741
  this._handle = this._lib.httpcloak_session_new(JSON.stringify(config));
732
742
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/darwin-arm64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for darwin arm64",
5
5
  "os": [
6
6
  "darwin"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/darwin-x64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for darwin x64",
5
5
  "os": [
6
6
  "darwin"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/linux-arm64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for linux arm64",
5
5
  "os": [
6
6
  "linux"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/linux-x64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for linux x64",
5
5
  "os": [
6
6
  "linux"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/win32-arm64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for win32 arm64",
5
5
  "os": [
6
6
  "win32"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httpcloak/win32-x64",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "HTTPCloak native binary for win32 x64",
5
5
  "os": [
6
6
  "win32"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "httpcloak",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "Browser fingerprint emulation HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",