@skrillex1224/playwright-toolkit 2.1.136 → 2.1.138

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
@@ -1432,7 +1432,7 @@ var Captcha = {
1432
1432
 
1433
1433
  // src/sse.js
1434
1434
  import https from "https";
1435
- import { URL as URL2 } from "url";
1435
+ import { URL } from "url";
1436
1436
  var logger8 = createInternalLogger("Sse");
1437
1437
  var Sse = {
1438
1438
  /**
@@ -1542,7 +1542,7 @@ var Sse = {
1542
1542
  try {
1543
1543
  const headers = await request.allHeaders();
1544
1544
  const postData = request.postData();
1545
- const urlObj = new URL2(request.url());
1545
+ const urlObj = new URL(request.url());
1546
1546
  delete headers["accept-encoding"];
1547
1547
  delete headers["content-length"];
1548
1548
  const reqOptions = {
@@ -1825,7 +1825,6 @@ var Interception = {
1825
1825
  * @param {Object} [options] - 配置选项
1826
1826
  * @param {string[]} [options.directDomains] - [已过时] 需要直连的域名列表,请改用 directConfig.domains
1827
1827
  * @param {Object} [options.directConfig] - 直连配置(参考 blockingConfig),支持 domains/directAllXxx 系列开关
1828
- * @param {boolean|Function} [options.enable] - 是否启用拦截处理(false 时始终 continue)
1829
1828
  * @param {Object} [options.blockingConfig] - 资源屏蔽配置
1830
1829
  * @param {boolean} [options.fallbackToProxy] - 直连失败时是否回退到代理(默认 true)
1831
1830
  * @returns {Promise<void>}
@@ -1834,7 +1833,6 @@ var Interception = {
1834
1833
  const {
1835
1834
  directDomains = [],
1836
1835
  directConfig = {},
1837
- enable = true,
1838
1836
  blockingConfig = {},
1839
1837
  fallbackToProxy = true
1840
1838
  } = options;
@@ -1854,6 +1852,16 @@ var Interception = {
1854
1852
  )
1855
1853
  );
1856
1854
  const hasDirectExtensions = normalizedDirectExtensions.length > 0;
1855
+ const blockedExtensionsSet = new Set(blockedExtensions);
1856
+ const directOnlyExtensions = normalizedDirectExtensions.filter((ext) => !blockedExtensionsSet.has(ext));
1857
+ const directRouteMatchers = [
1858
+ createDomainsRegex(normalizedDirectDomains),
1859
+ createExtensionsRegex(directOnlyExtensions)
1860
+ ].filter(Boolean);
1861
+ const blockRouteMatchers = [createExtensionsRegex(blockedExtensions)].filter(Boolean);
1862
+ const hasDirectRules = directRouteMatchers.length > 0;
1863
+ const hasBlockRules = blockRouteMatchers.length > 0;
1864
+ const hasInterceptionRules = hasDirectRules || hasBlockRules;
1857
1865
  const enabledCategories = [];
1858
1866
  if (mergedBlockingConfig.blockArchive) enabledCategories.push("\u538B\u7F29\u5305");
1859
1867
  if (mergedBlockingConfig.blockExecutable) enabledCategories.push("\u53EF\u6267\u884C\u6587\u4EF6");
@@ -1867,110 +1875,83 @@ var Interception = {
1867
1875
  if (hasDirectDomains) directRules.push(`\u76F4\u8FDE\u57DF\u540D: [${normalizedDirectDomains.length} \u4E2A]`);
1868
1876
  if (hasDirectExtensions) directRules.push(`\u76F4\u8FDE\u6269\u5C55\u540D: [${normalizedDirectExtensions.join(", ")}]`);
1869
1877
  logger9.start("setup", directRules.length > 0 ? `${directRules.join(" | ")} | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
1870
- await page.route("**/*", async (route) => {
1871
- let handled = false;
1878
+ if (!hasInterceptionRules) {
1879
+ logger9.info("\u65E0\u547D\u4E2D\u89C4\u5219\uFF0C\u8DF3\u8FC7 page.route \u6CE8\u518C");
1880
+ return;
1881
+ }
1882
+ const directRouteHandler = async (route) => {
1872
1883
  try {
1873
1884
  const request = route.request();
1874
1885
  const url = request.url();
1875
1886
  const urlLower = url.toLowerCase();
1876
1887
  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
- }
1883
1888
  const isSilent = DirectConfig.silentExtensions.some((ext) => urlPath.endsWith(ext));
1884
- const shouldBlock = blockedExtensions.some((ext) => urlPath.endsWith(ext));
1885
- if (shouldBlock) {
1886
- await route.abort();
1887
- handled = true;
1888
- return;
1889
- }
1890
- let isDirectByDomain = false;
1891
- if (hasDirectDomains) {
1892
- try {
1893
- const hostname = new URL(url).hostname;
1894
- isDirectByDomain = normalizedDirectDomains.some((domain) => hostname.startsWith(domain));
1895
- } catch (e) {
1896
- }
1897
- }
1898
- const isDirectByExtension = hasDirectExtensions ? normalizedDirectExtensions.some((ext) => urlPath.endsWith(ext)) : false;
1899
- const isDirect = isDirectByDomain || isDirectByExtension;
1900
- if (isDirect) {
1901
- try {
1902
- const reqHeaders = await request.allHeaders();
1903
- delete reqHeaders["host"];
1904
- const resolvedAcceptLanguage = reqHeaders["accept-language"] || "";
1905
- const userAgent = reqHeaders["user-agent"] || "";
1906
- const method = request.method();
1907
- const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
1908
- const response = await gotScraping({
1909
- ...SHARED_GOT_OPTIONS,
1910
- // 应用通用配置
1911
- url,
1912
- method,
1913
- headers: reqHeaders,
1914
- body: postData,
1915
- responseType: "buffer",
1916
- // 强制获取 Buffer
1917
- // 移除手动 TLS 指纹配置,使用 got-scraping 默认的高质量指纹
1918
- // headerGeneratorOptions: ...
1919
- // 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
1920
- agent: {
1921
- http: SHARED_HTTP_AGENT,
1922
- https: SHARED_HTTPS_AGENT
1923
- },
1924
- // 超时时间
1925
- timeout: { request: DirectConfig.directTimeout * 1e3 }
1926
- });
1927
- const resHeaders = {};
1928
- for (const [key, value] of Object.entries(response.headers)) {
1929
- if (Array.isArray(value)) {
1930
- resHeaders[key] = value.join(", ");
1931
- } else if (value) {
1932
- resHeaders[key] = String(value);
1933
- }
1934
- }
1935
- delete resHeaders["content-encoding"];
1936
- delete resHeaders["content-length"];
1937
- delete resHeaders["transfer-encoding"];
1938
- delete resHeaders["connection"];
1939
- delete resHeaders["keep-alive"];
1940
- isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
1941
- await safeFulfill(route, {
1942
- status: response.statusCode,
1943
- headers: resHeaders,
1944
- body: response.body
1945
- });
1946
- handled = true;
1947
- return;
1948
- } catch (e) {
1949
- const isTimeout = e.code === "ETIMEDOUT" || e.message.toLowerCase().includes("timeout");
1950
- const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
1951
- const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${e.message}`;
1952
- logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}: ${urlPath}`);
1953
- if (fallbackToProxy) {
1954
- await safeContinue(route);
1955
- } else {
1956
- await route.abort();
1957
- }
1958
- handled = true;
1959
- return;
1889
+ const reqHeaders = await request.allHeaders();
1890
+ delete reqHeaders["host"];
1891
+ const method = request.method();
1892
+ const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
1893
+ const response = await gotScraping({
1894
+ ...SHARED_GOT_OPTIONS,
1895
+ // 应用通用配置
1896
+ url,
1897
+ method,
1898
+ headers: reqHeaders,
1899
+ body: postData,
1900
+ responseType: "buffer",
1901
+ // 强制获取 Buffer
1902
+ // 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
1903
+ agent: {
1904
+ http: SHARED_HTTP_AGENT,
1905
+ https: SHARED_HTTPS_AGENT
1906
+ },
1907
+ // 超时时间
1908
+ timeout: { request: DirectConfig.directTimeout * 1e3 }
1909
+ });
1910
+ const resHeaders = {};
1911
+ for (const [key, value] of Object.entries(response.headers)) {
1912
+ if (Array.isArray(value)) {
1913
+ resHeaders[key] = value.join(", ");
1914
+ } else if (value) {
1915
+ resHeaders[key] = String(value);
1960
1916
  }
1961
1917
  }
1962
- await safeContinue(route);
1963
- handled = true;
1918
+ delete resHeaders["content-encoding"];
1919
+ delete resHeaders["content-length"];
1920
+ delete resHeaders["transfer-encoding"];
1921
+ delete resHeaders["connection"];
1922
+ delete resHeaders["keep-alive"];
1923
+ isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
1924
+ await safeFulfill(route, {
1925
+ status: response.statusCode,
1926
+ headers: resHeaders,
1927
+ body: response.body
1928
+ });
1964
1929
  } catch (err) {
1965
- logger9.warn(`\u8DEF\u7531\u5904\u7406\u5F02\u5E38: ${err.message}`);
1966
- if (!handled) {
1967
- try {
1968
- await route.continue();
1969
- } catch (_) {
1970
- }
1930
+ const message = String(err?.message || "");
1931
+ const isTimeout = err?.code === "ETIMEDOUT" || message.toLowerCase().includes("timeout");
1932
+ const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
1933
+ const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${message}`;
1934
+ logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}`);
1935
+ if (fallbackToProxy) {
1936
+ await safeContinue(route);
1937
+ } else {
1938
+ await safeAbort(route);
1971
1939
  }
1972
1940
  }
1973
- });
1941
+ };
1942
+ const blockRouteHandler = async (route) => {
1943
+ await safeAbort(route);
1944
+ };
1945
+ if (hasDirectRules) {
1946
+ for (const matcher of directRouteMatchers) {
1947
+ await page.route(matcher, directRouteHandler);
1948
+ }
1949
+ }
1950
+ if (hasBlockRules) {
1951
+ for (const matcher of blockRouteMatchers) {
1952
+ await page.route(matcher, blockRouteHandler);
1953
+ }
1954
+ }
1974
1955
  }
1975
1956
  };
1976
1957
  async function safeFulfill(route, options) {
@@ -1990,10 +1971,37 @@ async function safeContinue(route) {
1990
1971
  }
1991
1972
  }
1992
1973
  }
1974
+ async function safeAbort(route) {
1975
+ try {
1976
+ await route.abort();
1977
+ } catch (error) {
1978
+ if (!isIgnorableError(error)) {
1979
+ }
1980
+ }
1981
+ }
1993
1982
  function isIgnorableError(error) {
1994
1983
  const msg = error.message;
1995
1984
  return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
1996
1985
  }
1986
+ function createExtensionsRegex(extensions = []) {
1987
+ const normalized = Array.from(new Set(
1988
+ extensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
1989
+ ));
1990
+ if (!normalized.length) return null;
1991
+ const escaped = normalized.map((ext) => escapeRegex(ext));
1992
+ return new RegExp(`(?:${escaped.join("|")})(?:\\?.*)?$`, "i");
1993
+ }
1994
+ function createDomainsRegex(domains = []) {
1995
+ const normalized = Array.from(new Set(
1996
+ domains.map((domain) => String(domain || "").toLowerCase().trim()).filter(Boolean)
1997
+ ));
1998
+ if (!normalized.length) return null;
1999
+ const domainParts = normalized.map((domain) => `${escapeRegex(domain)}[^/:?#]*`);
2000
+ return new RegExp(`^https?:\\/\\/(?:${domainParts.join("|")})(?::\\d+)?(?:[/?#]|$)`, "i");
2001
+ }
2002
+ function escapeRegex(value) {
2003
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2004
+ }
1997
2005
 
1998
2006
  // src/mutation.js
1999
2007
  import { v4 as uuidv42 } from "uuid";