@skrillex1224/playwright-toolkit 2.1.163 → 2.1.165
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +489 -21
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +489 -21
- package/dist/index.js.map +3 -3
- package/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1414,6 +1414,27 @@ var resolveRouteByProxy = ({
|
|
|
1414
1414
|
// src/traffic-meter.js
|
|
1415
1415
|
var logger6 = createInternalLogger("TrafficMeter");
|
|
1416
1416
|
var encoder = new TextEncoder();
|
|
1417
|
+
var MAX_DOMAIN_BUCKETS = 160;
|
|
1418
|
+
var MAX_REASON_BUCKETS = 64;
|
|
1419
|
+
var MAX_TOP_ITEMS = 12;
|
|
1420
|
+
var MAX_HINT_ITEMS = 8;
|
|
1421
|
+
var UNKNOWN_DOMAIN = "(unknown)";
|
|
1422
|
+
var OTHER_DOMAINS = "(other-domains)";
|
|
1423
|
+
var OTHER_REASONS = "(other-reasons)";
|
|
1424
|
+
var STATIC_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
1425
|
+
"script",
|
|
1426
|
+
"stylesheet",
|
|
1427
|
+
"image",
|
|
1428
|
+
"font",
|
|
1429
|
+
"media",
|
|
1430
|
+
"manifest"
|
|
1431
|
+
]);
|
|
1432
|
+
var BACKEND_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
1433
|
+
"xhr",
|
|
1434
|
+
"fetch",
|
|
1435
|
+
"websocket",
|
|
1436
|
+
"eventsource"
|
|
1437
|
+
]);
|
|
1417
1438
|
var toSafeNumber = (value) => {
|
|
1418
1439
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
|
|
1419
1440
|
return Math.round(value);
|
|
@@ -1457,9 +1478,90 @@ var createTrafficState = () => ({
|
|
|
1457
1478
|
directUploadBytes: 0,
|
|
1458
1479
|
totalDownloadBytes: 0,
|
|
1459
1480
|
proxyDownloadBytes: 0,
|
|
1460
|
-
directDownloadBytes: 0
|
|
1481
|
+
directDownloadBytes: 0,
|
|
1482
|
+
totalFailedRequests: 0,
|
|
1483
|
+
proxyFailedRequests: 0,
|
|
1484
|
+
directFailedRequests: 0,
|
|
1485
|
+
totalCanceledRequests: 0,
|
|
1486
|
+
proxyCanceledRequests: 0,
|
|
1487
|
+
directCanceledRequests: 0,
|
|
1488
|
+
orphanDataReceivedBytes: 0,
|
|
1489
|
+
orphanProxyDataReceivedBytes: 0,
|
|
1490
|
+
orphanFinishDeltaBytes: 0,
|
|
1491
|
+
orphanProxyFinishDeltaBytes: 0,
|
|
1492
|
+
domainStats: /* @__PURE__ */ new Map(),
|
|
1493
|
+
typeStats: /* @__PURE__ */ new Map(),
|
|
1494
|
+
failedReasonStats: /* @__PURE__ */ new Map()
|
|
1461
1495
|
});
|
|
1462
1496
|
var ensureRoute = (route) => route === "proxy" ? "proxy" : "direct";
|
|
1497
|
+
var normalizeResourceType = (value) => {
|
|
1498
|
+
const type = String(value || "").trim().toLowerCase();
|
|
1499
|
+
if (!type) return "other";
|
|
1500
|
+
if (type === "ws") return "websocket";
|
|
1501
|
+
return type;
|
|
1502
|
+
};
|
|
1503
|
+
var parseHostname = (url = "") => {
|
|
1504
|
+
try {
|
|
1505
|
+
const hostname = new URL(String(url || "")).hostname.toLowerCase();
|
|
1506
|
+
return hostname || "";
|
|
1507
|
+
} catch {
|
|
1508
|
+
return "";
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
var normalizeDomainKey = (domain = "") => {
|
|
1512
|
+
const key = String(domain || "").trim().toLowerCase();
|
|
1513
|
+
return key || UNKNOWN_DOMAIN;
|
|
1514
|
+
};
|
|
1515
|
+
var isStaticType = (resourceType = "") => STATIC_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
|
|
1516
|
+
var isBackendType = (resourceType = "") => BACKEND_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
|
|
1517
|
+
var createDomainBucket = (domain) => ({
|
|
1518
|
+
domain,
|
|
1519
|
+
requests: 0,
|
|
1520
|
+
proxyRequests: 0,
|
|
1521
|
+
directRequests: 0,
|
|
1522
|
+
uploadBytes: 0,
|
|
1523
|
+
downloadBytes: 0,
|
|
1524
|
+
totalBytes: 0,
|
|
1525
|
+
proxyBytes: 0,
|
|
1526
|
+
directBytes: 0,
|
|
1527
|
+
failedRequests: 0,
|
|
1528
|
+
canceledRequests: 0,
|
|
1529
|
+
staticBytes: 0,
|
|
1530
|
+
backendBytes: 0
|
|
1531
|
+
});
|
|
1532
|
+
var createTypeBucket = (resourceType) => ({
|
|
1533
|
+
resourceType,
|
|
1534
|
+
requests: 0,
|
|
1535
|
+
proxyRequests: 0,
|
|
1536
|
+
directRequests: 0,
|
|
1537
|
+
uploadBytes: 0,
|
|
1538
|
+
downloadBytes: 0,
|
|
1539
|
+
totalBytes: 0,
|
|
1540
|
+
proxyBytes: 0,
|
|
1541
|
+
directBytes: 0,
|
|
1542
|
+
failedRequests: 0,
|
|
1543
|
+
canceledRequests: 0
|
|
1544
|
+
});
|
|
1545
|
+
var createReasonBucket = (reason) => ({
|
|
1546
|
+
reason,
|
|
1547
|
+
count: 0,
|
|
1548
|
+
canceledCount: 0,
|
|
1549
|
+
proxyCount: 0,
|
|
1550
|
+
directCount: 0
|
|
1551
|
+
});
|
|
1552
|
+
var formatBytes = (bytes = 0) => {
|
|
1553
|
+
const value = toSafeNumber(bytes);
|
|
1554
|
+
if (value <= 0) return "0B";
|
|
1555
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
1556
|
+
let size = value;
|
|
1557
|
+
let unit = 0;
|
|
1558
|
+
while (size >= 1024 && unit < units.length - 1) {
|
|
1559
|
+
size /= 1024;
|
|
1560
|
+
unit += 1;
|
|
1561
|
+
}
|
|
1562
|
+
const precision = size >= 100 || unit === 0 ? 0 : 2;
|
|
1563
|
+
return `${size.toFixed(precision)}${units[unit]}`;
|
|
1564
|
+
};
|
|
1463
1565
|
var addRequests = (state, route, count = 1) => {
|
|
1464
1566
|
const c = toSafeNumber(count);
|
|
1465
1567
|
if (c <= 0) return;
|
|
@@ -1493,13 +1595,201 @@ var addDownloadBytes = (state, route, bytes = 0) => {
|
|
|
1493
1595
|
}
|
|
1494
1596
|
state.directDownloadBytes += b;
|
|
1495
1597
|
};
|
|
1598
|
+
var incrementBucketRequests = (bucket, route) => {
|
|
1599
|
+
if (!bucket) return;
|
|
1600
|
+
bucket.requests += 1;
|
|
1601
|
+
if (ensureRoute(route) === "proxy") {
|
|
1602
|
+
bucket.proxyRequests += 1;
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
bucket.directRequests += 1;
|
|
1606
|
+
};
|
|
1607
|
+
var incrementBucketBytes = (bucket, route, bytes = 0, direction = "download", resourceType = "other") => {
|
|
1608
|
+
if (!bucket) return;
|
|
1609
|
+
const b = toSafeNumber(bytes);
|
|
1610
|
+
if (b <= 0) return;
|
|
1611
|
+
if (direction === "upload") {
|
|
1612
|
+
bucket.uploadBytes += b;
|
|
1613
|
+
} else {
|
|
1614
|
+
bucket.downloadBytes += b;
|
|
1615
|
+
}
|
|
1616
|
+
bucket.totalBytes += b;
|
|
1617
|
+
if (ensureRoute(route) === "proxy") {
|
|
1618
|
+
bucket.proxyBytes += b;
|
|
1619
|
+
} else {
|
|
1620
|
+
bucket.directBytes += b;
|
|
1621
|
+
}
|
|
1622
|
+
if (bucket.domain !== void 0) {
|
|
1623
|
+
if (isStaticType(resourceType)) {
|
|
1624
|
+
bucket.staticBytes += b;
|
|
1625
|
+
} else if (isBackendType(resourceType)) {
|
|
1626
|
+
bucket.backendBytes += b;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
var incrementBucketFailed = (bucket, canceled = false) => {
|
|
1631
|
+
if (!bucket) return;
|
|
1632
|
+
bucket.failedRequests += 1;
|
|
1633
|
+
if (canceled) {
|
|
1634
|
+
bucket.canceledRequests += 1;
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
var ensureReasonText = (reason) => {
|
|
1638
|
+
const normalized = String(reason || "").trim().toLowerCase();
|
|
1639
|
+
return normalized || "unknown";
|
|
1640
|
+
};
|
|
1641
|
+
var pickDomainBucket = (state, domain = "") => {
|
|
1642
|
+
const domainKey = normalizeDomainKey(domain);
|
|
1643
|
+
const knownBucket = state.domainStats.get(domainKey);
|
|
1644
|
+
if (knownBucket) return knownBucket;
|
|
1645
|
+
if (state.domainStats.size < MAX_DOMAIN_BUCKETS) {
|
|
1646
|
+
const bucket2 = createDomainBucket(domainKey);
|
|
1647
|
+
state.domainStats.set(domainKey, bucket2);
|
|
1648
|
+
return bucket2;
|
|
1649
|
+
}
|
|
1650
|
+
const overflow = state.domainStats.get(OTHER_DOMAINS);
|
|
1651
|
+
if (overflow) return overflow;
|
|
1652
|
+
const bucket = createDomainBucket(OTHER_DOMAINS);
|
|
1653
|
+
state.domainStats.set(OTHER_DOMAINS, bucket);
|
|
1654
|
+
return bucket;
|
|
1655
|
+
};
|
|
1656
|
+
var pickTypeBucket = (state, resourceType = "other") => {
|
|
1657
|
+
const typeKey = normalizeResourceType(resourceType);
|
|
1658
|
+
const knownBucket = state.typeStats.get(typeKey);
|
|
1659
|
+
if (knownBucket) return knownBucket;
|
|
1660
|
+
const bucket = createTypeBucket(typeKey);
|
|
1661
|
+
state.typeStats.set(typeKey, bucket);
|
|
1662
|
+
return bucket;
|
|
1663
|
+
};
|
|
1664
|
+
var pickReasonBucket = (state, reason = "") => {
|
|
1665
|
+
const reasonKey = ensureReasonText(reason);
|
|
1666
|
+
const knownBucket = state.failedReasonStats.get(reasonKey);
|
|
1667
|
+
if (knownBucket) return knownBucket;
|
|
1668
|
+
if (state.failedReasonStats.size < MAX_REASON_BUCKETS) {
|
|
1669
|
+
const bucket2 = createReasonBucket(reasonKey);
|
|
1670
|
+
state.failedReasonStats.set(reasonKey, bucket2);
|
|
1671
|
+
return bucket2;
|
|
1672
|
+
}
|
|
1673
|
+
const overflow = state.failedReasonStats.get(OTHER_REASONS);
|
|
1674
|
+
if (overflow) return overflow;
|
|
1675
|
+
const bucket = createReasonBucket(OTHER_REASONS);
|
|
1676
|
+
state.failedReasonStats.set(OTHER_REASONS, bucket);
|
|
1677
|
+
return bucket;
|
|
1678
|
+
};
|
|
1679
|
+
var addRequestProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
|
|
1680
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1681
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1682
|
+
incrementBucketRequests(domainBucket, route);
|
|
1683
|
+
incrementBucketRequests(typeBucket, route);
|
|
1684
|
+
incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
|
|
1685
|
+
incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
|
|
1686
|
+
};
|
|
1687
|
+
var addUploadProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
|
|
1688
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1689
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1690
|
+
incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
|
|
1691
|
+
incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
|
|
1692
|
+
};
|
|
1693
|
+
var addDownloadProfile = (state, route, domain, resourceType, downloadBytes = 0) => {
|
|
1694
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1695
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1696
|
+
incrementBucketBytes(domainBucket, route, downloadBytes, "download", resourceType);
|
|
1697
|
+
incrementBucketBytes(typeBucket, route, downloadBytes, "download", resourceType);
|
|
1698
|
+
};
|
|
1699
|
+
var addFailedProfile = (state, route, domain, resourceType, reason = "unknown", canceled = false) => {
|
|
1700
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1701
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1702
|
+
const reasonBucket = pickReasonBucket(state, reason);
|
|
1703
|
+
incrementBucketFailed(domainBucket, canceled);
|
|
1704
|
+
incrementBucketFailed(typeBucket, canceled);
|
|
1705
|
+
reasonBucket.count += 1;
|
|
1706
|
+
if (ensureRoute(route) === "proxy") {
|
|
1707
|
+
reasonBucket.proxyCount += 1;
|
|
1708
|
+
} else {
|
|
1709
|
+
reasonBucket.directCount += 1;
|
|
1710
|
+
}
|
|
1711
|
+
if (canceled) {
|
|
1712
|
+
reasonBucket.canceledCount += 1;
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
var toRoundedRatio = (numerator, denominator) => {
|
|
1716
|
+
if (denominator <= 0) return 0;
|
|
1717
|
+
return Number((numerator / denominator * 100).toFixed(2));
|
|
1718
|
+
};
|
|
1719
|
+
var sortByBytesAndRequests = (left, right) => {
|
|
1720
|
+
if (right.totalBytes !== left.totalBytes) return right.totalBytes - left.totalBytes;
|
|
1721
|
+
if (right.requests !== left.requests) return right.requests - left.requests;
|
|
1722
|
+
return String(left.domain || left.resourceType || "").localeCompare(String(right.domain || right.resourceType || ""));
|
|
1723
|
+
};
|
|
1724
|
+
var buildTopDomains = (state) => {
|
|
1725
|
+
return Array.from(state.domainStats.values()).filter((item) => item && item.totalBytes > 0).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1726
|
+
domain: item.domain,
|
|
1727
|
+
requests: item.requests,
|
|
1728
|
+
proxyRequests: item.proxyRequests,
|
|
1729
|
+
directRequests: item.directRequests,
|
|
1730
|
+
uploadBytes: item.uploadBytes,
|
|
1731
|
+
downloadBytes: item.downloadBytes,
|
|
1732
|
+
totalBytes: item.totalBytes,
|
|
1733
|
+
proxyBytes: item.proxyBytes,
|
|
1734
|
+
directBytes: item.directBytes,
|
|
1735
|
+
failedRequests: item.failedRequests,
|
|
1736
|
+
canceledRequests: item.canceledRequests,
|
|
1737
|
+
staticBytes: item.staticBytes,
|
|
1738
|
+
backendBytes: item.backendBytes
|
|
1739
|
+
}));
|
|
1740
|
+
};
|
|
1741
|
+
var buildTopResourceTypes = (state) => {
|
|
1742
|
+
return Array.from(state.typeStats.values()).filter((item) => item && (item.totalBytes > 0 || item.requests > 0)).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1743
|
+
resourceType: item.resourceType,
|
|
1744
|
+
requests: item.requests,
|
|
1745
|
+
proxyRequests: item.proxyRequests,
|
|
1746
|
+
directRequests: item.directRequests,
|
|
1747
|
+
uploadBytes: item.uploadBytes,
|
|
1748
|
+
downloadBytes: item.downloadBytes,
|
|
1749
|
+
totalBytes: item.totalBytes,
|
|
1750
|
+
proxyBytes: item.proxyBytes,
|
|
1751
|
+
directBytes: item.directBytes,
|
|
1752
|
+
failedRequests: item.failedRequests,
|
|
1753
|
+
canceledRequests: item.canceledRequests
|
|
1754
|
+
}));
|
|
1755
|
+
};
|
|
1756
|
+
var buildFailedReasons = (state) => {
|
|
1757
|
+
return Array.from(state.failedReasonStats.values()).filter((item) => item && item.count > 0).sort((left, right) => {
|
|
1758
|
+
if (right.count !== left.count) return right.count - left.count;
|
|
1759
|
+
return String(left.reason || "").localeCompare(String(right.reason || ""));
|
|
1760
|
+
}).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1761
|
+
reason: item.reason,
|
|
1762
|
+
count: item.count,
|
|
1763
|
+
canceledCount: item.canceledCount,
|
|
1764
|
+
proxyCount: item.proxyCount,
|
|
1765
|
+
directCount: item.directCount
|
|
1766
|
+
}));
|
|
1767
|
+
};
|
|
1768
|
+
var buildProxyByPassHints = (state) => {
|
|
1769
|
+
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) => {
|
|
1770
|
+
if (right.proxyBytes !== left.proxyBytes) return right.proxyBytes - left.proxyBytes;
|
|
1771
|
+
return right.proxyRequests - left.proxyRequests;
|
|
1772
|
+
}).slice(0, MAX_HINT_ITEMS).map((item) => ({
|
|
1773
|
+
domain: item.domain,
|
|
1774
|
+
proxyBytes: item.proxyBytes,
|
|
1775
|
+
proxyRequests: item.proxyRequests,
|
|
1776
|
+
totalBytes: item.totalBytes,
|
|
1777
|
+
staticBytes: item.staticBytes,
|
|
1778
|
+
backendBytes: item.backendBytes,
|
|
1779
|
+
staticRatioPct: toRoundedRatio(item.staticBytes, item.totalBytes)
|
|
1780
|
+
}));
|
|
1781
|
+
};
|
|
1496
1782
|
var createTrafficMeter = ({
|
|
1497
1783
|
enableProxy = false,
|
|
1498
|
-
byPassRules = []
|
|
1784
|
+
byPassRules = [],
|
|
1785
|
+
debugMode = false
|
|
1499
1786
|
} = {}) => {
|
|
1500
1787
|
const state = createTrafficState();
|
|
1501
1788
|
const requestMap = /* @__PURE__ */ new Map();
|
|
1789
|
+
const orphanReceivedMap = /* @__PURE__ */ new Map();
|
|
1502
1790
|
const wsRouteMap = /* @__PURE__ */ new Map();
|
|
1791
|
+
const attachedPages = /* @__PURE__ */ new WeakSet();
|
|
1792
|
+
const attachedContexts = /* @__PURE__ */ new WeakSet();
|
|
1503
1793
|
const resolveRoute = (url = "") => {
|
|
1504
1794
|
return resolveRouteByProxy({
|
|
1505
1795
|
requestUrl: url,
|
|
@@ -1507,80 +1797,234 @@ var createTrafficMeter = ({
|
|
|
1507
1797
|
byPassRules
|
|
1508
1798
|
}).route;
|
|
1509
1799
|
};
|
|
1800
|
+
const fallbackRoute = () => enableProxy ? "proxy" : "direct";
|
|
1801
|
+
const debugLog = (message) => {
|
|
1802
|
+
if (!debugMode) return;
|
|
1803
|
+
logger6.info(`[\u9010\u8BF7\u6C42\u8C03\u8BD5] ${message}`);
|
|
1804
|
+
};
|
|
1805
|
+
const addFailed = (route, canceled = false) => {
|
|
1806
|
+
const normalizedRoute = ensureRoute(route);
|
|
1807
|
+
state.totalFailedRequests += 1;
|
|
1808
|
+
if (normalizedRoute === "proxy") {
|
|
1809
|
+
state.proxyFailedRequests += 1;
|
|
1810
|
+
} else {
|
|
1811
|
+
state.directFailedRequests += 1;
|
|
1812
|
+
}
|
|
1813
|
+
if (!canceled) return;
|
|
1814
|
+
state.totalCanceledRequests += 1;
|
|
1815
|
+
if (normalizedRoute === "proxy") {
|
|
1816
|
+
state.proxyCanceledRequests += 1;
|
|
1817
|
+
} else {
|
|
1818
|
+
state.directCanceledRequests += 1;
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
const finalizeByEncodedLength = (requestId, encodedDataLength, source = "finished") => {
|
|
1822
|
+
const safeRequestId = String(requestId || "");
|
|
1823
|
+
if (!safeRequestId) return;
|
|
1824
|
+
const requestState = requestMap.get(safeRequestId);
|
|
1825
|
+
const orphanReceived = toSafeNumber(orphanReceivedMap.get(safeRequestId));
|
|
1826
|
+
const encoded = toSafeNumber(encodedDataLength);
|
|
1827
|
+
if (requestState) {
|
|
1828
|
+
const routed2 = ensureRoute(requestState.route);
|
|
1829
|
+
const downloaded = toSafeNumber(requestState.downloadBytes);
|
|
1830
|
+
const delta2 = Math.max(0, encoded - downloaded);
|
|
1831
|
+
if (delta2 > 0) {
|
|
1832
|
+
addDownloadBytes(state, routed2, delta2);
|
|
1833
|
+
addDownloadProfile(state, routed2, requestState.domain, requestState.resourceType, delta2);
|
|
1834
|
+
requestState.downloadBytes = downloaded + delta2;
|
|
1835
|
+
}
|
|
1836
|
+
const uploadBytes = toSafeNumber(requestState.uploadBytes);
|
|
1837
|
+
const total = uploadBytes + toSafeNumber(requestState.downloadBytes);
|
|
1838
|
+
debugLog(
|
|
1839
|
+
`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 || "-"}`
|
|
1840
|
+
);
|
|
1841
|
+
requestMap.delete(safeRequestId);
|
|
1842
|
+
orphanReceivedMap.delete(safeRequestId);
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
const routed = fallbackRoute();
|
|
1846
|
+
const delta = Math.max(0, encoded - orphanReceived);
|
|
1847
|
+
if (delta > 0) {
|
|
1848
|
+
addDownloadBytes(state, routed, delta);
|
|
1849
|
+
addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", delta);
|
|
1850
|
+
}
|
|
1851
|
+
state.orphanFinishDeltaBytes += delta;
|
|
1852
|
+
if (routed === "proxy") {
|
|
1853
|
+
state.orphanProxyFinishDeltaBytes += delta;
|
|
1854
|
+
}
|
|
1855
|
+
debugLog(
|
|
1856
|
+
`final id=${safeRequestId} source=${source} status=orphan route=${routed} encoded=${formatBytes(encoded)} (${encoded}) delta=${formatBytes(delta)} (${delta})`
|
|
1857
|
+
);
|
|
1858
|
+
orphanReceivedMap.delete(safeRequestId);
|
|
1859
|
+
};
|
|
1510
1860
|
const recordRequest = (params = {}) => {
|
|
1511
1861
|
const requestId = String(params.requestId || "");
|
|
1512
1862
|
const request = params.request && typeof params.request === "object" ? params.request : {};
|
|
1513
|
-
const
|
|
1863
|
+
const url = String(request.url || "");
|
|
1864
|
+
const route = resolveRoute(url);
|
|
1865
|
+
const resourceType = normalizeResourceType(params.type || request.type || "other");
|
|
1866
|
+
const domain = normalizeDomainKey(parseHostname(url));
|
|
1867
|
+
if (requestId && requestMap.has(requestId)) {
|
|
1868
|
+
const redirectResponse = params.redirectResponse && typeof params.redirectResponse === "object" ? params.redirectResponse : null;
|
|
1869
|
+
finalizeByEncodedLength(
|
|
1870
|
+
requestId,
|
|
1871
|
+
redirectResponse ? redirectResponse.encodedDataLength : 0,
|
|
1872
|
+
"redirect"
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1514
1875
|
addRequests(state, route, 1);
|
|
1515
1876
|
const uploadBytes = estimateRequestBytes(request);
|
|
1516
1877
|
addUploadBytes(state, route, uploadBytes);
|
|
1878
|
+
addRequestProfile(state, route, domain, resourceType, uploadBytes);
|
|
1517
1879
|
if (requestId) {
|
|
1518
1880
|
requestMap.set(requestId, {
|
|
1519
|
-
route
|
|
1881
|
+
route: ensureRoute(route),
|
|
1882
|
+
resourceType,
|
|
1883
|
+
domain,
|
|
1884
|
+
url,
|
|
1885
|
+
uploadBytes,
|
|
1886
|
+
downloadBytes: 0
|
|
1520
1887
|
});
|
|
1521
1888
|
}
|
|
1889
|
+
debugLog(
|
|
1890
|
+
`request id=${requestId || "-"} route=${route} type=${resourceType} upload=${formatBytes(uploadBytes)} (${uploadBytes}) method=${String(request.method || "GET")} url=${url || "-"}`
|
|
1891
|
+
);
|
|
1522
1892
|
};
|
|
1523
|
-
const
|
|
1893
|
+
const recordDataReceived = (params = {}) => {
|
|
1524
1894
|
const requestId = String(params.requestId || "");
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1895
|
+
const bytes = toSafeNumber(params.encodedDataLength);
|
|
1896
|
+
if (bytes <= 0) return;
|
|
1897
|
+
if (!requestId) {
|
|
1898
|
+
const routed2 = fallbackRoute();
|
|
1899
|
+
addDownloadBytes(state, routed2, bytes);
|
|
1900
|
+
addDownloadProfile(state, routed2, UNKNOWN_DOMAIN, "other", bytes);
|
|
1901
|
+
state.orphanDataReceivedBytes += bytes;
|
|
1902
|
+
if (routed2 === "proxy") {
|
|
1903
|
+
state.orphanProxyDataReceivedBytes += bytes;
|
|
1904
|
+
}
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
const requestState = requestMap.get(requestId);
|
|
1908
|
+
if (requestState) {
|
|
1909
|
+
requestState.downloadBytes = toSafeNumber(requestState.downloadBytes) + bytes;
|
|
1910
|
+
addDownloadBytes(state, requestState.route, bytes);
|
|
1911
|
+
addDownloadProfile(state, requestState.route, requestState.domain, requestState.resourceType, bytes);
|
|
1912
|
+
return;
|
|
1531
1913
|
}
|
|
1914
|
+
const prev = toSafeNumber(orphanReceivedMap.get(requestId));
|
|
1915
|
+
orphanReceivedMap.set(requestId, prev + bytes);
|
|
1916
|
+
const routed = fallbackRoute();
|
|
1917
|
+
addDownloadBytes(state, routed, bytes);
|
|
1918
|
+
addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", bytes);
|
|
1919
|
+
state.orphanDataReceivedBytes += bytes;
|
|
1920
|
+
if (routed === "proxy") {
|
|
1921
|
+
state.orphanProxyDataReceivedBytes += bytes;
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
const recordLoadingFinished = (params = {}) => {
|
|
1925
|
+
finalizeByEncodedLength(params.requestId, params.encodedDataLength, "loadingFinished");
|
|
1532
1926
|
};
|
|
1533
1927
|
const recordRequestFailed = (params = {}) => {
|
|
1534
1928
|
const requestId = String(params.requestId || "");
|
|
1929
|
+
const requestState = requestId ? requestMap.get(requestId) : null;
|
|
1930
|
+
const canceled = Boolean(params.canceled);
|
|
1931
|
+
const reason = ensureReasonText(params.errorText);
|
|
1932
|
+
const routed = ensureRoute(requestState?.route || fallbackRoute());
|
|
1933
|
+
const resourceType = normalizeResourceType(requestState?.resourceType || "other");
|
|
1934
|
+
const domain = normalizeDomainKey(requestState?.domain || "");
|
|
1935
|
+
if (requestState) {
|
|
1936
|
+
addFailed(routed, canceled);
|
|
1937
|
+
addFailedProfile(state, routed, domain, resourceType, reason, canceled);
|
|
1938
|
+
const uploadBytes = toSafeNumber(requestState.uploadBytes);
|
|
1939
|
+
const downloadBytes = toSafeNumber(requestState.downloadBytes);
|
|
1940
|
+
const totalBytes = uploadBytes + downloadBytes;
|
|
1941
|
+
debugLog(
|
|
1942
|
+
`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 || "-"}`
|
|
1943
|
+
);
|
|
1944
|
+
} else {
|
|
1945
|
+
const orphanDownload = toSafeNumber(orphanReceivedMap.get(requestId));
|
|
1946
|
+
addFailed(routed, canceled);
|
|
1947
|
+
addFailedProfile(state, routed, UNKNOWN_DOMAIN, "other", reason, canceled);
|
|
1948
|
+
debugLog(
|
|
1949
|
+
`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=-`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1535
1952
|
if (requestId) {
|
|
1536
1953
|
requestMap.delete(requestId);
|
|
1954
|
+
orphanReceivedMap.delete(requestId);
|
|
1537
1955
|
}
|
|
1538
1956
|
};
|
|
1539
1957
|
const bindWebSocketRoute = (params = {}) => {
|
|
1540
1958
|
const requestId = String(params.requestId || "");
|
|
1541
1959
|
if (!requestId) return;
|
|
1542
|
-
const
|
|
1543
|
-
|
|
1960
|
+
const url = String(params.url || "");
|
|
1961
|
+
const route = resolveRoute(url);
|
|
1962
|
+
wsRouteMap.set(requestId, { route, url, domain: normalizeDomainKey(parseHostname(url)) });
|
|
1544
1963
|
};
|
|
1545
1964
|
const clearWebSocketRoute = (params = {}) => {
|
|
1546
1965
|
const requestId = String(params.requestId || "");
|
|
1547
1966
|
if (!requestId) return;
|
|
1548
1967
|
wsRouteMap.delete(requestId);
|
|
1549
1968
|
};
|
|
1550
|
-
const
|
|
1551
|
-
if (!requestId) return "
|
|
1552
|
-
|
|
1969
|
+
const getWebSocketMeta = (requestId = "") => {
|
|
1970
|
+
if (!requestId) return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
|
|
1971
|
+
const meta = wsRouteMap.get(requestId);
|
|
1972
|
+
if (!meta || typeof meta !== "object") {
|
|
1973
|
+
return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
|
|
1974
|
+
}
|
|
1975
|
+
return {
|
|
1976
|
+
route: ensureRoute(meta.route),
|
|
1977
|
+
url: String(meta.url || ""),
|
|
1978
|
+
domain: normalizeDomainKey(meta.domain)
|
|
1979
|
+
};
|
|
1553
1980
|
};
|
|
1554
1981
|
const recordWebSocketFrameSent = (params = {}) => {
|
|
1555
1982
|
const requestId = String(params.requestId || "");
|
|
1556
|
-
const route =
|
|
1983
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1557
1984
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1558
1985
|
const bytes = byteLength(payload || "");
|
|
1559
1986
|
addUploadBytes(state, route, bytes);
|
|
1987
|
+
addUploadProfile(state, route, domain, "websocket", bytes);
|
|
1988
|
+
debugLog(`ws-send id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
|
|
1560
1989
|
};
|
|
1561
1990
|
const recordWebSocketFrameReceived = (params = {}) => {
|
|
1562
1991
|
const requestId = String(params.requestId || "");
|
|
1563
|
-
const route =
|
|
1992
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1564
1993
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1565
1994
|
const bytes = byteLength(payload || "");
|
|
1566
1995
|
addDownloadBytes(state, route, bytes);
|
|
1996
|
+
addDownloadProfile(state, route, domain, "websocket", bytes);
|
|
1997
|
+
debugLog(`ws-recv id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
|
|
1567
1998
|
};
|
|
1568
1999
|
const attachPage = async (page) => {
|
|
1569
2000
|
if (!page || typeof page.context !== "function") return;
|
|
2001
|
+
if (attachedPages.has(page)) return;
|
|
2002
|
+
attachedPages.add(page);
|
|
1570
2003
|
try {
|
|
1571
2004
|
const context = page.context();
|
|
1572
2005
|
if (!context || typeof context.newCDPSession !== "function") {
|
|
1573
2006
|
return;
|
|
1574
2007
|
}
|
|
2008
|
+
if (!attachedContexts.has(context) && typeof context.on === "function") {
|
|
2009
|
+
attachedContexts.add(context);
|
|
2010
|
+
context.on("page", (nextPage) => {
|
|
2011
|
+
if (!nextPage) return;
|
|
2012
|
+
attachPage(nextPage).catch((error) => {
|
|
2013
|
+
logger6.warn(`\u5B50\u9875\u9762 CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
|
|
2014
|
+
});
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
1575
2017
|
const session = await context.newCDPSession(page);
|
|
1576
2018
|
await session.send("Network.enable");
|
|
1577
2019
|
session.on("Network.requestWillBeSent", recordRequest);
|
|
2020
|
+
session.on("Network.dataReceived", recordDataReceived);
|
|
1578
2021
|
session.on("Network.loadingFinished", recordLoadingFinished);
|
|
1579
2022
|
session.on("Network.loadingFailed", recordRequestFailed);
|
|
1580
2023
|
session.on("Network.webSocketCreated", bindWebSocketRoute);
|
|
1581
2024
|
session.on("Network.webSocketClosed", clearWebSocketRoute);
|
|
1582
2025
|
session.on("Network.webSocketFrameSent", recordWebSocketFrameSent);
|
|
1583
2026
|
session.on("Network.webSocketFrameReceived", recordWebSocketFrameReceived);
|
|
2027
|
+
debugLog("CDP \u76D1\u542C\u5DF2\u6CE8\u518C");
|
|
1584
2028
|
} catch (error) {
|
|
1585
2029
|
logger6.warn(`CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
|
|
1586
2030
|
}
|
|
@@ -1590,7 +2034,7 @@ var createTrafficMeter = ({
|
|
|
1590
2034
|
const proxyBytes = state.proxyUploadBytes + state.proxyDownloadBytes;
|
|
1591
2035
|
const directBytes = state.directUploadBytes + state.directDownloadBytes;
|
|
1592
2036
|
return {
|
|
1593
|
-
meter: "cdp",
|
|
2037
|
+
meter: "cdp-data-received-v3",
|
|
1594
2038
|
totalRequests: state.totalRequests,
|
|
1595
2039
|
proxyRequests: state.proxyRequests,
|
|
1596
2040
|
directRequests: state.directRequests,
|
|
@@ -1602,12 +2046,29 @@ var createTrafficMeter = ({
|
|
|
1602
2046
|
directDownloadBytes: state.directDownloadBytes,
|
|
1603
2047
|
totalBytes,
|
|
1604
2048
|
proxyBytes,
|
|
1605
|
-
directBytes
|
|
2049
|
+
directBytes,
|
|
2050
|
+
totalFailedRequests: state.totalFailedRequests,
|
|
2051
|
+
proxyFailedRequests: state.proxyFailedRequests,
|
|
2052
|
+
directFailedRequests: state.directFailedRequests,
|
|
2053
|
+
totalCanceledRequests: state.totalCanceledRequests,
|
|
2054
|
+
proxyCanceledRequests: state.proxyCanceledRequests,
|
|
2055
|
+
directCanceledRequests: state.directCanceledRequests,
|
|
2056
|
+
orphanDataReceivedBytes: state.orphanDataReceivedBytes,
|
|
2057
|
+
orphanProxyDataReceivedBytes: state.orphanProxyDataReceivedBytes,
|
|
2058
|
+
orphanFinishDeltaBytes: state.orphanFinishDeltaBytes,
|
|
2059
|
+
orphanProxyFinishDeltaBytes: state.orphanProxyFinishDeltaBytes,
|
|
2060
|
+
openRequestCount: requestMap.size,
|
|
2061
|
+
orphanOpenCount: orphanReceivedMap.size,
|
|
2062
|
+
topDomains: buildTopDomains(state),
|
|
2063
|
+
topResourceTypes: buildTopResourceTypes(state),
|
|
2064
|
+
failedReasons: buildFailedReasons(state),
|
|
2065
|
+
proxyBypassHints: buildProxyByPassHints(state)
|
|
1606
2066
|
};
|
|
1607
2067
|
};
|
|
1608
2068
|
const reset = () => {
|
|
1609
2069
|
Object.assign(state, createTrafficState());
|
|
1610
2070
|
requestMap.clear();
|
|
2071
|
+
orphanReceivedMap.clear();
|
|
1611
2072
|
wsRouteMap.clear();
|
|
1612
2073
|
};
|
|
1613
2074
|
return {
|
|
@@ -1657,6 +2118,7 @@ var Launch = {
|
|
|
1657
2118
|
proxyConfiguration = {},
|
|
1658
2119
|
log: logOptions = null,
|
|
1659
2120
|
runInHeadfulMode = false,
|
|
2121
|
+
debugMode = false,
|
|
1660
2122
|
isRunningOnApify = false,
|
|
1661
2123
|
launcher = null,
|
|
1662
2124
|
preNavigationHooks = [],
|
|
@@ -1666,7 +2128,8 @@ var Launch = {
|
|
|
1666
2128
|
const byPassRules = buildByPassDomainRules(byPassDomains);
|
|
1667
2129
|
const trafficMeter2 = createTrafficMeter({
|
|
1668
2130
|
enableProxy: Boolean(launchProxy),
|
|
1669
|
-
byPassRules
|
|
2131
|
+
byPassRules,
|
|
2132
|
+
debugMode: Boolean(debugMode)
|
|
1670
2133
|
});
|
|
1671
2134
|
setTrafficMeter(trafficMeter2);
|
|
1672
2135
|
const launchOptions = {
|
|
@@ -1684,14 +2147,19 @@ var Launch = {
|
|
|
1684
2147
|
logger7.info(
|
|
1685
2148
|
`[\u4EE3\u7406\u5DF2\u542F\u7528] \u4EE3\u7406\u670D\u52A1=${launchProxy.server} \u76F4\u8FDE\u57DF\u540D=${(byPassDomains || []).join(",")}`
|
|
1686
2149
|
);
|
|
2150
|
+
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`);
|
|
1687
2151
|
} else if (enableByPassLogger && enableProxy && !launchProxy) {
|
|
1688
2152
|
logger7.info(
|
|
1689
2153
|
`[\u4EE3\u7406\u672A\u542F\u7528] enable_proxy=true \u4F46 proxy_url \u4E3A\u7A7A`
|
|
1690
2154
|
);
|
|
2155
|
+
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`);
|
|
1691
2156
|
} else if (enableByPassLogger && !enableProxy && proxyUrl) {
|
|
1692
2157
|
logger7.info(
|
|
1693
2158
|
`[\u4EE3\u7406\u672A\u542F\u7528] enable_proxy=false \u4E14 proxy_url \u5DF2\u914D\u7F6E`
|
|
1694
2159
|
);
|
|
2160
|
+
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`);
|
|
2161
|
+
} else if (enableByPassLogger) {
|
|
2162
|
+
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`);
|
|
1695
2163
|
}
|
|
1696
2164
|
const onPageCreated = (page) => {
|
|
1697
2165
|
const recommendedGotoOptions = {
|