@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/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, titlePattern, onDetected } = options;
1322
- if (!domSelector && !urlPattern && !titlePattern) {
1323
- throw new Error("[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector / urlPattern / titlePattern \u81F3\u5C11\u4E00\u4E2A");
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
- customExtensions: []
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 hasDirectDomains = directDomains.length > 0;
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
- logger9.start("setup", hasDirectDomains ? `\u76F4\u8FDE\u57DF\u540D: [${directDomains.length} \u4E2A] | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
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 isDirect = false;
1890
+ let isDirectByDomain = false;
1876
1891
  if (hasDirectDomains) {
1877
1892
  try {
1878
1893
  const hostname = new URL(url).hostname;
1879
- isDirect = directDomains.some((domain) => hostname.startsWith(domain));
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();