@skrillex1224/playwright-toolkit 2.1.227 → 2.1.229

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -466,6 +466,9 @@ function createInternalLogger(moduleName, explicitLogger) {
466
466
  };
467
467
  }
468
468
 
469
+ // src/internals/screenshot.js
470
+ var import_delay = __toESM(require("delay"), 1);
471
+
469
472
  // src/internals/viewport.js
470
473
  var toPositiveInt = (value) => {
471
474
  const number = Math.round(Number(value) || 0);
@@ -499,11 +502,18 @@ var DEFAULT_TIMEOUT_MS = 5e3;
499
502
  var FORCED_FULLPAGE_TYPE = "jpeg";
500
503
  var FORCED_FULLPAGE_QUALITY = 50;
501
504
  var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
505
+ var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
506
+ var DEFAULT_MAX_HEIGHT = 8e3;
507
+ var DEFAULT_SETTLE_MS = 1e3;
502
508
  var toPositiveNumber = (value, fallback = 0) => {
503
509
  const n = Number(value);
504
510
  if (!Number.isFinite(n) || n <= 0) return fallback;
505
511
  return n;
506
512
  };
513
+ var toPositiveInteger = (value, fallback = 0) => {
514
+ const number = Math.round(Number(value) || 0);
515
+ return number > 0 ? number : fallback;
516
+ };
507
517
  var normalizeType = (value) => {
508
518
  const raw = String(value || "png").trim().toLowerCase();
509
519
  if (!SUPPORTED_TYPES.has(raw)) return "png";
@@ -532,6 +542,138 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
532
542
  scale: 1
533
543
  };
534
544
  };
545
+ var expandScrollableContent = async (page, options = {}) => {
546
+ return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
547
+ const body = document.body;
548
+ const root = document.documentElement;
549
+ const scrollingElement = document.scrollingElement;
550
+ const candidates = [];
551
+ const seen = /* @__PURE__ */ new Set();
552
+ let maxHeight = window.innerHeight || 0;
553
+ const pushCandidate = (el) => {
554
+ if (!el || seen.has(el)) return;
555
+ seen.add(el);
556
+ candidates.push(el);
557
+ };
558
+ pushCandidate(scrollingElement);
559
+ pushCandidate(root);
560
+ pushCandidate(body);
561
+ document.querySelectorAll("*").forEach(pushCandidate);
562
+ const isDocumentElement = (el) => el === root || el === body || el === scrollingElement;
563
+ const isVisible = (el, style, rect) => {
564
+ if (!el || !style || !rect) return false;
565
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") {
566
+ return false;
567
+ }
568
+ if (Number(style.opacity) === 0) return false;
569
+ return rect.width > 0 && rect.height > 0;
570
+ };
571
+ const isScrollableY = (el, style) => {
572
+ if (!el || el.scrollHeight <= el.clientHeight + 1) {
573
+ return false;
574
+ }
575
+ if (isDocumentElement(el)) {
576
+ return true;
577
+ }
578
+ const overflowY = String(style.overflowY || "").toLowerCase();
579
+ const overflow = String(style.overflow || "").toLowerCase();
580
+ const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
581
+ return scrollableOverflow.has(overflowY) || scrollableOverflow.has(overflow);
582
+ };
583
+ candidates.forEach((el) => {
584
+ const style = window.getComputedStyle(el);
585
+ const rect = el.getBoundingClientRect();
586
+ if (visibleOnly && !isVisible(el, style, rect)) {
587
+ return;
588
+ }
589
+ if (!isScrollableY(el, style)) {
590
+ return;
591
+ }
592
+ const scrollHeight = Math.ceil(el.scrollHeight || 0);
593
+ if (scrollHeight <= 0) {
594
+ return;
595
+ }
596
+ if (scrollHeight > maxHeight) {
597
+ maxHeight = scrollHeight;
598
+ }
599
+ if (isDocumentElement(el)) {
600
+ return;
601
+ }
602
+ if (!el.classList.contains(className)) {
603
+ el.dataset.pkOrigOverflow = el.style.overflow;
604
+ el.dataset.pkOrigOverflowPriority = el.style.getPropertyPriority("overflow") || "";
605
+ el.dataset.pkOrigHeight = el.style.height;
606
+ el.dataset.pkOrigHeightPriority = el.style.getPropertyPriority("height") || "";
607
+ el.dataset.pkOrigMinHeight = el.style.minHeight;
608
+ el.dataset.pkOrigMinHeightPriority = el.style.getPropertyPriority("min-height") || "";
609
+ el.dataset.pkOrigMaxHeight = el.style.maxHeight;
610
+ el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
611
+ el.classList.add(className);
612
+ }
613
+ if (forceScrollableHeight) {
614
+ el.style.setProperty("overflow", "visible", "important");
615
+ el.style.setProperty("height", `${scrollHeight}px`, "important");
616
+ el.style.setProperty("min-height", `${scrollHeight}px`, "important");
617
+ el.style.setProperty("max-height", "none", "important");
618
+ return;
619
+ }
620
+ el.style.overflow = "visible";
621
+ el.style.height = "auto";
622
+ el.style.maxHeight = "none";
623
+ });
624
+ return maxHeight;
625
+ }, {
626
+ className: EXPANDED_SCROLLABLE_CLASS,
627
+ forceScrollableHeight: Boolean(options.forceScrollableHeight),
628
+ visibleOnly: options.visibleOnly !== false
629
+ });
630
+ };
631
+ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
632
+ const originalViewport = await resolveCurrentViewportSize(page);
633
+ const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
634
+ const buffer = options.buffer ?? defaultBuffer;
635
+ const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
636
+ const settleMs = Math.max(0, Number(options.settleMs ?? DEFAULT_SETTLE_MS) || 0);
637
+ const maxScrollHeight = await expandScrollableContent(page, {
638
+ forceScrollableHeight: options.forceScrollableHeight,
639
+ visibleOnly: options.visibleOnly !== false
640
+ });
641
+ const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
642
+ await page.setViewportSize({
643
+ width: originalViewport.width,
644
+ height: targetHeight
645
+ });
646
+ if (settleMs > 0) {
647
+ await (0, import_delay.default)(settleMs);
648
+ }
649
+ return {
650
+ originalViewport,
651
+ maxScrollHeight,
652
+ targetHeight
653
+ };
654
+ };
655
+ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
656
+ await page.evaluate((className) => {
657
+ document.querySelectorAll(`.${className}`).forEach((el) => {
658
+ el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
659
+ el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
660
+ el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
661
+ el.style.setProperty("max-height", el.dataset.pkOrigMaxHeight || "", el.dataset.pkOrigMaxHeightPriority || "");
662
+ delete el.dataset.pkOrigOverflow;
663
+ delete el.dataset.pkOrigOverflowPriority;
664
+ delete el.dataset.pkOrigHeight;
665
+ delete el.dataset.pkOrigHeightPriority;
666
+ delete el.dataset.pkOrigMinHeight;
667
+ delete el.dataset.pkOrigMinHeightPriority;
668
+ delete el.dataset.pkOrigMaxHeight;
669
+ delete el.dataset.pkOrigMaxHeightPriority;
670
+ el.classList.remove(className);
671
+ });
672
+ }, EXPANDED_SCROLLABLE_CLASS);
673
+ if (state?.originalViewport) {
674
+ await page.setViewportSize(state.originalViewport);
675
+ }
676
+ };
535
677
  var capturePageScreenshot = async (page, options = {}) => {
536
678
  const fullPage = Boolean(options.fullPage);
537
679
  const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
@@ -585,6 +727,22 @@ var capturePageScreenshot = async (page, options = {}) => {
585
727
  return await page.screenshot(fallbackOptions);
586
728
  }
587
729
  };
730
+ var captureExpandedFullPageScreenshot = async (page, options = {}) => {
731
+ const state = await prepareExpandedFullPageScreenshot(page, options);
732
+ try {
733
+ return await capturePageScreenshot(page, {
734
+ fullPage: true,
735
+ type: options.type || "png",
736
+ quality: options.quality,
737
+ timeout: options.timeout,
738
+ maxClipHeight: state.targetHeight
739
+ });
740
+ } finally {
741
+ if (options.restore) {
742
+ await restoreExpandedFullPageScreenshot(page, state);
743
+ }
744
+ }
745
+ };
588
746
 
589
747
  // src/errors.js
590
748
  var errors_exports = {};
@@ -2124,7 +2282,7 @@ var AntiCheat = {
2124
2282
  };
2125
2283
 
2126
2284
  // src/internals/humanize/desktop.js
2127
- var import_delay = __toESM(require("delay"), 1);
2285
+ var import_delay2 = __toESM(require("delay"), 1);
2128
2286
  var import_ghost_cursor_playwright = require("ghost-cursor-playwright");
2129
2287
  var logger6 = createInternalLogger("Humanize");
2130
2288
  var $CursorWeakMap = /* @__PURE__ */ new WeakMap();
@@ -2356,7 +2514,7 @@ var Humanize = {
2356
2514
  }
2357
2515
  await page.mouse.wheel(0, deltaY);
2358
2516
  didScroll = true;
2359
- await (0, import_delay.default)(this.jitterMs(20 + Math.random() * 40, 0.2));
2517
+ await (0, import_delay2.default)(this.jitterMs(20 + Math.random() * 40, 0.2));
2360
2518
  }
2361
2519
  logger6.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
2362
2520
  return { element, didScroll };
@@ -2385,7 +2543,7 @@ var Humanize = {
2385
2543
  restoreOnce.restored = true;
2386
2544
  if (typeof restoreOnce.do !== "function") return;
2387
2545
  try {
2388
- await (0, import_delay.default)(this.jitterMs(1e3));
2546
+ await (0, import_delay2.default)(this.jitterMs(1e3));
2389
2547
  await restoreOnce.do();
2390
2548
  } catch (restoreError) {
2391
2549
  logger6.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
@@ -2393,7 +2551,7 @@ var Humanize = {
2393
2551
  };
2394
2552
  try {
2395
2553
  if (target == null) {
2396
- await (0, import_delay.default)(this.jitterMs(reactionDelay, 0.4));
2554
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.4));
2397
2555
  await cursor.actions.click();
2398
2556
  logger6.success("humanClick", "Clicked current position");
2399
2557
  return true;
@@ -2427,7 +2585,7 @@ var Humanize = {
2427
2585
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.3;
2428
2586
  const y = box.y + box.height / 2 + (Math.random() - 0.5) * box.height * 0.3;
2429
2587
  await cursor.actions.move({ x, y });
2430
- await (0, import_delay.default)(this.jitterMs(reactionDelay, 0.4));
2588
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.4));
2431
2589
  await cursor.actions.click();
2432
2590
  await restoreOnce();
2433
2591
  logger6.success("humanClick");
@@ -2446,7 +2604,7 @@ var Humanize = {
2446
2604
  async randomSleep(baseMs, jitterPercent = 0.3) {
2447
2605
  const ms = this.jitterMs(baseMs, jitterPercent);
2448
2606
  logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
2449
- await (0, import_delay.default)(ms);
2607
+ await (0, import_delay2.default)(ms);
2450
2608
  logger6.success("randomSleep");
2451
2609
  },
2452
2610
  /**
@@ -2464,7 +2622,7 @@ var Humanize = {
2464
2622
  const x = 100 + Math.random() * (viewportSize.width - 200);
2465
2623
  const y = 100 + Math.random() * (viewportSize.height - 200);
2466
2624
  await cursor.actions.move({ x, y });
2467
- await (0, import_delay.default)(this.jitterMs(600, 0.5));
2625
+ await (0, import_delay2.default)(this.jitterMs(600, 0.5));
2468
2626
  }
2469
2627
  logger6.success("simulateGaze");
2470
2628
  },
@@ -2488,7 +2646,7 @@ var Humanize = {
2488
2646
  try {
2489
2647
  const locator = page.locator(selector);
2490
2648
  await Humanize.humanClick(page, locator);
2491
- await (0, import_delay.default)(this.jitterMs(200, 0.4));
2649
+ await (0, import_delay2.default)(this.jitterMs(200, 0.4));
2492
2650
  for (let i = 0; i < text.length; i++) {
2493
2651
  const char = text[i];
2494
2652
  let charDelay;
@@ -2500,11 +2658,11 @@ var Humanize = {
2500
2658
  charDelay = this.jitterMs(baseDelay, 0.4);
2501
2659
  }
2502
2660
  await page.keyboard.type(char);
2503
- await (0, import_delay.default)(charDelay);
2661
+ await (0, import_delay2.default)(charDelay);
2504
2662
  if (Math.random() < pauseProbability && i < text.length - 1) {
2505
2663
  const pauseTime = this.jitterMs(pauseBase, 0.5);
2506
2664
  logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
2507
- await (0, import_delay.default)(pauseTime);
2665
+ await (0, import_delay2.default)(pauseTime);
2508
2666
  }
2509
2667
  }
2510
2668
  logger6.success("humanType");
@@ -2538,7 +2696,7 @@ var Humanize = {
2538
2696
  if (hasTarget) {
2539
2697
  await this.humanClick(page, targetOrKey, { reactionDelay: focusDelay, scrollIfNeeded, throwOnMissing });
2540
2698
  }
2541
- await (0, import_delay.default)(this.jitterMs(reactionDelay, 0.45));
2699
+ await (0, import_delay2.default)(this.jitterMs(reactionDelay, 0.45));
2542
2700
  await page.keyboard.press(key, {
2543
2701
  ...keyboardOptions,
2544
2702
  delay: this.jitterMs(holdDelay, 0.5)
@@ -2560,14 +2718,14 @@ var Humanize = {
2560
2718
  try {
2561
2719
  const locator = page.locator(selector);
2562
2720
  await locator.click();
2563
- await (0, import_delay.default)(this.jitterMs(200, 0.4));
2721
+ await (0, import_delay2.default)(this.jitterMs(200, 0.4));
2564
2722
  const currentValue = await locator.inputValue();
2565
2723
  if (!currentValue || currentValue.length === 0) {
2566
2724
  logger6.success("humanClear", "already empty");
2567
2725
  return;
2568
2726
  }
2569
2727
  await page.keyboard.press("Meta+A");
2570
- await (0, import_delay.default)(this.jitterMs(100, 0.4));
2728
+ await (0, import_delay2.default)(this.jitterMs(100, 0.4));
2571
2729
  await page.keyboard.press("Backspace");
2572
2730
  logger6.success("humanClear");
2573
2731
  } catch (error) {
@@ -2593,13 +2751,13 @@ var Humanize = {
2593
2751
  const x = 100 + Math.random() * (viewportSize.width - 200);
2594
2752
  const y = 100 + Math.random() * (viewportSize.height - 200);
2595
2753
  await cursor.actions.move({ x, y });
2596
- await (0, import_delay.default)(this.jitterMs(350, 0.4));
2754
+ await (0, import_delay2.default)(this.jitterMs(350, 0.4));
2597
2755
  } else if (action < 0.7) {
2598
2756
  const scrollY = (Math.random() - 0.5) * 200;
2599
2757
  await page.mouse.wheel(0, scrollY);
2600
- await (0, import_delay.default)(this.jitterMs(500, 0.4));
2758
+ await (0, import_delay2.default)(this.jitterMs(500, 0.4));
2601
2759
  } else {
2602
- await (0, import_delay.default)(this.jitterMs(800, 0.5));
2760
+ await (0, import_delay2.default)(this.jitterMs(800, 0.5));
2603
2761
  }
2604
2762
  }
2605
2763
  logger6.success("warmUpBrowsing");
@@ -2628,7 +2786,7 @@ var Humanize = {
2628
2786
  const scrollAmount = stepDistance * factor * sign * jitter;
2629
2787
  await page.mouse.wheel(0, scrollAmount);
2630
2788
  const baseDelay = 60 + i * 25;
2631
- await (0, import_delay.default)(this.jitterMs(baseDelay, 0.3));
2789
+ await (0, import_delay2.default)(this.jitterMs(baseDelay, 0.3));
2632
2790
  }
2633
2791
  logger6.success("naturalScroll");
2634
2792
  } catch (error) {
@@ -2774,7 +2932,7 @@ var MachineHumanize = {
2774
2932
  };
2775
2933
 
2776
2934
  // src/internals/humanize/shared.js
2777
- var import_delay2 = __toESM(require("delay"), 1);
2935
+ var import_delay3 = __toESM(require("delay"), 1);
2778
2936
  var jitterMs = (base, jitterPercent = 0.3) => {
2779
2937
  const jitter = Number(base || 0) * Number(jitterPercent || 0) * (Math.random() * 2 - 1);
2780
2938
  return Math.max(10, Math.round(Number(base || 0) + jitter));
@@ -2800,7 +2958,7 @@ var resolveElement = async (page, target, { throwOnMissing = true } = {}) => {
2800
2958
  }
2801
2959
  return element;
2802
2960
  };
2803
- var waitJitter = (base, jitterPercent = 0.3) => (0, import_delay2.default)(jitterMs(base, jitterPercent));
2961
+ var waitJitter = (base, jitterPercent = 0.3) => (0, import_delay3.default)(jitterMs(base, jitterPercent));
2804
2962
 
2805
2963
  // src/internals/humanize/mobile.js
2806
2964
  var logger7 = createInternalLogger("Humanize.Mobile");
@@ -3601,8 +3759,8 @@ var callDelegate = (method, page, args) => {
3601
3759
  return delegate[method](page, ...args);
3602
3760
  };
3603
3761
  var Humanize2 = {
3604
- // M = Machine: native/mechanical operations for compatibility paths.
3605
- // These APIs intentionally do not humanize timing, motion, or intent.
3762
+ // M = Machine: native/mechanical operations for兼容路径。
3763
+ // 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
3606
3764
  M: MachineHumanize,
3607
3765
  jitterMs(base, jitterPercent = 0.3) {
3608
3766
  return Humanize.jitterMs(base, jitterPercent);
@@ -6109,7 +6267,7 @@ var Logger = {
6109
6267
  };
6110
6268
 
6111
6269
  // src/share.js
6112
- var import_delay3 = __toESM(require("delay"), 1);
6270
+ var import_delay4 = __toESM(require("delay"), 1);
6113
6271
 
6114
6272
  // src/internals/watermarkify.js
6115
6273
  var DEFAULT_TIMEZONE_OFFSET = 8;
@@ -6143,6 +6301,15 @@ var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
6143
6301
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
6144
6302
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
6145
6303
  var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
6304
+ var MOBILE_STRIP_HEIGHT = 78;
6305
+ var MOBILE_STRIP_PADDING_X = 14;
6306
+ var MOBILE_STRIP_PADDING_Y = 13;
6307
+ var MOBILE_STRIP_ROW_HEIGHT = 22;
6308
+ var MOBILE_STRIP_ROW_GAP = 8;
6309
+ var MOBILE_STRIP_LABEL_FONT_SIZE = 12.5;
6310
+ var MOBILE_STRIP_VALUE_FONT_SIZE = 13.5;
6311
+ var MOBILE_STRIP_META_GAP = 16;
6312
+ var MOBILE_STRIP_VALUE_WIDTH_SAFETY = 10;
6146
6313
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
6147
6314
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
6148
6315
  /(?:中国)?移动$/i,
@@ -6539,9 +6706,10 @@ var readImageInfo = (buffer) => {
6539
6706
  height: 0
6540
6707
  };
6541
6708
  };
6542
- var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
6709
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height, imageHeight }) => {
6543
6710
  const safeWidth = Math.max(1, Number(width) || 1);
6544
6711
  const safeHeight = Math.max(1, Number(height) || 1);
6712
+ const safeImageHeight = Math.max(1, Number(imageHeight || height) || 1);
6545
6713
  return `
6546
6714
  <!doctype html>
6547
6715
  <html lang="zh-CN">
@@ -6570,10 +6738,11 @@ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
6570
6738
 
6571
6739
  #pk-base-image {
6572
6740
  position: absolute;
6573
- inset: 0;
6741
+ top: 0;
6742
+ left: 0;
6574
6743
  display: block;
6575
6744
  width: ${safeWidth}px;
6576
- height: ${safeHeight}px;
6745
+ height: ${safeImageHeight}px;
6577
6746
  }
6578
6747
 
6579
6748
  #pk-overlay {
@@ -6607,7 +6776,8 @@ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageI
6607
6776
  try {
6608
6777
  const renderPage = renderScope.page;
6609
6778
  const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
6610
- const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
6779
+ const safeImageHeight = Math.max(1, Number(imageInfo.imageHeight || imageInfo.height) || 1);
6780
+ const safeHeight = Math.max(safeImageHeight, Number(imageInfo.height) || safeImageHeight);
6611
6781
  const viewportHeight = Math.max(
6612
6782
  1,
6613
6783
  Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
@@ -6621,7 +6791,8 @@ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageI
6621
6791
  imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
6622
6792
  overlaySvg,
6623
6793
  width: safeWidth,
6624
- height: safeHeight
6794
+ height: safeHeight,
6795
+ imageHeight: safeImageHeight
6625
6796
  }), {
6626
6797
  waitUntil: "load"
6627
6798
  });
@@ -6927,10 +7098,16 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
6927
7098
  }),
6928
7099
  watermark: options.watermark,
6929
7100
  strip: options.strip,
6930
- stripLogoSrc
7101
+ stripLogoSrc,
7102
+ device: resolvePageDevice(page)
6931
7103
  };
6932
7104
  };
6933
7105
  var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
7106
+ var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
7107
+ var findStripSegment = (segments, kind) => {
7108
+ const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
7109
+ return found && typeof found === "object" ? found : {};
7110
+ };
6934
7111
  var buildStripSegmentLayout = (segment, options = {}) => {
6935
7112
  const label = normalizeWhitespace(segment?.label || "");
6936
7113
  const rawValue = normalizeWhitespace(segment?.rawValue || segment?.value || "-") || "-";
@@ -7258,6 +7435,123 @@ var renderStripDivider = (x, centerY, height) => {
7258
7435
  />
7259
7436
  `;
7260
7437
  };
7438
+ var renderMobileStripText = ({
7439
+ label,
7440
+ value,
7441
+ labelX,
7442
+ valueX,
7443
+ y,
7444
+ valueWidth,
7445
+ fontFamily
7446
+ }) => {
7447
+ const safeLabel = normalizeWhitespace(label) || "-";
7448
+ const safeValue = fitTextWithEllipsis(
7449
+ Array.from(normalizeWhitespace(value) || "-"),
7450
+ Math.max(18, valueWidth - MOBILE_STRIP_VALUE_WIDTH_SAFETY),
7451
+ MOBILE_STRIP_VALUE_FONT_SIZE
7452
+ );
7453
+ return `
7454
+ <text
7455
+ x="${labelX}"
7456
+ y="${y}"
7457
+ fill="#111111"
7458
+ fill-opacity="0.54"
7459
+ font-family="${fontFamily}"
7460
+ font-size="${MOBILE_STRIP_LABEL_FONT_SIZE}"
7461
+ font-weight="650"
7462
+ dominant-baseline="middle"
7463
+ >${escapeXml(safeLabel)}</text>
7464
+ <text
7465
+ x="${valueX}"
7466
+ y="${y}"
7467
+ fill="#111111"
7468
+ font-family="${fontFamily}"
7469
+ font-size="${MOBILE_STRIP_VALUE_FONT_SIZE}"
7470
+ font-weight="730"
7471
+ dominant-baseline="middle"
7472
+ >${escapeXml(safeValue)}</text>
7473
+ `;
7474
+ };
7475
+ var renderMobileStrip = ({ meta, width, baseHeight, fontFamily }) => {
7476
+ const stripHeight = MOBILE_STRIP_HEIGHT;
7477
+ const stripY = baseHeight;
7478
+ const contentX = MOBILE_STRIP_PADDING_X;
7479
+ const contentWidth = Math.max(1, width - MOBILE_STRIP_PADDING_X * 2);
7480
+ const prompt = findStripSegment(meta.stripSegments, "prompt");
7481
+ const time = findStripSegment(meta.stripSegments, "time");
7482
+ const location = findStripSegment(meta.stripSegments, "location");
7483
+ const ip = findStripSegment(meta.stripSegments, "ip");
7484
+ const row1Y = stripY + MOBILE_STRIP_PADDING_Y + MOBILE_STRIP_ROW_HEIGHT / 2;
7485
+ const row2Y = row1Y + MOBILE_STRIP_ROW_HEIGHT + MOBILE_STRIP_ROW_GAP;
7486
+ const rightColumnX = Math.min(
7487
+ width - MOBILE_STRIP_PADDING_X - 112,
7488
+ Math.max(
7489
+ contentX + 200,
7490
+ contentX + Math.round(contentWidth * 0.62)
7491
+ )
7492
+ );
7493
+ const leftValueX = contentX + 48;
7494
+ const rightValueX = rightColumnX + 28;
7495
+ const promptValueWidth = Math.max(
7496
+ 28,
7497
+ rightColumnX - leftValueX - MOBILE_STRIP_META_GAP
7498
+ );
7499
+ const timeValueWidth = Math.max(
7500
+ 28,
7501
+ rightColumnX - leftValueX - MOBILE_STRIP_META_GAP
7502
+ );
7503
+ const locValueWidth = Math.max(
7504
+ 28,
7505
+ width - MOBILE_STRIP_PADDING_X - rightValueX
7506
+ );
7507
+ const ipValueWidth = Math.max(
7508
+ 28,
7509
+ width - MOBILE_STRIP_PADDING_X - rightValueX
7510
+ );
7511
+ return `
7512
+ <g id="strip">
7513
+ <rect x="0" y="${stripY}" width="${width}" height="${stripHeight}" fill="#ffffff" fill-opacity="0.985" />
7514
+ <rect x="0" y="${stripY}" width="${width}" height="1" fill="#111111" fill-opacity="0.10" />
7515
+ <rect x="${contentX}" y="${stripY}" width="${Math.max(96, Math.round(width * 0.34))}" height="2" fill="url(#stripAccent)" />
7516
+ ${renderMobileStripText({
7517
+ label: "Prompt",
7518
+ value: prompt.rawValue || prompt.value || "-",
7519
+ labelX: contentX,
7520
+ valueX: leftValueX,
7521
+ y: row1Y,
7522
+ valueWidth: promptValueWidth,
7523
+ fontFamily
7524
+ })}
7525
+ ${renderMobileStripText({
7526
+ label: "Loc",
7527
+ value: location.rawValue || location.value || "-",
7528
+ labelX: rightColumnX,
7529
+ valueX: rightValueX,
7530
+ y: row1Y,
7531
+ valueWidth: locValueWidth,
7532
+ fontFamily
7533
+ })}
7534
+ ${renderMobileStripText({
7535
+ label: "Time",
7536
+ value: time.rawValue || time.value || "-",
7537
+ labelX: contentX,
7538
+ valueX: leftValueX,
7539
+ y: row2Y,
7540
+ valueWidth: timeValueWidth,
7541
+ fontFamily
7542
+ })}
7543
+ ${renderMobileStripText({
7544
+ label: "IP",
7545
+ value: ip.rawValue || ip.value || "-",
7546
+ labelX: rightColumnX,
7547
+ valueX: rightValueX,
7548
+ y: row2Y,
7549
+ valueWidth: ipValueWidth,
7550
+ fontFamily
7551
+ })}
7552
+ </g>
7553
+ `;
7554
+ };
7261
7555
  var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7262
7556
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
7263
7557
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
@@ -7265,7 +7559,8 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7265
7559
  return "";
7266
7560
  }
7267
7561
  const width = Math.max(1, Number(imageWidth) || 1);
7268
- const height = Math.max(1, Number(imageHeight) || 1);
7562
+ const baseHeight = Math.max(1, Number(imageHeight) || 1);
7563
+ const canvasHeight = normalizeDevice(meta.device) === Device.Mobile && hasStrip ? baseHeight + MOBILE_STRIP_HEIGHT : baseHeight;
7269
7564
  const fontFamily = escapeXml(buildFontFamily());
7270
7565
  const parts = [];
7271
7566
  if (hasWatermark) {
@@ -7278,7 +7573,7 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7278
7573
  const startX = -Math.round(cellWidth * 0.16);
7279
7574
  const startY = -Math.round(cellHeight * 0.12);
7280
7575
  const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
7281
- const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
7576
+ const rows = Math.ceil((baseHeight + cellHeight * 0.9) / cellHeight) + 1;
7282
7577
  const stamps = [];
7283
7578
  for (let row = 0; row < rows; row += 1) {
7284
7579
  for (let col = 0; col < cols; col += 1) {
@@ -7306,13 +7601,34 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7306
7601
  parts.push(`<g id="watermarks">${stamps.join("")}</g>`);
7307
7602
  }
7308
7603
  if (hasStrip) {
7604
+ if (normalizeDevice(meta.device) === Device.Mobile) {
7605
+ parts.push(renderMobileStrip({
7606
+ meta,
7607
+ width,
7608
+ baseHeight,
7609
+ fontFamily
7610
+ }));
7611
+ return `
7612
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${canvasHeight}" viewBox="0 0 ${width} ${canvasHeight}">
7613
+ <defs>
7614
+ <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7615
+ <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
7616
+ <stop offset="24%" stop-color="#111111" stop-opacity="0.68" />
7617
+ <stop offset="58%" stop-color="#111111" stop-opacity="0.08" />
7618
+ <stop offset="100%" stop-color="#111111" stop-opacity="0" />
7619
+ </linearGradient>
7620
+ </defs>
7621
+ ${parts.join("")}
7622
+ </svg>
7623
+ `;
7624
+ }
7309
7625
  const logoSize = 28;
7310
7626
  const logoX = DEFAULT_STRIP_PADDING_LEFT;
7311
7627
  const contentStartX = logoX + logoSize + DEFAULT_STRIP_GAP;
7312
7628
  const contentWidth = width - contentStartX - DEFAULT_STRIP_PADDING_RIGHT;
7313
7629
  const stripLayout = buildStripLayout(meta.stripSegments, contentWidth);
7314
7630
  const stripHeight = stripLayout.height;
7315
- const stripY = height - stripHeight;
7631
+ const stripY = baseHeight - stripHeight;
7316
7632
  const logoY = Number((stripY + (stripHeight - logoSize) / 2).toFixed(2));
7317
7633
  let stripContentSvg = "";
7318
7634
  const centerY = stripY + stripHeight / 2 + 1;
@@ -7401,7 +7717,7 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
7401
7717
  `);
7402
7718
  }
7403
7719
  return `
7404
- <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
7720
+ <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${canvasHeight}" viewBox="0 0 ${width} ${canvasHeight}">
7405
7721
  <defs>
7406
7722
  <linearGradient id="stripAccent" x1="0%" y1="0%" x2="100%" y2="0%">
7407
7723
  <stop offset="0%" stop-color="#111111" stop-opacity="0.98" />
@@ -7425,23 +7741,29 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
7425
7741
  logger13.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
7426
7742
  return buffer;
7427
7743
  }
7744
+ const isMobileStrip = normalizeDevice(meta.device) === Device.Mobile && hasStrip;
7745
+ const outputImageInfo = isMobileStrip ? {
7746
+ ...imageInfo,
7747
+ imageHeight: imageInfo.height,
7748
+ height: imageInfo.height + MOBILE_STRIP_HEIGHT
7749
+ } : imageInfo;
7428
7750
  const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
7429
7751
  if (!overlaySvg) {
7430
7752
  return buffer;
7431
7753
  }
7432
- return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
7754
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, outputImageInfo);
7433
7755
  };
7434
7756
 
7435
- // src/internals/screenshot-compression.js
7757
+ // src/internals/compression.js
7436
7758
  var import_jimp = require("jimp");
7437
- var logger14 = createInternalLogger("ScreenshotCompression");
7759
+ var logger14 = createInternalLogger("Compression");
7438
7760
  var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
7439
7761
  var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
7440
7762
  var DEFAULT_SCREENSHOT_QUALITY = 0.72;
7441
7763
  var DEFAULT_SCREENSHOT_MIN_QUALITY = 0.38;
7442
7764
  var DEFAULT_SCREENSHOT_MIN_SCALE = 0.25;
7443
7765
  var SUPPORTED_SCREENSHOT_OUTPUT_TYPES = /* @__PURE__ */ new Set(["jpeg"]);
7444
- var toPositiveInteger = (value, fallback = 0) => {
7766
+ var toPositiveInteger2 = (value, fallback = 0) => {
7445
7767
  const number = Math.floor(Number(value) || 0);
7446
7768
  return number > 0 ? number : fallback;
7447
7769
  };
@@ -7463,7 +7785,7 @@ var normalizeScreenshotOutputType = (value) => {
7463
7785
  };
7464
7786
  var getBase64BytesFromBuffer = (buffer) => Math.ceil(buffer.length / 3) * 4;
7465
7787
  var toJpegQuality = (value) => Math.round(normalizeQuality2(value, DEFAULT_SCREENSHOT_QUALITY) * 100);
7466
- var resolveCaptureScreenCompression = (options = {}) => {
7788
+ var resolveImageCompression = (options = {}) => {
7467
7789
  const explicit = options.compression;
7468
7790
  const source = explicit && typeof explicit === "object" && !Array.isArray(explicit) ? explicit : {};
7469
7791
  const enabled = explicit !== false && source.enabled !== false && options.compress !== false;
@@ -7477,7 +7799,7 @@ var resolveCaptureScreenCompression = (options = {}) => {
7477
7799
  );
7478
7800
  return {
7479
7801
  enabled,
7480
- maxBytes: toPositiveInteger(
7802
+ maxBytes: toPositiveInteger2(
7481
7803
  source.maxBytes ?? source.maxBase64Bytes ?? options.maxBytes ?? options.maxBase64Bytes,
7482
7804
  DEFAULT_SCREENSHOT_MAX_BYTES
7483
7805
  ),
@@ -7514,7 +7836,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
7514
7836
  format: compression.outputType
7515
7837
  };
7516
7838
  };
7517
- var compressScreenshotBuffer = async (buffer, compression) => {
7839
+ var compressImageBuffer = async (buffer, compression) => {
7518
7840
  const sourceImage = await import_jimp.Jimp.read(buffer);
7519
7841
  const maxQuality = toJpegQuality(compression.quality);
7520
7842
  const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
@@ -7547,12 +7869,12 @@ var compressScreenshotBuffer = async (buffer, compression) => {
7547
7869
  const fallback = !smallest || finalCandidate.bytes < smallest.bytes ? finalCandidate : smallest;
7548
7870
  return { ...fallback, withinLimit: fallback.bytes <= compression.maxBytes };
7549
7871
  };
7550
- var compressScreenshotBufferToBase64 = async (buffer, compression) => {
7872
+ var compressImageBufferToBase64 = async (buffer, compression) => {
7551
7873
  const originalBytes = getBase64BytesFromBuffer(buffer);
7552
7874
  if (!compression.enabled || originalBytes <= compression.maxBytes) {
7553
7875
  return buffer.toString("base64");
7554
7876
  }
7555
- const result = await compressScreenshotBuffer(buffer, compression).catch((error) => {
7877
+ const result = await compressImageBuffer(buffer, compression).catch((error) => {
7556
7878
  logger14.warning(`captureScreen \u538B\u7F29\u5931\u8D25\uFF0C\u8FD4\u56DE\u539F\u56FE: ${error instanceof Error ? error.message : String(error)}`);
7557
7879
  return null;
7558
7880
  });
@@ -7951,7 +8273,7 @@ var Share = {
7951
8273
  );
7952
8274
  nextProgressLogTs = now + 5e3;
7953
8275
  }
7954
- await (0, import_delay3.default)(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
8276
+ await (0, import_delay4.default)(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
7955
8277
  }
7956
8278
  if (share.mode === "response" && stats.responseMatched === 0) {
7957
8279
  logger15.warning(
@@ -7989,71 +8311,27 @@ var Share = {
7989
8311
  * @returns {Promise<string>} base64 image
7990
8312
  */
7991
8313
  async captureScreen(page, options = {}) {
7992
- const originalViewport = await resolveCurrentViewportSize(page);
7993
- const defaultBuffer = Math.round((originalViewport.height || 1080) / 2);
7994
- const buffer = options.buffer ?? defaultBuffer;
7995
8314
  const restore = options.restore ?? false;
7996
- const maxHeight = options.maxHeight ?? 8e3;
7997
8315
  const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
7998
- const compression = resolveCaptureScreenCompression(options);
7999
- try {
8000
- const maxScrollHeight = await page.evaluate(() => {
8001
- let maxHeight2 = document.body.scrollHeight;
8002
- document.querySelectorAll("*").forEach((el) => {
8003
- const style = window.getComputedStyle(el);
8004
- const overflowY = style.overflowY;
8005
- if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
8006
- if (el.scrollHeight > maxHeight2) {
8007
- maxHeight2 = el.scrollHeight;
8008
- }
8009
- el.dataset.pkOrigOverflow = el.style.overflow;
8010
- el.dataset.pkOrigHeight = el.style.height;
8011
- el.dataset.pkOrigMaxHeight = el.style.maxHeight;
8012
- el.classList.add("__pk_expanded__");
8013
- el.style.overflow = "visible";
8014
- el.style.height = "auto";
8015
- el.style.maxHeight = "none";
8016
- }
8017
- });
8018
- return maxHeight2;
8019
- });
8020
- const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
8021
- await page.setViewportSize({
8022
- width: originalViewport.width,
8023
- height: targetHeight
8024
- });
8025
- await (0, import_delay3.default)(1e3);
8026
- const capturedAt = /* @__PURE__ */ new Date();
8027
- const rawBuffer = await capturePageScreenshot(page, {
8028
- fullPage: true,
8029
- type: "png",
8030
- maxClipHeight: targetHeight
8316
+ const compression = resolveImageCompression(options);
8317
+ const captureOptions = {
8318
+ buffer: options.buffer ?? 0,
8319
+ restore,
8320
+ maxHeight: options.maxHeight,
8321
+ type: "png",
8322
+ visibleOnly: true
8323
+ };
8324
+ const capturedAt = /* @__PURE__ */ new Date();
8325
+ const rawBuffer = await captureExpandedFullPageScreenshot(page, captureOptions);
8326
+ let outputBuffer = rawBuffer;
8327
+ if (screenshotWatermarkify.enabled) {
8328
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8329
+ ...screenshotWatermarkify,
8330
+ capturedAt
8031
8331
  });
8032
- let outputBuffer = rawBuffer;
8033
- if (screenshotWatermarkify.enabled) {
8034
- const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, {
8035
- ...screenshotWatermarkify,
8036
- capturedAt
8037
- });
8038
- outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
8039
- }
8040
- return await compressScreenshotBufferToBase64(outputBuffer, compression);
8041
- } finally {
8042
- if (restore) {
8043
- await page.evaluate(() => {
8044
- document.querySelectorAll(".__pk_expanded__").forEach((el) => {
8045
- el.style.overflow = el.dataset.pkOrigOverflow || "";
8046
- el.style.height = el.dataset.pkOrigHeight || "";
8047
- el.style.maxHeight = el.dataset.pkOrigMaxHeight || "";
8048
- delete el.dataset.pkOrigOverflow;
8049
- delete el.dataset.pkOrigHeight;
8050
- delete el.dataset.pkOrigMaxHeight;
8051
- el.classList.remove("__pk_expanded__");
8052
- });
8053
- });
8054
- await page.setViewportSize(originalViewport);
8055
- }
8332
+ outputBuffer = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
8056
8333
  }
8334
+ return await compressImageBufferToBase64(outputBuffer, compression);
8057
8335
  }
8058
8336
  };
8059
8337