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.
- package/dist/adapters/curl.cjs +73 -10
- package/dist/adapters/curl.js +73 -10
- package/dist/adapters/entries/curl.d.ts +66 -1
- package/dist/adapters/entries/fetch.d.ts +66 -1
- package/dist/adapters/entries/http.d.ts +66 -1
- package/dist/adapters/entries/http2.d.ts +66 -1
- package/dist/adapters/entries/react-native.d.ts +66 -1
- package/dist/adapters/entries/xhr.d.ts +66 -1
- package/dist/adapters/fetch.cjs +106 -59
- package/dist/adapters/fetch.js +106 -59
- package/dist/adapters/http.cjs +28 -15
- package/dist/adapters/http.js +28 -15
- package/dist/adapters/http2.cjs +114 -55
- package/dist/adapters/http2.js +114 -55
- package/dist/adapters/index.cjs +6 -6
- package/dist/cache/index.cjs +13 -13
- package/dist/crawler.d.ts +66 -1
- package/dist/entries/crawler.cjs +5 -5
- package/dist/index.cjs +24 -24
- package/dist/index.d.ts +66 -1
- package/dist/platform/browser.d.ts +66 -1
- package/dist/platform/bun.d.ts +66 -1
- package/dist/platform/deno.d.ts +66 -1
- package/dist/platform/node.d.ts +66 -1
- package/dist/platform/react-native.d.ts +66 -1
- package/dist/platform/worker.d.ts +66 -1
- package/dist/plugin/index.cjs +36 -36
- package/dist/proxy/index.cjs +2 -2
- package/dist/queue/index.cjs +8 -8
- package/dist/responses/buildError.cjs +5 -1
- package/dist/responses/buildError.js +5 -1
- package/dist/responses/buildResponse.cjs +30 -3
- package/dist/responses/buildResponse.js +30 -3
- package/dist/utils/compression.cjs +6 -6
- package/dist/utils/compression.js +6 -6
- package/dist/utils/headers.cjs +17 -0
- package/dist/utils/headers.js +17 -1
- package/dist/utils/http-config.cjs +47 -5
- package/dist/utils/http-config.js +47 -5
- package/package.json +1 -1
package/dist/adapters/curl.cjs
CHANGED
|
@@ -7,7 +7,7 @@ const { Readable } = require("node:stream");
|
|
|
7
7
|
const { EventEmitter } = require("node:events");
|
|
8
8
|
const { RezoError } = require('../errors/rezo-error.cjs');
|
|
9
9
|
const { buildSmartError } = require('../responses/buildError.cjs');
|
|
10
|
-
const { Cookie } = require('../utils/cookies.cjs');
|
|
10
|
+
const { RezoCookieJar, Cookie } = require('../utils/cookies.cjs');
|
|
11
11
|
const RezoFormData = require('../utils/form-data.cjs');
|
|
12
12
|
const { existsSync } = require("node:fs");
|
|
13
13
|
const { getDefaultConfig, prepareHTTPOptions } = require('../utils/http-config.cjs');
|
|
@@ -16,6 +16,24 @@ const { StreamResponse } = require('../responses/stream.cjs');
|
|
|
16
16
|
const { DownloadResponse } = require('../responses/download.cjs');
|
|
17
17
|
const { UploadResponse } = require('../responses/upload.cjs');
|
|
18
18
|
const { RezoPerformance } = require('../utils/tools.cjs');
|
|
19
|
+
function mergeRequestAndResponseCookies(requestCookies, responseCookies) {
|
|
20
|
+
if (!requestCookies || requestCookies.length === 0) {
|
|
21
|
+
return responseCookies;
|
|
22
|
+
}
|
|
23
|
+
if (responseCookies.length === 0) {
|
|
24
|
+
return requestCookies;
|
|
25
|
+
}
|
|
26
|
+
const cookieMap = new Map;
|
|
27
|
+
for (const cookie of requestCookies) {
|
|
28
|
+
const key = `${cookie.key}|${cookie.domain || ""}`;
|
|
29
|
+
cookieMap.set(key, cookie);
|
|
30
|
+
}
|
|
31
|
+
for (const cookie of responseCookies) {
|
|
32
|
+
const key = `${cookie.key}|${cookie.domain || ""}`;
|
|
33
|
+
cookieMap.set(key, cookie);
|
|
34
|
+
}
|
|
35
|
+
return Array.from(cookieMap.values());
|
|
36
|
+
}
|
|
19
37
|
|
|
20
38
|
class CurlCapabilities {
|
|
21
39
|
static instance;
|
|
@@ -261,7 +279,7 @@ class CurlCommandBuilder {
|
|
|
261
279
|
this.buildDownloadOptions(config, originalRequest, createdTempFiles);
|
|
262
280
|
this.buildHeaders(config);
|
|
263
281
|
this.buildRedirectOptions(config, originalRequest);
|
|
264
|
-
this.buildRequestBody(config, createdTempFiles);
|
|
282
|
+
this.buildRequestBody(config, originalRequest, createdTempFiles);
|
|
265
283
|
if (originalRequest.onUploadProgress || originalRequest.onDownloadProgress) {
|
|
266
284
|
this.addArg("--progress-bar");
|
|
267
285
|
}
|
|
@@ -1290,11 +1308,11 @@ class CurlCommandBuilder {
|
|
|
1290
1308
|
this.addArg("--max-redirs", "0");
|
|
1291
1309
|
}
|
|
1292
1310
|
}
|
|
1293
|
-
buildRequestBody(config, tempFiles) {
|
|
1294
|
-
|
|
1311
|
+
buildRequestBody(config, originalRequest, tempFiles) {
|
|
1312
|
+
const data = originalRequest.body ?? config.data;
|
|
1313
|
+
if (!data) {
|
|
1295
1314
|
return;
|
|
1296
1315
|
}
|
|
1297
|
-
const data = config.data;
|
|
1298
1316
|
if (typeof data === "string") {
|
|
1299
1317
|
this.addArg("-d", data);
|
|
1300
1318
|
} else if (Buffer.isBuffer(data)) {
|
|
@@ -1304,7 +1322,6 @@ class CurlCommandBuilder {
|
|
|
1304
1322
|
this.addArg("--data-binary", `@${dataFile}`);
|
|
1305
1323
|
} else if (data instanceof RezoFormData) {
|
|
1306
1324
|
const formData = data;
|
|
1307
|
-
const knownLength = formData.getLengthSync?.() || 0;
|
|
1308
1325
|
const formDataFile = this.tempFiles.createTempFile("formdata", ".txt");
|
|
1309
1326
|
const formBuffer = formData.getBuffer?.();
|
|
1310
1327
|
if (formBuffer) {
|
|
@@ -1315,6 +1332,7 @@ class CurlCommandBuilder {
|
|
|
1315
1332
|
if (boundary) {
|
|
1316
1333
|
this.addArg("-H", `Content-Type: multipart/form-data; boundary=${boundary}`);
|
|
1317
1334
|
}
|
|
1335
|
+
this.addArg("-H", `Content-Length: ${formBuffer.length}`);
|
|
1318
1336
|
}
|
|
1319
1337
|
} else if (data instanceof Readable) {
|
|
1320
1338
|
this.addArg("-d", "@-");
|
|
@@ -1324,7 +1342,8 @@ class CurlCommandBuilder {
|
|
|
1324
1342
|
}
|
|
1325
1343
|
buildWriteOutFormat() {
|
|
1326
1344
|
return [
|
|
1327
|
-
|
|
1345
|
+
`
|
|
1346
|
+
---CURL_STATS_START---`,
|
|
1328
1347
|
"http_code:%{http_code}",
|
|
1329
1348
|
"time_namelookup:%{time_namelookup}",
|
|
1330
1349
|
"time_connect:%{time_connect}",
|
|
@@ -1344,7 +1363,8 @@ class CurlCommandBuilder {
|
|
|
1344
1363
|
"ssl_verify_result:%{ssl_verify_result}",
|
|
1345
1364
|
"content_type:%{content_type}",
|
|
1346
1365
|
"---CURL_STATS_END---"
|
|
1347
|
-
].join(
|
|
1366
|
+
].join(`
|
|
1367
|
+
`);
|
|
1348
1368
|
}
|
|
1349
1369
|
}
|
|
1350
1370
|
|
|
@@ -1381,7 +1401,24 @@ class CurlResponseParser {
|
|
|
1381
1401
|
const statusText = this.getStatusText(status);
|
|
1382
1402
|
const headers = this.parseHeaders(headerSection);
|
|
1383
1403
|
const rezoHeaders = new RezoHeaders(headers);
|
|
1384
|
-
const
|
|
1404
|
+
const responseCookies = this.parseCookies(headers);
|
|
1405
|
+
const mergedCookieArray = mergeRequestAndResponseCookies(config.requestCookies, responseCookies.array);
|
|
1406
|
+
let cookies;
|
|
1407
|
+
if (mergedCookieArray.length > 0) {
|
|
1408
|
+
const mergedJar = new RezoCookieJar(mergedCookieArray, config.url || "");
|
|
1409
|
+
cookies = mergedJar.cookies();
|
|
1410
|
+
} else {
|
|
1411
|
+
cookies = {
|
|
1412
|
+
array: [],
|
|
1413
|
+
serialized: [],
|
|
1414
|
+
netscape: `# Netscape HTTP Cookie File
|
|
1415
|
+
# This file was generated by Rezo HTTP client
|
|
1416
|
+
# Based on uniqhtt cookie implementation
|
|
1417
|
+
`,
|
|
1418
|
+
string: "",
|
|
1419
|
+
setCookiesString: []
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1385
1422
|
let data;
|
|
1386
1423
|
const contentType = stats["content_type"] || rezoHeaders.get("content-type") || "";
|
|
1387
1424
|
const responseType = config.responseType || originalRequest.responseType || "auto";
|
|
@@ -1408,6 +1445,25 @@ class CurlResponseParser {
|
|
|
1408
1445
|
durationMs: totalMs
|
|
1409
1446
|
};
|
|
1410
1447
|
config.timing = timing;
|
|
1448
|
+
config.status = status;
|
|
1449
|
+
config.statusText = statusText;
|
|
1450
|
+
const isSecure = config.url?.startsWith("https") || false;
|
|
1451
|
+
config.adapterUsed = "curl";
|
|
1452
|
+
config.isSecure = isSecure;
|
|
1453
|
+
config.finalUrl = stats["redirect_url"] || config.url || "";
|
|
1454
|
+
if (!config.network) {
|
|
1455
|
+
config.network = {};
|
|
1456
|
+
}
|
|
1457
|
+
config.network.protocol = isSecure ? "https" : "http";
|
|
1458
|
+
config.network.httpVersion = headerSection.match(/HTTP\/([\d.]+)/)?.[1] || "1.1";
|
|
1459
|
+
if (!config.transfer) {
|
|
1460
|
+
config.transfer = { requestSize: 0, responseSize: 0, headerSize: 0, bodySize: 0 };
|
|
1461
|
+
}
|
|
1462
|
+
config.transfer.requestSize = parseInt(stats["size_upload"]) || 0;
|
|
1463
|
+
config.transfer.responseSize = parseInt(stats["size_download"]) || responseBody.length;
|
|
1464
|
+
config.transfer.bodySize = responseBody.length;
|
|
1465
|
+
config.transfer.headerSize = headerSection.length;
|
|
1466
|
+
config.responseCookies = cookies;
|
|
1411
1467
|
const urls = [config.url];
|
|
1412
1468
|
if (stats["redirect_url"]) {
|
|
1413
1469
|
urls.push(stats["redirect_url"]);
|
|
@@ -1507,7 +1563,7 @@ class CurlExecutor {
|
|
|
1507
1563
|
}
|
|
1508
1564
|
buildFinalUrl(config) {
|
|
1509
1565
|
let url = config.url;
|
|
1510
|
-
if (config.baseURL) {
|
|
1566
|
+
if (config.baseURL && !url.startsWith("http://") && !url.startsWith("https://")) {
|
|
1511
1567
|
url = config.baseURL.replace(/\/$/, "") + "/" + url.replace(/^\//, "");
|
|
1512
1568
|
}
|
|
1513
1569
|
if (config.params && Object.keys(config.params).length > 0) {
|
|
@@ -1596,6 +1652,13 @@ class CurlExecutor {
|
|
|
1596
1652
|
curl.on("close", (code) => {
|
|
1597
1653
|
try {
|
|
1598
1654
|
if (code !== 0 && code !== null) {
|
|
1655
|
+
if (code === 22 && stdout) {
|
|
1656
|
+
try {
|
|
1657
|
+
const response = CurlResponseParser.parse(stdout, stderr, config, originalRequest);
|
|
1658
|
+
resolve(response);
|
|
1659
|
+
return;
|
|
1660
|
+
} catch {}
|
|
1661
|
+
}
|
|
1599
1662
|
const errorCode = this.mapCurlErrorCode(code);
|
|
1600
1663
|
const errorMessage = this.buildDetailedErrorMessage(code, stderr, config);
|
|
1601
1664
|
const rezoError = new RezoError(errorMessage, config, errorCode);
|
package/dist/adapters/curl.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Readable } from "node:stream";
|
|
|
7
7
|
import { EventEmitter } from "node:events";
|
|
8
8
|
import { RezoError } from '../errors/rezo-error.js';
|
|
9
9
|
import { buildSmartError } from '../responses/buildError.js';
|
|
10
|
-
import { Cookie } from '../utils/cookies.js';
|
|
10
|
+
import { RezoCookieJar, Cookie } from '../utils/cookies.js';
|
|
11
11
|
import RezoFormData from '../utils/form-data.js';
|
|
12
12
|
import { existsSync } from "node:fs";
|
|
13
13
|
import { getDefaultConfig, prepareHTTPOptions } from '../utils/http-config.js';
|
|
@@ -16,6 +16,24 @@ import { StreamResponse } from '../responses/stream.js';
|
|
|
16
16
|
import { DownloadResponse } from '../responses/download.js';
|
|
17
17
|
import { UploadResponse } from '../responses/upload.js';
|
|
18
18
|
import { RezoPerformance } from '../utils/tools.js';
|
|
19
|
+
function mergeRequestAndResponseCookies(requestCookies, responseCookies) {
|
|
20
|
+
if (!requestCookies || requestCookies.length === 0) {
|
|
21
|
+
return responseCookies;
|
|
22
|
+
}
|
|
23
|
+
if (responseCookies.length === 0) {
|
|
24
|
+
return requestCookies;
|
|
25
|
+
}
|
|
26
|
+
const cookieMap = new Map;
|
|
27
|
+
for (const cookie of requestCookies) {
|
|
28
|
+
const key = `${cookie.key}|${cookie.domain || ""}`;
|
|
29
|
+
cookieMap.set(key, cookie);
|
|
30
|
+
}
|
|
31
|
+
for (const cookie of responseCookies) {
|
|
32
|
+
const key = `${cookie.key}|${cookie.domain || ""}`;
|
|
33
|
+
cookieMap.set(key, cookie);
|
|
34
|
+
}
|
|
35
|
+
return Array.from(cookieMap.values());
|
|
36
|
+
}
|
|
19
37
|
|
|
20
38
|
class CurlCapabilities {
|
|
21
39
|
static instance;
|
|
@@ -261,7 +279,7 @@ class CurlCommandBuilder {
|
|
|
261
279
|
this.buildDownloadOptions(config, originalRequest, createdTempFiles);
|
|
262
280
|
this.buildHeaders(config);
|
|
263
281
|
this.buildRedirectOptions(config, originalRequest);
|
|
264
|
-
this.buildRequestBody(config, createdTempFiles);
|
|
282
|
+
this.buildRequestBody(config, originalRequest, createdTempFiles);
|
|
265
283
|
if (originalRequest.onUploadProgress || originalRequest.onDownloadProgress) {
|
|
266
284
|
this.addArg("--progress-bar");
|
|
267
285
|
}
|
|
@@ -1290,11 +1308,11 @@ class CurlCommandBuilder {
|
|
|
1290
1308
|
this.addArg("--max-redirs", "0");
|
|
1291
1309
|
}
|
|
1292
1310
|
}
|
|
1293
|
-
buildRequestBody(config, tempFiles) {
|
|
1294
|
-
|
|
1311
|
+
buildRequestBody(config, originalRequest, tempFiles) {
|
|
1312
|
+
const data = originalRequest.body ?? config.data;
|
|
1313
|
+
if (!data) {
|
|
1295
1314
|
return;
|
|
1296
1315
|
}
|
|
1297
|
-
const data = config.data;
|
|
1298
1316
|
if (typeof data === "string") {
|
|
1299
1317
|
this.addArg("-d", data);
|
|
1300
1318
|
} else if (Buffer.isBuffer(data)) {
|
|
@@ -1304,7 +1322,6 @@ class CurlCommandBuilder {
|
|
|
1304
1322
|
this.addArg("--data-binary", `@${dataFile}`);
|
|
1305
1323
|
} else if (data instanceof RezoFormData) {
|
|
1306
1324
|
const formData = data;
|
|
1307
|
-
const knownLength = formData.getLengthSync?.() || 0;
|
|
1308
1325
|
const formDataFile = this.tempFiles.createTempFile("formdata", ".txt");
|
|
1309
1326
|
const formBuffer = formData.getBuffer?.();
|
|
1310
1327
|
if (formBuffer) {
|
|
@@ -1315,6 +1332,7 @@ class CurlCommandBuilder {
|
|
|
1315
1332
|
if (boundary) {
|
|
1316
1333
|
this.addArg("-H", `Content-Type: multipart/form-data; boundary=${boundary}`);
|
|
1317
1334
|
}
|
|
1335
|
+
this.addArg("-H", `Content-Length: ${formBuffer.length}`);
|
|
1318
1336
|
}
|
|
1319
1337
|
} else if (data instanceof Readable) {
|
|
1320
1338
|
this.addArg("-d", "@-");
|
|
@@ -1324,7 +1342,8 @@ class CurlCommandBuilder {
|
|
|
1324
1342
|
}
|
|
1325
1343
|
buildWriteOutFormat() {
|
|
1326
1344
|
return [
|
|
1327
|
-
|
|
1345
|
+
`
|
|
1346
|
+
---CURL_STATS_START---`,
|
|
1328
1347
|
"http_code:%{http_code}",
|
|
1329
1348
|
"time_namelookup:%{time_namelookup}",
|
|
1330
1349
|
"time_connect:%{time_connect}",
|
|
@@ -1344,7 +1363,8 @@ class CurlCommandBuilder {
|
|
|
1344
1363
|
"ssl_verify_result:%{ssl_verify_result}",
|
|
1345
1364
|
"content_type:%{content_type}",
|
|
1346
1365
|
"---CURL_STATS_END---"
|
|
1347
|
-
].join(
|
|
1366
|
+
].join(`
|
|
1367
|
+
`);
|
|
1348
1368
|
}
|
|
1349
1369
|
}
|
|
1350
1370
|
|
|
@@ -1381,7 +1401,24 @@ class CurlResponseParser {
|
|
|
1381
1401
|
const statusText = this.getStatusText(status);
|
|
1382
1402
|
const headers = this.parseHeaders(headerSection);
|
|
1383
1403
|
const rezoHeaders = new RezoHeaders(headers);
|
|
1384
|
-
const
|
|
1404
|
+
const responseCookies = this.parseCookies(headers);
|
|
1405
|
+
const mergedCookieArray = mergeRequestAndResponseCookies(config.requestCookies, responseCookies.array);
|
|
1406
|
+
let cookies;
|
|
1407
|
+
if (mergedCookieArray.length > 0) {
|
|
1408
|
+
const mergedJar = new RezoCookieJar(mergedCookieArray, config.url || "");
|
|
1409
|
+
cookies = mergedJar.cookies();
|
|
1410
|
+
} else {
|
|
1411
|
+
cookies = {
|
|
1412
|
+
array: [],
|
|
1413
|
+
serialized: [],
|
|
1414
|
+
netscape: `# Netscape HTTP Cookie File
|
|
1415
|
+
# This file was generated by Rezo HTTP client
|
|
1416
|
+
# Based on uniqhtt cookie implementation
|
|
1417
|
+
`,
|
|
1418
|
+
string: "",
|
|
1419
|
+
setCookiesString: []
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1385
1422
|
let data;
|
|
1386
1423
|
const contentType = stats["content_type"] || rezoHeaders.get("content-type") || "";
|
|
1387
1424
|
const responseType = config.responseType || originalRequest.responseType || "auto";
|
|
@@ -1408,6 +1445,25 @@ class CurlResponseParser {
|
|
|
1408
1445
|
durationMs: totalMs
|
|
1409
1446
|
};
|
|
1410
1447
|
config.timing = timing;
|
|
1448
|
+
config.status = status;
|
|
1449
|
+
config.statusText = statusText;
|
|
1450
|
+
const isSecure = config.url?.startsWith("https") || false;
|
|
1451
|
+
config.adapterUsed = "curl";
|
|
1452
|
+
config.isSecure = isSecure;
|
|
1453
|
+
config.finalUrl = stats["redirect_url"] || config.url || "";
|
|
1454
|
+
if (!config.network) {
|
|
1455
|
+
config.network = {};
|
|
1456
|
+
}
|
|
1457
|
+
config.network.protocol = isSecure ? "https" : "http";
|
|
1458
|
+
config.network.httpVersion = headerSection.match(/HTTP\/([\d.]+)/)?.[1] || "1.1";
|
|
1459
|
+
if (!config.transfer) {
|
|
1460
|
+
config.transfer = { requestSize: 0, responseSize: 0, headerSize: 0, bodySize: 0 };
|
|
1461
|
+
}
|
|
1462
|
+
config.transfer.requestSize = parseInt(stats["size_upload"]) || 0;
|
|
1463
|
+
config.transfer.responseSize = parseInt(stats["size_download"]) || responseBody.length;
|
|
1464
|
+
config.transfer.bodySize = responseBody.length;
|
|
1465
|
+
config.transfer.headerSize = headerSection.length;
|
|
1466
|
+
config.responseCookies = cookies;
|
|
1411
1467
|
const urls = [config.url];
|
|
1412
1468
|
if (stats["redirect_url"]) {
|
|
1413
1469
|
urls.push(stats["redirect_url"]);
|
|
@@ -1507,7 +1563,7 @@ class CurlExecutor {
|
|
|
1507
1563
|
}
|
|
1508
1564
|
buildFinalUrl(config) {
|
|
1509
1565
|
let url = config.url;
|
|
1510
|
-
if (config.baseURL) {
|
|
1566
|
+
if (config.baseURL && !url.startsWith("http://") && !url.startsWith("https://")) {
|
|
1511
1567
|
url = config.baseURL.replace(/\/$/, "") + "/" + url.replace(/^\//, "");
|
|
1512
1568
|
}
|
|
1513
1569
|
if (config.params && Object.keys(config.params).length > 0) {
|
|
@@ -1596,6 +1652,13 @@ class CurlExecutor {
|
|
|
1596
1652
|
curl.on("close", (code) => {
|
|
1597
1653
|
try {
|
|
1598
1654
|
if (code !== 0 && code !== null) {
|
|
1655
|
+
if (code === 22 && stdout) {
|
|
1656
|
+
try {
|
|
1657
|
+
const response = CurlResponseParser.parse(stdout, stderr, config, originalRequest);
|
|
1658
|
+
resolve(response);
|
|
1659
|
+
return;
|
|
1660
|
+
} catch {}
|
|
1661
|
+
}
|
|
1599
1662
|
const errorCode = this.mapCurlErrorCode(code);
|
|
1600
1663
|
const errorMessage = this.buildDetailedErrorMessage(code, stderr, config);
|
|
1601
1664
|
const rezoError = new RezoError(errorMessage, config, errorCode);
|
|
@@ -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
|
-
/**
|
|
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;
|
|
@@ -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
|
-
/**
|
|
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;
|
|
@@ -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
|
-
/**
|
|
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;
|
|
@@ -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
|
-
/**
|
|
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;
|