@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/README.md CHANGED
@@ -223,7 +223,7 @@ const image3 = await Share.captureScreen(page, {
223
223
  watermarkify: {
224
224
  query: '你好',
225
225
  timezoneOffsetHours: 8,
226
- // 默认会在同一浏览器上下文里访问 http://myip.ipip.net 补充 IP / Loc,超时默认 10000ms
226
+ // 默认会在同一浏览器上下文里访问 https://myip.ipip.net/json 补充 IP / Loc,超时默认 10000ms
227
227
  },
228
228
  });
229
229
 
package/dist/index.cjs CHANGED
@@ -350,18 +350,18 @@ var fallbackLog = {
350
350
  error: (...args) => console.error(...args),
351
351
  debug: (...args) => console.debug ? console.debug(...args) : console.log(...args)
352
352
  };
353
- var resolveLogMethod = (logger12, name) => {
354
- if (logger12 && typeof logger12[name] === "function") {
355
- return logger12[name].bind(logger12);
353
+ var resolveLogMethod = (logger13, name) => {
354
+ if (logger13 && typeof logger13[name] === "function") {
355
+ return logger13[name].bind(logger13);
356
356
  }
357
- if (name === "warning" && logger12 && typeof logger12.warn === "function") {
358
- return logger12.warn.bind(logger12);
357
+ if (name === "warning" && logger13 && typeof logger13.warn === "function") {
358
+ return logger13.warn.bind(logger13);
359
359
  }
360
360
  return fallbackLog[name];
361
361
  };
362
362
  var defaultLogger = null;
363
- var setDefaultLogger = (logger12) => {
364
- defaultLogger = logger12;
363
+ var setDefaultLogger = (logger13) => {
364
+ defaultLogger = logger13;
365
365
  };
366
366
  var resolveLogger = (explicitLogger) => {
367
367
  if (explicitLogger && typeof explicitLogger.info === "function") {
@@ -388,8 +388,8 @@ var colorize = (text, color) => {
388
388
  var createBaseLogger = (prefix = "", explicitLogger) => {
389
389
  const name = prefix ? String(prefix) : "";
390
390
  const dispatch = (methodName, icon, message, color) => {
391
- const logger12 = resolveLogger(explicitLogger);
392
- const logFn = resolveLogMethod(logger12, methodName);
391
+ const logger13 = resolveLogger(explicitLogger);
392
+ const logFn = resolveLogMethod(logger13, methodName);
393
393
  const timestamp = colorize(`[${formatTimestamp()}]`, ANSI.gray);
394
394
  const line = formatLine(name, icon, message);
395
395
  const coloredLine = colorize(line, color);
@@ -4569,7 +4569,7 @@ var createTemplateLogger = (baseLogger = createBaseLogger()) => {
4569
4569
  };
4570
4570
  var getDefaultBaseLogger = () => createBaseLogger("");
4571
4571
  var Logger = {
4572
- setLogger: (logger12) => setDefaultLogger(logger12),
4572
+ setLogger: (logger13) => setDefaultLogger(logger13),
4573
4573
  info: (message) => getDefaultBaseLogger().info(message),
4574
4574
  success: (message) => getDefaultBaseLogger().success(message),
4575
4575
  warning: (message) => getDefaultBaseLogger().warning(message),
@@ -4577,8 +4577,8 @@ var Logger = {
4577
4577
  error: (message) => getDefaultBaseLogger().error(message),
4578
4578
  debug: (message) => getDefaultBaseLogger().debug(message),
4579
4579
  start: (message) => getDefaultBaseLogger().start(message),
4580
- useTemplate: (logger12) => {
4581
- if (logger12) return createTemplateLogger(createBaseLogger("", logger12));
4580
+ useTemplate: (logger13) => {
4581
+ if (logger13) return createTemplateLogger(createBaseLogger("", logger13));
4582
4582
  return createTemplateLogger();
4583
4583
  }
4584
4584
  };
@@ -4587,7 +4587,6 @@ var Logger = {
4587
4587
  var import_delay2 = __toESM(require("delay"), 1);
4588
4588
 
4589
4589
  // src/internals/watermarkify.js
4590
- var import_sharp = __toESM(require("sharp"), 1);
4591
4590
  var DEFAULT_TIMEZONE_OFFSET = 8;
4592
4591
  var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
4593
4592
  var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
@@ -4596,7 +4595,7 @@ var DEFAULT_WATERMARK_ROTATE_DEG = -16;
4596
4595
  var DEFAULT_WATERMARK_CELL_WIDTH = 860;
4597
4596
  var DEFAULT_WATERMARK_CELL_HEIGHT = 330;
4598
4597
  var DEFAULT_STRIP_LOGO_URL = "https://static.heartbitai.com/geo/icon/favicon.png";
4599
- var DEFAULT_IP_LOOKUP_URL = "http://myip.ipip.net";
4598
+ var DEFAULT_IP_LOOKUP_URL = "https://myip.ipip.net/json";
4600
4599
  var DEFAULT_LOGO_FETCH_TIMEOUT_MS = 2500;
4601
4600
  var DEFAULT_STRIP_ONE_LINE_HEIGHT = 78;
4602
4601
  var DEFAULT_STRIP_WRAPPED_MIN_HEIGHT = 108;
@@ -4618,6 +4617,7 @@ var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
4618
4617
  var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
4619
4618
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
4620
4619
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
4620
+ var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
4621
4621
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
4622
4622
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4623
4623
  /(?:中国)?移动$/i,
@@ -4643,6 +4643,7 @@ var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4643
4643
  ];
4644
4644
  var cachedStripLogoSrcPromise = null;
4645
4645
  var cachedEnrichmentByContext = /* @__PURE__ */ new WeakMap();
4646
+ var logger11 = createInternalLogger("Watermarkify");
4646
4647
  var normalizeText = (value) => String(value || "").trim();
4647
4648
  var toInline = (value, maxLen = 200) => {
4648
4649
  const text = normalizeText(value);
@@ -4710,18 +4711,26 @@ var pickHeaderValue = async (response, names = []) => {
4710
4711
  }
4711
4712
  return "";
4712
4713
  };
4713
- var parseIpIpResponse = (rawText) => {
4714
+ var parseIpIpJsonResponse = (rawText) => {
4714
4715
  const text = normalizeWhitespace(rawText);
4715
- if (!text) return null;
4716
- 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);
4717
- const locationMatch = text.match(/来自于[::]?\s*(.+)$/i);
4718
- const ip = toInline(ipMatch?.[1], 80);
4719
- const rawLocation = toInline(locationMatch?.[1], 120);
4720
- const location = toInline(stripLocationNetworkSuffix(rawLocation), 80) || rawLocation;
4721
- if (!ip && !location) {
4716
+ if (!text || !text.startsWith("{") && !text.startsWith("[")) {
4717
+ return null;
4718
+ }
4719
+ try {
4720
+ const payload = JSON.parse(text);
4721
+ const ip = toInline(payload?.data?.ip || payload?.ip, 80);
4722
+ const locationParts = Array.isArray(payload?.data?.location) ? payload.data.location.map((item) => normalizeWhitespace(item)).filter(Boolean) : [];
4723
+ const location = toInline(
4724
+ stripLocationNetworkSuffix(locationParts.join(" ")),
4725
+ 80
4726
+ );
4727
+ if (!ip && !location) {
4728
+ return null;
4729
+ }
4730
+ return { ip, location };
4731
+ } catch {
4722
4732
  return null;
4723
4733
  }
4724
- return { ip, location };
4725
4734
  };
4726
4735
  var fillEnrichment = (target, source) => {
4727
4736
  if (!target || !source || typeof source !== "object") {
@@ -4871,10 +4880,16 @@ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
4871
4880
  if (!resolved || typeof resolved !== "object") {
4872
4881
  return null;
4873
4882
  }
4874
- return {
4883
+ const enrichment = {
4875
4884
  ip: toInline(resolved.ip, 80),
4876
4885
  location: toInline(resolved.location, 80)
4877
4886
  };
4887
+ if (enrichment.ip || enrichment.location) {
4888
+ logger11.info(`\u81EA\u5B9A\u4E49 resolver \u547D\u4E2D: ip=${enrichment.ip || "-"}, loc=${enrichment.location || "-"}`);
4889
+ } else {
4890
+ logger11.warning("\u81EA\u5B9A\u4E49 resolver \u5DF2\u6267\u884C\uFF0C\u4F46\u672A\u8FD4\u56DE IP/Loc");
4891
+ }
4892
+ return enrichment;
4878
4893
  } finally {
4879
4894
  controller?.abort();
4880
4895
  }
@@ -4925,12 +4940,205 @@ var openProbePage = async (page) => {
4925
4940
  }
4926
4941
  return null;
4927
4942
  };
4943
+ var readPngDimensions = (buffer) => {
4944
+ if (!Buffer.isBuffer(buffer) || buffer.length < 24) {
4945
+ return { width: 0, height: 0 };
4946
+ }
4947
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
4948
+ for (let index = 0; index < pngSignature.length; index += 1) {
4949
+ if (buffer[index] !== pngSignature[index]) {
4950
+ return { width: 0, height: 0 };
4951
+ }
4952
+ }
4953
+ return {
4954
+ width: buffer.readUInt32BE(16),
4955
+ height: buffer.readUInt32BE(20)
4956
+ };
4957
+ };
4958
+ var readJpegDimensions = (buffer) => {
4959
+ if (!Buffer.isBuffer(buffer) || buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
4960
+ return { width: 0, height: 0 };
4961
+ }
4962
+ let offset = 2;
4963
+ while (offset + 9 <= buffer.length) {
4964
+ if (buffer[offset] !== 255) {
4965
+ offset += 1;
4966
+ continue;
4967
+ }
4968
+ const marker = buffer[offset + 1];
4969
+ offset += 2;
4970
+ if (marker === 216 || marker === 217) {
4971
+ continue;
4972
+ }
4973
+ if (marker === 218) {
4974
+ break;
4975
+ }
4976
+ if (offset + 2 > buffer.length) {
4977
+ break;
4978
+ }
4979
+ const segmentLength = buffer.readUInt16BE(offset);
4980
+ if (segmentLength < 2 || offset + segmentLength > buffer.length) {
4981
+ break;
4982
+ }
4983
+ const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
4984
+ if (isStartOfFrame && offset + 7 <= buffer.length) {
4985
+ return {
4986
+ height: buffer.readUInt16BE(offset + 3),
4987
+ width: buffer.readUInt16BE(offset + 5)
4988
+ };
4989
+ }
4990
+ offset += segmentLength;
4991
+ }
4992
+ return { width: 0, height: 0 };
4993
+ };
4994
+ var readImageInfo = (buffer) => {
4995
+ const png = readPngDimensions(buffer);
4996
+ if (png.width && png.height) {
4997
+ return {
4998
+ mimeType: "image/png",
4999
+ width: png.width,
5000
+ height: png.height
5001
+ };
5002
+ }
5003
+ const jpeg = readJpegDimensions(buffer);
5004
+ if (jpeg.width && jpeg.height) {
5005
+ return {
5006
+ mimeType: "image/jpeg",
5007
+ width: jpeg.width,
5008
+ height: jpeg.height
5009
+ };
5010
+ }
5011
+ return {
5012
+ mimeType: "",
5013
+ width: 0,
5014
+ height: 0
5015
+ };
5016
+ };
5017
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
5018
+ const safeWidth = Math.max(1, Number(width) || 1);
5019
+ const safeHeight = Math.max(1, Number(height) || 1);
5020
+ return `
5021
+ <!doctype html>
5022
+ <html lang="zh-CN">
5023
+ <head>
5024
+ <meta charset="utf-8" />
5025
+ <style>
5026
+ html, body {
5027
+ margin: 0;
5028
+ padding: 0;
5029
+ width: ${safeWidth}px;
5030
+ height: ${safeHeight}px;
5031
+ overflow: hidden;
5032
+ background: #ffffff;
5033
+ }
5034
+
5035
+ body {
5036
+ position: relative;
5037
+ }
5038
+
5039
+ #pk-stage {
5040
+ position: relative;
5041
+ width: ${safeWidth}px;
5042
+ height: ${safeHeight}px;
5043
+ overflow: hidden;
5044
+ }
5045
+
5046
+ #pk-base-image {
5047
+ position: absolute;
5048
+ inset: 0;
5049
+ display: block;
5050
+ width: ${safeWidth}px;
5051
+ height: ${safeHeight}px;
5052
+ }
5053
+
5054
+ #pk-overlay {
5055
+ position: absolute;
5056
+ inset: 0;
5057
+ width: ${safeWidth}px;
5058
+ height: ${safeHeight}px;
5059
+ pointer-events: none;
5060
+ }
5061
+ </style>
5062
+ </head>
5063
+ <body>
5064
+ <div id="pk-stage">
5065
+ <img id="pk-base-image" src="${escapeHtmlAttribute(imageSrc)}" alt="" />
5066
+ <div id="pk-overlay">${overlaySvg}</div>
5067
+ </div>
5068
+ </body>
5069
+ </html>
5070
+ `;
5071
+ };
5072
+ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageInfo = {}) => {
5073
+ if (!page || typeof page.context !== "function") {
5074
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u7F3A\u5C11\u53EF\u7528 page");
5075
+ return buffer;
5076
+ }
5077
+ const renderScope = await openProbePage(page);
5078
+ if (!renderScope?.page) {
5079
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA render page");
5080
+ return buffer;
5081
+ }
5082
+ try {
5083
+ const renderPage = renderScope.page;
5084
+ const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
5085
+ const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
5086
+ const viewportHeight = Math.max(
5087
+ 1,
5088
+ Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
5089
+ );
5090
+ await renderPage.setViewportSize({
5091
+ width: safeWidth,
5092
+ height: viewportHeight
5093
+ }).catch(() => {
5094
+ });
5095
+ await renderPage.setContent(buildWatermarkifyRenderHtml({
5096
+ imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
5097
+ overlaySvg,
5098
+ width: safeWidth,
5099
+ height: safeHeight
5100
+ }), {
5101
+ waitUntil: "load"
5102
+ });
5103
+ await renderPage.waitForFunction(() => {
5104
+ const image = document.getElementById("pk-base-image");
5105
+ return image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0 && image.naturalHeight > 0;
5106
+ }, {
5107
+ timeout: 5e3
5108
+ }).catch(() => {
5109
+ });
5110
+ await renderPage.evaluate(async () => {
5111
+ if (document.fonts?.ready) {
5112
+ await document.fonts.ready.catch(() => {
5113
+ });
5114
+ }
5115
+ }).catch(() => {
5116
+ });
5117
+ const composed = await renderPage.screenshot({
5118
+ type: "png",
5119
+ fullPage: true,
5120
+ animations: "disabled"
5121
+ }).catch((error) => {
5122
+ logger11.warning(`watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5123
+ return null;
5124
+ });
5125
+ if (Buffer.isBuffer(composed) && composed.length > 0) {
5126
+ return composed;
5127
+ }
5128
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: \u672A\u5F97\u5230\u6709\u6548\u622A\u56FE\u7ED3\u679C");
5129
+ return buffer;
5130
+ } finally {
5131
+ await renderScope.close().catch(() => {
5132
+ });
5133
+ }
5134
+ };
4928
5135
  var resolveWithIpLookup = async (page, options = {}) => {
4929
5136
  if (!page || typeof page.context !== "function" || options.ipLookup === false) {
4930
5137
  return null;
4931
5138
  }
4932
5139
  const probeScope = await openProbePage(page);
4933
5140
  if (!probeScope?.page) {
5141
+ logger11.warning("ipLookup \u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA probe page");
4934
5142
  return null;
4935
5143
  }
4936
5144
  const timeoutMs = Math.max(
@@ -4939,10 +5147,16 @@ var resolveWithIpLookup = async (page, options = {}) => {
4939
5147
  );
4940
5148
  try {
4941
5149
  const probePage = probeScope.page;
5150
+ logger11.info(`ipLookup \u5C1D\u8BD5: url=${DEFAULT_IP_LOOKUP_URL}, timeoutMs=${timeoutMs}`);
4942
5151
  const response = await probePage.goto(DEFAULT_IP_LOOKUP_URL, {
4943
5152
  waitUntil: "commit",
4944
5153
  timeout: timeoutMs
4945
- }).catch(() => null);
5154
+ }).catch((error) => {
5155
+ logger11.warning(`ipLookup \u8BF7\u6C42\u5931\u8D25: url=${DEFAULT_IP_LOOKUP_URL}, error=${error instanceof Error ? error.message : String(error)}`);
5156
+ return null;
5157
+ });
5158
+ const status = response && typeof response.status === "function" ? response.status() : 0;
5159
+ const contentType = normalizeText(await pickHeaderValue(response, ["content-type"]));
4946
5160
  let rawText = "";
4947
5161
  if (response && typeof response.text === "function") {
4948
5162
  rawText = String(await withTimeout(
@@ -4958,8 +5172,15 @@ var resolveWithIpLookup = async (page, options = {}) => {
4958
5172
  Math.min(timeoutMs, 500)
4959
5173
  ) || "");
4960
5174
  }
4961
- return parseIpIpResponse(rawText);
4962
- } catch {
5175
+ const parsed = parseIpIpJsonResponse(rawText);
5176
+ if (parsed?.ip || parsed?.location) {
5177
+ logger11.info(`ipLookup \u6210\u529F: url=${DEFAULT_IP_LOOKUP_URL}, status=${status || "-"}, contentType=${contentType || "-"}, ip=${parsed.ip || "-"}, loc=${parsed.location || "-"}`);
5178
+ return parsed;
5179
+ }
5180
+ logger11.warning(`ipLookup \u672A\u89E3\u6790\u51FA IP/Loc: url=${DEFAULT_IP_LOOKUP_URL}, status=${status || "-"}, contentType=${contentType || "-"}, preview=${shortenTail(rawText, 120) || "[empty]"}`);
5181
+ return null;
5182
+ } catch (error) {
5183
+ logger11.warning(`ipLookup \u6267\u884C\u5F02\u5E38\uFF0C\u672A\u83B7\u5F97 IP/Loc: ${error instanceof Error ? error.message : String(error)}`);
4963
5184
  return null;
4964
5185
  } finally {
4965
5186
  await probeScope.close().catch(() => {
@@ -4973,7 +5194,11 @@ var resolveEnrichment = async (page, baseMeta, options) => {
4973
5194
  ip: toInline(options.ip, 80),
4974
5195
  location: toInline(options.location, 80)
4975
5196
  };
5197
+ logger11.info(`enrichment \u5F00\u59CB: host=${baseMeta.hostname || "-"}, hasPresetIp=${Boolean(merged.ip)}, hasPresetLoc=${Boolean(merged.location)}, ipLookup=${options.ipLookup !== false}`);
4976
5198
  if (!merged.ip || !merged.location) {
5199
+ if (cached?.ip || cached?.location) {
5200
+ logger11.info(`enrichment \u547D\u4E2D\u4E0A\u4E0B\u6587\u7F13\u5B58: ip=${cached.ip || "-"}, loc=${cached.location || "-"}`);
5201
+ }
4977
5202
  fillEnrichment(merged, cached);
4978
5203
  }
4979
5204
  if (!merged.ip || !merged.location) {
@@ -4996,10 +5221,16 @@ var resolveEnrichment = async (page, baseMeta, options) => {
4996
5221
  "x-geo-country"
4997
5222
  ]), 80);
4998
5223
  if (!merged.location || isWeakLocationValue(merged.location) && headerLocation) {
5224
+ logger11.info(`enrichment \u4F7F\u7528\u54CD\u5E94\u5934\u8865\u5145 Loc: ${headerLocation || "-"}`);
4999
5225
  merged.location = headerLocation || merged.location;
5000
5226
  }
5001
5227
  }
5002
5228
  writeCachedEnrichment(page, merged);
5229
+ if (merged.ip || merged.location) {
5230
+ logger11.info(`enrichment \u5B8C\u6210: ip=${merged.ip || "-"}, loc=${merged.location || "-"}`);
5231
+ } else {
5232
+ logger11.warning("enrichment \u5B8C\u6210: \u672A\u83B7\u5F97 IP/Loc");
5233
+ }
5003
5234
  return merged;
5004
5235
  };
5005
5236
  var buildWatermarkStamp = ({ prompt, captureTime, ip, location }) => {
@@ -5046,6 +5277,7 @@ var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
5046
5277
  ];
5047
5278
  };
5048
5279
  var escapeXml = (value) => String(value || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5280
+ var escapeHtmlAttribute = (value) => String(value || "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5049
5281
  var estimateTextWidth = (value, fontSize = 16) => {
5050
5282
  const text = String(value || "");
5051
5283
  let width = 0;
@@ -5657,28 +5889,26 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
5657
5889
  </svg>
5658
5890
  `;
5659
5891
  };
5660
- var watermarkifyScreenshotBuffer = async (buffer, meta) => {
5892
+ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
5661
5893
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
5662
5894
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
5663
5895
  if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
5664
5896
  return buffer;
5665
5897
  }
5666
- const image = (0, import_sharp.default)(buffer, { failOn: "none" });
5667
- const metadata = await image.metadata().catch(() => null);
5668
- const width = Math.max(1, Number(metadata?.width) || 0);
5669
- const height = Math.max(1, Number(metadata?.height) || 0);
5670
- if (!width || !height) {
5898
+ const imageInfo = readImageInfo(buffer);
5899
+ if (!imageInfo.width || !imageInfo.height || !imageInfo.mimeType) {
5900
+ logger11.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
5671
5901
  return buffer;
5672
5902
  }
5673
- const overlaySvg = buildWatermarkifySvg(meta, width, height);
5903
+ const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
5674
5904
  if (!overlaySvg) {
5675
5905
  return buffer;
5676
5906
  }
5677
- return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
5907
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
5678
5908
  };
5679
5909
 
5680
5910
  // src/share.js
5681
- var logger11 = createInternalLogger("Share");
5911
+ var logger12 = createInternalLogger("Share");
5682
5912
  var DEFAULT_TIMEOUT_MS2 = 50 * 1e3;
5683
5913
  var DEFAULT_PAYLOAD_SNAPSHOT_MAX_LEN = 500;
5684
5914
  var DEFAULT_POLL_INTERVAL_MS = 120;
@@ -5815,7 +6045,7 @@ var createDomShareMonitor = async (page, options = {}) => {
5815
6045
  const onMatch = typeof options.onMatch === "function" ? options.onMatch : null;
5816
6046
  const onTelemetry = typeof options.onTelemetry === "function" ? options.onTelemetry : null;
5817
6047
  let matched = false;
5818
- logger11.info(`DOM \u76D1\u542C\u51C6\u5907\u6302\u8F7D: selectors=${toJsonInline(selectors, 120)}, mode=${mode}`);
6048
+ logger12.info(`DOM \u76D1\u542C\u51C6\u5907\u6302\u8F7D: selectors=${toJsonInline(selectors, 120)}, mode=${mode}`);
5819
6049
  const monitor = await Mutation.useMonitor(page, selectors, {
5820
6050
  mode,
5821
6051
  onMutation: (context = {}) => {
@@ -5833,12 +6063,12 @@ ${text}`;
5833
6063
  });
5834
6064
  }
5835
6065
  if (mutationCount <= 5 || mutationCount % 50 === 0) {
5836
- logger11.info(`DOM \u53D8\u5316\u5DF2\u6355\u83B7: mutationCount=${mutationCount}, mutationNodes=${mutationNodes.length}`);
6066
+ logger12.info(`DOM \u53D8\u5316\u5DF2\u6355\u83B7: mutationCount=${mutationCount}, mutationNodes=${mutationNodes.length}`);
5837
6067
  }
5838
6068
  const [candidate] = Utils.parseLinks(rawDom, { prefix }) || [];
5839
6069
  if (!candidate) return;
5840
6070
  matched = true;
5841
- logger11.success("captureLink.domHit", `DOM \u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: mutationCount=${mutationCount}, link=${candidate}`);
6071
+ logger12.success("captureLink.domHit", `DOM \u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: mutationCount=${mutationCount}, link=${candidate}`);
5842
6072
  if (onMatch) {
5843
6073
  onMatch({
5844
6074
  link: candidate,
@@ -5854,7 +6084,7 @@ ${text}`;
5854
6084
  return {
5855
6085
  stop: async () => {
5856
6086
  const result = await monitor.stop();
5857
- logger11.info(`DOM \u76D1\u542C\u5DF2\u505C\u6B62: totalMutations=${result?.totalMutations || 0}`);
6087
+ logger12.info(`DOM \u76D1\u542C\u5DF2\u505C\u6B62: totalMutations=${result?.totalMutations || 0}`);
5858
6088
  return result;
5859
6089
  }
5860
6090
  };
@@ -5894,8 +6124,8 @@ var Share = {
5894
6124
  if (share.mode === "response" && apiMatchers.length === 0) {
5895
6125
  throw new Error("Share.captureLink requires share.xurl[0] api matcher when mode=response");
5896
6126
  }
5897
- logger11.start("captureLink", `mode=${share.mode}, timeoutMs=${timeoutMs}, prefix=${share.prefix}`);
5898
- logger11.info(`captureLink \u914D\u7F6E: xurl=${toJsonInline(share.xurl)}, domMode=${domMode}, domSelectors=${toJsonInline(domSelectors, 120)}`);
6127
+ logger12.start("captureLink", `mode=${share.mode}, timeoutMs=${timeoutMs}, prefix=${share.prefix}`);
6128
+ logger12.info(`captureLink \u914D\u7F6E: xurl=${toJsonInline(share.xurl)}, domMode=${domMode}, domSelectors=${toJsonInline(domSelectors, 120)}`);
5899
6129
  const stats = {
5900
6130
  actionTimedOut: false,
5901
6131
  domMutationCount: 0,
@@ -5920,7 +6150,7 @@ var Share = {
5920
6150
  link: validated,
5921
6151
  payloadText: String(payloadText || "")
5922
6152
  };
5923
- logger11.info(`\u5019\u9009\u94FE\u63A5\u5DF2\u786E\u8BA4: source=${source}, link=${validated}`);
6153
+ logger12.info(`\u5019\u9009\u94FE\u63A5\u5DF2\u786E\u8BA4: source=${source}, link=${validated}`);
5924
6154
  return true;
5925
6155
  };
5926
6156
  const resolveResponseCandidate = (responseText) => {
@@ -5955,7 +6185,7 @@ var Share = {
5955
6185
  try {
5956
6186
  await monitor.stop();
5957
6187
  } catch (error) {
5958
- logger11.warning(`\u505C\u6B62 DOM \u76D1\u542C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
6188
+ logger12.warning(`\u505C\u6B62 DOM \u76D1\u542C\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5959
6189
  }
5960
6190
  };
5961
6191
  const onResponse = async (response) => {
@@ -5968,29 +6198,29 @@ var Share = {
5968
6198
  stats.responseSampleUrls.push(url);
5969
6199
  }
5970
6200
  if (stats.responseObserved <= 5) {
5971
- logger11.info(`\u63A5\u53E3\u54CD\u5E94\u91C7\u6837(${stats.responseObserved}): ${url}`);
6201
+ logger12.info(`\u63A5\u53E3\u54CD\u5E94\u91C7\u6837(${stats.responseObserved}): ${url}`);
5972
6202
  }
5973
6203
  if (!apiMatchers.some((matcher) => url.includes(matcher))) return;
5974
6204
  stats.responseMatched += 1;
5975
6205
  stats.lastMatchedUrl = url;
5976
- logger11.info(`\u63A5\u53E3\u547D\u4E2D\u5339\u914D(${stats.responseMatched}): ${url}`);
6206
+ logger12.info(`\u63A5\u53E3\u547D\u4E2D\u5339\u914D(${stats.responseMatched}): ${url}`);
5977
6207
  const text = await response.text();
5978
6208
  const hit = resolveResponseCandidate(text);
5979
6209
  if (!hit?.link) {
5980
6210
  if (stats.responseMatched <= 3) {
5981
- logger11.info(`\u63A5\u53E3\u89E3\u6790\u5B8C\u6210\u4F46\u672A\u63D0\u53D6\u5230\u5206\u4EAB\u94FE\u63A5: payloadSize=${text.length}`);
6211
+ logger12.info(`\u63A5\u53E3\u89E3\u6790\u5B8C\u6210\u4F46\u672A\u63D0\u53D6\u5230\u5206\u4EAB\u94FE\u63A5: payloadSize=${text.length}`);
5982
6212
  }
5983
6213
  return;
5984
6214
  }
5985
6215
  stats.responseResolved += 1;
5986
- logger11.success("captureLink.responseHit", `\u63A5\u53E3\u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: url=${url}, link=${hit.link}`);
6216
+ logger12.success("captureLink.responseHit", `\u63A5\u53E3\u547D\u4E2D\u5206\u4EAB\u94FE\u63A5: url=${url}, link=${hit.link}`);
5987
6217
  setCandidate("response", hit.link, hit.payloadText);
5988
6218
  } catch (error) {
5989
- logger11.warning(`\u63A5\u53E3\u54CD\u5E94\u5904\u7406\u5F02\u5E38: ${error instanceof Error ? error.message : String(error)}`);
6219
+ logger12.warning(`\u63A5\u53E3\u54CD\u5E94\u5904\u7406\u5F02\u5E38: ${error instanceof Error ? error.message : String(error)}`);
5990
6220
  }
5991
6221
  };
5992
6222
  if (share.mode === "dom") {
5993
- logger11.info("\u5F53\u524D\u4E3A DOM \u6A21\u5F0F\uFF0C\u4EC5\u542F\u7528 DOM \u76D1\u542C");
6223
+ logger12.info("\u5F53\u524D\u4E3A DOM \u6A21\u5F0F\uFF0C\u4EC5\u542F\u7528 DOM \u76D1\u542C");
5994
6224
  domMonitor = await createDomShareMonitor(page, {
5995
6225
  prefix: share.prefix,
5996
6226
  selectors: domSelectors,
@@ -6005,14 +6235,14 @@ var Share = {
6005
6235
  });
6006
6236
  }
6007
6237
  if (share.mode === "response") {
6008
- logger11.info(`\u5F53\u524D\u4E3A\u63A5\u53E3\u6A21\u5F0F\uFF0C\u6302\u8F7D response \u76D1\u542C: apiMatchers=${toJsonInline(apiMatchers, 160)}`);
6238
+ logger12.info(`\u5F53\u524D\u4E3A\u63A5\u53E3\u6A21\u5F0F\uFF0C\u6302\u8F7D response \u76D1\u542C: apiMatchers=${toJsonInline(apiMatchers, 160)}`);
6009
6239
  page.on("response", onResponse);
6010
6240
  }
6011
6241
  const deadline = Date.now() + timeoutMs;
6012
6242
  const getRemainingMs = () => Math.max(0, deadline - Date.now());
6013
6243
  try {
6014
6244
  const actionTimeout = getRemainingMs();
6015
- logger11.start("captureLink.performActions", `\u6267\u884C\u52A8\u4F5C\u9884\u7B97=${actionTimeout}ms`);
6245
+ logger12.start("captureLink.performActions", `\u6267\u884C\u52A8\u4F5C\u9884\u7B97=${actionTimeout}ms`);
6016
6246
  if (actionTimeout > 0) {
6017
6247
  let timer = null;
6018
6248
  let actionError = null;
@@ -6026,21 +6256,21 @@ var Share = {
6026
6256
  const actionResult = await Promise.race([actionPromise, timeoutPromise]);
6027
6257
  if (timer) clearTimeout(timer);
6028
6258
  if (actionResult === "__ACTION_ERROR__") {
6029
- logger11.fail("captureLink.performActions", actionError);
6259
+ logger12.fail("captureLink.performActions", actionError);
6030
6260
  throw actionError;
6031
6261
  }
6032
6262
  if (actionResult === "__ACTION_TIMEOUT__") {
6033
6263
  stats.actionTimedOut = true;
6034
- logger11.warning(`performActions \u5DF2\u8D85\u65F6 (${actionTimeout}ms)\uFF0C\u52A8\u4F5C\u53EF\u80FD\u4ECD\u5728\u5F02\u6B65\u6267\u884C`);
6264
+ logger12.warning(`performActions \u5DF2\u8D85\u65F6 (${actionTimeout}ms)\uFF0C\u52A8\u4F5C\u53EF\u80FD\u4ECD\u5728\u5F02\u6B65\u6267\u884C`);
6035
6265
  } else {
6036
- logger11.success("captureLink.performActions", "\u6267\u884C\u52A8\u4F5C\u5B8C\u6210");
6266
+ logger12.success("captureLink.performActions", "\u6267\u884C\u52A8\u4F5C\u5B8C\u6210");
6037
6267
  }
6038
6268
  }
6039
6269
  let nextProgressLogTs = Date.now() + 3e3;
6040
6270
  while (true) {
6041
6271
  const selected = share.mode === "dom" ? candidates.dom : candidates.response;
6042
6272
  if (selected?.link) {
6043
- logger11.success("captureLink", `\u6355\u83B7\u6210\u529F: source=${share.mode}, link=${selected.link}`);
6273
+ logger12.success("captureLink", `\u6355\u83B7\u6210\u529F: source=${share.mode}, link=${selected.link}`);
6044
6274
  return {
6045
6275
  link: selected.link,
6046
6276
  payloadText: selected.payloadText,
@@ -6052,7 +6282,7 @@ var Share = {
6052
6282
  if (remaining <= 0) break;
6053
6283
  const now = Date.now();
6054
6284
  if (now >= nextProgressLogTs) {
6055
- logger11.info(
6285
+ logger12.info(
6056
6286
  `captureLink \u7B49\u5F85\u4E2D: remaining=${remaining}ms, domMutationCount=${stats.domMutationCount}, responseMatched=${stats.responseMatched}`
6057
6287
  );
6058
6288
  nextProgressLogTs = now + 5e3;
@@ -6060,11 +6290,11 @@ var Share = {
6060
6290
  await (0, import_delay2.default)(Math.max(0, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)));
6061
6291
  }
6062
6292
  if (share.mode === "response" && stats.responseMatched === 0) {
6063
- logger11.warning(
6293
+ logger12.warning(
6064
6294
  `\u63A5\u53E3\u76D1\u542C\u672A\u547D\u4E2D: apiMatchers=${toJsonInline(apiMatchers, 220)}, \u54CD\u5E94\u6837\u672CURLs=${toJsonInline(stats.responseSampleUrls, 420)}`
6065
6295
  );
6066
6296
  }
6067
- logger11.warning(
6297
+ logger12.warning(
6068
6298
  `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"}`
6069
6299
  );
6070
6300
  return {
@@ -6076,7 +6306,7 @@ var Share = {
6076
6306
  } finally {
6077
6307
  if (share.mode === "response") {
6078
6308
  page.off("response", onResponse);
6079
- logger11.info("response \u76D1\u542C\u5DF2\u5378\u8F7D");
6309
+ logger12.info("response \u76D1\u542C\u5DF2\u5378\u8F7D");
6080
6310
  }
6081
6311
  await stopDomMonitor();
6082
6312
  }
@@ -6138,7 +6368,7 @@ var Share = {
6138
6368
  ...screenshotWatermarkify,
6139
6369
  capturedAt
6140
6370
  });
6141
- const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
6371
+ const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
6142
6372
  return buffer_.toString("base64");
6143
6373
  } finally {
6144
6374
  if (restore) {