@skrillex1224/playwright-toolkit 2.1.27 → 2.1.29
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/index.cjs +74 -75
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +75 -76
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -713,16 +713,26 @@ var Humanize = {
|
|
|
713
713
|
while (current) {
|
|
714
714
|
if (isScrollable(current)) {
|
|
715
715
|
const crect = current.getBoundingClientRect();
|
|
716
|
-
if (rect.top < crect.top || rect.bottom > crect.bottom) {
|
|
716
|
+
if (rect.top < crect.top + 2 || rect.bottom > crect.bottom - 2) {
|
|
717
717
|
return true;
|
|
718
718
|
}
|
|
719
719
|
}
|
|
720
720
|
current = current.parentElement;
|
|
721
721
|
}
|
|
722
|
+
const cx = rect.left + rect.width / 2;
|
|
723
|
+
const cy = rect.top + rect.height / 2;
|
|
724
|
+
if (cx < 0 || cx > window.innerWidth || cy < 0 || cy > window.innerHeight) return true;
|
|
725
|
+
const pointElement = document.elementFromPoint(cx, cy);
|
|
726
|
+
if (pointElement) {
|
|
727
|
+
if (el.contains(pointElement) || pointElement.contains(el)) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
722
732
|
return false;
|
|
723
733
|
});
|
|
724
734
|
if (!needsScroll) {
|
|
725
|
-
logger4.debug("humanScroll", "Element already in view");
|
|
735
|
+
logger4.debug("humanScroll", "Element already in view (and unobstructed)");
|
|
726
736
|
return { element, didScroll: false, restore: async () => {
|
|
727
737
|
} };
|
|
728
738
|
}
|
|
@@ -771,9 +781,21 @@ var Humanize = {
|
|
|
771
781
|
}
|
|
772
782
|
const scrollingElement = document.scrollingElement || document.documentElement;
|
|
773
783
|
if (scrollingElement) scrollables.push(scrollingElement);
|
|
784
|
+
const cx = rect.left + rect.width / 2;
|
|
785
|
+
const cy = rect.top + rect.height / 2;
|
|
786
|
+
const viewH = window.innerHeight;
|
|
787
|
+
let isObstructed = false;
|
|
788
|
+
if (cy < 0 || cy > viewH) {
|
|
789
|
+
isObstructed = true;
|
|
790
|
+
} else {
|
|
791
|
+
const pointElement = document.elementFromPoint(cx, cy);
|
|
792
|
+
if (pointElement && !el.contains(pointElement) && !pointElement.contains(el)) {
|
|
793
|
+
isObstructed = true;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
774
796
|
let target2 = null;
|
|
775
797
|
for (const container of scrollables) {
|
|
776
|
-
const crect = container === scrollingElement ? { top: 0, bottom:
|
|
798
|
+
const crect = container === scrollingElement ? { top: 0, bottom: viewH } : container.getBoundingClientRect();
|
|
777
799
|
if (rect.top < crect.top + 2) {
|
|
778
800
|
target2 = { container, direction: -1 };
|
|
779
801
|
break;
|
|
@@ -782,26 +804,39 @@ var Humanize = {
|
|
|
782
804
|
target2 = { container, direction: 1 };
|
|
783
805
|
break;
|
|
784
806
|
}
|
|
807
|
+
if (isObstructed) {
|
|
808
|
+
const containerCenter = (crect.top + crect.bottom) / 2;
|
|
809
|
+
const elementCenter = (rect.top + rect.bottom) / 2;
|
|
810
|
+
const forceDirection = elementCenter > containerCenter ? 1 : -1;
|
|
811
|
+
const canScroll = forceDirection === 1 ? container.scrollTop < container.scrollHeight - container.clientHeight : container.scrollTop > 0;
|
|
812
|
+
if (canScroll) {
|
|
813
|
+
target2 = { container, direction: forceDirection };
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
785
817
|
}
|
|
786
818
|
if (!target2) {
|
|
787
|
-
return { moved: false, inView:
|
|
819
|
+
return { moved: false, inView: !isObstructed };
|
|
788
820
|
}
|
|
789
821
|
const maxScroll = target2.container.scrollHeight - target2.container.clientHeight;
|
|
790
822
|
if (maxScroll <= 0) {
|
|
791
|
-
return { moved: false, inView:
|
|
823
|
+
return { moved: false, inView: !isObstructed };
|
|
792
824
|
}
|
|
793
825
|
const before = target2.container.scrollTop;
|
|
794
826
|
let next = before + target2.direction * stepPx;
|
|
795
827
|
if (next < 0) next = 0;
|
|
796
828
|
if (next > maxScroll) next = maxScroll;
|
|
797
|
-
if (next
|
|
798
|
-
return { moved: false, inView:
|
|
829
|
+
if (Math.abs(next - before) < 1) {
|
|
830
|
+
return { moved: false, inView: !isObstructed };
|
|
799
831
|
}
|
|
800
832
|
target2.container.scrollTop = next;
|
|
801
833
|
return { moved: true, inView: false };
|
|
802
834
|
}, step);
|
|
803
835
|
if (result.inView) break;
|
|
804
|
-
if (!result.moved)
|
|
836
|
+
if (!result.moved && !result.inView) {
|
|
837
|
+
logger4.warn("humanScroll", "Stuck: cannot scroll further but element still obstructed/hidden");
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
805
840
|
await (0, import_delay2.default)(this.jitterMs(120, 0.4));
|
|
806
841
|
}
|
|
807
842
|
const restore = async () => {
|
|
@@ -1282,18 +1317,9 @@ var Captcha = {
|
|
|
1282
1317
|
};
|
|
1283
1318
|
|
|
1284
1319
|
// src/sse.js
|
|
1285
|
-
var
|
|
1286
|
-
var
|
|
1287
|
-
var import_https = require("https");
|
|
1320
|
+
var import_https = __toESM(require("https"), 1);
|
|
1321
|
+
var import_url = require("url");
|
|
1288
1322
|
var logger7 = createLogger("Sse");
|
|
1289
|
-
var SHARED_HTTP_AGENT = new import_http.Agent({ keepAlive: false });
|
|
1290
|
-
var SHARED_HTTPS_AGENT = new import_https.Agent({ keepAlive: false, rejectUnauthorized: false });
|
|
1291
|
-
var SHARED_GOT_OPTIONS = {
|
|
1292
|
-
http2: false,
|
|
1293
|
-
retry: { limit: 0 },
|
|
1294
|
-
throwHttpErrors: false,
|
|
1295
|
-
decompress: false
|
|
1296
|
-
};
|
|
1297
1323
|
var Sse = {
|
|
1298
1324
|
/**
|
|
1299
1325
|
* 解析 SSE 流文本
|
|
@@ -1320,7 +1346,7 @@ var Sse = {
|
|
|
1320
1346
|
return events;
|
|
1321
1347
|
},
|
|
1322
1348
|
/**
|
|
1323
|
-
* 拦截网络请求并使用
|
|
1349
|
+
* 拦截网络请求并使用 Node.js 原生 https 模块转发,以解决流式数据捕获问题。
|
|
1324
1350
|
* @param {import('playwright').Page} page
|
|
1325
1351
|
* @param {string|RegExp} urlPattern - 拦截的 URL 模式
|
|
1326
1352
|
* @param {object} options
|
|
@@ -1328,7 +1354,7 @@ var Sse = {
|
|
|
1328
1354
|
* @param {function(string, function): void} [options.onEnd] - (fullText, resolve) => void
|
|
1329
1355
|
* @param {function(Error, function): void} [options.onTimeout] - (error, reject) => void
|
|
1330
1356
|
* @param {number} [options.initialTimeout=90000] - 初始数据接收超时 (ms),默认 90s
|
|
1331
|
-
* @param {number} [options.
|
|
1357
|
+
* @param {number} [options.timeout=180000] - 整体请求超时时间 (ms),默认 180s
|
|
1332
1358
|
* @returns {Promise<any>} - 返回 Promise,当流满足条件时 resolve
|
|
1333
1359
|
*/
|
|
1334
1360
|
async intercept(page, urlPattern, options = {}) {
|
|
@@ -1354,39 +1380,19 @@ var Sse = {
|
|
|
1354
1380
|
logger7.info(`[MITM] \u5DF2\u62E6\u622A\u8BF7\u6C42: ${request.url()}`);
|
|
1355
1381
|
try {
|
|
1356
1382
|
const headers = await request.allHeaders();
|
|
1357
|
-
|
|
1383
|
+
const postData = request.postData();
|
|
1384
|
+
const urlObj = new import_url.URL(request.url());
|
|
1358
1385
|
delete headers["accept-encoding"];
|
|
1359
1386
|
delete headers["content-length"];
|
|
1360
|
-
const currentAcceptLanguage = headers["accept-language"] || "";
|
|
1361
|
-
AntiCheat.applyLocaleHeaders(headers, currentAcceptLanguage);
|
|
1362
|
-
const resolvedAcceptLanguage = headers["accept-language"] || "";
|
|
1363
|
-
const userAgent = headers["user-agent"] || "";
|
|
1364
|
-
const method = request.method();
|
|
1365
|
-
const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
|
|
1366
1387
|
const reqOptions = {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1388
|
+
hostname: urlObj.hostname,
|
|
1389
|
+
port: 443,
|
|
1390
|
+
path: urlObj.pathname + urlObj.search,
|
|
1391
|
+
method: request.method(),
|
|
1370
1392
|
headers,
|
|
1371
|
-
|
|
1372
|
-
agent: {
|
|
1373
|
-
http: SHARED_HTTP_AGENT,
|
|
1374
|
-
https: SHARED_HTTPS_AGENT
|
|
1375
|
-
},
|
|
1376
|
-
timeout: { request: overallTimeout }
|
|
1393
|
+
timeout: overallTimeout
|
|
1377
1394
|
};
|
|
1378
|
-
|
|
1379
|
-
reqOptions.body = postData;
|
|
1380
|
-
}
|
|
1381
|
-
const stream = import_got_scraping.gotScraping.stream(reqOptions);
|
|
1382
|
-
const handleStreamError = (error) => {
|
|
1383
|
-
clearAllTimers();
|
|
1384
|
-
stream.destroy();
|
|
1385
|
-
route.abort().catch(() => {
|
|
1386
|
-
});
|
|
1387
|
-
reject(error);
|
|
1388
|
-
};
|
|
1389
|
-
stream.on("response", (res) => {
|
|
1395
|
+
const req = import_https.default.request(reqOptions, (res) => {
|
|
1390
1396
|
const chunks = [];
|
|
1391
1397
|
let accumulatedText = "";
|
|
1392
1398
|
res.on("data", (chunk) => {
|
|
@@ -1409,7 +1415,6 @@ var Sse = {
|
|
|
1409
1415
|
}
|
|
1410
1416
|
}
|
|
1411
1417
|
});
|
|
1412
|
-
res.on("error", handleStreamError);
|
|
1413
1418
|
res.on("end", () => {
|
|
1414
1419
|
logger7.info("[MITM] \u4E0A\u6E38\u54CD\u5E94\u7ED3\u675F");
|
|
1415
1420
|
clearAllTimers();
|
|
@@ -1422,28 +1427,22 @@ var Sse = {
|
|
|
1422
1427
|
} else if (!onData) {
|
|
1423
1428
|
resolve(accumulatedText);
|
|
1424
1429
|
}
|
|
1425
|
-
const resHeaders = {};
|
|
1426
|
-
for (const [key, value] of Object.entries(res.headers || {})) {
|
|
1427
|
-
if (Array.isArray(value)) {
|
|
1428
|
-
resHeaders[key] = value.join(", ");
|
|
1429
|
-
} else if (value) {
|
|
1430
|
-
resHeaders[key] = String(value);
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
delete resHeaders["content-encoding"];
|
|
1434
|
-
delete resHeaders["content-length"];
|
|
1435
|
-
delete resHeaders["transfer-encoding"];
|
|
1436
|
-
delete resHeaders["connection"];
|
|
1437
|
-
delete resHeaders["keep-alive"];
|
|
1438
1430
|
route.fulfill({
|
|
1439
|
-
status: res.statusCode
|
|
1440
|
-
headers:
|
|
1431
|
+
status: res.statusCode,
|
|
1432
|
+
headers: res.headers,
|
|
1441
1433
|
body: Buffer.concat(chunks)
|
|
1442
1434
|
}).catch(() => {
|
|
1443
1435
|
});
|
|
1444
1436
|
});
|
|
1445
1437
|
});
|
|
1446
|
-
|
|
1438
|
+
req.on("error", (e) => {
|
|
1439
|
+
clearAllTimers();
|
|
1440
|
+
route.abort().catch(() => {
|
|
1441
|
+
});
|
|
1442
|
+
reject(e);
|
|
1443
|
+
});
|
|
1444
|
+
if (postData) req.write(postData);
|
|
1445
|
+
req.end();
|
|
1447
1446
|
} catch (e) {
|
|
1448
1447
|
clearAllTimers();
|
|
1449
1448
|
route.continue().catch(() => {
|
|
@@ -1502,12 +1501,12 @@ var Sse = {
|
|
|
1502
1501
|
};
|
|
1503
1502
|
|
|
1504
1503
|
// src/interception.js
|
|
1505
|
-
var
|
|
1506
|
-
var
|
|
1504
|
+
var import_got_scraping = require("got-scraping");
|
|
1505
|
+
var import_http = require("http");
|
|
1507
1506
|
var import_https2 = require("https");
|
|
1508
1507
|
var logger8 = createLogger("Interception");
|
|
1509
|
-
var
|
|
1510
|
-
var
|
|
1508
|
+
var SHARED_HTTP_AGENT = new import_http.Agent({ keepAlive: false });
|
|
1509
|
+
var SHARED_HTTPS_AGENT = new import_https2.Agent({ keepAlive: false, rejectUnauthorized: false });
|
|
1511
1510
|
var DirectConfig = {
|
|
1512
1511
|
/** 直连请求超时时间(秒) */
|
|
1513
1512
|
directTimeout: 12,
|
|
@@ -1560,7 +1559,7 @@ var DEFAULT_BLOCKING_CONFIG = {
|
|
|
1560
1559
|
/** 额外自定义扩展名列表 */
|
|
1561
1560
|
customExtensions: []
|
|
1562
1561
|
};
|
|
1563
|
-
var
|
|
1562
|
+
var SHARED_GOT_OPTIONS = {
|
|
1564
1563
|
http2: false,
|
|
1565
1564
|
// 禁用 HTTP2 避免在拦截场景下的握手兼容性问题
|
|
1566
1565
|
retry: { limit: 0 },
|
|
@@ -1669,8 +1668,8 @@ var Interception = {
|
|
|
1669
1668
|
const userAgent = reqHeaders["user-agent"] || "";
|
|
1670
1669
|
const method = request.method();
|
|
1671
1670
|
const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
|
|
1672
|
-
const response = await (0,
|
|
1673
|
-
...
|
|
1671
|
+
const response = await (0, import_got_scraping.gotScraping)({
|
|
1672
|
+
...SHARED_GOT_OPTIONS,
|
|
1674
1673
|
// 应用通用配置
|
|
1675
1674
|
url,
|
|
1676
1675
|
method,
|
|
@@ -1682,8 +1681,8 @@ var Interception = {
|
|
|
1682
1681
|
headerGeneratorOptions: AntiCheat.getTlsFingerprintOptions(userAgent, resolvedAcceptLanguage),
|
|
1683
1682
|
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1684
1683
|
agent: {
|
|
1685
|
-
http:
|
|
1686
|
-
https:
|
|
1684
|
+
http: SHARED_HTTP_AGENT,
|
|
1685
|
+
https: SHARED_HTTPS_AGENT
|
|
1687
1686
|
},
|
|
1688
1687
|
// 超时时间
|
|
1689
1688
|
timeout: { request: DirectConfig.directTimeout * 1e3 }
|