@webhands/core 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -131,8 +131,18 @@ This is **off by default** — vanilla Playwright stays the default. To enable i
131
131
  Chrome with or without the Patchright path, and stealth with or without a
132
132
  system browser. Other channel names work too (e.g. `msedge`).
133
133
 
134
- Programmatic equivalent (the `--stealth` / `--use-system-browser` flags map onto
135
- these transport options):
134
+ 3. Optional extra hardening. `--no-viewport` lets the real browser window drive
135
+ its own size instead of Playwright's fixed 1280x720 emulated viewport (a
136
+ known headless tell). It is **defaulted ON under `--stealth`** (Patchright's
137
+ recommended recipe) and is overridable; pass `--viewport` to keep the fixed
138
+ viewport even under stealth. webhands deliberately does **not** override
139
+ `user-agent`, `locale`, `timezone`, or `headers`: a wrong UA is a bigger tell
140
+ than none.
141
+
142
+ Programmatic equivalent (the `--stealth` / `--use-system-browser` /
143
+ `--no-viewport` flags map onto these transport options; the constructor also
144
+ takes `extraLaunchArgs` and `ignoreDefaultArgs` escape hatches for additional
145
+ hardening flags, none of which touch the `OpenTarget` seam):
136
146
 
137
147
  ```ts
138
148
  import {PlaywrightLaunchTransport} from '@webhands/core';
@@ -140,7 +150,7 @@ import {PlaywrightLaunchTransport} from '@webhands/core';
140
150
  const transport = new PlaywrightLaunchTransport(
141
151
  {}, // profile location (omit for ~/.webhands)
142
152
  [], // extra hands
143
- {stealth: true, systemBrowser: 'chrome'},
153
+ {stealth: true, systemBrowser: 'chrome'}, // noViewport defaults to true here
144
154
  );
145
155
  // Stealth + headed + a real logged-in profile is the strongest recipe:
146
156
  const session = await transport.open({
@@ -156,7 +166,9 @@ It **never silently falls back** to vanilla Playwright, because that would put
156
166
  the tell back without telling you.
157
167
 
158
168
  **Honest caveat.** Stealth addresses ONLY the CDP `Runtime.enable` automation
159
- tell. It is **necessary-but-not-sufficient**: IP reputation and session/profile
169
+ tell, and the launch-hardening knobs (`--no-viewport`, `extraLaunchArgs`,
170
+ `ignoreDefaultArgs`) reduce but do **not** eliminate detection. They are
171
+ **necessary-but-not-sufficient**: IP reputation and session/profile
160
172
  reputation still matter. The realistic recipe is stealth +
161
173
  `systemBrowser: 'chrome'` + headed + a warmed, logged-in profile + a residential
162
174
  IP (see
@@ -56,6 +56,53 @@ export interface PlaywrightLaunchTransportOptions {
56
56
  * Playwright vocabulary out of the public surface).
57
57
  */
58
58
  readonly systemBrowser?: string;
59
+ /**
60
+ * Don't impose a fixed emulated viewport: let the browser window drive its own
61
+ * size, exactly as a real user's browser does. Maps to Playwright's
62
+ * `viewport: null` on the persistent context.
63
+ *
64
+ * Why this matters for hardening: Playwright's DEFAULT is a fixed 1280x720
65
+ * emulated viewport that does NOT match the real OS window, a discrepancy
66
+ * (e.g. `window.outerWidth`/`innerWidth`/`screen` mismatches, no real resize
67
+ * behaviour) that fingerprinting scripts read as a headless/automation tell.
68
+ * Patchright's official recommended recipe sets `no_viewport=True` for this
69
+ * reason.
70
+ *
71
+ * Default: `undefined` leaves Playwright's behaviour as-is, EXCEPT that when
72
+ * {@link stealth} is enabled it defaults to `true` (the Patchright recipe).
73
+ * Pass an explicit `false` to keep the fixed emulated viewport even under
74
+ * stealth (e.g. when a caller deliberately wants a deterministic size). We pick
75
+ * the stealth-on default because shipping the stealth engine while leaving the
76
+ * tell it is meant to hide in place would be self-defeating; making it an
77
+ * explicit, overridable default keeps that honest and discoverable.
78
+ */
79
+ readonly noViewport?: boolean;
80
+ /**
81
+ * Extra command-line args appended to the browser launch (Playwright's
82
+ * `args`). An escape hatch for well-known hardening flags Patchright/Chromium
83
+ * users pass (e.g. `--disable-blink-features=AutomationControlled`) WITHOUT
84
+ * leaking a Playwright type across the seam: this is a plain `string[]`, kept
85
+ * confined to this transport-construction policy and deliberately NOT on
86
+ * {@link OpenTarget} (ADR-0003). Default: none.
87
+ *
88
+ * Caveat: args are passed THROUGH verbatim; a wrong or contradictory flag can
89
+ * itself become a tell or break the launch. Opt-in only.
90
+ */
91
+ readonly extraLaunchArgs?: readonly string[];
92
+ /**
93
+ * Passthrough for Playwright's `ignoreDefaultArgs`: either `true` to drop ALL
94
+ * of Playwright's default launch args, or a list of specific default args to
95
+ * drop, so a caller can strip more automation-flavoured defaults than the
96
+ * built-in stealth subset.
97
+ *
98
+ * When omitted, the stealth path still drops `--enable-automation` on its own
99
+ * (unchanged behaviour). When provided, this value REPLACES that built-in
100
+ * choice, so a caller opting in owns the full list (pass
101
+ * `['--enable-automation', ...]` to keep it). Like {@link extraLaunchArgs}
102
+ * this is a plain value confined to this module, never on {@link OpenTarget}.
103
+ * Default: none.
104
+ */
105
+ readonly ignoreDefaultArgs?: boolean | readonly string[];
59
106
  /**
60
107
  * INTERNAL test seam: override how the stealth chromium is imported. Omit in
61
108
  * production (defaults to `import('patchright')`). See
@@ -98,9 +145,11 @@ export declare class PlaywrightLaunchTransport implements Transport {
98
145
  * the operator's explicit config; the transport does NOT discover them. Omit
99
146
  * for the built-ins-only surface.
100
147
  * @param options transport-construction policy, notably the opt-in `stealth`
101
- * toggle and optional `systemBrowser` (see
148
+ * toggle, optional `systemBrowser`, and the launch-hardening knobs
149
+ * (`noViewport`, `extraLaunchArgs`, `ignoreDefaultArgs`; see
102
150
  * {@link PlaywrightLaunchTransportOptions}). Defaults to vanilla Playwright,
103
- * bundled Chromium, stealth OFF.
151
+ * bundled Chromium, stealth OFF. The hardening knobs are confined to this
152
+ * module and never reach {@link OpenTarget} (ADR-0003).
104
153
  */
105
154
  constructor(location?: ProfileLocationOptions, hands?: readonly Hand[], options?: PlaywrightLaunchTransportOptions);
106
155
  open(target: OpenTarget): Promise<Session>;
@@ -1 +1 @@
1
- {"version":3,"file":"playwright-launch-transport.d.ts","sourceRoot":"","sources":["../src/playwright-launch-transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAiC,MAAM,YAAY,CAAC;AAMpE,OAAO,EAAmB,KAAK,IAAI,EAAmB,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAEN,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAC,MAAM,WAAW,CAAC;AAE9D;;;;;;;;GAQG;AACH,KAAK,gBAAgB,GAAG,IAAI,CAAC,OAAO,QAAQ,EAAE,yBAAyB,CAAC,CAAC;AAEzE,oEAAoE;AACpE,UAAU,aAAa;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,gCAAgC;IAChD;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,uBAAuB,CAAC;CACzD;AAmBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,yBAA0B,YAAW,SAAS;;IAO1D;;;;;;;;;;;;OAYG;gBAEF,QAAQ,GAAE,sBAA2B,EACrC,KAAK,GAAE,SAAS,IAAI,EAAO,EAC3B,OAAO,GAAE,gCAAqC;IAUzC,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;CA8FhD"}
1
+ {"version":3,"file":"playwright-launch-transport.d.ts","sourceRoot":"","sources":["../src/playwright-launch-transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAiC,MAAM,YAAY,CAAC;AAMpE,OAAO,EAAmB,KAAK,IAAI,EAAmB,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAEN,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAC,MAAM,WAAW,CAAC;AAE9D;;;;;;;;GAQG;AACH,KAAK,gBAAgB,GAAG,IAAI,CAAC,OAAO,QAAQ,EAAE,yBAAyB,CAAC,CAAC;AAEzE,oEAAoE;AACpE,UAAU,aAAa;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,gCAAgC;IAChD;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;IACzD;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,uBAAuB,CAAC;CACzD;AAmBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,yBAA0B,YAAW,SAAS;;IAU1D;;;;;;;;;;;;;;OAcG;gBAEF,QAAQ,GAAE,sBAA2B,EACrC,KAAK,GAAE,SAAS,IAAI,EAAO,EAC3B,OAAO,GAAE,gCAAqC;IAazC,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;CAyHhD"}
@@ -47,6 +47,9 @@ export class PlaywrightLaunchTransport {
47
47
  #hands;
48
48
  #stealth;
49
49
  #systemBrowser;
50
+ #noViewport;
51
+ #extraLaunchArgs;
52
+ #ignoreDefaultArgs;
50
53
  #importStealthChromium;
51
54
  /**
52
55
  * @param location overrides for where profiles live (a `root` dir and/or an
@@ -57,15 +60,20 @@ export class PlaywrightLaunchTransport {
57
60
  * the operator's explicit config; the transport does NOT discover them. Omit
58
61
  * for the built-ins-only surface.
59
62
  * @param options transport-construction policy, notably the opt-in `stealth`
60
- * toggle and optional `systemBrowser` (see
63
+ * toggle, optional `systemBrowser`, and the launch-hardening knobs
64
+ * (`noViewport`, `extraLaunchArgs`, `ignoreDefaultArgs`; see
61
65
  * {@link PlaywrightLaunchTransportOptions}). Defaults to vanilla Playwright,
62
- * bundled Chromium, stealth OFF.
66
+ * bundled Chromium, stealth OFF. The hardening knobs are confined to this
67
+ * module and never reach {@link OpenTarget} (ADR-0003).
63
68
  */
64
69
  constructor(location = {}, hands = [], options = {}) {
65
70
  this.#location = location;
66
71
  this.#hands = hands;
67
72
  this.#stealth = options.stealth === true;
68
73
  this.#systemBrowser = options.systemBrowser;
74
+ this.#noViewport = options.noViewport;
75
+ this.#extraLaunchArgs = options.extraLaunchArgs;
76
+ this.#ignoreDefaultArgs = options.ignoreDefaultArgs;
69
77
  this.#importStealthChromium =
70
78
  options.importStealthChromium ?? defaultStealthImporter;
71
79
  }
@@ -100,9 +108,35 @@ export class PlaywrightLaunchTransport {
100
108
  if (this.#systemBrowser !== undefined) {
101
109
  launchOptions.channel = this.#systemBrowser;
102
110
  }
103
- if (this.#stealth) {
111
+ // no_viewport: explicit caller choice wins; otherwise default to TRUE under
112
+ // stealth (Patchright's recommended recipe), and leave Playwright's default
113
+ // fixed viewport in place when stealth is off. `viewport: null` is how
114
+ // Playwright expresses "let the real window drive the size".
115
+ const noViewport = this.#noViewport ?? this.#stealth;
116
+ if (noViewport) {
117
+ launchOptions.viewport = null;
118
+ }
119
+ // ignoreDefaultArgs: an explicit passthrough REPLACES the built-in stealth
120
+ // choice (the caller then owns the full list). With no passthrough, the
121
+ // stealth path keeps dropping just `--enable-automation` so it cannot re-add
122
+ // the fingerprint Patchright just removed.
123
+ if (this.#ignoreDefaultArgs !== undefined) {
124
+ launchOptions.ignoreDefaultArgs =
125
+ typeof this.#ignoreDefaultArgs === 'boolean'
126
+ ? this.#ignoreDefaultArgs
127
+ : [...this.#ignoreDefaultArgs];
128
+ }
129
+ else if (this.#stealth) {
104
130
  launchOptions.ignoreDefaultArgs = ['--enable-automation'];
105
131
  }
132
+ // Extra launch args (the hardening escape hatch) are appended verbatim. We do
133
+ // NOT set user-agent/locale/timezone/headers here: a wrong UA is a bigger
134
+ // tell than none (Patchright warns against overriding them), so those stay
135
+ // untouched by default.
136
+ if (this.#extraLaunchArgs !== undefined &&
137
+ this.#extraLaunchArgs.length > 0) {
138
+ launchOptions.args = [...this.#extraLaunchArgs];
139
+ }
106
140
  let context;
107
141
  try {
108
142
  context = await launcher.launchPersistentContext(loc.profileDir, launchOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"playwright-launch-transport.js","sourceRoot":"","sources":["../src/playwright-launch-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAC,QAAQ,EAAiC,MAAM,YAAY,CAAC;AACpE,OAAO,EACN,yBAAyB,EACzB,mBAAmB,EACnB,6BAA6B,GAC7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,gBAAgB,EAA8B,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EACN,sBAAsB,GAEtB,MAAM,uBAAuB,CAAC;AAoE/B;;;;;GAKG;AACH,MAAM,eAAe,GAAG,YAAY,CAAC;AAErC,uEAAuE;AACvE,MAAM,sBAAsB,GAA4B,KAAK,IAAI,EAAE;IAClE,sEAAsE;IACtE,2EAA2E;IAC3E,iDAAiD;IACjD,MAAM,SAAS,GAAG,eAAe,CAAC;IAClC,OAAO,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAA6B,CAAC;AAC9D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,yBAAyB;IAC5B,SAAS,CAAyB;IAClC,MAAM,CAAkB;IACxB,QAAQ,CAAU;IAClB,cAAc,CAAqB;IACnC,sBAAsB,CAA0B;IAEzD;;;;;;;;;;;;OAYG;IACH,YACC,WAAmC,EAAE,EACrC,QAAyB,EAAE,EAC3B,UAA4C,EAAE;QAE9C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC;QACzC,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;QAC5C,IAAI,CAAC,sBAAsB;YAC1B,OAAO,CAAC,qBAAqB,IAAI,sBAAsB,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAkB;QAC5B,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACd,mDAAmD;gBAClD,IAAI,MAAM,CAAC,IAAI,qCAAqC,CACrD,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnE,0EAA0E;QAC1E,oEAAoE;QACpE,wEAAwE;QACxE,0EAA0E;QAC1E,wEAAwE;QACxE,WAAW;QACX,IAAI,CAAC,CAAC,MAAM,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;QAExC,0EAA0E;QAC1E,6EAA6E;QAC7E,sDAAsD;QACtD,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;YAC7B,CAAC,CAAC,MAAM,IAAI,CAAC,uBAAuB,EAAE;YACtC,CAAC,CAAC,QAAQ,CAAC;QAEZ,6EAA6E;QAC7E,4EAA4E;QAC5E,yEAAyE;QACzE,sEAAsE;QACtE,MAAM,aAAa,GAEZ,EAAC,QAAQ,EAAC,CAAC;QAClB,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YACvC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC;QAC7C,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,aAAa,CAAC,iBAAiB,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,OAAuB,CAAC;QAC5B,IAAI,CAAC;YACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAC/C,GAAG,CAAC,UAAU,EACd,aAAa,CACb,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnC,sEAAsE;gBACtE,qEAAqE;gBACrE,iEAAiE;gBACjE,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,IAAI,UAAU,CAAC;gBAClD,MAAM,IAAI,yBAAyB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAC,KAAK,EAAC,CAAC,CAAC;YAClE,CAAC;YACD,MAAM,KAAK,CAAC;QACb,CAAC;QAED,0EAA0E;QAC1E,2EAA2E;QAC3E,yCAAyC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,OAAO,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,uBAAuB;QAC5B,IAAI,GAAkB,CAAC;QACvB,IAAI,CAAC;YACJ,GAAG,GAAG,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,6BAA6B,CAAC,YAAY,EAAE,SAAS,EAAE;gBAChE,KAAK;aACL,CAAC,CAAC;QACJ,CAAC;QACD,IACC,GAAG,KAAK,IAAI;YACZ,OAAO,GAAG,KAAK,QAAQ;YACvB,OAAO,GAAG,CAAC,QAAQ,EAAE,uBAAuB,KAAK,UAAU,EAC1D,CAAC;YACF,MAAM,IAAI,6BAA6B,CAAC,YAAY,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,CAAC;IACrB,CAAC;CACD;AAED,iDAAiD;AACjD,KAAK,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,CAAC;QACJ,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,sBAAsB,CAAC,KAAc;IAC7C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7E,OAAO,CACN,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC;QACzC,4DAA4D,CAAC,IAAI,CAChE,OAAO,CACP;QACD,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC;QACnC,0EAA0E;QAC1E,0CAA0C,CAAC,IAAI,CAAC,OAAO,CAAC;QACxD,2CAA2C,CAAC,IAAI,CAAC,OAAO,CAAC,CACzD,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,WAAW,CACnB,OAAuB,EACvB,MAAY,EACZ,UAA2B;IAE3B,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,MAAM,UAAU,GAAG,GAAG,EAAE;QACvB,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACtC,CAAC;IACF,CAAC,CAAC;IAEF,4EAA4E;IAC5E,yEAAyE;IACzE,yEAAyE;IACzE,mDAAmD;IACnD,IAAI,aAA0B,CAAC;IAC/B,MAAM,YAAY,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClD,aAAa,GAAG,OAAO,CAAC;IACzB,CAAC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,GAAG,EAAE;QACvB,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,aAAa,EAAE,CAAC;IACjB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAEhC,2EAA2E;IAC3E,8EAA8E;IAC9E,mEAAmE;IACnE,MAAM,WAAW,GAAgB,EAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAC,CAAC;IAC/D,MAAM,EAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAC,GAAG,gBAAgB,CACrD,WAAW,EACX,UAAU,CACV,CAAC;IAEF,OAAO;QACN,IAAI;QACJ,KAAK,CAAC,KAAK;YACV,IAAI,MAAM,EAAE,CAAC;gBACZ,OAAO;YACR,CAAC;YACD,uEAAuE;YACvE,mEAAmE;YACnE,2DAA2D;YAC3D,MAAM,YAAY,EAAE,CAAC;YACrB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,UAAU,EAAE,CAAC;QACd,CAAC;QACD,YAAY;YACX,OAAO,YAAY,CAAC;QACrB,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"playwright-launch-transport.js","sourceRoot":"","sources":["../src/playwright-launch-transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webhands/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Core library for webhands: drives a real, persistent browser via Playwright.",
5
5
  "keywords": [
6
6
  "browser",
@@ -69,6 +69,53 @@ export interface PlaywrightLaunchTransportOptions {
69
69
  * Playwright vocabulary out of the public surface).
70
70
  */
71
71
  readonly systemBrowser?: string;
72
+ /**
73
+ * Don't impose a fixed emulated viewport: let the browser window drive its own
74
+ * size, exactly as a real user's browser does. Maps to Playwright's
75
+ * `viewport: null` on the persistent context.
76
+ *
77
+ * Why this matters for hardening: Playwright's DEFAULT is a fixed 1280x720
78
+ * emulated viewport that does NOT match the real OS window, a discrepancy
79
+ * (e.g. `window.outerWidth`/`innerWidth`/`screen` mismatches, no real resize
80
+ * behaviour) that fingerprinting scripts read as a headless/automation tell.
81
+ * Patchright's official recommended recipe sets `no_viewport=True` for this
82
+ * reason.
83
+ *
84
+ * Default: `undefined` leaves Playwright's behaviour as-is, EXCEPT that when
85
+ * {@link stealth} is enabled it defaults to `true` (the Patchright recipe).
86
+ * Pass an explicit `false` to keep the fixed emulated viewport even under
87
+ * stealth (e.g. when a caller deliberately wants a deterministic size). We pick
88
+ * the stealth-on default because shipping the stealth engine while leaving the
89
+ * tell it is meant to hide in place would be self-defeating; making it an
90
+ * explicit, overridable default keeps that honest and discoverable.
91
+ */
92
+ readonly noViewport?: boolean;
93
+ /**
94
+ * Extra command-line args appended to the browser launch (Playwright's
95
+ * `args`). An escape hatch for well-known hardening flags Patchright/Chromium
96
+ * users pass (e.g. `--disable-blink-features=AutomationControlled`) WITHOUT
97
+ * leaking a Playwright type across the seam: this is a plain `string[]`, kept
98
+ * confined to this transport-construction policy and deliberately NOT on
99
+ * {@link OpenTarget} (ADR-0003). Default: none.
100
+ *
101
+ * Caveat: args are passed THROUGH verbatim; a wrong or contradictory flag can
102
+ * itself become a tell or break the launch. Opt-in only.
103
+ */
104
+ readonly extraLaunchArgs?: readonly string[];
105
+ /**
106
+ * Passthrough for Playwright's `ignoreDefaultArgs`: either `true` to drop ALL
107
+ * of Playwright's default launch args, or a list of specific default args to
108
+ * drop, so a caller can strip more automation-flavoured defaults than the
109
+ * built-in stealth subset.
110
+ *
111
+ * When omitted, the stealth path still drops `--enable-automation` on its own
112
+ * (unchanged behaviour). When provided, this value REPLACES that built-in
113
+ * choice, so a caller opting in owns the full list (pass
114
+ * `['--enable-automation', ...]` to keep it). Like {@link extraLaunchArgs}
115
+ * this is a plain value confined to this module, never on {@link OpenTarget}.
116
+ * Default: none.
117
+ */
118
+ readonly ignoreDefaultArgs?: boolean | readonly string[];
72
119
  /**
73
120
  * INTERNAL test seam: override how the stealth chromium is imported. Omit in
74
121
  * production (defaults to `import('patchright')`). See
@@ -123,6 +170,9 @@ export class PlaywrightLaunchTransport implements Transport {
123
170
  readonly #hands: readonly Hand[];
124
171
  readonly #stealth: boolean;
125
172
  readonly #systemBrowser: string | undefined;
173
+ readonly #noViewport: boolean | undefined;
174
+ readonly #extraLaunchArgs: readonly string[] | undefined;
175
+ readonly #ignoreDefaultArgs: boolean | readonly string[] | undefined;
126
176
  readonly #importStealthChromium: StealthChromiumImporter;
127
177
 
128
178
  /**
@@ -134,9 +184,11 @@ export class PlaywrightLaunchTransport implements Transport {
134
184
  * the operator's explicit config; the transport does NOT discover them. Omit
135
185
  * for the built-ins-only surface.
136
186
  * @param options transport-construction policy, notably the opt-in `stealth`
137
- * toggle and optional `systemBrowser` (see
187
+ * toggle, optional `systemBrowser`, and the launch-hardening knobs
188
+ * (`noViewport`, `extraLaunchArgs`, `ignoreDefaultArgs`; see
138
189
  * {@link PlaywrightLaunchTransportOptions}). Defaults to vanilla Playwright,
139
- * bundled Chromium, stealth OFF.
190
+ * bundled Chromium, stealth OFF. The hardening knobs are confined to this
191
+ * module and never reach {@link OpenTarget} (ADR-0003).
140
192
  */
141
193
  constructor(
142
194
  location: ProfileLocationOptions = {},
@@ -147,6 +199,9 @@ export class PlaywrightLaunchTransport implements Transport {
147
199
  this.#hands = hands;
148
200
  this.#stealth = options.stealth === true;
149
201
  this.#systemBrowser = options.systemBrowser;
202
+ this.#noViewport = options.noViewport;
203
+ this.#extraLaunchArgs = options.extraLaunchArgs;
204
+ this.#ignoreDefaultArgs = options.ignoreDefaultArgs;
150
205
  this.#importStealthChromium =
151
206
  options.importStealthChromium ?? defaultStealthImporter;
152
207
  }
@@ -191,9 +246,36 @@ export class PlaywrightLaunchTransport implements Transport {
191
246
  if (this.#systemBrowser !== undefined) {
192
247
  launchOptions.channel = this.#systemBrowser;
193
248
  }
194
- if (this.#stealth) {
249
+ // no_viewport: explicit caller choice wins; otherwise default to TRUE under
250
+ // stealth (Patchright's recommended recipe), and leave Playwright's default
251
+ // fixed viewport in place when stealth is off. `viewport: null` is how
252
+ // Playwright expresses "let the real window drive the size".
253
+ const noViewport = this.#noViewport ?? this.#stealth;
254
+ if (noViewport) {
255
+ launchOptions.viewport = null;
256
+ }
257
+ // ignoreDefaultArgs: an explicit passthrough REPLACES the built-in stealth
258
+ // choice (the caller then owns the full list). With no passthrough, the
259
+ // stealth path keeps dropping just `--enable-automation` so it cannot re-add
260
+ // the fingerprint Patchright just removed.
261
+ if (this.#ignoreDefaultArgs !== undefined) {
262
+ launchOptions.ignoreDefaultArgs =
263
+ typeof this.#ignoreDefaultArgs === 'boolean'
264
+ ? this.#ignoreDefaultArgs
265
+ : [...this.#ignoreDefaultArgs];
266
+ } else if (this.#stealth) {
195
267
  launchOptions.ignoreDefaultArgs = ['--enable-automation'];
196
268
  }
269
+ // Extra launch args (the hardening escape hatch) are appended verbatim. We do
270
+ // NOT set user-agent/locale/timezone/headers here: a wrong UA is a bigger
271
+ // tell than none (Patchright warns against overriding them), so those stay
272
+ // untouched by default.
273
+ if (
274
+ this.#extraLaunchArgs !== undefined &&
275
+ this.#extraLaunchArgs.length > 0
276
+ ) {
277
+ launchOptions.args = [...this.#extraLaunchArgs];
278
+ }
197
279
 
198
280
  let context: BrowserContext;
199
281
  try {