@skrillex1224/playwright-toolkit 2.1.211 → 2.1.213

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
@@ -323,18 +323,18 @@ var fallbackLog = {
323
323
  error: (...args) => console.error(...args),
324
324
  debug: (...args) => console.debug ? console.debug(...args) : console.log(...args)
325
325
  };
326
- var resolveLogMethod = (logger12, name) => {
327
- if (logger12 && typeof logger12[name] === "function") {
328
- return logger12[name].bind(logger12);
326
+ var resolveLogMethod = (logger13, name) => {
327
+ if (logger13 && typeof logger13[name] === "function") {
328
+ return logger13[name].bind(logger13);
329
329
  }
330
- if (name === "warning" && logger12 && typeof logger12.warn === "function") {
331
- return logger12.warn.bind(logger12);
330
+ if (name === "warning" && logger13 && typeof logger13.warn === "function") {
331
+ return logger13.warn.bind(logger13);
332
332
  }
333
333
  return fallbackLog[name];
334
334
  };
335
335
  var defaultLogger = null;
336
- var setDefaultLogger = (logger12) => {
337
- defaultLogger = logger12;
336
+ var setDefaultLogger = (logger13) => {
337
+ defaultLogger = logger13;
338
338
  };
339
339
  var resolveLogger = (explicitLogger) => {
340
340
  if (explicitLogger && typeof explicitLogger.info === "function") {
@@ -361,8 +361,8 @@ var colorize = (text, color) => {
361
361
  var createBaseLogger = (prefix = "", explicitLogger) => {
362
362
  const name = prefix ? String(prefix) : "";
363
363
  const dispatch = (methodName, icon, message, color) => {
364
- const logger12 = resolveLogger(explicitLogger);
365
- const logFn = resolveLogMethod(logger12, methodName);
364
+ const logger13 = resolveLogger(explicitLogger);
365
+ const logFn = resolveLogMethod(logger13, methodName);
366
366
  const timestamp = colorize(`[${formatTimestamp()}]`, ANSI.gray);
367
367
  const line = formatLine(name, icon, message);
368
368
  const coloredLine = colorize(line, color);
@@ -4541,7 +4541,7 @@ var createTemplateLogger = (baseLogger = createBaseLogger()) => {
4541
4541
  };
4542
4542
  var getDefaultBaseLogger = () => createBaseLogger("");
4543
4543
  var Logger = {
4544
- setLogger: (logger12) => setDefaultLogger(logger12),
4544
+ setLogger: (logger13) => setDefaultLogger(logger13),
4545
4545
  info: (message) => getDefaultBaseLogger().info(message),
4546
4546
  success: (message) => getDefaultBaseLogger().success(message),
4547
4547
  warning: (message) => getDefaultBaseLogger().warning(message),
@@ -4549,8 +4549,8 @@ var Logger = {
4549
4549
  error: (message) => getDefaultBaseLogger().error(message),
4550
4550
  debug: (message) => getDefaultBaseLogger().debug(message),
4551
4551
  start: (message) => getDefaultBaseLogger().start(message),
4552
- useTemplate: (logger12) => {
4553
- if (logger12) return createTemplateLogger(createBaseLogger("", logger12));
4552
+ useTemplate: (logger13) => {
4553
+ if (logger13) return createTemplateLogger(createBaseLogger("", logger13));
4554
4554
  return createTemplateLogger();
4555
4555
  }
4556
4556
  };
@@ -4559,7 +4559,6 @@ var Logger = {
4559
4559
  import delay2 from "delay";
4560
4560
 
4561
4561
  // src/internals/watermarkify.js
4562
- import sharp from "sharp";
4563
4562
  var DEFAULT_TIMEZONE_OFFSET = 8;
4564
4563
  var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
4565
4564
  var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
@@ -4568,7 +4567,7 @@ var DEFAULT_WATERMARK_ROTATE_DEG = -16;
4568
4567
  var DEFAULT_WATERMARK_CELL_WIDTH = 860;
4569
4568
  var DEFAULT_WATERMARK_CELL_HEIGHT = 330;
4570
4569
  var DEFAULT_STRIP_LOGO_URL = "https://static.heartbitai.com/geo/icon/favicon.png";
4571
- var DEFAULT_IP_LOOKUP_URL = "http://myip.ipip.net";
4570
+ var DEFAULT_IP_LOOKUP_URL = "https://myip.ipip.net/json";
4572
4571
  var DEFAULT_LOGO_FETCH_TIMEOUT_MS = 2500;
4573
4572
  var DEFAULT_STRIP_ONE_LINE_HEIGHT = 78;
4574
4573
  var DEFAULT_STRIP_WRAPPED_MIN_HEIGHT = 108;
@@ -4590,6 +4589,7 @@ var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
4590
4589
  var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
4591
4590
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
4592
4591
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
4592
+ var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
4593
4593
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
4594
4594
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4595
4595
  /(?:中国)?移动$/i,
@@ -4615,6 +4615,7 @@ var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4615
4615
  ];
4616
4616
  var cachedStripLogoSrcPromise = null;
4617
4617
  var cachedEnrichmentByContext = /* @__PURE__ */ new WeakMap();
4618
+ var logger11 = createInternalLogger("Watermarkify");
4618
4619
  var normalizeText = (value) => String(value || "").trim();
4619
4620
  var toInline = (value, maxLen = 200) => {
4620
4621
  const text = normalizeText(value);
@@ -4682,18 +4683,26 @@ var pickHeaderValue = async (response, names = []) => {
4682
4683
  }
4683
4684
  return "";
4684
4685
  };
4685
- var parseIpIpResponse = (rawText) => {
4686
+ var parseIpIpJsonResponse = (rawText) => {
4686
4687
  const text = normalizeWhitespace(rawText);
4687
- if (!text) return null;
4688
- const ipMatch = text.match(/当前\s*IP[::]\s*([^\s]+)/i) || text.match(/\b((?:\d{1,3}\.){3}\d{1,3}|(?:[0-9a-f]{0,4}:){2,}[0-9a-f]{0,4})\b/i);
4689
- const locationMatch = text.match(/来自于[::]?\s*(.+)$/i);
4690
- const ip = toInline(ipMatch?.[1], 80);
4691
- const rawLocation = toInline(locationMatch?.[1], 120);
4692
- const location = toInline(stripLocationNetworkSuffix(rawLocation), 80) || rawLocation;
4693
- if (!ip && !location) {
4688
+ if (!text || !text.startsWith("{") && !text.startsWith("[")) {
4689
+ return null;
4690
+ }
4691
+ try {
4692
+ const payload = JSON.parse(text);
4693
+ const ip = toInline(payload?.data?.ip || payload?.ip, 80);
4694
+ const locationParts = Array.isArray(payload?.data?.location) ? payload.data.location.map((item) => normalizeWhitespace(item)).filter(Boolean) : [];
4695
+ const location = toInline(
4696
+ stripLocationNetworkSuffix(locationParts.join(" ")),
4697
+ 80
4698
+ );
4699
+ if (!ip && !location) {
4700
+ return null;
4701
+ }
4702
+ return { ip, location };
4703
+ } catch {
4694
4704
  return null;
4695
4705
  }
4696
- return { ip, location };
4697
4706
  };
4698
4707
  var fillEnrichment = (target, source) => {
4699
4708
  if (!target || !source || typeof source !== "object") {
@@ -4843,10 +4852,16 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
4843
4852
  if (!resolved || typeof resolved !== "object") {
4844
4853
  return null;
4845
4854
  }
4846
- return {
4855
+ const enrichment = {
4847
4856
  ip: toInline(resolved.ip, 80),
4848
4857
  location: toInline(resolved.location, 80)
4849
4858
  };
4859
+ if (enrichment.ip || enrichment.location) {
4860
+ logger11.info(`\u81EA\u5B9A\u4E49 resolver \u547D\u4E2D: ip=${enrichment.ip || "-"}, loc=${enrichment.location || "-"}`);
4861
+ } else {
4862
+ logger11.warning("\u81EA\u5B9A\u4E49 resolver \u5DF2\u6267\u884C\uFF0C\u4F46\u672A\u8FD4\u56DE IP/Loc");
4863
+ }
4864
+ return enrichment;
4850
4865
  } finally {
4851
4866
  controller?.abort();
4852
4867
  }
@@ -4897,12 +4912,205 @@ var openProbePage = async (page) => {
4897
4912
  }
4898
4913
  return null;
4899
4914
  };
4915
+ var readPngDimensions = (buffer) => {
4916
+ if (!Buffer.isBuffer(buffer) || buffer.length < 24) {
4917
+ return { width: 0, height: 0 };
4918
+ }
4919
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
4920
+ for (let index = 0; index < pngSignature.length; index += 1) {
4921
+ if (buffer[index] !== pngSignature[index]) {
4922
+ return { width: 0, height: 0 };
4923
+ }
4924
+ }
4925
+ return {
4926
+ width: buffer.readUInt32BE(16),
4927
+ height: buffer.readUInt32BE(20)
4928
+ };
4929
+ };
4930
+ var readJpegDimensions = (buffer) => {
4931
+ if (!Buffer.isBuffer(buffer) || buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
4932
+ return { width: 0, height: 0 };
4933
+ }
4934
+ let offset = 2;
4935
+ while (offset + 9 <= buffer.length) {
4936
+ if (buffer[offset] !== 255) {
4937
+ offset += 1;
4938
+ continue;
4939
+ }
4940
+ const marker = buffer[offset + 1];
4941
+ offset += 2;
4942
+ if (marker === 216 || marker === 217) {
4943
+ continue;
4944
+ }
4945
+ if (marker === 218) {
4946
+ break;
4947
+ }
4948
+ if (offset + 2 > buffer.length) {
4949
+ break;
4950
+ }
4951
+ const segmentLength = buffer.readUInt16BE(offset);
4952
+ if (segmentLength < 2 || offset + segmentLength > buffer.length) {
4953
+ break;
4954
+ }
4955
+ const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
4956
+ if (isStartOfFrame && offset + 7 <= buffer.length) {
4957
+ return {
4958
+ height: buffer.readUInt16BE(offset + 3),
4959
+ width: buffer.readUInt16BE(offset + 5)
4960
+ };
4961
+ }
4962
+ offset += segmentLength;
4963
+ }
4964
+ return { width: 0, height: 0 };
4965
+ };
4966
+ var readImageInfo = (buffer) => {
4967
+ const png = readPngDimensions(buffer);
4968
+ if (png.width && png.height) {
4969
+ return {
4970
+ mimeType: "image/png",
4971
+ width: png.width,
4972
+ height: png.height
4973
+ };
4974
+ }
4975
+ const jpeg = readJpegDimensions(buffer);
4976
+ if (jpeg.width && jpeg.height) {
4977
+ return {
4978
+ mimeType: "image/jpeg",
4979
+ width: jpeg.width,
4980
+ height: jpeg.height
4981
+ };
4982
+ }
4983
+ return {
4984
+ mimeType: "",
4985
+ width: 0,
4986
+ height: 0
4987
+ };
4988
+ };
4989
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
4990
+ const safeWidth = Math.max(1, Number(width) || 1);
4991
+ const safeHeight = Math.max(1, Number(height) || 1);
4992
+ return `
4993
+ <!doctype html>
4994
+ <html lang="zh-CN">
4995
+ <head>
4996
+ <meta charset="utf-8" />
4997
+ <style>
4998
+ html, body {
4999
+ margin: 0;
5000
+ padding: 0;
5001
+ width: ${safeWidth}px;
5002
+ height: ${safeHeight}px;
5003
+ overflow: hidden;
5004
+ background: #ffffff;
5005
+ }
5006
+
5007
+ body {
5008
+ position: relative;
5009
+ }
5010
+
5011
+ #pk-stage {
5012
+ position: relative;
5013
+ width: ${safeWidth}px;
5014
+ height: ${safeHeight}px;
5015
+ overflow: hidden;
5016
+ }
5017
+
5018
+ #pk-base-image {
5019
+ position: absolute;
5020
+ inset: 0;
5021
+ display: block;
5022
+ width: ${safeWidth}px;
5023
+ height: ${safeHeight}px;
5024
+ }
5025
+
5026
+ #pk-overlay {
5027
+ position: absolute;
5028
+ inset: 0;
5029
+ width: ${safeWidth}px;
5030
+ height: ${safeHeight}px;
5031
+ pointer-events: none;
5032
+ }
5033
+ </style>
5034
+ </head>
5035
+ <body>
5036
+ <div id="pk-stage">
5037
+ <img id="pk-base-image" src="${escapeHtmlAttribute(imageSrc)}" alt="" />
5038
+ <div id="pk-overlay">${overlaySvg}</div>
5039
+ </div>
5040
+ </body>
5041
+ </html>
5042
+ `;
5043
+ };
5044
+ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageInfo = {}) => {
5045
+ if (!page || typeof page.context !== "function") {
5046
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u7F3A\u5C11\u53EF\u7528 page");
5047
+ return buffer;
5048
+ }
5049
+ const renderScope = await openProbePage(page);
5050
+ if (!renderScope?.page) {
5051
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA render page");
5052
+ return buffer;
5053
+ }
5054
+ try {
5055
+ const renderPage = renderScope.page;
5056
+ const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
5057
+ const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
5058
+ const viewportHeight = Math.max(
5059
+ 1,
5060
+ Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
5061
+ );
5062
+ await renderPage.setViewportSize({
5063
+ width: safeWidth,
5064
+ height: viewportHeight
5065
+ }).catch(() => {
5066
+ });
5067
+ await renderPage.setContent(buildWatermarkifyRenderHtml({
5068
+ imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
5069
+ overlaySvg,
5070
+ width: safeWidth,
5071
+ height: safeHeight
5072
+ }), {
5073
+ waitUntil: "load"
5074
+ });
5075
+ await renderPage.waitForFunction(() => {
5076
+ const image = document.getElementById("pk-base-image");
5077
+ return image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0 && image.naturalHeight > 0;
5078
+ }, {
5079
+ timeout: 5e3
5080
+ }).catch(() => {
5081
+ });
5082
+ await renderPage.evaluate(async () => {
5083
+ if (document.fonts?.ready) {
5084
+ await document.fonts.ready.catch(() => {
5085
+ });
5086
+ }
5087
+ }).catch(() => {
5088
+ });
5089
+ const composed = await renderPage.screenshot({
5090
+ type: "png",
5091
+ fullPage: true,
5092
+ animations: "disabled"
5093
+ }).catch((error) => {
5094
+ logger11.warning(`watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5095
+ return null;
5096
+ });
5097
+ if (Buffer.isBuffer(composed) && composed.length > 0) {
5098
+ return composed;
5099
+ }
5100
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: \u672A\u5F97\u5230\u6709\u6548\u622A\u56FE\u7ED3\u679C");
5101
+ return buffer;
5102
+ } finally {
5103
+ await renderScope.close().catch(() => {
5104
+ });
5105
+ }
5106
+ };
4900
5107
  var resolveWithIpLookup = async (page, options = {}) => {
4901
5108
  if (!page || typeof page.context !== "function" || options.ipLookup === false) {
4902
5109
  return null;
4903
5110
  }
4904
5111
  const probeScope = await openProbePage(page);
4905
5112
  if (!probeScope?.page) {
5113
+ logger11.warning("ipLookup \u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA probe page");
4906
5114
  return null;
4907
5115
  }
4908
5116
  const timeoutMs = Math.max(
@@ -4911,10 +5119,16 @@ var resolveWithIpLookup = async (page, options = {}) => {
4911
5119
  );
4912
5120
  try {
4913
5121
  const probePage = probeScope.page;
5122
+ logger11.info(`ipLookup \u5C1D\u8BD5: url=${DEFAULT_IP_LOOKUP_URL}, timeoutMs=${timeoutMs}`);
4914
5123
  const response = await probePage.goto(DEFAULT_IP_LOOKUP_URL, {
4915
5124
  waitUntil: "commit",
4916
5125
  timeout: timeoutMs
4917
- }).catch(() => null);
5126
+ }).catch((error) => {
5127
+ logger11.warning(`ipLookup \u8BF7\u6C42\u5931\u8D25: url=${DEFAULT_IP_LOOKUP_URL}, error=${error instanceof Error ? error.message : String(error)}`);
5128
+ return null;
5129
+ });
5130
+ const status = response && typeof response.status === "function" ? response.status() : 0;
5131
+ const contentType = normalizeText(await pickHeaderValue(response, ["content-type"]));
4918
5132
  let rawText = "";
4919
5133
  if (response && typeof response.text === "function") {
4920
5134
  rawText = String(await withTimeout(
@@ -4930,8 +5144,15 @@ var resolveWithIpLookup = async (page, options = {}) => {
4930
5144
  Math.min(timeoutMs, 500)
4931
5145
  ) || "");
4932
5146
  }
4933
- return parseIpIpResponse(rawText);
4934
- } catch {
5147
+ const parsed = parseIpIpJsonResponse(rawText);
5148
+ if (parsed?.ip || parsed?.location) {
5149
+ logger11.info(`ipLookup \u6210\u529F: url=${DEFAULT_IP_LOOKUP_URL}, status=${status || "-"}, contentType=${contentType || "-"}, ip=${parsed.ip || "-"}, loc=${parsed.location || "-"}`);
5150
+ return parsed;
5151
+ }
5152
+ logger11.warning(`ipLookup \u672A\u89E3\u6790\u51FA IP/Loc: url=${DEFAULT_IP_LOOKUP_URL}, status=${status || "-"}, contentType=${contentType || "-"}, preview=${shortenTail(rawText, 120) || "[empty]"}`);
5153
+ return null;
5154
+ } catch (error) {
5155
+ logger11.warning(`ipLookup \u6267\u884C\u5F02\u5E38\uFF0C\u672A\u83B7\u5F97 IP/Loc: ${error instanceof Error ? error.message : String(error)}`);
4935
5156
  return null;
4936
5157
  } finally {
4937
5158
  await probeScope.close().catch(() => {
@@ -4945,7 +5166,11 @@ var resolveEnrichment = async (page, baseMeta, options) => {
4945
5166
  ip: toInline(options.ip, 80),
4946
5167
  location: toInline(options.location, 80)
4947
5168
  };
5169
+ logger11.info(`enrichment \u5F00\u59CB: host=${baseMeta.hostname || "-"}, hasPresetIp=${Boolean(merged.ip)}, hasPresetLoc=${Boolean(merged.location)}, ipLookup=${options.ipLookup !== false}`);
4948
5170
  if (!merged.ip || !merged.location) {
5171
+ if (cached?.ip || cached?.location) {
5172
+ logger11.info(`enrichment \u547D\u4E2D\u4E0A\u4E0B\u6587\u7F13\u5B58: ip=${cached.ip || "-"}, loc=${cached.location || "-"}`);
5173
+ }
4949
5174
  fillEnrichment(merged, cached);
4950
5175
  }
4951
5176
  if (!merged.ip || !merged.location) {
@@ -4968,10 +5193,16 @@ var resolveEnrichment = async (page, baseMeta, options) => {
4968
5193
  "x-geo-country"
4969
5194
  ]), 80);
4970
5195
  if (!merged.location || isWeakLocationValue(merged.location) && headerLocation) {
5196
+ logger11.info(`enrichment \u4F7F\u7528\u54CD\u5E94\u5934\u8865\u5145 Loc: ${headerLocation || "-"}`);
4971
5197
  merged.location = headerLocation || merged.location;
4972
5198
  }
4973
5199
  }
4974
5200
  writeCachedEnrichment(page, merged);
5201
+ if (merged.ip || merged.location) {
5202
+ logger11.info(`enrichment \u5B8C\u6210: ip=${merged.ip || "-"}, loc=${merged.location || "-"}`);
5203
+ } else {
5204
+ logger11.warning("enrichment \u5B8C\u6210: \u672A\u83B7\u5F97 IP/Loc");
5205
+ }
4975
5206
  return merged;
4976
5207
  };
4977
5208
  var buildWatermarkStamp = ({ prompt, captureTime, ip, location }) => {
@@ -5018,6 +5249,7 @@ var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
5018
5249
  ];
5019
5250
  };
5020
5251
  var escapeXml = (value) => String(value || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5252
+ var escapeHtmlAttribute = (value) => String(value || "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5021
5253
  var estimateTextWidth = (value, fontSize = 16) => {
5022
5254
  const text = String(value || "");
5023
5255
  let width = 0;
@@ -5629,28 +5861,26 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
5629
5861
  </svg>
5630
5862
  `;
5631
5863
  };
5632
- var watermarkifyScreenshotBuffer = async (buffer, meta) => {
5864
+ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
5633
5865
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
5634
5866
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
5635
5867
  if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
5636
5868
  return buffer;
5637
5869
  }
5638
- const image = sharp(buffer, { failOn: "none" });
5639
- const metadata = await image.metadata().catch(() => null);
5640
- const width = Math.max(1, Number(metadata?.width) || 0);
5641
- const height = Math.max(1, Number(metadata?.height) || 0);
5642
- if (!width || !height) {
5870
+ const imageInfo = readImageInfo(buffer);
5871
+ if (!imageInfo.width || !imageInfo.height || !imageInfo.mimeType) {
5872
+ logger11.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
5643
5873
  return buffer;
5644
5874
  }
5645
- const overlaySvg = buildWatermarkifySvg(meta, width, height);
5875
+ const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
5646
5876
  if (!overlaySvg) {
5647
5877
  return buffer;
5648
5878
  }
5649
- return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
5879
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
5650
5880
  };
5651
5881
 
5652
5882
  // src/share.js
5653
- var logger11 = createInternalLogger("Share");
5883
+ var logger12 = createInternalLogger("Share");
5654
5884
  var DEFAULT_TIMEOUT_MS2 = 50 * 1e3;
5655
5885
  var DEFAULT_PAYLOAD_SNAPSHOT_MAX_LEN = 500;
5656
5886
  var DEFAULT_POLL_INTERVAL_MS = 120;
@@ -5787,7 +6017,7 @@ var createDomShareMonitor = async (page, options = {}) => {
5787
6017
  const onMatch = typeof options.onMatch === "function" ? options.onMatch : null;
5788
6018
  const onTelemetry = typeof options.onTelemetry === "function" ? options.onTelemetry : null;
5789
6019
  let matched = false;
5790
- logger11.info(`DOM \u76D1\u542C\u51C6\u5907\u6302\u8F7D: selectors=${toJsonInline(selectors, 120)}, mode=${mode}`);
6020
+ logger12.info(`DOM \u76D1\u542C\u51C6\u5907\u6302\u8F7D: selectors=${toJsonInline(selectors, 120)}, mode=${mode}`);
5791
6021
  const monitor = await Mutation.useMonitor(page, selectors, {
5792
6022
  mode,
5793
6023
  onMutation: (context = {}) => {
@@ -5805,12 +6035,12 @@ ${text}`;
5805
6035
  });
5806
6036
  }
5807
6037
  if (mutationCount <= 5 || mutationCount % 50 === 0) {
5808
- logger11.info(`DOM \u53D8\u5316\u5DF2\u6355\u83B7: mutationCount=${mutationCount}, mutationNodes=${mutationNodes.length}`);
6038
+ logger12.info(`DOM \u53D8\u5316\u5DF2\u6355\u83B7: mutationCount=${mutationCount}, mutationNodes=${mutationNodes.length}`);
5809
6039
  }
5810
6040
  const [candidate] = Utils.parseLinks(rawDom, { prefix }) || [];
5811
6041
  if (!candidate) return;
5812
6042
  matched = true;
5813
- logger11.success("captureLink.domHit", `DOM \u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: mutationCount=${mutationCount}, link=${candidate}`);
6043
+ logger12.success("captureLink.domHit", `DOM \u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: mutationCount=${mutationCount}, link=${candidate}`);
5814
6044
  if (onMatch) {
5815
6045
  onMatch({
5816
6046
  link: candidate,
@@ -5826,7 +6056,7 @@ ${text}`;
5826
6056
  return {
5827
6057
  stop: async () => {
5828
6058
  const result = await monitor.stop();
5829
- logger11.info(`DOM \u76D1\u542C\u5DF2\u505C\u6B62: totalMutations=${result?.totalMutations || 0}`);
6059
+ logger12.info(`DOM \u76D1\u542C\u5DF2\u505C\u6B62: totalMutations=${result?.totalMutations || 0}`);
5830
6060
  return result;
5831
6061
  }
5832
6062
  };
@@ -5866,8 +6096,8 @@ var Share = {
5866
6096
  if (share.mode === "response" && apiMatchers.length === 0) {
5867
6097
  throw new Error("Share.captureLink requires share.xurl[0] api matcher when mode=response");
5868
6098
  }
5869
- logger11.start("captureLink", `mode=${share.mode}, timeoutMs=${timeoutMs}, prefix=${share.prefix}`);
5870
- logger11.info(`captureLink \u914D\u7F6E: xurl=${toJsonInline(share.xurl)}, domMode=${domMode}, domSelectors=${toJsonInline(domSelectors, 120)}`);
6099
+ logger12.start("captureLink", `mode=${share.mode}, timeoutMs=${timeoutMs}, prefix=${share.prefix}`);
6100
+ logger12.info(`captureLink \u914D\u7F6E: xurl=${toJsonInline(share.xurl)}, domMode=${domMode}, domSelectors=${toJsonInline(domSelectors, 120)}`);
5871
6101
  const stats = {
5872
6102
  actionTimedOut: false,
5873
6103
  domMutationCount: 0,
@@ -5892,7 +6122,7 @@ var Share = {
5892
6122
  link: validated,
5893
6123
  payloadText: String(payloadText || "")
5894
6124
  };
5895
- logger11.info(`\u5019\u9009\u94FE\u63A5\u5DF2\u786E\u8BA4: source=${source}, link=${validated}`);
6125
+ logger12.info(`\u5019\u9009\u94FE\u63A5\u5DF2\u786E\u8BA4: source=${source}, link=${validated}`);
5896
6126
  return true;
5897
6127
  };
5898
6128
  const resolveResponseCandidate = (responseText) => {
@@ -5927,7 +6157,7 @@ var Share = {
5927
6157
  try {
5928
6158
  await monitor.stop();
5929
6159
  } catch (error) {
5930
- logger11.warning(`\u505C\u6B62 DOM \u76D1\u542C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
6160
+ logger12.warning(`\u505C\u6B62 DOM \u76D1\u542C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5931
6161
  }
5932
6162
  };
5933
6163
  const onResponse = async (response) => {
@@ -5940,29 +6170,29 @@ var Share = {
5940
6170
  stats.responseSampleUrls.push(url);
5941
6171
  }
5942
6172
  if (stats.responseObserved <= 5) {
5943
- logger11.info(`\u63A5\u53E3\u54CD\u5E94\u91C7\u6837(${stats.responseObserved}): ${url}`);
6173
+ logger12.info(`\u63A5\u53E3\u54CD\u5E94\u91C7\u6837(${stats.responseObserved}): ${url}`);
5944
6174
  }
5945
6175
  if (!apiMatchers.some((matcher) => url.includes(matcher))) return;
5946
6176
  stats.responseMatched += 1;
5947
6177
  stats.lastMatchedUrl = url;
5948
- logger11.info(`\u63A5\u53E3\u547D\u4E2D\u5339\u914D(${stats.responseMatched}): ${url}`);
6178
+ logger12.info(`\u63A5\u53E3\u547D\u4E2D\u5339\u914D(${stats.responseMatched}): ${url}`);
5949
6179
  const text = await response.text();
5950
6180
  const hit = resolveResponseCandidate(text);
5951
6181
  if (!hit?.link) {
5952
6182
  if (stats.responseMatched <= 3) {
5953
- logger11.info(`\u63A5\u53E3\u89E3\u6790\u5B8C\u6210\u4F46\u672A\u63D0\u53D6\u5230\u5206\u4EAB\u94FE\u63A5: payloadSize=${text.length}`);
6183
+ logger12.info(`\u63A5\u53E3\u89E3\u6790\u5B8C\u6210\u4F46\u672A\u63D0\u53D6\u5230\u5206\u4EAB\u94FE\u63A5: payloadSize=${text.length}`);
5954
6184
  }
5955
6185
  return;
5956
6186
  }
5957
6187
  stats.responseResolved += 1;
5958
- logger11.success("captureLink.responseHit", `\u63A5\u53E3\u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: url=${url}, link=${hit.link}`);
6188
+ logger12.success("captureLink.responseHit", `\u63A5\u53E3\u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: url=${url}, link=${hit.link}`);
5959
6189
  setCandidate("response", hit.link, hit.payloadText);
5960
6190
  } catch (error) {
5961
- logger11.warning(`\u63A5\u53E3\u54CD\u5E94\u5904\u7406\u5F02\u5E38: ${error instanceof Error ? error.message : String(error)}`);
6191
+ logger12.warning(`\u63A5\u53E3\u54CD\u5E94\u5904\u7406\u5F02\u5E38: ${error instanceof Error ? error.message : String(error)}`);
5962
6192
  }
5963
6193
  };
5964
6194
  if (share.mode === "dom") {
5965
- logger11.info("\u5F53\u524D\u4E3A DOM \u6A21\u5F0F\uFF0C\u4EC5\u542F\u7528 DOM \u76D1\u542C");
6195
+ logger12.info("\u5F53\u524D\u4E3A DOM \u6A21\u5F0F\uFF0C\u4EC5\u542F\u7528 DOM \u76D1\u542C");
5966
6196
  domMonitor = await createDomShareMonitor(page, {
5967
6197
  prefix: share.prefix,
5968
6198
  selectors: domSelectors,
@@ -5977,14 +6207,14 @@ var Share = {
5977
6207
  });
5978
6208
  }
5979
6209
  if (share.mode === "response") {
5980
- logger11.info(`\u5F53\u524D\u4E3A\u63A5\u53E3\u6A21\u5F0F\uFF0C\u6302\u8F7D response \u76D1\u542C: apiMatchers=${toJsonInline(apiMatchers, 160)}`);
6210
+ logger12.info(`\u5F53\u524D\u4E3A\u63A5\u53E3\u6A21\u5F0F\uFF0C\u6302\u8F7D response \u76D1\u542C: apiMatchers=${toJsonInline(apiMatchers, 160)}`);
5981
6211
  page.on("response", onResponse);
5982
6212
  }
5983
6213
  const deadline = Date.now() + timeoutMs;
5984
6214
  const getRemainingMs = () => Math.max(0, deadline - Date.now());
5985
6215
  try {
5986
6216
  const actionTimeout = getRemainingMs();
5987
- logger11.start("captureLink.performActions", `\u6267\u884C\u52A8\u4F5C\u9884\u7B97=${actionTimeout}ms`);
6217
+ logger12.start("captureLink.performActions", `\u6267\u884C\u52A8\u4F5C\u9884\u7B97=${actionTimeout}ms`);
5988
6218
  if (actionTimeout > 0) {
5989
6219
  let timer = null;
5990
6220
  let actionError = null;
@@ -5998,21 +6228,21 @@ var Share = {
5998
6228
  const actionResult = await Promise.race([actionPromise, timeoutPromise]);
5999
6229
  if (timer) clearTimeout(timer);
6000
6230
  if (actionResult === "__ACTION_ERROR__") {
6001
- logger11.fail("captureLink.performActions", actionError);
6231
+ logger12.fail("captureLink.performActions", actionError);
6002
6232
  throw actionError;
6003
6233
  }
6004
6234
  if (actionResult === "__ACTION_TIMEOUT__") {
6005
6235
  stats.actionTimedOut = true;
6006
- logger11.warning(`performActions \u5DF2\u8D85\u65F6 (${actionTimeout}ms)\uFF0C\u52A8\u4F5C\u53EF\u80FD\u4ECD\u5728\u5F02\u6B65\u6267\u884C`);
6236
+ logger12.warning(`performActions \u5DF2\u8D85\u65F6 (${actionTimeout}ms)\uFF0C\u52A8\u4F5C\u53EF\u80FD\u4ECD\u5728\u5F02\u6B65\u6267\u884C`);
6007
6237
  } else {
6008
- logger11.success("captureLink.performActions", "\u6267\u884C\u52A8\u4F5C\u5B8C\u6210");
6238
+ logger12.success("captureLink.performActions", "\u6267\u884C\u52A8\u4F5C\u5B8C\u6210");
6009
6239
  }
6010
6240
  }
6011
6241
  let nextProgressLogTs = Date.now() + 3e3;
6012
6242
  while (true) {
6013
6243
  const selected = share.mode === "dom" ? candidates.dom : candidates.response;
6014
6244
  if (selected?.link) {
6015
- logger11.success("captureLink", `\u6355\u83B7\u6210\u529F: source=${share.mode}, link=${selected.link}`);
6245
+ logger12.success("captureLink", `\u6355\u83B7\u6210\u529F: source=${share.mode}, link=${selected.link}`);
6016
6246
  return {
6017
6247
  link: selected.link,
6018
6248
  payloadText: selected.payloadText,
@@ -6024,7 +6254,7 @@ var Share = {
6024
6254
  if (remaining <= 0) break;
6025
6255
  const now = Date.now();
6026
6256
  if (now >= nextProgressLogTs) {
6027
- logger11.info(
6257
+ logger12.info(
6028
6258
  `captureLink \u7B49\u5F85\u4E2D: remaining=${remaining}ms, domMutationCount=${stats.domMutationCount}, responseMatched=${stats.responseMatched}`
6029
6259
  );
6030
6260
  nextProgressLogTs = now + 5e3;
@@ -6032,11 +6262,11 @@ var Share = {
6032
6262
  await delay2(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
6033
6263
  }
6034
6264
  if (share.mode === "response" && stats.responseMatched === 0) {
6035
- logger11.warning(
6265
+ logger12.warning(
6036
6266
  `\u63A5\u53E3\u76D1\u542C\u672A\u547D\u4E2D: apiMatchers=${toJsonInline(apiMatchers, 220)}, \u54CD\u5E94\u6837\u672CURLs=${toJsonInline(stats.responseSampleUrls, 420)}`
6037
6267
  );
6038
6268
  }
6039
- logger11.warning(
6269
+ logger12.warning(
6040
6270
  `captureLink \u8D85\u65F6\u672A\u62FF\u5230\u94FE\u63A5: mode=${share.mode}, actionTimedOut=${stats.actionTimedOut}, domMutationCount=${stats.domMutationCount}, responseObserved=${stats.responseObserved}, responseMatched=${stats.responseMatched}, lastMatchedUrl=${stats.lastMatchedUrl || "none"}`
6041
6271
  );
6042
6272
  return {
@@ -6048,7 +6278,7 @@ var Share = {
6048
6278
  } finally {
6049
6279
  if (share.mode === "response") {
6050
6280
  page.off("response", onResponse);
6051
- logger11.info("response \u76D1\u542C\u5DF2\u5378\u8F7D");
6281
+ logger12.info("response \u76D1\u542C\u5DF2\u5378\u8F7D");
6052
6282
  }
6053
6283
  await stopDomMonitor();
6054
6284
  }
@@ -6110,7 +6340,7 @@ var Share = {
6110
6340
  ...screenshotWatermarkify,
6111
6341
  capturedAt
6112
6342
  });
6113
- const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
6343
+ const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
6114
6344
  return buffer_.toString("base64");
6115
6345
  } finally {
6116
6346
  if (restore) {