rezo 1.0.11 → 1.0.13

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 (40) hide show
  1. package/dist/adapters/curl.cjs +73 -10
  2. package/dist/adapters/curl.js +73 -10
  3. package/dist/adapters/entries/curl.d.ts +66 -1
  4. package/dist/adapters/entries/fetch.d.ts +66 -1
  5. package/dist/adapters/entries/http.d.ts +66 -1
  6. package/dist/adapters/entries/http2.d.ts +66 -1
  7. package/dist/adapters/entries/react-native.d.ts +66 -1
  8. package/dist/adapters/entries/xhr.d.ts +66 -1
  9. package/dist/adapters/fetch.cjs +106 -59
  10. package/dist/adapters/fetch.js +106 -59
  11. package/dist/adapters/http.cjs +28 -15
  12. package/dist/adapters/http.js +28 -15
  13. package/dist/adapters/http2.cjs +114 -55
  14. package/dist/adapters/http2.js +114 -55
  15. package/dist/adapters/index.cjs +6 -6
  16. package/dist/cache/index.cjs +13 -13
  17. package/dist/crawler.d.ts +66 -1
  18. package/dist/entries/crawler.cjs +5 -5
  19. package/dist/index.cjs +24 -24
  20. package/dist/index.d.ts +66 -1
  21. package/dist/platform/browser.d.ts +66 -1
  22. package/dist/platform/bun.d.ts +66 -1
  23. package/dist/platform/deno.d.ts +66 -1
  24. package/dist/platform/node.d.ts +66 -1
  25. package/dist/platform/react-native.d.ts +66 -1
  26. package/dist/platform/worker.d.ts +66 -1
  27. package/dist/plugin/index.cjs +36 -36
  28. package/dist/proxy/index.cjs +2 -2
  29. package/dist/queue/index.cjs +8 -8
  30. package/dist/responses/buildError.cjs +5 -1
  31. package/dist/responses/buildError.js +5 -1
  32. package/dist/responses/buildResponse.cjs +30 -3
  33. package/dist/responses/buildResponse.js +30 -3
  34. package/dist/utils/compression.cjs +6 -6
  35. package/dist/utils/compression.js +6 -6
  36. package/dist/utils/headers.cjs +17 -0
  37. package/dist/utils/headers.js +17 -1
  38. package/dist/utils/http-config.cjs +47 -5
  39. package/dist/utils/http-config.js +47 -5
  40. package/package.json +1 -1
@@ -4,14 +4,15 @@ import { URL } from "node:url";
4
4
  import { Readable } from "node:stream";
5
5
  import { RezoError } from '../errors/rezo-error.js';
6
6
  import { buildSmartError, buildDecompressionError, builErrorFromResponse, buildDownloadError } from '../responses/buildError.js';
7
- import { Cookie } from '../utils/cookies.js';
7
+ import { RezoCookieJar } from '../utils/cookies.js';
8
8
  import RezoFormData from '../utils/form-data.js';
9
9
  import { getDefaultConfig, prepareHTTPOptions } from '../utils/http-config.js';
10
- import { RezoHeaders } from '../utils/headers.js';
10
+ import { RezoHeaders, sanitizeHttp2Headers } from '../utils/headers.js';
11
11
  import { RezoURLSearchParams } from '../utils/data-operations.js';
12
12
  import { StreamResponse } from '../responses/stream.js';
13
13
  import { DownloadResponse } from '../responses/download.js';
14
14
  import { UploadResponse } from '../responses/upload.js';
15
+ import { CompressionUtil } from '../utils/compression.js';
15
16
  import { isSameDomain, RezoPerformance } from '../utils/tools.js';
16
17
  import { ResponseCache } from '../cache/response-cache.js';
17
18
  let zstdDecompressSync = null;
@@ -142,6 +143,9 @@ class Http2SessionPool {
142
143
  reject(new Error(`HTTP/2 connection timeout after ${timeout}ms`));
143
144
  }
144
145
  }, timeout) : null;
146
+ if (timeoutId && typeof timeoutId === "object" && "unref" in timeoutId) {
147
+ timeoutId.unref();
148
+ }
145
149
  session.on("connect", () => {
146
150
  if (!settled) {
147
151
  settled = true;
@@ -166,6 +170,12 @@ class Http2SessionPool {
166
170
  if (entry) {
167
171
  entry.refCount = Math.max(0, entry.refCount - 1);
168
172
  entry.lastUsed = Date.now();
173
+ if (entry.refCount === 0) {
174
+ const socket = entry.session.socket;
175
+ if (socket && typeof socket.unref === "function") {
176
+ socket.unref();
177
+ }
178
+ }
169
179
  }
170
180
  }
171
181
  closeSession(url) {
@@ -271,38 +281,66 @@ function updateCookies(config, headers, url) {
271
281
  if (!setCookieHeaders)
272
282
  return;
273
283
  const cookieHeaderArray = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders];
274
- if (!config.responseCookies) {
275
- config.responseCookies = {
276
- array: [],
277
- serialized: [],
278
- netscape: "",
279
- string: "",
280
- setCookiesString: []
281
- };
284
+ if (cookieHeaderArray.length === 0)
285
+ return;
286
+ const jar = new RezoCookieJar;
287
+ jar.setCookiesSync(cookieHeaderArray, url);
288
+ if (config.enableCookieJar && config.cookieJar) {
289
+ config.cookieJar.setCookiesSync(cookieHeaderArray, url);
282
290
  }
283
- for (const cookieStr of cookieHeaderArray) {
284
- config.responseCookies.setCookiesString.push(cookieStr);
285
- const parts = cookieStr.split(";");
286
- const [nameValue] = parts;
287
- const [name, ...valueParts] = nameValue.split("=");
288
- const value = valueParts.join("=");
289
- if (name && value !== undefined) {
290
- const cookie = new Cookie({
291
- key: name.trim(),
292
- value: value.trim(),
293
- domain: new URL(url).hostname,
294
- path: "/",
295
- httpOnly: cookieStr.toLowerCase().includes("httponly"),
296
- secure: cookieStr.toLowerCase().includes("secure"),
297
- sameSite: "lax"
298
- });
299
- config.responseCookies.array.push(cookie);
291
+ const cookies = jar.cookies();
292
+ cookies.setCookiesString = cookieHeaderArray;
293
+ if (config.useCookies) {
294
+ const existingArray = config.responseCookies?.array || [];
295
+ for (const cookie of cookies.array) {
296
+ const existingIndex = existingArray.findIndex((c) => c.key === cookie.key && c.domain === cookie.domain);
297
+ if (existingIndex >= 0) {
298
+ existingArray[existingIndex] = cookie;
299
+ } else {
300
+ existingArray.push(cookie);
301
+ }
300
302
  }
303
+ const mergedJar = new RezoCookieJar(existingArray, url);
304
+ config.responseCookies = mergedJar.cookies();
305
+ config.responseCookies.setCookiesString = cookieHeaderArray;
306
+ } else {
307
+ config.responseCookies = cookies;
301
308
  }
302
- config.responseCookies.string = config.responseCookies.array.map((c) => `${c.key}=${c.value}`).join("; ");
303
- config.responseCookies.serialized = config.responseCookies.array.map((c) => c.toJSON());
304
- config.responseCookies.netscape = config.responseCookies.array.map((c) => c.toNetscapeFormat()).join(`
305
- `);
309
+ }
310
+ function mergeRequestAndResponseCookies(config, responseCookies, url) {
311
+ const mergedCookiesArray = [];
312
+ const cookieKeyDomainMap = new Map;
313
+ if (config.requestCookies && config.requestCookies.length > 0) {
314
+ for (const cookie of config.requestCookies) {
315
+ const key = `${cookie.key}|${cookie.domain || ""}`;
316
+ mergedCookiesArray.push(cookie);
317
+ cookieKeyDomainMap.set(key, mergedCookiesArray.length - 1);
318
+ }
319
+ }
320
+ for (const cookie of responseCookies.array) {
321
+ const key = `${cookie.key}|${cookie.domain || ""}`;
322
+ const existingIndex = cookieKeyDomainMap.get(key);
323
+ if (existingIndex !== undefined) {
324
+ mergedCookiesArray[existingIndex] = cookie;
325
+ } else {
326
+ mergedCookiesArray.push(cookie);
327
+ cookieKeyDomainMap.set(key, mergedCookiesArray.length - 1);
328
+ }
329
+ }
330
+ if (mergedCookiesArray.length > 0) {
331
+ const mergedJar = new RezoCookieJar(mergedCookiesArray, url);
332
+ return mergedJar.cookies();
333
+ }
334
+ return {
335
+ array: [],
336
+ serialized: [],
337
+ netscape: `# Netscape HTTP Cookie File
338
+ # This file was generated by Rezo HTTP client
339
+ # Based on uniqhtt cookie implementation
340
+ `,
341
+ string: "",
342
+ setCookiesString: []
343
+ };
306
344
  }
307
345
  export async function executeRequest(options, defaultOptions, jar) {
308
346
  if (!options.responseType) {
@@ -480,6 +518,8 @@ async function executeHttp2Request(fetchOptions, config, options, perform, fs, s
480
518
  if (fileName && fs && fs.existsSync(fileName)) {
481
519
  fs.unlinkSync(fileName);
482
520
  }
521
+ if (!config.errors)
522
+ config.errors = [];
483
523
  config.errors.push({
484
524
  attempt: config.retryAttempts + 1,
485
525
  error: response,
@@ -517,7 +557,7 @@ async function executeHttp2Request(fetchOptions, config, options, perform, fs, s
517
557
  }
518
558
  continue;
519
559
  }
520
- if (statusOnNext === "success") {
560
+ if (statusOnNext === "success" || statusOnNext === "error") {
521
561
  return response;
522
562
  }
523
563
  if (statusOnNext === "redirect") {
@@ -616,6 +656,13 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
616
656
  if (!headers["accept-encoding"]) {
617
657
  headers["accept-encoding"] = "gzip, deflate, br";
618
658
  }
659
+ if (body instanceof RezoFormData) {
660
+ headers["content-type"] = `multipart/form-data; boundary=${body.getBoundary()}`;
661
+ } else if (body instanceof FormData) {
662
+ const tempForm = await RezoFormData.fromNativeFormData(body);
663
+ headers["content-type"] = `multipart/form-data; boundary=${tempForm.getBoundary()}`;
664
+ fetchOptions._convertedFormData = tempForm;
665
+ }
619
666
  const eventEmitter = streamResult || downloadResult || uploadResult;
620
667
  if (eventEmitter && requestCount === 0) {
621
668
  const startEvent = {
@@ -731,6 +778,25 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
731
778
  config.timing.endTimestamp = Date.now();
732
779
  config.timing.durationMs = performance.now() - timing.startTime;
733
780
  config.timing.transferMs = timing.firstByteTime ? performance.now() - timing.firstByteTime : config.timing.durationMs;
781
+ if (!config.transfer) {
782
+ config.transfer = { requestSize: 0, responseSize: 0, headerSize: 0, bodySize: 0 };
783
+ }
784
+ if (config.transfer.requestSize === undefined) {
785
+ config.transfer.requestSize = 0;
786
+ }
787
+ if (config.transfer.requestSize === 0 && body) {
788
+ if (typeof body === "string") {
789
+ config.transfer.requestSize = Buffer.byteLength(body, "utf8");
790
+ } else if (body instanceof Buffer || body instanceof Uint8Array) {
791
+ config.transfer.requestSize = body.length;
792
+ } else if (body instanceof URLSearchParams || body instanceof RezoURLSearchParams) {
793
+ config.transfer.requestSize = Buffer.byteLength(body.toString(), "utf8");
794
+ } else if (body instanceof RezoFormData) {
795
+ config.transfer.requestSize = body.getLengthSync();
796
+ } else if (typeof body === "object") {
797
+ config.transfer.requestSize = Buffer.byteLength(JSON.stringify(body), "utf8");
798
+ }
799
+ }
734
800
  config.transfer.bodySize = contentLengthCounter;
735
801
  config.transfer.responseSize = contentLengthCounter;
736
802
  (sessionPool || Http2SessionPool.getInstance()).releaseSession(url);
@@ -739,7 +805,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
739
805
  data: "",
740
806
  status,
741
807
  statusText,
742
- headers: new RezoHeaders(responseHeaders),
808
+ headers: new RezoHeaders(sanitizeHttp2Headers(responseHeaders)),
743
809
  cookies: config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] },
744
810
  config,
745
811
  contentType: responseHeaders["content-type"],
@@ -752,14 +818,14 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
752
818
  }
753
819
  let responseBody = Buffer.concat(chunks);
754
820
  const contentEncoding = responseHeaders["content-encoding"];
755
- if (contentEncoding && contentLengthCounter > 0) {
821
+ if (contentEncoding && contentLengthCounter > 0 && CompressionUtil.shouldDecompress(contentEncoding, config)) {
756
822
  try {
757
823
  const decompressed = await decompressBuffer(responseBody, contentEncoding);
758
824
  responseBody = decompressed;
759
825
  } catch (err) {
760
826
  const error = buildDecompressionError({
761
827
  statusCode: status,
762
- headers: responseHeaders,
828
+ headers: sanitizeHttp2Headers(responseHeaders),
763
829
  contentType: responseHeaders["content-type"],
764
830
  contentLength: String(contentLengthCounter),
765
831
  cookies: config.responseCookies?.setCookiesString || [],
@@ -799,24 +865,17 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
799
865
  data = responseBody.toString("utf-8");
800
866
  }
801
867
  }
802
- if (status >= 400) {
803
- const error = builErrorFromResponse(`HTTP Error ${status}: ${statusText}`, {
804
- status,
805
- statusText,
806
- headers: new RezoHeaders(responseHeaders),
807
- data
808
- }, config, fetchOptions);
809
- _stats.statusOnNext = "error";
810
- resolve(error);
811
- return;
812
- }
813
- _stats.statusOnNext = "success";
868
+ config.status = status;
869
+ config.statusText = statusText;
870
+ _stats.statusOnNext = status >= 400 ? "error" : "success";
871
+ const responseCookies = config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] };
872
+ const mergedCookies = mergeRequestAndResponseCookies(config, responseCookies, url.href);
814
873
  const finalResponse = {
815
874
  data,
816
875
  status,
817
876
  statusText,
818
- headers: new RezoHeaders(responseHeaders),
819
- cookies: config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] },
877
+ headers: new RezoHeaders(sanitizeHttp2Headers(responseHeaders)),
878
+ cookies: mergedCookies,
820
879
  config,
821
880
  contentType,
822
881
  contentLength: contentLengthCounter,
@@ -829,11 +888,11 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
829
888
  const downloadFinishEvent = {
830
889
  status,
831
890
  statusText,
832
- headers: new RezoHeaders(responseHeaders),
891
+ headers: new RezoHeaders(sanitizeHttp2Headers(responseHeaders)),
833
892
  contentType,
834
893
  contentLength: responseBody.length,
835
894
  finalUrl: url.href,
836
- cookies: config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] },
895
+ cookies: mergedCookies,
837
896
  urls: buildUrlTree(config, url.href),
838
897
  fileName: config.fileName,
839
898
  fileSize: responseBody.length,
@@ -854,7 +913,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
854
913
  } catch (err) {
855
914
  const error = buildDownloadError({
856
915
  statusCode: status,
857
- headers: responseHeaders,
916
+ headers: sanitizeHttp2Headers(responseHeaders),
858
917
  contentType,
859
918
  contentLength: String(contentLengthCounter),
860
919
  cookies: config.responseCookies?.setCookiesString || [],
@@ -874,7 +933,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
874
933
  const streamFinishEvent = {
875
934
  status,
876
935
  statusText,
877
- headers: new RezoHeaders(responseHeaders),
936
+ headers: new RezoHeaders(sanitizeHttp2Headers(responseHeaders)),
878
937
  contentType,
879
938
  contentLength: contentLengthCounter,
880
939
  finalUrl: url.href,
@@ -900,7 +959,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
900
959
  response: {
901
960
  status,
902
961
  statusText,
903
- headers: new RezoHeaders(responseHeaders),
962
+ headers: new RezoHeaders(sanitizeHttp2Headers(responseHeaders)),
904
963
  data,
905
964
  contentType,
906
965
  contentLength: contentLengthCounter
@@ -945,7 +1004,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
945
1004
  body.pipe(req);
946
1005
  return;
947
1006
  } else {
948
- const form = await RezoFormData.fromNativeFormData(body);
1007
+ const form = fetchOptions._convertedFormData || await RezoFormData.fromNativeFormData(body);
949
1008
  form.pipe(req);
950
1009
  return;
951
1010
  }
@@ -1,6 +1,6 @@
1
- const _mod_2r8qwe = require('./picker.cjs');
2
- exports.detectRuntime = _mod_2r8qwe.detectRuntime;
3
- exports.getAdapterCapabilities = _mod_2r8qwe.getAdapterCapabilities;
4
- exports.buildAdapterContext = _mod_2r8qwe.buildAdapterContext;
5
- exports.getAvailableAdapters = _mod_2r8qwe.getAvailableAdapters;
6
- exports.selectAdapter = _mod_2r8qwe.selectAdapter;;
1
+ const _mod_h6yyuw = require('./picker.cjs');
2
+ exports.detectRuntime = _mod_h6yyuw.detectRuntime;
3
+ exports.getAdapterCapabilities = _mod_h6yyuw.getAdapterCapabilities;
4
+ exports.buildAdapterContext = _mod_h6yyuw.buildAdapterContext;
5
+ exports.getAvailableAdapters = _mod_h6yyuw.getAvailableAdapters;
6
+ exports.selectAdapter = _mod_h6yyuw.selectAdapter;;
@@ -1,13 +1,13 @@
1
- const _mod_n1lpkm = require('./lru-cache.cjs');
2
- exports.LRUCache = _mod_n1lpkm.LRUCache;;
3
- const _mod_iq5ukf = require('./dns-cache.cjs');
4
- exports.DNSCache = _mod_iq5ukf.DNSCache;
5
- exports.getGlobalDNSCache = _mod_iq5ukf.getGlobalDNSCache;
6
- exports.resetGlobalDNSCache = _mod_iq5ukf.resetGlobalDNSCache;;
7
- const _mod_f96z7x = require('./response-cache.cjs');
8
- exports.ResponseCache = _mod_f96z7x.ResponseCache;
9
- exports.normalizeResponseCacheConfig = _mod_f96z7x.normalizeResponseCacheConfig;;
10
- const _mod_j5l68j = require('./file-cacher.cjs');
11
- exports.FileCacher = _mod_j5l68j.FileCacher;;
12
- const _mod_2bqslo = require('./url-store.cjs');
13
- exports.UrlStore = _mod_2bqslo.UrlStore;;
1
+ const _mod_vgyhxh = require('./lru-cache.cjs');
2
+ exports.LRUCache = _mod_vgyhxh.LRUCache;;
3
+ const _mod_57d30y = require('./dns-cache.cjs');
4
+ exports.DNSCache = _mod_57d30y.DNSCache;
5
+ exports.getGlobalDNSCache = _mod_57d30y.getGlobalDNSCache;
6
+ exports.resetGlobalDNSCache = _mod_57d30y.resetGlobalDNSCache;;
7
+ const _mod_qx55fg = require('./response-cache.cjs');
8
+ exports.ResponseCache = _mod_qx55fg.ResponseCache;
9
+ exports.normalizeResponseCacheConfig = _mod_qx55fg.normalizeResponseCacheConfig;;
10
+ const _mod_clz0cm = require('./file-cacher.cjs');
11
+ exports.FileCacher = _mod_clz0cm.FileCacher;;
12
+ const _mod_39vswi = require('./url-store.cjs');
13
+ exports.UrlStore = _mod_39vswi.UrlStore;;
package/dist/crawler.d.ts CHANGED
@@ -2620,8 +2620,73 @@ export interface RezoRequestConfig<D = any> {
2620
2620
  maxRedirects?: number;
2621
2621
  /** Whether to automatically decompress response data */
2622
2622
  decompress?: boolean;
2623
- /** Whether to keep the connection alive for reuse */
2623
+ /**
2624
+ * Whether to keep TCP connections alive for reuse across multiple requests.
2625
+ *
2626
+ * When enabled, the underlying TCP connection is kept open after a request completes,
2627
+ * allowing subsequent requests to the same host to reuse the connection. This reduces
2628
+ * latency by avoiding the overhead of establishing new connections (TCP handshake,
2629
+ * TLS negotiation for HTTPS).
2630
+ *
2631
+ * **Behavior:**
2632
+ * - `false` (default) - Connection closes after each request. Process exits immediately.
2633
+ * - `true` - Connection stays open for reuse. Idle connections close after `keepAliveMsecs`.
2634
+ *
2635
+ * **When to use `keepAlive: true`:**
2636
+ * - Making multiple requests to the same host in sequence
2637
+ * - Long-running applications (servers, bots, scrapers)
2638
+ * - Performance-critical applications where connection overhead matters
2639
+ *
2640
+ * **When to use `keepAlive: false` (default):**
2641
+ * - Single requests or scripts that should exit immediately
2642
+ * - CLI tools that make one-off requests
2643
+ * - When you need predictable process termination
2644
+ *
2645
+ * @example
2646
+ * ```typescript
2647
+ * // Default: process exits immediately after request
2648
+ * const { data } = await rezo.get('https://api.example.com/data');
2649
+ *
2650
+ * // Keep connection alive for 1 minute (default) for subsequent requests
2651
+ * const client = new Rezo({ keepAlive: true });
2652
+ * await client.get('https://api.example.com/users');
2653
+ * await client.get('https://api.example.com/posts'); // Reuses connection
2654
+ *
2655
+ * // Custom keep-alive timeout (30 seconds)
2656
+ * const client = new Rezo({ keepAlive: true, keepAliveMsecs: 30000 });
2657
+ * ```
2658
+ *
2659
+ * @default false
2660
+ */
2624
2661
  keepAlive?: boolean;
2662
+ /**
2663
+ * How long to keep idle connections alive in milliseconds.
2664
+ *
2665
+ * Only applies when `keepAlive: true`. After this duration of inactivity,
2666
+ * the connection is closed automatically. This prevents resource leaks
2667
+ * from connections that are no longer needed.
2668
+ *
2669
+ * **Note:** Even with keep-alive enabled, the Node.js process can still exit
2670
+ * cleanly when there's no other work to do, thanks to socket unreferencing.
2671
+ *
2672
+ * @example
2673
+ * ```typescript
2674
+ * // Keep connections alive for 30 seconds
2675
+ * const client = new Rezo({
2676
+ * keepAlive: true,
2677
+ * keepAliveMsecs: 30000
2678
+ * });
2679
+ *
2680
+ * // Keep connections alive for 2 minutes
2681
+ * const client = new Rezo({
2682
+ * keepAlive: true,
2683
+ * keepAliveMsecs: 120000
2684
+ * });
2685
+ * ```
2686
+ *
2687
+ * @default 60000 (1 minute)
2688
+ */
2689
+ keepAliveMsecs?: number;
2625
2690
  withoutBodyOnRedirect?: boolean;
2626
2691
  autoSetReferer?: boolean;
2627
2692
  autoSetOrigin?: boolean;
@@ -1,5 +1,5 @@
1
- const _mod_260i4j = require('../plugin/crawler.cjs');
2
- exports.Crawler = _mod_260i4j.Crawler;;
3
- const _mod_laig8l = require('../plugin/crawler-options.cjs');
4
- exports.CrawlerOptions = _mod_laig8l.CrawlerOptions;
5
- exports.Domain = _mod_laig8l.Domain;;
1
+ const _mod_m9euun = require('../plugin/crawler.cjs');
2
+ exports.Crawler = _mod_m9euun.Crawler;;
3
+ const _mod_358g2f = require('../plugin/crawler-options.cjs');
4
+ exports.CrawlerOptions = _mod_358g2f.CrawlerOptions;
5
+ exports.Domain = _mod_358g2f.Domain;;
package/dist/index.cjs CHANGED
@@ -1,27 +1,27 @@
1
- const _mod_ivdy34 = require('./core/rezo.cjs');
2
- exports.Rezo = _mod_ivdy34.Rezo;
3
- exports.createRezoInstance = _mod_ivdy34.createRezoInstance;
4
- exports.createDefaultInstance = _mod_ivdy34.createDefaultInstance;;
5
- const _mod_eleqc6 = require('./errors/rezo-error.cjs');
6
- exports.RezoError = _mod_eleqc6.RezoError;
7
- exports.RezoErrorCode = _mod_eleqc6.RezoErrorCode;;
8
- const _mod_s3mojl = require('./utils/headers.cjs');
9
- exports.RezoHeaders = _mod_s3mojl.RezoHeaders;;
10
- const _mod_ltzvhk = require('./utils/form-data.cjs');
11
- exports.RezoFormData = _mod_ltzvhk.RezoFormData;;
12
- const _mod_9b4i5y = require('./utils/cookies.cjs');
13
- exports.RezoCookieJar = _mod_9b4i5y.RezoCookieJar;
14
- exports.Cookie = _mod_9b4i5y.Cookie;;
15
- const _mod_ip126y = require('./core/hooks.cjs');
16
- exports.createDefaultHooks = _mod_ip126y.createDefaultHooks;
17
- exports.mergeHooks = _mod_ip126y.mergeHooks;;
18
- const _mod_zptoz7 = require('./proxy/manager.cjs');
19
- exports.ProxyManager = _mod_zptoz7.ProxyManager;;
20
- const _mod_qvzoi6 = require('./queue/index.cjs');
21
- exports.RezoQueue = _mod_qvzoi6.RezoQueue;
22
- exports.HttpQueue = _mod_qvzoi6.HttpQueue;
23
- exports.Priority = _mod_qvzoi6.Priority;
24
- exports.HttpMethodPriority = _mod_qvzoi6.HttpMethodPriority;;
1
+ const _mod_txkkmz = require('./core/rezo.cjs');
2
+ exports.Rezo = _mod_txkkmz.Rezo;
3
+ exports.createRezoInstance = _mod_txkkmz.createRezoInstance;
4
+ exports.createDefaultInstance = _mod_txkkmz.createDefaultInstance;;
5
+ const _mod_a3vsp1 = require('./errors/rezo-error.cjs');
6
+ exports.RezoError = _mod_a3vsp1.RezoError;
7
+ exports.RezoErrorCode = _mod_a3vsp1.RezoErrorCode;;
8
+ const _mod_2ef980 = require('./utils/headers.cjs');
9
+ exports.RezoHeaders = _mod_2ef980.RezoHeaders;;
10
+ const _mod_e56bdp = require('./utils/form-data.cjs');
11
+ exports.RezoFormData = _mod_e56bdp.RezoFormData;;
12
+ const _mod_ss7zpn = require('./utils/cookies.cjs');
13
+ exports.RezoCookieJar = _mod_ss7zpn.RezoCookieJar;
14
+ exports.Cookie = _mod_ss7zpn.Cookie;;
15
+ const _mod_vdi6fa = require('./core/hooks.cjs');
16
+ exports.createDefaultHooks = _mod_vdi6fa.createDefaultHooks;
17
+ exports.mergeHooks = _mod_vdi6fa.mergeHooks;;
18
+ const _mod_049k4s = require('./proxy/manager.cjs');
19
+ exports.ProxyManager = _mod_049k4s.ProxyManager;;
20
+ const _mod_5l0v67 = require('./queue/index.cjs');
21
+ exports.RezoQueue = _mod_5l0v67.RezoQueue;
22
+ exports.HttpQueue = _mod_5l0v67.HttpQueue;
23
+ exports.Priority = _mod_5l0v67.Priority;
24
+ exports.HttpMethodPriority = _mod_5l0v67.HttpMethodPriority;;
25
25
  const { RezoError } = require('./errors/rezo-error.cjs');
26
26
  const isRezoError = exports.isRezoError = RezoError.isRezoError;
27
27
  const Cancel = exports.Cancel = RezoError;
package/dist/index.d.ts CHANGED
@@ -2628,8 +2628,73 @@ export interface RezoRequestConfig<D = any> {
2628
2628
  maxRedirects?: number;
2629
2629
  /** Whether to automatically decompress response data */
2630
2630
  decompress?: boolean;
2631
- /** Whether to keep the connection alive for reuse */
2631
+ /**
2632
+ * Whether to keep TCP connections alive for reuse across multiple requests.
2633
+ *
2634
+ * When enabled, the underlying TCP connection is kept open after a request completes,
2635
+ * allowing subsequent requests to the same host to reuse the connection. This reduces
2636
+ * latency by avoiding the overhead of establishing new connections (TCP handshake,
2637
+ * TLS negotiation for HTTPS).
2638
+ *
2639
+ * **Behavior:**
2640
+ * - `false` (default) - Connection closes after each request. Process exits immediately.
2641
+ * - `true` - Connection stays open for reuse. Idle connections close after `keepAliveMsecs`.
2642
+ *
2643
+ * **When to use `keepAlive: true`:**
2644
+ * - Making multiple requests to the same host in sequence
2645
+ * - Long-running applications (servers, bots, scrapers)
2646
+ * - Performance-critical applications where connection overhead matters
2647
+ *
2648
+ * **When to use `keepAlive: false` (default):**
2649
+ * - Single requests or scripts that should exit immediately
2650
+ * - CLI tools that make one-off requests
2651
+ * - When you need predictable process termination
2652
+ *
2653
+ * @example
2654
+ * ```typescript
2655
+ * // Default: process exits immediately after request
2656
+ * const { data } = await rezo.get('https://api.example.com/data');
2657
+ *
2658
+ * // Keep connection alive for 1 minute (default) for subsequent requests
2659
+ * const client = new Rezo({ keepAlive: true });
2660
+ * await client.get('https://api.example.com/users');
2661
+ * await client.get('https://api.example.com/posts'); // Reuses connection
2662
+ *
2663
+ * // Custom keep-alive timeout (30 seconds)
2664
+ * const client = new Rezo({ keepAlive: true, keepAliveMsecs: 30000 });
2665
+ * ```
2666
+ *
2667
+ * @default false
2668
+ */
2632
2669
  keepAlive?: boolean;
2670
+ /**
2671
+ * How long to keep idle connections alive in milliseconds.
2672
+ *
2673
+ * Only applies when `keepAlive: true`. After this duration of inactivity,
2674
+ * the connection is closed automatically. This prevents resource leaks
2675
+ * from connections that are no longer needed.
2676
+ *
2677
+ * **Note:** Even with keep-alive enabled, the Node.js process can still exit
2678
+ * cleanly when there's no other work to do, thanks to socket unreferencing.
2679
+ *
2680
+ * @example
2681
+ * ```typescript
2682
+ * // Keep connections alive for 30 seconds
2683
+ * const client = new Rezo({
2684
+ * keepAlive: true,
2685
+ * keepAliveMsecs: 30000
2686
+ * });
2687
+ *
2688
+ * // Keep connections alive for 2 minutes
2689
+ * const client = new Rezo({
2690
+ * keepAlive: true,
2691
+ * keepAliveMsecs: 120000
2692
+ * });
2693
+ * ```
2694
+ *
2695
+ * @default 60000 (1 minute)
2696
+ */
2697
+ keepAliveMsecs?: number;
2633
2698
  withoutBodyOnRedirect?: boolean;
2634
2699
  autoSetReferer?: boolean;
2635
2700
  autoSetOrigin?: boolean;
@@ -2502,8 +2502,73 @@ export interface RezoRequestConfig<D = any> {
2502
2502
  maxRedirects?: number;
2503
2503
  /** Whether to automatically decompress response data */
2504
2504
  decompress?: boolean;
2505
- /** Whether to keep the connection alive for reuse */
2505
+ /**
2506
+ * Whether to keep TCP connections alive for reuse across multiple requests.
2507
+ *
2508
+ * When enabled, the underlying TCP connection is kept open after a request completes,
2509
+ * allowing subsequent requests to the same host to reuse the connection. This reduces
2510
+ * latency by avoiding the overhead of establishing new connections (TCP handshake,
2511
+ * TLS negotiation for HTTPS).
2512
+ *
2513
+ * **Behavior:**
2514
+ * - `false` (default) - Connection closes after each request. Process exits immediately.
2515
+ * - `true` - Connection stays open for reuse. Idle connections close after `keepAliveMsecs`.
2516
+ *
2517
+ * **When to use `keepAlive: true`:**
2518
+ * - Making multiple requests to the same host in sequence
2519
+ * - Long-running applications (servers, bots, scrapers)
2520
+ * - Performance-critical applications where connection overhead matters
2521
+ *
2522
+ * **When to use `keepAlive: false` (default):**
2523
+ * - Single requests or scripts that should exit immediately
2524
+ * - CLI tools that make one-off requests
2525
+ * - When you need predictable process termination
2526
+ *
2527
+ * @example
2528
+ * ```typescript
2529
+ * // Default: process exits immediately after request
2530
+ * const { data } = await rezo.get('https://api.example.com/data');
2531
+ *
2532
+ * // Keep connection alive for 1 minute (default) for subsequent requests
2533
+ * const client = new Rezo({ keepAlive: true });
2534
+ * await client.get('https://api.example.com/users');
2535
+ * await client.get('https://api.example.com/posts'); // Reuses connection
2536
+ *
2537
+ * // Custom keep-alive timeout (30 seconds)
2538
+ * const client = new Rezo({ keepAlive: true, keepAliveMsecs: 30000 });
2539
+ * ```
2540
+ *
2541
+ * @default false
2542
+ */
2506
2543
  keepAlive?: boolean;
2544
+ /**
2545
+ * How long to keep idle connections alive in milliseconds.
2546
+ *
2547
+ * Only applies when `keepAlive: true`. After this duration of inactivity,
2548
+ * the connection is closed automatically. This prevents resource leaks
2549
+ * from connections that are no longer needed.
2550
+ *
2551
+ * **Note:** Even with keep-alive enabled, the Node.js process can still exit
2552
+ * cleanly when there's no other work to do, thanks to socket unreferencing.
2553
+ *
2554
+ * @example
2555
+ * ```typescript
2556
+ * // Keep connections alive for 30 seconds
2557
+ * const client = new Rezo({
2558
+ * keepAlive: true,
2559
+ * keepAliveMsecs: 30000
2560
+ * });
2561
+ *
2562
+ * // Keep connections alive for 2 minutes
2563
+ * const client = new Rezo({
2564
+ * keepAlive: true,
2565
+ * keepAliveMsecs: 120000
2566
+ * });
2567
+ * ```
2568
+ *
2569
+ * @default 60000 (1 minute)
2570
+ */
2571
+ keepAliveMsecs?: number;
2507
2572
  withoutBodyOnRedirect?: boolean;
2508
2573
  autoSetReferer?: boolean;
2509
2574
  autoSetOrigin?: boolean;