@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.js CHANGED
@@ -439,6 +439,9 @@ function createInternalLogger(moduleName, explicitLogger) {
439
439
  };
440
440
  }
441
441
 
442
+ // src/internals/screenshot.js
443
+ import delay from "delay";
444
+
442
445
  // src/internals/viewport.js
443
446
  var toPositiveInt = (value) => {
444
447
  const number = Math.round(Number(value) || 0);
@@ -472,11 +475,18 @@ var DEFAULT_TIMEOUT_MS = 5e3;
472
475
  var FORCED_FULLPAGE_TYPE = "jpeg";
473
476
  var FORCED_FULLPAGE_QUALITY = 50;
474
477
  var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
478
+ var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
479
+ var DEFAULT_MAX_HEIGHT = 8e3;
480
+ var DEFAULT_SETTLE_MS = 1e3;
475
481
  var toPositiveNumber = (value, fallback = 0) => {
476
482
  const n = Number(value);
477
483
  if (!Number.isFinite(n) || n <= 0) return fallback;
478
484
  return n;
479
485
  };
486
+ var toPositiveInteger = (value, fallback = 0) => {
487
+ const number = Math.round(Number(value) || 0);
488
+ return number > 0 ? number : fallback;
489
+ };
480
490
  var normalizeType = (value) => {
481
491
  const raw = String(value || "png").trim().toLowerCase();
482
492
  if (!SUPPORTED_TYPES.has(raw)) return "png";
@@ -505,6 +515,138 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
505
515
  scale: 1
506
516
  };
507
517
  };
518
+ var expandScrollableContent = async (page, options = {}) => {
519
+ return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
520
+ const body = document.body;
521
+ const root = document.documentElement;
522
+ const scrollingElement = document.scrollingElement;
523
+ const candidates = [];
524
+ const seen = /* @__PURE__ */ new Set();
525
+ let maxHeight = window.innerHeight || 0;
526
+ const pushCandidate = (el) => {
527
+ if (!el || seen.has(el)) return;
528
+ seen.add(el);
529
+ candidates.push(el);
530
+ };
531
+ pushCandidate(scrollingElement);
532
+ pushCandidate(root);
533
+ pushCandidate(body);
534
+ document.querySelectorAll("*").forEach(pushCandidate);
535
+ const isDocumentElement = (el) => el === root || el === body || el === scrollingElement;
536
+ const isVisible = (el, style, rect) => {
537
+ if (!el || !style || !rect) return false;
538
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
539
+ return false;
540
+ }
541
+ if (Number(style.opacity) === 0) return false;
542
+ return rect.width > 0 && rect.height > 0;
543
+ };
544
+ const isScrollableY = (el, style) => {
545
+ if (!el || el.scrollHeight <= el.clientHeight + 1) {
546
+ return false;
547
+ }
548
+ if (isDocumentElement(el)) {
549
+ return true;
550
+ }
551
+ const overflowY = String(style.overflowY || "").toLowerCase();
552
+ const overflow = String(style.overflow || "").toLowerCase();
553
+ const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
554
+ return scrollableOverflow.has(overflowY) || scrollableOverflow.has(overflow);
555
+ };
556
+ candidates.forEach((el) => {
557
+ const style = window.getComputedStyle(el);
558
+ const rect = el.getBoundingClientRect();
559
+ if (visibleOnly && !isVisible(el, style, rect)) {
560
+ return;
561
+ }
562
+ if (!isScrollableY(el, style)) {
563
+ return;
564
+ }
565
+ const scrollHeight = Math.ceil(el.scrollHeight || 0);
566
+ if (scrollHeight <= 0) {
567
+ return;
568
+ }
569
+ if (scrollHeight > maxHeight) {
570
+ maxHeight = scrollHeight;
571
+ }
572
+ if (isDocumentElement(el)) {
573
+ return;
574
+ }
575
+ if (!el.classList.contains(className)) {
576
+ el.dataset.pkOrigOverflow = el.style.overflow;
577
+ el.dataset.pkOrigOverflowPriority = el.style.getPropertyPriority("overflow") || "";
578
+ el.dataset.pkOrigHeight = el.style.height;
579
+ el.dataset.pkOrigHeightPriority = el.style.getPropertyPriority("height") || "";
580
+ el.dataset.pkOrigMinHeight = el.style.minHeight;
581
+ el.dataset.pkOrigMinHeightPriority = el.style.getPropertyPriority("min-height") || "";
582
+ el.dataset.pkOrigMaxHeight = el.style.maxHeight;
583
+ el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
584
+ el.classList.add(className);
585
+ }
586
+ if (forceScrollableHeight) {
587
+ el.style.setProperty("overflow", "visible", "important");
588
+ el.style.setProperty("height", `${scrollHeight}px`, "important");
589
+ el.style.setProperty("min-height", `${scrollHeight}px`, "important");
590
+ el.style.setProperty("max-height", "none", "important");
591
+ return;
592
+ }
593
+ el.style.overflow = "visible";
594
+ el.style.height = "auto";
595
+ el.style.maxHeight = "none";
596
+ });
597
+ return maxHeight;
598
+ }, {
599
+ className: EXPANDED_SCROLLABLE_CLASS,
600
+ forceScrollableHeight: Boolean(options.forceScrollableHeight),
601
+ visibleOnly: options.visibleOnly !== false
602
+ });
603
+ };
604
+ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
605
+ const originalViewport = await resolveCurrentViewportSize(page);
606
+ const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
607
+ const buffer = options.buffer ?? defaultBuffer;
608
+ const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
609
+ const settleMs = Math.max(0, Number(options.settleMs ?? DEFAULT_SETTLE_MS) || 0);
610
+ const maxScrollHeight = await expandScrollableContent(page, {
611
+ forceScrollableHeight: options.forceScrollableHeight,
612
+ visibleOnly: options.visibleOnly !== false
613
+ });
614
+ const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
615
+ await page.setViewportSize({
616
+ width: originalViewport.width,
617
+ height: targetHeight
618
+ });
619
+ if (settleMs > 0) {
620
+ await delay(settleMs);
621
+ }
622
+ return {
623
+ originalViewport,
624
+ maxScrollHeight,
625
+ targetHeight
626
+ };
627
+ };
628
+ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
629
+ await page.evaluate((className) => {
630
+ document.querySelectorAll(`.${className}`).forEach((el) => {
631
+ el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
632
+ el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
633
+ el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
634
+ el.style.setProperty("max-height", el.dataset.pkOrigMaxHeight || "", el.dataset.pkOrigMaxHeightPriority || "");
635
+ delete el.dataset.pkOrigOverflow;
636
+ delete el.dataset.pkOrigOverflowPriority;
637
+ delete el.dataset.pkOrigHeight;
638
+ delete el.dataset.pkOrigHeightPriority;
639
+ delete el.dataset.pkOrigMinHeight;
640
+ delete el.dataset.pkOrigMinHeightPriority;
641
+ delete el.dataset.pkOrigMaxHeight;
642
+ delete el.dataset.pkOrigMaxHeightPriority;
643
+ el.classList.remove(className);
644
+ });
645
+ }, EXPANDED_SCROLLABLE_CLASS);
646
+ if (state?.originalViewport) {
647
+ await page.setViewportSize(state.originalViewport);
648
+ }
649
+ };
508
650
  var capturePageScreenshot = async (page, options = {}) => {
509
651
  const fullPage = Boolean(options.fullPage);
510
652
  const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
@@ -558,6 +700,22 @@ var capturePageScreenshot = async (page, options = {}) => {
558
700
  return await page.screenshot(fallbackOptions);
559
701
  }
560
702
  };
703
+ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
704
+ const state = await prepareExpandedFullPageScreenshot(page, options);
705
+ try {
706
+ return await capturePageScreenshot(page, {
707
+ fullPage: true,
708
+ type: options.type || "png",
709
+ quality: options.quality,
710
+ timeout: options.timeout,
711
+ maxClipHeight: state.targetHeight
712
+ });
713
+ } finally {
714
+ if (options.restore) {
715
+ await restoreExpandedFullPageScreenshot(page, state);
716
+ }
717
+ }
718
+ };
561
719
 
562
720
  // src/errors.js
563
721
  var errors_exports = {};
@@ -2096,7 +2254,7 @@ var AntiCheat = {
2096
2254
  };
2097
2255
 
2098
2256
  // src/internals/humanize/desktop.js
2099
- import delay from "delay";
2257
+ import delay2 from "delay";
2100
2258
  import { createCursor } from "ghost-cursor-playwright";
2101
2259
  var logger6 = createInternalLogger("Humanize");
2102
2260
  var $CursorWeakMap = /* @__PURE__ */ new WeakMap();
@@ -2328,7 +2486,7 @@ var Humanize = {
2328
2486
  }
2329
2487
  await page.mouse.wheel(0, deltaY);
2330
2488
  didScroll = true;
2331
- await delay(this.jitterMs(20 + Math.random() * 40, 0.2));
2489
+ await delay2(this.jitterMs(20 + Math.random() * 40, 0.2));
2332
2490
  }
2333
2491
  logger6.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
2334
2492
  return { element, didScroll };
@@ -2357,7 +2515,7 @@ var Humanize = {
2357
2515
  restoreOnce.restored = true;
2358
2516
  if (typeof restoreOnce.do !== "function") return;
2359
2517
  try {
2360
- await delay(this.jitterMs(1e3));
2518
+ await delay2(this.jitterMs(1e3));
2361
2519
  await restoreOnce.do();
2362
2520
  } catch (restoreError) {
2363
2521
  logger6.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
@@ -2365,7 +2523,7 @@ var Humanize = {
2365
2523
  };
2366
2524
  try {
2367
2525
  if (target == null) {
2368
- await delay(this.jitterMs(reactionDelay, 0.4));
2526
+ await delay2(this.jitterMs(reactionDelay, 0.4));
2369
2527
  await cursor.actions.click();
2370
2528
  logger6.success("humanClick", "Clicked current position");
2371
2529
  return true;
@@ -2399,7 +2557,7 @@ var Humanize = {
2399
2557
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.3;
2400
2558
  const y = box.y + box.height / 2 + (Math.random() - 0.5) * box.height * 0.3;
2401
2559
  await cursor.actions.move({ x, y });
2402
- await delay(this.jitterMs(reactionDelay, 0.4));
2560
+ await delay2(this.jitterMs(reactionDelay, 0.4));
2403
2561
  await cursor.actions.click();
2404
2562
  await restoreOnce();
2405
2563
  logger6.success("humanClick");
@@ -2418,7 +2576,7 @@ var Humanize = {
2418
2576
  async randomSleep(baseMs, jitterPercent = 0.3) {
2419
2577
  const ms = this.jitterMs(baseMs, jitterPercent);
2420
2578
  logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
2421
- await delay(ms);
2579
+ await delay2(ms);
2422
2580
  logger6.success("randomSleep");
2423
2581
  },
2424
2582
  /**
@@ -2436,7 +2594,7 @@ var Humanize = {
2436
2594
  const x = 100 + Math.random() * (viewportSize.width - 200);
2437
2595
  const y = 100 + Math.random() * (viewportSize.height - 200);
2438
2596
  await cursor.actions.move({ x, y });
2439
- await delay(this.jitterMs(600, 0.5));
2597
+ await delay2(this.jitterMs(600, 0.5));
2440
2598
  }
2441
2599
  logger6.success("simulateGaze");
2442
2600
  },
@@ -2460,7 +2618,7 @@ var Humanize = {
2460
2618
  try {
2461
2619
  const locator = page.locator(selector);
2462
2620
  await Humanize.humanClick(page, locator);
2463
- await delay(this.jitterMs(200, 0.4));
2621
+ await delay2(this.jitterMs(200, 0.4));
2464
2622
  for (let i = 0; i < text.length; i++) {
2465
2623
  const char = text[i];
2466
2624
  let charDelay;
@@ -2472,11 +2630,11 @@ var Humanize = {
2472
2630
  charDelay = this.jitterMs(baseDelay, 0.4);
2473
2631
  }
2474
2632
  await page.keyboard.type(char);
2475
- await delay(charDelay);
2633
+ await delay2(charDelay);
2476
2634
  if (Math.random() < pauseProbability && i < text.length - 1) {
2477
2635
  const pauseTime = this.jitterMs(pauseBase, 0.5);
2478
2636
  logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
2479
- await delay(pauseTime);
2637
+ await delay2(pauseTime);
2480
2638
  }
2481
2639
  }
2482
2640
  logger6.success("humanType");
@@ -2485,6 +2643,43 @@ var Humanize = {
2485
2643
  throw error;
2486
2644
  }
2487
2645
  },
2646
+ /**
2647
+ * 人类化按键 - 模拟用户在当前焦点或指定目标上按下一次键。
2648
+ * @param {import('playwright').Page} page
2649
+ * @param {string|import('playwright').ElementHandle|import('playwright').Locator} targetOrKey - 目标或按键
2650
+ * @param {string|Object} [maybeKey] - 按键或选项
2651
+ * @param {Object} [options]
2652
+ */
2653
+ async humanPress(page, targetOrKey, maybeKey, options = {}) {
2654
+ const hasTarget = typeof maybeKey === "string";
2655
+ const key = hasTarget ? maybeKey : targetOrKey;
2656
+ const pressOptions = hasTarget ? options : maybeKey || options;
2657
+ const {
2658
+ reactionDelay = 180,
2659
+ holdDelay = 45,
2660
+ focusDelay = 180,
2661
+ scrollIfNeeded = true,
2662
+ throwOnMissing = true,
2663
+ keyboardOptions = {}
2664
+ } = pressOptions || {};
2665
+ const targetDesc = hasTarget ? typeof targetOrKey === "string" ? targetOrKey : "ElementHandle" : "current focus";
2666
+ logger6.start("humanPress", `key=${key}, target=${targetDesc}`);
2667
+ try {
2668
+ if (hasTarget) {
2669
+ await this.humanClick(page, targetOrKey, { reactionDelay: focusDelay, scrollIfNeeded, throwOnMissing });
2670
+ }
2671
+ await delay2(this.jitterMs(reactionDelay, 0.45));
2672
+ await page.keyboard.press(key, {
2673
+ ...keyboardOptions,
2674
+ delay: this.jitterMs(holdDelay, 0.5)
2675
+ });
2676
+ logger6.success("humanPress");
2677
+ return true;
2678
+ } catch (error) {
2679
+ logger6.fail("humanPress", error);
2680
+ throw error;
2681
+ }
2682
+ },
2488
2683
  /**
2489
2684
  * 人类化清空输入框 - 模拟人类删除文本的行为
2490
2685
  * @param {import('playwright').Page} page
@@ -2495,14 +2690,14 @@ var Humanize = {
2495
2690
  try {
2496
2691
  const locator = page.locator(selector);
2497
2692
  await locator.click();
2498
- await delay(this.jitterMs(200, 0.4));
2693
+ await delay2(this.jitterMs(200, 0.4));
2499
2694
  const currentValue = await locator.inputValue();
2500
2695
  if (!currentValue || currentValue.length === 0) {
2501
2696
  logger6.success("humanClear", "already empty");
2502
2697
  return;
2503
2698
  }
2504
2699
  await page.keyboard.press("Meta+A");
2505
- await delay(this.jitterMs(100, 0.4));
2700
+ await delay2(this.jitterMs(100, 0.4));
2506
2701
  await page.keyboard.press("Backspace");
2507
2702
  logger6.success("humanClear");
2508
2703
  } catch (error) {
@@ -2528,13 +2723,13 @@ var Humanize = {
2528
2723
  const x = 100 + Math.random() * (viewportSize.width - 200);
2529
2724
  const y = 100 + Math.random() * (viewportSize.height - 200);
2530
2725
  await cursor.actions.move({ x, y });
2531
- await delay(this.jitterMs(350, 0.4));
2726
+ await delay2(this.jitterMs(350, 0.4));
2532
2727
  } else if (action < 0.7) {
2533
2728
  const scrollY = (Math.random() - 0.5) * 200;
2534
2729
  await page.mouse.wheel(0, scrollY);
2535
- await delay(this.jitterMs(500, 0.4));
2730
+ await delay2(this.jitterMs(500, 0.4));
2536
2731
  } else {
2537
- await delay(this.jitterMs(800, 0.5));
2732
+ await delay2(this.jitterMs(800, 0.5));
2538
2733
  }
2539
2734
  }
2540
2735
  logger6.success("warmUpBrowsing");
@@ -2563,7 +2758,7 @@ var Humanize = {
2563
2758
  const scrollAmount = stepDistance * factor * sign * jitter;
2564
2759
  await page.mouse.wheel(0, scrollAmount);
2565
2760
  const baseDelay = 60 + i * 25;
2566
- await delay(this.jitterMs(baseDelay, 0.3));
2761
+ await delay2(this.jitterMs(baseDelay, 0.3));
2567
2762
  }
2568
2763
  logger6.success("naturalScroll");
2569
2764
  } catch (error) {
@@ -2573,8 +2768,143 @@ var Humanize = {
2573
2768
  }
2574
2769
  };
2575
2770
 
2771
+ // src/internals/humanize/machine.js
2772
+ var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
2773
+ var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
2774
+ var resolveNativeTarget = (page, target) => {
2775
+ if (!target) return null;
2776
+ if (typeof target === "string") {
2777
+ return page.locator(target);
2778
+ }
2779
+ return target;
2780
+ };
2781
+ var normalizeSelectorOptions = (options = {}) => ({
2782
+ targetParent: Boolean(options.targetParent ?? options.parent ?? false),
2783
+ pick: options.pick === "last" || options.last ? "last" : "first",
2784
+ visibleOnly: options.visibleOnly !== false,
2785
+ fallbackDomClick: Boolean(options.fallbackDomClick),
2786
+ forceMouse: Boolean(options.forceMouse)
2787
+ });
2788
+ var MachineHumanize = {
2789
+ async clickPoint(page, pointOrX, maybeY, options = {}) {
2790
+ const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
2791
+ const point = isPoint(pointOrX) ? pointOrX : { x: pointOrX, y: maybeY };
2792
+ const x = Number(point.x);
2793
+ const y = Number(point.y);
2794
+ if (!Number.isFinite(x) || !Number.isFinite(y)) {
2795
+ throw new Error(`Invalid click point: ${JSON.stringify(point)}`);
2796
+ }
2797
+ const resolvedDevice = resolveDeviceFromPage(page);
2798
+ if (resolvedDevice === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
2799
+ await page.touchscreen.tap(x, y);
2800
+ return true;
2801
+ }
2802
+ await page.mouse.click(x, y, clickOptions.mouseOptions || {});
2803
+ return true;
2804
+ },
2805
+ async click(page, target, options = {}) {
2806
+ if (isPoint(target)) {
2807
+ return MachineHumanize.clickPoint(page, target, void 0, options);
2808
+ }
2809
+ const nativeTarget = resolveNativeTarget(page, target);
2810
+ if (!nativeTarget || typeof nativeTarget.click !== "function") {
2811
+ throw new Error("Machine click target does not expose click()");
2812
+ }
2813
+ await nativeTarget.click(options.clickOptions || options);
2814
+ return true;
2815
+ },
2816
+ async focus(page, target, options = {}) {
2817
+ const nativeTarget = resolveNativeTarget(page, target);
2818
+ if (!nativeTarget || typeof nativeTarget.focus !== "function") {
2819
+ throw new Error("Machine focus target does not expose focus()");
2820
+ }
2821
+ await nativeTarget.focus(options);
2822
+ return true;
2823
+ },
2824
+ async fill(page, target, value, options = {}) {
2825
+ const nativeTarget = resolveNativeTarget(page, target);
2826
+ if (!nativeTarget || typeof nativeTarget.fill !== "function") {
2827
+ throw new Error("Machine fill target does not expose fill()");
2828
+ }
2829
+ await nativeTarget.fill(value, options);
2830
+ return true;
2831
+ },
2832
+ async keyboardType(page, text, options = {}) {
2833
+ await page.keyboard.type(text, options);
2834
+ return true;
2835
+ },
2836
+ async type(page, targetOrText, maybeText, options = {}) {
2837
+ if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
2838
+ return MachineHumanize.keyboardType(page, targetOrText, maybeText || options);
2839
+ }
2840
+ const nativeTarget = resolveNativeTarget(page, targetOrText);
2841
+ if (!nativeTarget || typeof nativeTarget.type !== "function") {
2842
+ throw new Error("Machine type target does not expose type()");
2843
+ }
2844
+ await nativeTarget.type(maybeText, options);
2845
+ return true;
2846
+ },
2847
+ async selectorCenterPoint(page, selector, options = {}) {
2848
+ const normalizedOptions = normalizeSelectorOptions(options);
2849
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2850
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2851
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2852
+ let rect = null;
2853
+ for (const node of ordered) {
2854
+ if (!node) continue;
2855
+ const target = innerOptions.targetParent ? node.parentElement || node : node;
2856
+ rect = target.getBoundingClientRect?.() || null;
2857
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2858
+ if (innerOptions.visibleOnly && !isVisible) continue;
2859
+ break;
2860
+ }
2861
+ if (!rect || rect.width <= 0 || rect.height <= 0) return null;
2862
+ return {
2863
+ x: rect.left + rect.width / 2,
2864
+ y: rect.top + rect.height / 2
2865
+ };
2866
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2867
+ },
2868
+ async domClick(page, selector, options = {}) {
2869
+ const normalizedOptions = normalizeSelectorOptions(options);
2870
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2871
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2872
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2873
+ let target = null;
2874
+ for (const node of ordered) {
2875
+ if (!node) continue;
2876
+ const candidate = innerOptions.targetParent ? node.parentElement || node : node;
2877
+ const rect = candidate.getBoundingClientRect?.() || null;
2878
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2879
+ if (innerOptions.visibleOnly && !isVisible) continue;
2880
+ target = candidate;
2881
+ break;
2882
+ }
2883
+ if (!target || typeof target.click !== "function") return false;
2884
+ target.click();
2885
+ return true;
2886
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2887
+ },
2888
+ async clickSelectorCenter(page, selector, options = {}) {
2889
+ const normalizedOptions = normalizeSelectorOptions(options);
2890
+ try {
2891
+ const point = await MachineHumanize.selectorCenterPoint(page, selector, normalizedOptions);
2892
+ if (point) {
2893
+ await MachineHumanize.clickPoint(page, point, void 0, normalizedOptions);
2894
+ return true;
2895
+ }
2896
+ } catch (error) {
2897
+ if (!normalizedOptions.fallbackDomClick) throw error;
2898
+ }
2899
+ if (normalizedOptions.fallbackDomClick) {
2900
+ return MachineHumanize.domClick(page, selector, normalizedOptions);
2901
+ }
2902
+ return false;
2903
+ }
2904
+ };
2905
+
2576
2906
  // src/internals/humanize/shared.js
2577
- import delay2 from "delay";
2907
+ import delay3 from "delay";
2578
2908
  var jitterMs = (base, jitterPercent = 0.3) => {
2579
2909
  const jitter = Number(base || 0) * Number(jitterPercent || 0) * (Math.random() * 2 - 1);
2580
2910
  return Math.max(10, Math.round(Number(base || 0) + jitter));
@@ -2600,7 +2930,7 @@ var resolveElement = async (page, target, { throwOnMissing = true } = {}) => {
2600
2930
  }
2601
2931
  return element;
2602
2932
  };
2603
- var waitJitter = (base, jitterPercent = 0.3) => delay2(jitterMs(base, jitterPercent));
2933
+ var waitJitter = (base, jitterPercent = 0.3) => delay3(jitterMs(base, jitterPercent));
2604
2934
 
2605
2935
  // src/internals/humanize/mobile.js
2606
2936
  var logger7 = createInternalLogger("Humanize.Mobile");
@@ -2902,6 +3232,49 @@ var scrollScrollableAncestor = async (element, deltaY) => {
2902
3232
  };
2903
3233
  }, deltaY);
2904
3234
  };
3235
+ var scrollAwayFromObstruction = async (element, status) => {
3236
+ return element.evaluate((el, innerStatus) => {
3237
+ const isScrollable = (node) => {
3238
+ const style = window.getComputedStyle(node);
3239
+ if (!style) return false;
3240
+ const overflowY = style.overflowY;
3241
+ if (!["auto", "scroll", "overlay"].includes(overflowY)) return false;
3242
+ return node.scrollHeight > node.clientHeight + 1;
3243
+ };
3244
+ let scroller = el;
3245
+ while (scroller && scroller !== document.body) {
3246
+ if (isScrollable(scroller)) break;
3247
+ scroller = scroller.parentElement;
3248
+ }
3249
+ if (!scroller || scroller === document.body) {
3250
+ return { moved: false, scrollTop: 0, deltaY: 0 };
3251
+ }
3252
+ const rect = el.getBoundingClientRect();
3253
+ const scrollerRect = scroller.getBoundingClientRect();
3254
+ const obstruction = innerStatus?.obstruction || {};
3255
+ const obstructionTop = Number(obstruction.top);
3256
+ const obstructionBottom = Number(obstruction.bottom);
3257
+ const obstructionMiddle = Number.isFinite(obstructionTop) && Number.isFinite(obstructionBottom) ? (obstructionTop + obstructionBottom) / 2 : scrollerRect.top + scrollerRect.height / 2;
3258
+ const scrollerMiddle = scrollerRect.top + scrollerRect.height / 2;
3259
+ const padding = 18;
3260
+ let deltaY = 0;
3261
+ if (Number.isFinite(obstructionTop) && rect.bottom > obstructionTop && obstructionTop >= scrollerRect.top && obstructionTop <= scrollerRect.bottom && obstructionMiddle >= scrollerMiddle) {
3262
+ deltaY = rect.bottom - obstructionTop + padding;
3263
+ } else if (Number.isFinite(obstructionBottom) && rect.top < obstructionBottom && obstructionBottom >= scrollerRect.top && obstructionBottom <= scrollerRect.bottom && obstructionMiddle < scrollerMiddle) {
3264
+ deltaY = rect.top - obstructionBottom - padding;
3265
+ } else {
3266
+ const fallbackDistance = Math.max(48, Math.min(180, scrollerRect.height * 0.45));
3267
+ deltaY = obstructionMiddle >= scrollerMiddle ? fallbackDistance : -fallbackDistance;
3268
+ }
3269
+ const beforeTop = scroller.scrollTop;
3270
+ scroller.scrollTop = beforeTop + deltaY;
3271
+ return {
3272
+ moved: Math.abs(scroller.scrollTop - beforeTop) > 2,
3273
+ scrollTop: scroller.scrollTop,
3274
+ deltaY
3275
+ };
3276
+ }, status);
3277
+ };
2905
3278
  var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
2906
3279
  const viewport = resolveViewport(page);
2907
3280
  const rawRect = options.rect || null;
@@ -3065,6 +3438,15 @@ var MobileHumanize = {
3065
3438
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
3066
3439
  return { element, didScroll, restore: null };
3067
3440
  }
3441
+ if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
3442
+ const moved = await scrollAwayFromObstruction(element, status);
3443
+ if (moved.moved) {
3444
+ logger7.debug(`humanScroll | sticky/fixed \u906E\u6321\u8865\u507F\u6EDA\u52A8 top=${Math.round(moved.scrollTop || 0)}`);
3445
+ await waitJitter(90, 0.3);
3446
+ didScroll = true;
3447
+ continue;
3448
+ }
3449
+ }
3068
3450
  if (Date.now() - startTime > maxDurationMs) {
3069
3451
  logger7.warn(`humanScroll | mobile timeout (${maxDurationMs}ms, status=${status.code}, direction=${status.direction || "unknown"}, fixed=${Boolean(status.isFixed)})`);
3070
3452
  return { element, didScroll, restore: null };
@@ -3196,7 +3578,7 @@ var MobileHumanize = {
3196
3578
  await MobileHumanize.humanScroll(page, element, { throwOnMissing });
3197
3579
  }
3198
3580
  const status = await checkElementVisibility(element).catch(() => null);
3199
- if (status && (status.code === "ZERO_DIMENSIONS" || status.code === "NOT_INTERACTABLE")) {
3581
+ if (status && status.code !== "VISIBLE") {
3200
3582
  const message = `\u5143\u7D20\u4E0D\u53EF\u70B9\u51FB: ${status.reason || status.code}`;
3201
3583
  if (throwOnMissing) throw new Error(message);
3202
3584
  logger7.warn(`humanClick: ${message}\uFF0C\u8DF3\u8FC7\u70B9\u51FB`);
@@ -3256,6 +3638,40 @@ var MobileHumanize = {
3256
3638
  }
3257
3639
  }
3258
3640
  },
3641
+ async humanPress(page, targetOrKey, maybeKey, options = {}) {
3642
+ const hasTarget = typeof maybeKey === "string";
3643
+ const key = hasTarget ? maybeKey : targetOrKey;
3644
+ const pressOptions = hasTarget ? options : maybeKey || options;
3645
+ const {
3646
+ reactionDelay = 170,
3647
+ holdDelay = 42,
3648
+ focusDelay = 180,
3649
+ scrollIfNeeded = true,
3650
+ throwOnMissing = true,
3651
+ keyboardOptions = {}
3652
+ } = pressOptions || {};
3653
+ const targetDesc = hasTarget ? describeTarget(targetOrKey) : "current focus";
3654
+ logger7.start("humanPress", `key=${key}, target=${targetDesc}`);
3655
+ try {
3656
+ if (hasTarget) {
3657
+ await MobileHumanize.humanClick(page, targetOrKey, {
3658
+ reactionDelay: focusDelay,
3659
+ scrollIfNeeded,
3660
+ throwOnMissing
3661
+ });
3662
+ }
3663
+ await waitJitter(reactionDelay, 0.45);
3664
+ await page.keyboard.press(key, {
3665
+ ...keyboardOptions,
3666
+ delay: jitterMs(holdDelay, 0.5)
3667
+ });
3668
+ logger7.success("humanPress");
3669
+ return true;
3670
+ } catch (error) {
3671
+ logger7.fail("humanPress", error);
3672
+ throw error;
3673
+ }
3674
+ },
3259
3675
  async humanClear(page, selector) {
3260
3676
  const locator = page.locator(selector);
3261
3677
  await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
@@ -3306,15 +3722,18 @@ var MobileHumanize = {
3306
3722
  };
3307
3723
 
3308
3724
  // src/humanize.js
3309
- var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
3725
+ var resolveDeviceFromPage2 = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
3310
3726
  var resolveDelegate = (page) => {
3311
- return resolveDeviceFromPage(page) === Device.Mobile ? MobileHumanize : Humanize;
3727
+ return resolveDeviceFromPage2(page) === Device.Mobile ? MobileHumanize : Humanize;
3312
3728
  };
3313
3729
  var callDelegate = (method, page, args) => {
3314
3730
  const delegate = resolveDelegate(page);
3315
3731
  return delegate[method](page, ...args);
3316
3732
  };
3317
3733
  var Humanize2 = {
3734
+ // M = Machine: native/mechanical operations for兼容路径。
3735
+ // 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
3736
+ M: MachineHumanize,
3318
3737
  jitterMs(base, jitterPercent = 0.3) {
3319
3738
  return Humanize.jitterMs(base, jitterPercent);
3320
3739
  },
@@ -3343,6 +3762,12 @@ var Humanize2 = {
3343
3762
  humanType(page, selector, text, options = {}) {
3344
3763
  return callDelegate("humanType", page, [selector, text, options]);
3345
3764
  },
3765
+ humanPress(page, targetOrKey, maybeKey, options = {}) {
3766
+ if (typeof maybeKey === "string") {
3767
+ return callDelegate("humanPress", page, [targetOrKey, maybeKey, options]);
3768
+ }
3769
+ return callDelegate("humanPress", page, [targetOrKey, maybeKey || options]);
3770
+ },
3346
3771
  humanClear(page, selector) {
3347
3772
  return callDelegate("humanClear", page, [selector]);
3348
3773
  },
@@ -5814,7 +6239,7 @@ var Logger = {
5814
6239
  };
5815
6240
 
5816
6241
  // src/share.js
5817
- import delay3 from "delay";
6242
+ import delay4 from "delay";
5818
6243
 
5819
6244
  // src/internals/watermarkify.js
5820
6245
  var DEFAULT_TIMEZONE_OFFSET = 8;
@@ -5848,6 +6273,18 @@ var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
5848
6273
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
5849
6274
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
5850
6275
  var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
6276
+ var MOBILE_STRIP_HEIGHT = 104;
6277
+ var MOBILE_STRIP_PADDING_X = 14;
6278
+ var MOBILE_STRIP_PADDING_Y = 13;
6279
+ var MOBILE_STRIP_ROW_HEIGHT = 22;
6280
+ var MOBILE_STRIP_ROW_GAP = 7;
6281
+ var MOBILE_STRIP_LABEL_FONT_SIZE = 12.5;
6282
+ var MOBILE_STRIP_VALUE_FONT_SIZE = 13.5;
6283
+ var MOBILE_STRIP_LABEL_WIDTH = 45;
6284
+ var MOBILE_STRIP_PROMPT_LABEL_WIDTH = 60;
6285
+ var MOBILE_STRIP_LOC_LABEL_WIDTH = 30;
6286
+ var MOBILE_STRIP_IP_LABEL_WIDTH = 22;
6287
+ var MOBILE_STRIP_META_GAP = 12;
5851
6288
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
5852
6289
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
5853
6290
  /(?:中国)?移动$/i,
@@ -6632,10 +7069,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
6632
7069
  }),
6633
7070
  watermark: options.watermark,
6634
7071
  strip: options.strip,
6635
- stripLogoSrc
7072
+ stripLogoSrc,
7073
+ device: resolvePageDevice(page)
6636
7074
  };
6637
7075
  };
6638
7076
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7077
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7078
+ var findStripSegment = (segments, kind) => {
7079
+ const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7080
+ return found && typeof found === "object" ? found : {};
7081
+ };
6639
7082
  var buildStripSegmentLayout = (segment, options = {}) => {
6640
7083
  const label = normalizeWhitespace(segment?.label || "");
6641
7084
  const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
@@ -6963,6 +7406,116 @@ var renderStripDivider = (x, centerY, height) => {
6963
7406
  />
6964
7407
  `;
6965
7408
  };
7409
+ var renderMobileStripText = ({
7410
+ label,
7411
+ value,
7412
+ labelX,
7413
+ y,
7414
+ valueWidth,
7415
+ labelWidth = MOBILE_STRIP_LABEL_WIDTH,
7416
+ fontFamily
7417
+ }) => {
7418
+ const safeLabel = normalizeWhitespace(label) || "-";
7419
+ const safeValue = fitTextWithEllipsis(
7420
+ Array.from(normalizeWhitespace(value) || "-"),
7421
+ Math.max(18, valueWidth),
7422
+ MOBILE_STRIP_VALUE_FONT_SIZE
7423
+ );
7424
+ return `
7425
+ <text
7426
+ x="${labelX}"
7427
+ y="${y}"
7428
+ fill="#111111"
7429
+ fill-opacity="0.54"
7430
+ font-family="${fontFamily}"
7431
+ font-size="${MOBILE_STRIP_LABEL_FONT_SIZE}"
7432
+ font-weight="650"
7433
+ dominant-baseline="middle"
7434
+ >${escapeXml(safeLabel)}</text>
7435
+ <text
7436
+ x="${labelX + labelWidth}"
7437
+ y="${y}"
7438
+ fill="#111111"
7439
+ font-family="${fontFamily}"
7440
+ font-size="${MOBILE_STRIP_VALUE_FONT_SIZE}"
7441
+ font-weight="730"
7442
+ dominant-baseline="middle"
7443
+ >${escapeXml(safeValue)}</text>
7444
+ `;
7445
+ };
7446
+ var renderMobileStrip = ({ meta, width, height, fontFamily }) => {
7447
+ const stripHeight = MOBILE_STRIP_HEIGHT;
7448
+ const stripY = height - stripHeight;
7449
+ const contentX = MOBILE_STRIP_PADDING_X;
7450
+ const contentWidth = Math.max(1, width - MOBILE_STRIP_PADDING_X * 2);
7451
+ const prompt = findStripSegment(meta.stripSegments, "prompt");
7452
+ const time = findStripSegment(meta.stripSegments, "time");
7453
+ const location = findStripSegment(meta.stripSegments, "location");
7454
+ const ip = findStripSegment(meta.stripSegments, "ip");
7455
+ const row1Y = stripY + MOBILE_STRIP_PADDING_Y + MOBILE_STRIP_ROW_HEIGHT / 2;
7456
+ const row2Y = row1Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7457
+ const row3Y = row2Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7458
+ const promptValueWidth = contentWidth - MOBILE_STRIP_PROMPT_LABEL_WIDTH;
7459
+ const locValueX = contentX + MOBILE_STRIP_LOC_LABEL_WIDTH;
7460
+ const ipLabelX = Math.min(
7461
+ width - MOBILE_STRIP_PADDING_X - MOBILE_STRIP_IP_LABEL_WIDTH - 70,
7462
+ Math.max(
7463
+ locValueX + 80 + MOBILE_STRIP_META_GAP,
7464
+ contentX + Math.round(contentWidth * 0.52)
7465
+ )
7466
+ );
7467
+ const locValueWidth = Math.max(
7468
+ 28,
7469
+ ipLabelX - locValueX - MOBILE_STRIP_META_GAP
7470
+ );
7471
+ const ipValueWidth = Math.max(
7472
+ 28,
7473
+ width - MOBILE_STRIP_PADDING_X - (ipLabelX + MOBILE_STRIP_IP_LABEL_WIDTH)
7474
+ );
7475
+ return `
7476
+ <g id="strip">
7477
+ <rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
7478
+ <rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
7479
+ <rect x="${contentX}" y="${stripY}" width="${Math.max(96, Math.round(width * 0.36))}" height="2" fill="url(#stripAccent)" />
7480
+ ${renderMobileStripText({
7481
+ label: "Prompt",
7482
+ value: prompt.rawValue || prompt.value || "-",
7483
+ labelX: contentX,
7484
+ y: row1Y,
7485
+ valueWidth: promptValueWidth,
7486
+ labelWidth: MOBILE_STRIP_PROMPT_LABEL_WIDTH,
7487
+ fontFamily
7488
+ })}
7489
+ ${renderMobileStripText({
7490
+ label: "Time",
7491
+ value: time.rawValue || time.value || "-",
7492
+ labelX: contentX,
7493
+ y: row2Y,
7494
+ valueWidth: promptValueWidth,
7495
+ labelWidth: MOBILE_STRIP_LABEL_WIDTH,
7496
+ fontFamily
7497
+ })}
7498
+ ${renderMobileStripText({
7499
+ label: "Loc",
7500
+ value: location.rawValue || location.value || "-",
7501
+ labelX: contentX,
7502
+ y: row3Y,
7503
+ valueWidth: locValueWidth,
7504
+ labelWidth: MOBILE_STRIP_LOC_LABEL_WIDTH,
7505
+ fontFamily
7506
+ })}
7507
+ ${renderMobileStripText({
7508
+ label: "IP",
7509
+ value: ip.rawValue || ip.value || "-",
7510
+ labelX: ipLabelX,
7511
+ y: row3Y,
7512
+ valueWidth: ipValueWidth,
7513
+ labelWidth: MOBILE_STRIP_IP_LABEL_WIDTH,
7514
+ fontFamily
7515
+ })}
7516
+ </g>
7517
+ `;
7518
+ };
6966
7519
  var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
6967
7520
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
6968
7521
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
@@ -7011,6 +7564,27 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7011
7564
  parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
7012
7565
  }
7013
7566
  if (hasStrip) {
7567
+ if (normalizeDevice(meta.device) === Device.Mobile) {
7568
+ parts.push(renderMobileStrip({
7569
+ meta,
7570
+ width,
7571
+ height,
7572
+ fontFamily
7573
+ }));
7574
+ return `
7575
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7576
+ <defs>
7577
+ <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7578
+ <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
7579
+ <stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
7580
+ <stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
7581
+ <stop offset="100%" stop-color="#111111" stop-opacity="0" />
7582
+ </linearGradient>
7583
+ </defs>
7584
+ ${parts.join("")}
7585
+ </svg>
7586
+ `;
7587
+ }
7014
7588
  const logoSize = 28;
7015
7589
  const logoX = DEFAULT_STRIP_PADDING_LEFT;
7016
7590
  const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
@@ -7137,16 +7711,16 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
7137
7711
  return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
7138
7712
  };
7139
7713
 
7140
- // src/internals/screenshot-compression.js
7714
+ // src/internals/compression.js
7141
7715
  import { Jimp, JimpMime, ResizeStrategy } from "jimp";
7142
- var logger14 = createInternalLogger("ScreenshotCompression");
7716
+ var logger14 = createInternalLogger("Compression");
7143
7717
  var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
7144
7718
  var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
7145
7719
  var DEFAULT_SCREENSHOT_QUALITY = 0.72;
7146
7720
  var DEFAULT_SCREENSHOT_MIN_QUALITY = 0.38;
7147
7721
  var DEFAULT_SCREENSHOT_MIN_SCALE = 0.25;
7148
7722
  var SUPPORTED_SCREENSHOT_OUTPUT_TYPES = /* @__PURE__ */ new Set(["jpeg"]);
7149
- var toPositiveInteger = (value, fallback = 0) => {
7723
+ var toPositiveInteger2 = (value, fallback = 0) => {
7150
7724
  const number = Math.floor(Number(value) || 0);
7151
7725
  return number > 0 ? number : fallback;
7152
7726
  };
@@ -7168,7 +7742,7 @@ var normalizeScreenshotOutputType = (value) => {
7168
7742
  };
7169
7743
  var getBase64BytesFromBuffer = (buffer) => Math.ceil(buffer.length / 3) * 4;
7170
7744
  var toJpegQuality = (value) => Math.round(normalizeQuality2(value, DEFAULT_SCREENSHOT_QUALITY) * 100);
7171
- var resolveCaptureScreenCompression = (options = {}) => {
7745
+ var resolveImageCompression = (options = {}) => {
7172
7746
  const explicit = options.compression;
7173
7747
  const source = explicit && typeof explicit === "object" && !Array.isArray(explicit) ? explicit : {};
7174
7748
  const enabled = explicit !== false && source.enabled !== false && options.compress !== false;
@@ -7182,7 +7756,7 @@ var resolveCaptureScreenCompression = (options = {}) => {
7182
7756
  );
7183
7757
  return {
7184
7758
  enabled,
7185
- maxBytes: toPositiveInteger(
7759
+ maxBytes: toPositiveInteger2(
7186
7760
  source.maxBytes ?? source.maxBase64Bytes ?? options.maxBytes ?? options.maxBase64Bytes,
7187
7761
  DEFAULT_SCREENSHOT_MAX_BYTES
7188
7762
  ),
@@ -7219,7 +7793,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
7219
7793
  format: compression.outputType
7220
7794
  };
7221
7795
  };
7222
- var compressScreenshotBuffer = async (buffer, compression) => {
7796
+ var compressImageBuffer = async (buffer, compression) => {
7223
7797
  const sourceImage = await Jimp.read(buffer);
7224
7798
  const maxQuality = toJpegQuality(compression.quality);
7225
7799
  const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
@@ -7252,12 +7826,12 @@ var compressScreenshotBuffer = async (buffer, compression) => {
7252
7826
  const fallback = !smallest || finalCandidate.bytes < smallest.bytes ? finalCandidate : smallest;
7253
7827
  return { ...fallback, withinLimit: fallback.bytes <= compression.maxBytes };
7254
7828
  };
7255
- var compressScreenshotBufferToBase64 = async (buffer, compression) => {
7829
+ var compressImageBufferToBase64 = async (buffer, compression) => {
7256
7830
  const originalBytes = getBase64BytesFromBuffer(buffer);
7257
7831
  if (!compression.enabled || originalBytes <= compression.maxBytes) {
7258
7832
  return buffer.toString("base64");
7259
7833
  }
7260
- const result = await compressScreenshotBuffer(buffer, compression).catch((error) => {
7834
+ const result = await compressImageBuffer(buffer, compression).catch((error) => {
7261
7835
  logger14.warning(`captureScreen \u538B\u7F29\u5931\u8D25\uFF0C\u8FD4\u56DE\u539F\u56FE: ${error instanceof Error ? error.message : String(error)}`);
7262
7836
  return null;
7263
7837
  });
@@ -7656,7 +8230,7 @@ var Share = {
7656
8230
  );
7657
8231
  nextProgressLogTs = now + 5e3;
7658
8232
  }
7659
- await delay3(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
8233
+ await delay4(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
7660
8234
  }
7661
8235
  if (share.mode === "response" && stats.responseMatched === 0) {
7662
8236
  logger15.warning(
@@ -7694,71 +8268,27 @@ var Share = {
7694
8268
  * @returns {Promise<string>} base64 image
7695
8269
  */
7696
8270
  async captureScreen(page, options = {}) {
7697
- const originalViewport = await resolveCurrentViewportSize(page);
7698
- const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
7699
- const buffer = options.buffer ?? defaultBuffer;
7700
8271
  const restore = options.restore ?? false;
7701
- const maxHeight = options.maxHeight ?? 8e3;
7702
8272
  const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
7703
- const compression = resolveCaptureScreenCompression(options);
7704
- try {
7705
- const maxScrollHeight = await page.evaluate(() => {
7706
- let maxHeight2 = document.body.scrollHeight;
7707
- document.querySelectorAll("*").forEach((el) => {
7708
- const style = window.getComputedStyle(el);
7709
- const overflowY = style.overflowY;
7710
- if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
7711
- if (el.scrollHeight > maxHeight2) {
7712
- maxHeight2 = el.scrollHeight;
7713
- }
7714
- el.dataset.pkOrigOverflow = el.style.overflow;
7715
- el.dataset.pkOrigHeight = el.style.height;
7716
- el.dataset.pkOrigMaxHeight = el.style.maxHeight;
7717
- el.classList.add("__pk_expanded__");
7718
- el.style.overflow = "visible";
7719
- el.style.height = "auto";
7720
- el.style.maxHeight = "none";
7721
- }
7722
- });
7723
- return maxHeight2;
7724
- });
7725
- const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
7726
- await page.setViewportSize({
7727
- width: originalViewport.width,
7728
- height: targetHeight
7729
- });
7730
- await delay3(1e3);
7731
- const capturedAt = /* @__PURE__ */ new Date();
7732
- const rawBuffer = await capturePageScreenshot(page, {
7733
- fullPage: true,
7734
- type: "png",
7735
- maxClipHeight: targetHeight
8273
+ const compression = resolveImageCompression(options);
8274
+ const captureOptions = {
8275
+ buffer: options.buffer ?? 0,
8276
+ restore,
8277
+ maxHeight: options.maxHeight,
8278
+ type: "png",
8279
+ visibleOnly: true
8280
+ };
8281
+ const capturedAt = /* @__PURE__ */ new Date();
8282
+ const rawBuffer = await captureExpandedFullPageScreenshot(page, captureOptions);
8283
+ let outputBuffer = rawBuffer;
8284
+ if (screenshotWatermarkify.enabled) {
8285
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8286
+ ...screenshotWatermarkify,
8287
+ capturedAt
7736
8288
  });
7737
- let outputBuffer = rawBuffer;
7738
- if (screenshotWatermarkify.enabled) {
7739
- const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
7740
- ...screenshotWatermarkify,
7741
- capturedAt
7742
- });
7743
- outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
7744
- }
7745
- return await compressScreenshotBufferToBase64(outputBuffer, compression);
7746
- } finally {
7747
- if (restore) {
7748
- await page.evaluate(() => {
7749
- document.querySelectorAll(".__pk_expanded__").forEach((el) => {
7750
- el.style.overflow = el.dataset.pkOrigOverflow || "";
7751
- el.style.height = el.dataset.pkOrigHeight || "";
7752
- el.style.maxHeight = el.dataset.pkOrigMaxHeight || "";
7753
- delete el.dataset.pkOrigOverflow;
7754
- delete el.dataset.pkOrigHeight;
7755
- delete el.dataset.pkOrigMaxHeight;
7756
- el.classList.remove("__pk_expanded__");
7757
- });
7758
- });
7759
- await page.setViewportSize(originalViewport);
7760
- }
8289
+ outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
7761
8290
  }
8291
+ return await compressImageBufferToBase64(outputBuffer, compression);
7762
8292
  }
7763
8293
  };
7764
8294