@skrillex1224/playwright-toolkit 2.1.207 → 2.1.208

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
@@ -319,17 +319,6 @@ var ActorInfo = {
319
319
  "id"
320
320
  ]
321
321
  }
322
- }),
323
- quark: createActorInfo({
324
- key: "quark",
325
- name: "\u5938\u514B",
326
- domain: "ai.quark.cn",
327
- path: "/s",
328
- share: {
329
- mode: "dom",
330
- prefix: "",
331
- xurl: []
332
- }
333
322
  })
334
323
  };
335
324
 
@@ -3285,7 +3274,7 @@ var Mutation = {
3285
3274
  if (text.length <= max) return text;
3286
3275
  return `${text.slice(0, max)}...`;
3287
3276
  };
3288
- const normalizeText = (value) => String(value || "").replace(/\s+/g, " ").trim();
3277
+ const normalizeText2 = (value) => String(value || "").replace(/\s+/g, " ").trim();
3289
3278
  const normalizeHtml = (value) => String(value || "").trim();
3290
3279
  const hashSnapshot = (value) => (0, import_node_crypto.createHash)("sha256").update(String(value || "")).digest("hex");
3291
3280
  const buildState = async () => {
@@ -3350,7 +3339,7 @@ var Mutation = {
3350
3339
  if (frame) {
3351
3340
  try {
3352
3341
  const frameSnapshot = await readFrameSnapshot(frame);
3353
- text = normalizeText(frameSnapshot?.text || "");
3342
+ text = normalizeText2(frameSnapshot?.text || "");
3354
3343
  html = normalizeHtml(frameSnapshot?.html || "");
3355
3344
  frameUrl = String(frameSnapshot?.url || "").trim();
3356
3345
  readyState = String(frameSnapshot?.readyState || "").trim();
@@ -3364,7 +3353,7 @@ var Mutation = {
3364
3353
  } else {
3365
3354
  try {
3366
3355
  const elementSnapshot = await readElementSnapshot(handle);
3367
- text = normalizeText(elementSnapshot?.text || "");
3356
+ text = normalizeText2(elementSnapshot?.text || "");
3368
3357
  html = normalizeHtml(elementSnapshot?.html || "");
3369
3358
  } catch (error) {
3370
3359
  source = "main-unreadable";
@@ -4558,6 +4547,905 @@ var Logger = {
4558
4547
 
4559
4548
  // src/share.js
4560
4549
  var import_delay2 = __toESM(require("delay"), 1);
4550
+
4551
+ // src/internals/watermarkify.js
4552
+ var SCREENSHOT_WATERMARKIFY_HOST_ID = "__pk_screenshot_watermarkify__";
4553
+ var DEFAULT_TIMEZONE_OFFSET = 8;
4554
+ var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
4555
+ var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
4556
+ var DEFAULT_WATERMARK_OPACITY = 0.156;
4557
+ var DEFAULT_WATERMARK_ROTATE_DEG = -16;
4558
+ var DEFAULT_WATERMARK_CELL_WIDTH = 860;
4559
+ var DEFAULT_WATERMARK_CELL_HEIGHT = 330;
4560
+ var DEFAULT_STRIP_LOGO_URL = "https://static.heartbitai.com/geo/icon/favicon.png";
4561
+ var DEFAULT_IP_LOOKUP_URL = "http://myip.ipip.net";
4562
+ var DEFAULT_LOGO_FETCH_TIMEOUT_MS = 2500;
4563
+ var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
4564
+ var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4565
+ /(?:中国)?移动$/i,
4566
+ /(?:中国)?联通$/i,
4567
+ /(?:中国)?电信$/i,
4568
+ /铁通$/i,
4569
+ /教育网$/i,
4570
+ /广电$/i,
4571
+ /鹏博士$/i,
4572
+ /阿里云$/i,
4573
+ /腾讯云$/i,
4574
+ /百度云$/i,
4575
+ /华为云$/i,
4576
+ /cloudflare$/i,
4577
+ /amazon$/i,
4578
+ /aws$/i,
4579
+ /azure$/i,
4580
+ /google$/i,
4581
+ /oracle$/i,
4582
+ /linode$/i,
4583
+ /vultr$/i,
4584
+ /digitalocean$/i
4585
+ ];
4586
+ var cachedStripLogoSrcPromise = null;
4587
+ var normalizeText = (value) => String(value || "").trim();
4588
+ var toInline = (value, maxLen = 200) => {
4589
+ const text = normalizeText(value);
4590
+ if (!text) return "";
4591
+ return text.replace(/\s+/g, " ").trim().slice(0, maxLen);
4592
+ };
4593
+ var shortenTail = (value, maxLen = 80) => {
4594
+ const text = toInline(value, Math.max(maxLen * 2, maxLen + 8));
4595
+ if (!text || text.length <= maxLen) return text;
4596
+ return `${text.slice(0, Math.max(0, maxLen - 1)).trimEnd()}\u2026`;
4597
+ };
4598
+ var shortenMiddle = (value, maxLen = 56, headLen = 32, tailLen = 14) => {
4599
+ const text = toInline(value, Math.max(maxLen * 2, maxLen + headLen + tailLen));
4600
+ if (!text || text.length <= maxLen) return text;
4601
+ const safeHeadLen = Math.max(4, Math.min(headLen, maxLen - 5));
4602
+ const safeTailLen = Math.max(4, Math.min(tailLen, maxLen - safeHeadLen - 1));
4603
+ return `${text.slice(0, safeHeadLen).trimEnd()}\u2026${text.slice(-safeTailLen).trimStart()}`;
4604
+ };
4605
+ var padDatePart = (value) => String(value).padStart(2, "0");
4606
+ var formatUtcOffsetLabel = (offsetHours = DEFAULT_TIMEZONE_OFFSET) => {
4607
+ const sign = offsetHours >= 0 ? "+" : "-";
4608
+ const absolute = Math.abs(offsetHours);
4609
+ const hours = Math.trunc(absolute);
4610
+ const minutes = Math.round((absolute - hours) * 60);
4611
+ if (!minutes) {
4612
+ return `UTC${sign}${hours}`;
4613
+ }
4614
+ return `UTC${sign}${hours}:${padDatePart(minutes)}`;
4615
+ };
4616
+ var formatTimestampForUtcOffset = (date, offsetHours = DEFAULT_TIMEZONE_OFFSET) => {
4617
+ const source = date instanceof Date ? date : new Date(date || Date.now());
4618
+ const shifted = new Date(source.getTime() + offsetHours * 60 * 60 * 1e3);
4619
+ return [
4620
+ `${shifted.getUTCFullYear()}-${padDatePart(shifted.getUTCMonth() + 1)}-${padDatePart(shifted.getUTCDate())}`,
4621
+ `${padDatePart(shifted.getUTCHours())}:${padDatePart(shifted.getUTCMinutes())}:${padDatePart(shifted.getUTCSeconds())}`,
4622
+ formatUtcOffsetLabel(offsetHours)
4623
+ ].join(" ");
4624
+ };
4625
+ var normalizeWhitespace = (value) => String(value || "").replace(/\u00a0/g, " ").replace(/\s+/g, " ").trim();
4626
+ var stripLocationNetworkSuffix = (value) => {
4627
+ const parts = normalizeWhitespace(value).split(" ").filter(Boolean);
4628
+ if (parts.length <= 1) {
4629
+ return normalizeWhitespace(value);
4630
+ }
4631
+ const last = parts[parts.length - 1];
4632
+ if (!LOCATION_NETWORK_SUFFIX_PATTERNS.some((pattern) => pattern.test(last))) {
4633
+ return parts.join(" ");
4634
+ }
4635
+ return parts.slice(0, -1).join(" ").trim();
4636
+ };
4637
+ var isWeakLocationValue = (value) => {
4638
+ const text = normalizeWhitespace(value).toLowerCase();
4639
+ if (!text) return true;
4640
+ if (WEAK_LOCATION_VALUES.has(text)) return true;
4641
+ return /^[a-z]{2,3}$/i.test(text);
4642
+ };
4643
+ var pickHeaderValue = async (response, names = []) => {
4644
+ if (!response || typeof response.headerValue !== "function") return "";
4645
+ for (const name of names) {
4646
+ const value = await response.headerValue(name).catch(() => null);
4647
+ const text = normalizeText(value);
4648
+ if (text) return text;
4649
+ }
4650
+ return "";
4651
+ };
4652
+ var parseIpIpResponse = (rawText) => {
4653
+ const text = normalizeWhitespace(rawText);
4654
+ if (!text) return null;
4655
+ 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);
4656
+ const locationMatch = text.match(/来自于[::]?\s*(.+)$/i);
4657
+ const ip = toInline(ipMatch?.[1], 80);
4658
+ const rawLocation = toInline(locationMatch?.[1], 120);
4659
+ const location = toInline(stripLocationNetworkSuffix(rawLocation), 80) || rawLocation;
4660
+ if (!ip && !location) {
4661
+ return null;
4662
+ }
4663
+ return { ip, location };
4664
+ };
4665
+ var fillEnrichment = (target, source) => {
4666
+ if (!target || !source || typeof source !== "object") {
4667
+ return target;
4668
+ }
4669
+ if (!target.ip && source.ip) {
4670
+ target.ip = toInline(source.ip, 80);
4671
+ }
4672
+ if (!target.location && source.location) {
4673
+ target.location = toInline(source.location, 80);
4674
+ }
4675
+ return target;
4676
+ };
4677
+ var getHostname = (url) => {
4678
+ try {
4679
+ const parsed = new URL(url);
4680
+ return parsed.hostname || parsed.host || "\u672C\u5730\u9875\u9762";
4681
+ } catch {
4682
+ if (/^https?:\/\//i.test(url)) {
4683
+ return url;
4684
+ }
4685
+ return "\u672C\u5730\u9875\u9762";
4686
+ }
4687
+ };
4688
+ var withTimeout = async (promise, timeoutMs) => {
4689
+ const safeTimeoutMs = Math.max(0, Number(timeoutMs) || 0);
4690
+ if (!safeTimeoutMs) {
4691
+ return promise;
4692
+ }
4693
+ let timer = null;
4694
+ try {
4695
+ return await Promise.race([
4696
+ promise,
4697
+ new Promise((resolve) => {
4698
+ timer = setTimeout(() => resolve(null), safeTimeoutMs);
4699
+ })
4700
+ ]);
4701
+ } finally {
4702
+ if (timer) clearTimeout(timer);
4703
+ }
4704
+ };
4705
+ var fetchAsDataUrl = async (url, timeoutMs = DEFAULT_LOGO_FETCH_TIMEOUT_MS) => {
4706
+ if (typeof fetch !== "function") {
4707
+ return "";
4708
+ }
4709
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
4710
+ const safeTimeoutMs = Math.max(300, Number(timeoutMs) || DEFAULT_LOGO_FETCH_TIMEOUT_MS);
4711
+ const timer = controller ? setTimeout(() => controller.abort(), safeTimeoutMs) : null;
4712
+ try {
4713
+ const response = await fetch(url, {
4714
+ redirect: "follow",
4715
+ signal: controller?.signal
4716
+ });
4717
+ if (!response?.ok) {
4718
+ return "";
4719
+ }
4720
+ const contentType = normalizeText(response.headers?.get?.("content-type")) || "image/png";
4721
+ if (!/^image\//i.test(contentType)) {
4722
+ return "";
4723
+ }
4724
+ const buffer = Buffer.from(await response.arrayBuffer());
4725
+ if (!buffer.length) {
4726
+ return "";
4727
+ }
4728
+ return `data:${contentType};base64,${buffer.toString("base64")}`;
4729
+ } catch {
4730
+ return "";
4731
+ } finally {
4732
+ if (timer) clearTimeout(timer);
4733
+ }
4734
+ };
4735
+ var resolveStripLogoSrc = async () => {
4736
+ if (!cachedStripLogoSrcPromise) {
4737
+ cachedStripLogoSrcPromise = (async () => {
4738
+ const dataUrl = await fetchAsDataUrl(DEFAULT_STRIP_LOGO_URL);
4739
+ return dataUrl || DEFAULT_STRIP_LOGO_URL;
4740
+ })();
4741
+ }
4742
+ const resolved = await cachedStripLogoSrcPromise.catch(() => DEFAULT_STRIP_LOGO_URL);
4743
+ return normalizeText(resolved) || DEFAULT_STRIP_LOGO_URL;
4744
+ };
4745
+ var normalizeLayer = (value, defaults) => {
4746
+ if (value === false) {
4747
+ return {
4748
+ ...defaults,
4749
+ enabled: false
4750
+ };
4751
+ }
4752
+ if (value && typeof value === "object") {
4753
+ return {
4754
+ ...defaults,
4755
+ ...value,
4756
+ enabled: value.enabled !== false
4757
+ };
4758
+ }
4759
+ return {
4760
+ ...defaults,
4761
+ enabled: true
4762
+ };
4763
+ };
4764
+ var resolveWithCustomResolver = async (page, baseMeta, options = {}) => {
4765
+ const resolver = typeof options.resolver === "function" ? options.resolver : null;
4766
+ if (!resolver) {
4767
+ return null;
4768
+ }
4769
+ const response = options.response && typeof options.response === "object" ? options.response : null;
4770
+ const serverAddr = response && typeof response.serverAddr === "function" ? await response.serverAddr().catch(() => null) : null;
4771
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
4772
+ try {
4773
+ const resolved = await withTimeout(
4774
+ Promise.resolve(resolver({
4775
+ page,
4776
+ response,
4777
+ url: baseMeta.url,
4778
+ hostname: baseMeta.hostname,
4779
+ title: baseMeta.title,
4780
+ query: baseMeta.query,
4781
+ taskId: baseMeta.taskId,
4782
+ serverAddr,
4783
+ signal: controller?.signal
4784
+ })).catch(() => null),
4785
+ options.resolverTimeoutMs ?? DEFAULT_RESOLVER_TIMEOUT_MS
4786
+ );
4787
+ if (!resolved || typeof resolved !== "object") {
4788
+ return null;
4789
+ }
4790
+ return {
4791
+ ip: toInline(resolved.ip, 80),
4792
+ location: toInline(resolved.location, 80)
4793
+ };
4794
+ } finally {
4795
+ controller?.abort();
4796
+ }
4797
+ };
4798
+ var openProbePage = async (page) => {
4799
+ if (!page || typeof page.context !== "function") {
4800
+ return null;
4801
+ }
4802
+ const context = page.context();
4803
+ if (!context) {
4804
+ return null;
4805
+ }
4806
+ if (typeof context.newPage === "function") {
4807
+ try {
4808
+ const probePage2 = await context.newPage();
4809
+ return {
4810
+ page: probePage2,
4811
+ close: async () => {
4812
+ await probePage2.close().catch(() => {
4813
+ });
4814
+ }
4815
+ };
4816
+ } catch {
4817
+ }
4818
+ }
4819
+ const browser = typeof context.browser === "function" ? context.browser() : null;
4820
+ if (!browser || typeof browser.newContext !== "function") {
4821
+ return null;
4822
+ }
4823
+ const probeContext = await browser.newContext().catch(() => null);
4824
+ if (!probeContext || typeof probeContext.newPage !== "function") {
4825
+ await probeContext?.close?.().catch(() => {
4826
+ });
4827
+ return null;
4828
+ }
4829
+ const probePage = await probeContext.newPage().catch(async () => {
4830
+ await probeContext.close().catch(() => {
4831
+ });
4832
+ return null;
4833
+ });
4834
+ if (!probePage) {
4835
+ return null;
4836
+ }
4837
+ return {
4838
+ page: probePage,
4839
+ close: async () => {
4840
+ await probeContext.close().catch(() => {
4841
+ });
4842
+ }
4843
+ };
4844
+ };
4845
+ var resolveWithIpLookup = async (page, options = {}) => {
4846
+ if (!page || typeof page.context !== "function" || options.ipLookup === false) {
4847
+ return null;
4848
+ }
4849
+ const probeScope = await openProbePage(page);
4850
+ if (!probeScope?.page) {
4851
+ return null;
4852
+ }
4853
+ const timeoutMs = Math.max(
4854
+ 300,
4855
+ Number(options.ipLookupTimeoutMs) || DEFAULT_IP_LOOKUP_TIMEOUT_MS
4856
+ );
4857
+ try {
4858
+ const probePage = probeScope.page;
4859
+ const response = await probePage.goto(DEFAULT_IP_LOOKUP_URL, {
4860
+ waitUntil: "commit",
4861
+ timeout: timeoutMs
4862
+ }).catch(() => null);
4863
+ let rawText = "";
4864
+ if (response && typeof response.text === "function") {
4865
+ rawText = String(await withTimeout(
4866
+ response.text().catch(() => ""),
4867
+ timeoutMs
4868
+ ) || "");
4869
+ }
4870
+ if (!rawText) {
4871
+ rawText = String(await withTimeout(
4872
+ probePage.evaluate(() => {
4873
+ return document.body?.innerText || document.documentElement?.innerText || "";
4874
+ }).catch(() => ""),
4875
+ Math.min(timeoutMs, 500)
4876
+ ) || "");
4877
+ }
4878
+ return parseIpIpResponse(rawText);
4879
+ } catch {
4880
+ return null;
4881
+ } finally {
4882
+ await probeScope.close().catch(() => {
4883
+ });
4884
+ }
4885
+ };
4886
+ var resolveEnrichment = async (page, baseMeta, options) => {
4887
+ const response = options.response && typeof options.response === "object" ? options.response : null;
4888
+ const merged = {
4889
+ ip: toInline(options.ip, 80),
4890
+ location: toInline(options.location, 80)
4891
+ };
4892
+ if (!merged.ip || !merged.location) {
4893
+ fillEnrichment(
4894
+ merged,
4895
+ await resolveWithCustomResolver(page, baseMeta, options)
4896
+ );
4897
+ }
4898
+ if ((!merged.ip || !merged.location) && options.ipLookup !== false) {
4899
+ fillEnrichment(
4900
+ merged,
4901
+ await resolveWithIpLookup(page, options)
4902
+ );
4903
+ }
4904
+ if (!merged.location || isWeakLocationValue(merged.location)) {
4905
+ const headerLocation = toInline(await pickHeaderValue(response, [
4906
+ "cf-ipcountry",
4907
+ "x-vercel-ip-country",
4908
+ "x-country-code",
4909
+ "x-geo-country"
4910
+ ]), 80);
4911
+ if (!merged.location || isWeakLocationValue(merged.location) && headerLocation) {
4912
+ merged.location = headerLocation || merged.location;
4913
+ }
4914
+ }
4915
+ return merged;
4916
+ };
4917
+ var buildWatermarkStamp = ({ taskId, captureTime, ip, location }) => {
4918
+ const parts = [
4919
+ `TaskID ${shortenMiddle(taskId, 56, 24, 16) || "-"}`,
4920
+ `Time ${captureTime}`,
4921
+ `Loc ${shortenTail(location, 20) || "-"}`,
4922
+ `IP ${toInline(ip, 24) || "-"}`
4923
+ ];
4924
+ return parts.join(" | ");
4925
+ };
4926
+ var buildStripSegments = ({ taskId, captureTime, ip, location }) => {
4927
+ return [
4928
+ {
4929
+ kind: "taskId",
4930
+ label: "TaskID",
4931
+ value: toInline(taskId, 240) || "-",
4932
+ rawValue: toInline(taskId, 240) || "-"
4933
+ },
4934
+ {
4935
+ kind: "time",
4936
+ label: "Time",
4937
+ value: captureTime,
4938
+ rawValue: captureTime
4939
+ },
4940
+ {
4941
+ kind: "location",
4942
+ label: "Loc",
4943
+ value: shortenTail(location, 24) || "-",
4944
+ rawValue: toInline(location, 80) || "-"
4945
+ },
4946
+ {
4947
+ kind: "ip",
4948
+ label: "IP",
4949
+ value: toInline(ip, 28) || "-",
4950
+ rawValue: toInline(ip, 80) || "-"
4951
+ }
4952
+ ];
4953
+ };
4954
+ var createBaseWatermarkifyOptions = () => ({
4955
+ enabled: true,
4956
+ timezoneOffsetHours: DEFAULT_TIMEZONE_OFFSET,
4957
+ response: null,
4958
+ ip: "",
4959
+ location: "",
4960
+ query: "",
4961
+ taskId: "",
4962
+ ipLookup: true,
4963
+ ipLookupTimeoutMs: DEFAULT_IP_LOOKUP_TIMEOUT_MS,
4964
+ resolver: null,
4965
+ resolverTimeoutMs: DEFAULT_RESOLVER_TIMEOUT_MS,
4966
+ watermark: normalizeLayer(void 0, {
4967
+ opacity: DEFAULT_WATERMARK_OPACITY,
4968
+ rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
4969
+ cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
4970
+ cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT
4971
+ }),
4972
+ strip: normalizeLayer(void 0, {})
4973
+ });
4974
+ var createDisabledWatermarkifyOptions = () => ({
4975
+ ...createBaseWatermarkifyOptions(),
4976
+ enabled: false,
4977
+ watermark: normalizeLayer(false, {
4978
+ opacity: DEFAULT_WATERMARK_OPACITY,
4979
+ rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
4980
+ cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
4981
+ cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT
4982
+ }),
4983
+ strip: normalizeLayer(false, {})
4984
+ });
4985
+ var normalizeScreenshotWatermarkify = (value) => {
4986
+ const base = createBaseWatermarkifyOptions();
4987
+ if (value === false) {
4988
+ return createDisabledWatermarkifyOptions();
4989
+ }
4990
+ if (value == null || value === true) {
4991
+ return base;
4992
+ }
4993
+ const source = value && typeof value === "object" ? value : {};
4994
+ const timezoneOffsetHoursRaw = Number(source.timezoneOffsetHours);
4995
+ const ipLookupTimeoutMsRaw = Number(source.ipLookupTimeoutMs);
4996
+ const resolverTimeoutMsRaw = Number(source.resolverTimeoutMs);
4997
+ return {
4998
+ ...base,
4999
+ enabled: source.enabled !== false,
5000
+ timezoneOffsetHours: Number.isFinite(timezoneOffsetHoursRaw) ? timezoneOffsetHoursRaw : DEFAULT_TIMEZONE_OFFSET,
5001
+ response: source.response ?? null,
5002
+ ip: normalizeText(source.ip),
5003
+ location: normalizeText(source.location),
5004
+ query: toInline(source.query, 140),
5005
+ taskId: toInline(source.taskId, 120),
5006
+ ipLookup: source.ipLookup !== false,
5007
+ ipLookupTimeoutMs: Number.isFinite(ipLookupTimeoutMsRaw) ? ipLookupTimeoutMsRaw : DEFAULT_IP_LOOKUP_TIMEOUT_MS,
5008
+ resolver: typeof source.resolver === "function" ? source.resolver : null,
5009
+ resolverTimeoutMs: Number.isFinite(resolverTimeoutMsRaw) ? resolverTimeoutMsRaw : DEFAULT_RESOLVER_TIMEOUT_MS,
5010
+ watermark: normalizeLayer(source.watermark, {
5011
+ opacity: DEFAULT_WATERMARK_OPACITY,
5012
+ rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
5013
+ cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
5014
+ cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT
5015
+ }),
5016
+ strip: normalizeLayer(source.strip, {})
5017
+ };
5018
+ };
5019
+ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
5020
+ const timezoneOffsetHours = options.timezoneOffsetHours ?? DEFAULT_TIMEZONE_OFFSET;
5021
+ const url = normalizeText(page?.url?.()) || "about:blank";
5022
+ const title = normalizeText(await page.title().catch(() => "")) || "\u672A\u547D\u540D\u9875\u9762";
5023
+ const hostname = getHostname(url);
5024
+ const query = normalizeText(options.query) || title || "\u672A\u63D0\u4F9B Query";
5025
+ const taskId = normalizeText(options.taskId) || "-";
5026
+ const captureTime = formatTimestampForUtcOffset(/* @__PURE__ */ new Date(), timezoneOffsetHours);
5027
+ const [enrichment, stripLogoSrc] = await Promise.all([
5028
+ resolveEnrichment(page, {
5029
+ url,
5030
+ hostname,
5031
+ title,
5032
+ query,
5033
+ taskId
5034
+ }, options),
5035
+ resolveStripLogoSrc()
5036
+ ]);
5037
+ const ip = enrichment.ip || "-";
5038
+ const location = enrichment.location || "-";
5039
+ return {
5040
+ watermarkText: buildWatermarkStamp({
5041
+ taskId,
5042
+ captureTime,
5043
+ ip,
5044
+ location
5045
+ }),
5046
+ stripSegments: buildStripSegments({
5047
+ taskId,
5048
+ captureTime,
5049
+ ip,
5050
+ location
5051
+ }),
5052
+ watermark: options.watermark,
5053
+ strip: options.strip,
5054
+ stripLogoSrc
5055
+ };
5056
+ };
5057
+ var installScreenshotWatermarkify = async (page, meta) => {
5058
+ const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
5059
+ const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
5060
+ if (!page || !meta || !hasWatermark && !hasStrip) {
5061
+ return async () => {
5062
+ };
5063
+ }
5064
+ await page.evaluate(({ hostId, watermarkifyMeta, defaults }) => {
5065
+ const previousHost = document.getElementById(hostId);
5066
+ if (previousHost && typeof previousHost.__pkCleanup === "function") {
5067
+ previousHost.__pkCleanup();
5068
+ }
5069
+ previousHost?.remove();
5070
+ const mountPoint = document.body || document.documentElement;
5071
+ if (!mountPoint) return;
5072
+ const createNode = (tagName, className) => {
5073
+ const node = document.createElement(tagName);
5074
+ if (className) node.className = className;
5075
+ return node;
5076
+ };
5077
+ const safeText = (value) => String(value || "").trim();
5078
+ const host = document.createElement("div");
5079
+ host.id = hostId;
5080
+ host.style.position = "fixed";
5081
+ host.style.inset = "0";
5082
+ host.style.width = "100vw";
5083
+ host.style.height = "100vh";
5084
+ host.style.pointerEvents = "none";
5085
+ host.style.zIndex = "2147483646";
5086
+ const shadow = host.attachShadow({ mode: "open" });
5087
+ const style = document.createElement("style");
5088
+ style.textContent = `
5089
+ :host {
5090
+ all: initial;
5091
+ position: fixed;
5092
+ inset: 0;
5093
+ width: 100vw;
5094
+ height: 100vh;
5095
+ pointer-events: none;
5096
+ z-index: 2147483646;
5097
+ }
5098
+
5099
+ .root {
5100
+ position: absolute;
5101
+ inset: 0;
5102
+ width: 100%;
5103
+ height: 100%;
5104
+ overflow: hidden;
5105
+ pointer-events: none;
5106
+ font-family: MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
5107
+ }
5108
+
5109
+ .watermark {
5110
+ position: absolute;
5111
+ inset: 0;
5112
+ overflow: hidden;
5113
+ pointer-events: none;
5114
+ }
5115
+
5116
+ .wmStamp {
5117
+ position: absolute;
5118
+ left: 0;
5119
+ top: 0;
5120
+ transform-origin: left center;
5121
+ pointer-events: none;
5122
+ white-space: nowrap;
5123
+ }
5124
+
5125
+ .wmStampText {
5126
+ color: rgba(17, 17, 17, var(--wm-opacity, 0.15));
5127
+ font-size: 19px;
5128
+ font-weight: 720;
5129
+ line-height: 1;
5130
+ letter-spacing: 0.032em;
5131
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.44);
5132
+ -webkit-text-stroke: 0.22px rgba(255, 255, 255, 0.12);
5133
+ font-variant-numeric: tabular-nums;
5134
+ filter: saturate(0.92);
5135
+ }
5136
+
5137
+ .strip {
5138
+ position: absolute;
5139
+ left: 0;
5140
+ right: 0;
5141
+ bottom: 0;
5142
+ min-height: 78px;
5143
+ padding: 0 22px 0 20px;
5144
+ display: flex;
5145
+ align-items: center;
5146
+ overflow: hidden;
5147
+ border-top: 1px solid rgba(17, 17, 17, 0.1);
5148
+ background:
5149
+ linear-gradient(180deg, rgba(255, 255, 255, 0.995) 0%, rgba(248, 248, 247, 0.985) 100%);
5150
+ box-shadow:
5151
+ 0 -22px 48px rgba(15, 23, 42, 0.1),
5152
+ inset 0 1px 0 rgba(255, 255, 255, 0.92);
5153
+ backdrop-filter: blur(16px);
5154
+ -webkit-backdrop-filter: blur(16px);
5155
+ }
5156
+
5157
+ .strip::before {
5158
+ content: "";
5159
+ position: absolute;
5160
+ left: 20px;
5161
+ right: 52%;
5162
+ top: 0;
5163
+ height: 2px;
5164
+ border-radius: 999px;
5165
+ background: linear-gradient(
5166
+ 90deg,
5167
+ rgba(17, 17, 17, 0.98) 0%,
5168
+ rgba(17, 17, 17, 0.68) 24%,
5169
+ rgba(17, 17, 17, 0.08) 58%,
5170
+ rgba(17, 17, 17, 0) 100%
5171
+ );
5172
+ }
5173
+
5174
+ .stripInner {
5175
+ position: relative;
5176
+ z-index: 1;
5177
+ display: flex;
5178
+ align-items: center;
5179
+ gap: 16px;
5180
+ width: 100%;
5181
+ min-width: 0;
5182
+ }
5183
+
5184
+ .stripLogo {
5185
+ position: relative;
5186
+ width: 28px;
5187
+ height: 28px;
5188
+ flex: none;
5189
+ display: flex;
5190
+ align-items: center;
5191
+ justify-content: center;
5192
+ }
5193
+
5194
+ .stripLogoImg {
5195
+ width: 28px;
5196
+ height: 28px;
5197
+ object-fit: contain;
5198
+ display: block;
5199
+ }
5200
+
5201
+ .segments {
5202
+ display: flex;
5203
+ align-items: center;
5204
+ gap: 0;
5205
+ flex: 1 1 auto;
5206
+ min-width: 0;
5207
+ white-space: nowrap;
5208
+ }
5209
+
5210
+ .segment {
5211
+ position: relative;
5212
+ display: inline-flex;
5213
+ align-items: center;
5214
+ gap: 10px;
5215
+ min-width: 0;
5216
+ flex: none;
5217
+ padding-right: 16px;
5218
+ margin-right: 16px;
5219
+ }
5220
+
5221
+ .segment:not(:last-child)::after {
5222
+ content: "";
5223
+ position: absolute;
5224
+ top: 50%;
5225
+ right: 0;
5226
+ width: 1px;
5227
+ height: 25px;
5228
+ transform: translateY(-50%);
5229
+ background: linear-gradient(
5230
+ 180deg,
5231
+ rgba(148, 163, 184, 0) 0%,
5232
+ rgba(148, 163, 184, 0.34) 24%,
5233
+ rgba(148, 163, 184, 0.34) 76%,
5234
+ rgba(148, 163, 184, 0) 100%
5235
+ );
5236
+ }
5237
+
5238
+ .segmentTaskId {
5239
+ flex: 1 1 auto;
5240
+ max-width: none;
5241
+ min-width: 0;
5242
+ }
5243
+
5244
+ .label {
5245
+ width: 52px;
5246
+ color: rgba(17, 17, 17, 0.42);
5247
+ font-size: 12px;
5248
+ font-weight: 600;
5249
+ line-height: 1;
5250
+ letter-spacing: 0.01em;
5251
+ flex: none;
5252
+ display: inline-flex;
5253
+ align-items: center;
5254
+ justify-content: flex-start;
5255
+ }
5256
+
5257
+ .value {
5258
+ color: #111111;
5259
+ font-size: 18px;
5260
+ font-weight: 710;
5261
+ line-height: 1;
5262
+ min-width: 0;
5263
+ overflow: hidden;
5264
+ text-overflow: ellipsis;
5265
+ font-variant-numeric: tabular-nums;
5266
+ display: inline-flex;
5267
+ align-items: center;
5268
+ }
5269
+
5270
+ .segmentTaskId .value {
5271
+ color: #101010;
5272
+ font-size: 15px;
5273
+ font-weight: 760;
5274
+ letter-spacing: -0.01em;
5275
+ }
5276
+
5277
+ .segmentTime .value {
5278
+ color: #202020;
5279
+ font-size: 17px;
5280
+ font-weight: 700;
5281
+ }
5282
+
5283
+ .segmentLocation .value,
5284
+ .segmentIp .value {
5285
+ color: #2a2a2a;
5286
+ font-size: 17px;
5287
+ font-weight: 700;
5288
+ }
5289
+
5290
+ `;
5291
+ const root = createNode("div", "root");
5292
+ const watermarkNode = createNode("div", "watermark");
5293
+ const stripNode = createNode("div", "strip");
5294
+ const stripInner = createNode("div", "stripInner");
5295
+ const stripLogo = createNode("div", "stripLogo");
5296
+ const stripLogoImg = createNode("img", "stripLogoImg");
5297
+ const stripSegmentsNode = createNode("div", "segments");
5298
+ stripLogoImg.alt = "";
5299
+ stripLogoImg.decoding = "async";
5300
+ stripLogoImg.referrerPolicy = "no-referrer";
5301
+ stripLogoImg.src = safeText(watermarkifyMeta?.stripLogoSrc) || defaults.logoUrl;
5302
+ stripLogo.appendChild(stripLogoImg);
5303
+ stripInner.appendChild(stripLogo);
5304
+ stripInner.appendChild(stripSegmentsNode);
5305
+ stripNode.appendChild(stripInner);
5306
+ root.appendChild(watermarkNode);
5307
+ root.appendChild(stripNode);
5308
+ shadow.appendChild(style);
5309
+ shadow.appendChild(root);
5310
+ mountPoint.appendChild(host);
5311
+ const buildSegmentNode = (segment) => {
5312
+ const kind = String(segment?.kind || "").trim();
5313
+ const label = String(segment?.label || "").trim();
5314
+ const value = String(segment?.value || "").trim();
5315
+ const rawValue = String(segment?.rawValue || value).trim();
5316
+ const classSuffix = kind ? ` segment${kind.slice(0, 1).toUpperCase()}${kind.slice(1)}` : "";
5317
+ const segmentNode = createNode("span", `segment${classSuffix}`);
5318
+ const labelNode = createNode("span", "label");
5319
+ const valueNode = createNode("span", "value");
5320
+ labelNode.textContent = label;
5321
+ valueNode.textContent = value;
5322
+ segmentNode.title = rawValue ? `${label} ${rawValue}` : label;
5323
+ segmentNode.appendChild(labelNode);
5324
+ segmentNode.appendChild(valueNode);
5325
+ return segmentNode;
5326
+ };
5327
+ const renderStrip = () => {
5328
+ const stripSegments = Array.isArray(watermarkifyMeta?.stripSegments) ? watermarkifyMeta.stripSegments : [];
5329
+ if (!watermarkifyMeta?.strip?.enabled || stripSegments.length === 0) {
5330
+ stripNode.remove();
5331
+ return;
5332
+ }
5333
+ const fragment = document.createDocumentFragment();
5334
+ for (const segment of stripSegments) {
5335
+ fragment.appendChild(buildSegmentNode(segment));
5336
+ }
5337
+ stripSegmentsNode.replaceChildren(fragment);
5338
+ };
5339
+ const waitForLogo = async () => {
5340
+ if (!stripLogoImg.getAttribute("src")) {
5341
+ return;
5342
+ }
5343
+ await new Promise((resolve) => {
5344
+ let settled = false;
5345
+ const done = () => {
5346
+ if (settled) return;
5347
+ settled = true;
5348
+ resolve();
5349
+ };
5350
+ const fail = () => {
5351
+ if (settled) return;
5352
+ stripLogo.remove();
5353
+ done();
5354
+ };
5355
+ const timeoutDone = () => {
5356
+ if (settled) return;
5357
+ done();
5358
+ };
5359
+ if (stripLogoImg.complete && stripLogoImg.naturalWidth > 0) {
5360
+ done();
5361
+ return;
5362
+ }
5363
+ if (stripLogoImg.complete && stripLogoImg.naturalWidth === 0) {
5364
+ fail();
5365
+ return;
5366
+ }
5367
+ stripLogoImg.addEventListener("load", done, { once: true });
5368
+ stripLogoImg.addEventListener("error", fail, { once: true });
5369
+ setTimeout(timeoutDone, 2500);
5370
+ });
5371
+ };
5372
+ const renderWatermark = () => {
5373
+ const stampText = safeText(watermarkifyMeta?.watermarkText);
5374
+ if (!watermarkifyMeta?.watermark?.enabled || !stampText) {
5375
+ watermarkNode.remove();
5376
+ return;
5377
+ }
5378
+ const cellWidth = Math.max(680, Number(watermarkifyMeta.watermark.cellWidth) || defaults.cellWidth);
5379
+ const cellHeight = Math.max(260, Number(watermarkifyMeta.watermark.cellHeight) || defaults.cellHeight);
5380
+ const rotateDeg = Number(watermarkifyMeta.watermark.rotateDeg) || defaults.rotateDeg;
5381
+ const opacity = Math.min(0.22, Math.max(0.05, Number(watermarkifyMeta.watermark.opacity) || defaults.opacity));
5382
+ const width = watermarkNode.clientWidth || window.innerWidth || document.documentElement.clientWidth || cellWidth;
5383
+ const height = watermarkNode.clientHeight || window.innerHeight || document.documentElement.clientHeight || cellHeight;
5384
+ const rowOffset = Math.round(cellWidth * 0.24);
5385
+ const startX = -Math.round(cellWidth * 0.16);
5386
+ const startY = -Math.round(cellHeight * 0.12);
5387
+ const cols = Math.ceil((width + cellWidth * 1.1) / cellWidth) + 1;
5388
+ const rows = Math.ceil((height + cellHeight * 0.9) / cellHeight) + 1;
5389
+ const fragment = document.createDocumentFragment();
5390
+ for (let row = 0; row < rows; row += 1) {
5391
+ for (let col = 0; col < cols; col += 1) {
5392
+ const stamp = createNode("div", "wmStamp");
5393
+ const stampTextNode = createNode("div", "wmStampText");
5394
+ const x = startX + col * cellWidth + (row % 2 ? rowOffset : 0);
5395
+ const y = startY + row * cellHeight + (row % 2 ? 14 : -8);
5396
+ stamp.style.transform = `translate(${x}px, ${y}px) rotate(${rotateDeg}deg)`;
5397
+ stampTextNode.style.setProperty("--wm-opacity", String(opacity));
5398
+ stampTextNode.textContent = stampText;
5399
+ stamp.appendChild(stampTextNode);
5400
+ fragment.appendChild(stamp);
5401
+ }
5402
+ }
5403
+ watermarkNode.replaceChildren(fragment);
5404
+ };
5405
+ let resizeFrame = 0;
5406
+ const queueWatermarkRender = () => {
5407
+ if (!watermarkNode.isConnected) return;
5408
+ cancelAnimationFrame(resizeFrame);
5409
+ resizeFrame = requestAnimationFrame(() => {
5410
+ renderWatermark();
5411
+ });
5412
+ };
5413
+ const handleResize = () => {
5414
+ queueWatermarkRender();
5415
+ };
5416
+ host.__pkCleanup = () => {
5417
+ cancelAnimationFrame(resizeFrame);
5418
+ window.removeEventListener("resize", handleResize);
5419
+ };
5420
+ renderStrip();
5421
+ renderWatermark();
5422
+ queueWatermarkRender();
5423
+ window.addEventListener("resize", handleResize, { passive: true });
5424
+ return waitForLogo();
5425
+ }, {
5426
+ hostId: SCREENSHOT_WATERMARKIFY_HOST_ID,
5427
+ watermarkifyMeta: meta,
5428
+ defaults: {
5429
+ opacity: DEFAULT_WATERMARK_OPACITY,
5430
+ rotateDeg: DEFAULT_WATERMARK_ROTATE_DEG,
5431
+ cellWidth: DEFAULT_WATERMARK_CELL_WIDTH,
5432
+ cellHeight: DEFAULT_WATERMARK_CELL_HEIGHT,
5433
+ logoUrl: DEFAULT_STRIP_LOGO_URL
5434
+ }
5435
+ });
5436
+ return async () => {
5437
+ await page.evaluate((hostId) => {
5438
+ const host = document.getElementById(hostId);
5439
+ if (host && typeof host.__pkCleanup === "function") {
5440
+ host.__pkCleanup();
5441
+ }
5442
+ host?.remove();
5443
+ }, SCREENSHOT_WATERMARKIFY_HOST_ID).catch(() => {
5444
+ });
5445
+ };
5446
+ };
5447
+
5448
+ // src/share.js
4561
5449
  var logger11 = createInternalLogger("Share");
4562
5450
  var DEFAULT_TIMEOUT_MS2 = 50 * 1e3;
4563
5451
  var DEFAULT_PAYLOAD_SNAPSHOT_MAX_LEN = 500;
@@ -4568,14 +5456,14 @@ var toSnapshot = (value, maxLen) => {
4568
5456
  if (!text) return "";
4569
5457
  return text.replace(/\s+/g, " ").trim().slice(0, maxLen);
4570
5458
  };
4571
- var toInline = (value, maxLen = 200) => {
5459
+ var toInline2 = (value, maxLen = 200) => {
4572
5460
  const text = String(value || "");
4573
5461
  if (!text) return "";
4574
5462
  return text.replace(/\s+/g, " ").trim().slice(0, maxLen);
4575
5463
  };
4576
5464
  var toJsonInline = (value, maxLen = 260) => {
4577
5465
  try {
4578
- return toInline(JSON.stringify(value), maxLen);
5466
+ return toInline2(JSON.stringify(value), maxLen);
4579
5467
  } catch {
4580
5468
  return "[\u4E0D\u53EF\u5E8F\u5217\u5316]";
4581
5469
  }
@@ -4963,6 +5851,9 @@ var Share = {
4963
5851
  const buffer = options.buffer ?? defaultBuffer;
4964
5852
  const restore = options.restore ?? false;
4965
5853
  const maxHeight = options.maxHeight ?? 8e3;
5854
+ const screenshotWatermarkify = normalizeScreenshotWatermarkify(options.watermarkify ?? true);
5855
+ let cleanupScreenshotWatermarkify = async () => {
5856
+ };
4966
5857
  try {
4967
5858
  const maxScrollHeight = await page.evaluate(() => {
4968
5859
  let maxHeight2 = document.body.scrollHeight;
@@ -4990,6 +5881,11 @@ var Share = {
4990
5881
  height: targetHeight
4991
5882
  });
4992
5883
  await (0, import_delay2.default)(1e3);
5884
+ if (screenshotWatermarkify.enabled) {
5885
+ const watermarkifyMeta = await resolveScreenshotWatermarkifyMeta(page, screenshotWatermarkify);
5886
+ cleanupScreenshotWatermarkify = await installScreenshotWatermarkify(page, watermarkifyMeta);
5887
+ await (0, import_delay2.default)(120);
5888
+ }
4993
5889
  const buffer_ = await capturePageScreenshot(page, {
4994
5890
  fullPage: true,
4995
5891
  type: "png",
@@ -4997,6 +5893,7 @@ var Share = {
4997
5893
  });
4998
5894
  return buffer_.toString("base64");
4999
5895
  } finally {
5896
+ await cleanupScreenshotWatermarkify();
5000
5897
  if (restore) {
5001
5898
  await page.evaluate(() => {
5002
5899
  document.querySelectorAll(".__pk_expanded__").forEach((el) => {