@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.js
CHANGED
|
@@ -1387,6 +1387,27 @@ var resolveRouteByProxy = ({
|
|
|
1387
1387
|
// src/traffic-meter.js
|
|
1388
1388
|
var logger6 = createInternalLogger("TrafficMeter");
|
|
1389
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
|
+
]);
|
|
1390
1411
|
var toSafeNumber = (value) => {
|
|
1391
1412
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
|
|
1392
1413
|
return Math.round(value);
|
|
@@ -1430,9 +1451,90 @@ var createTrafficState = () => ({
|
|
|
1430
1451
|
directUploadBytes: 0,
|
|
1431
1452
|
totalDownloadBytes: 0,
|
|
1432
1453
|
proxyDownloadBytes: 0,
|
|
1433
|
-
directDownloadBytes: 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()
|
|
1434
1468
|
});
|
|
1435
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
|
+
};
|
|
1436
1538
|
var addRequests = (state, route, count = 1) => {
|
|
1437
1539
|
const c = toSafeNumber(count);
|
|
1438
1540
|
if (c <= 0) return;
|
|
@@ -1466,13 +1568,201 @@ var addDownloadBytes = (state, route, bytes = 0) => {
|
|
|
1466
1568
|
}
|
|
1467
1569
|
state.directDownloadBytes += b;
|
|
1468
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
|
+
};
|
|
1469
1755
|
var createTrafficMeter = ({
|
|
1470
1756
|
enableProxy = false,
|
|
1471
|
-
byPassRules = []
|
|
1757
|
+
byPassRules = [],
|
|
1758
|
+
debugMode = false
|
|
1472
1759
|
} = {}) => {
|
|
1473
1760
|
const state = createTrafficState();
|
|
1474
1761
|
const requestMap = /* @__PURE__ */ new Map();
|
|
1762
|
+
const orphanReceivedMap = /* @__PURE__ */ new Map();
|
|
1475
1763
|
const wsRouteMap = /* @__PURE__ */ new Map();
|
|
1764
|
+
const attachedPages = /* @__PURE__ */ new WeakSet();
|
|
1765
|
+
const attachedContexts = /* @__PURE__ */ new WeakSet();
|
|
1476
1766
|
const resolveRoute = (url = "") => {
|
|
1477
1767
|
return resolveRouteByProxy({
|
|
1478
1768
|
requestUrl: url,
|
|
@@ -1480,80 +1770,234 @@ var createTrafficMeter = ({
|
|
|
1480
1770
|
byPassRules
|
|
1481
1771
|
}).route;
|
|
1482
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
|
+
};
|
|
1483
1833
|
const recordRequest = (params = {}) => {
|
|
1484
1834
|
const requestId = String(params.requestId || "");
|
|
1485
1835
|
const request = params.request && typeof params.request === "object" ? params.request : {};
|
|
1486
|
-
const
|
|
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
|
+
}
|
|
1487
1848
|
addRequests(state, route, 1);
|
|
1488
1849
|
const uploadBytes = estimateRequestBytes(request);
|
|
1489
1850
|
addUploadBytes(state, route, uploadBytes);
|
|
1851
|
+
addRequestProfile(state, route, domain, resourceType, uploadBytes);
|
|
1490
1852
|
if (requestId) {
|
|
1491
1853
|
requestMap.set(requestId, {
|
|
1492
|
-
route
|
|
1854
|
+
route: ensureRoute(route),
|
|
1855
|
+
resourceType,
|
|
1856
|
+
domain,
|
|
1857
|
+
url,
|
|
1858
|
+
uploadBytes,
|
|
1859
|
+
downloadBytes: 0
|
|
1493
1860
|
});
|
|
1494
1861
|
}
|
|
1862
|
+
debugLog(
|
|
1863
|
+
`request id=${requestId || "-"} route=${route} type=${resourceType} upload=${formatBytes(uploadBytes)} (${uploadBytes}) method=${String(request.method || "GET")} url=${url || "-"}`
|
|
1864
|
+
);
|
|
1495
1865
|
};
|
|
1496
|
-
const
|
|
1866
|
+
const recordDataReceived = (params = {}) => {
|
|
1497
1867
|
const requestId = String(params.requestId || "");
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
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;
|
|
1504
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");
|
|
1505
1899
|
};
|
|
1506
1900
|
const recordRequestFailed = (params = {}) => {
|
|
1507
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
|
+
}
|
|
1508
1925
|
if (requestId) {
|
|
1509
1926
|
requestMap.delete(requestId);
|
|
1927
|
+
orphanReceivedMap.delete(requestId);
|
|
1510
1928
|
}
|
|
1511
1929
|
};
|
|
1512
1930
|
const bindWebSocketRoute = (params = {}) => {
|
|
1513
1931
|
const requestId = String(params.requestId || "");
|
|
1514
1932
|
if (!requestId) return;
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1933
|
+
const url = String(params.url || "");
|
|
1934
|
+
const route = resolveRoute(url);
|
|
1935
|
+
wsRouteMap.set(requestId, { route, url, domain: normalizeDomainKey(parseHostname(url)) });
|
|
1517
1936
|
};
|
|
1518
1937
|
const clearWebSocketRoute = (params = {}) => {
|
|
1519
1938
|
const requestId = String(params.requestId || "");
|
|
1520
1939
|
if (!requestId) return;
|
|
1521
1940
|
wsRouteMap.delete(requestId);
|
|
1522
1941
|
};
|
|
1523
|
-
const
|
|
1524
|
-
if (!requestId) return "
|
|
1525
|
-
|
|
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
|
+
};
|
|
1526
1953
|
};
|
|
1527
1954
|
const recordWebSocketFrameSent = (params = {}) => {
|
|
1528
1955
|
const requestId = String(params.requestId || "");
|
|
1529
|
-
const route =
|
|
1956
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1530
1957
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1531
1958
|
const bytes = byteLength(payload || "");
|
|
1532
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 || "-"}`);
|
|
1533
1962
|
};
|
|
1534
1963
|
const recordWebSocketFrameReceived = (params = {}) => {
|
|
1535
1964
|
const requestId = String(params.requestId || "");
|
|
1536
|
-
const route =
|
|
1965
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1537
1966
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1538
1967
|
const bytes = byteLength(payload || "");
|
|
1539
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 || "-"}`);
|
|
1540
1971
|
};
|
|
1541
1972
|
const attachPage = async (page) => {
|
|
1542
1973
|
if (!page || typeof page.context !== "function") return;
|
|
1974
|
+
if (attachedPages.has(page)) return;
|
|
1975
|
+
attachedPages.add(page);
|
|
1543
1976
|
try {
|
|
1544
1977
|
const context = page.context();
|
|
1545
1978
|
if (!context || typeof context.newCDPSession !== "function") {
|
|
1546
1979
|
return;
|
|
1547
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
|
+
}
|
|
1548
1990
|
const session = await context.newCDPSession(page);
|
|
1549
1991
|
await session.send("Network.enable");
|
|
1550
1992
|
session.on("Network.requestWillBeSent", recordRequest);
|
|
1993
|
+
session.on("Network.dataReceived", recordDataReceived);
|
|
1551
1994
|
session.on("Network.loadingFinished", recordLoadingFinished);
|
|
1552
1995
|
session.on("Network.loadingFailed", recordRequestFailed);
|
|
1553
1996
|
session.on("Network.webSocketCreated", bindWebSocketRoute);
|
|
1554
1997
|
session.on("Network.webSocketClosed", clearWebSocketRoute);
|
|
1555
1998
|
session.on("Network.webSocketFrameSent", recordWebSocketFrameSent);
|
|
1556
1999
|
session.on("Network.webSocketFrameReceived", recordWebSocketFrameReceived);
|
|
2000
|
+
debugLog("CDP \u76D1\u542C\u5DF2\u6CE8\u518C");
|
|
1557
2001
|
} catch (error) {
|
|
1558
2002
|
logger6.warn(`CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
|
|
1559
2003
|
}
|
|
@@ -1563,7 +2007,7 @@ var createTrafficMeter = ({
|
|
|
1563
2007
|
const proxyBytes = state.proxyUploadBytes + state.proxyDownloadBytes;
|
|
1564
2008
|
const directBytes = state.directUploadBytes + state.directDownloadBytes;
|
|
1565
2009
|
return {
|
|
1566
|
-
meter: "cdp",
|
|
2010
|
+
meter: "cdp-data-received-v3",
|
|
1567
2011
|
totalRequests: state.totalRequests,
|
|
1568
2012
|
proxyRequests: state.proxyRequests,
|
|
1569
2013
|
directRequests: state.directRequests,
|
|
@@ -1575,12 +2019,29 @@ var createTrafficMeter = ({
|
|
|
1575
2019
|
directDownloadBytes: state.directDownloadBytes,
|
|
1576
2020
|
totalBytes,
|
|
1577
2021
|
proxyBytes,
|
|
1578
|
-
directBytes
|
|
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)
|
|
1579
2039
|
};
|
|
1580
2040
|
};
|
|
1581
2041
|
const reset = () => {
|
|
1582
2042
|
Object.assign(state, createTrafficState());
|
|
1583
2043
|
requestMap.clear();
|
|
2044
|
+
orphanReceivedMap.clear();
|
|
1584
2045
|
wsRouteMap.clear();
|
|
1585
2046
|
};
|
|
1586
2047
|
return {
|
|
@@ -1630,6 +2091,7 @@ var Launch = {
|
|
|
1630
2091
|
proxyConfiguration = {},
|
|
1631
2092
|
log: logOptions = null,
|
|
1632
2093
|
runInHeadfulMode = false,
|
|
2094
|
+
debugMode = false,
|
|
1633
2095
|
isRunningOnApify = false,
|
|
1634
2096
|
launcher = null,
|
|
1635
2097
|
preNavigationHooks = [],
|
|
@@ -1639,7 +2101,8 @@ var Launch = {
|
|
|
1639
2101
|
const byPassRules = buildByPassDomainRules(byPassDomains);
|
|
1640
2102
|
const trafficMeter2 = createTrafficMeter({
|
|
1641
2103
|
enableProxy: Boolean(launchProxy),
|
|
1642
|
-
byPassRules
|
|
2104
|
+
byPassRules,
|
|
2105
|
+
debugMode: Boolean(debugMode)
|
|
1643
2106
|
});
|
|
1644
2107
|
setTrafficMeter(trafficMeter2);
|
|
1645
2108
|
const launchOptions = {
|
|
@@ -1657,14 +2120,19 @@ var Launch = {
|
|
|
1657
2120
|
logger7.info(
|
|
1658
2121
|
`[\u4EE3\u7406\u5DF2\u542F\u7528] \u4EE3\u7406\u670D\u52A1=${launchProxy.server} \u76F4\u8FDE\u57DF\u540D=${(byPassDomains || []).join(",")}`
|
|
1659
2122
|
);
|
|
2123
|
+
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`);
|
|
1660
2124
|
} else if (enableByPassLogger && enableProxy && !launchProxy) {
|
|
1661
2125
|
logger7.info(
|
|
1662
2126
|
`[\u4EE3\u7406\u672A\u542F\u7528] enable_proxy=true \u4F46 proxy_url \u4E3A\u7A7A`
|
|
1663
2127
|
);
|
|
2128
|
+
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`);
|
|
1664
2129
|
} else if (enableByPassLogger && !enableProxy && proxyUrl) {
|
|
1665
2130
|
logger7.info(
|
|
1666
2131
|
`[\u4EE3\u7406\u672A\u542F\u7528] enable_proxy=false \u4E14 proxy_url \u5DF2\u914D\u7F6E`
|
|
1667
2132
|
);
|
|
2133
|
+
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`);
|
|
2134
|
+
} else if (enableByPassLogger) {
|
|
2135
|
+
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`);
|
|
1668
2136
|
}
|
|
1669
2137
|
const onPageCreated = (page) => {
|
|
1670
2138
|
const recommendedGotoOptions = {
|