@skrillex1224/playwright-toolkit 2.1.232 → 2.1.234

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
@@ -312,6 +312,7 @@ var ActorInfo = {
312
312
  name: "\u901A\u4E49\u5343\u95EE",
313
313
  domain: "www.qianwen.com",
314
314
  path: "/chat",
315
+ device: Device.Mobile,
315
316
  share: {
316
317
  mode: "response",
317
318
  prefix: "https://www.qianwen.com/share/chat/",
@@ -469,6 +470,9 @@ function createInternalLogger(moduleName, explicitLogger) {
469
470
  // src/internals/screenshot.js
470
471
  var import_delay = __toESM(require("delay"), 1);
471
472
 
473
+ // src/internals/constants.js
474
+ var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
475
+
472
476
  // src/internals/viewport.js
473
477
  var toPositiveInt = (value) => {
474
478
  const number = Math.round(Number(value) || 0);
@@ -505,9 +509,7 @@ var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
505
509
  var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
506
510
  var DEFAULT_MAX_HEIGHT = 8e3;
507
511
  var DEFAULT_SETTLE_MS = 1e3;
508
- var DEFAULT_BUFFER_RATIO = 0.25;
509
- var DEFAULT_BUFFER_MIN = 120;
510
- var DEFAULT_BUFFER_MAX = 320;
512
+ var DEFAULT_MOBILE_SETTLE_MS = 50;
511
513
  var toPositiveNumber = (value, fallback = 0) => {
512
514
  const n = Number(value);
513
515
  if (!Number.isFinite(n) || n <= 0) return fallback;
@@ -517,10 +519,6 @@ var toPositiveInteger = (value, fallback = 0) => {
517
519
  const number = Math.round(Number(value) || 0);
518
520
  return number > 0 ? number : fallback;
519
521
  };
520
- var resolveDefaultBuffer = (viewport = {}) => {
521
- const height = Math.max(1, Number(viewport.height) || 0);
522
- return Math.round(Math.min(DEFAULT_BUFFER_MAX, Math.max(DEFAULT_BUFFER_MIN, height * DEFAULT_BUFFER_RATIO)));
523
- };
524
522
  var normalizeType = (value) => {
525
523
  const raw = String(value || "png").trim().toLowerCase();
526
524
  if (!SUPPORTED_TYPES.has(raw)) return "png";
@@ -534,6 +532,7 @@ var normalizeQuality = (value, type) => {
534
532
  if (rounded < 0 || rounded > 100) return void 0;
535
533
  return rounded;
536
534
  };
535
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
537
536
  var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
538
537
  const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
539
538
  const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
@@ -550,7 +549,7 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
550
549
  };
551
550
  };
552
551
  var expandScrollableContent = async (page, options = {}) => {
553
- return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
552
+ return await page.evaluate(({ className, forceScrollableHeight, visibleOnly, expandDocumentElements }) => {
554
553
  const body = document.body;
555
554
  const root = document.documentElement;
556
555
  const scrollingElement = document.scrollingElement;
@@ -575,8 +574,8 @@ var expandScrollableContent = async (page, options = {}) => {
575
574
  if (Number(style.opacity) === 0) return false;
576
575
  return rect.width > 0 && rect.height > 0;
577
576
  };
578
- const rememberOriginalBoxStyles = (el) => {
579
- if (!el || isDocumentElement(el) || el.classList.contains(className)) {
577
+ const rememberOriginalBoxStyles = (el, { includeDocumentElement = false } = {}) => {
578
+ if (!el || !includeDocumentElement && isDocumentElement(el) || el.classList.contains(className)) {
580
579
  return;
581
580
  }
582
581
  el.dataset.pkOrigOverflow = el.style.overflow;
@@ -589,6 +588,19 @@ var expandScrollableContent = async (page, options = {}) => {
589
588
  el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
590
589
  el.classList.add(className);
591
590
  };
591
+ const expandDocumentElementsToHeight = (height) => {
592
+ if (!expandDocumentElements) return;
593
+ const targetHeight = Math.ceil(Number(height) || 0);
594
+ if (targetHeight <= 0) return;
595
+ [root, body, scrollingElement].forEach((el) => {
596
+ if (!el) return;
597
+ rememberOriginalBoxStyles(el, { includeDocumentElement: true });
598
+ el.style.setProperty("overflow", "visible", "important");
599
+ el.style.setProperty("height", `${targetHeight}px`, "important");
600
+ el.style.setProperty("min-height", `${targetHeight}px`, "important");
601
+ el.style.setProperty("max-height", "none", "important");
602
+ });
603
+ };
592
604
  const isScrollableY = (el, style, rect) => {
593
605
  if (!el || el.scrollHeight <= el.clientHeight + 1) {
594
606
  return false;
@@ -625,6 +637,7 @@ var expandScrollableContent = async (page, options = {}) => {
625
637
  return documentTop + scrollHeight;
626
638
  };
627
639
  const scrollableElements = [];
640
+ const expandedAncestors = [];
628
641
  const expandElementToScrollHeight = (el) => {
629
642
  if (!el || isDocumentElement(el)) return;
630
643
  const scrollHeight = Math.ceil(el.scrollHeight || 0);
@@ -647,13 +660,44 @@ var expandScrollableContent = async (page, options = {}) => {
647
660
  rememberOriginalBoxStyles(node);
648
661
  node.style.setProperty("overflow", "visible", "important");
649
662
  node.style.setProperty("max-height", "none", "important");
650
- if (node.scrollHeight > node.clientHeight + 1) {
663
+ expandedAncestors.push(node);
664
+ }
665
+ };
666
+ const expandAncestorsToCurrentScrollHeight = () => {
667
+ const ancestors = [...new Set(expandedAncestors)];
668
+ for (let pass = 0; pass < 2; pass += 1) {
669
+ ancestors.forEach((node) => {
670
+ if (!node || isDocumentElement(node)) return;
651
671
  const scrollHeight = Math.ceil(node.scrollHeight || 0);
672
+ if (scrollHeight <= node.clientHeight + 1) return;
673
+ rememberOriginalBoxStyles(node);
652
674
  node.style.setProperty("height", `${scrollHeight}px`, "important");
653
675
  node.style.setProperty("min-height", `${scrollHeight}px`, "important");
654
- }
676
+ node.style.setProperty("max-height", "none", "important");
677
+ });
655
678
  }
656
679
  };
680
+ const measureExpandedRenderedBottom = () => {
681
+ let renderedBottom = maxHeight;
682
+ const scrollY = window.scrollY || window.pageYOffset || 0;
683
+ candidates.forEach((el) => {
684
+ if (!el || isDocumentElement(el)) return;
685
+ if (!el.classList.contains(className) && !el.closest(`.${className}`)) return;
686
+ const style = window.getComputedStyle(el);
687
+ const rect = el.getBoundingClientRect();
688
+ if (!isVisible(el, style, rect)) return;
689
+ renderedBottom = Math.max(renderedBottom, Math.ceil(rect.bottom + scrollY));
690
+ });
691
+ return renderedBottom;
692
+ };
693
+ const measureDocumentScrollHeight = () => {
694
+ return Math.max(
695
+ maxHeight,
696
+ Math.ceil(root?.scrollHeight || 0),
697
+ Math.ceil(body?.scrollHeight || 0),
698
+ Math.ceil(scrollingElement?.scrollHeight || 0)
699
+ );
700
+ };
657
701
  candidates.forEach((el) => {
658
702
  const style = window.getComputedStyle(el);
659
703
  const rect = el.getBoundingClientRect();
@@ -684,46 +728,69 @@ var expandScrollableContent = async (page, options = {}) => {
684
728
  el.style.height = "auto";
685
729
  el.style.maxHeight = "none";
686
730
  });
731
+ expandAncestorsToCurrentScrollHeight();
687
732
  scrollableElements.forEach((el) => {
688
733
  const neededHeight = measureNeededHeight(el);
689
734
  if (neededHeight > maxHeight) {
690
735
  maxHeight = neededHeight;
691
736
  }
692
737
  });
693
- return maxHeight;
738
+ maxHeight = Math.max(maxHeight, measureDocumentScrollHeight(), measureExpandedRenderedBottom());
739
+ if (expandDocumentElements) {
740
+ for (let pass = 0; pass < 2; pass += 1) {
741
+ expandDocumentElementsToHeight(maxHeight);
742
+ maxHeight = Math.max(maxHeight, measureDocumentScrollHeight(), measureExpandedRenderedBottom());
743
+ }
744
+ }
745
+ return Math.ceil(maxHeight);
694
746
  }, {
695
747
  className: EXPANDED_SCROLLABLE_CLASS,
696
748
  forceScrollableHeight: options.forceScrollableHeight !== false,
697
- visibleOnly: options.visibleOnly !== false
749
+ visibleOnly: options.visibleOnly !== false,
750
+ expandDocumentElements: options.expandDocumentElements === true
698
751
  });
699
752
  };
700
753
  var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
701
754
  const originalViewport = await resolveCurrentViewportSize(page);
702
- const defaultBuffer = resolveDefaultBuffer(originalViewport);
703
- const buffer = options.buffer ?? defaultBuffer;
704
755
  const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
705
- const settleMs = Math.max(0, Number(options.settleMs ?? DEFAULT_SETTLE_MS) || 0);
756
+ const preserveViewport = options.preserveViewport ?? resolvePageDevice(page) === Device.Mobile;
757
+ const defaultSettleMs = preserveViewport ? DEFAULT_MOBILE_SETTLE_MS : DEFAULT_SETTLE_MS;
758
+ const requestedSettleMs = Math.max(0, Number(options.settleMs ?? defaultSettleMs) || 0);
759
+ const settleMs = preserveViewport ? Math.min(requestedSettleMs, DEFAULT_MOBILE_SETTLE_MS) : requestedSettleMs;
706
760
  const maxScrollHeight = await expandScrollableContent(page, {
707
761
  forceScrollableHeight: options.forceScrollableHeight,
708
- visibleOnly: options.visibleOnly !== false
709
- });
710
- const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
711
- await page.setViewportSize({
712
- width: originalViewport.width,
713
- height: targetHeight
762
+ visibleOnly: options.visibleOnly !== false,
763
+ expandDocumentElements: preserveViewport
714
764
  });
765
+ const targetHeight = Math.min(maxScrollHeight, maxHeight);
766
+ let viewportResized = false;
767
+ if (!preserveViewport) {
768
+ await page.setViewportSize({
769
+ width: originalViewport.width,
770
+ height: targetHeight
771
+ });
772
+ viewportResized = true;
773
+ }
715
774
  if (settleMs > 0) {
716
775
  await (0, import_delay.default)(settleMs);
717
776
  }
718
777
  return {
719
778
  originalViewport,
720
779
  maxScrollHeight,
721
- targetHeight
780
+ targetHeight,
781
+ preserveViewport,
782
+ viewportResized
722
783
  };
723
784
  };
724
785
  var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
725
786
  await page.evaluate((className) => {
726
- document.querySelectorAll(`.${className}`).forEach((el) => {
787
+ const targets = new Set([
788
+ ...document.querySelectorAll(`.${className}`),
789
+ document.documentElement,
790
+ document.body,
791
+ document.scrollingElement
792
+ ].filter((el) => el?.classList?.contains(className)));
793
+ targets.forEach((el) => {
727
794
  el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
728
795
  el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
729
796
  el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
@@ -739,7 +806,7 @@ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
739
806
  el.classList.remove(className);
740
807
  });
741
808
  }, EXPANDED_SCROLLABLE_CLASS);
742
- if (state?.originalViewport) {
809
+ if (state?.originalViewport && state?.viewportResized) {
743
810
  await page.setViewportSize(state.originalViewport);
744
811
  }
745
812
  };
@@ -1237,9 +1304,6 @@ var ProxyMeterRuntime = {
1237
1304
  getProxyMeterSnapshot
1238
1305
  };
1239
1306
 
1240
- // src/internals/constants.js
1241
- var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
1242
-
1243
1307
  // src/runtime-env.js
1244
1308
  var BROWSER_PROFILE_SCHEMA_VERSION = 1;
1245
1309
  var rememberedRuntimeState = null;
@@ -2350,6 +2414,358 @@ var AntiCheat = {
2350
2414
  }
2351
2415
  };
2352
2416
 
2417
+ // src/device-input.js
2418
+ var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
2419
+ var assertPage = (page, method) => {
2420
+ if (!page || typeof page !== "object") {
2421
+ throw new Error(`DeviceInput.${method} requires a Playwright page`);
2422
+ }
2423
+ };
2424
+ var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
2425
+ var pointFromArgs = (pointOrX, maybeY) => {
2426
+ if (isPoint(pointOrX)) {
2427
+ return { x: Number(pointOrX.x), y: Number(pointOrX.y) };
2428
+ }
2429
+ return { x: Number(pointOrX), y: Number(maybeY) };
2430
+ };
2431
+ var resolveNativeTarget = (page, target) => {
2432
+ if (!target) return null;
2433
+ if (typeof target === "string") return page.locator(target);
2434
+ return target;
2435
+ };
2436
+ var normalizeSelectorOptions = (options = {}) => ({
2437
+ targetParent: Boolean(options.targetParent ?? options.parent ?? false),
2438
+ pick: options.pick === "last" || options.last ? "last" : "first",
2439
+ visibleOnly: options.visibleOnly !== false,
2440
+ fallbackDomClick: Boolean(options.fallbackDomClick),
2441
+ forceMouse: Boolean(options.forceMouse),
2442
+ forceClick: Boolean(options.forceClick),
2443
+ mouseOptions: options.mouseOptions || {},
2444
+ clickOptions: options.clickOptions || {},
2445
+ tapOptions: options.tapOptions || {}
2446
+ });
2447
+ var waitFor = (page, timeout) => {
2448
+ if (!timeout) return Promise.resolve();
2449
+ if (page && typeof page.waitForTimeout === "function") {
2450
+ return page.waitForTimeout(timeout);
2451
+ }
2452
+ return new Promise((resolve) => setTimeout(resolve, timeout));
2453
+ };
2454
+ var getTargetBoundingBox = async (target) => {
2455
+ if (!target) return null;
2456
+ if (typeof target.boundingBox === "function") return target.boundingBox();
2457
+ if (typeof target.elementHandle === "function") {
2458
+ const handle = await target.elementHandle();
2459
+ try {
2460
+ return await handle?.boundingBox?.();
2461
+ } finally {
2462
+ if (handle && typeof handle.dispose === "function") {
2463
+ await handle.dispose().catch(() => {
2464
+ });
2465
+ }
2466
+ }
2467
+ }
2468
+ return null;
2469
+ };
2470
+ var assertPoint = (point) => {
2471
+ if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
2472
+ throw new Error(`Invalid input point: ${JSON.stringify(point)}`);
2473
+ }
2474
+ };
2475
+ var dispatchMouseMove = (page, point, options = {}) => page.mouse.move(point.x, point.y, options);
2476
+ var dispatchMouseStart = (page, options = {}) => page.mouse.down(options);
2477
+ var dispatchMouseEnd = (page, options = {}) => page.mouse.up(options);
2478
+ var dragWithMouse = async (page, points, options = {}) => {
2479
+ await dispatchMouseMove(page, points.start, { steps: 8 });
2480
+ await waitFor(page, options.initialDelayMs ?? 250);
2481
+ await dispatchMouseStart(page);
2482
+ await waitFor(page, options.holdDelayMs ?? 350);
2483
+ await dispatchMouseMove(page, points.lift, { steps: 6 });
2484
+ await waitFor(page, options.liftDelayMs ?? 250);
2485
+ for (let step = 1; step <= points.steps; step += 1) {
2486
+ const progress = step / points.steps;
2487
+ const easedProgress = 1 - (1 - progress) * (1 - progress);
2488
+ await dispatchMouseMove(page, {
2489
+ x: points.lift.x + (points.end.x - points.lift.x) * easedProgress,
2490
+ y: points.lift.y + (points.end.y - points.lift.y) * easedProgress
2491
+ }, { steps: 2 });
2492
+ await waitFor(page, options.stepDelayMs ?? 90);
2493
+ }
2494
+ await waitFor(page, options.beforeReleaseDelayMs ?? 100);
2495
+ await dispatchMouseEnd(page);
2496
+ await waitFor(page, options.afterReleaseDelayMs ?? 100);
2497
+ return true;
2498
+ };
2499
+ var dragWithTouch = async (page, points, options = {}) => {
2500
+ let client = null;
2501
+ try {
2502
+ client = await page.context().newCDPSession(page);
2503
+ await client.send("Input.dispatchTouchEvent", {
2504
+ type: "touchStart",
2505
+ touchPoints: [{ x: points.start.x, y: points.start.y, id: 1 }]
2506
+ });
2507
+ await waitFor(page, options.holdDelayMs ?? 350);
2508
+ const totalSteps = points.steps + 1;
2509
+ for (let step = 1; step <= totalSteps; step += 1) {
2510
+ const progress = step / totalSteps;
2511
+ const easedProgress = 1 - (1 - progress) * (1 - progress);
2512
+ const from = step === 1 ? points.start : points.lift;
2513
+ const to = points.end;
2514
+ await client.send("Input.dispatchTouchEvent", {
2515
+ type: "touchMove",
2516
+ touchPoints: [{
2517
+ x: from.x + (to.x - from.x) * easedProgress,
2518
+ y: from.y + (to.y - from.y) * easedProgress,
2519
+ id: 1
2520
+ }]
2521
+ });
2522
+ await waitFor(page, options.stepDelayMs ?? 90);
2523
+ }
2524
+ await waitFor(page, options.beforeReleaseDelayMs ?? 100);
2525
+ await client.send("Input.dispatchTouchEvent", {
2526
+ type: "touchEnd",
2527
+ touchPoints: []
2528
+ });
2529
+ await waitFor(page, options.afterReleaseDelayMs ?? 100);
2530
+ return true;
2531
+ } finally {
2532
+ if (client && typeof client.detach === "function") {
2533
+ await client.detach().catch(() => {
2534
+ });
2535
+ }
2536
+ }
2537
+ };
2538
+ var clickTargetWithDevice = async (page, target, options = {}) => {
2539
+ const normalizedOptions = normalizeSelectorOptions(options);
2540
+ const resolvedDevice = resolveDeviceFromPage(page);
2541
+ if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick) {
2542
+ if (typeof target.tap === "function") {
2543
+ await target.tap(normalizedOptions.tapOptions);
2544
+ return true;
2545
+ }
2546
+ const box = await getTargetBoundingBox(target);
2547
+ if (box) {
2548
+ await DeviceInput.clickPoint(page, {
2549
+ x: box.x + box.width / 2,
2550
+ y: box.y + box.height / 2
2551
+ }, normalizedOptions);
2552
+ return true;
2553
+ }
2554
+ }
2555
+ if (!target || typeof target.click !== "function") {
2556
+ throw new Error("DeviceInput click target does not expose click()");
2557
+ }
2558
+ await target.click(normalizedOptions.clickOptions || options);
2559
+ return true;
2560
+ };
2561
+ var DeviceInput = {
2562
+ device(page) {
2563
+ return resolveDeviceFromPage(page);
2564
+ },
2565
+ isMobile(page) {
2566
+ return resolveDeviceFromPage(page) === Device.Mobile;
2567
+ },
2568
+ async clickPoint(page, pointOrX, maybeY, options = {}) {
2569
+ assertPage(page, "clickPoint");
2570
+ const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
2571
+ const point = pointFromArgs(pointOrX, maybeY);
2572
+ assertPoint(point);
2573
+ if (resolveDeviceFromPage(page) === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
2574
+ await page.touchscreen.tap(point.x, point.y);
2575
+ return true;
2576
+ }
2577
+ await page.mouse.click(point.x, point.y, clickOptions.mouseOptions || {});
2578
+ return true;
2579
+ },
2580
+ async tapPoint(page, pointOrX, maybeY, options = {}) {
2581
+ return DeviceInput.clickPoint(page, pointOrX, maybeY, options);
2582
+ },
2583
+ async click(page, target, options = {}) {
2584
+ assertPage(page, "click");
2585
+ if (isPoint(target)) {
2586
+ return DeviceInput.clickPoint(page, target, void 0, options);
2587
+ }
2588
+ const nativeTarget = resolveNativeTarget(page, target);
2589
+ return clickTargetWithDevice(page, nativeTarget, options);
2590
+ },
2591
+ async tap(page, target, options = {}) {
2592
+ return DeviceInput.click(page, target, options);
2593
+ },
2594
+ async move(page, pointOrX, maybeY, options = {}) {
2595
+ assertPage(page, "move");
2596
+ const moveOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
2597
+ const point = pointFromArgs(pointOrX, maybeY);
2598
+ assertPoint(point);
2599
+ if (resolveDeviceFromPage(page) === Device.Mobile && !moveOptions.forceMouse) {
2600
+ return true;
2601
+ }
2602
+ await page.mouse.move(point.x, point.y, moveOptions.mouseOptions || moveOptions);
2603
+ return true;
2604
+ },
2605
+ async focus(page, target, options = {}) {
2606
+ assertPage(page, "focus");
2607
+ const nativeTarget = resolveNativeTarget(page, target);
2608
+ if (!nativeTarget || typeof nativeTarget.focus !== "function") {
2609
+ throw new Error("DeviceInput focus target does not expose focus()");
2610
+ }
2611
+ await nativeTarget.focus(options);
2612
+ return true;
2613
+ },
2614
+ async fill(page, target, value, options = {}) {
2615
+ assertPage(page, "fill");
2616
+ const nativeTarget = resolveNativeTarget(page, target);
2617
+ if (!nativeTarget || typeof nativeTarget.fill !== "function") {
2618
+ throw new Error("DeviceInput fill target does not expose fill()");
2619
+ }
2620
+ await nativeTarget.fill(value, options);
2621
+ return true;
2622
+ },
2623
+ async keyboardType(page, text, options = {}) {
2624
+ assertPage(page, "keyboardType");
2625
+ await page.keyboard.type(text, options);
2626
+ return true;
2627
+ },
2628
+ async type(page, targetOrText, maybeText, options = {}) {
2629
+ assertPage(page, "type");
2630
+ if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
2631
+ return DeviceInput.keyboardType(page, targetOrText, maybeText || options);
2632
+ }
2633
+ const nativeTarget = resolveNativeTarget(page, targetOrText);
2634
+ if (!nativeTarget || typeof nativeTarget.type !== "function") {
2635
+ throw new Error("DeviceInput type target does not expose type()");
2636
+ }
2637
+ await nativeTarget.type(maybeText, options);
2638
+ return true;
2639
+ },
2640
+ async press(page, targetOrKey, maybeKey, options = {}) {
2641
+ assertPage(page, "press");
2642
+ const hasTarget = typeof maybeKey === "string";
2643
+ const key = hasTarget ? maybeKey : targetOrKey;
2644
+ const pressOptions = hasTarget ? options : maybeKey || options;
2645
+ if (hasTarget) {
2646
+ await DeviceInput.click(page, targetOrKey, pressOptions.clickOptions || {});
2647
+ }
2648
+ await page.keyboard.press(key, pressOptions.keyboardOptions || pressOptions);
2649
+ return true;
2650
+ },
2651
+ async selectorCenterPoint(page, selector, options = {}) {
2652
+ assertPage(page, "selectorCenterPoint");
2653
+ const normalizedOptions = normalizeSelectorOptions(options);
2654
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2655
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2656
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2657
+ let rect = null;
2658
+ for (const node of ordered) {
2659
+ if (!node) continue;
2660
+ const target = innerOptions.targetParent ? node.parentElement || node : node;
2661
+ rect = target.getBoundingClientRect?.() || null;
2662
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2663
+ if (innerOptions.visibleOnly && !isVisible) continue;
2664
+ break;
2665
+ }
2666
+ if (!rect || rect.width <= 0 || rect.height <= 0) return null;
2667
+ return {
2668
+ x: rect.left + rect.width / 2,
2669
+ y: rect.top + rect.height / 2
2670
+ };
2671
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2672
+ },
2673
+ async domClick(page, selector, options = {}) {
2674
+ assertPage(page, "domClick");
2675
+ const normalizedOptions = normalizeSelectorOptions(options);
2676
+ return page.evaluate(({ innerSelector, innerOptions }) => {
2677
+ const nodes = Array.from(document.querySelectorAll(innerSelector));
2678
+ const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2679
+ let target = null;
2680
+ for (const node of ordered) {
2681
+ if (!node) continue;
2682
+ const candidate = innerOptions.targetParent ? node.parentElement || node : node;
2683
+ const rect = candidate.getBoundingClientRect?.() || null;
2684
+ const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2685
+ if (innerOptions.visibleOnly && !isVisible) continue;
2686
+ target = candidate;
2687
+ break;
2688
+ }
2689
+ if (!target || typeof target.click !== "function") return false;
2690
+ target.click();
2691
+ return true;
2692
+ }, { innerSelector: selector, innerOptions: normalizedOptions });
2693
+ },
2694
+ async clickSelectorCenter(page, selector, options = {}) {
2695
+ assertPage(page, "clickSelectorCenter");
2696
+ const normalizedOptions = normalizeSelectorOptions(options);
2697
+ try {
2698
+ const point = await DeviceInput.selectorCenterPoint(page, selector, normalizedOptions);
2699
+ if (point) {
2700
+ await DeviceInput.clickPoint(page, point, void 0, normalizedOptions);
2701
+ return true;
2702
+ }
2703
+ } catch (error) {
2704
+ if (!normalizedOptions.fallbackDomClick) throw error;
2705
+ }
2706
+ if (normalizedOptions.fallbackDomClick) {
2707
+ return DeviceInput.domClick(page, selector, normalizedOptions);
2708
+ }
2709
+ return false;
2710
+ },
2711
+ async clickText(frameOrPage, texts, options = {}) {
2712
+ for (const text of texts || []) {
2713
+ if (!text) continue;
2714
+ const candidates = [
2715
+ frameOrPage.getByText(text, { exact: false }).first(),
2716
+ frameOrPage.locator(`text=${text}`).first()
2717
+ ];
2718
+ for (const candidate of candidates) {
2719
+ const isVisible = await candidate.isVisible({
2720
+ timeout: options.visibleTimeoutMs ?? options.actionVisibleTimeoutMs ?? 1500
2721
+ }).catch(() => false);
2722
+ if (!isVisible) continue;
2723
+ const page = options.page || (frameOrPage && typeof frameOrPage.context === "function" ? frameOrPage : null) || candidate.page?.();
2724
+ if (!page) {
2725
+ throw new Error("DeviceInput.clickText requires options.page when used with a frame locator");
2726
+ }
2727
+ await DeviceInput.click(page, candidate, options);
2728
+ return true;
2729
+ }
2730
+ }
2731
+ return false;
2732
+ },
2733
+ async drag(page, sourceLocator, targetLocator, options = {}) {
2734
+ assertPage(page, "drag");
2735
+ const sourceBox = await sourceLocator.boundingBox();
2736
+ const targetBox = await targetLocator.boundingBox();
2737
+ if (!sourceBox || !targetBox) {
2738
+ throw new Error("Unable to resolve drag coordinates.");
2739
+ }
2740
+ const steps = options.steps || 10;
2741
+ const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
2742
+ const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
2743
+ const points = {
2744
+ start: {
2745
+ x: sourceBox.x + sourceBox.width / 2,
2746
+ y: sourceBox.y + sourceBox.height / 2
2747
+ },
2748
+ lift: {
2749
+ x: sourceBox.x + sourceBox.width / 2 + liftOffsetX,
2750
+ y: sourceBox.y + sourceBox.height / 2 + liftOffsetY
2751
+ },
2752
+ end: {
2753
+ x: targetBox.x + targetBox.width / 2,
2754
+ y: targetBox.y + targetBox.height / 2
2755
+ },
2756
+ steps
2757
+ };
2758
+ if (resolveDeviceFromPage(page) === Device.Mobile && !options.forceMouse) {
2759
+ try {
2760
+ return await dragWithTouch(page, points, options);
2761
+ } catch (error) {
2762
+ if (options.allowMouseFallback === false) throw error;
2763
+ }
2764
+ }
2765
+ return dragWithMouse(page, points, options);
2766
+ }
2767
+ };
2768
+
2353
2769
  // src/internals/humanize/desktop.js
2354
2770
  var import_delay2 = __toESM(require("delay"), 1);
2355
2771
  var import_ghost_cursor_playwright = require("ghost-cursor-playwright");
@@ -2865,141 +3281,6 @@ var Humanize = {
2865
3281
  }
2866
3282
  };
2867
3283
 
2868
- // src/internals/humanize/machine.js
2869
- var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
2870
- var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
2871
- var resolveNativeTarget = (page, target) => {
2872
- if (!target) return null;
2873
- if (typeof target === "string") {
2874
- return page.locator(target);
2875
- }
2876
- return target;
2877
- };
2878
- var normalizeSelectorOptions = (options = {}) => ({
2879
- targetParent: Boolean(options.targetParent ?? options.parent ?? false),
2880
- pick: options.pick === "last" || options.last ? "last" : "first",
2881
- visibleOnly: options.visibleOnly !== false,
2882
- fallbackDomClick: Boolean(options.fallbackDomClick),
2883
- forceMouse: Boolean(options.forceMouse)
2884
- });
2885
- var MachineHumanize = {
2886
- async clickPoint(page, pointOrX, maybeY, options = {}) {
2887
- const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
2888
- const point = isPoint(pointOrX) ? pointOrX : { x: pointOrX, y: maybeY };
2889
- const x = Number(point.x);
2890
- const y = Number(point.y);
2891
- if (!Number.isFinite(x) || !Number.isFinite(y)) {
2892
- throw new Error(`Invalid click point: ${JSON.stringify(point)}`);
2893
- }
2894
- const resolvedDevice = resolveDeviceFromPage(page);
2895
- if (resolvedDevice === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
2896
- await page.touchscreen.tap(x, y);
2897
- return true;
2898
- }
2899
- await page.mouse.click(x, y, clickOptions.mouseOptions || {});
2900
- return true;
2901
- },
2902
- async click(page, target, options = {}) {
2903
- if (isPoint(target)) {
2904
- return MachineHumanize.clickPoint(page, target, void 0, options);
2905
- }
2906
- const nativeTarget = resolveNativeTarget(page, target);
2907
- if (!nativeTarget || typeof nativeTarget.click !== "function") {
2908
- throw new Error("Machine click target does not expose click()");
2909
- }
2910
- await nativeTarget.click(options.clickOptions || options);
2911
- return true;
2912
- },
2913
- async focus(page, target, options = {}) {
2914
- const nativeTarget = resolveNativeTarget(page, target);
2915
- if (!nativeTarget || typeof nativeTarget.focus !== "function") {
2916
- throw new Error("Machine focus target does not expose focus()");
2917
- }
2918
- await nativeTarget.focus(options);
2919
- return true;
2920
- },
2921
- async fill(page, target, value, options = {}) {
2922
- const nativeTarget = resolveNativeTarget(page, target);
2923
- if (!nativeTarget || typeof nativeTarget.fill !== "function") {
2924
- throw new Error("Machine fill target does not expose fill()");
2925
- }
2926
- await nativeTarget.fill(value, options);
2927
- return true;
2928
- },
2929
- async keyboardType(page, text, options = {}) {
2930
- await page.keyboard.type(text, options);
2931
- return true;
2932
- },
2933
- async type(page, targetOrText, maybeText, options = {}) {
2934
- if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
2935
- return MachineHumanize.keyboardType(page, targetOrText, maybeText || options);
2936
- }
2937
- const nativeTarget = resolveNativeTarget(page, targetOrText);
2938
- if (!nativeTarget || typeof nativeTarget.type !== "function") {
2939
- throw new Error("Machine type target does not expose type()");
2940
- }
2941
- await nativeTarget.type(maybeText, options);
2942
- return true;
2943
- },
2944
- async selectorCenterPoint(page, selector, options = {}) {
2945
- const normalizedOptions = normalizeSelectorOptions(options);
2946
- return page.evaluate(({ innerSelector, innerOptions }) => {
2947
- const nodes = Array.from(document.querySelectorAll(innerSelector));
2948
- const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2949
- let rect = null;
2950
- for (const node of ordered) {
2951
- if (!node) continue;
2952
- const target = innerOptions.targetParent ? node.parentElement || node : node;
2953
- rect = target.getBoundingClientRect?.() || null;
2954
- const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2955
- if (innerOptions.visibleOnly && !isVisible) continue;
2956
- break;
2957
- }
2958
- if (!rect || rect.width <= 0 || rect.height <= 0) return null;
2959
- return {
2960
- x: rect.left + rect.width / 2,
2961
- y: rect.top + rect.height / 2
2962
- };
2963
- }, { innerSelector: selector, innerOptions: normalizedOptions });
2964
- },
2965
- async domClick(page, selector, options = {}) {
2966
- const normalizedOptions = normalizeSelectorOptions(options);
2967
- return page.evaluate(({ innerSelector, innerOptions }) => {
2968
- const nodes = Array.from(document.querySelectorAll(innerSelector));
2969
- const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
2970
- let target = null;
2971
- for (const node of ordered) {
2972
- if (!node) continue;
2973
- const candidate = innerOptions.targetParent ? node.parentElement || node : node;
2974
- const rect = candidate.getBoundingClientRect?.() || null;
2975
- const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
2976
- if (innerOptions.visibleOnly && !isVisible) continue;
2977
- target = candidate;
2978
- break;
2979
- }
2980
- if (!target || typeof target.click !== "function") return false;
2981
- target.click();
2982
- return true;
2983
- }, { innerSelector: selector, innerOptions: normalizedOptions });
2984
- },
2985
- async clickSelectorCenter(page, selector, options = {}) {
2986
- const normalizedOptions = normalizeSelectorOptions(options);
2987
- try {
2988
- const point = await MachineHumanize.selectorCenterPoint(page, selector, normalizedOptions);
2989
- if (point) {
2990
- await MachineHumanize.clickPoint(page, point, void 0, normalizedOptions);
2991
- return true;
2992
- }
2993
- } catch (error) {
2994
- if (!normalizedOptions.fallbackDomClick) throw error;
2995
- }
2996
- if (normalizedOptions.fallbackDomClick) {
2997
- return MachineHumanize.domClick(page, selector, normalizedOptions);
2998
- }
2999
- return false;
3000
- }
3001
- };
3002
-
3003
3284
  // src/internals/humanize/shared.js
3004
3285
  var import_delay3 = __toESM(require("delay"), 1);
3005
3286
  var jitterMs = (base, jitterPercent = 0.3) => {
@@ -3828,9 +4109,6 @@ var callDelegate = (method, page, args) => {
3828
4109
  return delegate[method](page, ...args);
3829
4110
  };
3830
4111
  var Humanize2 = {
3831
- // M = Machine: native/mechanical operations for兼容路径。
3832
- // 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
3833
- M: MachineHumanize,
3834
4112
  jitterMs(base, jitterPercent = 0.3) {
3835
4113
  return Humanize.jitterMs(base, jitterPercent);
3836
4114
  },
@@ -4406,42 +4684,14 @@ var clickCaptchaAction = async (frame, texts, options) => {
4406
4684
  if (!isVisible) {
4407
4685
  continue;
4408
4686
  }
4409
- await candidate.click();
4687
+ await DeviceInput.click(options.page, candidate);
4410
4688
  return true;
4411
4689
  }
4412
4690
  }
4413
4691
  return false;
4414
4692
  };
4415
- var dragCaptchaWithMouse = async (page, sourceLocator, targetLocator) => {
4416
- const sourceBox = await sourceLocator.boundingBox();
4417
- const targetBox = await targetLocator.boundingBox();
4418
- if (!sourceBox || !targetBox) {
4419
- throw new Error("Unable to resolve captcha drag coordinates.");
4420
- }
4421
- const startX = sourceBox.x + sourceBox.width / 2;
4422
- const startY = sourceBox.y + sourceBox.height / 2;
4423
- const endX = targetBox.x + targetBox.width / 2;
4424
- const endY = targetBox.y + targetBox.height / 2;
4425
- const steps = 10;
4426
- const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
4427
- const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
4428
- await page.mouse.move(startX, startY, { steps: 8 });
4429
- await page.waitForTimeout(250);
4430
- await page.mouse.down();
4431
- await page.waitForTimeout(350);
4432
- await page.mouse.move(startX + liftOffsetX, startY + liftOffsetY, { steps: 6 });
4433
- await page.waitForTimeout(250);
4434
- for (let step = 1; step <= steps; step++) {
4435
- const progress = step / steps;
4436
- const easedProgress = 1 - (1 - progress) * (1 - progress);
4437
- const currentX = startX + liftOffsetX + (endX - startX - liftOffsetX) * easedProgress;
4438
- const currentY = startY + liftOffsetY + (endY - startY - liftOffsetY) * easedProgress;
4439
- await page.mouse.move(currentX, currentY, { steps: 2 });
4440
- await page.waitForTimeout(90);
4441
- }
4442
- await page.waitForTimeout(100);
4443
- await page.mouse.up();
4444
- await page.waitForTimeout(100);
4693
+ var dragCaptchaAction = async (page, sourceLocator, targetLocator) => {
4694
+ await DeviceInput.drag(page, sourceLocator, targetLocator);
4445
4695
  };
4446
4696
 
4447
4697
  // src/internals/captcha/bytedance.js
@@ -4537,7 +4787,7 @@ var getVerifycenterCaptchaContext = async (page, options) => {
4537
4787
  return { iframeLocator, frame };
4538
4788
  };
4539
4789
  var refreshCaptcha = async (page, frame, options) => {
4540
- const clicked = await clickCaptchaAction(frame, options.refreshTexts, options).catch(() => false);
4790
+ const clicked = await clickCaptchaAction(frame, options.refreshTexts, { ...options, page }).catch(() => false);
4541
4791
  if (!clicked) {
4542
4792
  logger10.warn("Refresh button not found.");
4543
4793
  return false;
@@ -4663,9 +4913,9 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
4663
4913
  state: "visible",
4664
4914
  timeout: config.sourceImageVisibleTimeoutMs
4665
4915
  });
4666
- await dragCaptchaWithMouse(page, sourceImage, dropTarget);
4916
+ await dragCaptchaAction(page, sourceImage, dropTarget);
4667
4917
  }
4668
- const submitted = await clickCaptchaAction(frame, config.submitTexts, config).catch(() => false);
4918
+ const submitted = await clickCaptchaAction(frame, config.submitTexts, { ...config, page }).catch(() => false);
4669
4919
  if (!submitted) {
4670
4920
  logger10.warn("\u672A\u627E\u5230\u63D0\u4EA4\u6309\u94AE\uFF0C\u53EF\u80FD\u4F1A\u81EA\u52A8\u63D0\u4EA4\u3002");
4671
4921
  }
@@ -7168,11 +7418,11 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
7168
7418
  watermark: options.watermark,
7169
7419
  strip: options.strip,
7170
7420
  stripLogoSrc,
7171
- device: resolvePageDevice(page)
7421
+ device: resolvePageDevice2(page)
7172
7422
  };
7173
7423
  };
7174
7424
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7175
- var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7425
+ var resolvePageDevice2 = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7176
7426
  var findStripSegment = (segments, kind) => {
7177
7427
  const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7178
7428
  return found && typeof found === "object" ? found : {};
@@ -8371,7 +8621,6 @@ var Share = {
8371
8621
  *
8372
8622
  * @param {import('playwright').Page} page
8373
8623
  * @param {Object} [options]
8374
- * @param {number} [options.buffer] 额外缓冲高度;默认按视口高度自动计算,传 0 可关闭
8375
8624
  * @param {boolean} [options.restore]
8376
8625
  * @param {number} [options.maxHeight]
8377
8626
  * @param {number} [options.maxBytes] 默认 5MiB,返回 base64 超过后会压缩
@@ -8384,7 +8633,6 @@ var Share = {
8384
8633
  const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
8385
8634
  const compression = resolveImageCompression(options);
8386
8635
  const captureOptions = {
8387
- ...Object.prototype.hasOwnProperty.call(options, "buffer") ? { buffer: options.buffer } : {},
8388
8636
  restore,
8389
8637
  maxHeight: options.maxHeight,
8390
8638
  type: "png",
@@ -8410,6 +8658,7 @@ var usePlaywrightToolKit = () => {
8410
8658
  return {
8411
8659
  ApifyKit,
8412
8660
  AntiCheat,
8661
+ DeviceInput,
8413
8662
  Humanize: Humanize2,
8414
8663
  Launch,
8415
8664
  LiveView,