@skrillex1224/playwright-toolkit 2.1.240 → 2.1.242

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
@@ -140,8 +140,9 @@ var ActorInfo = {
140
140
  qbot: createActorInfo({
141
141
  key: "qbot",
142
142
  name: "QQ\u6D4F\u89C8\u5668AI\u641C",
143
- domain: "sogou.com",
143
+ domain: "m.sogou.com",
144
144
  path: "/web",
145
+ device: Device.Mobile,
145
146
  share: {
146
147
  mode: "dom",
147
148
  prefix: "",
@@ -722,14 +723,16 @@ var expandScrollableContent = async (page, options = {}) => {
722
723
  expandDocumentElements: options.expandDocumentElements === true
723
724
  });
724
725
  };
725
- var pinBottomAffixedElements = async (page, options = {}) => {
726
+ var adjustAffixedElementsForExpandedScreenshot = async (page, options = {}) => {
726
727
  return await page.evaluate(({ className, targetHeight }) => {
728
+ const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0;
727
729
  const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0;
730
+ const scrollY = window.scrollY || window.pageYOffset || 0;
728
731
  const safeTargetHeight = Math.ceil(Number(targetHeight) || 0);
729
- const deltaY = safeTargetHeight - viewportHeight;
730
- if (deltaY <= 1) {
732
+ if (safeTargetHeight <= viewportHeight + 1) {
731
733
  return 0;
732
734
  }
735
+ const hasOwn = (source, key) => Object.prototype.hasOwnProperty.call(source, key);
733
736
  const isVisible = (el, style, rect) => {
734
737
  if (!el || !style || !rect) return false;
735
738
  if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
@@ -738,7 +741,7 @@ var pinBottomAffixedElements = async (page, options = {}) => {
738
741
  if (Number(style.opacity) === 0) return false;
739
742
  return rect.width > 0 && rect.height > 0;
740
743
  };
741
- const bottomThreshold = Math.max(24, Math.min(96, viewportHeight * 0.12));
744
+ const edgeThreshold = Math.max(24, Math.min(96, viewportHeight * 0.12));
742
745
  const maxAffixedHeight = Math.max(56, viewportHeight * 0.65);
743
746
  const candidates = [];
744
747
  document.querySelectorAll("*").forEach((el) => {
@@ -748,28 +751,49 @@ var pinBottomAffixedElements = async (page, options = {}) => {
748
751
  const rect = el.getBoundingClientRect();
749
752
  if (!isVisible(el, style, rect)) return;
750
753
  if (rect.height > maxAffixedHeight) return;
751
- if (rect.bottom < viewportHeight - bottomThreshold) return;
754
+ if (rect.width < viewportWidth * 0.25 && rect.height < 80) return;
755
+ const top = Number.parseFloat(style.top);
752
756
  const bottom = Number.parseFloat(style.bottom);
757
+ const hasTopRule = Number.isFinite(top) && top <= Math.max(160, viewportHeight * 0.25);
753
758
  const hasBottomRule = Number.isFinite(bottom) && bottom <= Math.max(160, viewportHeight * 0.25);
754
- const isNearViewportBottom = rect.bottom >= viewportHeight - bottomThreshold;
755
- if (!hasBottomRule && !isNearViewportBottom) return;
756
- candidates.push(el);
759
+ const isNearViewportTop = rect.top <= edgeThreshold;
760
+ const isNearViewportBottom = rect.bottom >= viewportHeight - edgeThreshold;
761
+ const edge = (hasBottomRule || isNearViewportBottom) && !(hasTopRule || isNearViewportTop) ? "bottom" : "top";
762
+ if (position === "fixed" && edge === "top" && !hasTopRule && !isNearViewportTop) return;
763
+ if (position === "fixed" && edge === "bottom" && !hasBottomRule && !isNearViewportBottom) return;
764
+ if (position === "sticky" && !hasTopRule && !hasBottomRule && !isNearViewportTop && !isNearViewportBottom) return;
765
+ candidates.push({ el, position, edge });
757
766
  });
758
- const candidateSet = new Set(candidates);
759
- const topLevelCandidates = candidates.filter((el) => {
767
+ const candidateSet = new Set(candidates.map(({ el }) => el));
768
+ const topLevelCandidates = candidates.filter(({ el }) => {
760
769
  for (let parent = el.parentElement; parent; parent = parent.parentElement) {
761
770
  if (candidateSet.has(parent)) return false;
762
771
  }
763
772
  return true;
764
773
  });
765
- topLevelCandidates.forEach((el) => {
766
- if (!Object.prototype.hasOwnProperty.call(el.dataset, "pkBottomPinned")) {
767
- el.dataset.pkBottomPinned = "1";
774
+ topLevelCandidates.forEach(({ el, position, edge }) => {
775
+ if (!hasOwn(el.dataset, "pkAffixedAdjusted")) {
776
+ el.dataset.pkAffixedAdjusted = "1";
777
+ el.dataset.pkOrigPosition = el.style.getPropertyValue("position") || "";
778
+ el.dataset.pkOrigPositionPriority = el.style.getPropertyPriority("position") || "";
779
+ el.dataset.pkOrigTop = el.style.getPropertyValue("top") || "";
780
+ el.dataset.pkOrigTopPriority = el.style.getPropertyPriority("top") || "";
781
+ el.dataset.pkOrigBottom = el.style.getPropertyValue("bottom") || "";
782
+ el.dataset.pkOrigBottomPriority = el.style.getPropertyPriority("bottom") || "";
768
783
  el.dataset.pkOrigTranslate = el.style.getPropertyValue("translate") || "";
769
784
  el.dataset.pkOrigTranslatePriority = el.style.getPropertyPriority("translate") || "";
770
785
  }
771
786
  el.classList.add(className);
772
- el.style.setProperty("translate", `0 ${Math.round(deltaY)}px`, "important");
787
+ if (position === "fixed") {
788
+ const deltaY = edge === "bottom" ? safeTargetHeight - viewportHeight - scrollY : -scrollY;
789
+ if (Math.abs(deltaY) > 1) {
790
+ el.style.setProperty("translate", `0 ${Math.round(deltaY)}px`, "important");
791
+ }
792
+ return;
793
+ }
794
+ el.style.setProperty("position", "relative", "important");
795
+ el.style.setProperty("top", "auto", "important");
796
+ el.style.setProperty("bottom", "auto", "important");
773
797
  });
774
798
  return topLevelCandidates.length;
775
799
  }, {
@@ -777,7 +801,7 @@ var pinBottomAffixedElements = async (page, options = {}) => {
777
801
  targetHeight: options.targetHeight
778
802
  });
779
803
  };
780
- var restoreBottomAffixedElements = async (page) => {
804
+ var restoreAffixedElementsForExpandedScreenshot = async (page) => {
781
805
  await page.evaluate((className) => {
782
806
  const hasOwn = (source, key) => Object.prototype.hasOwnProperty.call(source, key);
783
807
  const expansionKeys = [
@@ -786,13 +810,28 @@ var restoreBottomAffixedElements = async (page) => {
786
810
  "pkOrigMinHeight",
787
811
  "pkOrigMaxHeight"
788
812
  ];
789
- document.querySelectorAll('[data-pk-bottom-pinned="1"]').forEach((el) => {
813
+ document.querySelectorAll('[data-pk-affixed-adjusted="1"]').forEach((el) => {
814
+ if (hasOwn(el.dataset, "pkOrigPosition")) {
815
+ el.style.setProperty("position", el.dataset.pkOrigPosition || "", el.dataset.pkOrigPositionPriority || "");
816
+ delete el.dataset.pkOrigPosition;
817
+ delete el.dataset.pkOrigPositionPriority;
818
+ }
819
+ if (hasOwn(el.dataset, "pkOrigTop")) {
820
+ el.style.setProperty("top", el.dataset.pkOrigTop || "", el.dataset.pkOrigTopPriority || "");
821
+ delete el.dataset.pkOrigTop;
822
+ delete el.dataset.pkOrigTopPriority;
823
+ }
824
+ if (hasOwn(el.dataset, "pkOrigBottom")) {
825
+ el.style.setProperty("bottom", el.dataset.pkOrigBottom || "", el.dataset.pkOrigBottomPriority || "");
826
+ delete el.dataset.pkOrigBottom;
827
+ delete el.dataset.pkOrigBottomPriority;
828
+ }
790
829
  if (hasOwn(el.dataset, "pkOrigTranslate")) {
791
830
  el.style.setProperty("translate", el.dataset.pkOrigTranslate || "", el.dataset.pkOrigTranslatePriority || "");
792
831
  delete el.dataset.pkOrigTranslate;
793
832
  delete el.dataset.pkOrigTranslatePriority;
794
833
  }
795
- delete el.dataset.pkBottomPinned;
834
+ delete el.dataset.pkAffixedAdjusted;
796
835
  const stillExpanded = expansionKeys.some((key) => hasOwn(el.dataset, key));
797
836
  if (!stillExpanded) {
798
837
  el.classList.remove(className);
@@ -821,8 +860,8 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
821
860
  });
822
861
  viewportResized = true;
823
862
  } else {
824
- await pinBottomAffixedElements(page, { targetHeight }).catch((error) => {
825
- logger.warning(`\u79FB\u52A8\u7AEF\u5438\u5E95\u5143\u7D20\u91CD\u5B9A\u4F4D\u5931\u8D25: ${error?.message || error}`);
863
+ await adjustAffixedElementsForExpandedScreenshot(page, { targetHeight }).catch((error) => {
864
+ logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u91CD\u5B9A\u4F4D\u5931\u8D25: ${error?.message || error}`);
826
865
  });
827
866
  }
828
867
  if (settleMs > 0) {
@@ -928,8 +967,8 @@ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
928
967
  maxClipHeight: state.targetHeight
929
968
  });
930
969
  } finally {
931
- await restoreBottomAffixedElements(page).catch((error) => {
932
- logger.warning(`\u79FB\u52A8\u7AEF\u5438\u5E95\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
970
+ await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
971
+ logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
933
972
  });
934
973
  if (options.restore) {
935
974
  await restoreExpandedFullPageScreenshot(page, state);
@@ -3369,6 +3408,26 @@ var waitJitter = (base, jitterPercent = 0.3) => delay3(jitterMs(base, jitterPerc
3369
3408
  // src/internals/humanize/mobile.js
3370
3409
  var logger7 = createInternalLogger("Humanize.Mobile");
3371
3410
  var initializedPages = /* @__PURE__ */ new WeakSet();
3411
+ var DEFAULT_TAP_TIMEOUT_MS = 2500;
3412
+ var DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS = 1200;
3413
+ var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
3414
+ var INTERACTIVE_SELECTOR = [
3415
+ "button",
3416
+ '[role="button"]',
3417
+ "a[href]",
3418
+ "label",
3419
+ "input",
3420
+ "textarea",
3421
+ "select",
3422
+ "summary",
3423
+ '[contenteditable="true"]',
3424
+ '[tabindex]:not([tabindex="-1"])'
3425
+ ].join(",");
3426
+ var EDITABLE_SELECTOR = [
3427
+ "input",
3428
+ "textarea",
3429
+ '[contenteditable="true"]'
3430
+ ].join(",");
3372
3431
  var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
3373
3432
  var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
3374
3433
  var describeTarget = (target) => {
@@ -3391,8 +3450,24 @@ var clipBoxToViewport = (box, viewport) => {
3391
3450
  }
3392
3451
  return box;
3393
3452
  };
3453
+ var withTimeout = async (operation, timeoutMs, label) => {
3454
+ const safeTimeoutMs = Math.max(50, Number(timeoutMs || 0));
3455
+ let timeoutId = null;
3456
+ try {
3457
+ return await Promise.race([
3458
+ Promise.resolve().then(operation),
3459
+ new Promise((_, reject) => {
3460
+ timeoutId = setTimeout(() => {
3461
+ reject(new Error(`${label} timeout after ${safeTimeoutMs}ms`));
3462
+ }, safeTimeoutMs);
3463
+ })
3464
+ ]);
3465
+ } finally {
3466
+ if (timeoutId) clearTimeout(timeoutId);
3467
+ }
3468
+ };
3394
3469
  var checkElementVisibility = async (element) => {
3395
- return element.evaluate((el) => {
3470
+ return element.evaluate((el, interactiveSelector) => {
3396
3471
  const targetStyle = window.getComputedStyle(el);
3397
3472
  if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
3398
3473
  return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
@@ -3409,10 +3484,12 @@ var checkElementVisibility = async (element) => {
3409
3484
  let clipTop = 0;
3410
3485
  let clipBottom = viewH;
3411
3486
  let isFixed = false;
3487
+ let positioning = null;
3412
3488
  for (let node = el; node && node !== document.body; node = node.parentElement) {
3413
3489
  const style = window.getComputedStyle(node);
3414
3490
  if (style && (style.position === "fixed" || style.position === "sticky")) {
3415
3491
  isFixed = true;
3492
+ positioning = style.position;
3416
3493
  break;
3417
3494
  }
3418
3495
  }
@@ -3448,21 +3525,10 @@ var checkElementVisibility = async (element) => {
3448
3525
  direction: centerY < clipTop ? "up" : "down",
3449
3526
  cy: centerY,
3450
3527
  viewH,
3451
- isFixed
3528
+ isFixed,
3529
+ positioning
3452
3530
  };
3453
3531
  }
3454
- const interactiveSelector = [
3455
- "button",
3456
- '[role="button"]',
3457
- "a[href]",
3458
- "label",
3459
- "input",
3460
- "textarea",
3461
- "select",
3462
- "summary",
3463
- '[contenteditable="true"]',
3464
- '[tabindex]:not([tabindex="-1"])'
3465
- ].join(",");
3466
3532
  const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3467
3533
  const sameInteractiveTarget = (pointElement) => {
3468
3534
  if (!pointElement) return false;
@@ -3484,6 +3550,7 @@ var checkElementVisibility = async (element) => {
3484
3550
  id: node.id || "",
3485
3551
  className,
3486
3552
  isFixed: Boolean(style && (style.position === "fixed" || style.position === "sticky")),
3553
+ positioning: style?.position || "",
3487
3554
  top: rect2 ? rect2.top : null,
3488
3555
  bottom: rect2 ? rect2.bottom : null,
3489
3556
  left: rect2 ? rect2.left : null,
@@ -3501,7 +3568,7 @@ var checkElementVisibility = async (element) => {
3501
3568
  for (const point of samplePoints) {
3502
3569
  const pointElement = document.elementFromPoint(point.x, point.y);
3503
3570
  if (sameInteractiveTarget(pointElement)) {
3504
- return { code: "VISIBLE", isFixed };
3571
+ return { code: "VISIBLE", isFixed, positioning };
3505
3572
  }
3506
3573
  obstruction = obstruction || describeElement(pointElement);
3507
3574
  }
@@ -3513,14 +3580,15 @@ var checkElementVisibility = async (element) => {
3513
3580
  obstruction,
3514
3581
  cy,
3515
3582
  viewH,
3516
- isFixed
3583
+ isFixed,
3584
+ positioning
3517
3585
  };
3518
3586
  }
3519
- return { code: "VISIBLE", isFixed };
3520
- });
3587
+ return { code: "VISIBLE", isFixed, positioning };
3588
+ }, INTERACTIVE_SELECTOR);
3521
3589
  };
3522
3590
  var resolveSafeTapPoint = async (element) => {
3523
- return element.evaluate((el) => {
3591
+ return element.evaluate((el, interactiveSelector) => {
3524
3592
  const rect = el.getBoundingClientRect();
3525
3593
  if (!rect || rect.width <= 0 || rect.height <= 0) {
3526
3594
  return null;
@@ -3557,18 +3625,6 @@ var resolveSafeTapPoint = async (element) => {
3557
3625
  if (visibleWidth <= 1 || visibleHeight <= 1) {
3558
3626
  return null;
3559
3627
  }
3560
- const interactiveSelector = [
3561
- "button",
3562
- '[role="button"]',
3563
- "a[href]",
3564
- "label",
3565
- "input",
3566
- "textarea",
3567
- "select",
3568
- "summary",
3569
- '[contenteditable="true"]',
3570
- '[tabindex]:not([tabindex="-1"])'
3571
- ].join(",");
3572
3628
  const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3573
3629
  const sameInteractiveTarget = (pointElement) => {
3574
3630
  if (!pointElement) return false;
@@ -3606,6 +3662,46 @@ var resolveSafeTapPoint = async (element) => {
3606
3662
  x: chosen.x,
3607
3663
  y: chosen.y
3608
3664
  };
3665
+ }, INTERACTIVE_SELECTOR);
3666
+ };
3667
+ var activateElementFallback = async (element, point = null, options = {}) => {
3668
+ return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector }) => {
3669
+ const pointElement = innerPoint ? document.elementFromPoint(innerPoint.x, innerPoint.y) : null;
3670
+ const nearestInteractive = (node) => {
3671
+ if (!node || typeof node.closest !== "function") return null;
3672
+ return node.closest(interactiveSelector);
3673
+ };
3674
+ const targetInteractive = nearestInteractive(el);
3675
+ const pointInteractive = nearestInteractive(pointElement);
3676
+ let target = null;
3677
+ if (pointInteractive && (pointInteractive === targetInteractive || pointInteractive === el || pointInteractive.contains(el) || el.contains(pointInteractive))) {
3678
+ target = pointInteractive;
3679
+ }
3680
+ target = target || targetInteractive || el;
3681
+ const editable = typeof target.closest === "function" ? target.closest(editableSelector) : null;
3682
+ if (editable && typeof editable.focus === "function") {
3683
+ editable.focus({ preventScroll: true });
3684
+ if (innerOptions.editableOnly) {
3685
+ return { activated: true, method: "focus", tag: editable.tagName || "" };
3686
+ }
3687
+ }
3688
+ if (typeof target.focus === "function") {
3689
+ target.focus({ preventScroll: true });
3690
+ }
3691
+ if (!innerOptions.editableOnly && typeof target.click === "function") {
3692
+ target.click();
3693
+ return { activated: true, method: "dom-click", tag: target.tagName || "" };
3694
+ }
3695
+ return {
3696
+ activated: Boolean(editable),
3697
+ method: editable ? "focus" : "none",
3698
+ tag: target?.tagName || ""
3699
+ };
3700
+ }, {
3701
+ innerPoint: point,
3702
+ innerOptions: options || {},
3703
+ interactiveSelector: INTERACTIVE_SELECTOR,
3704
+ editableSelector: EDITABLE_SELECTOR
3609
3705
  });
3610
3706
  };
3611
3707
  var getScrollableRect = async (element) => {
@@ -3810,12 +3906,31 @@ var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
3810
3906
  }
3811
3907
  }
3812
3908
  };
3813
- var tapPoint = async (page, point) => {
3909
+ var tapPoint = async (page, point, options = {}) => {
3910
+ const {
3911
+ timeoutMs = DEFAULT_TAP_TIMEOUT_MS,
3912
+ mouseFallbackTimeoutMs = DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS,
3913
+ allowMouseFallback = true
3914
+ } = options;
3814
3915
  if (page.touchscreen && typeof page.touchscreen.tap === "function") {
3815
- await page.touchscreen.tap(point.x, point.y);
3816
- return;
3916
+ try {
3917
+ await withTimeout(
3918
+ () => page.touchscreen.tap(point.x, point.y),
3919
+ timeoutMs,
3920
+ "touchscreen.tap"
3921
+ );
3922
+ return { method: "touchscreen" };
3923
+ } catch (error) {
3924
+ logger7.warn(`tapPoint | touchscreen.tap \u5931\u8D25\u6216\u8D85\u65F6\uFF0C\u5C1D\u8BD5\u9F20\u6807\u515C\u5E95: ${error?.message || error}`);
3925
+ if (!allowMouseFallback) throw error;
3926
+ }
3817
3927
  }
3818
- await page.mouse.click(point.x, point.y);
3928
+ await withTimeout(
3929
+ () => page.mouse.click(point.x, point.y),
3930
+ mouseFallbackTimeoutMs,
3931
+ "mouse.click fallback"
3932
+ );
3933
+ return { method: "mouse" };
3819
3934
  };
3820
3935
  var MobileHumanize = {
3821
3936
  jitterMs,
@@ -3868,6 +3983,10 @@ var MobileHumanize = {
3868
3983
  return { element, didScroll, restore: null };
3869
3984
  }
3870
3985
  const scrollRect = await getScrollableRect(element);
3986
+ if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
3987
+ 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"})`);
3988
+ return { element, didScroll, restore: null };
3989
+ }
3871
3990
  if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
3872
3991
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
3873
3992
  return { element, didScroll, restore: null };
@@ -3988,7 +4107,12 @@ var MobileHumanize = {
3988
4107
  const {
3989
4108
  reactionDelay = 220,
3990
4109
  throwOnMissing = true,
3991
- scrollIfNeeded = true
4110
+ scrollIfNeeded = true,
4111
+ tapTimeoutMs = DEFAULT_TAP_TIMEOUT_MS,
4112
+ mouseFallbackTimeoutMs = DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS,
4113
+ activateFallbackTimeoutMs = DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS,
4114
+ fallbackDomClick = true,
4115
+ fallbackDomClickOnTapError = true
3992
4116
  } = options;
3993
4117
  const targetDesc = describeTarget(target);
3994
4118
  logger7.start("humanClick", `target=${targetDesc}`);
@@ -3999,6 +4123,9 @@ var MobileHumanize = {
3999
4123
  await tapPoint(page, {
4000
4124
  x: viewport.width * (0.45 + Math.random() * 0.1),
4001
4125
  y: viewport.height * (0.48 + Math.random() * 0.12)
4126
+ }, {
4127
+ timeoutMs: tapTimeoutMs,
4128
+ mouseFallbackTimeoutMs
4002
4129
  });
4003
4130
  logger7.success("humanClick", "Tapped current position");
4004
4131
  return true;
@@ -4013,6 +4140,19 @@ var MobileHumanize = {
4013
4140
  }
4014
4141
  const status = await checkElementVisibility(element).catch(() => null);
4015
4142
  if (status && status.code !== "VISIBLE") {
4143
+ if (fallbackDomClick && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4144
+ const fallback = await withTimeout(
4145
+ () => activateElementFallback(element, null, {
4146
+ editableOnly: true
4147
+ }),
4148
+ activateFallbackTimeoutMs,
4149
+ "focus fallback"
4150
+ ).catch(() => null);
4151
+ if (fallback?.activated) {
4152
+ logger7.warn(`humanClick: fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4153
+ return true;
4154
+ }
4155
+ }
4016
4156
  const message = `\u5143\u7D20\u4E0D\u53EF\u70B9\u51FB: ${status.reason || status.code}`;
4017
4157
  if (throwOnMissing) throw new Error(message);
4018
4158
  logger7.warn(`humanClick: ${message}\uFF0C\u8DF3\u8FC7\u70B9\u51FB`);
@@ -4027,7 +4167,23 @@ var MobileHumanize = {
4027
4167
  await waitJitter(reactionDelay, 0.45);
4028
4168
  const safePoint = await resolveSafeTapPoint(element).catch(() => null);
4029
4169
  const tapTarget = safePoint || randomPointInBox(clipBoxToViewport(box, resolveViewport(page)), 0.2);
4030
- await tapPoint(page, tapTarget);
4170
+ try {
4171
+ await tapPoint(page, tapTarget, {
4172
+ timeoutMs: tapTimeoutMs,
4173
+ mouseFallbackTimeoutMs
4174
+ });
4175
+ } catch (tapError) {
4176
+ if (!fallbackDomClickOnTapError) throw tapError;
4177
+ const fallback = await withTimeout(
4178
+ () => activateElementFallback(element, tapTarget, {
4179
+ editableOnly: false
4180
+ }),
4181
+ activateFallbackTimeoutMs,
4182
+ "activation fallback"
4183
+ ).catch(() => null);
4184
+ if (!fallback?.activated) throw tapError;
4185
+ logger7.warn(`humanClick: tap \u5931\u8D25\u540E\u5DF2\u7528 ${fallback.method} \u515C\u5E95: ${tapError?.message || tapError}`);
4186
+ }
4031
4187
  await waitJitter(120, 0.35);
4032
4188
  logger7.success("humanClick");
4033
4189
  return true;
@@ -6845,7 +7001,7 @@ var getHostname = (url) => {
6845
7001
  return "\u672C\u5730\u9875\u9762";
6846
7002
  }
6847
7003
  };
6848
- var withTimeout = async (promise, timeoutMs) => {
7004
+ var withTimeout2 = async (promise, timeoutMs) => {
6849
7005
  const safeTimeoutMs = Math.max(0, Number(timeoutMs) || 0);
6850
7006
  if (!safeTimeoutMs) {
6851
7007
  return promise;
@@ -6930,7 +7086,7 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
6930
7086
  const serverAddr = response && typeof response.serverAddr === "function" ? await response.serverAddr().catch(() => null) : null;
6931
7087
  const controller = typeof AbortController === "function" ? new AbortController() : null;
6932
7088
  try {
6933
- const resolved = await withTimeout(
7089
+ const resolved = await withTimeout2(
6934
7090
  Promise.resolve(resolver({
6935
7091
  page,
6936
7092
  response,
@@ -7230,13 +7386,13 @@ var resolveWithIpLookup = async (page, options = {}) => {
7230
7386
  const contentType = normalizeText(await pickHeaderValue(response, ["content-type"]));
7231
7387
  let rawText = "";
7232
7388
  if (response && typeof response.text === "function") {
7233
- rawText = String(await withTimeout(
7389
+ rawText = String(await withTimeout2(
7234
7390
  response.text().catch(() => ""),
7235
7391
  timeoutMs
7236
7392
  ) || "");
7237
7393
  }
7238
7394
  if (!rawText) {
7239
- rawText = String(await withTimeout(
7395
+ rawText = String(await withTimeout2(
7240
7396
  probePage.evaluate(() => {
7241
7397
  return document.body?.innerText || document.documentElement?.innerText || "";
7242
7398
  }).catch(() => ""),