@skrillex1224/playwright-toolkit 2.1.207 → 2.1.209

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