@agentium/browser 2.1.0 → 2.1.1

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
@@ -118,29 +118,39 @@ function getStealthScript() {
118
118
  };
119
119
  }
120
120
 
121
- // \u2500\u2500 Prevent iframe detection of automation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
122
- Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
123
- get: function() {
124
- return window;
125
- },
126
- });
127
-
128
- // \u2500\u2500 Remove "cdc_" Playwright/ChromeDriver markers from DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500
129
- const observer = new MutationObserver((mutations) => {
130
- for (const mutation of mutations) {
131
- for (const node of mutation.addedNodes) {
132
- if (node.nodeType === 1) {
133
- const el = node;
134
- for (const attr of [...el.attributes]) {
135
- if (attr.name.startsWith('cdc_') || attr.name.startsWith('__playwright')) {
136
- el.removeAttribute(attr.name);
121
+ // \u2500\u2500 Remove "cdc_" Playwright/ChromeDriver markers from new elements \u2500
122
+ // Only watches childList additions, NOT every attribute mutation \u2014
123
+ // attributes:true subtree:true is O(every DOM write) on heavy SPAs
124
+ // like FreightOS and noticeably slows the page.
125
+ try {
126
+ const observer = new MutationObserver((mutations) => {
127
+ for (const mutation of mutations) {
128
+ for (const node of mutation.addedNodes) {
129
+ if (node && node.nodeType === 1) {
130
+ const el = node;
131
+ if (!el.attributes) continue;
132
+ for (const attr of [...el.attributes]) {
133
+ if (attr.name.startsWith('cdc_') || attr.name.startsWith('__playwright')) {
134
+ el.removeAttribute(attr.name);
135
+ }
137
136
  }
138
137
  }
139
138
  }
140
139
  }
140
+ });
141
+ if (document.documentElement) {
142
+ observer.observe(document.documentElement, { childList: true, subtree: true });
141
143
  }
142
- });
143
- observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true });
144
+ } catch (_e) { /* never break the page over a stealth patch */ }
145
+
146
+ // NOTE on iframe.contentWindow:
147
+ // We deliberately do NOT override HTMLIFrameElement.prototype.contentWindow.
148
+ // An earlier version returned the parent window, which breaks legitimate
149
+ // page JS on any site that uses iframes (checkout widgets, embedded
150
+ // videos, A/B test scripts, analytics). The "anti-detection" value was
151
+ // minimal \u2014 modern detectors don't rely on that property anyway \u2014 and
152
+ // the breakage caused pages to fail to boot, leaving font-test residue
153
+ // on screen.
144
154
  `;
145
155
  }
146
156
  function buildStealthContextOpts(config, viewport) {
@@ -226,14 +236,20 @@ var BrowserProvider = class {
226
236
  }
227
237
  const stealthEnabled = !!opts?.stealth;
228
238
  const stealthCfg = typeof opts?.stealth === "object" ? opts.stealth : {};
229
- const launchOpts = {
230
- headless: opts?.headless ?? true
231
- };
239
+ const headless = opts?.headless ?? true;
240
+ const launchOpts = { headless };
241
+ const args = [];
232
242
  if (stealthEnabled) {
233
- const { args, proxy } = buildStealthLaunchArgs(stealthCfg);
234
- launchOpts.args = args;
235
- if (proxy) launchOpts.proxy = proxy;
243
+ const stealth = buildStealthLaunchArgs(stealthCfg);
244
+ args.push(...stealth.args);
245
+ if (stealth.proxy) launchOpts.proxy = stealth.proxy;
246
+ }
247
+ if (!headless) {
248
+ const CHROME_VERTICAL_CHROME_PX = 140;
249
+ args.push(`--window-size=${this._viewport.width},${this._viewport.height + CHROME_VERTICAL_CHROME_PX}`);
250
+ args.push("--window-position=0,0");
236
251
  }
252
+ if (args.length) launchOpts.args = args;
237
253
  this.browser = await chromium.launch(launchOpts);
238
254
  let contextOpts;
239
255
  if (stealthEnabled) {
package/dist/index.js CHANGED
@@ -80,29 +80,39 @@ function getStealthScript() {
80
80
  };
81
81
  }
82
82
 
83
- // \u2500\u2500 Prevent iframe detection of automation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
84
- Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
85
- get: function() {
86
- return window;
87
- },
88
- });
89
-
90
- // \u2500\u2500 Remove "cdc_" Playwright/ChromeDriver markers from DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500
91
- const observer = new MutationObserver((mutations) => {
92
- for (const mutation of mutations) {
93
- for (const node of mutation.addedNodes) {
94
- if (node.nodeType === 1) {
95
- const el = node;
96
- for (const attr of [...el.attributes]) {
97
- if (attr.name.startsWith('cdc_') || attr.name.startsWith('__playwright')) {
98
- el.removeAttribute(attr.name);
83
+ // \u2500\u2500 Remove "cdc_" Playwright/ChromeDriver markers from new elements \u2500
84
+ // Only watches childList additions, NOT every attribute mutation \u2014
85
+ // attributes:true subtree:true is O(every DOM write) on heavy SPAs
86
+ // like FreightOS and noticeably slows the page.
87
+ try {
88
+ const observer = new MutationObserver((mutations) => {
89
+ for (const mutation of mutations) {
90
+ for (const node of mutation.addedNodes) {
91
+ if (node && node.nodeType === 1) {
92
+ const el = node;
93
+ if (!el.attributes) continue;
94
+ for (const attr of [...el.attributes]) {
95
+ if (attr.name.startsWith('cdc_') || attr.name.startsWith('__playwright')) {
96
+ el.removeAttribute(attr.name);
97
+ }
99
98
  }
100
99
  }
101
100
  }
102
101
  }
102
+ });
103
+ if (document.documentElement) {
104
+ observer.observe(document.documentElement, { childList: true, subtree: true });
103
105
  }
104
- });
105
- observer.observe(document.documentElement, { attributes: true, childList: true, subtree: true });
106
+ } catch (_e) { /* never break the page over a stealth patch */ }
107
+
108
+ // NOTE on iframe.contentWindow:
109
+ // We deliberately do NOT override HTMLIFrameElement.prototype.contentWindow.
110
+ // An earlier version returned the parent window, which breaks legitimate
111
+ // page JS on any site that uses iframes (checkout widgets, embedded
112
+ // videos, A/B test scripts, analytics). The "anti-detection" value was
113
+ // minimal \u2014 modern detectors don't rely on that property anyway \u2014 and
114
+ // the breakage caused pages to fail to boot, leaving font-test residue
115
+ // on screen.
106
116
  `;
107
117
  }
108
118
  function buildStealthContextOpts(config, viewport) {
@@ -188,14 +198,20 @@ var BrowserProvider = class {
188
198
  }
189
199
  const stealthEnabled = !!opts?.stealth;
190
200
  const stealthCfg = typeof opts?.stealth === "object" ? opts.stealth : {};
191
- const launchOpts = {
192
- headless: opts?.headless ?? true
193
- };
201
+ const headless = opts?.headless ?? true;
202
+ const launchOpts = { headless };
203
+ const args = [];
194
204
  if (stealthEnabled) {
195
- const { args, proxy } = buildStealthLaunchArgs(stealthCfg);
196
- launchOpts.args = args;
197
- if (proxy) launchOpts.proxy = proxy;
205
+ const stealth = buildStealthLaunchArgs(stealthCfg);
206
+ args.push(...stealth.args);
207
+ if (stealth.proxy) launchOpts.proxy = stealth.proxy;
208
+ }
209
+ if (!headless) {
210
+ const CHROME_VERTICAL_CHROME_PX = 140;
211
+ args.push(`--window-size=${this._viewport.width},${this._viewport.height + CHROME_VERTICAL_CHROME_PX}`);
212
+ args.push("--window-position=0,0");
198
213
  }
214
+ if (args.length) launchOpts.args = args;
199
215
  this.browser = await chromium.launch(launchOpts);
200
216
  let contextOpts;
201
217
  if (stealthEnabled) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentium/browser",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Browser automation agent for Agentium using Playwright",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -46,7 +46,7 @@
46
46
  "typescript": "^5.6.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@agentium/core": "^2.1.0",
49
+ "@agentium/core": "^2.1.1",
50
50
  "playwright": ">=1.40.0"
51
51
  },
52
52
  "peerDependenciesMeta": {