@skrillex1224/playwright-toolkit 2.1.240 → 2.1.241

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
@@ -167,8 +167,9 @@ var ActorInfo = {
167
167
  qbot: createActorInfo({
168
168
  key: "qbot",
169
169
  name: "QQ\u6D4F\u89C8\u5668AI\u641C",
170
- domain: "sogou.com",
170
+ domain: "m.sogou.com",
171
171
  path: "/web",
172
+ device: Device.Mobile,
172
173
  share: {
173
174
  mode: "dom",
174
175
  prefix: "",
@@ -749,14 +750,16 @@ var expandScrollableContent = async (page, options = {}) => {
749
750
  expandDocumentElements: options.expandDocumentElements === true
750
751
  });
751
752
  };
752
- var pinBottomAffixedElements = async (page, options = {}) => {
753
+ var adjustAffixedElementsForExpandedScreenshot = async (page, options = {}) => {
753
754
  return await page.evaluate(({ className, targetHeight }) => {
755
+ const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0;
754
756
  const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0;
757
+ const scrollY = window.scrollY || window.pageYOffset || 0;
755
758
  const safeTargetHeight = Math.ceil(Number(targetHeight) || 0);
756
- const deltaY = safeTargetHeight - viewportHeight;
757
- if (deltaY <= 1) {
759
+ if (safeTargetHeight <= viewportHeight + 1) {
758
760
  return 0;
759
761
  }
762
+ const hasOwn = (source, key) => Object.prototype.hasOwnProperty.call(source, key);
760
763
  const isVisible = (el, style, rect) => {
761
764
  if (!el || !style || !rect) return false;
762
765
  if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
@@ -765,7 +768,7 @@ var pinBottomAffixedElements = async (page, options = {}) => {
765
768
  if (Number(style.opacity) === 0) return false;
766
769
  return rect.width > 0 && rect.height > 0;
767
770
  };
768
- const bottomThreshold = Math.max(24, Math.min(96, viewportHeight * 0.12));
771
+ const edgeThreshold = Math.max(24, Math.min(96, viewportHeight * 0.12));
769
772
  const maxAffixedHeight = Math.max(56, viewportHeight * 0.65);
770
773
  const candidates = [];
771
774
  document.querySelectorAll("*").forEach((el) => {
@@ -775,28 +778,49 @@ var pinBottomAffixedElements = async (page, options = {}) => {
775
778
  const rect = el.getBoundingClientRect();
776
779
  if (!isVisible(el, style, rect)) return;
777
780
  if (rect.height > maxAffixedHeight) return;
778
- if (rect.bottom < viewportHeight - bottomThreshold) return;
781
+ if (rect.width < viewportWidth * 0.25 && rect.height < 80) return;
782
+ const top = Number.parseFloat(style.top);
779
783
  const bottom = Number.parseFloat(style.bottom);
784
+ const hasTopRule = Number.isFinite(top) && top <= Math.max(160, viewportHeight * 0.25);
780
785
  const hasBottomRule = Number.isFinite(bottom) && bottom <= Math.max(160, viewportHeight * 0.25);
781
- const isNearViewportBottom = rect.bottom >= viewportHeight - bottomThreshold;
782
- if (!hasBottomRule && !isNearViewportBottom) return;
783
- candidates.push(el);
786
+ const isNearViewportTop = rect.top <= edgeThreshold;
787
+ const isNearViewportBottom = rect.bottom >= viewportHeight - edgeThreshold;
788
+ const edge = (hasBottomRule || isNearViewportBottom) && !(hasTopRule || isNearViewportTop) ? "bottom" : "top";
789
+ if (position === "fixed" && edge === "top" && !hasTopRule && !isNearViewportTop) return;
790
+ if (position === "fixed" && edge === "bottom" && !hasBottomRule && !isNearViewportBottom) return;
791
+ if (position === "sticky" && !hasTopRule && !hasBottomRule && !isNearViewportTop && !isNearViewportBottom) return;
792
+ candidates.push({ el, position, edge });
784
793
  });
785
- const candidateSet = new Set(candidates);
786
- const topLevelCandidates = candidates.filter((el) => {
794
+ const candidateSet = new Set(candidates.map(({ el }) => el));
795
+ const topLevelCandidates = candidates.filter(({ el }) => {
787
796
  for (let parent = el.parentElement; parent; parent = parent.parentElement) {
788
797
  if (candidateSet.has(parent)) return false;
789
798
  }
790
799
  return true;
791
800
  });
792
- topLevelCandidates.forEach((el) => {
793
- if (!Object.prototype.hasOwnProperty.call(el.dataset, "pkBottomPinned")) {
794
- el.dataset.pkBottomPinned = "1";
801
+ topLevelCandidates.forEach(({ el, position, edge }) => {
802
+ if (!hasOwn(el.dataset, "pkAffixedAdjusted")) {
803
+ el.dataset.pkAffixedAdjusted = "1";
804
+ el.dataset.pkOrigPosition = el.style.getPropertyValue("position") || "";
805
+ el.dataset.pkOrigPositionPriority = el.style.getPropertyPriority("position") || "";
806
+ el.dataset.pkOrigTop = el.style.getPropertyValue("top") || "";
807
+ el.dataset.pkOrigTopPriority = el.style.getPropertyPriority("top") || "";
808
+ el.dataset.pkOrigBottom = el.style.getPropertyValue("bottom") || "";
809
+ el.dataset.pkOrigBottomPriority = el.style.getPropertyPriority("bottom") || "";
795
810
  el.dataset.pkOrigTranslate = el.style.getPropertyValue("translate") || "";
796
811
  el.dataset.pkOrigTranslatePriority = el.style.getPropertyPriority("translate") || "";
797
812
  }
798
813
  el.classList.add(className);
799
- el.style.setProperty("translate", `0 ${Math.round(deltaY)}px`, "important");
814
+ if (position === "fixed") {
815
+ const deltaY = edge === "bottom" ? safeTargetHeight - viewportHeight - scrollY : -scrollY;
816
+ if (Math.abs(deltaY) > 1) {
817
+ el.style.setProperty("translate", `0 ${Math.round(deltaY)}px`, "important");
818
+ }
819
+ return;
820
+ }
821
+ el.style.setProperty("position", "relative", "important");
822
+ el.style.setProperty("top", "auto", "important");
823
+ el.style.setProperty("bottom", "auto", "important");
800
824
  });
801
825
  return topLevelCandidates.length;
802
826
  }, {
@@ -804,7 +828,7 @@ var pinBottomAffixedElements = async (page, options = {}) => {
804
828
  targetHeight: options.targetHeight
805
829
  });
806
830
  };
807
- var restoreBottomAffixedElements = async (page) => {
831
+ var restoreAffixedElementsForExpandedScreenshot = async (page) => {
808
832
  await page.evaluate((className) => {
809
833
  const hasOwn = (source, key) => Object.prototype.hasOwnProperty.call(source, key);
810
834
  const expansionKeys = [
@@ -813,13 +837,28 @@ var restoreBottomAffixedElements = async (page) => {
813
837
  "pkOrigMinHeight",
814
838
  "pkOrigMaxHeight"
815
839
  ];
816
- document.querySelectorAll('[data-pk-bottom-pinned="1"]').forEach((el) => {
840
+ document.querySelectorAll('[data-pk-affixed-adjusted="1"]').forEach((el) => {
841
+ if (hasOwn(el.dataset, "pkOrigPosition")) {
842
+ el.style.setProperty("position", el.dataset.pkOrigPosition || "", el.dataset.pkOrigPositionPriority || "");
843
+ delete el.dataset.pkOrigPosition;
844
+ delete el.dataset.pkOrigPositionPriority;
845
+ }
846
+ if (hasOwn(el.dataset, "pkOrigTop")) {
847
+ el.style.setProperty("top", el.dataset.pkOrigTop || "", el.dataset.pkOrigTopPriority || "");
848
+ delete el.dataset.pkOrigTop;
849
+ delete el.dataset.pkOrigTopPriority;
850
+ }
851
+ if (hasOwn(el.dataset, "pkOrigBottom")) {
852
+ el.style.setProperty("bottom", el.dataset.pkOrigBottom || "", el.dataset.pkOrigBottomPriority || "");
853
+ delete el.dataset.pkOrigBottom;
854
+ delete el.dataset.pkOrigBottomPriority;
855
+ }
817
856
  if (hasOwn(el.dataset, "pkOrigTranslate")) {
818
857
  el.style.setProperty("translate", el.dataset.pkOrigTranslate || "", el.dataset.pkOrigTranslatePriority || "");
819
858
  delete el.dataset.pkOrigTranslate;
820
859
  delete el.dataset.pkOrigTranslatePriority;
821
860
  }
822
- delete el.dataset.pkBottomPinned;
861
+ delete el.dataset.pkAffixedAdjusted;
823
862
  const stillExpanded = expansionKeys.some((key) => hasOwn(el.dataset, key));
824
863
  if (!stillExpanded) {
825
864
  el.classList.remove(className);
@@ -848,8 +887,8 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
848
887
  });
849
888
  viewportResized = true;
850
889
  } else {
851
- await pinBottomAffixedElements(page, { targetHeight }).catch((error) => {
852
- logger.warning(`\u79FB\u52A8\u7AEF\u5438\u5E95\u5143\u7D20\u91CD\u5B9A\u4F4D\u5931\u8D25: ${error?.message || error}`);
890
+ await adjustAffixedElementsForExpandedScreenshot(page, { targetHeight }).catch((error) => {
891
+ logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u91CD\u5B9A\u4F4D\u5931\u8D25: ${error?.message || error}`);
853
892
  });
854
893
  }
855
894
  if (settleMs > 0) {
@@ -955,8 +994,8 @@ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
955
994
  maxClipHeight: state.targetHeight
956
995
  });
957
996
  } finally {
958
- await restoreBottomAffixedElements(page).catch((error) => {
959
- logger.warning(`\u79FB\u52A8\u7AEF\u5438\u5E95\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
997
+ await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
998
+ logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
960
999
  });
961
1000
  if (options.restore) {
962
1001
  await restoreExpandedFullPageScreenshot(page, state);
@@ -3397,6 +3436,26 @@ var waitJitter = (base, jitterPercent = 0.3) => (0, import_delay3.default)(jitte
3397
3436
  // src/internals/humanize/mobile.js
3398
3437
  var logger7 = createInternalLogger("Humanize.Mobile");
3399
3438
  var initializedPages = /* @__PURE__ */ new WeakSet();
3439
+ var DEFAULT_TAP_TIMEOUT_MS = 2500;
3440
+ var DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS = 1200;
3441
+ var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
3442
+ var INTERACTIVE_SELECTOR = [
3443
+ "button",
3444
+ '[role="button"]',
3445
+ "a[href]",
3446
+ "label",
3447
+ "input",
3448
+ "textarea",
3449
+ "select",
3450
+ "summary",
3451
+ '[contenteditable="true"]',
3452
+ '[tabindex]:not([tabindex="-1"])'
3453
+ ].join(",");
3454
+ var EDITABLE_SELECTOR = [
3455
+ "input",
3456
+ "textarea",
3457
+ '[contenteditable="true"]'
3458
+ ].join(",");
3400
3459
  var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
3401
3460
  var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
3402
3461
  var describeTarget = (target) => {
@@ -3419,8 +3478,24 @@ var clipBoxToViewport = (box, viewport) => {
3419
3478
  }
3420
3479
  return box;
3421
3480
  };
3481
+ var withTimeout = async (operation, timeoutMs, label) => {
3482
+ const safeTimeoutMs = Math.max(50, Number(timeoutMs || 0));
3483
+ let timeoutId = null;
3484
+ try {
3485
+ return await Promise.race([
3486
+ Promise.resolve().then(operation),
3487
+ new Promise((_, reject) => {
3488
+ timeoutId = setTimeout(() => {
3489
+ reject(new Error(`${label} timeout after ${safeTimeoutMs}ms`));
3490
+ }, safeTimeoutMs);
3491
+ })
3492
+ ]);
3493
+ } finally {
3494
+ if (timeoutId) clearTimeout(timeoutId);
3495
+ }
3496
+ };
3422
3497
  var checkElementVisibility = async (element) => {
3423
- return element.evaluate((el) => {
3498
+ return element.evaluate((el, interactiveSelector) => {
3424
3499
  const targetStyle = window.getComputedStyle(el);
3425
3500
  if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
3426
3501
  return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
@@ -3437,10 +3512,12 @@ var checkElementVisibility = async (element) => {
3437
3512
  let clipTop = 0;
3438
3513
  let clipBottom = viewH;
3439
3514
  let isFixed = false;
3515
+ let positioning = null;
3440
3516
  for (let node = el; node && node !== document.body; node = node.parentElement) {
3441
3517
  const style = window.getComputedStyle(node);
3442
3518
  if (style && (style.position === "fixed" || style.position === "sticky")) {
3443
3519
  isFixed = true;
3520
+ positioning = style.position;
3444
3521
  break;
3445
3522
  }
3446
3523
  }
@@ -3476,21 +3553,10 @@ var checkElementVisibility = async (element) => {
3476
3553
  direction: centerY < clipTop ? "up" : "down",
3477
3554
  cy: centerY,
3478
3555
  viewH,
3479
- isFixed
3556
+ isFixed,
3557
+ positioning
3480
3558
  };
3481
3559
  }
3482
- const interactiveSelector = [
3483
- "button",
3484
- '[role="button"]',
3485
- "a[href]",
3486
- "label",
3487
- "input",
3488
- "textarea",
3489
- "select",
3490
- "summary",
3491
- '[contenteditable="true"]',
3492
- '[tabindex]:not([tabindex="-1"])'
3493
- ].join(",");
3494
3560
  const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3495
3561
  const sameInteractiveTarget = (pointElement) => {
3496
3562
  if (!pointElement) return false;
@@ -3512,6 +3578,7 @@ var checkElementVisibility = async (element) => {
3512
3578
  id: node.id || "",
3513
3579
  className,
3514
3580
  isFixed: Boolean(style && (style.position === "fixed" || style.position === "sticky")),
3581
+ positioning: style?.position || "",
3515
3582
  top: rect2 ? rect2.top : null,
3516
3583
  bottom: rect2 ? rect2.bottom : null,
3517
3584
  left: rect2 ? rect2.left : null,
@@ -3529,7 +3596,7 @@ var checkElementVisibility = async (element) => {
3529
3596
  for (const point of samplePoints) {
3530
3597
  const pointElement = document.elementFromPoint(point.x, point.y);
3531
3598
  if (sameInteractiveTarget(pointElement)) {
3532
- return { code: "VISIBLE", isFixed };
3599
+ return { code: "VISIBLE", isFixed, positioning };
3533
3600
  }
3534
3601
  obstruction = obstruction || describeElement(pointElement);
3535
3602
  }
@@ -3541,14 +3608,15 @@ var checkElementVisibility = async (element) => {
3541
3608
  obstruction,
3542
3609
  cy,
3543
3610
  viewH,
3544
- isFixed
3611
+ isFixed,
3612
+ positioning
3545
3613
  };
3546
3614
  }
3547
- return { code: "VISIBLE", isFixed };
3548
- });
3615
+ return { code: "VISIBLE", isFixed, positioning };
3616
+ }, INTERACTIVE_SELECTOR);
3549
3617
  };
3550
3618
  var resolveSafeTapPoint = async (element) => {
3551
- return element.evaluate((el) => {
3619
+ return element.evaluate((el, interactiveSelector) => {
3552
3620
  const rect = el.getBoundingClientRect();
3553
3621
  if (!rect || rect.width <= 0 || rect.height <= 0) {
3554
3622
  return null;
@@ -3585,18 +3653,6 @@ var resolveSafeTapPoint = async (element) => {
3585
3653
  if (visibleWidth <= 1 || visibleHeight <= 1) {
3586
3654
  return null;
3587
3655
  }
3588
- const interactiveSelector = [
3589
- "button",
3590
- '[role="button"]',
3591
- "a[href]",
3592
- "label",
3593
- "input",
3594
- "textarea",
3595
- "select",
3596
- "summary",
3597
- '[contenteditable="true"]',
3598
- '[tabindex]:not([tabindex="-1"])'
3599
- ].join(",");
3600
3656
  const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3601
3657
  const sameInteractiveTarget = (pointElement) => {
3602
3658
  if (!pointElement) return false;
@@ -3634,6 +3690,46 @@ var resolveSafeTapPoint = async (element) => {
3634
3690
  x: chosen.x,
3635
3691
  y: chosen.y
3636
3692
  };
3693
+ }, INTERACTIVE_SELECTOR);
3694
+ };
3695
+ var activateElementFallback = async (element, point = null, options = {}) => {
3696
+ return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector }) => {
3697
+ const pointElement = innerPoint ? document.elementFromPoint(innerPoint.x, innerPoint.y) : null;
3698
+ const nearestInteractive = (node) => {
3699
+ if (!node || typeof node.closest !== "function") return null;
3700
+ return node.closest(interactiveSelector);
3701
+ };
3702
+ const targetInteractive = nearestInteractive(el);
3703
+ const pointInteractive = nearestInteractive(pointElement);
3704
+ let target = null;
3705
+ if (pointInteractive && (pointInteractive === targetInteractive || pointInteractive === el || pointInteractive.contains(el) || el.contains(pointInteractive))) {
3706
+ target = pointInteractive;
3707
+ }
3708
+ target = target || targetInteractive || el;
3709
+ const editable = typeof target.closest === "function" ? target.closest(editableSelector) : null;
3710
+ if (editable && typeof editable.focus === "function") {
3711
+ editable.focus({ preventScroll: true });
3712
+ if (innerOptions.editableOnly) {
3713
+ return { activated: true, method: "focus", tag: editable.tagName || "" };
3714
+ }
3715
+ }
3716
+ if (typeof target.focus === "function") {
3717
+ target.focus({ preventScroll: true });
3718
+ }
3719
+ if (!innerOptions.editableOnly && typeof target.click === "function") {
3720
+ target.click();
3721
+ return { activated: true, method: "dom-click", tag: target.tagName || "" };
3722
+ }
3723
+ return {
3724
+ activated: Boolean(editable),
3725
+ method: editable ? "focus" : "none",
3726
+ tag: target?.tagName || ""
3727
+ };
3728
+ }, {
3729
+ innerPoint: point,
3730
+ innerOptions: options || {},
3731
+ interactiveSelector: INTERACTIVE_SELECTOR,
3732
+ editableSelector: EDITABLE_SELECTOR
3637
3733
  });
3638
3734
  };
3639
3735
  var getScrollableRect = async (element) => {
@@ -3838,12 +3934,31 @@ var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
3838
3934
  }
3839
3935
  }
3840
3936
  };
3841
- var tapPoint = async (page, point) => {
3937
+ var tapPoint = async (page, point, options = {}) => {
3938
+ const {
3939
+ timeoutMs = DEFAULT_TAP_TIMEOUT_MS,
3940
+ mouseFallbackTimeoutMs = DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS,
3941
+ allowMouseFallback = true
3942
+ } = options;
3842
3943
  if (page.touchscreen && typeof page.touchscreen.tap === "function") {
3843
- await page.touchscreen.tap(point.x, point.y);
3844
- return;
3944
+ try {
3945
+ await withTimeout(
3946
+ () => page.touchscreen.tap(point.x, point.y),
3947
+ timeoutMs,
3948
+ "touchscreen.tap"
3949
+ );
3950
+ return { method: "touchscreen" };
3951
+ } catch (error) {
3952
+ logger7.warn(`tapPoint | touchscreen.tap \u5931\u8D25\u6216\u8D85\u65F6\uFF0C\u5C1D\u8BD5\u9F20\u6807\u515C\u5E95: ${error?.message || error}`);
3953
+ if (!allowMouseFallback) throw error;
3954
+ }
3845
3955
  }
3846
- await page.mouse.click(point.x, point.y);
3956
+ await withTimeout(
3957
+ () => page.mouse.click(point.x, point.y),
3958
+ mouseFallbackTimeoutMs,
3959
+ "mouse.click fallback"
3960
+ );
3961
+ return { method: "mouse" };
3847
3962
  };
3848
3963
  var MobileHumanize = {
3849
3964
  jitterMs,
@@ -3896,6 +4011,10 @@ var MobileHumanize = {
3896
4011
  return { element, didScroll, restore: null };
3897
4012
  }
3898
4013
  const scrollRect = await getScrollableRect(element);
4014
+ if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4015
+ logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u9875\u9762\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (direction=${status.direction || "unknown"})`);
4016
+ return { element, didScroll, restore: null };
4017
+ }
3899
4018
  if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
3900
4019
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
3901
4020
  return { element, didScroll, restore: null };
@@ -4016,7 +4135,12 @@ var MobileHumanize = {
4016
4135
  const {
4017
4136
  reactionDelay = 220,
4018
4137
  throwOnMissing = true,
4019
- scrollIfNeeded = true
4138
+ scrollIfNeeded = true,
4139
+ tapTimeoutMs = DEFAULT_TAP_TIMEOUT_MS,
4140
+ mouseFallbackTimeoutMs = DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS,
4141
+ activateFallbackTimeoutMs = DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS,
4142
+ fallbackDomClick = true,
4143
+ fallbackDomClickOnTapError = true
4020
4144
  } = options;
4021
4145
  const targetDesc = describeTarget(target);
4022
4146
  logger7.start("humanClick", `target=${targetDesc}`);
@@ -4027,6 +4151,9 @@ var MobileHumanize = {
4027
4151
  await tapPoint(page, {
4028
4152
  x: viewport.width * (0.45 + Math.random() * 0.1),
4029
4153
  y: viewport.height * (0.48 + Math.random() * 0.12)
4154
+ }, {
4155
+ timeoutMs: tapTimeoutMs,
4156
+ mouseFallbackTimeoutMs
4030
4157
  });
4031
4158
  logger7.success("humanClick", "Tapped current position");
4032
4159
  return true;
@@ -4041,6 +4168,19 @@ var MobileHumanize = {
4041
4168
  }
4042
4169
  const status = await checkElementVisibility(element).catch(() => null);
4043
4170
  if (status && status.code !== "VISIBLE") {
4171
+ if (fallbackDomClick && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4172
+ const fallback = await withTimeout(
4173
+ () => activateElementFallback(element, null, {
4174
+ editableOnly: true
4175
+ }),
4176
+ activateFallbackTimeoutMs,
4177
+ "focus fallback"
4178
+ ).catch(() => null);
4179
+ if (fallback?.activated) {
4180
+ logger7.warn(`humanClick: fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4181
+ return true;
4182
+ }
4183
+ }
4044
4184
  const message = `\u5143\u7D20\u4E0D\u53EF\u70B9\u51FB: ${status.reason || status.code}`;
4045
4185
  if (throwOnMissing) throw new Error(message);
4046
4186
  logger7.warn(`humanClick: ${message}\uFF0C\u8DF3\u8FC7\u70B9\u51FB`);
@@ -4055,7 +4195,23 @@ var MobileHumanize = {
4055
4195
  await waitJitter(reactionDelay, 0.45);
4056
4196
  const safePoint = await resolveSafeTapPoint(element).catch(() => null);
4057
4197
  const tapTarget = safePoint || randomPointInBox(clipBoxToViewport(box, resolveViewport(page)), 0.2);
4058
- await tapPoint(page, tapTarget);
4198
+ try {
4199
+ await tapPoint(page, tapTarget, {
4200
+ timeoutMs: tapTimeoutMs,
4201
+ mouseFallbackTimeoutMs
4202
+ });
4203
+ } catch (tapError) {
4204
+ if (!fallbackDomClickOnTapError) throw tapError;
4205
+ const fallback = await withTimeout(
4206
+ () => activateElementFallback(element, tapTarget, {
4207
+ editableOnly: false
4208
+ }),
4209
+ activateFallbackTimeoutMs,
4210
+ "activation fallback"
4211
+ ).catch(() => null);
4212
+ if (!fallback?.activated) throw tapError;
4213
+ logger7.warn(`humanClick: tap \u5931\u8D25\u540E\u5DF2\u7528 ${fallback.method} \u515C\u5E95: ${tapError?.message || tapError}`);
4214
+ }
4059
4215
  await waitJitter(120, 0.35);
4060
4216
  logger7.success("humanClick");
4061
4217
  return true;
@@ -6873,7 +7029,7 @@ var getHostname = (url) => {
6873
7029
  return "\u672C\u5730\u9875\u9762";
6874
7030
  }
6875
7031
  };
6876
- var withTimeout = async (promise, timeoutMs) => {
7032
+ var withTimeout2 = async (promise, timeoutMs) => {
6877
7033
  const safeTimeoutMs = Math.max(0, Number(timeoutMs) || 0);
6878
7034
  if (!safeTimeoutMs) {
6879
7035
  return promise;
@@ -6958,7 +7114,7 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
6958
7114
  const serverAddr = response && typeof response.serverAddr === "function" ? await response.serverAddr().catch(() => null) : null;
6959
7115
  const controller = typeof AbortController === "function" ? new AbortController() : null;
6960
7116
  try {
6961
- const resolved = await withTimeout(
7117
+ const resolved = await withTimeout2(
6962
7118
  Promise.resolve(resolver({
6963
7119
  page,
6964
7120
  response,
@@ -7258,13 +7414,13 @@ var resolveWithIpLookup = async (page, options = {}) => {
7258
7414
  const contentType = normalizeText(await pickHeaderValue(response, ["content-type"]));
7259
7415
  let rawText = "";
7260
7416
  if (response && typeof response.text === "function") {
7261
- rawText = String(await withTimeout(
7417
+ rawText = String(await withTimeout2(
7262
7418
  response.text().catch(() => ""),
7263
7419
  timeoutMs
7264
7420
  ) || "");
7265
7421
  }
7266
7422
  if (!rawText) {
7267
- rawText = String(await withTimeout(
7423
+ rawText = String(await withTimeout2(
7268
7424
  probePage.evaluate(() => {
7269
7425
  return document.body?.innerText || document.documentElement?.innerText || "";
7270
7426
  }).catch(() => ""),