@skrillex1224/playwright-toolkit 2.1.226 → 2.1.228

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 CHANGED
@@ -466,6 +466,9 @@ function createInternalLogger(moduleName, explicitLogger) {
466
466
  };
467
467
  }
468
468
 
469
+ // src/internals/screenshot.js
470
+ var import_delay = __toESM(require("delay"), 1);
471
+
469
472
  // src/internals/viewport.js
470
473
  var toPositiveInt = (value) => {
471
474
  const number = Math.round(Number(value) || 0);
@@ -499,11 +502,18 @@ var DEFAULT_TIMEOUT_MS = 5e3;
499
502
  var FORCED_FULLPAGE_TYPE = "jpeg";
500
503
  var FORCED_FULLPAGE_QUALITY = 50;
501
504
  var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
505
+ var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
506
+ var DEFAULT_MAX_HEIGHT = 8e3;
507
+ var DEFAULT_SETTLE_MS = 1e3;
502
508
  var toPositiveNumber = (value, fallback = 0) => {
503
509
  const n = Number(value);
504
510
  if (!Number.isFinite(n) || n <= 0) return fallback;
505
511
  return n;
506
512
  };
513
+ var toPositiveInteger = (value, fallback = 0) => {
514
+ const number = Math.round(Number(value) || 0);
515
+ return number > 0 ? number : fallback;
516
+ };
507
517
  var normalizeType = (value) => {
508
518
  const raw = String(value || "png").trim().toLowerCase();
509
519
  if (!SUPPORTED_TYPES.has(raw)) return "png";
@@ -532,6 +542,138 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
532
542
  scale: 1
533
543
  };
534
544
  };
545
+ var expandScrollableContent = async (page, options = {}) => {
546
+ return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
547
+ const body = document.body;
548
+ const root = document.documentElement;
549
+ const scrollingElement = document.scrollingElement;
550
+ const candidates = [];
551
+ const seen = /* @__PURE__ */ new Set();
552
+ let maxHeight = window.innerHeight || 0;
553
+ const pushCandidate = (el) => {
554
+ if (!el || seen.has(el)) return;
555
+ seen.add(el);
556
+ candidates.push(el);
557
+ };
558
+ pushCandidate(scrollingElement);
559
+ pushCandidate(root);
560
+ pushCandidate(body);
561
+ document.querySelectorAll("*").forEach(pushCandidate);
562
+ const isDocumentElement = (el) => el === root || el === body || el === scrollingElement;
563
+ const isVisible = (el, style, rect) => {
564
+ if (!el || !style || !rect) return false;
565
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
566
+ return false;
567
+ }
568
+ if (Number(style.opacity) === 0) return false;
569
+ return rect.width > 0 && rect.height > 0;
570
+ };
571
+ const isScrollableY = (el, style) => {
572
+ if (!el || el.scrollHeight <= el.clientHeight + 1) {
573
+ return false;
574
+ }
575
+ if (isDocumentElement(el)) {
576
+ return true;
577
+ }
578
+ const overflowY = String(style.overflowY || "").toLowerCase();
579
+ const overflow = String(style.overflow || "").toLowerCase();
580
+ const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
581
+ return scrollableOverflow.has(overflowY) || scrollableOverflow.has(overflow);
582
+ };
583
+ candidates.forEach((el) => {
584
+ const style = window.getComputedStyle(el);
585
+ const rect = el.getBoundingClientRect();
586
+ if (visibleOnly && !isVisible(el, style, rect)) {
587
+ return;
588
+ }
589
+ if (!isScrollableY(el, style)) {
590
+ return;
591
+ }
592
+ const scrollHeight = Math.ceil(el.scrollHeight || 0);
593
+ if (scrollHeight <= 0) {
594
+ return;
595
+ }
596
+ if (scrollHeight > maxHeight) {
597
+ maxHeight = scrollHeight;
598
+ }
599
+ if (isDocumentElement(el)) {
600
+ return;
601
+ }
602
+ if (!el.classList.contains(className)) {
603
+ el.dataset.pkOrigOverflow = el.style.overflow;
604
+ el.dataset.pkOrigOverflowPriority = el.style.getPropertyPriority("overflow") || "";
605
+ el.dataset.pkOrigHeight = el.style.height;
606
+ el.dataset.pkOrigHeightPriority = el.style.getPropertyPriority("height") || "";
607
+ el.dataset.pkOrigMinHeight = el.style.minHeight;
608
+ el.dataset.pkOrigMinHeightPriority = el.style.getPropertyPriority("min-height") || "";
609
+ el.dataset.pkOrigMaxHeight = el.style.maxHeight;
610
+ el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
611
+ el.classList.add(className);
612
+ }
613
+ if (forceScrollableHeight) {
614
+ el.style.setProperty("overflow", "visible", "important");
615
+ el.style.setProperty("height", `${scrollHeight}px`, "important");
616
+ el.style.setProperty("min-height", `${scrollHeight}px`, "important");
617
+ el.style.setProperty("max-height", "none", "important");
618
+ return;
619
+ }
620
+ el.style.overflow = "visible";
621
+ el.style.height = "auto";
622
+ el.style.maxHeight = "none";
623
+ });
624
+ return maxHeight;
625
+ }, {
626
+ className: EXPANDED_SCROLLABLE_CLASS,
627
+ forceScrollableHeight: Boolean(options.forceScrollableHeight),
628
+ visibleOnly: options.visibleOnly !== false
629
+ });
630
+ };
631
+ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
632
+ const originalViewport = await resolveCurrentViewportSize(page);
633
+ const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
634
+ const buffer = options.buffer ?? defaultBuffer;
635
+ const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
636
+ const settleMs = Math.max(0, Number(options.settleMs ?? DEFAULT_SETTLE_MS) || 0);
637
+ const maxScrollHeight = await expandScrollableContent(page, {
638
+ forceScrollableHeight: options.forceScrollableHeight,
639
+ visibleOnly: options.visibleOnly !== false
640
+ });
641
+ const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
642
+ await page.setViewportSize({
643
+ width: originalViewport.width,
644
+ height: targetHeight
645
+ });
646
+ if (settleMs > 0) {
647
+ await (0, import_delay.default)(settleMs);
648
+ }
649
+ return {
650
+ originalViewport,
651
+ maxScrollHeight,
652
+ targetHeight
653
+ };
654
+ };
655
+ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
656
+ await page.evaluate((className) => {
657
+ document.querySelectorAll(`.${className}`).forEach((el) => {
658
+ el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
659
+ el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
660
+ el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
661
+ el.style.setProperty("max-height", el.dataset.pkOrigMaxHeight || "", el.dataset.pkOrigMaxHeightPriority || "");
662
+ delete el.dataset.pkOrigOverflow;
663
+ delete el.dataset.pkOrigOverflowPriority;
664
+ delete el.dataset.pkOrigHeight;
665
+ delete el.dataset.pkOrigHeightPriority;
666
+ delete el.dataset.pkOrigMinHeight;
667
+ delete el.dataset.pkOrigMinHeightPriority;
668
+ delete el.dataset.pkOrigMaxHeight;
669
+ delete el.dataset.pkOrigMaxHeightPriority;
670
+ el.classList.remove(className);
671
+ });
672
+ }, EXPANDED_SCROLLABLE_CLASS);
673
+ if (state?.originalViewport) {
674
+ await page.setViewportSize(state.originalViewport);
675
+ }
676
+ };
535
677
  var capturePageScreenshot = async (page, options = {}) => {
536
678
  const fullPage = Boolean(options.fullPage);
537
679
  const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
@@ -585,6 +727,22 @@ var capturePageScreenshot = async (page, options = {}) => {
585
727
  return await page.screenshot(fallbackOptions);
586
728
  }
587
729
  };
730
+ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
731
+ const state = await prepareExpandedFullPageScreenshot(page, options);
732
+ try {
733
+ return await capturePageScreenshot(page, {
734
+ fullPage: true,
735
+ type: options.type || "png",
736
+ quality: options.quality,
737
+ timeout: options.timeout,
738
+ maxClipHeight: state.targetHeight
739
+ });
740
+ } finally {
741
+ if (options.restore) {
742
+ await restoreExpandedFullPageScreenshot(page, state);
743
+ }
744
+ }
745
+ };
588
746
 
589
747
  // src/errors.js
590
748
  var errors_exports = {};
@@ -2124,7 +2282,7 @@ var AntiCheat = {
2124
2282
  };
2125
2283
 
2126
2284
  // src/internals/humanize/desktop.js
2127
- var import_delay = __toESM(require("delay"), 1);
2285
+ var import_delay2 = __toESM(require("delay"), 1);
2128
2286
  var import_ghost_cursor_playwright = require("ghost-cursor-playwright");
2129
2287
  var logger6 = createInternalLogger("Humanize");
2130
2288
  var $CursorWeakMap = /* @__PURE__ */ new WeakMap();
@@ -2356,7 +2514,7 @@ var Humanize = {
2356
2514
  }
2357
2515
  await page.mouse.wheel(0, deltaY);
2358
2516
  didScroll = true;
2359
- await (0, import_delay.default)(this.jitterMs(20 + Math.random() * 40, 0.2));
2517
+ await (0, import_delay2.default)(this.jitterMs(20 + Math.random() * 40, 0.2));
2360
2518
  }
2361
2519
  logger6.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
2362
2520
  return { element, didScroll };
@@ -2385,7 +2543,7 @@ var Humanize = {
2385
2543
  restoreOnce.restored = true;
2386
2544
  if (typeof restoreOnce.do !== "function") return;
2387
2545
  try {
2388
- await (0, import_delay.default)(this.jitterMs(1e3));
2546
+ await (0, import_delay2.default)(this.jitterMs(1e3));
2389
2547
  await restoreOnce.do();
2390
2548
  } catch (restoreError) {
2391
2549
  logger6.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
@@ -2393,7 +2551,7 @@ var Humanize = {
2393
2551
  };
2394
2552
  try {
2395
2553
  if (target == null) {
2396
- await (0, import_delay.default)(this.jitterMs(reactionDelay, 0.4));
2554
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.4));
2397
2555
  await cursor.actions.click();
2398
2556
  logger6.success("humanClick", "Clicked current position");
2399
2557
  return true;
@@ -2427,7 +2585,7 @@ var Humanize = {
2427
2585
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.3;
2428
2586
  const y = box.y + box.height / 2 + (Math.random() - 0.5) * box.height * 0.3;
2429
2587
  await cursor.actions.move({ x, y });
2430
- await (0, import_delay.default)(this.jitterMs(reactionDelay, 0.4));
2588
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.4));
2431
2589
  await cursor.actions.click();
2432
2590
  await restoreOnce();
2433
2591
  logger6.success("humanClick");
@@ -2446,7 +2604,7 @@ var Humanize = {
2446
2604
  async randomSleep(baseMs, jitterPercent = 0.3) {
2447
2605
  const ms = this.jitterMs(baseMs, jitterPercent);
2448
2606
  logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
2449
- await (0, import_delay.default)(ms);
2607
+ await (0, import_delay2.default)(ms);
2450
2608
  logger6.success("randomSleep");
2451
2609
  },
2452
2610
  /**
@@ -2464,7 +2622,7 @@ var Humanize = {
2464
2622
  const x = 100 + Math.random() * (viewportSize.width - 200);
2465
2623
  const y = 100 + Math.random() * (viewportSize.height - 200);
2466
2624
  await cursor.actions.move({ x, y });
2467
- await (0, import_delay.default)(this.jitterMs(600, 0.5));
2625
+ await (0, import_delay2.default)(this.jitterMs(600, 0.5));
2468
2626
  }
2469
2627
  logger6.success("simulateGaze");
2470
2628
  },
@@ -2488,7 +2646,7 @@ var Humanize = {
2488
2646
  try {
2489
2647
  const locator = page.locator(selector);
2490
2648
  await Humanize.humanClick(page, locator);
2491
- await (0, import_delay.default)(this.jitterMs(200, 0.4));
2649
+ await (0, import_delay2.default)(this.jitterMs(200, 0.4));
2492
2650
  for (let i = 0; i < text.length; i++) {
2493
2651
  const char = text[i];
2494
2652
  let charDelay;
@@ -2500,11 +2658,11 @@ var Humanize = {
2500
2658
  charDelay = this.jitterMs(baseDelay, 0.4);
2501
2659
  }
2502
2660
  await page.keyboard.type(char);
2503
- await (0, import_delay.default)(charDelay);
2661
+ await (0, import_delay2.default)(charDelay);
2504
2662
  if (Math.random() < pauseProbability && i < text.length - 1) {
2505
2663
  const pauseTime = this.jitterMs(pauseBase, 0.5);
2506
2664
  logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
2507
- await (0, import_delay.default)(pauseTime);
2665
+ await (0, import_delay2.default)(pauseTime);
2508
2666
  }
2509
2667
  }
2510
2668
  logger6.success("humanType");
@@ -2513,6 +2671,43 @@ var Humanize = {
2513
2671
  throw error;
2514
2672
  }
2515
2673
  },
2674
+ /**
2675
+ * 人类化按键 - 模拟用户在当前焦点或指定目标上按下一次键。
2676
+ * @param {import('playwright').Page} page
2677
+ * @param {string|import('playwright').ElementHandle|import('playwright').Locator} targetOrKey - 目标或按键
2678
+ * @param {string|Object} [maybeKey] - 按键或选项
2679
+ * @param {Object} [options]
2680
+ */
2681
+ async humanPress(page, targetOrKey, maybeKey, options = {}) {
2682
+ const hasTarget = typeof maybeKey === "string";
2683
+ const key = hasTarget ? maybeKey : targetOrKey;
2684
+ const pressOptions = hasTarget ? options : maybeKey || options;
2685
+ const {
2686
+ reactionDelay = 180,
2687
+ holdDelay = 45,
2688
+ focusDelay = 180,
2689
+ scrollIfNeeded = true,
2690
+ throwOnMissing = true,
2691
+ keyboardOptions = {}
2692
+ } = pressOptions || {};
2693
+ const targetDesc = hasTarget ? typeof targetOrKey === "string" ? targetOrKey : "ElementHandle" : "current focus";
2694
+ logger6.start("humanPress", `key=${key}, target=${targetDesc}`);
2695
+ try {
2696
+ if (hasTarget) {
2697
+ await this.humanClick(page, targetOrKey, { reactionDelay: focusDelay, scrollIfNeeded, throwOnMissing });
2698
+ }
2699
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.45));
2700
+ await page.keyboard.press(key, {
2701
+ ...keyboardOptions,
2702
+ delay: this.jitterMs(holdDelay, 0.5)
2703
+ });
2704
+ logger6.success("humanPress");
2705
+ return true;
2706
+ } catch (error) {
2707
+ logger6.fail("humanPress", error);
2708
+ throw error;
2709
+ }
2710
+ },
2516
2711
  /**
2517
2712
  * 人类化清空输入框 - 模拟人类删除文本的行为
2518
2713
  * @param {import('playwright').Page} page
@@ -2523,14 +2718,14 @@ var Humanize = {
2523
2718
  try {
2524
2719
  const locator = page.locator(selector);
2525
2720
  await locator.click();
2526
- await (0, import_delay.default)(this.jitterMs(200, 0.4));
2721
+ await (0, import_delay2.default)(this.jitterMs(200, 0.4));
2527
2722
  const currentValue = await locator.inputValue();
2528
2723
  if (!currentValue || currentValue.length === 0) {
2529
2724
  logger6.success("humanClear", "already empty");
2530
2725
  return;
2531
2726
  }
2532
2727
  await page.keyboard.press("Meta+A");
2533
- await (0, import_delay.default)(this.jitterMs(100, 0.4));
2728
+ await (0, import_delay2.default)(this.jitterMs(100, 0.4));
2534
2729
  await page.keyboard.press("Backspace");
2535
2730
  logger6.success("humanClear");
2536
2731
  } catch (error) {
@@ -2556,13 +2751,13 @@ var Humanize = {
2556
2751
  const x = 100 + Math.random() * (viewportSize.width - 200);
2557
2752
  const y = 100 + Math.random() * (viewportSize.height - 200);
2558
2753
  await cursor.actions.move({ x, y });
2559
- await (0, import_delay.default)(this.jitterMs(350, 0.4));
2754
+ await (0, import_delay2.default)(this.jitterMs(350, 0.4));
2560
2755
  } else if (action < 0.7) {
2561
2756
  const scrollY = (Math.random() - 0.5) * 200;
2562
2757
  await page.mouse.wheel(0, scrollY);
2563
- await (0, import_delay.default)(this.jitterMs(500, 0.4));
2758
+ await (0, import_delay2.default)(this.jitterMs(500, 0.4));
2564
2759
  } else {
2565
- await (0, import_delay.default)(this.jitterMs(800, 0.5));
2760
+ await (0, import_delay2.default)(this.jitterMs(800, 0.5));
2566
2761
  }
2567
2762
  }
2568
2763
  logger6.success("warmUpBrowsing");
@@ -2591,7 +2786,7 @@ var Humanize = {
2591
2786
  const scrollAmount = stepDistance * factor * sign * jitter;
2592
2787
  await page.mouse.wheel(0, scrollAmount);
2593
2788
  const baseDelay = 60 + i * 25;
2594
- await (0, import_delay.default)(this.jitterMs(baseDelay, 0.3));
2789
+ await (0, import_delay2.default)(this.jitterMs(baseDelay, 0.3));
2595
2790
  }
2596
2791
  logger6.success("naturalScroll");
2597
2792
  } catch (error) {
@@ -2601,8 +2796,143 @@ var Humanize = {
2601
2796
  }
2602
2797
  };
2603
2798
 
2799
+ // src/internals/humanize/machine.js
2800
+ var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
2801
+ var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
2802
+ var resolveNativeTarget = (page, target) => {
2803
+ if (!target) return null;
2804
+ if (typeof target === "string") {
2805
+ return page.locator(target);
2806
+ }
2807
+ return target;
2808
+ };
2809
+ var normalizeSelectorOptions = (options = {}) => ({
2810
+ targetParent: Boolean(options.targetParent ?? options.parent ?? false),
2811
+ pick: options.pick === "last" || options.last ? "last" : "first",
2812
+ visibleOnly: options.visibleOnly !== false,
2813
+ fallbackDomClick: Boolean(options.fallbackDomClick),
2814
+ forceMouse: Boolean(options.forceMouse)
2815
+ });
2816
+ var MachineHumanize = {
2817
+ async clickPoint(page, pointOrX, maybeY, options = {}) {
2818
+ const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
2819
+ const point = isPoint(pointOrX) ? pointOrX : { x: pointOrX, y: maybeY };
2820
+ const x = Number(point.x);
2821
+ const y = Number(point.y);
2822
+ if (!Number.isFinite(x) || !Number.isFinite(y)) {
2823
+ throw new Error(`Invalid click point: ${JSON.stringify(point)}`);
2824
+ }
2825
+ const resolvedDevice = resolveDeviceFromPage(page);
2826
+ if (resolvedDevice === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
2827
+ await page.touchscreen.tap(x, y);
2828
+ return true;
2829
+ }
2830
+ await page.mouse.click(x, y, clickOptions.mouseOptions || {});
2831
+ return true;
2832
+ },
2833
+ async click(page, target, options = {}) {
2834
+ if (isPoint(target)) {
2835
+ return MachineHumanize.clickPoint(page, target, void 0, options);
2836
+ }
2837
+ const nativeTarget = resolveNativeTarget(page, target);
2838
+ if (!nativeTarget || typeof nativeTarget.click !== "function") {
2839
+ throw new Error("Machine click target does not expose click()");
2840
+ }
2841
+ await nativeTarget.click(options.clickOptions || options);
2842
+ return true;
2843
+ },
2844
+ async focus(page, target, options = {}) {
2845
+ const nativeTarget = resolveNativeTarget(page, target);
2846
+ if (!nativeTarget || typeof nativeTarget.focus !== "function") {
2847
+ throw new Error("Machine focus target does not expose focus()");
2848
+ }
2849
+ await nativeTarget.focus(options);
2850
+ return true;
2851
+ },
2852
+ async fill(page, target, value, options = {}) {
2853
+ const nativeTarget = resolveNativeTarget(page, target);
2854
+ if (!nativeTarget || typeof nativeTarget.fill !== "function") {
2855
+ throw new Error("Machine fill target does not expose fill()");
2856
+ }
2857
+ await nativeTarget.fill(value, options);
2858
+ return true;
2859
+ },
2860
+ async keyboardType(page, text, options = {}) {
2861
+ await page.keyboard.type(text, options);
2862
+ return true;
2863
+ },
2864
+ async type(page, targetOrText, maybeText, options = {}) {
2865
+ if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
2866
+ return MachineHumanize.keyboardType(page, targetOrText, maybeText || options);
2867
+ }
2868
+ const nativeTarget = resolveNativeTarget(page, targetOrText);
2869
+ if (!nativeTarget || typeof nativeTarget.type !== "function") {
2870
+ throw new Error("Machine type target does not expose type()");
2871
+ }
2872
+ await nativeTarget.type(maybeText, options);
2873
+ return true;
2874
+ },
2875
+ async selectorCenterPoint(page, selector, options = {}) {
2876
+ const normalizedOptions = normalizeSelectorOptions(options);
2877
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2878
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2879
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2880
+ let rect = null;
2881
+ for (const node of ordered) {
2882
+ if (!node) continue;
2883
+ const target = innerOptions.targetParent ? node.parentElement || node : node;
2884
+ rect = target.getBoundingClientRect?.() || null;
2885
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2886
+ if (innerOptions.visibleOnly && !isVisible) continue;
2887
+ break;
2888
+ }
2889
+ if (!rect || rect.width <= 0 || rect.height <= 0) return null;
2890
+ return {
2891
+ x: rect.left + rect.width / 2,
2892
+ y: rect.top + rect.height / 2
2893
+ };
2894
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2895
+ },
2896
+ async domClick(page, selector, options = {}) {
2897
+ const normalizedOptions = normalizeSelectorOptions(options);
2898
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2899
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2900
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2901
+ let target = null;
2902
+ for (const node of ordered) {
2903
+ if (!node) continue;
2904
+ const candidate = innerOptions.targetParent ? node.parentElement || node : node;
2905
+ const rect = candidate.getBoundingClientRect?.() || null;
2906
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2907
+ if (innerOptions.visibleOnly && !isVisible) continue;
2908
+ target = candidate;
2909
+ break;
2910
+ }
2911
+ if (!target || typeof target.click !== "function") return false;
2912
+ target.click();
2913
+ return true;
2914
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2915
+ },
2916
+ async clickSelectorCenter(page, selector, options = {}) {
2917
+ const normalizedOptions = normalizeSelectorOptions(options);
2918
+ try {
2919
+ const point = await MachineHumanize.selectorCenterPoint(page, selector, normalizedOptions);
2920
+ if (point) {
2921
+ await MachineHumanize.clickPoint(page, point, void 0, normalizedOptions);
2922
+ return true;
2923
+ }
2924
+ } catch (error) {
2925
+ if (!normalizedOptions.fallbackDomClick) throw error;
2926
+ }
2927
+ if (normalizedOptions.fallbackDomClick) {
2928
+ return MachineHumanize.domClick(page, selector, normalizedOptions);
2929
+ }
2930
+ return false;
2931
+ }
2932
+ };
2933
+
2604
2934
  // src/internals/humanize/shared.js
2605
- var import_delay2 = __toESM(require("delay"), 1);
2935
+ var import_delay3 = __toESM(require("delay"), 1);
2606
2936
  var jitterMs = (base, jitterPercent = 0.3) => {
2607
2937
  const jitter = Number(base || 0) * Number(jitterPercent || 0) * (Math.random() * 2 - 1);
2608
2938
  return Math.max(10, Math.round(Number(base || 0) + jitter));
@@ -2628,7 +2958,7 @@ var resolveElement = async (page, target, { throwOnMissing = true } = {}) => {
2628
2958
  }
2629
2959
  return element;
2630
2960
  };
2631
- var waitJitter = (base, jitterPercent = 0.3) => (0, import_delay2.default)(jitterMs(base, jitterPercent));
2961
+ var waitJitter = (base, jitterPercent = 0.3) => (0, import_delay3.default)(jitterMs(base, jitterPercent));
2632
2962
 
2633
2963
  // src/internals/humanize/mobile.js
2634
2964
  var logger7 = createInternalLogger("Humanize.Mobile");
@@ -2930,6 +3260,49 @@ var scrollScrollableAncestor = async (element, deltaY) => {
2930
3260
  };
2931
3261
  }, deltaY);
2932
3262
  };
3263
+ var scrollAwayFromObstruction = async (element, status) => {
3264
+ return element.evaluate((el, innerStatus) => {
3265
+ const isScrollable = (node) => {
3266
+ const style = window.getComputedStyle(node);
3267
+ if (!style) return false;
3268
+ const overflowY = style.overflowY;
3269
+ if (!["auto", "scroll", "overlay"].includes(overflowY)) return false;
3270
+ return node.scrollHeight > node.clientHeight + 1;
3271
+ };
3272
+ let scroller = el;
3273
+ while (scroller && scroller !== document.body) {
3274
+ if (isScrollable(scroller)) break;
3275
+ scroller = scroller.parentElement;
3276
+ }
3277
+ if (!scroller || scroller === document.body) {
3278
+ return { moved: false, scrollTop: 0, deltaY: 0 };
3279
+ }
3280
+ const rect = el.getBoundingClientRect();
3281
+ const scrollerRect = scroller.getBoundingClientRect();
3282
+ const obstruction = innerStatus?.obstruction || {};
3283
+ const obstructionTop = Number(obstruction.top);
3284
+ const obstructionBottom = Number(obstruction.bottom);
3285
+ const obstructionMiddle = Number.isFinite(obstructionTop) && Number.isFinite(obstructionBottom) ? (obstructionTop + obstructionBottom) / 2 : scrollerRect.top + scrollerRect.height / 2;
3286
+ const scrollerMiddle = scrollerRect.top + scrollerRect.height / 2;
3287
+ const padding = 18;
3288
+ let deltaY = 0;
3289
+ if (Number.isFinite(obstructionTop) && rect.bottom > obstructionTop && obstructionTop >= scrollerRect.top && obstructionTop <= scrollerRect.bottom && obstructionMiddle >= scrollerMiddle) {
3290
+ deltaY = rect.bottom - obstructionTop + padding;
3291
+ } else if (Number.isFinite(obstructionBottom) && rect.top < obstructionBottom && obstructionBottom >= scrollerRect.top && obstructionBottom <= scrollerRect.bottom && obstructionMiddle < scrollerMiddle) {
3292
+ deltaY = rect.top - obstructionBottom - padding;
3293
+ } else {
3294
+ const fallbackDistance = Math.max(48, Math.min(180, scrollerRect.height * 0.45));
3295
+ deltaY = obstructionMiddle >= scrollerMiddle ? fallbackDistance : -fallbackDistance;
3296
+ }
3297
+ const beforeTop = scroller.scrollTop;
3298
+ scroller.scrollTop = beforeTop + deltaY;
3299
+ return {
3300
+ moved: Math.abs(scroller.scrollTop - beforeTop) > 2,
3301
+ scrollTop: scroller.scrollTop,
3302
+ deltaY
3303
+ };
3304
+ }, status);
3305
+ };
2933
3306
  var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
2934
3307
  const viewport = resolveViewport(page);
2935
3308
  const rawRect = options.rect || null;
@@ -3093,6 +3466,15 @@ var MobileHumanize = {
3093
3466
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
3094
3467
  return { element, didScroll, restore: null };
3095
3468
  }
3469
+ if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
3470
+ const moved = await scrollAwayFromObstruction(element, status);
3471
+ if (moved.moved) {
3472
+ logger7.debug(`humanScroll | sticky/fixed \u906E\u6321\u8865\u507F\u6EDA\u52A8 top=${Math.round(moved.scrollTop || 0)}`);
3473
+ await waitJitter(90, 0.3);
3474
+ didScroll = true;
3475
+ continue;
3476
+ }
3477
+ }
3096
3478
  if (Date.now() - startTime > maxDurationMs) {
3097
3479
  logger7.warn(`humanScroll | mobile timeout (${maxDurationMs}ms, status=${status.code}, direction=${status.direction || "unknown"}, fixed=${Boolean(status.isFixed)})`);
3098
3480
  return { element, didScroll, restore: null };
@@ -3224,7 +3606,7 @@ var MobileHumanize = {
3224
3606
  await MobileHumanize.humanScroll(page, element, { throwOnMissing });
3225
3607
  }
3226
3608
  const status = await checkElementVisibility(element).catch(() => null);
3227
- if (status && (status.code === "ZERO_DIMENSIONS" || status.code === "NOT_INTERACTABLE")) {
3609
+ if (status && status.code !== "VISIBLE") {
3228
3610
  const message = `\u5143\u7D20\u4E0D\u53EF\u70B9\u51FB: ${status.reason || status.code}`;
3229
3611
  if (throwOnMissing) throw new Error(message);
3230
3612
  logger7.warn(`humanClick: ${message}\uFF0C\u8DF3\u8FC7\u70B9\u51FB`);
@@ -3284,6 +3666,40 @@ var MobileHumanize = {
3284
3666
  }
3285
3667
  }
3286
3668
  },
3669
+ async humanPress(page, targetOrKey, maybeKey, options = {}) {
3670
+ const hasTarget = typeof maybeKey === "string";
3671
+ const key = hasTarget ? maybeKey : targetOrKey;
3672
+ const pressOptions = hasTarget ? options : maybeKey || options;
3673
+ const {
3674
+ reactionDelay = 170,
3675
+ holdDelay = 42,
3676
+ focusDelay = 180,
3677
+ scrollIfNeeded = true,
3678
+ throwOnMissing = true,
3679
+ keyboardOptions = {}
3680
+ } = pressOptions || {};
3681
+ const targetDesc = hasTarget ? describeTarget(targetOrKey) : "current focus";
3682
+ logger7.start("humanPress", `key=${key}, target=${targetDesc}`);
3683
+ try {
3684
+ if (hasTarget) {
3685
+ await MobileHumanize.humanClick(page, targetOrKey, {
3686
+ reactionDelay: focusDelay,
3687
+ scrollIfNeeded,
3688
+ throwOnMissing
3689
+ });
3690
+ }
3691
+ await waitJitter(reactionDelay, 0.45);
3692
+ await page.keyboard.press(key, {
3693
+ ...keyboardOptions,
3694
+ delay: jitterMs(holdDelay, 0.5)
3695
+ });
3696
+ logger7.success("humanPress");
3697
+ return true;
3698
+ } catch (error) {
3699
+ logger7.fail("humanPress", error);
3700
+ throw error;
3701
+ }
3702
+ },
3287
3703
  async humanClear(page, selector) {
3288
3704
  const locator = page.locator(selector);
3289
3705
  await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
@@ -3334,15 +3750,18 @@ var MobileHumanize = {
3334
3750
  };
3335
3751
 
3336
3752
  // src/humanize.js
3337
- var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
3753
+ var resolveDeviceFromPage2 = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
3338
3754
  var resolveDelegate = (page) => {
3339
- return resolveDeviceFromPage(page) === Device.Mobile ? MobileHumanize : Humanize;
3755
+ return resolveDeviceFromPage2(page) === Device.Mobile ? MobileHumanize : Humanize;
3340
3756
  };
3341
3757
  var callDelegate = (method, page, args) => {
3342
3758
  const delegate = resolveDelegate(page);
3343
3759
  return delegate[method](page, ...args);
3344
3760
  };
3345
3761
  var Humanize2 = {
3762
+ // M = Machine: native/mechanical operations for兼容路径。
3763
+ // 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
3764
+ M: MachineHumanize,
3346
3765
  jitterMs(base, jitterPercent = 0.3) {
3347
3766
  return Humanize.jitterMs(base, jitterPercent);
3348
3767
  },
@@ -3371,6 +3790,12 @@ var Humanize2 = {
3371
3790
  humanType(page, selector, text, options = {}) {
3372
3791
  return callDelegate("humanType", page, [selector, text, options]);
3373
3792
  },
3793
+ humanPress(page, targetOrKey, maybeKey, options = {}) {
3794
+ if (typeof maybeKey === "string") {
3795
+ return callDelegate("humanPress", page, [targetOrKey, maybeKey, options]);
3796
+ }
3797
+ return callDelegate("humanPress", page, [targetOrKey, maybeKey || options]);
3798
+ },
3374
3799
  humanClear(page, selector) {
3375
3800
  return callDelegate("humanClear", page, [selector]);
3376
3801
  },
@@ -5842,7 +6267,7 @@ var Logger = {
5842
6267
  };
5843
6268
 
5844
6269
  // src/share.js
5845
- var import_delay3 = __toESM(require("delay"), 1);
6270
+ var import_delay4 = __toESM(require("delay"), 1);
5846
6271
 
5847
6272
  // src/internals/watermarkify.js
5848
6273
  var DEFAULT_TIMEZONE_OFFSET = 8;
@@ -5876,6 +6301,18 @@ var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
5876
6301
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
5877
6302
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
5878
6303
  var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
6304
+ var MOBILE_STRIP_HEIGHT = 104;
6305
+ var MOBILE_STRIP_PADDING_X = 14;
6306
+ var MOBILE_STRIP_PADDING_Y = 13;
6307
+ var MOBILE_STRIP_ROW_HEIGHT = 22;
6308
+ var MOBILE_STRIP_ROW_GAP = 7;
6309
+ var MOBILE_STRIP_LABEL_FONT_SIZE = 12.5;
6310
+ var MOBILE_STRIP_VALUE_FONT_SIZE = 13.5;
6311
+ var MOBILE_STRIP_LABEL_WIDTH = 45;
6312
+ var MOBILE_STRIP_PROMPT_LABEL_WIDTH = 60;
6313
+ var MOBILE_STRIP_LOC_LABEL_WIDTH = 30;
6314
+ var MOBILE_STRIP_IP_LABEL_WIDTH = 22;
6315
+ var MOBILE_STRIP_META_GAP = 12;
5879
6316
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
5880
6317
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
5881
6318
  /(?:中国)?移动$/i,
@@ -6660,10 +7097,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
6660
7097
  }),
6661
7098
  watermark: options.watermark,
6662
7099
  strip: options.strip,
6663
- stripLogoSrc
7100
+ stripLogoSrc,
7101
+ device: resolvePageDevice(page)
6664
7102
  };
6665
7103
  };
6666
7104
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7105
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7106
+ var findStripSegment = (segments, kind) => {
7107
+ const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7108
+ return found && typeof found === "object" ? found : {};
7109
+ };
6667
7110
  var buildStripSegmentLayout = (segment, options = {}) => {
6668
7111
  const label = normalizeWhitespace(segment?.label || "");
6669
7112
  const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
@@ -6991,6 +7434,116 @@ var renderStripDivider = (x, centerY, height) => {
6991
7434
  />
6992
7435
  `;
6993
7436
  };
7437
+ var renderMobileStripText = ({
7438
+ label,
7439
+ value,
7440
+ labelX,
7441
+ y,
7442
+ valueWidth,
7443
+ labelWidth = MOBILE_STRIP_LABEL_WIDTH,
7444
+ fontFamily
7445
+ }) => {
7446
+ const safeLabel = normalizeWhitespace(label) || "-";
7447
+ const safeValue = fitTextWithEllipsis(
7448
+ Array.from(normalizeWhitespace(value) || "-"),
7449
+ Math.max(18, valueWidth),
7450
+ MOBILE_STRIP_VALUE_FONT_SIZE
7451
+ );
7452
+ return `
7453
+ <text
7454
+ x="${labelX}"
7455
+ y="${y}"
7456
+ fill="#111111"
7457
+ fill-opacity="0.54"
7458
+ font-family="${fontFamily}"
7459
+ font-size="${MOBILE_STRIP_LABEL_FONT_SIZE}"
7460
+ font-weight="650"
7461
+ dominant-baseline="middle"
7462
+ >${escapeXml(safeLabel)}</text>
7463
+ <text
7464
+ x="${labelX + labelWidth}"
7465
+ y="${y}"
7466
+ fill="#111111"
7467
+ font-family="${fontFamily}"
7468
+ font-size="${MOBILE_STRIP_VALUE_FONT_SIZE}"
7469
+ font-weight="730"
7470
+ dominant-baseline="middle"
7471
+ >${escapeXml(safeValue)}</text>
7472
+ `;
7473
+ };
7474
+ var renderMobileStrip = ({ meta, width, height, fontFamily }) => {
7475
+ const stripHeight = MOBILE_STRIP_HEIGHT;
7476
+ const stripY = height - stripHeight;
7477
+ const contentX = MOBILE_STRIP_PADDING_X;
7478
+ const contentWidth = Math.max(1, width - MOBILE_STRIP_PADDING_X * 2);
7479
+ const prompt = findStripSegment(meta.stripSegments, "prompt");
7480
+ const time = findStripSegment(meta.stripSegments, "time");
7481
+ const location = findStripSegment(meta.stripSegments, "location");
7482
+ const ip = findStripSegment(meta.stripSegments, "ip");
7483
+ const row1Y = stripY + MOBILE_STRIP_PADDING_Y + MOBILE_STRIP_ROW_HEIGHT / 2;
7484
+ const row2Y = row1Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7485
+ const row3Y = row2Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7486
+ const promptValueWidth = contentWidth - MOBILE_STRIP_PROMPT_LABEL_WIDTH;
7487
+ const locValueX = contentX + MOBILE_STRIP_LOC_LABEL_WIDTH;
7488
+ const ipLabelX = Math.min(
7489
+ width - MOBILE_STRIP_PADDING_X - MOBILE_STRIP_IP_LABEL_WIDTH - 70,
7490
+ Math.max(
7491
+ locValueX + 80 + MOBILE_STRIP_META_GAP,
7492
+ contentX + Math.round(contentWidth * 0.52)
7493
+ )
7494
+ );
7495
+ const locValueWidth = Math.max(
7496
+ 28,
7497
+ ipLabelX - locValueX - MOBILE_STRIP_META_GAP
7498
+ );
7499
+ const ipValueWidth = Math.max(
7500
+ 28,
7501
+ width - MOBILE_STRIP_PADDING_X - (ipLabelX + MOBILE_STRIP_IP_LABEL_WIDTH)
7502
+ );
7503
+ return `
7504
+ <g id="strip">
7505
+ <rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
7506
+ <rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
7507
+ <rect x="${contentX}" y="${stripY}" width="${Math.max(96, Math.round(width * 0.36))}" height="2" fill="url(#stripAccent)" />
7508
+ ${renderMobileStripText({
7509
+ label: "Prompt",
7510
+ value: prompt.rawValue || prompt.value || "-",
7511
+ labelX: contentX,
7512
+ y: row1Y,
7513
+ valueWidth: promptValueWidth,
7514
+ labelWidth: MOBILE_STRIP_PROMPT_LABEL_WIDTH,
7515
+ fontFamily
7516
+ })}
7517
+ ${renderMobileStripText({
7518
+ label: "Time",
7519
+ value: time.rawValue || time.value || "-",
7520
+ labelX: contentX,
7521
+ y: row2Y,
7522
+ valueWidth: promptValueWidth,
7523
+ labelWidth: MOBILE_STRIP_LABEL_WIDTH,
7524
+ fontFamily
7525
+ })}
7526
+ ${renderMobileStripText({
7527
+ label: "Loc",
7528
+ value: location.rawValue || location.value || "-",
7529
+ labelX: contentX,
7530
+ y: row3Y,
7531
+ valueWidth: locValueWidth,
7532
+ labelWidth: MOBILE_STRIP_LOC_LABEL_WIDTH,
7533
+ fontFamily
7534
+ })}
7535
+ ${renderMobileStripText({
7536
+ label: "IP",
7537
+ value: ip.rawValue || ip.value || "-",
7538
+ labelX: ipLabelX,
7539
+ y: row3Y,
7540
+ valueWidth: ipValueWidth,
7541
+ labelWidth: MOBILE_STRIP_IP_LABEL_WIDTH,
7542
+ fontFamily
7543
+ })}
7544
+ </g>
7545
+ `;
7546
+ };
6994
7547
  var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
6995
7548
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
6996
7549
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
@@ -7039,6 +7592,27 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7039
7592
  parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
7040
7593
  }
7041
7594
  if (hasStrip) {
7595
+ if (normalizeDevice(meta.device) === Device.Mobile) {
7596
+ parts.push(renderMobileStrip({
7597
+ meta,
7598
+ width,
7599
+ height,
7600
+ fontFamily
7601
+ }));
7602
+ return `
7603
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7604
+ <defs>
7605
+ <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7606
+ <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
7607
+ <stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
7608
+ <stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
7609
+ <stop offset="100%" stop-color="#111111" stop-opacity="0" />
7610
+ </linearGradient>
7611
+ </defs>
7612
+ ${parts.join("")}
7613
+ </svg>
7614
+ `;
7615
+ }
7042
7616
  const logoSize = 28;
7043
7617
  const logoX = DEFAULT_STRIP_PADDING_LEFT;
7044
7618
  const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
@@ -7165,16 +7739,16 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
7165
7739
  return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
7166
7740
  };
7167
7741
 
7168
- // src/internals/screenshot-compression.js
7742
+ // src/internals/compression.js
7169
7743
  var import_jimp = require("jimp");
7170
- var logger14 = createInternalLogger("ScreenshotCompression");
7744
+ var logger14 = createInternalLogger("Compression");
7171
7745
  var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
7172
7746
  var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
7173
7747
  var DEFAULT_SCREENSHOT_QUALITY = 0.72;
7174
7748
  var DEFAULT_SCREENSHOT_MIN_QUALITY = 0.38;
7175
7749
  var DEFAULT_SCREENSHOT_MIN_SCALE = 0.25;
7176
7750
  var SUPPORTED_SCREENSHOT_OUTPUT_TYPES = /* @__PURE__ */ new Set(["jpeg"]);
7177
- var toPositiveInteger = (value, fallback = 0) => {
7751
+ var toPositiveInteger2 = (value, fallback = 0) => {
7178
7752
  const number = Math.floor(Number(value) || 0);
7179
7753
  return number > 0 ? number : fallback;
7180
7754
  };
@@ -7196,7 +7770,7 @@ var normalizeScreenshotOutputType = (value) => {
7196
7770
  };
7197
7771
  var getBase64BytesFromBuffer = (buffer) => Math.ceil(buffer.length / 3) * 4;
7198
7772
  var toJpegQuality = (value) => Math.round(normalizeQuality2(value, DEFAULT_SCREENSHOT_QUALITY) * 100);
7199
- var resolveCaptureScreenCompression = (options = {}) => {
7773
+ var resolveImageCompression = (options = {}) => {
7200
7774
  const explicit = options.compression;
7201
7775
  const source = explicit && typeof explicit === "object" && !Array.isArray(explicit) ? explicit : {};
7202
7776
  const enabled = explicit !== false && source.enabled !== false && options.compress !== false;
@@ -7210,7 +7784,7 @@ var resolveCaptureScreenCompression = (options = {}) => {
7210
7784
  );
7211
7785
  return {
7212
7786
  enabled,
7213
- maxBytes: toPositiveInteger(
7787
+ maxBytes: toPositiveInteger2(
7214
7788
  source.maxBytes ?? source.maxBase64Bytes ?? options.maxBytes ?? options.maxBase64Bytes,
7215
7789
  DEFAULT_SCREENSHOT_MAX_BYTES
7216
7790
  ),
@@ -7247,7 +7821,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
7247
7821
  format: compression.outputType
7248
7822
  };
7249
7823
  };
7250
- var compressScreenshotBuffer = async (buffer, compression) => {
7824
+ var compressImageBuffer = async (buffer, compression) => {
7251
7825
  const sourceImage = await import_jimp.Jimp.read(buffer);
7252
7826
  const maxQuality = toJpegQuality(compression.quality);
7253
7827
  const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
@@ -7280,12 +7854,12 @@ var compressScreenshotBuffer = async (buffer, compression) => {
7280
7854
  const fallback = !smallest || finalCandidate.bytes < smallest.bytes ? finalCandidate : smallest;
7281
7855
  return { ...fallback, withinLimit: fallback.bytes <= compression.maxBytes };
7282
7856
  };
7283
- var compressScreenshotBufferToBase64 = async (buffer, compression) => {
7857
+ var compressImageBufferToBase64 = async (buffer, compression) => {
7284
7858
  const originalBytes = getBase64BytesFromBuffer(buffer);
7285
7859
  if (!compression.enabled || originalBytes <= compression.maxBytes) {
7286
7860
  return buffer.toString("base64");
7287
7861
  }
7288
- const result = await compressScreenshotBuffer(buffer, compression).catch((error) => {
7862
+ const result = await compressImageBuffer(buffer, compression).catch((error) => {
7289
7863
  logger14.warning(`captureScreen \u538B\u7F29\u5931\u8D25\uFF0C\u8FD4\u56DE\u539F\u56FE: ${error instanceof Error ? error.message : String(error)}`);
7290
7864
  return null;
7291
7865
  });
@@ -7684,7 +8258,7 @@ var Share = {
7684
8258
  );
7685
8259
  nextProgressLogTs = now + 5e3;
7686
8260
  }
7687
- await (0, import_delay3.default)(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
8261
+ await (0, import_delay4.default)(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
7688
8262
  }
7689
8263
  if (share.mode === "response" && stats.responseMatched === 0) {
7690
8264
  logger15.warning(
@@ -7722,71 +8296,27 @@ var Share = {
7722
8296
  * @returns {Promise<string>} base64 image
7723
8297
  */
7724
8298
  async captureScreen(page, options = {}) {
7725
- const originalViewport = await resolveCurrentViewportSize(page);
7726
- const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
7727
- const buffer = options.buffer ?? defaultBuffer;
7728
8299
  const restore = options.restore ?? false;
7729
- const maxHeight = options.maxHeight ?? 8e3;
7730
8300
  const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
7731
- const compression = resolveCaptureScreenCompression(options);
7732
- try {
7733
- const maxScrollHeight = await page.evaluate(() => {
7734
- let maxHeight2 = document.body.scrollHeight;
7735
- document.querySelectorAll("*").forEach((el) => {
7736
- const style = window.getComputedStyle(el);
7737
- const overflowY = style.overflowY;
7738
- if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
7739
- if (el.scrollHeight > maxHeight2) {
7740
- maxHeight2 = el.scrollHeight;
7741
- }
7742
- el.dataset.pkOrigOverflow = el.style.overflow;
7743
- el.dataset.pkOrigHeight = el.style.height;
7744
- el.dataset.pkOrigMaxHeight = el.style.maxHeight;
7745
- el.classList.add("__pk_expanded__");
7746
- el.style.overflow = "visible";
7747
- el.style.height = "auto";
7748
- el.style.maxHeight = "none";
7749
- }
7750
- });
7751
- return maxHeight2;
7752
- });
7753
- const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
7754
- await page.setViewportSize({
7755
- width: originalViewport.width,
7756
- height: targetHeight
7757
- });
7758
- await (0, import_delay3.default)(1e3);
7759
- const capturedAt = /* @__PURE__ */ new Date();
7760
- const rawBuffer = await capturePageScreenshot(page, {
7761
- fullPage: true,
7762
- type: "png",
7763
- maxClipHeight: targetHeight
8301
+ const compression = resolveImageCompression(options);
8302
+ const captureOptions = {
8303
+ buffer: options.buffer ?? 0,
8304
+ restore,
8305
+ maxHeight: options.maxHeight,
8306
+ type: "png",
8307
+ visibleOnly: true
8308
+ };
8309
+ const capturedAt = /* @__PURE__ */ new Date();
8310
+ const rawBuffer = await captureExpandedFullPageScreenshot(page, captureOptions);
8311
+ let outputBuffer = rawBuffer;
8312
+ if (screenshotWatermarkify.enabled) {
8313
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8314
+ ...screenshotWatermarkify,
8315
+ capturedAt
7764
8316
  });
7765
- let outputBuffer = rawBuffer;
7766
- if (screenshotWatermarkify.enabled) {
7767
- const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
7768
- ...screenshotWatermarkify,
7769
- capturedAt
7770
- });
7771
- outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
7772
- }
7773
- return await compressScreenshotBufferToBase64(outputBuffer, compression);
7774
- } finally {
7775
- if (restore) {
7776
- await page.evaluate(() => {
7777
- document.querySelectorAll(".__pk_expanded__").forEach((el) => {
7778
- el.style.overflow = el.dataset.pkOrigOverflow || "";
7779
- el.style.height = el.dataset.pkOrigHeight || "";
7780
- el.style.maxHeight = el.dataset.pkOrigMaxHeight || "";
7781
- delete el.dataset.pkOrigOverflow;
7782
- delete el.dataset.pkOrigHeight;
7783
- delete el.dataset.pkOrigMaxHeight;
7784
- el.classList.remove("__pk_expanded__");
7785
- });
7786
- });
7787
- await page.setViewportSize(originalViewport);
7788
- }
8317
+ outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
7789
8318
  }
8319
+ return await compressImageBufferToBase64(outputBuffer, compression);
7790
8320
  }
7791
8321
  };
7792
8322