@skrillex1224/playwright-toolkit 2.1.166 → 2.1.167

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
@@ -93,10 +93,10 @@ var createActorInfo = (info) => {
93
93
  xurl
94
94
  };
95
95
  };
96
- const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path: path2 }) => {
96
+ const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path: path3 }) => {
97
97
  const safeProtocol = String(protocol2).trim();
98
98
  const safeDomain = normalizeDomain(domain2);
99
- const safePath = normalizePath(path2);
99
+ const safePath = normalizePath(path3);
100
100
  return `${safeProtocol}://${safeDomain}${safePath}`;
101
101
  };
102
102
  const buildIcon = ({ key }) => {
@@ -104,13 +104,13 @@ var createActorInfo = (info) => {
104
104
  };
105
105
  const protocol = info.protocol || "https";
106
106
  const domain = normalizeDomain(info.domain);
107
- const path = normalizePath(info.path);
107
+ const path2 = normalizePath(info.path);
108
108
  const share = normalizeShare2(info.share);
109
109
  return {
110
110
  ...info,
111
111
  protocol,
112
112
  domain,
113
- path,
113
+ path: path2,
114
114
  share,
115
115
  get icon() {
116
116
  if (info.icon) return info.icon;
@@ -124,7 +124,7 @@ var createActorInfo = (info) => {
124
124
  var ActorInfo = {
125
125
  qbot: createActorInfo({
126
126
  key: "qbot",
127
- name: "\u641C\u72D7QBot",
127
+ name: "QQ\u6D4F\u89C8\u5668AI\u641C",
128
128
  domain: "sogou.com",
129
129
  path: "/web",
130
130
  share: {
@@ -546,20 +546,306 @@ var CrawlerError = class _CrawlerError extends Error {
546
546
  // src/apify-kit.js
547
547
  import { serializeError as serializeError2 } from "serialize-error";
548
548
 
549
- // src/traffic-runtime.js
550
- var trafficMeter = null;
551
- var setTrafficMeter = (meter) => {
552
- trafficMeter = meter || null;
549
+ // src/proxy-meter-runtime.js
550
+ import { spawn, spawnSync } from "child_process";
551
+ import { existsSync, mkdirSync, readFileSync, rmSync } from "fs";
552
+ import { tmpdir } from "os";
553
+ import path from "path";
554
+ import { fileURLToPath } from "url";
555
+ var logger2 = createInternalLogger("ProxyMeter");
556
+ var MAX_TOP_DOMAINS = 20;
557
+ var FLUSH_INTERVAL_MS = 2e3;
558
+ var DEFAULT_DEBUG_MAX_EVENTS = 400;
559
+ var runtime = null;
560
+ var cleanupInstalled = false;
561
+ var toSafeInt = (value) => {
562
+ const num = Number(value);
563
+ if (!Number.isFinite(num) || num <= 0) return 0;
564
+ return Math.round(num);
553
565
  };
554
- var getTrafficSnapshot = () => {
555
- if (!trafficMeter || typeof trafficMeter.snapshot !== "function") {
566
+ var toSafeFloat = (value) => {
567
+ const num = Number(value);
568
+ if (!Number.isFinite(num)) return 0;
569
+ return num;
570
+ };
571
+ var resolveScriptPath = () => {
572
+ const baseDir = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
573
+ return path.join(baseDir, "proxy-meter.js");
574
+ };
575
+ var pickFreePort = () => {
576
+ const script = [
577
+ 'const net=require("net");',
578
+ "const server=net.createServer();",
579
+ 'server.listen(0,"127.0.0.1",()=>{',
580
+ "const port=server.address().port;",
581
+ "server.close(()=>{console.log(port);});",
582
+ "});"
583
+ ].join("");
584
+ const result = spawnSync(process.execPath, ["-e", script], { encoding: "utf8" });
585
+ const port = Number(String(result.stdout || "").trim());
586
+ if (result.status === 0 && Number.isFinite(port) && port > 0) {
587
+ return port;
588
+ }
589
+ return 2e4 + Math.floor(Math.random() * 2e4);
590
+ };
591
+ var resolveLogDir = () => {
592
+ const storageDir = process.env.APIFY_STORAGE_DIR || process.env.APIFY_LOCAL_STORAGE_DIR || "";
593
+ if (storageDir) {
594
+ return path.join(storageDir, "proxy-meter");
595
+ }
596
+ return path.join(tmpdir(), "proxy-meter");
597
+ };
598
+ var ensureLogPath = () => {
599
+ const baseDir = resolveLogDir();
600
+ if (!existsSync(baseDir)) {
601
+ try {
602
+ mkdirSync(baseDir, { recursive: true });
603
+ } catch {
604
+ }
605
+ }
606
+ const runId = String(process.env.APIFY_ACTOR_RUN_ID || "").trim();
607
+ const suffix = `${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
608
+ const label = runId ? `proxy-meter-${runId}-${suffix}.json` : `proxy-meter-${process.pid}-${suffix}.json`;
609
+ return path.join(baseDir, label);
610
+ };
611
+ var readSnapshot = (logPath) => {
612
+ if (!logPath || !existsSync(logPath)) return null;
613
+ try {
614
+ const raw = readFileSync(logPath, "utf8");
615
+ if (!raw) return null;
616
+ return JSON.parse(raw);
617
+ } catch {
618
+ return null;
619
+ }
620
+ };
621
+ var normalizeDomainRows = (hosts) => {
622
+ const rows = [];
623
+ let requestCount = 0;
624
+ let connectCount = 0;
625
+ for (const [domain, stat] of Object.entries(hosts || {})) {
626
+ if (!stat || typeof stat !== "object") continue;
627
+ const inBytes = toSafeInt(stat.inBytes);
628
+ const outBytes = toSafeInt(stat.outBytes);
629
+ const requests = toSafeInt(stat.requests);
630
+ const connections = toSafeInt(stat.connections);
631
+ const totalBytes = inBytes + outBytes;
632
+ requestCount += requests;
633
+ connectCount += connections;
634
+ if (totalBytes <= 0 && requests <= 0 && connections <= 0) continue;
635
+ rows.push({
636
+ domain,
637
+ inBytes,
638
+ outBytes,
639
+ totalBytes,
640
+ requests,
641
+ connections
642
+ });
643
+ }
644
+ rows.sort((a, b) => {
645
+ if (b.totalBytes !== a.totalBytes) return b.totalBytes - a.totalBytes;
646
+ if (b.requests !== a.requests) return b.requests - a.requests;
647
+ return String(a.domain).localeCompare(String(b.domain));
648
+ });
649
+ return {
650
+ topDomains: rows.slice(0, MAX_TOP_DOMAINS),
651
+ requestCount,
652
+ connectCount
653
+ };
654
+ };
655
+ var normalizeDebugRows = (rows, type) => {
656
+ if (!Array.isArray(rows) || rows.length === 0) return void 0;
657
+ const normalized = rows.map((row) => {
658
+ if (!row || typeof row !== "object") return null;
659
+ return {
660
+ domain: String(row.domain || "").trim(),
661
+ status: String(row.status || "").trim(),
662
+ count: toSafeInt(row.count),
663
+ failedCount: toSafeInt(row.failedCount),
664
+ inBytes: toSafeInt(row.inBytes),
665
+ outBytes: toSafeInt(row.outBytes),
666
+ totalBytes: toSafeInt(row.totalBytes),
667
+ avgDurationMs: toSafeFloat(row.avgDurationMs),
668
+ reconnectCount: toSafeInt(row.reconnectCount),
669
+ largeResponseCount: toSafeInt(row.largeResponseCount),
670
+ failureRatePct: toSafeFloat(row.failureRatePct),
671
+ type
672
+ };
673
+ }).filter((row) => row && row.domain && row.count > 0);
674
+ return normalized.length > 0 ? normalized : void 0;
675
+ };
676
+ var normalizeDebugEvent = (row) => {
677
+ if (!row || typeof row !== "object") return null;
678
+ const host = String(row.host || "").trim();
679
+ if (!host) return null;
680
+ return {
681
+ ts: String(row.ts || ""),
682
+ runId: String(row.runId || ""),
683
+ channel: String(row.channel || ""),
684
+ host,
685
+ method: String(row.method || ""),
686
+ path: String(row.path || ""),
687
+ statusCode: toSafeInt(row.statusCode),
688
+ durationMs: toSafeInt(row.durationMs),
689
+ inBytes: toSafeInt(row.inBytes),
690
+ outBytes: toSafeInt(row.outBytes),
691
+ totalBytes: toSafeInt(row.totalBytes),
692
+ error: String(row.error || "")
693
+ };
694
+ };
695
+ var normalizeDebugSummary = (debug) => {
696
+ if (!debug || typeof debug !== "object" || !debug.summary || typeof debug.summary !== "object") {
556
697
  return null;
557
698
  }
558
- return trafficMeter.snapshot();
699
+ const summary = debug.summary;
700
+ const domainStatus = normalizeDebugRows(summary.domainStatus, "domain_status");
701
+ const topFailureDomains = normalizeDebugRows(summary.topFailureDomains, "top_failure");
702
+ const topLargeDomains = normalizeDebugRows(summary.topLargeDomains, "top_large");
703
+ const topReconnectDomains = normalizeDebugRows(summary.topReconnectDomains, "top_reconnect");
704
+ return {
705
+ enabled: Boolean(debug.enabled),
706
+ sampledEvents: toSafeInt(debug.sampledEvents),
707
+ droppedEvents: toSafeInt(debug.droppedEvents),
708
+ totalEvents: toSafeInt(debug.totalEvents),
709
+ largeResponseThresholdBytes: toSafeInt(summary.largeResponseThresholdBytes),
710
+ requestCount: toSafeInt(summary.requestCount),
711
+ failedCount: toSafeInt(summary.failedCount),
712
+ failureRatePct: toSafeFloat(summary.failureRatePct),
713
+ largeResponseCount: toSafeInt(summary.largeResponseCount),
714
+ reconnectCount: toSafeInt(summary.reconnectCount),
715
+ domainStatus,
716
+ topFailureDomains,
717
+ topLargeDomains,
718
+ topReconnectDomains
719
+ };
720
+ };
721
+ var normalizeSnapshot = (raw) => {
722
+ if (!raw || typeof raw !== "object") return null;
723
+ const totalIn = toSafeInt(raw.totalInBytes);
724
+ const totalOut = toSafeInt(raw.totalOutBytes);
725
+ const domains = normalizeDomainRows(raw.hosts && typeof raw.hosts === "object" ? raw.hosts : {});
726
+ const normalized = {
727
+ meter: "proxy-meter-v1",
728
+ totalBytes: totalIn + totalOut,
729
+ uploadBytes: totalOut,
730
+ downloadBytes: totalIn,
731
+ requestCount: domains.requestCount,
732
+ connectCount: domains.connectCount,
733
+ topDomains: domains.topDomains
734
+ };
735
+ const debug = raw.debug && typeof raw.debug === "object" ? raw.debug : null;
736
+ const summary = normalizeDebugSummary(debug);
737
+ const events = Array.isArray(debug?.events) ? debug.events.map(normalizeDebugEvent).filter(Boolean) : [];
738
+ if (summary) {
739
+ normalized.trafficDebugSummary = summary;
740
+ }
741
+ if (events.length > 0) {
742
+ normalized.trafficDebugEvents = events;
743
+ }
744
+ const hasSignal = normalized.totalBytes > 0 || normalized.uploadBytes > 0 || normalized.downloadBytes > 0 || normalized.requestCount > 0 || normalized.connectCount > 0 || normalized.topDomains && normalized.topDomains.length > 0 || Boolean(summary) || events.length > 0;
745
+ if (!hasSignal) return null;
746
+ return normalized;
747
+ };
748
+ var registerCleanup = () => {
749
+ if (cleanupInstalled) return;
750
+ cleanupInstalled = true;
751
+ const shutdown = () => {
752
+ if (!runtime || !runtime.proc) return;
753
+ try {
754
+ runtime.proc.kill("SIGTERM");
755
+ } catch {
756
+ }
757
+ };
758
+ process.once("exit", shutdown);
759
+ process.once("SIGINT", shutdown);
760
+ process.once("SIGTERM", shutdown);
761
+ };
762
+ var startProxyMeter = (options = {}) => {
763
+ const upstreamUrl = String(options.proxyUrl || "").trim();
764
+ if (!upstreamUrl) return null;
765
+ if (runtime && runtime.proc) {
766
+ try {
767
+ runtime.proc.kill("SIGTERM");
768
+ } catch {
769
+ }
770
+ runtime = null;
771
+ }
772
+ const port = pickFreePort();
773
+ const logPath = ensureLogPath();
774
+ const scriptPath = resolveScriptPath();
775
+ const debugMode = Boolean(options.debugMode);
776
+ const debugMaxEvents = Math.max(10, toSafeInt(options.debugMaxEvents) || DEFAULT_DEBUG_MAX_EVENTS);
777
+ const env = {
778
+ ...process.env,
779
+ PROXY_METER_PORT: String(port),
780
+ PROXY_METER_LOG: logPath,
781
+ PROXY_METER_UPSTREAM: upstreamUrl,
782
+ PROXY_METER_FLUSH_MS: String(FLUSH_INTERVAL_MS),
783
+ PROXY_METER_DEBUG: debugMode ? "1" : "0",
784
+ PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents)
785
+ };
786
+ const child = spawn(process.execPath, [scriptPath], {
787
+ env,
788
+ stdio: ["ignore", "ignore", "ignore"]
789
+ });
790
+ child.once("exit", (code) => {
791
+ if (code && code !== 0) {
792
+ logger2.warn(`[proxy-meter] exited with code ${code}`);
793
+ }
794
+ });
795
+ runtime = {
796
+ proc: child,
797
+ port,
798
+ logPath,
799
+ startedAt: Date.now()
800
+ };
801
+ registerCleanup();
802
+ return { server: `http://127.0.0.1:${port}` };
803
+ };
804
+ var stopProxyMeter = async () => {
805
+ if (!runtime) return null;
806
+ const { proc, logPath } = runtime;
807
+ if (!proc || proc.killed) {
808
+ runtime = null;
809
+ return logPath || null;
810
+ }
811
+ await new Promise((resolve) => {
812
+ const timeout = setTimeout(() => {
813
+ try {
814
+ proc.kill("SIGKILL");
815
+ } catch {
816
+ }
817
+ resolve();
818
+ }, 2e3);
819
+ proc.once("exit", () => {
820
+ clearTimeout(timeout);
821
+ resolve();
822
+ });
823
+ try {
824
+ proc.kill("SIGTERM");
825
+ } catch {
826
+ resolve();
827
+ }
828
+ });
829
+ runtime = null;
830
+ return logPath || null;
831
+ };
832
+ var getProxyMeterSnapshot = async (options = {}) => {
833
+ if (!runtime) return null;
834
+ const finalize = Boolean(options.finalize);
835
+ const logPath = finalize ? await stopProxyMeter() : runtime.logPath;
836
+ const raw = readSnapshot(logPath);
837
+ const snapshot = normalizeSnapshot(raw);
838
+ if (finalize && logPath) {
839
+ try {
840
+ rmSync(logPath, { force: true });
841
+ } catch {
842
+ }
843
+ }
844
+ return snapshot;
559
845
  };
560
846
 
561
847
  // src/apify-kit.js
562
- var logger2 = createInternalLogger("ApifyKit");
848
+ var logger3 = createInternalLogger("ApifyKit");
563
849
  async function createApifyKit() {
564
850
  let apify = null;
565
851
  try {
@@ -587,29 +873,29 @@ async function createApifyKit() {
587
873
  const { times: retryTimes = 0, mode: retryMode = "direct", before: beforeRetry } = retry;
588
874
  const executeAction = async (attemptNumber) => {
589
875
  const attemptLabel = attemptNumber > 0 ? ` (\u91CD\u8BD5 #${attemptNumber})` : "";
590
- logger2.start(`[Step] ${step}${attemptLabel}`);
876
+ logger3.start(`[Step] ${step}${attemptLabel}`);
591
877
  try {
592
878
  const result = await actionFn();
593
- logger2.success(`[Step] ${step}${attemptLabel}`);
879
+ logger3.success(`[Step] ${step}${attemptLabel}`);
594
880
  return { success: true, result };
595
881
  } catch (error) {
596
- logger2.fail(`[Step] ${step}${attemptLabel}`, error);
882
+ logger3.fail(`[Step] ${step}${attemptLabel}`, error);
597
883
  return { success: false, error };
598
884
  }
599
885
  };
600
886
  const prepareForRetry = async (attemptNumber) => {
601
887
  if (typeof beforeRetry === "function") {
602
- logger2.start(`[RetryStep] \u6267\u884C\u81EA\u5B9A\u4E49 before \u94A9\u5B50 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
888
+ logger3.start(`[RetryStep] \u6267\u884C\u81EA\u5B9A\u4E49 before \u94A9\u5B50 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
603
889
  await beforeRetry(page, attemptNumber);
604
- logger2.success(`[RetryStep] before \u94A9\u5B50\u5B8C\u6210`);
890
+ logger3.success(`[RetryStep] before \u94A9\u5B50\u5B8C\u6210`);
605
891
  } else if (retryMode === "refresh") {
606
- logger2.start(`[RetryStep] \u5237\u65B0\u9875\u9762 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
892
+ logger3.start(`[RetryStep] \u5237\u65B0\u9875\u9762 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
607
893
  await page.reload({ waitUntil: "commit" });
608
- logger2.success(`[RetryStep] \u9875\u9762\u5237\u65B0\u5B8C\u6210`);
894
+ logger3.success(`[RetryStep] \u9875\u9762\u5237\u65B0\u5B8C\u6210`);
609
895
  } else {
610
- logger2.start(`[RetryStep] \u7B49\u5F85 3 \u79D2 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
896
+ logger3.start(`[RetryStep] \u7B49\u5F85 3 \u79D2 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
611
897
  await new Promise((resolve) => setTimeout(resolve, 3e3));
612
- logger2.success(`[RetryStep] \u7B49\u5F85\u5B8C\u6210`);
898
+ logger3.success(`[RetryStep] \u7B49\u5F85\u5B8C\u6210`);
613
899
  }
614
900
  };
615
901
  let lastResult = await executeAction(0);
@@ -617,11 +903,11 @@ async function createApifyKit() {
617
903
  return lastResult.result;
618
904
  }
619
905
  for (let attempt = 1; attempt <= retryTimes; attempt++) {
620
- logger2.start(`[RetryStep] \u51C6\u5907\u7B2C ${attempt}/${retryTimes} \u6B21\u91CD\u8BD5: ${step}`);
906
+ logger3.start(`[RetryStep] \u51C6\u5907\u7B2C ${attempt}/${retryTimes} \u6B21\u91CD\u8BD5: ${step}`);
621
907
  try {
622
908
  await prepareForRetry(attempt);
623
909
  } catch (prepareError) {
624
- logger2.warn(`[RetryStep] \u91CD\u8BD5\u51C6\u5907\u5931\u8D25: ${prepareError.message}`);
910
+ logger3.warn(`[RetryStep] \u91CD\u8BD5\u51C6\u5907\u5931\u8D25: ${prepareError.message}`);
625
911
  continue;
626
912
  }
627
913
  lastResult = await executeAction(attempt);
@@ -642,7 +928,7 @@ async function createApifyKit() {
642
928
  base64 = `data:image/jpeg;base64,${buffer.toString("base64")}`;
643
929
  }
644
930
  } catch (snapErr) {
645
- logger2.warn(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);
931
+ logger3.warn(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);
646
932
  }
647
933
  await this.pushFailed(finalError, {
648
934
  step,
@@ -676,7 +962,7 @@ async function createApifyKit() {
676
962
  * @param {Object} data - 要推送的数据对象
677
963
  */
678
964
  async pushSuccess(data) {
679
- const traffic = getTrafficSnapshot();
965
+ const traffic = await getProxyMeterSnapshot({ finalize: true });
680
966
  await Actor2.pushData({
681
967
  // 固定为0
682
968
  code: Code.Success,
@@ -685,7 +971,7 @@ async function createApifyKit() {
685
971
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
686
972
  data
687
973
  });
688
- logger2.success("pushSuccess", "Data pushed");
974
+ logger3.success("pushSuccess", "Data pushed");
689
975
  },
690
976
  /**
691
977
  * 推送失败数据的通用方法(私有方法,仅供runStep内部使用)
@@ -698,7 +984,7 @@ async function createApifyKit() {
698
984
  const isCrawlerError = CrawlerError.isCrawlerError(error);
699
985
  const code = isCrawlerError ? error.code : Code.UnknownError;
700
986
  const context = isCrawlerError ? error.context : {};
701
- const traffic = getTrafficSnapshot();
987
+ const traffic = await getProxyMeterSnapshot({ finalize: true });
702
988
  await Actor2.pushData({
703
989
  // 如果是 CrawlerError,使用其 code,否则使用默认 Failed code
704
990
  code,
@@ -709,7 +995,7 @@ async function createApifyKit() {
709
995
  context,
710
996
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
711
997
  });
712
- logger2.success("pushFailed", "Error data pushed");
998
+ logger3.success("pushFailed", "Error data pushed");
713
999
  }
714
1000
  };
715
1001
  }
@@ -725,7 +1011,7 @@ var ApifyKit = {
725
1011
  };
726
1012
 
727
1013
  // src/internals/utils.js
728
- var logger3 = createInternalLogger("InternalUtils");
1014
+ var logger4 = createInternalLogger("InternalUtils");
729
1015
  var parseCookies = (cookieString, domain) => {
730
1016
  const cookies = [];
731
1017
  const pairs = cookieString.split(";").map((c) => c.trim());
@@ -743,7 +1029,7 @@ var parseCookies = (cookieString, domain) => {
743
1029
  cookies.push(cookie);
744
1030
  }
745
1031
  }
746
- logger3.success("parseCookies", `parsed ${cookies.length} cookies`);
1032
+ logger4.success("parseCookies", `parsed ${cookies.length} cookies`);
747
1033
  return cookies;
748
1034
  };
749
1035
 
@@ -786,7 +1072,7 @@ var Utils = {
786
1072
  };
787
1073
 
788
1074
  // src/anti-cheat.js
789
- var logger4 = createInternalLogger("AntiCheat");
1075
+ var logger5 = createInternalLogger("AntiCheat");
790
1076
  var BASE_CONFIG = Object.freeze({
791
1077
  locale: "zh-CN",
792
1078
  acceptLanguage: "zh-CN,zh;q=0.9",
@@ -848,7 +1134,7 @@ var AntiCheat = {
848
1134
  // src/humanize.js
849
1135
  import delay from "delay";
850
1136
  import { createCursor } from "ghost-cursor-playwright";
851
- var logger5 = createInternalLogger("Humanize");
1137
+ var logger6 = createInternalLogger("Humanize");
852
1138
  var $CursorWeakMap = /* @__PURE__ */ new WeakMap();
853
1139
  function $GetCursor(page) {
854
1140
  const cursor = $CursorWeakMap.get(page);
@@ -876,13 +1162,13 @@ var Humanize = {
876
1162
  */
877
1163
  async initializeCursor(page) {
878
1164
  if ($CursorWeakMap.has(page)) {
879
- logger5.debug("initializeCursor: cursor already exists, skipping");
1165
+ logger6.debug("initializeCursor: cursor already exists, skipping");
880
1166
  return;
881
1167
  }
882
- logger5.start("initializeCursor", "creating cursor");
1168
+ logger6.start("initializeCursor", "creating cursor");
883
1169
  const cursor = await createCursor(page);
884
1170
  $CursorWeakMap.set(page, cursor);
885
- logger5.success("initializeCursor", "cursor initialized");
1171
+ logger6.success("initializeCursor", "cursor initialized");
886
1172
  },
887
1173
  /**
888
1174
  * 人类化鼠标移动 - 使用 ghost-cursor 移动到指定位置或元素
@@ -892,17 +1178,17 @@ var Humanize = {
892
1178
  */
893
1179
  async humanMove(page, target) {
894
1180
  const cursor = $GetCursor(page);
895
- logger5.start("humanMove", `target=${typeof target === "string" ? target : "element/coords"}`);
1181
+ logger6.start("humanMove", `target=${typeof target === "string" ? target : "element/coords"}`);
896
1182
  try {
897
1183
  if (typeof target === "string") {
898
1184
  const element = await page.$(target);
899
1185
  if (!element) {
900
- logger5.warn(`humanMove: \u5143\u7D20\u4E0D\u5B58\u5728 ${target}`);
1186
+ logger6.warn(`humanMove: \u5143\u7D20\u4E0D\u5B58\u5728 ${target}`);
901
1187
  return false;
902
1188
  }
903
1189
  const box = await element.boundingBox();
904
1190
  if (!box) {
905
- logger5.warn(`humanMove: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E ${target}`);
1191
+ logger6.warn(`humanMove: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E ${target}`);
906
1192
  return false;
907
1193
  }
908
1194
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.2;
@@ -918,10 +1204,10 @@ var Humanize = {
918
1204
  await cursor.actions.move({ x, y });
919
1205
  }
920
1206
  }
921
- logger5.success("humanMove");
1207
+ logger6.success("humanMove");
922
1208
  return true;
923
1209
  } catch (error) {
924
- logger5.fail("humanMove", error);
1210
+ logger6.fail("humanMove", error);
925
1211
  throw error;
926
1212
  }
927
1213
  },
@@ -945,12 +1231,12 @@ var Humanize = {
945
1231
  maxDurationMs = maxSteps * 220 + 800
946
1232
  } = options;
947
1233
  const targetDesc = typeof target === "string" ? target : "ElementHandle";
948
- logger5.start("humanScroll", `target=${targetDesc}`);
1234
+ logger6.start("humanScroll", `target=${targetDesc}`);
949
1235
  let element;
950
1236
  if (typeof target === "string") {
951
1237
  element = await page.$(target);
952
1238
  if (!element) {
953
- logger5.warn(`humanScroll | \u5143\u7D20\u672A\u627E\u5230: ${target}`);
1239
+ logger6.warn(`humanScroll | \u5143\u7D20\u672A\u627E\u5230: ${target}`);
954
1240
  return { element: null, didScroll: false };
955
1241
  }
956
1242
  } else {
@@ -1025,26 +1311,26 @@ var Humanize = {
1025
1311
  try {
1026
1312
  for (let i = 0; i < maxSteps; i++) {
1027
1313
  if (Date.now() - startTime > maxDurationMs) {
1028
- logger5.warn(`humanScroll | \u8D85\u65F6\u4FDD\u62A4\u89E6\u53D1 (${maxDurationMs}ms)`);
1314
+ logger6.warn(`humanScroll | \u8D85\u65F6\u4FDD\u62A4\u89E6\u53D1 (${maxDurationMs}ms)`);
1029
1315
  return { element, didScroll };
1030
1316
  }
1031
1317
  const status = await checkVisibility();
1032
1318
  if (status.code === "VISIBLE") {
1033
1319
  if (status.isFixed) {
1034
- logger5.info("humanScroll | fixed \u5BB9\u5668\u5185\uFF0C\u8DF3\u8FC7\u6EDA\u52A8");
1320
+ logger6.info("humanScroll | fixed \u5BB9\u5668\u5185\uFF0C\u8DF3\u8FC7\u6EDA\u52A8");
1035
1321
  } else {
1036
- logger5.debug("humanScroll | \u5143\u7D20\u53EF\u89C1\u4E14\u65E0\u906E\u6321");
1322
+ logger6.debug("humanScroll | \u5143\u7D20\u53EF\u89C1\u4E14\u65E0\u906E\u6321");
1037
1323
  }
1038
- logger5.success("humanScroll", didScroll ? "\u5DF2\u6EDA\u52A8" : "\u65E0\u9700\u6EDA\u52A8");
1324
+ logger6.success("humanScroll", didScroll ? "\u5DF2\u6EDA\u52A8" : "\u65E0\u9700\u6EDA\u52A8");
1039
1325
  return { element, didScroll };
1040
1326
  }
1041
- logger5.debug(`humanScroll | \u6B65\u9AA4 ${i + 1}/${maxSteps}: ${status.reason} ${status.direction ? `(${status.direction})` : ""}`);
1327
+ logger6.debug(`humanScroll | \u6B65\u9AA4 ${i + 1}/${maxSteps}: ${status.reason} ${status.direction ? `(${status.direction})` : ""}`);
1042
1328
  if (status.code === "OBSTRUCTED" && status.obstruction) {
1043
- logger5.debug(`humanScroll | \u88AB\u4EE5\u4E0B\u5143\u7D20\u906E\u6321 <${status.obstruction.tag} id="${status.obstruction.id}">`);
1329
+ logger6.debug(`humanScroll | \u88AB\u4EE5\u4E0B\u5143\u7D20\u906E\u6321 <${status.obstruction.tag} id="${status.obstruction.id}">`);
1044
1330
  }
1045
1331
  const scrollRect = await getScrollableRect();
1046
1332
  if (!scrollRect && status.isFixed) {
1047
- logger5.warn("humanScroll | fixed \u5BB9\u5668\u5185\u4E14\u65E0\u53EF\u6EDA\u52A8\u7956\u5148\uFF0C\u8DF3\u8FC7\u6EDA\u52A8");
1333
+ logger6.warn("humanScroll | fixed \u5BB9\u5668\u5185\u4E14\u65E0\u53EF\u6EDA\u52A8\u7956\u5148\uFF0C\u8DF3\u8FC7\u6EDA\u52A8");
1048
1334
  return { element, didScroll };
1049
1335
  }
1050
1336
  const stepMin = scrollRect ? Math.min(minStep, Math.max(60, scrollRect.height * 0.4)) : minStep;
@@ -1080,10 +1366,10 @@ var Humanize = {
1080
1366
  didScroll = true;
1081
1367
  await delay(this.jitterMs(20 + Math.random() * 40, 0.2));
1082
1368
  }
1083
- logger5.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
1369
+ logger6.warn(`humanScroll | \u5728 ${maxSteps} \u6B65\u540E\u65E0\u6CD5\u786E\u4FDD\u53EF\u89C1\u6027`);
1084
1370
  return { element, didScroll };
1085
1371
  } catch (error) {
1086
- logger5.fail("humanScroll", error);
1372
+ logger6.fail("humanScroll", error);
1087
1373
  throw error;
1088
1374
  }
1089
1375
  },
@@ -1101,7 +1387,7 @@ var Humanize = {
1101
1387
  const cursor = $GetCursor(page);
1102
1388
  const { reactionDelay = 250, throwOnMissing = true, scrollIfNeeded = true, restore = false } = options;
1103
1389
  const targetDesc = target == null ? "Current Position" : typeof target === "string" ? target : "ElementHandle";
1104
- logger5.start("humanClick", `target=${targetDesc}`);
1390
+ logger6.start("humanClick", `target=${targetDesc}`);
1105
1391
  const restoreOnce = async () => {
1106
1392
  if (restoreOnce.restored) return;
1107
1393
  restoreOnce.restored = true;
@@ -1110,14 +1396,14 @@ var Humanize = {
1110
1396
  await delay(this.jitterMs(1e3));
1111
1397
  await restoreOnce.do();
1112
1398
  } catch (restoreError) {
1113
- logger5.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
1399
+ logger6.warn(`humanClick: \u6062\u590D\u6EDA\u52A8\u4F4D\u7F6E\u5931\u8D25: ${restoreError.message}`);
1114
1400
  }
1115
1401
  };
1116
1402
  try {
1117
1403
  if (target == null) {
1118
1404
  await delay(this.jitterMs(reactionDelay, 0.4));
1119
1405
  await cursor.actions.click();
1120
- logger5.success("humanClick", "Clicked current position");
1406
+ logger6.success("humanClick", "Clicked current position");
1121
1407
  return true;
1122
1408
  }
1123
1409
  let element;
@@ -1127,7 +1413,7 @@ var Humanize = {
1127
1413
  if (throwOnMissing) {
1128
1414
  throw new Error(`\u627E\u4E0D\u5230\u5143\u7D20 ${target}`);
1129
1415
  }
1130
- logger5.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${target}`);
1416
+ logger6.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${target}`);
1131
1417
  return false;
1132
1418
  }
1133
1419
  } else {
@@ -1143,7 +1429,7 @@ var Humanize = {
1143
1429
  if (throwOnMissing) {
1144
1430
  throw new Error("\u65E0\u6CD5\u83B7\u53D6\u5143\u7D20\u4F4D\u7F6E");
1145
1431
  }
1146
- logger5.warn("humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB");
1432
+ logger6.warn("humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB");
1147
1433
  return false;
1148
1434
  }
1149
1435
  const x = box.x + box.width / 2 + (Math.random() - 0.5) * box.width * 0.3;
@@ -1152,11 +1438,11 @@ var Humanize = {
1152
1438
  await delay(this.jitterMs(reactionDelay, 0.4));
1153
1439
  await cursor.actions.click();
1154
1440
  await restoreOnce();
1155
- logger5.success("humanClick");
1441
+ logger6.success("humanClick");
1156
1442
  return true;
1157
1443
  } catch (error) {
1158
1444
  await restoreOnce();
1159
- logger5.fail("humanClick", error);
1445
+ logger6.fail("humanClick", error);
1160
1446
  throw error;
1161
1447
  }
1162
1448
  },
@@ -1167,9 +1453,9 @@ var Humanize = {
1167
1453
  */
1168
1454
  async randomSleep(baseMs, jitterPercent = 0.3) {
1169
1455
  const ms = this.jitterMs(baseMs, jitterPercent);
1170
- logger5.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
1456
+ logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
1171
1457
  await delay(ms);
1172
- logger5.success("randomSleep");
1458
+ logger6.success("randomSleep");
1173
1459
  },
1174
1460
  /**
1175
1461
  * 模拟人类"注视"或"阅读"行为:鼠标在页面上随机微动
@@ -1179,7 +1465,7 @@ var Humanize = {
1179
1465
  async simulateGaze(page, baseDurationMs = 2500) {
1180
1466
  const cursor = $GetCursor(page);
1181
1467
  const durationMs = this.jitterMs(baseDurationMs, 0.4);
1182
- logger5.start("simulateGaze", `duration=${durationMs}ms`);
1468
+ logger6.start("simulateGaze", `duration=${durationMs}ms`);
1183
1469
  const startTime = Date.now();
1184
1470
  const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };
1185
1471
  while (Date.now() - startTime < durationMs) {
@@ -1188,7 +1474,7 @@ var Humanize = {
1188
1474
  await cursor.actions.move({ x, y });
1189
1475
  await delay(this.jitterMs(600, 0.5));
1190
1476
  }
1191
- logger5.success("simulateGaze");
1477
+ logger6.success("simulateGaze");
1192
1478
  },
1193
1479
  /**
1194
1480
  * 人类化输入 - 带节奏变化(快-慢-停顿-偶尔加速)
@@ -1201,7 +1487,7 @@ var Humanize = {
1201
1487
  * @param {number} [options.pauseBase=800] - 停顿时长基础值 (ms),实际 ±50% 抖动
1202
1488
  */
1203
1489
  async humanType(page, selector, text, options = {}) {
1204
- logger5.start("humanType", `selector=${selector}, textLen=${text.length}`);
1490
+ logger6.start("humanType", `selector=${selector}, textLen=${text.length}`);
1205
1491
  const {
1206
1492
  baseDelay = 180,
1207
1493
  pauseProbability = 0.08,
@@ -1225,13 +1511,13 @@ var Humanize = {
1225
1511
  await delay(charDelay);
1226
1512
  if (Math.random() < pauseProbability && i < text.length - 1) {
1227
1513
  const pauseTime = this.jitterMs(pauseBase, 0.5);
1228
- logger5.debug(`\u505C\u987F ${pauseTime}ms...`);
1514
+ logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
1229
1515
  await delay(pauseTime);
1230
1516
  }
1231
1517
  }
1232
- logger5.success("humanType");
1518
+ logger6.success("humanType");
1233
1519
  } catch (error) {
1234
- logger5.fail("humanType", error);
1520
+ logger6.fail("humanType", error);
1235
1521
  throw error;
1236
1522
  }
1237
1523
  },
@@ -1241,22 +1527,22 @@ var Humanize = {
1241
1527
  * @param {string} selector - 输入框选择器
1242
1528
  */
1243
1529
  async humanClear(page, selector) {
1244
- logger5.start("humanClear", `selector=${selector}`);
1530
+ logger6.start("humanClear", `selector=${selector}`);
1245
1531
  try {
1246
1532
  const locator = page.locator(selector);
1247
1533
  await locator.click();
1248
1534
  await delay(this.jitterMs(200, 0.4));
1249
1535
  const currentValue = await locator.inputValue();
1250
1536
  if (!currentValue || currentValue.length === 0) {
1251
- logger5.success("humanClear", "already empty");
1537
+ logger6.success("humanClear", "already empty");
1252
1538
  return;
1253
1539
  }
1254
1540
  await page.keyboard.press("Meta+A");
1255
1541
  await delay(this.jitterMs(100, 0.4));
1256
1542
  await page.keyboard.press("Backspace");
1257
- logger5.success("humanClear");
1543
+ logger6.success("humanClear");
1258
1544
  } catch (error) {
1259
- logger5.fail("humanClear", error);
1545
+ logger6.fail("humanClear", error);
1260
1546
  throw error;
1261
1547
  }
1262
1548
  },
@@ -1268,7 +1554,7 @@ var Humanize = {
1268
1554
  async warmUpBrowsing(page, baseDuration = 3500) {
1269
1555
  const cursor = $GetCursor(page);
1270
1556
  const durationMs = this.jitterMs(baseDuration, 0.4);
1271
- logger5.start("warmUpBrowsing", `duration=${durationMs}ms`);
1557
+ logger6.start("warmUpBrowsing", `duration=${durationMs}ms`);
1272
1558
  const startTime = Date.now();
1273
1559
  const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };
1274
1560
  try {
@@ -1287,9 +1573,9 @@ var Humanize = {
1287
1573
  await delay(this.jitterMs(800, 0.5));
1288
1574
  }
1289
1575
  }
1290
- logger5.success("warmUpBrowsing");
1576
+ logger6.success("warmUpBrowsing");
1291
1577
  } catch (error) {
1292
- logger5.fail("warmUpBrowsing", error);
1578
+ logger6.fail("warmUpBrowsing", error);
1293
1579
  throw error;
1294
1580
  }
1295
1581
  },
@@ -1303,7 +1589,7 @@ var Humanize = {
1303
1589
  async naturalScroll(page, direction = "down", distance = 300, baseSteps = 5) {
1304
1590
  const steps = Math.max(3, baseSteps + Math.floor(Math.random() * 3) - 1);
1305
1591
  const actualDistance = this.jitterMs(distance, 0.15);
1306
- logger5.start("naturalScroll", `dir=${direction}, dist=${actualDistance}, steps=${steps}`);
1592
+ logger6.start("naturalScroll", `dir=${direction}, dist=${actualDistance}, steps=${steps}`);
1307
1593
  const sign = direction === "down" ? 1 : -1;
1308
1594
  const stepDistance = actualDistance / steps;
1309
1595
  try {
@@ -1315,9 +1601,9 @@ var Humanize = {
1315
1601
  const baseDelay = 60 + i * 25;
1316
1602
  await delay(this.jitterMs(baseDelay, 0.3));
1317
1603
  }
1318
- logger5.success("naturalScroll");
1604
+ logger6.success("naturalScroll");
1319
1605
  } catch (error) {
1320
- logger5.fail("naturalScroll", error);
1606
+ logger6.fail("naturalScroll", error);
1321
1607
  throw error;
1322
1608
  }
1323
1609
  }
@@ -1366,690 +1652,6 @@ var findMatchedByPassRule = (rules = [], requestUrl = "") => {
1366
1652
  hostname
1367
1653
  };
1368
1654
  };
1369
- var resolveRouteByProxy = ({
1370
- requestUrl = "",
1371
- enableProxy = false,
1372
- byPassRules = []
1373
- }) => {
1374
- if (!enableProxy) {
1375
- return { route: "direct", matchedRule: null, hostname: "" };
1376
- }
1377
- const matched = findMatchedByPassRule(byPassRules, requestUrl);
1378
- if (!matched) {
1379
- return { route: "proxy", matchedRule: null, hostname: "" };
1380
- }
1381
- if (matched.rule) {
1382
- return { route: "direct", matchedRule: matched.rule, hostname: matched.hostname };
1383
- }
1384
- return { route: "proxy", matchedRule: null, hostname: matched.hostname };
1385
- };
1386
-
1387
- // src/traffic-meter.js
1388
- var logger6 = createInternalLogger("TrafficMeter");
1389
- var encoder = new TextEncoder();
1390
- var MAX_DOMAIN_BUCKETS = 160;
1391
- var MAX_REASON_BUCKETS = 64;
1392
- var MAX_TOP_ITEMS = 12;
1393
- var MAX_HINT_ITEMS = 8;
1394
- var UNKNOWN_DOMAIN = "(unknown)";
1395
- var OTHER_DOMAINS = "(other-domains)";
1396
- var OTHER_REASONS = "(other-reasons)";
1397
- var STATIC_RESOURCE_TYPES = /* @__PURE__ */ new Set([
1398
- "script",
1399
- "stylesheet",
1400
- "image",
1401
- "font",
1402
- "media",
1403
- "manifest"
1404
- ]);
1405
- var BACKEND_RESOURCE_TYPES = /* @__PURE__ */ new Set([
1406
- "xhr",
1407
- "fetch",
1408
- "websocket",
1409
- "eventsource"
1410
- ]);
1411
- var toSafeNumber = (value) => {
1412
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
1413
- return Math.round(value);
1414
- };
1415
- var byteLength = (value) => {
1416
- const text = String(value || "");
1417
- if (!text) return 0;
1418
- try {
1419
- return encoder.encode(text).length;
1420
- } catch {
1421
- return text.length;
1422
- }
1423
- };
1424
- var normalizeHeaderValue = (value) => {
1425
- if (Array.isArray(value)) return value.join(",");
1426
- if (value === null || value === void 0) return "";
1427
- return String(value);
1428
- };
1429
- var estimateRequestBytes = (request = {}) => {
1430
- const method = String(request.method || "GET");
1431
- const url = String(request.url || "");
1432
- let total = byteLength(`${method} ${url} HTTP/1.1\r
1433
- `);
1434
- const headers = request.headers && typeof request.headers === "object" ? request.headers : {};
1435
- Object.entries(headers).forEach(([key, value]) => {
1436
- total += byteLength(`${key}: ${normalizeHeaderValue(value)}\r
1437
- `);
1438
- });
1439
- total += 2;
1440
- if (typeof request.postData === "string" && request.postData) {
1441
- total += byteLength(request.postData);
1442
- }
1443
- return total;
1444
- };
1445
- var createTrafficState = () => ({
1446
- totalRequests: 0,
1447
- proxyRequests: 0,
1448
- directRequests: 0,
1449
- totalUploadBytes: 0,
1450
- proxyUploadBytes: 0,
1451
- directUploadBytes: 0,
1452
- totalDownloadBytes: 0,
1453
- proxyDownloadBytes: 0,
1454
- directDownloadBytes: 0,
1455
- totalFailedRequests: 0,
1456
- proxyFailedRequests: 0,
1457
- directFailedRequests: 0,
1458
- totalCanceledRequests: 0,
1459
- proxyCanceledRequests: 0,
1460
- directCanceledRequests: 0,
1461
- orphanDataReceivedBytes: 0,
1462
- orphanProxyDataReceivedBytes: 0,
1463
- orphanFinishDeltaBytes: 0,
1464
- orphanProxyFinishDeltaBytes: 0,
1465
- domainStats: /* @__PURE__ */ new Map(),
1466
- typeStats: /* @__PURE__ */ new Map(),
1467
- failedReasonStats: /* @__PURE__ */ new Map()
1468
- });
1469
- var ensureRoute = (route) => route === "proxy" ? "proxy" : "direct";
1470
- var normalizeResourceType = (value) => {
1471
- const type = String(value || "").trim().toLowerCase();
1472
- if (!type) return "other";
1473
- if (type === "ws") return "websocket";
1474
- return type;
1475
- };
1476
- var parseHostname = (url = "") => {
1477
- try {
1478
- const hostname = new URL(String(url || "")).hostname.toLowerCase();
1479
- return hostname || "";
1480
- } catch {
1481
- return "";
1482
- }
1483
- };
1484
- var normalizeDomainKey = (domain = "") => {
1485
- const key = String(domain || "").trim().toLowerCase();
1486
- return key || UNKNOWN_DOMAIN;
1487
- };
1488
- var isStaticType = (resourceType = "") => STATIC_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
1489
- var isBackendType = (resourceType = "") => BACKEND_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
1490
- var createDomainBucket = (domain) => ({
1491
- domain,
1492
- requests: 0,
1493
- proxyRequests: 0,
1494
- directRequests: 0,
1495
- uploadBytes: 0,
1496
- downloadBytes: 0,
1497
- totalBytes: 0,
1498
- proxyBytes: 0,
1499
- directBytes: 0,
1500
- failedRequests: 0,
1501
- canceledRequests: 0,
1502
- staticBytes: 0,
1503
- backendBytes: 0
1504
- });
1505
- var createTypeBucket = (resourceType) => ({
1506
- resourceType,
1507
- requests: 0,
1508
- proxyRequests: 0,
1509
- directRequests: 0,
1510
- uploadBytes: 0,
1511
- downloadBytes: 0,
1512
- totalBytes: 0,
1513
- proxyBytes: 0,
1514
- directBytes: 0,
1515
- failedRequests: 0,
1516
- canceledRequests: 0
1517
- });
1518
- var createReasonBucket = (reason) => ({
1519
- reason,
1520
- count: 0,
1521
- canceledCount: 0,
1522
- proxyCount: 0,
1523
- directCount: 0
1524
- });
1525
- var formatBytes = (bytes = 0) => {
1526
- const value = toSafeNumber(bytes);
1527
- if (value <= 0) return "0B";
1528
- const units = ["B", "KB", "MB", "GB", "TB"];
1529
- let size = value;
1530
- let unit = 0;
1531
- while (size >= 1024 && unit < units.length - 1) {
1532
- size /= 1024;
1533
- unit += 1;
1534
- }
1535
- const precision = size >= 100 || unit === 0 ? 0 : 2;
1536
- return `${size.toFixed(precision)}${units[unit]}`;
1537
- };
1538
- var addRequests = (state, route, count = 1) => {
1539
- const c = toSafeNumber(count);
1540
- if (c <= 0) return;
1541
- const normalizedRoute = ensureRoute(route);
1542
- state.totalRequests += c;
1543
- if (normalizedRoute === "proxy") {
1544
- state.proxyRequests += c;
1545
- return;
1546
- }
1547
- state.directRequests += c;
1548
- };
1549
- var addUploadBytes = (state, route, bytes = 0) => {
1550
- const b = toSafeNumber(bytes);
1551
- if (b <= 0) return;
1552
- const normalizedRoute = ensureRoute(route);
1553
- state.totalUploadBytes += b;
1554
- if (normalizedRoute === "proxy") {
1555
- state.proxyUploadBytes += b;
1556
- return;
1557
- }
1558
- state.directUploadBytes += b;
1559
- };
1560
- var addDownloadBytes = (state, route, bytes = 0) => {
1561
- const b = toSafeNumber(bytes);
1562
- if (b <= 0) return;
1563
- const normalizedRoute = ensureRoute(route);
1564
- state.totalDownloadBytes += b;
1565
- if (normalizedRoute === "proxy") {
1566
- state.proxyDownloadBytes += b;
1567
- return;
1568
- }
1569
- state.directDownloadBytes += b;
1570
- };
1571
- var incrementBucketRequests = (bucket, route) => {
1572
- if (!bucket) return;
1573
- bucket.requests += 1;
1574
- if (ensureRoute(route) === "proxy") {
1575
- bucket.proxyRequests += 1;
1576
- return;
1577
- }
1578
- bucket.directRequests += 1;
1579
- };
1580
- var incrementBucketBytes = (bucket, route, bytes = 0, direction = "download", resourceType = "other") => {
1581
- if (!bucket) return;
1582
- const b = toSafeNumber(bytes);
1583
- if (b <= 0) return;
1584
- if (direction === "upload") {
1585
- bucket.uploadBytes += b;
1586
- } else {
1587
- bucket.downloadBytes += b;
1588
- }
1589
- bucket.totalBytes += b;
1590
- if (ensureRoute(route) === "proxy") {
1591
- bucket.proxyBytes += b;
1592
- } else {
1593
- bucket.directBytes += b;
1594
- }
1595
- if (bucket.domain !== void 0) {
1596
- if (isStaticType(resourceType)) {
1597
- bucket.staticBytes += b;
1598
- } else if (isBackendType(resourceType)) {
1599
- bucket.backendBytes += b;
1600
- }
1601
- }
1602
- };
1603
- var incrementBucketFailed = (bucket, canceled = false) => {
1604
- if (!bucket) return;
1605
- bucket.failedRequests += 1;
1606
- if (canceled) {
1607
- bucket.canceledRequests += 1;
1608
- }
1609
- };
1610
- var ensureReasonText = (reason) => {
1611
- const normalized = String(reason || "").trim().toLowerCase();
1612
- return normalized || "unknown";
1613
- };
1614
- var pickDomainBucket = (state, domain = "") => {
1615
- const domainKey = normalizeDomainKey(domain);
1616
- const knownBucket = state.domainStats.get(domainKey);
1617
- if (knownBucket) return knownBucket;
1618
- if (state.domainStats.size < MAX_DOMAIN_BUCKETS) {
1619
- const bucket2 = createDomainBucket(domainKey);
1620
- state.domainStats.set(domainKey, bucket2);
1621
- return bucket2;
1622
- }
1623
- const overflow = state.domainStats.get(OTHER_DOMAINS);
1624
- if (overflow) return overflow;
1625
- const bucket = createDomainBucket(OTHER_DOMAINS);
1626
- state.domainStats.set(OTHER_DOMAINS, bucket);
1627
- return bucket;
1628
- };
1629
- var pickTypeBucket = (state, resourceType = "other") => {
1630
- const typeKey = normalizeResourceType(resourceType);
1631
- const knownBucket = state.typeStats.get(typeKey);
1632
- if (knownBucket) return knownBucket;
1633
- const bucket = createTypeBucket(typeKey);
1634
- state.typeStats.set(typeKey, bucket);
1635
- return bucket;
1636
- };
1637
- var pickReasonBucket = (state, reason = "") => {
1638
- const reasonKey = ensureReasonText(reason);
1639
- const knownBucket = state.failedReasonStats.get(reasonKey);
1640
- if (knownBucket) return knownBucket;
1641
- if (state.failedReasonStats.size < MAX_REASON_BUCKETS) {
1642
- const bucket2 = createReasonBucket(reasonKey);
1643
- state.failedReasonStats.set(reasonKey, bucket2);
1644
- return bucket2;
1645
- }
1646
- const overflow = state.failedReasonStats.get(OTHER_REASONS);
1647
- if (overflow) return overflow;
1648
- const bucket = createReasonBucket(OTHER_REASONS);
1649
- state.failedReasonStats.set(OTHER_REASONS, bucket);
1650
- return bucket;
1651
- };
1652
- var addRequestProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
1653
- const domainBucket = pickDomainBucket(state, domain);
1654
- const typeBucket = pickTypeBucket(state, resourceType);
1655
- incrementBucketRequests(domainBucket, route);
1656
- incrementBucketRequests(typeBucket, route);
1657
- incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
1658
- incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
1659
- };
1660
- var addUploadProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
1661
- const domainBucket = pickDomainBucket(state, domain);
1662
- const typeBucket = pickTypeBucket(state, resourceType);
1663
- incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
1664
- incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
1665
- };
1666
- var addDownloadProfile = (state, route, domain, resourceType, downloadBytes = 0) => {
1667
- const domainBucket = pickDomainBucket(state, domain);
1668
- const typeBucket = pickTypeBucket(state, resourceType);
1669
- incrementBucketBytes(domainBucket, route, downloadBytes, "download", resourceType);
1670
- incrementBucketBytes(typeBucket, route, downloadBytes, "download", resourceType);
1671
- };
1672
- var addFailedProfile = (state, route, domain, resourceType, reason = "unknown", canceled = false) => {
1673
- const domainBucket = pickDomainBucket(state, domain);
1674
- const typeBucket = pickTypeBucket(state, resourceType);
1675
- const reasonBucket = pickReasonBucket(state, reason);
1676
- incrementBucketFailed(domainBucket, canceled);
1677
- incrementBucketFailed(typeBucket, canceled);
1678
- reasonBucket.count += 1;
1679
- if (ensureRoute(route) === "proxy") {
1680
- reasonBucket.proxyCount += 1;
1681
- } else {
1682
- reasonBucket.directCount += 1;
1683
- }
1684
- if (canceled) {
1685
- reasonBucket.canceledCount += 1;
1686
- }
1687
- };
1688
- var toRoundedRatio = (numerator, denominator) => {
1689
- if (denominator <= 0) return 0;
1690
- return Number((numerator / denominator * 100).toFixed(2));
1691
- };
1692
- var sortByBytesAndRequests = (left, right) => {
1693
- if (right.totalBytes !== left.totalBytes) return right.totalBytes - left.totalBytes;
1694
- if (right.requests !== left.requests) return right.requests - left.requests;
1695
- return String(left.domain || left.resourceType || "").localeCompare(String(right.domain || right.resourceType || ""));
1696
- };
1697
- var buildTopDomains = (state) => {
1698
- return Array.from(state.domainStats.values()).filter((item) => item && item.totalBytes > 0).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
1699
- domain: item.domain,
1700
- requests: item.requests,
1701
- proxyRequests: item.proxyRequests,
1702
- directRequests: item.directRequests,
1703
- uploadBytes: item.uploadBytes,
1704
- downloadBytes: item.downloadBytes,
1705
- totalBytes: item.totalBytes,
1706
- proxyBytes: item.proxyBytes,
1707
- directBytes: item.directBytes,
1708
- failedRequests: item.failedRequests,
1709
- canceledRequests: item.canceledRequests,
1710
- staticBytes: item.staticBytes,
1711
- backendBytes: item.backendBytes
1712
- }));
1713
- };
1714
- var buildTopResourceTypes = (state) => {
1715
- return Array.from(state.typeStats.values()).filter((item) => item && (item.totalBytes > 0 || item.requests > 0)).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
1716
- resourceType: item.resourceType,
1717
- requests: item.requests,
1718
- proxyRequests: item.proxyRequests,
1719
- directRequests: item.directRequests,
1720
- uploadBytes: item.uploadBytes,
1721
- downloadBytes: item.downloadBytes,
1722
- totalBytes: item.totalBytes,
1723
- proxyBytes: item.proxyBytes,
1724
- directBytes: item.directBytes,
1725
- failedRequests: item.failedRequests,
1726
- canceledRequests: item.canceledRequests
1727
- }));
1728
- };
1729
- var buildFailedReasons = (state) => {
1730
- return Array.from(state.failedReasonStats.values()).filter((item) => item && item.count > 0).sort((left, right) => {
1731
- if (right.count !== left.count) return right.count - left.count;
1732
- return String(left.reason || "").localeCompare(String(right.reason || ""));
1733
- }).slice(0, MAX_TOP_ITEMS).map((item) => ({
1734
- reason: item.reason,
1735
- count: item.count,
1736
- canceledCount: item.canceledCount,
1737
- proxyCount: item.proxyCount,
1738
- directCount: item.directCount
1739
- }));
1740
- };
1741
- var buildProxyByPassHints = (state) => {
1742
- return Array.from(state.domainStats.values()).filter((item) => item && item.domain !== UNKNOWN_DOMAIN && item.domain !== OTHER_DOMAINS).filter((item) => item.proxyBytes >= 128 * 1024 && item.proxyRequests >= 2 && item.totalBytes > 0).filter((item) => item.staticBytes > item.backendBytes && toRoundedRatio(item.staticBytes, item.totalBytes) >= 80).sort((left, right) => {
1743
- if (right.proxyBytes !== left.proxyBytes) return right.proxyBytes - left.proxyBytes;
1744
- return right.proxyRequests - left.proxyRequests;
1745
- }).slice(0, MAX_HINT_ITEMS).map((item) => ({
1746
- domain: item.domain,
1747
- proxyBytes: item.proxyBytes,
1748
- proxyRequests: item.proxyRequests,
1749
- totalBytes: item.totalBytes,
1750
- staticBytes: item.staticBytes,
1751
- backendBytes: item.backendBytes,
1752
- staticRatioPct: toRoundedRatio(item.staticBytes, item.totalBytes)
1753
- }));
1754
- };
1755
- var createTrafficMeter = ({
1756
- enableProxy = false,
1757
- byPassRules = [],
1758
- debugMode = false
1759
- } = {}) => {
1760
- const state = createTrafficState();
1761
- const requestMap = /* @__PURE__ */ new Map();
1762
- const orphanReceivedMap = /* @__PURE__ */ new Map();
1763
- const wsRouteMap = /* @__PURE__ */ new Map();
1764
- const attachedPages = /* @__PURE__ */ new WeakSet();
1765
- const attachedContexts = /* @__PURE__ */ new WeakSet();
1766
- const resolveRoute = (url = "") => {
1767
- return resolveRouteByProxy({
1768
- requestUrl: url,
1769
- enableProxy,
1770
- byPassRules
1771
- }).route;
1772
- };
1773
- const fallbackRoute = () => enableProxy ? "proxy" : "direct";
1774
- const debugLog = (message) => {
1775
- if (!debugMode) return;
1776
- logger6.info(`[\u9010\u8BF7\u6C42\u8C03\u8BD5] ${message}`);
1777
- };
1778
- const addFailed = (route, canceled = false) => {
1779
- const normalizedRoute = ensureRoute(route);
1780
- state.totalFailedRequests += 1;
1781
- if (normalizedRoute === "proxy") {
1782
- state.proxyFailedRequests += 1;
1783
- } else {
1784
- state.directFailedRequests += 1;
1785
- }
1786
- if (!canceled) return;
1787
- state.totalCanceledRequests += 1;
1788
- if (normalizedRoute === "proxy") {
1789
- state.proxyCanceledRequests += 1;
1790
- } else {
1791
- state.directCanceledRequests += 1;
1792
- }
1793
- };
1794
- const finalizeByEncodedLength = (requestId, encodedDataLength, source = "finished") => {
1795
- const safeRequestId = String(requestId || "");
1796
- if (!safeRequestId) return;
1797
- const requestState = requestMap.get(safeRequestId);
1798
- const orphanReceived = toSafeNumber(orphanReceivedMap.get(safeRequestId));
1799
- const encoded = toSafeNumber(encodedDataLength);
1800
- if (requestState) {
1801
- const routed2 = ensureRoute(requestState.route);
1802
- const downloaded = toSafeNumber(requestState.downloadBytes);
1803
- const delta2 = Math.max(0, encoded - downloaded);
1804
- if (delta2 > 0) {
1805
- addDownloadBytes(state, routed2, delta2);
1806
- addDownloadProfile(state, routed2, requestState.domain, requestState.resourceType, delta2);
1807
- requestState.downloadBytes = downloaded + delta2;
1808
- }
1809
- const uploadBytes = toSafeNumber(requestState.uploadBytes);
1810
- const total = uploadBytes + toSafeNumber(requestState.downloadBytes);
1811
- debugLog(
1812
- `final id=${safeRequestId} source=${source} status=ok route=${routed2} type=${requestState.resourceType || "other"} upload=${formatBytes(uploadBytes)} (${uploadBytes}) download=${formatBytes(requestState.downloadBytes)} (${requestState.downloadBytes}) total=${formatBytes(total)} (${total}) url=${requestState.url || "-"}`
1813
- );
1814
- requestMap.delete(safeRequestId);
1815
- orphanReceivedMap.delete(safeRequestId);
1816
- return;
1817
- }
1818
- const routed = fallbackRoute();
1819
- const delta = Math.max(0, encoded - orphanReceived);
1820
- if (delta > 0) {
1821
- addDownloadBytes(state, routed, delta);
1822
- addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", delta);
1823
- }
1824
- state.orphanFinishDeltaBytes += delta;
1825
- if (routed === "proxy") {
1826
- state.orphanProxyFinishDeltaBytes += delta;
1827
- }
1828
- debugLog(
1829
- `final id=${safeRequestId} source=${source} status=orphan route=${routed} encoded=${formatBytes(encoded)} (${encoded}) delta=${formatBytes(delta)} (${delta})`
1830
- );
1831
- orphanReceivedMap.delete(safeRequestId);
1832
- };
1833
- const recordRequest = (params = {}) => {
1834
- const requestId = String(params.requestId || "");
1835
- const request = params.request && typeof params.request === "object" ? params.request : {};
1836
- const url = String(request.url || "");
1837
- const route = resolveRoute(url);
1838
- const resourceType = normalizeResourceType(params.type || request.type || "other");
1839
- const domain = normalizeDomainKey(parseHostname(url));
1840
- if (requestId && requestMap.has(requestId)) {
1841
- const redirectResponse = params.redirectResponse && typeof params.redirectResponse === "object" ? params.redirectResponse : null;
1842
- finalizeByEncodedLength(
1843
- requestId,
1844
- redirectResponse ? redirectResponse.encodedDataLength : 0,
1845
- "redirect"
1846
- );
1847
- }
1848
- addRequests(state, route, 1);
1849
- const uploadBytes = estimateRequestBytes(request);
1850
- addUploadBytes(state, route, uploadBytes);
1851
- addRequestProfile(state, route, domain, resourceType, uploadBytes);
1852
- if (requestId) {
1853
- requestMap.set(requestId, {
1854
- route: ensureRoute(route),
1855
- resourceType,
1856
- domain,
1857
- url,
1858
- uploadBytes,
1859
- downloadBytes: 0
1860
- });
1861
- }
1862
- debugLog(
1863
- `request id=${requestId || "-"} route=${route} type=${resourceType} upload=${formatBytes(uploadBytes)} (${uploadBytes}) method=${String(request.method || "GET")} url=${url || "-"}`
1864
- );
1865
- };
1866
- const recordDataReceived = (params = {}) => {
1867
- const requestId = String(params.requestId || "");
1868
- const bytes = toSafeNumber(params.encodedDataLength);
1869
- if (bytes <= 0) return;
1870
- if (!requestId) {
1871
- const routed2 = fallbackRoute();
1872
- addDownloadBytes(state, routed2, bytes);
1873
- addDownloadProfile(state, routed2, UNKNOWN_DOMAIN, "other", bytes);
1874
- state.orphanDataReceivedBytes += bytes;
1875
- if (routed2 === "proxy") {
1876
- state.orphanProxyDataReceivedBytes += bytes;
1877
- }
1878
- return;
1879
- }
1880
- const requestState = requestMap.get(requestId);
1881
- if (requestState) {
1882
- requestState.downloadBytes = toSafeNumber(requestState.downloadBytes) + bytes;
1883
- addDownloadBytes(state, requestState.route, bytes);
1884
- addDownloadProfile(state, requestState.route, requestState.domain, requestState.resourceType, bytes);
1885
- return;
1886
- }
1887
- const prev = toSafeNumber(orphanReceivedMap.get(requestId));
1888
- orphanReceivedMap.set(requestId, prev + bytes);
1889
- const routed = fallbackRoute();
1890
- addDownloadBytes(state, routed, bytes);
1891
- addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", bytes);
1892
- state.orphanDataReceivedBytes += bytes;
1893
- if (routed === "proxy") {
1894
- state.orphanProxyDataReceivedBytes += bytes;
1895
- }
1896
- };
1897
- const recordLoadingFinished = (params = {}) => {
1898
- finalizeByEncodedLength(params.requestId, params.encodedDataLength, "loadingFinished");
1899
- };
1900
- const recordRequestFailed = (params = {}) => {
1901
- const requestId = String(params.requestId || "");
1902
- const requestState = requestId ? requestMap.get(requestId) : null;
1903
- const canceled = Boolean(params.canceled);
1904
- const reason = ensureReasonText(params.errorText);
1905
- const routed = ensureRoute(requestState?.route || fallbackRoute());
1906
- const resourceType = normalizeResourceType(requestState?.resourceType || "other");
1907
- const domain = normalizeDomainKey(requestState?.domain || "");
1908
- if (requestState) {
1909
- addFailed(routed, canceled);
1910
- addFailedProfile(state, routed, domain, resourceType, reason, canceled);
1911
- const uploadBytes = toSafeNumber(requestState.uploadBytes);
1912
- const downloadBytes = toSafeNumber(requestState.downloadBytes);
1913
- const totalBytes = uploadBytes + downloadBytes;
1914
- debugLog(
1915
- `final id=${requestId || "-"} source=loadingFailed status=failed route=${routed} type=${requestState.resourceType || "other"} upload=${formatBytes(uploadBytes)} (${uploadBytes}) download=${formatBytes(downloadBytes)} (${downloadBytes}) total=${formatBytes(totalBytes)} (${totalBytes}) canceled=${canceled} reason=${reason} url=${requestState.url || "-"}`
1916
- );
1917
- } else {
1918
- const orphanDownload = toSafeNumber(orphanReceivedMap.get(requestId));
1919
- addFailed(routed, canceled);
1920
- addFailedProfile(state, routed, UNKNOWN_DOMAIN, "other", reason, canceled);
1921
- debugLog(
1922
- `final id=${requestId || "-"} source=loadingFailed status=orphan-failed route=${routed} upload=0B (0) download=${formatBytes(orphanDownload)} (${orphanDownload}) total=${formatBytes(orphanDownload)} (${orphanDownload}) canceled=${canceled} reason=${reason} url=-`
1923
- );
1924
- }
1925
- if (requestId) {
1926
- requestMap.delete(requestId);
1927
- orphanReceivedMap.delete(requestId);
1928
- }
1929
- };
1930
- const bindWebSocketRoute = (params = {}) => {
1931
- const requestId = String(params.requestId || "");
1932
- if (!requestId) return;
1933
- const url = String(params.url || "");
1934
- const route = resolveRoute(url);
1935
- wsRouteMap.set(requestId, { route, url, domain: normalizeDomainKey(parseHostname(url)) });
1936
- };
1937
- const clearWebSocketRoute = (params = {}) => {
1938
- const requestId = String(params.requestId || "");
1939
- if (!requestId) return;
1940
- wsRouteMap.delete(requestId);
1941
- };
1942
- const getWebSocketMeta = (requestId = "") => {
1943
- if (!requestId) return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
1944
- const meta = wsRouteMap.get(requestId);
1945
- if (!meta || typeof meta !== "object") {
1946
- return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
1947
- }
1948
- return {
1949
- route: ensureRoute(meta.route),
1950
- url: String(meta.url || ""),
1951
- domain: normalizeDomainKey(meta.domain)
1952
- };
1953
- };
1954
- const recordWebSocketFrameSent = (params = {}) => {
1955
- const requestId = String(params.requestId || "");
1956
- const { route, url, domain } = getWebSocketMeta(requestId);
1957
- const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
1958
- const bytes = byteLength(payload || "");
1959
- addUploadBytes(state, route, bytes);
1960
- addUploadProfile(state, route, domain, "websocket", bytes);
1961
- debugLog(`ws-send id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
1962
- };
1963
- const recordWebSocketFrameReceived = (params = {}) => {
1964
- const requestId = String(params.requestId || "");
1965
- const { route, url, domain } = getWebSocketMeta(requestId);
1966
- const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
1967
- const bytes = byteLength(payload || "");
1968
- addDownloadBytes(state, route, bytes);
1969
- addDownloadProfile(state, route, domain, "websocket", bytes);
1970
- debugLog(`ws-recv id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
1971
- };
1972
- const attachPage = async (page) => {
1973
- if (!page || typeof page.context !== "function") return;
1974
- if (attachedPages.has(page)) return;
1975
- attachedPages.add(page);
1976
- try {
1977
- const context = page.context();
1978
- if (!context || typeof context.newCDPSession !== "function") {
1979
- return;
1980
- }
1981
- if (!attachedContexts.has(context) && typeof context.on === "function") {
1982
- attachedContexts.add(context);
1983
- context.on("page", (nextPage) => {
1984
- if (!nextPage) return;
1985
- attachPage(nextPage).catch((error) => {
1986
- logger6.warn(`\u5B50\u9875\u9762 CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
1987
- });
1988
- });
1989
- }
1990
- const session = await context.newCDPSession(page);
1991
- await session.send("Network.enable");
1992
- session.on("Network.requestWillBeSent", recordRequest);
1993
- session.on("Network.dataReceived", recordDataReceived);
1994
- session.on("Network.loadingFinished", recordLoadingFinished);
1995
- session.on("Network.loadingFailed", recordRequestFailed);
1996
- session.on("Network.webSocketCreated", bindWebSocketRoute);
1997
- session.on("Network.webSocketClosed", clearWebSocketRoute);
1998
- session.on("Network.webSocketFrameSent", recordWebSocketFrameSent);
1999
- session.on("Network.webSocketFrameReceived", recordWebSocketFrameReceived);
2000
- debugLog("CDP \u76D1\u542C\u5DF2\u6CE8\u518C");
2001
- } catch (error) {
2002
- logger6.warn(`CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
2003
- }
2004
- };
2005
- const snapshot = () => {
2006
- const totalBytes = state.totalUploadBytes + state.totalDownloadBytes;
2007
- const proxyBytes = state.proxyUploadBytes + state.proxyDownloadBytes;
2008
- const directBytes = state.directUploadBytes + state.directDownloadBytes;
2009
- return {
2010
- meter: "cdp-data-received-v3",
2011
- totalRequests: state.totalRequests,
2012
- proxyRequests: state.proxyRequests,
2013
- directRequests: state.directRequests,
2014
- totalUploadBytes: state.totalUploadBytes,
2015
- proxyUploadBytes: state.proxyUploadBytes,
2016
- directUploadBytes: state.directUploadBytes,
2017
- totalDownloadBytes: state.totalDownloadBytes,
2018
- proxyDownloadBytes: state.proxyDownloadBytes,
2019
- directDownloadBytes: state.directDownloadBytes,
2020
- totalBytes,
2021
- proxyBytes,
2022
- directBytes,
2023
- totalFailedRequests: state.totalFailedRequests,
2024
- proxyFailedRequests: state.proxyFailedRequests,
2025
- directFailedRequests: state.directFailedRequests,
2026
- totalCanceledRequests: state.totalCanceledRequests,
2027
- proxyCanceledRequests: state.proxyCanceledRequests,
2028
- directCanceledRequests: state.directCanceledRequests,
2029
- orphanDataReceivedBytes: state.orphanDataReceivedBytes,
2030
- orphanProxyDataReceivedBytes: state.orphanProxyDataReceivedBytes,
2031
- orphanFinishDeltaBytes: state.orphanFinishDeltaBytes,
2032
- orphanProxyFinishDeltaBytes: state.orphanProxyFinishDeltaBytes,
2033
- openRequestCount: requestMap.size,
2034
- orphanOpenCount: orphanReceivedMap.size,
2035
- topDomains: buildTopDomains(state),
2036
- topResourceTypes: buildTopResourceTypes(state),
2037
- failedReasons: buildFailedReasons(state),
2038
- proxyBypassHints: buildProxyByPassHints(state)
2039
- };
2040
- };
2041
- const reset = () => {
2042
- Object.assign(state, createTrafficState());
2043
- requestMap.clear();
2044
- orphanReceivedMap.clear();
2045
- wsRouteMap.clear();
2046
- };
2047
- return {
2048
- attachPage,
2049
- snapshot,
2050
- reset
2051
- };
2052
- };
2053
1655
 
2054
1656
  // src/launch.js
2055
1657
  var logger7 = createInternalLogger("Launch");
@@ -2064,24 +1666,10 @@ var resolveProxyLaunchOptions = (proxyConfiguration = {}) => {
2064
1666
  const proxyUrl = String(config.proxy_url || "").trim();
2065
1667
  const enableProxy = typeof config.enable_proxy === "boolean" ? config.enable_proxy : proxyUrl !== "";
2066
1668
  if (!enableProxy || !proxyUrl) {
2067
- return { launchProxy: null, byPassDomains: [], enableProxy, proxyUrl };
1669
+ return { byPassDomains: [], enableProxy, proxyUrl };
2068
1670
  }
2069
1671
  const byPassDomains = normalizeByPassDomains(config.by_pass_domains);
2070
- let parsedProxyUrl;
2071
- parsedProxyUrl = new URL(proxyUrl);
2072
- const launchProxy = {
2073
- server: `${parsedProxyUrl.protocol}//${parsedProxyUrl.host}`
2074
- };
2075
- if (parsedProxyUrl.username) {
2076
- launchProxy.username = decodeURIComponent(parsedProxyUrl.username);
2077
- }
2078
- if (parsedProxyUrl.password) {
2079
- launchProxy.password = decodeURIComponent(parsedProxyUrl.password);
2080
- }
2081
- if (byPassDomains.length > 0) {
2082
- launchProxy.bypass = byPassDomains.join(",");
2083
- }
2084
- return { launchProxy, byPassDomains, enableProxy, proxyUrl };
1672
+ return { byPassDomains, enableProxy, proxyUrl };
2085
1673
  };
2086
1674
  var Launch = {
2087
1675
  getPlaywrightCrawlerOptions(options = {}) {
@@ -2097,14 +1685,13 @@ var Launch = {
2097
1685
  preNavigationHooks = [],
2098
1686
  postNavigationHooks = []
2099
1687
  } = normalizedOptions;
2100
- const { launchProxy, byPassDomains, enableProxy, proxyUrl } = resolveProxyLaunchOptions(proxyConfiguration);
1688
+ const { byPassDomains, enableProxy, proxyUrl } = resolveProxyLaunchOptions(proxyConfiguration);
2101
1689
  const byPassRules = buildByPassDomainRules(byPassDomains);
2102
- const trafficMeter2 = createTrafficMeter({
2103
- enableProxy: Boolean(launchProxy),
2104
- byPassRules,
2105
- debugMode: Boolean(debugMode)
2106
- });
2107
- setTrafficMeter(trafficMeter2);
1690
+ const proxyMeter = enableProxy && proxyUrl ? startProxyMeter({ proxyUrl, debugMode }) : null;
1691
+ const launchProxy = proxyMeter ? { server: proxyMeter.server } : null;
1692
+ if (launchProxy && byPassDomains.length > 0) {
1693
+ launchProxy.bypass = byPassDomains.join(",");
1694
+ }
2108
1695
  const launchOptions = {
2109
1696
  args: [
2110
1697
  ...AntiCheat.getLaunchArgs(),
@@ -2117,8 +1704,14 @@ var Launch = {
2117
1704
  }
2118
1705
  const enableByPassLogger = Boolean(logOptions && logOptions.enable);
2119
1706
  if (enableByPassLogger && launchProxy) {
1707
+ let upstreamLabel = "";
1708
+ try {
1709
+ const parsedProxyUrl = new URL(proxyUrl);
1710
+ upstreamLabel = `${parsedProxyUrl.protocol}//${parsedProxyUrl.host}`;
1711
+ } catch {
1712
+ }
2120
1713
  logger7.info(
2121
- `[\u4EE3\u7406\u5DF2\u542F\u7528] \u4EE3\u7406\u670D\u52A1=${launchProxy.server} \u76F4\u8FDE\u57DF\u540D=${(byPassDomains || []).join(",")}`
1714
+ `[\u4EE3\u7406\u5DF2\u542F\u7528] \u672C\u5730=${launchProxy.server} \u4E0A\u6E38=${upstreamLabel || "-"} \u76F4\u8FDE\u57DF\u540D=${(byPassDomains || []).join(",")}`
2122
1715
  );
2123
1716
  logger7.info(`[\u6D41\u91CF\u89C2\u6D4B] \u9010\u8BF7\u6C42\u8C03\u8BD5=${Boolean(debugMode) ? "\u5F00\u542F" : "\u5173\u95ED"}\uFF08\u6C47\u603B\u59CB\u7EC8\u5F00\u542F\uFF09`);
2124
1717
  } else if (enableByPassLogger && enableProxy && !launchProxy) {
@@ -2138,9 +1731,6 @@ var Launch = {
2138
1731
  const recommendedGotoOptions = {
2139
1732
  waitUntil: "commit"
2140
1733
  };
2141
- if (page && typeof page.on === "function") {
2142
- trafficMeter2.attachPage(page);
2143
- }
2144
1734
  if (!enableByPassLogger || byPassDomains.length === 0 || !page || typeof page.on !== "function") {
2145
1735
  return recommendedGotoOptions;
2146
1736
  }
@@ -2833,10 +2423,10 @@ var Mutation = {
2833
2423
  let text = "";
2834
2424
  let html = "";
2835
2425
  let source = "main";
2836
- let path = `${selector}[${index}]`;
2426
+ let path2 = `${selector}[${index}]`;
2837
2427
  if (isIframe) {
2838
2428
  source = "iframe";
2839
- path = `${selector}[${index}]::iframe(${safeFrameId(node)})`;
2429
+ path2 = `${selector}[${index}]::iframe(${safeFrameId(node)})`;
2840
2430
  try {
2841
2431
  const frameDoc = node.contentDocument;
2842
2432
  const frameRoot = frameDoc?.body || frameDoc?.documentElement;
@@ -2854,7 +2444,7 @@ var Mutation = {
2854
2444
  items.push({
2855
2445
  selector,
2856
2446
  source,
2857
- path,
2447
+ path: path2,
2858
2448
  text,
2859
2449
  html,
2860
2450
  snapshot