@skrillex1224/playwright-toolkit 2.1.134 → 2.1.136
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/README.md +0 -6
- package/dist/index.cjs +86 -69
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +86 -69
- package/dist/index.js.map +2 -2
- package/index.d.ts +30 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1318,19 +1318,15 @@ var LiveView = {
|
|
|
1318
1318
|
import { v4 as uuidv4 } from "uuid";
|
|
1319
1319
|
var logger7 = createInternalLogger("Captcha");
|
|
1320
1320
|
function useCaptchaMonitor(page, options) {
|
|
1321
|
-
const { domSelector, urlPattern,
|
|
1322
|
-
if (!domSelector && !urlPattern
|
|
1323
|
-
throw new Error("[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector
|
|
1321
|
+
const { domSelector, urlPattern, onDetected } = options;
|
|
1322
|
+
if (!domSelector && !urlPattern) {
|
|
1323
|
+
throw new Error("[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A");
|
|
1324
1324
|
}
|
|
1325
1325
|
if (!onDetected || typeof onDetected !== "function") {
|
|
1326
1326
|
throw new Error("[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570");
|
|
1327
1327
|
}
|
|
1328
|
-
if (titlePattern && typeof titlePattern !== "string" && !(titlePattern instanceof RegExp)) {
|
|
1329
|
-
throw new Error("[CaptchaMonitor] titlePattern \u5FC5\u987B\u662F string \u6216 RegExp");
|
|
1330
|
-
}
|
|
1331
1328
|
let isHandled = false;
|
|
1332
1329
|
let frameHandler = null;
|
|
1333
|
-
let titleFrameHandler = null;
|
|
1334
1330
|
let exposedFunctionName = null;
|
|
1335
1331
|
const triggerDetected = async () => {
|
|
1336
1332
|
if (isHandled) return;
|
|
@@ -1420,51 +1416,6 @@ function useCaptchaMonitor(page, options) {
|
|
|
1420
1416
|
page.off("framenavigated", frameHandler);
|
|
1421
1417
|
});
|
|
1422
1418
|
}
|
|
1423
|
-
if (titlePattern) {
|
|
1424
|
-
let titleTimer = null;
|
|
1425
|
-
let lastTitle = null;
|
|
1426
|
-
const matchTitle = (title) => {
|
|
1427
|
-
if (!titlePattern) return false;
|
|
1428
|
-
const normalized = String(title || "");
|
|
1429
|
-
if (titlePattern instanceof RegExp) {
|
|
1430
|
-
titlePattern.lastIndex = 0;
|
|
1431
|
-
return titlePattern.test(normalized);
|
|
1432
|
-
}
|
|
1433
|
-
return normalized.includes(String(titlePattern));
|
|
1434
|
-
};
|
|
1435
|
-
const checkCurrentTitle = async (force = false) => {
|
|
1436
|
-
try {
|
|
1437
|
-
const currentTitle = await page.title();
|
|
1438
|
-
if (!force && currentTitle === lastTitle) return;
|
|
1439
|
-
lastTitle = currentTitle;
|
|
1440
|
-
if (!matchTitle(currentTitle)) return;
|
|
1441
|
-
await triggerDetected();
|
|
1442
|
-
} catch {
|
|
1443
|
-
}
|
|
1444
|
-
};
|
|
1445
|
-
titleFrameHandler = async (frame) => {
|
|
1446
|
-
if (frame !== page.mainFrame()) return;
|
|
1447
|
-
await checkCurrentTitle();
|
|
1448
|
-
};
|
|
1449
|
-
page.on("framenavigated", titleFrameHandler);
|
|
1450
|
-
checkCurrentTitle(true).catch(() => {
|
|
1451
|
-
});
|
|
1452
|
-
titleTimer = setInterval(() => {
|
|
1453
|
-
if (isHandled) return;
|
|
1454
|
-
checkCurrentTitle(false).catch(() => {
|
|
1455
|
-
});
|
|
1456
|
-
}, 1e3);
|
|
1457
|
-
logger7.success("useCaptchaMonitor", `Title \u76D1\u63A7\u5DF2\u542F\u7528: ${String(titlePattern)}`);
|
|
1458
|
-
cleanupFns.push(async () => {
|
|
1459
|
-
if (titleTimer) {
|
|
1460
|
-
clearInterval(titleTimer);
|
|
1461
|
-
titleTimer = null;
|
|
1462
|
-
}
|
|
1463
|
-
if (titleFrameHandler) {
|
|
1464
|
-
page.off("framenavigated", titleFrameHandler);
|
|
1465
|
-
}
|
|
1466
|
-
});
|
|
1467
|
-
}
|
|
1468
1419
|
return {
|
|
1469
1420
|
stop: async () => {
|
|
1470
1421
|
logger7.info("useCaptchaMonitor", "\u6B63\u5728\u505C\u6B62\u76D1\u63A7...");
|
|
@@ -1729,12 +1680,6 @@ var SHARED_HTTPS_AGENT = new HttpsAgent({
|
|
|
1729
1680
|
maxFreeSockets: 10,
|
|
1730
1681
|
rejectUnauthorized: false
|
|
1731
1682
|
});
|
|
1732
|
-
var DirectConfig = {
|
|
1733
|
-
/** 直连请求超时时间(秒) */
|
|
1734
|
-
directTimeout: 12,
|
|
1735
|
-
/** 静默扩展名:这些扩展名的直连成功日志用 debug 级别 */
|
|
1736
|
-
silentExtensions: [".js"]
|
|
1737
|
-
};
|
|
1738
1683
|
var ARCHIVE_EXTENSIONS = [".7z", ".zip", ".rar", ".gz", ".bz2", ".tar", ".zst"];
|
|
1739
1684
|
var EXECUTABLE_EXTENSIONS = [".exe", ".apk", ".bin", ".dmg", ".jar", ".class"];
|
|
1740
1685
|
var DOCUMENT_EXTENSIONS = [".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".csv"];
|
|
@@ -1760,7 +1705,14 @@ var IMAGE_EXTENSIONS = [
|
|
|
1760
1705
|
var MEDIA_EXTENSIONS = [".mp3", ".mp4", ".avi", ".mkv", ".webm", ".midi", ".mid", ".ogg", ".flac", ".swf"];
|
|
1761
1706
|
var FONT_EXTENSIONS = [".woff", ".woff2", ".ttf", ".otf"];
|
|
1762
1707
|
var CSS_EXTENSIONS = [".css"];
|
|
1708
|
+
var JS_EXTENSIONS = [".js"];
|
|
1763
1709
|
var OTHER_EXTENSIONS = [".ps", ".iso"];
|
|
1710
|
+
var DirectConfig = {
|
|
1711
|
+
/** 直连请求超时时间(秒) */
|
|
1712
|
+
directTimeout: 12,
|
|
1713
|
+
/** 静默扩展名:这些扩展名的直连成功日志用 debug 级别 */
|
|
1714
|
+
silentExtensions: JS_EXTENSIONS
|
|
1715
|
+
};
|
|
1764
1716
|
var DEFAULT_BLOCKING_CONFIG = {
|
|
1765
1717
|
/** 屏蔽压缩包 */
|
|
1766
1718
|
blockArchive: true,
|
|
@@ -1777,9 +1729,29 @@ var DEFAULT_BLOCKING_CONFIG = {
|
|
|
1777
1729
|
/** 屏蔽 CSS (注意:可能影响页面视觉效果) */
|
|
1778
1730
|
blockCss: false,
|
|
1779
1731
|
/** 屏蔽其他资源 */
|
|
1780
|
-
blockOther: true
|
|
1781
|
-
|
|
1782
|
-
|
|
1732
|
+
blockOther: true
|
|
1733
|
+
};
|
|
1734
|
+
var DEFAULT_DIRECT_CONFIG = {
|
|
1735
|
+
/** 直连域名 */
|
|
1736
|
+
domains: [],
|
|
1737
|
+
/** 直连压缩包 */
|
|
1738
|
+
directAllArchive: false,
|
|
1739
|
+
/** 直连可执行文件 */
|
|
1740
|
+
directAllExecutable: false,
|
|
1741
|
+
/** 直连办公文档 */
|
|
1742
|
+
directAllDocument: false,
|
|
1743
|
+
/** 直连图片 */
|
|
1744
|
+
directAllImage: false,
|
|
1745
|
+
/** 直连音视频 */
|
|
1746
|
+
directAllMedia: false,
|
|
1747
|
+
/** 直连字体 */
|
|
1748
|
+
directAllFont: false,
|
|
1749
|
+
/** 直连 CSS */
|
|
1750
|
+
directAllCss: false,
|
|
1751
|
+
/** 直连 JS */
|
|
1752
|
+
directAllJs: false,
|
|
1753
|
+
/** 直连其他资源 */
|
|
1754
|
+
directAllOther: false
|
|
1783
1755
|
};
|
|
1784
1756
|
var SHARED_GOT_OPTIONS = {
|
|
1785
1757
|
http2: false,
|
|
@@ -1807,9 +1779,6 @@ var Interception = {
|
|
|
1807
1779
|
if (mergedConfig.blockFont) extensions.push(...FONT_EXTENSIONS);
|
|
1808
1780
|
if (mergedConfig.blockCss) extensions.push(...CSS_EXTENSIONS);
|
|
1809
1781
|
if (mergedConfig.blockOther) extensions.push(...OTHER_EXTENSIONS);
|
|
1810
|
-
if (mergedConfig.customExtensions?.length > 0) {
|
|
1811
|
-
extensions.push(...mergedConfig.customExtensions);
|
|
1812
|
-
}
|
|
1813
1782
|
return [...new Set(extensions)];
|
|
1814
1783
|
},
|
|
1815
1784
|
/**
|
|
@@ -1829,12 +1798,34 @@ var Interception = {
|
|
|
1829
1798
|
other: { name: "\u5176\u4ED6\u8D44\u6E90", extensions: OTHER_EXTENSIONS }
|
|
1830
1799
|
};
|
|
1831
1800
|
},
|
|
1801
|
+
/**
|
|
1802
|
+
* 根据配置生成需要直连的扩展名列表
|
|
1803
|
+
*
|
|
1804
|
+
* @param {Object} [config] - 直连扩展名配置
|
|
1805
|
+
* @returns {string[]} 需要直连的扩展名列表
|
|
1806
|
+
*/
|
|
1807
|
+
getDirectExtensions(config = {}) {
|
|
1808
|
+
const mergedConfig = { ...DEFAULT_DIRECT_CONFIG, ...config };
|
|
1809
|
+
const extensions = [];
|
|
1810
|
+
if (mergedConfig.directAllArchive) extensions.push(...ARCHIVE_EXTENSIONS);
|
|
1811
|
+
if (mergedConfig.directAllExecutable) extensions.push(...EXECUTABLE_EXTENSIONS);
|
|
1812
|
+
if (mergedConfig.directAllDocument) extensions.push(...DOCUMENT_EXTENSIONS);
|
|
1813
|
+
if (mergedConfig.directAllImage) extensions.push(...IMAGE_EXTENSIONS);
|
|
1814
|
+
if (mergedConfig.directAllMedia) extensions.push(...MEDIA_EXTENSIONS);
|
|
1815
|
+
if (mergedConfig.directAllFont) extensions.push(...FONT_EXTENSIONS);
|
|
1816
|
+
if (mergedConfig.directAllCss) extensions.push(...CSS_EXTENSIONS);
|
|
1817
|
+
if (mergedConfig.directAllJs) extensions.push(...JS_EXTENSIONS);
|
|
1818
|
+
if (mergedConfig.directAllOther) extensions.push(...OTHER_EXTENSIONS);
|
|
1819
|
+
return [...new Set(extensions)];
|
|
1820
|
+
},
|
|
1832
1821
|
/**
|
|
1833
1822
|
* 设置网络拦截规则(资源屏蔽 + CDN 直连)
|
|
1834
1823
|
*
|
|
1835
1824
|
* @param {import('playwright').Page} page - Playwright Page 对象
|
|
1836
1825
|
* @param {Object} [options] - 配置选项
|
|
1837
|
-
* @param {string[]} [options.directDomains] -
|
|
1826
|
+
* @param {string[]} [options.directDomains] - [已过时] 需要直连的域名列表,请改用 directConfig.domains
|
|
1827
|
+
* @param {Object} [options.directConfig] - 直连配置(参考 blockingConfig),支持 domains/directAllXxx 系列开关
|
|
1828
|
+
* @param {boolean|Function} [options.enable] - 是否启用拦截处理(false 时始终 continue)
|
|
1838
1829
|
* @param {Object} [options.blockingConfig] - 资源屏蔽配置
|
|
1839
1830
|
* @param {boolean} [options.fallbackToProxy] - 直连失败时是否回退到代理(默认 true)
|
|
1840
1831
|
* @returns {Promise<void>}
|
|
@@ -1842,12 +1833,27 @@ var Interception = {
|
|
|
1842
1833
|
async setup(page, options = {}) {
|
|
1843
1834
|
const {
|
|
1844
1835
|
directDomains = [],
|
|
1836
|
+
directConfig = {},
|
|
1837
|
+
enable = true,
|
|
1845
1838
|
blockingConfig = {},
|
|
1846
1839
|
fallbackToProxy = true
|
|
1847
1840
|
} = options;
|
|
1848
1841
|
const mergedBlockingConfig = { ...DEFAULT_BLOCKING_CONFIG, ...blockingConfig };
|
|
1842
|
+
const mergedDirectConfig = { ...DEFAULT_DIRECT_CONFIG, ...directConfig };
|
|
1849
1843
|
const blockedExtensions = this.getBlockedExtensions(mergedBlockingConfig);
|
|
1850
|
-
const
|
|
1844
|
+
const configuredDirectExtensions = this.getDirectExtensions(mergedDirectConfig);
|
|
1845
|
+
const normalizedDirectDomains = Array.from(
|
|
1846
|
+
new Set(
|
|
1847
|
+
[...directDomains, ...mergedDirectConfig.domains || []].map((domain) => String(domain || "").toLowerCase().trim()).filter(Boolean)
|
|
1848
|
+
)
|
|
1849
|
+
);
|
|
1850
|
+
const hasDirectDomains = normalizedDirectDomains.length > 0;
|
|
1851
|
+
const normalizedDirectExtensions = Array.from(
|
|
1852
|
+
new Set(
|
|
1853
|
+
configuredDirectExtensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
|
|
1854
|
+
)
|
|
1855
|
+
);
|
|
1856
|
+
const hasDirectExtensions = normalizedDirectExtensions.length > 0;
|
|
1851
1857
|
const enabledCategories = [];
|
|
1852
1858
|
if (mergedBlockingConfig.blockArchive) enabledCategories.push("\u538B\u7F29\u5305");
|
|
1853
1859
|
if (mergedBlockingConfig.blockExecutable) enabledCategories.push("\u53EF\u6267\u884C\u6587\u4EF6");
|
|
@@ -1857,7 +1863,10 @@ var Interception = {
|
|
|
1857
1863
|
if (mergedBlockingConfig.blockFont) enabledCategories.push("\u5B57\u4F53");
|
|
1858
1864
|
if (mergedBlockingConfig.blockCss) enabledCategories.push("CSS");
|
|
1859
1865
|
if (mergedBlockingConfig.blockOther) enabledCategories.push("\u5176\u4ED6");
|
|
1860
|
-
|
|
1866
|
+
const directRules = [];
|
|
1867
|
+
if (hasDirectDomains) directRules.push(`\u76F4\u8FDE\u57DF\u540D: [${normalizedDirectDomains.length} \u4E2A]`);
|
|
1868
|
+
if (hasDirectExtensions) directRules.push(`\u76F4\u8FDE\u6269\u5C55\u540D: [${normalizedDirectExtensions.join(", ")}]`);
|
|
1869
|
+
logger9.start("setup", directRules.length > 0 ? `${directRules.join(" | ")} | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
|
|
1861
1870
|
await page.route("**/*", async (route) => {
|
|
1862
1871
|
let handled = false;
|
|
1863
1872
|
try {
|
|
@@ -1865,6 +1874,12 @@ var Interception = {
|
|
|
1865
1874
|
const url = request.url();
|
|
1866
1875
|
const urlLower = url.toLowerCase();
|
|
1867
1876
|
const urlPath = urlLower.split("?")[0];
|
|
1877
|
+
const interceptionEnabled = typeof enable === "function" ? Boolean(enable()) : Boolean(enable);
|
|
1878
|
+
if (!interceptionEnabled) {
|
|
1879
|
+
await safeContinue(route);
|
|
1880
|
+
handled = true;
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1868
1883
|
const isSilent = DirectConfig.silentExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1869
1884
|
const shouldBlock = blockedExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1870
1885
|
if (shouldBlock) {
|
|
@@ -1872,14 +1887,16 @@ var Interception = {
|
|
|
1872
1887
|
handled = true;
|
|
1873
1888
|
return;
|
|
1874
1889
|
}
|
|
1875
|
-
let
|
|
1890
|
+
let isDirectByDomain = false;
|
|
1876
1891
|
if (hasDirectDomains) {
|
|
1877
1892
|
try {
|
|
1878
1893
|
const hostname = new URL(url).hostname;
|
|
1879
|
-
|
|
1894
|
+
isDirectByDomain = normalizedDirectDomains.some((domain) => hostname.startsWith(domain));
|
|
1880
1895
|
} catch (e) {
|
|
1881
1896
|
}
|
|
1882
1897
|
}
|
|
1898
|
+
const isDirectByExtension = hasDirectExtensions ? normalizedDirectExtensions.some((ext) => urlPath.endsWith(ext)) : false;
|
|
1899
|
+
const isDirect = isDirectByDomain || isDirectByExtension;
|
|
1883
1900
|
if (isDirect) {
|
|
1884
1901
|
try {
|
|
1885
1902
|
const reqHeaders = await request.allHeaders();
|