httpcloak 1.6.1-beta.3 → 1.6.5

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
@@ -16,7 +16,7 @@ npm install httpcloak
16
16
  const { Session } = require("httpcloak");
17
17
 
18
18
  async function main() {
19
- const session = new Session({ preset: "chrome-145" });
19
+ const session = new Session({ preset: "chrome-latest" });
20
20
 
21
21
  try {
22
22
  // GET request
@@ -53,7 +53,7 @@ main();
53
53
  ```javascript
54
54
  import { Session } from "httpcloak";
55
55
 
56
- const session = new Session({ preset: "chrome-145" });
56
+ const session = new Session({ preset: "chrome-latest" });
57
57
 
58
58
  const response = await session.get("https://example.com");
59
59
  console.log(response.text);
@@ -66,7 +66,7 @@ session.close();
66
66
  ```javascript
67
67
  const { Session } = require("httpcloak");
68
68
 
69
- const session = new Session({ preset: "chrome-145" });
69
+ const session = new Session({ preset: "chrome-latest" });
70
70
 
71
71
  // Sync GET
72
72
  const response = session.getSync("https://example.com");
@@ -86,7 +86,7 @@ session.close();
86
86
  ```javascript
87
87
  const { Session } = require("httpcloak");
88
88
 
89
- const session = new Session({ preset: "chrome-145" });
89
+ const session = new Session({ preset: "chrome-latest" });
90
90
 
91
91
  // GET with callback
92
92
  session.getCb("https://example.com", (err, response) => {
@@ -121,7 +121,7 @@ const { Session } = require("httpcloak");
121
121
  const fs = require("fs");
122
122
 
123
123
  async function downloadFile() {
124
- const session = new Session({ preset: "chrome-145" });
124
+ const session = new Session({ preset: "chrome-latest" });
125
125
 
126
126
  try {
127
127
  // Start streaming request
@@ -158,7 +158,7 @@ downloadFile();
158
158
  ```javascript
159
159
  const { Session } = require("httpcloak");
160
160
 
161
- const session = new Session({ preset: "chrome-145" });
161
+ const session = new Session({ preset: "chrome-latest" });
162
162
 
163
163
  // Stream GET
164
164
  const getStream = session.getStream("https://example.com/data");
@@ -195,19 +195,19 @@ const { Session } = require("httpcloak");
195
195
 
196
196
  // Basic HTTP proxy
197
197
  const session = new Session({
198
- preset: "chrome-145",
198
+ preset: "chrome-latest",
199
199
  proxy: "http://host:port",
200
200
  });
201
201
 
202
202
  // With authentication
203
203
  const sessionAuth = new Session({
204
- preset: "chrome-145",
204
+ preset: "chrome-latest",
205
205
  proxy: "http://user:pass@host:port",
206
206
  });
207
207
 
208
208
  // HTTPS proxy
209
209
  const sessionHttps = new Session({
210
- preset: "chrome-145",
210
+ preset: "chrome-latest",
211
211
  proxy: "https://user:pass@host:port",
212
212
  });
213
213
  ```
@@ -219,13 +219,13 @@ const { Session } = require("httpcloak");
219
219
 
220
220
  // SOCKS5 proxy (with DNS resolution on proxy)
221
221
  const session = new Session({
222
- preset: "chrome-145",
222
+ preset: "chrome-latest",
223
223
  proxy: "socks5h://host:port",
224
224
  });
225
225
 
226
226
  // With authentication
227
227
  const sessionAuth = new Session({
228
- preset: "chrome-145",
228
+ preset: "chrome-latest",
229
229
  proxy: "socks5h://user:pass@host:port",
230
230
  });
231
231
 
@@ -242,7 +242,7 @@ const { Session } = require("httpcloak");
242
242
 
243
243
  // MASQUE proxy (auto-detected for known providers like Bright Data)
244
244
  const session = new Session({
245
- preset: "chrome-145",
245
+ preset: "chrome-latest",
246
246
  proxy: "https://user:pass@brd.superproxy.io:10001",
247
247
  });
248
248
 
@@ -258,7 +258,7 @@ Use different proxies for TCP (HTTP/1.1, HTTP/2) and UDP (HTTP/3) traffic:
258
258
  const { Session } = require("httpcloak");
259
259
 
260
260
  const session = new Session({
261
- preset: "chrome-145",
261
+ preset: "chrome-latest",
262
262
  tcpProxy: "http://tcp-proxy:port", // For HTTP/1.1, HTTP/2
263
263
  udpProxy: "https://masque-proxy:port", // For HTTP/3
264
264
  });
@@ -275,7 +275,7 @@ const { Session } = require("httpcloak");
275
275
 
276
276
  // Enable ECH for Cloudflare domains
277
277
  const session = new Session({
278
- preset: "chrome-145",
278
+ preset: "chrome-latest",
279
279
  echConfigDomain: "cloudflare-ech.com",
280
280
  });
281
281
 
@@ -293,7 +293,7 @@ const { Session } = require("httpcloak");
293
293
 
294
294
  // Connect to example.com's IP but request www.cloudflare.com
295
295
  const session = new Session({
296
- preset: "chrome-145",
296
+ preset: "chrome-latest",
297
297
  connectTo: { "www.cloudflare.com": "example.com" },
298
298
  });
299
299
 
@@ -308,7 +308,7 @@ Get HTTP/3 with encrypted SNI through a SOCKS5 proxy:
308
308
  const { Session } = require("httpcloak");
309
309
 
310
310
  const session = new Session({
311
- preset: "chrome-145",
311
+ preset: "chrome-latest",
312
312
  proxy: "socks5h://user:pass@host:port",
313
313
  echConfigDomain: "cloudflare-ech.com",
314
314
  });
@@ -324,18 +324,31 @@ const { Session } = require("httpcloak");
324
324
 
325
325
  const session = new Session();
326
326
 
327
- // Set a cookie
327
+ // Set a simple cookie (global, sent to all domains)
328
328
  session.setCookie("session_id", "abc123");
329
329
 
330
- // Get all cookies
330
+ // Set a domain-scoped cookie with full metadata
331
+ session.setCookie("auth", "token", {
332
+ domain: ".example.com",
333
+ path: "/",
334
+ secure: true,
335
+ httpOnly: true,
336
+ sameSite: "Lax",
337
+ });
338
+
339
+ // Get all cookies (returns Cookie[] with full metadata)
331
340
  const cookies = session.getCookies();
332
- console.log(cookies);
341
+ for (const cookie of cookies) {
342
+ console.log(`${cookie.name}=${cookie.value} (domain: ${cookie.domain})`);
343
+ }
333
344
 
334
- // Access cookies as property
335
- console.log(session.cookies);
345
+ // Get a specific cookie by name (returns Cookie or null)
346
+ const cookie = session.getCookie("session_id");
347
+ if (cookie) console.log(cookie.value);
336
348
 
337
- // Delete a cookie
349
+ // Delete a cookie (omit domain to delete from all domains)
338
350
  session.deleteCookie("session_id");
351
+ session.deleteCookie("auth", ".example.com"); // delete from specific domain
339
352
 
340
353
  // Clear all cookies
341
354
  session.clearCookies();
@@ -349,7 +362,7 @@ session.close();
349
362
  const { Session } = require("httpcloak");
350
363
 
351
364
  const session = new Session({
352
- preset: "chrome-145", // Browser fingerprint preset
365
+ preset: "chrome-latest", // Browser fingerprint preset
353
366
  proxy: null, // Proxy URL
354
367
  tcpProxy: null, // Separate TCP proxy
355
368
  udpProxy: null, // Separate UDP proxy (MASQUE)
@@ -371,8 +384,8 @@ const session = new Session({
371
384
  const { availablePresets } = require("httpcloak");
372
385
 
373
386
  console.log(availablePresets());
374
- // ['chrome-145', 'chrome-144', 'chrome-143', 'chrome-141', 'chrome-133',
375
- // 'firefox-133', 'safari-18', 'chrome-145-ios', ...]
387
+ // ['chrome-146', 'chrome-145', 'chrome-144', 'chrome-143', 'chrome-141', 'chrome-133',
388
+ // 'firefox-133', 'safari-18', 'chrome-146-ios', ...]
376
389
  ```
377
390
 
378
391
  ## Response Object
@@ -428,7 +441,7 @@ stream.close();
428
441
  ```javascript
429
442
  const { Session } = require("httpcloak");
430
443
 
431
- const session = new Session({ preset: "chrome-145" });
444
+ const session = new Session({ preset: "chrome-latest" });
432
445
 
433
446
  // GET
434
447
  const response = await session.get("https://example.com");
@@ -452,9 +465,7 @@ const headResponse = await session.head("https://example.com");
452
465
  const optionsResponse = await session.options("https://example.com");
453
466
 
454
467
  // Custom request
455
- const customResponse = await session.request({
456
- method: "PUT",
457
- url: "https://api.example.com/resource",
468
+ const customResponse = await session.request("PUT", "https://api.example.com/resource", {
458
469
  headers: { "X-Custom": "value" },
459
470
  body: { data: "value" },
460
471
  timeout: 60,
@@ -490,7 +501,7 @@ HTTPCloak includes TypeScript definitions out of the box:
490
501
  ```typescript
491
502
  import { Session, Response, StreamResponse, HTTPCloakError } from "httpcloak";
492
503
 
493
- const session = new Session({ preset: "chrome-145" });
504
+ const session = new Session({ preset: "chrome-latest" });
494
505
 
495
506
  async function fetchData(): Promise<Response> {
496
507
  return session.get("https://example.com");
@@ -519,7 +530,7 @@ const { LocalProxy } = require("httpcloak");
519
530
  const axios = require("axios");
520
531
 
521
532
  // Start local proxy with Chrome fingerprint
522
- const proxy = new LocalProxy({ preset: "chrome-145" });
533
+ const proxy = new LocalProxy({ preset: "chrome-latest" });
523
534
  console.log(`Proxy running on ${proxy.proxyUrl}`);
524
535
 
525
536
  // Use X-HTTPCloak-Scheme header for HTTPS with fingerprinting + streaming
@@ -558,7 +569,7 @@ const { LocalProxy } = require("httpcloak");
558
569
  const axios = require("axios");
559
570
 
560
571
  // Start local proxy with Chrome fingerprint
561
- const proxy = new LocalProxy({ preset: "chrome-145" });
572
+ const proxy = new LocalProxy({ preset: "chrome-latest" });
562
573
 
563
574
  // Standard HTTPS (uses CONNECT tunnel - fingerprinting via upstream proxy only)
564
575
  const response = await axios.get("https://example.com", {
@@ -590,7 +601,7 @@ When your client already provides authentic browser headers, use TLS-only mode:
590
601
  const { LocalProxy } = require("httpcloak");
591
602
 
592
603
  // Only apply TLS fingerprint, pass headers through
593
- const proxy = new LocalProxy({ preset: "chrome-145", tlsOnly: true });
604
+ const proxy = new LocalProxy({ preset: "chrome-latest", tlsOnly: true });
594
605
 
595
606
  // Your client's headers are preserved
596
607
  const response = await fetch("https://example.com", {
@@ -608,10 +619,10 @@ Route different requests through different browser fingerprints:
608
619
  ```javascript
609
620
  const { LocalProxy, Session } = require("httpcloak");
610
621
 
611
- const proxy = new LocalProxy({ preset: "chrome-145" });
622
+ const proxy = new LocalProxy({ preset: "chrome-latest" });
612
623
 
613
624
  // Create sessions with different fingerprints
614
- const chromeSession = new Session({ preset: "chrome-145" });
625
+ const chromeSession = new Session({ preset: "chrome-latest" });
615
626
  const firefoxSession = new Session({ preset: "firefox-133" });
616
627
 
617
628
  // Register sessions with the proxy
@@ -638,7 +649,7 @@ proxy.close();
638
649
  ```javascript
639
650
  const proxy = new LocalProxy({
640
651
  port: 0, // Port (0 = auto-select)
641
- preset: "chrome-145", // Browser fingerprint
652
+ preset: "chrome-latest", // Browser fingerprint
642
653
  timeout: 30, // Request timeout in seconds
643
654
  maxConnections: 1000, // Max concurrent connections
644
655
  tcpProxy: null, // Default upstream TCP proxy
package/lib/index.d.ts CHANGED
@@ -195,7 +195,7 @@ export class StreamResponse {
195
195
  }
196
196
 
197
197
  export interface SessionOptions {
198
- /** Browser preset to use (default: "chrome-145") */
198
+ /** Browser preset to use (default: "chrome-146") */
199
199
  preset?: string;
200
200
  /** Proxy URL (e.g., "http://user:pass@host:port" or "socks5://host:port") */
201
201
  proxy?: string;
@@ -268,6 +268,19 @@ export interface RequestOptions {
268
268
  auth?: [string, string];
269
269
  /** Optional request timeout in seconds */
270
270
  timeout?: number;
271
+ /**
272
+ * Explicit Sec-Fetch-Mode/Dest override for requests where auto-sniffing isn't enough.
273
+ *
274
+ * Valid values:
275
+ * - `"cors"` - XHR/fetch() request (Sec-Fetch-Mode: cors, Sec-Fetch-Dest: empty, Sec-Fetch-Site: same-origin)
276
+ * - `"no-cors"` - Subresource load (image/script/stylesheet tag)
277
+ * - `"navigate"` - Top-level navigation (document load, classic form POST)
278
+ * - `"websocket"` - WebSocket upgrade
279
+ *
280
+ * When unset (default), httpcloak auto-detects based on method, Accept, Content-Type, and Sec-Fetch-Dest headers.
281
+ * Set this explicitly when the auto-sniff gets it wrong (e.g., POST to a CORS endpoint without a JSON Accept header).
282
+ */
283
+ fetchMode?: "cors" | "no-cors" | "navigate" | "websocket";
271
284
  }
272
285
 
273
286
  export class Session {
@@ -337,22 +350,50 @@ export class Session {
337
350
  options(url: string, options?: RequestOptions): Promise<Response>;
338
351
 
339
352
  // Cookie management
340
- /** Get all cookies from the session */
353
+
354
+ /** Get all cookies with full metadata (domain, path, expiry, flags) */
355
+ getCookiesDetailed(): Cookie[];
356
+
357
+ /** Get a specific cookie by name with full metadata */
358
+ getCookieDetailed(name: string): Cookie | null;
359
+
360
+ /**
361
+ * Get all cookies as a flat name-value object.
362
+ * @deprecated Will return Cookie[] with full metadata in a future release. Use getCookiesDetailed() for the new format now.
363
+ */
341
364
  getCookies(): Record<string, string>;
342
365
 
343
- /** Get a specific cookie by name */
366
+ /**
367
+ * Get a specific cookie value by name.
368
+ * @deprecated Will return Cookie|null in a future release. Use getCookieDetailed() for the new format now.
369
+ */
344
370
  getCookie(name: string): string | null;
345
371
 
346
372
  /** Set a cookie in the session */
347
- setCookie(name: string, value: string): void;
348
-
349
- /** Delete a specific cookie by name */
350
- deleteCookie(name: string): void;
373
+ setCookie(
374
+ name: string,
375
+ value: string,
376
+ options?: {
377
+ domain?: string;
378
+ path?: string;
379
+ secure?: boolean;
380
+ httpOnly?: boolean;
381
+ sameSite?: string;
382
+ maxAge?: number;
383
+ expires?: string;
384
+ }
385
+ ): void;
386
+
387
+ /** Delete a specific cookie by name. If domain is omitted, deletes from all domains. */
388
+ deleteCookie(name: string, domain?: string): void;
351
389
 
352
390
  /** Clear all cookies from the session */
353
391
  clearCookies(): void;
354
392
 
355
- /** Get cookies as a property */
393
+ /**
394
+ * Get cookies as a property.
395
+ * @deprecated Will return Cookie[] with full metadata in a future release.
396
+ */
356
397
  readonly cookies: Record<string, string>;
357
398
 
358
399
  // Proxy management
@@ -619,7 +660,7 @@ export class Session {
619
660
  export interface LocalProxyOptions {
620
661
  /** Port to listen on (default: 0 for auto-assign) */
621
662
  port?: number;
622
- /** Browser preset to use (default: "chrome-145") */
663
+ /** Browser preset to use (default: "chrome-146") */
623
664
  preset?: string;
624
665
  /** Request timeout in seconds (default: 30) */
625
666
  timeout?: number;
@@ -659,7 +700,7 @@ export interface LocalProxyStats {
659
700
  *
660
701
  * @example
661
702
  * // Basic usage
662
- * const proxy = new LocalProxy({ preset: "chrome-145", tlsOnly: true });
703
+ * const proxy = new LocalProxy({ preset: "chrome-146", tlsOnly: true });
663
704
  * console.log(`Proxy running on ${proxy.proxyUrl}`);
664
705
  * // Use with any HTTP client pointing to the proxy
665
706
  * proxy.close();
@@ -816,6 +857,10 @@ export function request(method: string, url: string, options?: RequestOptions):
816
857
 
817
858
  /** Available browser presets */
818
859
  export const Preset: {
860
+ CHROME_146: string;
861
+ CHROME_146_WINDOWS: string;
862
+ CHROME_146_LINUX: string;
863
+ CHROME_146_MACOS: string;
819
864
  CHROME_145: string;
820
865
  CHROME_145_WINDOWS: string;
821
866
  CHROME_145_LINUX: string;
@@ -833,9 +878,11 @@ export const Preset: {
833
878
  CHROME_143_IOS: string;
834
879
  CHROME_144_IOS: string;
835
880
  CHROME_145_IOS: string;
881
+ CHROME_146_IOS: string;
836
882
  CHROME_143_ANDROID: string;
837
883
  CHROME_144_ANDROID: string;
838
884
  CHROME_145_ANDROID: string;
885
+ CHROME_146_ANDROID: string;
839
886
  FIREFOX_133: string;
840
887
  SAFARI_18: string;
841
888
  SAFARI_17_IOS: string;
@@ -844,9 +891,11 @@ export const Preset: {
844
891
  IOS_CHROME_143: string;
845
892
  IOS_CHROME_144: string;
846
893
  IOS_CHROME_145: string;
894
+ IOS_CHROME_146: string;
847
895
  ANDROID_CHROME_143: string;
848
896
  ANDROID_CHROME_144: string;
849
897
  ANDROID_CHROME_145: string;
898
+ ANDROID_CHROME_146: string;
850
899
  IOS_SAFARI_17: string;
851
900
  IOS_SAFARI_18: string;
852
901
  all(): string[];
@@ -984,3 +1033,66 @@ export function configureSessionCache(options: SessionCacheOptions): SessionCach
984
1033
  * After calling this, new sessions will not use distributed caching.
985
1034
  */
986
1035
  export function clearSessionCache(): void;
1036
+
1037
+ /**
1038
+ * Load a custom preset from a JSON file and register it.
1039
+ * @param filePath - Path to the preset JSON file
1040
+ * @returns The registered preset name
1041
+ */
1042
+ export function loadPreset(filePath: string): string;
1043
+
1044
+ /**
1045
+ * Load a custom preset from a JSON string and register it.
1046
+ * @param jsonData - JSON string defining the preset
1047
+ * @returns The registered preset name
1048
+ */
1049
+ export function loadPresetFromJSON(jsonData: string): string;
1050
+
1051
+ /**
1052
+ * Unregister a custom preset by name.
1053
+ * @param name - The preset name to unregister
1054
+ */
1055
+ export function unregisterPreset(name: string): void;
1056
+
1057
+ /**
1058
+ * A pool of custom fingerprint presets for rotation.
1059
+ *
1060
+ * Pools load multiple presets from a single JSON file and provide
1061
+ * round-robin or random selection. All presets are auto-registered
1062
+ * on construction, so you can pass the returned name directly to
1063
+ * `new Session({ preset: name })`.
1064
+ */
1065
+ export class PresetPool {
1066
+ /**
1067
+ * Load a preset pool from a JSON file.
1068
+ * @param filePath - Path to the pool JSON file
1069
+ */
1070
+ constructor(filePath: string);
1071
+
1072
+ /**
1073
+ * Load a preset pool from a JSON string.
1074
+ * @param jsonData - JSON string defining the pool
1075
+ */
1076
+ static fromJSON(jsonData: string): PresetPool;
1077
+
1078
+ /** Pick a preset using the pool's configured strategy. */
1079
+ pick(): string;
1080
+
1081
+ /** Pick a random preset from the pool. */
1082
+ random(): string;
1083
+
1084
+ /** Pick the next preset in round-robin order. */
1085
+ next(): string;
1086
+
1087
+ /** Get a preset by index. */
1088
+ get(index: number): string;
1089
+
1090
+ /** Number of presets in the pool. */
1091
+ readonly size: number;
1092
+
1093
+ /** Name of the preset pool. */
1094
+ readonly name: string;
1095
+
1096
+ /** Free the pool handle and unregister all its presets. */
1097
+ close(): void;
1098
+ }