@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.js CHANGED
@@ -684,16 +684,26 @@ var Humanize = {
684
684
  while (current) {
685
685
  if (isScrollable(current)) {
686
686
  const crect = current.getBoundingClientRect();
687
- if (rect.top < crect.top || rect.bottom > crect.bottom) {
687
+ if (rect.top < crect.top + 2 || rect.bottom > crect.bottom - 2) {
688
688
  return true;
689
689
  }
690
690
  }
691
691
  current = current.parentElement;
692
692
  }
693
+ const cx = rect.left + rect.width / 2;
694
+ const cy = rect.top + rect.height / 2;
695
+ if (cx < 0 || cx > window.innerWidth || cy < 0 || cy > window.innerHeight) return true;
696
+ const pointElement = document.elementFromPoint(cx, cy);
697
+ if (pointElement) {
698
+ if (el.contains(pointElement) || pointElement.contains(el)) {
699
+ return false;
700
+ }
701
+ return true;
702
+ }
693
703
  return false;
694
704
  });
695
705
  if (!needsScroll) {
696
- logger4.debug("humanScroll", "Element already in view");
706
+ logger4.debug("humanScroll", "Element already in view (and unobstructed)");
697
707
  return { element, didScroll: false, restore: async () => {
698
708
  } };
699
709
  }
@@ -742,9 +752,21 @@ var Humanize = {
742
752
  }
743
753
  const scrollingElement = document.scrollingElement || document.documentElement;
744
754
  if (scrollingElement) scrollables.push(scrollingElement);
755
+ const cx = rect.left + rect.width / 2;
756
+ const cy = rect.top + rect.height / 2;
757
+ const viewH = window.innerHeight;
758
+ let isObstructed = false;
759
+ if (cy < 0 || cy > viewH) {
760
+ isObstructed = true;
761
+ } else {
762
+ const pointElement = document.elementFromPoint(cx, cy);
763
+ if (pointElement && !el.contains(pointElement) && !pointElement.contains(el)) {
764
+ isObstructed = true;
765
+ }
766
+ }
745
767
  let target2 = null;
746
768
  for (const container of scrollables) {
747
- const crect = container === scrollingElement ? { top: 0, bottom: window.innerHeight } : container.getBoundingClientRect();
769
+ const crect = container === scrollingElement ? { top: 0, bottom: viewH } : container.getBoundingClientRect();
748
770
  if (rect.top < crect.top + 2) {
749
771
  target2 = { container, direction: -1 };
750
772
  break;
@@ -753,26 +775,39 @@ var Humanize = {
753
775
  target2 = { container, direction: 1 };
754
776
  break;
755
777
  }
778
+ if (isObstructed) {
779
+ const containerCenter = (crect.top + crect.bottom) / 2;
780
+ const elementCenter = (rect.top + rect.bottom) / 2;
781
+ const forceDirection = elementCenter > containerCenter ? 1 : -1;
782
+ const canScroll = forceDirection === 1 ? container.scrollTop < container.scrollHeight - container.clientHeight : container.scrollTop > 0;
783
+ if (canScroll) {
784
+ target2 = { container, direction: forceDirection };
785
+ break;
786
+ }
787
+ }
756
788
  }
757
789
  if (!target2) {
758
- return { moved: false, inView: true };
790
+ return { moved: false, inView: !isObstructed };
759
791
  }
760
792
  const maxScroll = target2.container.scrollHeight - target2.container.clientHeight;
761
793
  if (maxScroll <= 0) {
762
- return { moved: false, inView: false };
794
+ return { moved: false, inView: !isObstructed };
763
795
  }
764
796
  const before = target2.container.scrollTop;
765
797
  let next = before + target2.direction * stepPx;
766
798
  if (next < 0) next = 0;
767
799
  if (next > maxScroll) next = maxScroll;
768
- if (next === before) {
769
- return { moved: false, inView: false };
800
+ if (Math.abs(next - before) < 1) {
801
+ return { moved: false, inView: !isObstructed };
770
802
  }
771
803
  target2.container.scrollTop = next;
772
804
  return { moved: true, inView: false };
773
805
  }, step);
774
806
  if (result.inView) break;
775
- if (!result.moved) break;
807
+ if (!result.moved && !result.inView) {
808
+ logger4.warn("humanScroll", "Stuck: cannot scroll further but element still obstructed/hidden");
809
+ break;
810
+ }
776
811
  await delay2(this.jitterMs(120, 0.4));
777
812
  }
778
813
  const restore = async () => {
@@ -1253,18 +1288,9 @@ var Captcha = {
1253
1288
  };
1254
1289
 
1255
1290
  // src/sse.js
1256
- import { gotScraping } from "got-scraping";
1257
- import { Agent as HttpAgent } from "http";
1258
- import { Agent as HttpsAgent } from "https";
1291
+ import https from "https";
1292
+ import { URL as URL2 } from "url";
1259
1293
  var logger7 = createLogger("Sse");
1260
- var SHARED_HTTP_AGENT = new HttpAgent({ keepAlive: false });
1261
- var SHARED_HTTPS_AGENT = new HttpsAgent({ keepAlive: false, rejectUnauthorized: false });
1262
- var SHARED_GOT_OPTIONS = {
1263
- http2: false,
1264
- retry: { limit: 0 },
1265
- throwHttpErrors: false,
1266
- decompress: false
1267
- };
1268
1294
  var Sse = {
1269
1295
  /**
1270
1296
  * 解析 SSE 流文本
@@ -1291,7 +1317,7 @@ var Sse = {
1291
1317
  return events;
1292
1318
  },
1293
1319
  /**
1294
- * 拦截网络请求并使用 got-scraping 转发,以解决流式数据捕获问题。
1320
+ * 拦截网络请求并使用 Node.js 原生 https 模块转发,以解决流式数据捕获问题。
1295
1321
  * @param {import('playwright').Page} page
1296
1322
  * @param {string|RegExp} urlPattern - 拦截的 URL 模式
1297
1323
  * @param {object} options
@@ -1299,7 +1325,7 @@ var Sse = {
1299
1325
  * @param {function(string, function): void} [options.onEnd] - (fullText, resolve) => void
1300
1326
  * @param {function(Error, function): void} [options.onTimeout] - (error, reject) => void
1301
1327
  * @param {number} [options.initialTimeout=90000] - 初始数据接收超时 (ms),默认 90s
1302
- * @param {number} [options.overallTimeout=180000] - 整体请求超时时间 (ms),默认 180s
1328
+ * @param {number} [options.timeout=180000] - 整体请求超时时间 (ms),默认 180s
1303
1329
  * @returns {Promise<any>} - 返回 Promise,当流满足条件时 resolve
1304
1330
  */
1305
1331
  async intercept(page, urlPattern, options = {}) {
@@ -1325,39 +1351,19 @@ var Sse = {
1325
1351
  logger7.info(`[MITM] \u5DF2\u62E6\u622A\u8BF7\u6C42: ${request.url()}`);
1326
1352
  try {
1327
1353
  const headers = await request.allHeaders();
1328
- delete headers["host"];
1354
+ const postData = request.postData();
1355
+ const urlObj = new URL2(request.url());
1329
1356
  delete headers["accept-encoding"];
1330
1357
  delete headers["content-length"];
1331
- const currentAcceptLanguage = headers["accept-language"] || "";
1332
- AntiCheat.applyLocaleHeaders(headers, currentAcceptLanguage);
1333
- const resolvedAcceptLanguage = headers["accept-language"] || "";
1334
- const userAgent = headers["user-agent"] || "";
1335
- const method = request.method();
1336
- const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
1337
1358
  const reqOptions = {
1338
- ...SHARED_GOT_OPTIONS,
1339
- url: request.url(),
1340
- method,
1359
+ hostname: urlObj.hostname,
1360
+ port: 443,
1361
+ path: urlObj.pathname + urlObj.search,
1362
+ method: request.method(),
1341
1363
  headers,
1342
- headerGeneratorOptions: AntiCheat.getTlsFingerprintOptions(userAgent, resolvedAcceptLanguage),
1343
- agent: {
1344
- http: SHARED_HTTP_AGENT,
1345
- https: SHARED_HTTPS_AGENT
1346
- },
1347
- timeout: { request: overallTimeout }
1348
- };
1349
- if (postData) {
1350
- reqOptions.body = postData;
1351
- }
1352
- const stream = gotScraping.stream(reqOptions);
1353
- const handleStreamError = (error) => {
1354
- clearAllTimers();
1355
- stream.destroy();
1356
- route.abort().catch(() => {
1357
- });
1358
- reject(error);
1364
+ timeout: overallTimeout
1359
1365
  };
1360
- stream.on("response", (res) => {
1366
+ const req = https.request(reqOptions, (res) => {
1361
1367
  const chunks = [];
1362
1368
  let accumulatedText = "";
1363
1369
  res.on("data", (chunk) => {
@@ -1380,7 +1386,6 @@ var Sse = {
1380
1386
  }
1381
1387
  }
1382
1388
  });
1383
- res.on("error", handleStreamError);
1384
1389
  res.on("end", () => {
1385
1390
  logger7.info("[MITM] \u4E0A\u6E38\u54CD\u5E94\u7ED3\u675F");
1386
1391
  clearAllTimers();
@@ -1393,28 +1398,22 @@ var Sse = {
1393
1398
  } else if (!onData) {
1394
1399
  resolve(accumulatedText);
1395
1400
  }
1396
- const resHeaders = {};
1397
- for (const [key, value] of Object.entries(res.headers || {})) {
1398
- if (Array.isArray(value)) {
1399
- resHeaders[key] = value.join(", ");
1400
- } else if (value) {
1401
- resHeaders[key] = String(value);
1402
- }
1403
- }
1404
- delete resHeaders["content-encoding"];
1405
- delete resHeaders["content-length"];
1406
- delete resHeaders["transfer-encoding"];
1407
- delete resHeaders["connection"];
1408
- delete resHeaders["keep-alive"];
1409
1401
  route.fulfill({
1410
- status: res.statusCode || 200,
1411
- headers: resHeaders,
1402
+ status: res.statusCode,
1403
+ headers: res.headers,
1412
1404
  body: Buffer.concat(chunks)
1413
1405
  }).catch(() => {
1414
1406
  });
1415
1407
  });
1416
1408
  });
1417
- stream.on("error", handleStreamError);
1409
+ req.on("error", (e) => {
1410
+ clearAllTimers();
1411
+ route.abort().catch(() => {
1412
+ });
1413
+ reject(e);
1414
+ });
1415
+ if (postData) req.write(postData);
1416
+ req.end();
1418
1417
  } catch (e) {
1419
1418
  clearAllTimers();
1420
1419
  route.continue().catch(() => {
@@ -1473,12 +1472,12 @@ var Sse = {
1473
1472
  };
1474
1473
 
1475
1474
  // src/interception.js
1476
- import { gotScraping as gotScraping2 } from "got-scraping";
1477
- import { Agent as HttpAgent2 } from "http";
1478
- import { Agent as HttpsAgent2 } from "https";
1475
+ import { gotScraping } from "got-scraping";
1476
+ import { Agent as HttpAgent } from "http";
1477
+ import { Agent as HttpsAgent } from "https";
1479
1478
  var logger8 = createLogger("Interception");
1480
- var SHARED_HTTP_AGENT2 = new HttpAgent2({ keepAlive: false });
1481
- var SHARED_HTTPS_AGENT2 = new HttpsAgent2({ keepAlive: false, rejectUnauthorized: false });
1479
+ var SHARED_HTTP_AGENT = new HttpAgent({ keepAlive: false });
1480
+ var SHARED_HTTPS_AGENT = new HttpsAgent({ keepAlive: false, rejectUnauthorized: false });
1482
1481
  var DirectConfig = {
1483
1482
  /** 直连请求超时时间(秒) */
1484
1483
  directTimeout: 12,
@@ -1531,7 +1530,7 @@ var DEFAULT_BLOCKING_CONFIG = {
1531
1530
  /** 额外自定义扩展名列表 */
1532
1531
  customExtensions: []
1533
1532
  };
1534
- var SHARED_GOT_OPTIONS2 = {
1533
+ var SHARED_GOT_OPTIONS = {
1535
1534
  http2: false,
1536
1535
  // 禁用 HTTP2 避免在拦截场景下的握手兼容性问题
1537
1536
  retry: { limit: 0 },
@@ -1640,8 +1639,8 @@ var Interception = {
1640
1639
  const userAgent = reqHeaders["user-agent"] || "";
1641
1640
  const method = request.method();
1642
1641
  const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
1643
- const response = await gotScraping2({
1644
- ...SHARED_GOT_OPTIONS2,
1642
+ const response = await gotScraping({
1643
+ ...SHARED_GOT_OPTIONS,
1645
1644
  // 应用通用配置
1646
1645
  url,
1647
1646
  method,
@@ -1653,8 +1652,8 @@ var Interception = {
1653
1652
  headerGeneratorOptions: AntiCheat.getTlsFingerprintOptions(userAgent, resolvedAcceptLanguage),
1654
1653
  // 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
1655
1654
  agent: {
1656
- http: SHARED_HTTP_AGENT2,
1657
- https: SHARED_HTTPS_AGENT2
1655
+ http: SHARED_HTTP_AGENT,
1656
+ https: SHARED_HTTPS_AGENT
1658
1657
  },
1659
1658
  // 超时时间
1660
1659
  timeout: { request: DirectConfig.directTimeout * 1e3 }