@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/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +384 -793
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +381 -791
- package/dist/index.js.map +4 -4
- package/dist/proxy-meter.js +549 -0
- package/package.json +1 -1
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:
|
|
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(
|
|
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
|
|
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
|
|
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/
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
|
555
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
876
|
+
logger3.start(`[Step] ${step}${attemptLabel}`);
|
|
591
877
|
try {
|
|
592
878
|
const result = await actionFn();
|
|
593
|
-
|
|
879
|
+
logger3.success(`[Step] ${step}${attemptLabel}`);
|
|
594
880
|
return { success: true, result };
|
|
595
881
|
} catch (error) {
|
|
596
|
-
|
|
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
|
-
|
|
888
|
+
logger3.start(`[RetryStep] \u6267\u884C\u81EA\u5B9A\u4E49 before \u94A9\u5B50 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
|
|
603
889
|
await beforeRetry(page, attemptNumber);
|
|
604
|
-
|
|
890
|
+
logger3.success(`[RetryStep] before \u94A9\u5B50\u5B8C\u6210`);
|
|
605
891
|
} else if (retryMode === "refresh") {
|
|
606
|
-
|
|
892
|
+
logger3.start(`[RetryStep] \u5237\u65B0\u9875\u9762 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
|
|
607
893
|
await page.reload({ waitUntil: "commit" });
|
|
608
|
-
|
|
894
|
+
logger3.success(`[RetryStep] \u9875\u9762\u5237\u65B0\u5B8C\u6210`);
|
|
609
895
|
} else {
|
|
610
|
-
|
|
896
|
+
logger3.start(`[RetryStep] \u7B49\u5F85 3 \u79D2 (\u7B2C ${attemptNumber} \u6B21\u91CD\u8BD5)`);
|
|
611
897
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
612
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1165
|
+
logger6.debug("initializeCursor: cursor already exists, skipping");
|
|
880
1166
|
return;
|
|
881
1167
|
}
|
|
882
|
-
|
|
1168
|
+
logger6.start("initializeCursor", "creating cursor");
|
|
883
1169
|
const cursor = await createCursor(page);
|
|
884
1170
|
$CursorWeakMap.set(page, cursor);
|
|
885
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1207
|
+
logger6.success("humanMove");
|
|
922
1208
|
return true;
|
|
923
1209
|
} catch (error) {
|
|
924
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1320
|
+
logger6.info("humanScroll | fixed \u5BB9\u5668\u5185\uFF0C\u8DF3\u8FC7\u6EDA\u52A8");
|
|
1035
1321
|
} else {
|
|
1036
|
-
|
|
1322
|
+
logger6.debug("humanScroll | \u5143\u7D20\u53EF\u89C1\u4E14\u65E0\u906E\u6321");
|
|
1037
1323
|
}
|
|
1038
|
-
|
|
1324
|
+
logger6.success("humanScroll", didScroll ? "\u5DF2\u6EDA\u52A8" : "\u65E0\u9700\u6EDA\u52A8");
|
|
1039
1325
|
return { element, didScroll };
|
|
1040
1326
|
}
|
|
1041
|
-
|
|
1327
|
+
logger6.debug(`humanScroll | \u6B65\u9AA4 ${i + 1}/${maxSteps}: ${status.reason} ${status.direction ? `(${status.direction})` : ""}`);
|
|
1042
1328
|
if (status.code === "OBSTRUCTED" && status.obstruction) {
|
|
1043
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1441
|
+
logger6.success("humanClick");
|
|
1156
1442
|
return true;
|
|
1157
1443
|
} catch (error) {
|
|
1158
1444
|
await restoreOnce();
|
|
1159
|
-
|
|
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
|
-
|
|
1456
|
+
logger6.start("randomSleep", `base=${baseMs}, actual=${ms}ms`);
|
|
1171
1457
|
await delay(ms);
|
|
1172
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1514
|
+
logger6.debug(`\u505C\u987F ${pauseTime}ms...`);
|
|
1229
1515
|
await delay(pauseTime);
|
|
1230
1516
|
}
|
|
1231
1517
|
}
|
|
1232
|
-
|
|
1518
|
+
logger6.success("humanType");
|
|
1233
1519
|
} catch (error) {
|
|
1234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1543
|
+
logger6.success("humanClear");
|
|
1258
1544
|
} catch (error) {
|
|
1259
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1576
|
+
logger6.success("warmUpBrowsing");
|
|
1291
1577
|
} catch (error) {
|
|
1292
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1604
|
+
logger6.success("naturalScroll");
|
|
1319
1605
|
} catch (error) {
|
|
1320
|
-
|
|
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 {
|
|
1669
|
+
return { byPassDomains: [], enableProxy, proxyUrl };
|
|
2068
1670
|
}
|
|
2069
1671
|
const byPassDomains = normalizeByPassDomains(config.by_pass_domains);
|
|
2070
|
-
|
|
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 {
|
|
1688
|
+
const { byPassDomains, enableProxy, proxyUrl } = resolveProxyLaunchOptions(proxyConfiguration);
|
|
2101
1689
|
const byPassRules = buildByPassDomainRules(byPassDomains);
|
|
2102
|
-
const
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
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] \
|
|
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
|
|
2426
|
+
let path2 = `${selector}[${index}]`;
|
|
2837
2427
|
if (isIframe) {
|
|
2838
2428
|
source = "iframe";
|
|
2839
|
-
|
|
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
|