@skrillex1224/playwright-toolkit 2.1.135 → 2.1.137

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