capiumbrowser 1.1.7 → 1.1.8

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/lib/config.js CHANGED
@@ -17,6 +17,42 @@ const fs = require('fs');
17
17
  const os = require('os');
18
18
  const path = require('path');
19
19
 
20
+ // Playwright/Puppeteer default args to SUPPRESS (ignoreDefaultArgs): these leak automation
21
+ // or force a software render.
22
+ // --enable-automation : exposes navigator.webdriver=true + an automation banner.
23
+ // --enable-unsafe-swiftshader : the driver adds this so headless WebGL "works", but it ENABLES
24
+ // the (for us, broken-ICD) bundled SwiftShader path -> getContext
25
+ // ('webgl')=null headless / a software-raster tell. Stripping it
26
+ // forces Chromium onto the real GPU (GPU host) or system Mesa.
27
+ const IGNORE_DEFAULT_ARGS = ['--enable-automation', '--enable-unsafe-swiftshader'];
28
+
29
+ // Headless default screen/viewport. Headless has no real display, so the per-seed device-pool
30
+ // screen (e.g. 2560x1440) has no window manager to size a matching window against -- the
31
+ // framebuffer would stay at Chromium's small headless default and screen != viewport (a
32
+ // browserscan VM tell). Instead model the single MOST COMMON real setup: a maximized Chrome
33
+ // window on a 1080p Windows monitor -- screen 1920x1080, viewport 1920x947 (1040 avail height
34
+ // minus ~93px of tab/omnibox/bookmark chrome). Dominant real-world viewport, so a headless
35
+ // instance blends in, and screen > viewport stays coherent. Applied only in headless and only
36
+ // when the caller pins no screen (an explicit --fingerprint-screen-* / --window-size opts out).
37
+ const HEADLESS_SCREEN = [1920, 1080];
38
+ const HEADLESS_VIEWPORT = [1920, 947];
39
+
40
+ function getHeadlessDefaultArgs() {
41
+ const [sw, sh] = HEADLESS_SCREEN;
42
+ const [vw, vh] = HEADLESS_VIEWPORT;
43
+ return [
44
+ `--fingerprint-screen-width=${sw}`,
45
+ `--fingerprint-screen-height=${sh}`,
46
+ `--window-size=${vw},${vh}`,
47
+ ];
48
+ }
49
+
50
+ function hasScreenOverride(extra) {
51
+ if (!Array.isArray(extra)) return false;
52
+ const keys = ['--window-size', '--fingerprint-screen-width', '--fingerprint-screen-height'];
53
+ return extra.some((a) => typeof a === 'string' && keys.some((k) => a.startsWith(k)));
54
+ }
55
+
20
56
  /**
21
57
  * Return the default per-launch fingerprint flags.
22
58
  *
@@ -285,6 +321,11 @@ function findBinary(binary = null) {
285
321
 
286
322
  module.exports = {
287
323
  getDefaultStealthArgs,
324
+ IGNORE_DEFAULT_ARGS,
325
+ HEADLESS_SCREEN,
326
+ HEADLESS_VIEWPORT,
327
+ getHeadlessDefaultArgs,
328
+ hasScreenOverride,
288
329
  newSeed,
289
330
  findBinary,
290
331
  searchBases,
@@ -39,9 +39,17 @@ function proxyAndGeoArgs(spec, geoipOn) {
39
39
  return { launchOptions, args: out };
40
40
  }
41
41
 
42
- function buildArgs({ seed, platform, stealthArgs, timezone, locale, extensionPaths, extra }) {
42
+ function buildArgs({ seed, platform, stealthArgs, timezone, locale, extensionPaths, extra,
43
+ headless = false }) {
43
44
  let args = [];
44
- if (stealthArgs) args = args.concat(config.getDefaultStealthArgs(seed, platform));
45
+ if (stealthArgs) {
46
+ args = args.concat(config.getDefaultStealthArgs(seed, platform));
47
+ // Headless: pin the maximized-1080p-Windows screen/viewport (see config), unless the
48
+ // caller already set their own screen/window via extra args.
49
+ if (headless && !config.hasScreenOverride(extra)) {
50
+ args = args.concat(config.getHeadlessDefaultArgs());
51
+ }
52
+ }
45
53
  if (timezone) args.push(`--timezone=${timezone}`); // capium in-binary tz spoof
46
54
  if (locale) {
47
55
  args.push(`--lang=${locale}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capiumbrowser",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "Drop-in stealth browser SDK on top of Playwright or Puppeteer (Capium Chromium).",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Capzy (https://capzy.ai)",
package/playwright.js CHANGED
@@ -78,7 +78,7 @@ async function prepare(opts) {
78
78
  seed = null, platform = 'windows', proxy = null, geoip = null, args = null,
79
79
  stealthArgs = true, timezone = null, locale = null, extensionPaths = null,
80
80
  binary = null, licenseKey = null, licenseServer = null,
81
- licenseThroughProxy = false, licensePreflight = true,
81
+ licenseThroughProxy = false, licensePreflight = true, headless = false,
82
82
  } = opts;
83
83
  if (licensePreflight) license.preflight(licenseKey, licenseServer);
84
84
  const { key } = license.effective(licenseKey, licenseServer);
@@ -87,6 +87,7 @@ async function prepare(opts) {
87
87
  const { launchOptions, args: proxyArgs } = proxyAndGeoArgs(proxy, geoip);
88
88
  const launchArgs = proxyArgs.concat(buildArgs({
89
89
  seed: finalSeed, platform, stealthArgs, timezone, locale, extensionPaths, extra: args,
90
+ headless,
90
91
  }));
91
92
  if (licenseThroughProxy) launchArgs.push('--license-through-proxy');
92
93
  const env = license.childEnv(licenseKey, licenseServer);
@@ -121,10 +122,11 @@ async function buildLaunchOptions(opts = {}) {
121
122
  } = opts;
122
123
  const prep = await prepare({
123
124
  seed, platform, proxy, geoip, args, stealthArgs, timezone, locale, extensionPaths,
124
- binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight,
125
+ binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight, headless,
125
126
  });
126
127
  return {
127
128
  executablePath: prep.binPath, headless, args: prep.launchArgs, env: prep.env,
129
+ ignoreDefaultArgs: config.IGNORE_DEFAULT_ARGS, // strip automation + forced-software WebGL defaults
128
130
  ...prep.launchOptions, ...rest,
129
131
  };
130
132
  }
@@ -174,13 +176,14 @@ async function launch(opts = {}) {
174
176
  } = opts;
175
177
  const prep = await prepare({
176
178
  seed, platform, proxy, geoip, args, stealthArgs, timezone, locale, extensionPaths,
177
- binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight,
179
+ binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight, headless,
178
180
  });
179
181
  const pw = requireDriver();
180
182
  let browser;
181
183
  try {
182
184
  browser = await pw.chromium.launch({
183
185
  executablePath: prep.binPath, headless, args: prep.launchArgs, env: prep.env,
186
+ ignoreDefaultArgs: config.IGNORE_DEFAULT_ARGS, // strip automation + forced-software WebGL defaults
184
187
  ...prep.launchOptions, ...rest,
185
188
  });
186
189
  } catch (e) {
@@ -204,7 +207,7 @@ async function launchPersistentContext(userDataDir, opts = {}) {
204
207
  } = opts;
205
208
  const prep = await prepare({
206
209
  seed, platform, proxy, geoip, args, stealthArgs, timezone, locale, extensionPaths,
207
- binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight,
210
+ binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight, headless,
208
211
  });
209
212
  // Default to the page filling the window (see launchContext) unless the caller pinned a
210
213
  // viewport themselves. viewport: null is Playwright-JS for "no fixed viewport".
@@ -214,6 +217,7 @@ async function launchPersistentContext(userDataDir, opts = {}) {
214
217
  try {
215
218
  ctx = await pw.chromium.launchPersistentContext(userDataDir, {
216
219
  executablePath: prep.binPath, headless, args: prep.launchArgs, env: prep.env,
220
+ ignoreDefaultArgs: config.IGNORE_DEFAULT_ARGS, // strip automation + forced-software WebGL defaults
217
221
  ...prep.launchOptions, ...rest,
218
222
  });
219
223
  } catch (e) {
package/puppeteer.js CHANGED
@@ -78,7 +78,7 @@ async function prepare(opts) {
78
78
  seed = null, platform = 'windows', proxy = null, geoip = null, args = null,
79
79
  stealthArgs = true, timezone = null, locale = null, extensionPaths = null,
80
80
  binary = null, licenseKey = null, licenseServer = null,
81
- licenseThroughProxy = false, licensePreflight = true,
81
+ licenseThroughProxy = false, licensePreflight = true, headless = false,
82
82
  } = opts;
83
83
  if (licensePreflight) license.preflight(licenseKey, licenseServer);
84
84
  const { key } = license.effective(licenseKey, licenseServer);
@@ -87,6 +87,7 @@ async function prepare(opts) {
87
87
  const { launchOptions, args: proxyArgs } = proxyAndGeoArgs(proxy, geoip);
88
88
  const launchArgs = proxyArgs.concat(buildArgs({
89
89
  seed: finalSeed, platform, stealthArgs, timezone, locale, extensionPaths, extra: args,
90
+ headless,
90
91
  }));
91
92
  if (licenseThroughProxy) launchArgs.push('--license-through-proxy');
92
93
  const env = license.childEnv(licenseKey, licenseServer);
@@ -135,7 +136,7 @@ async function buildLaunchOptions(opts = {}) {
135
136
  } = opts;
136
137
  const prep = await prepare({
137
138
  seed, platform, proxy, geoip, args, stealthArgs, timezone, locale, extensionPaths,
138
- binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight,
139
+ binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight, headless,
139
140
  });
140
141
  const proxyOption = prep.launchOptions.proxy || null;
141
142
  const launchArgs = [...prep.launchArgs];
@@ -149,7 +150,7 @@ async function buildLaunchOptions(opts = {}) {
149
150
  args: launchArgs,
150
151
  env: prep.env,
151
152
  defaultViewport: 'defaultViewport' in rest ? rest.defaultViewport : null,
152
- ignoreDefaultArgs: ignoreDefaultArgs === undefined ? ['--enable-automation'] : ignoreDefaultArgs,
153
+ ignoreDefaultArgs: ignoreDefaultArgs === undefined ? config.IGNORE_DEFAULT_ARGS : ignoreDefaultArgs,
153
154
  ...rest,
154
155
  };
155
156
  }
@@ -167,7 +168,7 @@ async function launch(opts = {}) {
167
168
  } = opts;
168
169
  const prep = await prepare({
169
170
  seed, platform, proxy, geoip, args, stealthArgs, timezone, locale, extensionPaths,
170
- binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight,
171
+ binary, licenseKey, licenseServer, licenseThroughProxy, licensePreflight, headless,
171
172
  });
172
173
  const puppeteer = requireDriver();
173
174
  // The CDP escape hatch puts {proxy: {server, username?, ...}} in launchOptions; Puppeteer
@@ -178,8 +179,8 @@ async function launch(opts = {}) {
178
179
  launchArgs.push(`--proxy-server=${proxyOption.server}`);
179
180
  if (proxyOption.bypass) launchArgs.push(`--proxy-bypass-list=${proxyOption.bypass}`);
180
181
  }
181
- // Strip Puppeteer's --enable-automation unless the caller took over ignoreDefaultArgs.
182
- const ida = ignoreDefaultArgs === undefined ? ['--enable-automation'] : ignoreDefaultArgs;
182
+ // Strip automation + forced-software WebGL defaults unless the caller took over ignoreDefaultArgs.
183
+ const ida = ignoreDefaultArgs === undefined ? config.IGNORE_DEFAULT_ARGS : ignoreDefaultArgs;
183
184
  let browser;
184
185
  try {
185
186
  browser = await puppeteer.launch({