arn-browser 0.1.11 → 0.1.13

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.11",
3
+ "version": "0.1.13",
4
4
  "description": "A lightweight, browser autmation helper.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "https-proxy-agent": "^7.0.6",
23
23
  "node-cache": "^5.1.2",
24
24
  "node-fetch": "^3.3.2",
25
- "playwright": "^1.42.1",
25
+ "playwright-core": "1.42.1",
26
26
  "proxy-chain": "^2.6.0",
27
27
  "puppeteer-core": "^24.38.0",
28
28
  "randomstring": "^1.3.1",
package/src/index.d.ts CHANGED
@@ -4,7 +4,8 @@ import { ppLaunch } from "./utility/puppeteer/ppLaunch";
4
4
  import { ppRoute, ppCacheLogs } from "./utility/puppeteer/routes/ppRoute";
5
5
  import { pwLaunch } from "./utility/playwright/pwLaunch";
6
6
  import { pwRoute, pwCacheLogs } from "./utility/playwright/routes/pwRoute";
7
- import { retryNavigation, retryClick, checkPageConditions } from "./utility/playwright/playwright-helper";
7
+ import { retryNavigation, retryClick, checkPageConditions } from "./utility/playwright/pwHelper";
8
+ import { retryNavigation as ppRetryNavigation } from "./utility/puppeteer/ppHelper";
8
9
  import { startProxyServer, fetchPublicIP, fetchProxyDetails } from "./utility/proxy-utility/proxy-chain";
9
10
  import {
10
11
  fetchAwsProxy, getInstanceStatus, getPublicIpAddress,
@@ -20,6 +21,7 @@ export declare const ppBrowser: {
20
21
  launch: typeof ppLaunch;
21
22
  route: typeof ppRoute;
22
23
  cacheLogs: typeof ppCacheLogs;
24
+ ppGoto: typeof ppRetryNavigation;
23
25
  };
24
26
 
25
27
  export declare const pwBrowser: {
@@ -31,7 +33,7 @@ export declare const pwBrowser: {
31
33
  pwConditions: typeof checkPageConditions;
32
34
  };
33
35
 
34
- export declare const proxy: {
36
+ export declare const proxyUtil: {
35
37
  startServer: typeof startProxyServer;
36
38
  fetchPublicIP: typeof fetchPublicIP;
37
39
  fetchDetails: typeof fetchProxyDetails;
package/src/index.js CHANGED
@@ -5,17 +5,19 @@
5
5
  // --- Puppeteer ---
6
6
  import { ppLaunch } from "./utility/puppeteer/ppLaunch.js";
7
7
  import { ppRoute, ppCacheLogs } from "./utility/puppeteer/routes/ppRoute.js";
8
+ import { retryNavigation as ppRetryNavigation } from "./utility/puppeteer/ppHelper.js";
8
9
 
9
10
  export const ppBrowser = {
10
11
  launch: ppLaunch,
11
12
  route: ppRoute,
12
13
  cacheLogs: ppCacheLogs,
14
+ ppGoto: ppRetryNavigation,
13
15
  };
14
16
 
15
17
  // --- Playwright ---
16
18
  import { pwLaunch } from "./utility/playwright/pwLaunch.js";
17
19
  import { pwRoute, pwCacheLogs } from "./utility/playwright/routes/pwRoute.js";
18
- import { retryNavigation, retryClick, checkPageConditions } from "./utility/playwright/playwright-helper.js";
20
+ import { retryNavigation, retryClick, checkPageConditions } from "./utility/playwright/pwHelper.js";
19
21
 
20
22
  export const pwBrowser = {
21
23
  launch: pwLaunch,
@@ -45,7 +47,7 @@ import {
45
47
  } from "./utility/proxy-utility/custom-proxy.js";
46
48
  import { get_multilogin_proxy, get_packetstream_proxy, get_x_proxy, fetchNextProxy } from "./utility/proxy-utility/proxy-helper.js";
47
49
 
48
- export const proxy = {
50
+ export const proxyUtil = {
49
51
  startServer: startProxyServer,
50
52
  fetchPublicIP,
51
53
  fetchDetails: fetchProxyDetails,
@@ -273,9 +273,9 @@ function createHumanLocator(cursor, locator) {
273
273
  * Create a HumanCursor that acts as a drop-in replacement for Page
274
274
  * All page methods work, but click/fill/type/check/hover use human cursor
275
275
  *
276
- * @param {import('playwright').Page} page - Playwright Page object
276
+ * @param {import('playwright-core').Page} page - Playwright Page object
277
277
  * @param {Object} options - Configuration options
278
- * @returns {import('playwright').Page & HumanCursorMethods}
278
+ * @returns {import('playwright-core').Page & HumanCursorMethods}
279
279
  */
280
280
  export function createCursor(page, options = {}) {
281
281
  const config = {
@@ -2,7 +2,7 @@
2
2
  * TypeScript declarations for human-cursor-playwright
3
3
  */
4
4
 
5
- import type { Page, Locator, Response, PageScreenshotOptions, WaitForURLOptions } from 'playwright';
5
+ import type { Page, Locator, Response, PageScreenshotOptions, WaitForURLOptions } from 'playwright-core';
6
6
 
7
7
  // ============= Tweening Functions =============
8
8
 
@@ -1,4 +1,4 @@
1
- import { Page, Locator } from "playwright";
1
+ import { Page, Locator } from "playwright-core";
2
2
 
3
3
  /**
4
4
  * Options for the retryNavigation function.
@@ -3,7 +3,7 @@
3
3
  * If navigation fails, it temporarily goes to "about:blank" before retrying.
4
4
  *
5
5
  * @param {Object} options
6
- * @param {import('playwright').Page} options.page - Playwright Page object
6
+ * @param {import('playwright-core').Page} options.page - Playwright Page object
7
7
  * @param {string} options.url - Target URL
8
8
  * @param {number} [options.maxRetries=5] - Maximum number of attempts
9
9
  * @param {string|null} [options.referer=null] - Referer header
@@ -54,7 +54,7 @@ export const retryNavigation = async ({
54
54
  * EXPECTATION: The element should disappear (become hidden) after clicking.
55
55
  *
56
56
  * @param {Object} options
57
- * @param {import('playwright').Locator} options.locator - The element to click
57
+ * @param {import('playwright-core').Locator} options.locator - The element to click
58
58
  * @param {number} [options.maxRetries=3] - Max retries
59
59
  * @param {number} [options.timeout=15000] - Timeout for visibility checks
60
60
  */
@@ -80,8 +80,8 @@ export const retryClick = async ({ locator, maxRetries = 3, timeout = 15000 }) =
80
80
  * Races multiple conditions (URL or Element) to see which happens first.
81
81
  * Modifies the input object by deleting the matched key.
82
82
  *
83
- * @param {import('playwright').Page} page
84
- * @param {Object.<string, string|import('playwright').Locator|null>} checksToPerform - Map of names to URL strings or Locators
83
+ * @param {import('playwright-core').Page} page
84
+ * @param {Object.<string, string|import('playwright-core').Locator|null>} checksToPerform - Map of names to URL strings or Locators
85
85
  * @param {number} timeout - Timeout in ms
86
86
  * @returns {Promise<string|null>} The key of the matched condition
87
87
  */
@@ -1,4 +1,4 @@
1
- import { Browser, BrowserContext, Page } from "playwright";
1
+ import { Browser, BrowserContext, Page } from "playwright-core";
2
2
  import type { FingerprintGeneratorOptions } from "fingerprint-generator";
3
3
  import type { HumanPage, CreateCursorOptions } from "./human-cursor/index";
4
4
  type Screen = FingerprintGeneratorOptions["screen"];
@@ -9,7 +9,7 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import os from "os";
11
11
  import crypto from "node:crypto";
12
- import { chromium, firefox } from "playwright";
12
+ import { chromium, firefox } from "playwright-core";
13
13
  import { setTimeout as sleep } from "timers/promises";
14
14
 
15
15
  // Fingerprint management
@@ -966,11 +966,27 @@ async function launchExistingMultiloginProfile(profileId, humanize_options = nul
966
966
  page = createCursor(page, humanize_options);
967
967
  }
968
968
 
969
+ let closing = false;
969
970
  const closeBrowser = async () => {
971
+ if (closing) return false;
972
+ closing = true;
973
+ if (signalHandler) {
974
+ process.off("SIGINT", signalHandler);
975
+ process.off("SIGTERM", signalHandler);
976
+ process.off("SIGHUP", signalHandler);
977
+ }
970
978
  if (browser) await browser.close().catch(() => { });
971
979
  return await stopMultiloginProfile(profileId);
972
980
  };
973
981
 
982
+ let signalHandler = async () => {
983
+ await closeBrowser();
984
+ process.exit(0);
985
+ };
986
+ process.once("SIGINT", signalHandler);
987
+ process.once("SIGTERM", signalHandler);
988
+ process.once("SIGHUP", signalHandler);
989
+
974
990
  return { browser, context, page, isBrowserRunning: () => !!browser, closeBrowser, launchError: null };
975
991
  } catch (error) {
976
992
  console.error("Multilogin Launch Error:", error.message);
@@ -1040,11 +1056,27 @@ async function launchQuickMultiloginProfile({ os_type, proxy, canvas_noise, medi
1040
1056
  page = createCursor(page, humanize_options);
1041
1057
  }
1042
1058
 
1059
+ let closing = false;
1043
1060
  const closeBrowser = async () => {
1061
+ if (closing) return false;
1062
+ closing = true;
1063
+ if (signalHandler) {
1064
+ process.off("SIGINT", signalHandler);
1065
+ process.off("SIGTERM", signalHandler);
1066
+ process.off("SIGHUP", signalHandler);
1067
+ }
1044
1068
  if (browser) await browser.close().catch(() => { });
1045
1069
  return await stopMultiloginProfile(profileId);
1046
1070
  };
1047
1071
 
1072
+ let signalHandler = async () => {
1073
+ await closeBrowser();
1074
+ process.exit(0);
1075
+ };
1076
+ process.once("SIGINT", signalHandler);
1077
+ process.once("SIGTERM", signalHandler);
1078
+ process.once("SIGHUP", signalHandler);
1079
+
1048
1080
  return { browser, context, page, isBrowserRunning: () => !!browser, closeBrowser, launchError: null };
1049
1081
  } catch (error) {
1050
1082
  console.error("Quick Profile Error:", error);
@@ -1,4 +1,4 @@
1
- import { Browser, BrowserContext, Page } from "playwright";
1
+ import { Browser, BrowserContext, Page } from "playwright-core";
2
2
 
3
3
  // ============================================================================
4
4
  // ROUTING & CACHE TYPES
@@ -0,0 +1,26 @@
1
+ import { Page } from "puppeteer-core";
2
+
3
+ /**
4
+ * Options for the retryNavigation function.
5
+ */
6
+ export interface RetryNavigationOptions {
7
+ /** The Puppeteer Page object. */
8
+ page: Page;
9
+ /** The target URL to navigate to. */
10
+ url: string;
11
+ /** Maximum number of retry attempts. Default: 5 */
12
+ maxRetries?: number;
13
+ /** Custom Referer header. Default: null */
14
+ referer?: string | null;
15
+ /** Base timeout in milliseconds. Default: 30000 */
16
+ timeout?: number;
17
+ /** When to consider operation succeeded. Default: "load" */
18
+ waitUntil?: "load" | "domcontentloaded" | "networkidle0" | "networkidle2";
19
+ }
20
+
21
+ /**
22
+ * Navigates to a URL with retry logic and incremental timeouts.
23
+ * If navigation fails, it temporarily goes to "about:blank" before retrying.
24
+ * @returns True if navigation succeeded, throws error otherwise.
25
+ */
26
+ export function retryNavigation(options: RetryNavigationOptions): Promise<boolean>;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Navigates to a URL with retry logic and incremental timeouts.
3
+ * If navigation fails, it temporarily goes to "about:blank" before retrying.
4
+ *
5
+ * @param {Object} options
6
+ * @param {import('puppeteer-core').Page} options.page - Puppeteer Page object
7
+ * @param {string} options.url - Target URL
8
+ * @param {number} [options.maxRetries=5] - Maximum number of attempts
9
+ * @param {string|null} [options.referer=null] - Referer header
10
+ * @param {number} [options.timeout=30000] - Base timeout in ms
11
+ * @param {"load"|"domcontentloaded"|"networkidle0"|"networkidle2"} [options.waitUntil="load"] - Wait condition
12
+ * @returns {Promise<boolean>} True if successful
13
+ */
14
+ export const retryNavigation = async ({
15
+ page,
16
+ url,
17
+ maxRetries = 5,
18
+ referer = null,
19
+ timeout = 30000,
20
+ waitUntil = "load",
21
+ }) => {
22
+ for (let retryCount = 0; retryCount < maxRetries; retryCount++) {
23
+ // Apply incremental timeout only if the initial timeout is <= 30,000
24
+ const currentTimeout = timeout <= 30000 ? timeout + retryCount * 15000 : timeout;
25
+ try {
26
+ const gotoOptions = {
27
+ waitUntil: waitUntil,
28
+ timeout: currentTimeout,
29
+ };
30
+
31
+ if (referer) {
32
+ gotoOptions.referer = referer;
33
+ }
34
+
35
+ await page.goto(url, gotoOptions);
36
+
37
+ return true;
38
+ } catch (error) {
39
+ console.log(`Navigation attempt ${retryCount + 1} failed.`, url);
40
+ await page.goto("about:blank", { waitUntil: "load", timeout: timeout });
41
+ if (retryCount === maxRetries - 1) {
42
+ console.log("All retry attempts failed");
43
+ throw error;
44
+ }
45
+ }
46
+ }
47
+ return false;
48
+ };
@@ -612,13 +612,29 @@ async function launchExistingMultiloginProfile(profileId) {
612
612
  const pages = await browser.pages();
613
613
  const page = pages[0] ?? (await browser.newPage());
614
614
 
615
+ let closing = false;
615
616
  const closeBrowser = async () => {
617
+ if (closing) return false;
618
+ closing = true;
619
+ if (signalHandler) {
620
+ process.off("SIGINT", signalHandler);
621
+ process.off("SIGTERM", signalHandler);
622
+ process.off("SIGHUP", signalHandler);
623
+ }
616
624
  try {
617
625
  if (browser?.connected) await browser.close();
618
626
  } catch { }
619
627
  return await stopMultiloginProfile(profileId);
620
628
  };
621
629
 
630
+ let signalHandler = async () => {
631
+ await closeBrowser();
632
+ process.exit(0);
633
+ };
634
+ process.once("SIGINT", signalHandler);
635
+ process.once("SIGTERM", signalHandler);
636
+ process.once("SIGHUP", signalHandler);
637
+
622
638
  return { browser, context: browser, page, isBrowserRunning: () => !!browser?.connected, closeBrowser, launchError: null };
623
639
  } catch (error) {
624
640
  console.error("Multilogin Launch Error:", error.message);
@@ -685,13 +701,29 @@ async function launchQuickMultiloginProfile({ os_type, proxy, canvas_noise, medi
685
701
  const pages = await browser.pages();
686
702
  const page = pages[0] ?? (await browser.newPage());
687
703
 
704
+ let closing = false;
688
705
  const closeBrowser = async () => {
706
+ if (closing) return false;
707
+ closing = true;
708
+ if (signalHandler) {
709
+ process.off("SIGINT", signalHandler);
710
+ process.off("SIGTERM", signalHandler);
711
+ process.off("SIGHUP", signalHandler);
712
+ }
689
713
  try {
690
714
  if (browser?.connected) await browser.close();
691
715
  } catch { }
692
716
  return await stopMultiloginProfile(profileId);
693
717
  };
694
718
 
719
+ let signalHandler = async () => {
720
+ await closeBrowser();
721
+ process.exit(0);
722
+ };
723
+ process.once("SIGINT", signalHandler);
724
+ process.once("SIGTERM", signalHandler);
725
+ process.once("SIGHUP", signalHandler);
726
+
695
727
  return { browser, context: browser, page, isBrowserRunning: () => !!browser?.connected, closeBrowser, launchError: null };
696
728
  } catch (error) {
697
729
  console.error("Quick Profile Error:", error);