@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 +16 -4
- package/dist/playwright-launch-transport.d.ts +51 -2
- package/dist/playwright-launch-transport.d.ts.map +1 -1
- package/dist/playwright-launch-transport.js +37 -3
- package/dist/playwright-launch-transport.js.map +1 -1
- package/package.json +1 -1
- package/src/playwright-launch-transport.ts +85 -3
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
|
-
|
|
135
|
-
|
|
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
|
|
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
|
|
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;;
|
|
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
|
|
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
|
-
|
|
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;
|
|
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
|
@@ -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
|
|
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
|
-
|
|
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 {
|