arn-browser 0.1.15 → 0.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arn-browser",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "A lightweight, browser autmation helper.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -32,6 +32,13 @@ export interface PwRouteOptions {
32
32
  /** Enable caching for requests */
33
33
  useCache?: boolean;
34
34
 
35
+ /**
36
+ * Proxy for custom fetch requests (only used when useGot is true).
37
+ * String: "http://host:port", "socks5://user:pass@host:port"
38
+ * Object: { type, host, port, user, pass }
39
+ */
40
+ proxy?: string | { type?: string; host: string; port: number; user?: string; pass?: string } | null;
41
+
35
42
  /** Data object for Doublelist message interception (POST logic) */
36
43
  m4w_send_on_post?: Record<string, any> | null;
37
44
 
@@ -2,6 +2,8 @@
2
2
  import superagent from "superagent";
3
3
  import { FiltersEngine, Request } from "@ghostery/adblocker";
4
4
  import fetch from "node-fetch";
5
+ import { HttpsProxyAgent } from "https-proxy-agent";
6
+ import { SocksProxyAgent } from "socks-proxy-agent";
5
7
  import NodeCache from "node-cache";
6
8
 
7
9
  let AdBlockEngine;
@@ -37,6 +39,38 @@ export function pwCacheLogs(log_cache = globalCache, interval = 10) {
37
39
  }
38
40
  }
39
41
 
42
+ /**
43
+ * Normalizes proxy input (string or object) into a URL string.
44
+ * Accepts:
45
+ * - String: "http://host:port", "socks5://user:pass@host:port", etc.
46
+ * - Object: { type, host, port, user, pass }
47
+ * @param {string|Object|null} proxy
48
+ * @returns {string|null} - Proxy URL string or null
49
+ */
50
+ function formatProxyUrl(proxy) {
51
+ if (!proxy) return null;
52
+ if (typeof proxy === "string") return proxy;
53
+ if (typeof proxy === "object") {
54
+ const { type = "http", host, port, user, pass } = proxy;
55
+ const auth = user && pass ? `${user}:${pass}@` : "";
56
+ return `${type}://${auth}${host}:${port}`;
57
+ }
58
+ return null;
59
+ }
60
+
61
+ /**
62
+ * Creates an HTTP agent for the given proxy URL.
63
+ * @param {string|null} proxyUrl
64
+ * @returns {Object|null} - HttpsProxyAgent or SocksProxyAgent instance
65
+ */
66
+ function createProxyAgent(proxyUrl) {
67
+ if (!proxyUrl) return null;
68
+ if (proxyUrl.startsWith("socks")) {
69
+ return new SocksProxyAgent(proxyUrl);
70
+ }
71
+ return new HttpsProxyAgent(proxyUrl);
72
+ }
73
+
40
74
  /**
41
75
  * Function to fetch resources using Superagent library with optional caching.
42
76
  * This mimics the browser's request but handles it in Node.js to allow caching or header manipulation.
@@ -46,9 +80,10 @@ export function pwCacheLogs(log_cache = globalCache, interval = 10) {
46
80
  * @param {string} method - HTTP method (GET, POST, etc.)
47
81
  * @param {boolean} useFullUrl - Whether to use the full URL as cache key or just origin+path
48
82
  * @param {string|false} logger - Log level: "info" (success+error), "error" (errors only), false (no logs)
83
+ * @param {Object|null} proxyAgent - Proxy agent to use for the request
49
84
  * @returns {Promise<Object>} - The response object containing status, headers, and body
50
85
  */
51
- async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl, logger) {
86
+ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl, logger, proxyAgent) {
52
87
  // Determine the cache key based on configuration
53
88
  let mainUrl = new URL(url).origin + new URL(url).pathname;
54
89
  if (useFullUrl) {
@@ -67,18 +102,29 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
67
102
  try {
68
103
  // Fetch the resource using superagent
69
104
  // buffer(true) ensures we get the raw binary data (essential for images/fonts)
70
- const response = await superagent(method, url).set(requestHeaders).buffer(true);
105
+ let request = superagent(method, url).set(requestHeaders).buffer(true);
106
+
107
+ // Apply proxy agent if provided
108
+ if (proxyAgent) {
109
+ request = request.agent(proxyAgent);
110
+ }
111
+
112
+ const response = await request;
71
113
 
72
114
  // Determine the correct body type (Buffer for binary, text for others)
73
115
  const responseBody = response.body instanceof Buffer ? response.body : response.text;
74
116
 
75
- // Save to cache
76
- globalCache.set(mainUrl, {
77
- status: response.status,
78
- headers: response.headers,
79
- body: responseBody,
80
- });
81
- if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
117
+ // Save to cache only when caching is enabled
118
+ if (useCache) {
119
+ globalCache.set(mainUrl, {
120
+ status: response.status,
121
+ headers: response.headers,
122
+ body: responseBody,
123
+ });
124
+ if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
125
+ } else {
126
+ if (logger === "info") console.log(`Success (not cached): ${mainUrl}`);
127
+ }
82
128
 
83
129
  return {
84
130
  status: response.status,
@@ -102,6 +148,7 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
102
148
  * @param {boolean} options.useGot - Enable custom fetching via Superagent (bypassing browser network stack for intercepted types)
103
149
  * @param {boolean} options.useFullUrl - Use full URL for cache keys
104
150
  * @param {boolean} options.useCache - Enable caching
151
+ * @param {string|Object|null} options.proxy - Proxy for custom fetch. String: "http://host:port" or "socks5://user:pass@host:port". Object: { type, host, port, user, pass }
105
152
  * @param {Object} options.m4w_send_on_post - Custom handler data for Doublelist posts
106
153
  * @param {Object} options.m4w_send_on_message - Custom handler data for Doublelist messages
107
154
  * @param {Array<string>} options.allowImagePatterns - Array of strings/patterns. If a URL contains any of these, it will NOT be blocked even if blockImage is true.
@@ -113,9 +160,10 @@ export async function pwRoute({
113
160
  logger = false,
114
161
  blockAds = true,
115
162
  blockImage = true,
116
- useGot = true,
163
+ useGot = false,
117
164
  useFullUrl = true,
118
165
  useCache = true,
166
+ proxy = null,
119
167
  m4w_send_on_post = null,
120
168
  m4w_send_on_message = null,
121
169
  allowImagePatterns = [], // Default empty, merged inside
@@ -149,6 +197,10 @@ export async function pwRoute({
149
197
  // Define resource types to intercept for custom fetching (useGot)
150
198
  const interceptedResourceTypes = ["stylesheet", "script", "font"];
151
199
 
200
+ // Create proxy agent once (reused for all requests in this route)
201
+ const proxyUrl = formatProxyUrl(proxy);
202
+ const proxyAgent = createProxyAgent(proxyUrl);
203
+
152
204
  // If images are NOT blocked, we generally want to intercept/cache them too.
153
205
  if (!blockImage) {
154
206
  interceptedResourceTypes.push("image");
@@ -291,7 +343,8 @@ export async function pwRoute({
291
343
  requestHeaders,
292
344
  requestMethod,
293
345
  useFullUrl,
294
- logger
346
+ logger,
347
+ proxyAgent
295
348
  );
296
349
 
297
350
  if (response) {
@@ -29,6 +29,13 @@ export interface PpRouteOptions {
29
29
  /** Enable caching for requests */
30
30
  useCache?: boolean;
31
31
 
32
+ /**
33
+ * Proxy for custom fetch requests (only used when useGot is true).
34
+ * String: "http://host:port", "socks5://user:pass@host:port"
35
+ * Object: { type, host, port, user, pass }
36
+ */
37
+ proxy?: string | { type?: string; host: string; port: number; user?: string; pass?: string } | null;
38
+
32
39
  /** Data object for Doublelist message interception (POST logic) */
33
40
  m4w_send_on_post?: Record<string, any> | null;
34
41
 
@@ -2,6 +2,8 @@
2
2
  import superagent from "superagent";
3
3
  import { FiltersEngine, Request } from "@ghostery/adblocker";
4
4
  import fetch from "node-fetch";
5
+ import { HttpsProxyAgent } from "https-proxy-agent";
6
+ import { SocksProxyAgent } from "socks-proxy-agent";
5
7
  import NodeCache from "node-cache";
6
8
 
7
9
  let AdBlockEngine;
@@ -37,6 +39,38 @@ export function ppCacheLogs(log_cache = globalCache, interval = 10) {
37
39
  }
38
40
  }
39
41
 
42
+ /**
43
+ * Normalizes proxy input (string or object) into a URL string.
44
+ * Accepts:
45
+ * - String: "http://host:port", "socks5://user:pass@host:port", etc.
46
+ * - Object: { type, host, port, user, pass }
47
+ * @param {string|Object|null} proxy
48
+ * @returns {string|null} - Proxy URL string or null
49
+ */
50
+ function formatProxyUrl(proxy) {
51
+ if (!proxy) return null;
52
+ if (typeof proxy === "string") return proxy;
53
+ if (typeof proxy === "object") {
54
+ const { type = "http", host, port, user, pass } = proxy;
55
+ const auth = user && pass ? `${user}:${pass}@` : "";
56
+ return `${type}://${auth}${host}:${port}`;
57
+ }
58
+ return null;
59
+ }
60
+
61
+ /**
62
+ * Creates an HTTP agent for the given proxy URL.
63
+ * @param {string|null} proxyUrl
64
+ * @returns {Object|null} - HttpsProxyAgent or SocksProxyAgent instance
65
+ */
66
+ function createProxyAgent(proxyUrl) {
67
+ if (!proxyUrl) return null;
68
+ if (proxyUrl.startsWith("socks")) {
69
+ return new SocksProxyAgent(proxyUrl);
70
+ }
71
+ return new HttpsProxyAgent(proxyUrl);
72
+ }
73
+
40
74
  /**
41
75
  * Function to fetch resources using Superagent library with optional caching.
42
76
  * This mimics the browser's request but handles it in Node.js to allow caching or header manipulation.
@@ -46,9 +80,10 @@ export function ppCacheLogs(log_cache = globalCache, interval = 10) {
46
80
  * @param {string} method - HTTP method (GET, POST, etc.)
47
81
  * @param {boolean} useFullUrl - Whether to use the full URL as cache key or just origin+path
48
82
  * @param {string|false} logger - Log level: "info" (success+error), "error" (errors only), false (no logs)
83
+ * @param {Object|null} proxyAgent - Proxy agent to use for the request
49
84
  * @returns {Promise<Object>} - The response object containing status, headers, and body
50
85
  */
51
- async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl, logger) {
86
+ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl, logger, proxyAgent) {
52
87
  // Determine the cache key based on configuration
53
88
  let mainUrl = new URL(url).origin + new URL(url).pathname;
54
89
  if (useFullUrl) {
@@ -67,18 +102,29 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
67
102
  try {
68
103
  // Fetch the resource using superagent
69
104
  // buffer(true) ensures we get the raw binary data (essential for images/fonts)
70
- const response = await superagent(method, url).set(requestHeaders).buffer(true);
105
+ let request = superagent(method, url).set(requestHeaders).buffer(true);
106
+
107
+ // Apply proxy agent if provided
108
+ if (proxyAgent) {
109
+ request = request.agent(proxyAgent);
110
+ }
111
+
112
+ const response = await request;
71
113
 
72
114
  // Determine the correct body type (Buffer for binary, text for others)
73
115
  const responseBody = response.body instanceof Buffer ? response.body : response.text;
74
116
 
75
- // Save to cache
76
- globalCache.set(mainUrl, {
77
- status: response.status,
78
- headers: response.headers,
79
- body: responseBody,
80
- });
81
- if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
117
+ // Save to cache only when caching is enabled
118
+ if (useCache) {
119
+ globalCache.set(mainUrl, {
120
+ status: response.status,
121
+ headers: response.headers,
122
+ body: responseBody,
123
+ });
124
+ if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
125
+ } else {
126
+ if (logger === "info") console.log(`Success (not cached): ${mainUrl}`);
127
+ }
82
128
 
83
129
  return {
84
130
  status: response.status,
@@ -92,16 +138,16 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
92
138
  }
93
139
 
94
140
  /**
95
- * Main function to set up routing, ad blocking, and request interception in Playwright.
141
+ * Main function to set up routing, ad blocking, and request interception in Puppeteer.
96
142
  * @param {Object} options - Configuration options
97
- * @param {Object} options.context - Playwright context (optional, one is required)
98
- * @param {Object} options.page - Playwright page (optional, one is required)
143
+ * @param {Object} options.page - Puppeteer page (required)
99
144
  * @param {boolean} options.blockImage - Enable global image blocking
100
145
  * @param {boolean} options.blockAds - Enable Ghostery ad blocking
101
146
  * @param {string|false} [options.logger="error"] - Log level: "info" (success+error), "error" (errors only), false (no logs)
102
147
  * @param {boolean} options.useGot - Enable custom fetching via Superagent (bypassing browser network stack for intercepted types)
103
148
  * @param {boolean} options.useFullUrl - Use full URL for cache keys
104
149
  * @param {boolean} options.useCache - Enable caching
150
+ * @param {string|Object|null} options.proxy - Proxy for custom fetch. String: "http://host:port" or "socks5://user:pass@host:port". Object: { type, host, port, user, pass }
105
151
  * @param {Object} options.m4w_send_on_post - Custom handler data for Doublelist posts
106
152
  * @param {Object} options.m4w_send_on_message - Custom handler data for Doublelist messages
107
153
  * @param {Array<string>} options.allowImagePatterns - Array of strings/patterns. If a URL contains any of these, it will NOT be blocked even if blockImage is true.
@@ -112,9 +158,10 @@ export async function ppRoute({
112
158
  logger = false,
113
159
  blockAds = true,
114
160
  blockImage = true,
115
- useGot = true,
161
+ useGot = false,
116
162
  useFullUrl = true,
117
163
  useCache = true,
164
+ proxy = null,
118
165
  m4w_send_on_post = null,
119
166
  m4w_send_on_message = null,
120
167
  allowImagePatterns = [], // Default empty, merged inside
@@ -147,6 +194,10 @@ export async function ppRoute({
147
194
  // Define resource types to intercept for custom fetching (useGot)
148
195
  const interceptedResourceTypes = ["stylesheet", "script", "font"];
149
196
 
197
+ // Create proxy agent once (reused for all requests in this route)
198
+ const proxyUrl = formatProxyUrl(proxy);
199
+ const proxyAgent = createProxyAgent(proxyUrl);
200
+
150
201
  // If images are NOT blocked, we generally want to intercept/cache them too.
151
202
  if (!blockImage) {
152
203
  interceptedResourceTypes.push("image");
@@ -295,7 +346,8 @@ export async function ppRoute({
295
346
  requestHeaders,
296
347
  requestMethod,
297
348
  useFullUrl,
298
- logger
349
+ logger,
350
+ proxyAgent
299
351
  );
300
352
 
301
353
  if (response) {