real-browser-plus 1.1.0

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.

Potentially problematic release.


This version of real-browser-plus might be problematic. Click here for more details.

package/dist/index.js ADDED
@@ -0,0 +1,692 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Logger: () => Logger,
34
+ blockWebRTCLeak: () => blockWebRTCLeak,
35
+ connect: () => connect,
36
+ default: () => index_default,
37
+ generateFingerprint: () => generateFingerprint,
38
+ ghostClick: () => ghostClick,
39
+ humanScroll: () => humanScroll,
40
+ humanType: () => humanType,
41
+ logger: () => logger,
42
+ moveMouseHuman: () => moveMouseHuman,
43
+ restoreSession: () => restoreSession,
44
+ saveSession: () => saveSession,
45
+ solveTurnstile: () => solveTurnstile,
46
+ withRetry: () => withRetry
47
+ });
48
+ module.exports = __toCommonJS(index_exports);
49
+ var import_puppeteer_extra = __toESM(require("puppeteer-extra"));
50
+ var import_puppeteer_extra_plugin_stealth = __toESM(require("puppeteer-extra-plugin-stealth"));
51
+
52
+ // src/stealth/evasions.ts
53
+ async function applyStealthEvasions(page) {
54
+ await page.evaluateOnNewDocument(() => {
55
+ Object.defineProperty(Navigator.prototype, "webdriver", { get: () => void 0, configurable: true });
56
+ const w = window;
57
+ if (!w.chrome) {
58
+ w.chrome = {
59
+ runtime: {},
60
+ loadTimes: function() {
61
+ },
62
+ csi: function() {
63
+ },
64
+ app: { isInstalled: false }
65
+ };
66
+ }
67
+ const originalQuery = window.navigator.permissions.query;
68
+ window.navigator.permissions.query = (parameters) => parameters.name === "notifications" ? Promise.resolve({ state: Notification.permission }) : originalQuery(parameters);
69
+ Object.defineProperty(navigator, "plugins", {
70
+ get: () => [
71
+ { name: "PDF Viewer", filename: "internal-pdf-viewer" },
72
+ { name: "Chrome PDF Viewer", filename: "internal-pdf-viewer" },
73
+ { name: "Chromium PDF Viewer", filename: "internal-pdf-viewer" },
74
+ { name: "Native Client", filename: "internal-nacl-plugin" }
75
+ ]
76
+ });
77
+ try {
78
+ const proto = HTMLIFrameElement.prototype;
79
+ const oIFCW = proto.__lookupGetter__?.call(HTMLIFrameElement.prototype, "contentWindow");
80
+ if (oIFCW) {
81
+ Object.defineProperty(HTMLIFrameElement.prototype, "contentWindow", {
82
+ get: function() {
83
+ return oIFCW.call(this);
84
+ }
85
+ });
86
+ }
87
+ } catch {
88
+ }
89
+ const doc = document;
90
+ delete doc.$cdc_asdjflasutopfhvcZLmcfl_;
91
+ const win = window;
92
+ delete win.cdc_adoQpoasnfa76pfcZLmcfl_Array;
93
+ window.Function.prototype.toString = new Proxy(window.Function.prototype.toString, {
94
+ apply(target, thisArg, args) {
95
+ if (thisArg === window.navigator.permissions.query) return "function query() { [native code] }";
96
+ return Reflect.apply(target, thisArg, args);
97
+ }
98
+ });
99
+ try {
100
+ Object.defineProperty(Notification, "permission", { get: () => "default" });
101
+ } catch {
102
+ }
103
+ });
104
+ }
105
+
106
+ // src/stealth/index.ts
107
+ var STEALTH_LAUNCH_ARGS = [
108
+ "--disable-blink-features=AutomationControlled",
109
+ "--disable-features=IsolateOrigins,site-per-process",
110
+ "--no-first-run",
111
+ "--no-default-browser-check",
112
+ "--disable-infobars",
113
+ "--window-position=0,0",
114
+ "--disable-dev-shm-usage"
115
+ ];
116
+ async function applyAllStealth(page) {
117
+ await applyStealthEvasions(page);
118
+ }
119
+
120
+ // src/fingerprint/generator.ts
121
+ var CHROME_VERSIONS = ["128.0.6613.120", "129.0.6668.90", "130.0.6723.92", "131.0.6778.86", "132.0.6834.83"];
122
+ var WINDOWS_UA_TEMPLATE = (v) => `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${v} Safari/537.36`;
123
+ var MAC_UA_TEMPLATE = (v) => `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${v} Safari/537.36`;
124
+ var RESOLUTIONS = [
125
+ { screen: { width: 1920, height: 1080 }, viewport: { width: 1920, height: 1040 } },
126
+ { screen: { width: 1536, height: 864 }, viewport: { width: 1536, height: 824 } },
127
+ { screen: { width: 1440, height: 900 }, viewport: { width: 1440, height: 860 } },
128
+ { screen: { width: 1366, height: 768 }, viewport: { width: 1366, height: 728 } },
129
+ { screen: { width: 1280, height: 800 }, viewport: { width: 1280, height: 760 } }
130
+ ];
131
+ var GPU_PROFILES = [
132
+ { vendor: "Google Inc. (NVIDIA)", renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)" },
133
+ { vendor: "Google Inc. (Intel)", renderer: "ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)" },
134
+ { vendor: "Google Inc. (AMD)", renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)" },
135
+ { vendor: "Apple Inc.", renderer: "Apple M1" },
136
+ { vendor: "Apple Inc.", renderer: "Apple M2" }
137
+ ];
138
+ var TIMEZONES = ["Asia/Jakarta", "Asia/Singapore", "America/New_York", "Europe/London", "Asia/Tokyo"];
139
+ var LOCALES = ["en-US", "en-GB", "id-ID"];
140
+ function pick(arr) {
141
+ return arr[Math.floor(Math.random() * arr.length)];
142
+ }
143
+ function generateFingerprint(overrides = {}) {
144
+ const isMac = Math.random() < 0.3;
145
+ const chromeVersion = pick(CHROME_VERSIONS);
146
+ const chromeMajorVersion = chromeVersion.split(".")[0];
147
+ const gpu = pick(GPU_PROFILES.filter((g) => isMac ? g.vendor === "Apple Inc." : g.vendor !== "Apple Inc."));
148
+ const resolution = pick(RESOLUTIONS);
149
+ const profile = {
150
+ userAgent: isMac ? MAC_UA_TEMPLATE(chromeVersion) : WINDOWS_UA_TEMPLATE(chromeVersion),
151
+ chromeVersion,
152
+ chromeMajorVersion,
153
+ platform: isMac ? "MacIntel" : "Win32",
154
+ viewport: { ...resolution.viewport, deviceScaleFactor: pick([1, 1.25, 1.5]) },
155
+ screen: resolution.screen,
156
+ hardwareConcurrency: pick([4, 8, 12, 16]),
157
+ deviceMemory: pick([4, 8, 16]),
158
+ timezone: pick(TIMEZONES),
159
+ locale: pick(LOCALES),
160
+ webglVendor: gpu.vendor,
161
+ webglRenderer: gpu.renderer,
162
+ languages: ["en-US", "en"],
163
+ ...overrides
164
+ };
165
+ return profile;
166
+ }
167
+
168
+ // src/fingerprint/index.ts
169
+ async function applyFingerprint(page, profile) {
170
+ await page.setUserAgent(profile.userAgent);
171
+ await page.setViewport(profile.viewport);
172
+ const client = await page.target().createCDPSession();
173
+ await client.send("Emulation.setTimezoneOverride", { timezoneId: profile.timezone });
174
+ await client.send("Emulation.setLocaleOverride", { locale: profile.locale });
175
+ await client.send("Network.setUserAgentOverride", {
176
+ userAgent: profile.userAgent,
177
+ acceptLanguage: profile.languages.join(","),
178
+ platform: profile.platform,
179
+ userAgentMetadata: {
180
+ brands: [
181
+ { brand: "Not/A)Brand", version: "99" },
182
+ { brand: "Google Chrome", version: profile.chromeMajorVersion },
183
+ { brand: "Chromium", version: profile.chromeMajorVersion }
184
+ ],
185
+ fullVersionList: [
186
+ { brand: "Not/A)Brand", version: "99.0.0.0" },
187
+ { brand: "Google Chrome", version: profile.chromeVersion },
188
+ { brand: "Chromium", version: profile.chromeVersion }
189
+ ],
190
+ fullVersion: profile.chromeVersion,
191
+ platform: profile.platform === "MacIntel" ? "macOS" : "Windows",
192
+ platformVersion: profile.platform === "MacIntel" ? "13.0.0" : "10.0.0",
193
+ architecture: "x86",
194
+ model: "",
195
+ mobile: false
196
+ }
197
+ });
198
+ await page.setExtraHTTPHeaders({
199
+ "Accept-Language": `${profile.languages[0]};q=0.9,${profile.languages.slice(1).join(";q=0.8,")}`.replace(/;q=0\.8,$/, "")
200
+ });
201
+ await page.evaluateOnNewDocument((p) => {
202
+ Object.defineProperty(navigator, "platform", { get: () => p.platform });
203
+ Object.defineProperty(navigator, "hardwareConcurrency", { get: () => p.hardwareConcurrency });
204
+ Object.defineProperty(navigator, "deviceMemory", { get: () => p.deviceMemory });
205
+ Object.defineProperty(navigator, "languages", { get: () => p.languages });
206
+ Object.defineProperty(screen, "width", { get: () => p.screen.width });
207
+ Object.defineProperty(screen, "height", { get: () => p.screen.height });
208
+ Object.defineProperty(screen, "availWidth", { get: () => p.screen.width });
209
+ Object.defineProperty(screen, "availHeight", { get: () => p.screen.height - 40 });
210
+ Object.defineProperty(window, "outerWidth", { get: () => p.screen.width });
211
+ Object.defineProperty(window, "outerHeight", { get: () => p.screen.height });
212
+ Object.defineProperty(window, "devicePixelRatio", { get: () => p.viewport.deviceScaleFactor });
213
+ const patchGetParameter = (proto) => {
214
+ const original = proto.getParameter;
215
+ proto.getParameter = function(parameter) {
216
+ const UNMASKED_VENDOR_WEBGL = 37445;
217
+ const UNMASKED_RENDERER_WEBGL = 37446;
218
+ if (parameter === UNMASKED_VENDOR_WEBGL) return p.webglVendor;
219
+ if (parameter === UNMASKED_RENDERER_WEBGL) return p.webglRenderer;
220
+ return original.call(this, parameter);
221
+ };
222
+ };
223
+ patchGetParameter(WebGLRenderingContext.prototype);
224
+ if (typeof WebGL2RenderingContext !== "undefined") {
225
+ patchGetParameter(WebGL2RenderingContext.prototype);
226
+ }
227
+ const toDataURLProto = HTMLCanvasElement.prototype.toDataURL;
228
+ HTMLCanvasElement.prototype.toDataURL = function(...args) {
229
+ const ctx = this.getContext("2d");
230
+ if (ctx) {
231
+ const imageData = ctx.getImageData(0, 0, this.width, this.height);
232
+ for (let i = 0; i < imageData.data.length; i += 4) {
233
+ imageData.data[i] = imageData.data[i] ^ 1;
234
+ }
235
+ ctx.putImageData(imageData, 0, 0);
236
+ }
237
+ return toDataURLProto.apply(this, args);
238
+ };
239
+ const origCreateAnalyser = AudioContext.prototype.createAnalyser;
240
+ AudioContext.prototype.createAnalyser = function() {
241
+ const analyser = origCreateAnalyser.call(this);
242
+ const origGetFloatFrequencyData = analyser.getFloatFrequencyData.bind(analyser);
243
+ analyser.getFloatFrequencyData = ((array) => {
244
+ origGetFloatFrequencyData(array);
245
+ const typedArray = array;
246
+ for (let i = 0; i < typedArray.length; i++) typedArray[i] += Math.random() * 1e-4;
247
+ });
248
+ return analyser;
249
+ };
250
+ const nav = navigator;
251
+ if (nav.getBattery) {
252
+ nav.getBattery = () => Promise.resolve({
253
+ charging: true,
254
+ chargingTime: 0,
255
+ dischargingTime: Infinity,
256
+ level: 1,
257
+ addEventListener: () => {
258
+ },
259
+ removeEventListener: () => {
260
+ }
261
+ });
262
+ }
263
+ const navConn = navigator;
264
+ if (navConn.connection) {
265
+ Object.defineProperty(navConn, "connection", {
266
+ get: () => ({
267
+ effectiveType: "4g",
268
+ rtt: 50,
269
+ downlink: 10,
270
+ saveData: false,
271
+ addEventListener: () => {
272
+ },
273
+ removeEventListener: () => {
274
+ }
275
+ })
276
+ });
277
+ }
278
+ }, profile);
279
+ }
280
+
281
+ // src/cursor/ghostCursor.ts
282
+ function bezierPath(start, end, steps) {
283
+ const c1 = {
284
+ x: start.x + (end.x - start.x) * (0.3 + Math.random() * 0.2) + (Math.random() - 0.5) * 100,
285
+ y: start.y + (end.y - start.y) * (0.1 + Math.random() * 0.3) + (Math.random() - 0.5) * 100
286
+ };
287
+ const c2 = {
288
+ x: start.x + (end.x - start.x) * (0.6 + Math.random() * 0.2) + (Math.random() - 0.5) * 100,
289
+ y: start.y + (end.y - start.y) * (0.7 + Math.random() * 0.2) + (Math.random() - 0.5) * 100
290
+ };
291
+ const points = [];
292
+ for (let i = 0; i <= steps; i++) {
293
+ const t = i / steps;
294
+ const x = Math.pow(1 - t, 3) * start.x + 3 * Math.pow(1 - t, 2) * t * c1.x + 3 * (1 - t) * Math.pow(t, 2) * c2.x + Math.pow(t, 3) * end.x;
295
+ const y = Math.pow(1 - t, 3) * start.y + 3 * Math.pow(1 - t, 2) * t * c1.y + 3 * (1 - t) * Math.pow(t, 2) * c2.y + Math.pow(t, 3) * end.y;
296
+ points.push({ x, y });
297
+ }
298
+ return points;
299
+ }
300
+ function easeInOutQuad(t) {
301
+ return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
302
+ }
303
+ var lastPosition = { x: 100, y: 100 };
304
+ async function moveMouseHuman(page, target) {
305
+ const steps = 20 + Math.floor(Math.random() * 15);
306
+ const path = bezierPath(lastPosition, target, steps);
307
+ for (let i = 0; i < path.length; i++) {
308
+ const eased = easeInOutQuad(i / path.length);
309
+ const idx = Math.min(path.length - 1, Math.floor(eased * path.length));
310
+ const p = path[idx];
311
+ await page.mouse.move(p.x, p.y);
312
+ await new Promise((r) => setTimeout(r, 3 + Math.random() * 10));
313
+ }
314
+ lastPosition = target;
315
+ }
316
+ async function ghostClick(page, selector) {
317
+ const handle = await page.waitForSelector(selector, { timeout: 15e3 });
318
+ if (!handle) throw new Error(`real-browser-plus: element not found for selector "${selector}"`);
319
+ const box = await handle.boundingBox();
320
+ if (!box) throw new Error(`real-browser-plus: element "${selector}" has no bounding box (is it visible?)`);
321
+ const target = {
322
+ x: box.x + box.width * (0.3 + Math.random() * 0.4),
323
+ y: box.y + box.height * (0.3 + Math.random() * 0.4)
324
+ };
325
+ await moveMouseHuman(page, target);
326
+ await new Promise((r) => setTimeout(r, 50 + Math.random() * 150));
327
+ await page.mouse.down();
328
+ await new Promise((r) => setTimeout(r, 30 + Math.random() * 90));
329
+ await page.mouse.up();
330
+ }
331
+
332
+ // src/humanize/typing.ts
333
+ var NEARBY_KEYS = {
334
+ a: ["s", "q", "z"],
335
+ s: ["a", "d", "w"],
336
+ e: ["w", "r", "d"],
337
+ i: ["u", "o", "k"],
338
+ o: ["i", "p", "l"],
339
+ n: ["b", "m", "h"]
340
+ };
341
+ function randomDelay(min, max) {
342
+ return min + Math.random() * (max - min);
343
+ }
344
+ async function humanType(page, selector, text) {
345
+ await ghostClick(page, selector);
346
+ await new Promise((r) => setTimeout(r, randomDelay(200, 600)));
347
+ for (const char of text) {
348
+ const lower = char.toLowerCase();
349
+ const nearby = NEARBY_KEYS[lower];
350
+ const shouldTypo = Math.random() < 0.04 && nearby;
351
+ if (shouldTypo) {
352
+ const wrongChar = nearby[Math.floor(Math.random() * nearby.length)];
353
+ await page.keyboard.type(wrongChar, { delay: randomDelay(60, 180) });
354
+ await new Promise((r) => setTimeout(r, randomDelay(150, 350)));
355
+ await page.keyboard.press("Backspace");
356
+ await new Promise((r) => setTimeout(r, randomDelay(80, 200)));
357
+ }
358
+ await page.keyboard.type(char, { delay: randomDelay(60, 180) });
359
+ if (Math.random() < 0.06) {
360
+ await new Promise((r) => setTimeout(r, randomDelay(300, 900)));
361
+ }
362
+ }
363
+ }
364
+
365
+ // src/humanize/scroll.ts
366
+ async function humanScroll(page, distance) {
367
+ const direction = distance > 0 ? 1 : -1;
368
+ let remaining = Math.abs(distance);
369
+ while (remaining > 0) {
370
+ const step = Math.min(remaining, 60 + Math.random() * 120);
371
+ await page.mouse.wheel({ deltaY: direction * step });
372
+ remaining -= step;
373
+ const delay = Math.random() < 0.15 ? 400 + Math.random() * 800 : 30 + Math.random() * 90;
374
+ await new Promise((r) => setTimeout(r, delay));
375
+ }
376
+ }
377
+
378
+ // src/captcha/turnstile.ts
379
+ var TURNSTILE_IFRAME_SELECTOR = 'iframe[src*="challenges.cloudflare.com"]';
380
+ var TURNSTILE_TIMEOUT_MS = 2e4;
381
+ async function solveTurnstile(page) {
382
+ let frameHandle;
383
+ try {
384
+ frameHandle = await page.waitForSelector(TURNSTILE_IFRAME_SELECTOR, { timeout: 4e3 });
385
+ } catch {
386
+ return false;
387
+ }
388
+ if (!frameHandle) return false;
389
+ const frame = await frameHandle.contentFrame();
390
+ if (!frame) return false;
391
+ const checkbox = await frame.waitForSelector('input[type="checkbox"], #challenge-stage', { timeout: TURNSTILE_TIMEOUT_MS }).catch(() => null);
392
+ if (!checkbox) return false;
393
+ const box = await checkbox.boundingBox();
394
+ if (!box) return false;
395
+ const frameElement = frameHandle.asElement();
396
+ const parentFrameBox = frameElement ? await frameElement.boundingBox() : null;
397
+ const offsetX = parentFrameBox?.x ?? 0;
398
+ const offsetY = parentFrameBox?.y ?? 0;
399
+ await moveMouseHuman(page, {
400
+ x: offsetX + box.x + box.width / 2,
401
+ y: offsetY + box.y + box.height / 2
402
+ });
403
+ await new Promise((r) => setTimeout(r, 150 + Math.random() * 250));
404
+ await page.mouse.down();
405
+ await new Promise((r) => setTimeout(r, 40 + Math.random() * 80));
406
+ await page.mouse.up();
407
+ await page.waitForSelector(TURNSTILE_IFRAME_SELECTOR, { hidden: true, timeout: TURNSTILE_TIMEOUT_MS }).catch(() => null);
408
+ return true;
409
+ }
410
+ function watchForTurnstile(page) {
411
+ page.on("framenavigated", async () => {
412
+ try {
413
+ await solveTurnstile(page);
414
+ } catch {
415
+ }
416
+ });
417
+ }
418
+
419
+ // src/proxy/index.ts
420
+ function resolveProxy(proxy) {
421
+ if (!proxy) return void 0;
422
+ if (Array.isArray(proxy)) return proxy[Math.floor(Math.random() * proxy.length)];
423
+ return proxy;
424
+ }
425
+ function proxyLaunchArg(proxy) {
426
+ const server = proxy.server.startsWith("http") ? proxy.server : `http://${proxy.server}`;
427
+ return `--proxy-server=${server}`;
428
+ }
429
+ async function applyProxyAuth(page, proxy) {
430
+ if (!proxy.username || !proxy.password) return;
431
+ await page.authenticate({ username: proxy.username, password: proxy.password });
432
+ }
433
+
434
+ // src/webrtc/index.ts
435
+ async function blockWebRTCLeak(page) {
436
+ await page.evaluateOnNewDocument(() => {
437
+ const OriginalRTCPeerConnection = window.RTCPeerConnection;
438
+ if (!OriginalRTCPeerConnection) return;
439
+ class PatchedRTCPeerConnection extends OriginalRTCPeerConnection {
440
+ constructor(config) {
441
+ const sanitizedConfig = { ...config, iceServers: [] };
442
+ super(sanitizedConfig);
443
+ }
444
+ }
445
+ Object.defineProperty(window, "RTCPeerConnection", {
446
+ value: PatchedRTCPeerConnection,
447
+ writable: false,
448
+ configurable: true
449
+ });
450
+ Object.defineProperty(window, "webkitRTCPeerConnection", {
451
+ value: PatchedRTCPeerConnection,
452
+ writable: false,
453
+ configurable: true
454
+ });
455
+ });
456
+ }
457
+
458
+ // src/session/index.ts
459
+ async function saveSession(page) {
460
+ const cookies = await page.cookies();
461
+ const storageSnapshot = await page.evaluate(() => {
462
+ const local = {};
463
+ const session = {};
464
+ for (let i = 0; i < window.localStorage.length; i++) {
465
+ const key = window.localStorage.key(i);
466
+ if (key !== null) local[key] = window.localStorage.getItem(key) ?? "";
467
+ }
468
+ for (let i = 0; i < window.sessionStorage.length; i++) {
469
+ const key = window.sessionStorage.key(i);
470
+ if (key !== null) session[key] = window.sessionStorage.getItem(key) ?? "";
471
+ }
472
+ return { local, session, origin: window.location.origin };
473
+ });
474
+ return {
475
+ cookies,
476
+ localStorage: storageSnapshot.local,
477
+ sessionStorage: storageSnapshot.session,
478
+ origin: storageSnapshot.origin
479
+ };
480
+ }
481
+ async function restoreSession(page, session) {
482
+ if (session.cookies.length > 0) {
483
+ await page.setCookie(...session.cookies);
484
+ }
485
+ if (session.origin) {
486
+ await page.evaluateOnNewDocument(
487
+ (data) => {
488
+ for (const [key, value] of Object.entries(data.localStorage)) {
489
+ window.localStorage.setItem(key, value);
490
+ }
491
+ for (const [key, value] of Object.entries(data.sessionStorage)) {
492
+ window.sessionStorage.setItem(key, value);
493
+ }
494
+ },
495
+ { localStorage: session.localStorage, sessionStorage: session.sessionStorage }
496
+ );
497
+ }
498
+ }
499
+
500
+ // src/retry/index.ts
501
+ async function withRetry(fn, options = {}) {
502
+ const { retries = 3, minDelayMs = 300, maxDelayMs = 3e3, onRetry } = options;
503
+ let lastError;
504
+ for (let attempt = 0; attempt <= retries; attempt++) {
505
+ try {
506
+ return await fn();
507
+ } catch (error) {
508
+ lastError = error;
509
+ if (attempt === retries) break;
510
+ onRetry?.(attempt + 1, error);
511
+ const exponential = Math.min(maxDelayMs, minDelayMs * Math.pow(2, attempt));
512
+ const jitter = exponential * (0.5 + Math.random() * 0.5);
513
+ await new Promise((r) => setTimeout(r, jitter));
514
+ }
515
+ }
516
+ throw lastError;
517
+ }
518
+
519
+ // src/logger/index.ts
520
+ var LEVEL_WEIGHT = {
521
+ silent: 0,
522
+ error: 1,
523
+ warn: 2,
524
+ info: 3,
525
+ debug: 4
526
+ };
527
+ var Logger = class {
528
+ constructor(level = "warn") {
529
+ this.level = level;
530
+ }
531
+ setLevel(level) {
532
+ this.level = level;
533
+ }
534
+ shouldLog(target) {
535
+ return LEVEL_WEIGHT[this.level] >= LEVEL_WEIGHT[target];
536
+ }
537
+ error(...args) {
538
+ if (this.shouldLog("error")) console.error("[real-browser-plus]", ...args);
539
+ }
540
+ warn(...args) {
541
+ if (this.shouldLog("warn")) console.warn("[real-browser-plus]", ...args);
542
+ }
543
+ info(...args) {
544
+ if (this.shouldLog("info")) console.info("[real-browser-plus]", ...args);
545
+ }
546
+ debug(...args) {
547
+ if (this.shouldLog("debug")) console.debug("[real-browser-plus]", ...args);
548
+ }
549
+ };
550
+ var logger = new Logger();
551
+
552
+ // src/plugins/index.ts
553
+ var PluginManager = class {
554
+ constructor() {
555
+ this.plugins = [];
556
+ }
557
+ register(plugin) {
558
+ this.plugins.push(plugin);
559
+ }
560
+ async runBrowserLaunched(browser) {
561
+ for (const plugin of this.plugins) {
562
+ await plugin.onBrowserLaunched?.(browser);
563
+ }
564
+ }
565
+ async runPageCreated(page) {
566
+ for (const plugin of this.plugins) {
567
+ await plugin.onPageCreated?.(page);
568
+ }
569
+ }
570
+ async runBeforeClose(browser) {
571
+ for (const plugin of this.plugins) {
572
+ await plugin.onBeforeClose?.(browser);
573
+ }
574
+ }
575
+ };
576
+
577
+ // src/index.ts
578
+ import_puppeteer_extra.default.use((0, import_puppeteer_extra_plugin_stealth.default)());
579
+ async function connect(options = {}) {
580
+ const {
581
+ headless = false,
582
+ args = [],
583
+ executablePath,
584
+ proxy,
585
+ turnstile = true,
586
+ fingerprint: fingerprintOverrides,
587
+ disableFingerprinting = false,
588
+ ghostCursor = true,
589
+ blockWebRTCLeak: shouldBlockWebRTC = true,
590
+ connectToExisting,
591
+ customConfig = {},
592
+ ignoreAllFlags = false,
593
+ plugins = [],
594
+ logLevel = "warn",
595
+ session
596
+ } = options;
597
+ logger.setLevel(logLevel);
598
+ const pluginManager = new PluginManager();
599
+ for (const plugin of plugins) pluginManager.register(plugin);
600
+ const chosenProxy = resolveProxy(proxy);
601
+ const launchArgs = ignoreAllFlags ? args : [...STEALTH_LAUNCH_ARGS, ...args, ...chosenProxy ? [proxyLaunchArg(chosenProxy)] : []];
602
+ let browser;
603
+ if (connectToExisting) {
604
+ browser = await import_puppeteer_extra.default.connect(connectToExisting);
605
+ logger.info("Attached to existing browser instance");
606
+ } else {
607
+ browser = await import_puppeteer_extra.default.launch({
608
+ headless,
609
+ args: launchArgs,
610
+ executablePath,
611
+ defaultViewport: null,
612
+ ignoreDefaultArgs: ["--enable-automation"],
613
+ ...customConfig
614
+ });
615
+ logger.info("Launched new browser instance", { headless, proxy: Boolean(chosenProxy) });
616
+ }
617
+ await pluginManager.runBrowserLaunched(browser);
618
+ const page = await browser.newPage();
619
+ if (chosenProxy) {
620
+ await applyProxyAuth(page, chosenProxy);
621
+ logger.debug("Proxy authentication applied");
622
+ }
623
+ if (!ignoreAllFlags) {
624
+ await applyAllStealth(page);
625
+ }
626
+ if (shouldBlockWebRTC && !ignoreAllFlags) {
627
+ await blockWebRTCLeak(page);
628
+ }
629
+ const fingerprint = generateFingerprint(fingerprintOverrides);
630
+ if (!disableFingerprinting && !ignoreAllFlags) {
631
+ await applyFingerprint(page, fingerprint);
632
+ logger.debug("Fingerprint applied", fingerprint);
633
+ }
634
+ if (session) {
635
+ await restoreSession(page, session);
636
+ logger.debug("Session restored", { origin: session.origin });
637
+ }
638
+ if (turnstile) {
639
+ watchForTurnstile(page);
640
+ solveTurnstile(page).catch((error) => logger.debug("Initial turnstile check skipped", error));
641
+ }
642
+ await pluginManager.runPageCreated(page);
643
+ const humanClick = async (targetPage, selector) => {
644
+ if (ghostCursor) {
645
+ await ghostClick(targetPage, selector);
646
+ } else {
647
+ await targetPage.click(selector);
648
+ }
649
+ };
650
+ const use = async (plugin) => {
651
+ pluginManager.register(plugin);
652
+ await plugin.onPageCreated?.(page);
653
+ };
654
+ browser.on("disconnected", () => {
655
+ logger.info("Browser disconnected");
656
+ });
657
+ const originalClose = browser.close.bind(browser);
658
+ browser.close = (async () => {
659
+ await pluginManager.runBeforeClose(browser);
660
+ return originalClose();
661
+ });
662
+ return {
663
+ browser,
664
+ page,
665
+ fingerprint,
666
+ humanClick,
667
+ humanType,
668
+ humanScroll,
669
+ solveTurnstile,
670
+ saveSession,
671
+ restoreSession,
672
+ withRetry,
673
+ use
674
+ };
675
+ }
676
+ var index_default = { connect };
677
+ // Annotate the CommonJS export names for ESM import in node:
678
+ 0 && (module.exports = {
679
+ Logger,
680
+ blockWebRTCLeak,
681
+ connect,
682
+ generateFingerprint,
683
+ ghostClick,
684
+ humanScroll,
685
+ humanType,
686
+ logger,
687
+ moveMouseHuman,
688
+ restoreSession,
689
+ saveSession,
690
+ solveTurnstile,
691
+ withRetry
692
+ });