playwright-core 1.55.0-alpha-2025-07-29 → 1.55.0-alpha-1753913825000
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/browsers.json +8 -8
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/protocol/validator.js +0 -16
- package/lib/server/android/android.js +54 -43
- package/lib/server/bidi/bidiPage.js +4 -0
- package/lib/server/browser.js +22 -18
- package/lib/server/browserContext.js +73 -46
- package/lib/server/browserType.js +67 -48
- package/lib/server/chromium/chromium.js +34 -28
- package/lib/server/chromium/crCoverage.js +3 -4
- package/lib/server/chromium/crDragDrop.js +17 -13
- package/lib/server/chromium/videoRecorder.js +10 -19
- package/lib/server/codegen/jsonl.js +2 -1
- package/lib/server/debugController.js +2 -18
- package/lib/server/deviceDescriptorsSource.json +2 -2
- package/lib/server/dispatchers/debugControllerDispatcher.js +0 -9
- package/lib/server/dispatchers/localUtilsDispatcher.js +0 -5
- package/lib/server/electron/electron.js +66 -66
- package/lib/server/fetch.js +6 -2
- package/lib/server/frames.js +6 -6
- package/lib/server/helper.js +4 -7
- package/lib/server/localUtils.js +23 -16
- package/lib/server/playwright.js +0 -4
- package/lib/server/progress.js +17 -11
- package/lib/server/recorder/recorderUtils.js +5 -0
- package/lib/server/recorder.js +61 -1
- package/lib/server/screenshotter.js +72 -56
- package/lib/server/socksClientCertificatesInterceptor.js +59 -43
- package/lib/server/transport.js +19 -15
- package/lib/server/utils/network.js +28 -17
- package/lib/server/utils/processLauncher.js +4 -1
- package/lib/utils/isomorphic/ariaSnapshot.js +58 -4
- package/lib/utils/isomorphic/protocolMetainfo.js +1 -5
- package/lib/utils/isomorphic/urlMatch.js +0 -2
- package/lib/vite/htmlReport/index.html +16 -16
- package/lib/vite/recorder/assets/{codeMirrorModule-cgtwtYOb.js → codeMirrorModule-B5Ye5Cij.js} +1 -1
- package/lib/vite/recorder/assets/{index-KWWSfrzB.js → index-B5VmX9JT.js} +48 -48
- package/lib/vite/recorder/index.html +1 -1
- package/lib/vite/traceViewer/assets/{codeMirrorModule-k_7BpzGX.js → codeMirrorModule-3XE5WU2G.js} +1 -1
- package/lib/vite/traceViewer/assets/{defaultSettingsView-CKM53V_K.js → defaultSettingsView-u5uZPktL.js} +103 -103
- package/lib/vite/traceViewer/{index.CCXGYfh2.js → index.CycYDQ3P.js} +1 -1
- package/lib/vite/traceViewer/index.html +2 -2
- package/lib/vite/traceViewer/{uiMode.CNa3x5Xj.js → uiMode.DeaA8YiP.js} +1 -1
- package/lib/vite/traceViewer/uiMode.html +2 -2
- package/package.json +1 -1
|
@@ -166,20 +166,20 @@ class Screenshotter {
|
|
|
166
166
|
progress.log("taking page screenshot");
|
|
167
167
|
const viewportSize = await this._originalViewportSize(progress);
|
|
168
168
|
await this._preparePageForScreenshot(progress, this._page.mainFrame(), options.style, options.caret !== "initial", options.animations === "disabled");
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
169
|
+
try {
|
|
170
|
+
if (options.fullPage) {
|
|
171
|
+
const fullPageSize = await this._fullPageSize(progress);
|
|
172
|
+
let documentRect = { x: 0, y: 0, width: fullPageSize.width, height: fullPageSize.height };
|
|
173
|
+
const fitsViewport = fullPageSize.width <= viewportSize.width && fullPageSize.height <= viewportSize.height;
|
|
174
|
+
if (options.clip)
|
|
175
|
+
documentRect = trimClipToSize(options.clip, documentRect);
|
|
176
|
+
return await this._screenshot(progress, format, documentRect, void 0, fitsViewport, options);
|
|
177
|
+
}
|
|
178
|
+
const viewportRect = options.clip ? trimClipToSize(options.clip, viewportSize) : { x: 0, y: 0, ...viewportSize };
|
|
179
|
+
return await this._screenshot(progress, format, void 0, viewportRect, true, options);
|
|
180
|
+
} finally {
|
|
176
181
|
await this._restorePageAfterScreenshot();
|
|
177
|
-
return buffer2;
|
|
178
182
|
}
|
|
179
|
-
const viewportRect = options.clip ? trimClipToSize(options.clip, viewportSize) : { x: 0, y: 0, ...viewportSize };
|
|
180
|
-
const buffer = await this._screenshot(progress, format, void 0, viewportRect, true, options);
|
|
181
|
-
await this._restorePageAfterScreenshot();
|
|
182
|
-
return buffer;
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
async screenshotElement(progress, handle, options) {
|
|
@@ -188,36 +188,42 @@ class Screenshotter {
|
|
|
188
188
|
progress.log("taking element screenshot");
|
|
189
189
|
const viewportSize = await this._originalViewportSize(progress);
|
|
190
190
|
await this._preparePageForScreenshot(progress, handle._frame, options.style, options.caret !== "initial", options.animations === "disabled");
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
191
|
+
try {
|
|
192
|
+
await handle._waitAndScrollIntoViewIfNeeded(
|
|
193
|
+
progress,
|
|
194
|
+
true
|
|
195
|
+
/* waitForVisible */
|
|
196
|
+
);
|
|
197
|
+
const boundingBox = await progress.race(handle.boundingBox());
|
|
198
|
+
(0, import_utils.assert)(boundingBox, "Node is either not visible or not an HTMLElement");
|
|
199
|
+
(0, import_utils.assert)(boundingBox.width !== 0, "Node has 0 width.");
|
|
200
|
+
(0, import_utils.assert)(boundingBox.height !== 0, "Node has 0 height.");
|
|
201
|
+
const fitsViewport = boundingBox.width <= viewportSize.width && boundingBox.height <= viewportSize.height;
|
|
202
|
+
const scrollOffset = await this._page.mainFrame().waitForFunctionValueInUtility(progress, () => ({ x: window.scrollX, y: window.scrollY }));
|
|
203
|
+
const documentRect = { ...boundingBox };
|
|
204
|
+
documentRect.x += scrollOffset.x;
|
|
205
|
+
documentRect.y += scrollOffset.y;
|
|
206
|
+
return await this._screenshot(progress, format, import_helper.helper.enclosingIntRect(documentRect), void 0, fitsViewport, options);
|
|
207
|
+
} finally {
|
|
208
|
+
await this._restorePageAfterScreenshot();
|
|
209
|
+
}
|
|
208
210
|
});
|
|
209
211
|
}
|
|
210
212
|
async _preparePageForScreenshot(progress, frame, screenshotStyle, hideCaret, disableAnimations) {
|
|
211
213
|
if (disableAnimations)
|
|
212
214
|
progress.log(" disabled all CSS animations");
|
|
213
215
|
const syncAnimations = this._page.delegate.shouldToggleStyleSheetToSyncAnimations();
|
|
214
|
-
progress.cleanupWhenAborted(() => this._restorePageAfterScreenshot());
|
|
215
216
|
await progress.race(this._page.safeNonStallingEvaluateInAllFrames("(" + inPagePrepareForScreenshots.toString() + `)(${JSON.stringify(screenshotStyle)}, ${hideCaret}, ${disableAnimations}, ${syncAnimations})`, "utility"));
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
try {
|
|
218
|
+
if (!process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY) {
|
|
219
|
+
progress.log("waiting for fonts to load...");
|
|
220
|
+
await progress.race(frame.nonStallingEvaluateInExistingContext("document.fonts.ready", "utility").catch(() => {
|
|
221
|
+
}));
|
|
222
|
+
progress.log("fonts loaded");
|
|
223
|
+
}
|
|
224
|
+
} catch (error) {
|
|
225
|
+
await this._restorePageAfterScreenshot();
|
|
226
|
+
throw error;
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
async _restorePageAfterScreenshot() {
|
|
@@ -227,39 +233,49 @@ class Screenshotter {
|
|
|
227
233
|
if (!options.mask || !options.mask.length)
|
|
228
234
|
return () => Promise.resolve();
|
|
229
235
|
const framesToParsedSelectors = new import_multimap.MultiMap();
|
|
230
|
-
const cleanup = async () => {
|
|
231
|
-
await Promise.all([...framesToParsedSelectors.keys()].map(async (frame) => {
|
|
232
|
-
await frame.hideHighlight();
|
|
233
|
-
}));
|
|
234
|
-
};
|
|
235
|
-
progress.cleanupWhenAborted(cleanup);
|
|
236
236
|
await progress.race(Promise.all((options.mask || []).map(async ({ frame, selector }) => {
|
|
237
237
|
const pair = await frame.selectors.resolveFrameForSelector(selector);
|
|
238
238
|
if (pair)
|
|
239
239
|
framesToParsedSelectors.set(pair.frame, pair.info.parsed);
|
|
240
240
|
})));
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
const frames = [...framesToParsedSelectors.keys()];
|
|
242
|
+
const cleanup = async () => {
|
|
243
|
+
await Promise.all(frames.map((frame) => frame.hideHighlight()));
|
|
244
|
+
};
|
|
245
|
+
try {
|
|
246
|
+
const promises = frames.map((frame) => frame.maskSelectors(framesToParsedSelectors.get(frame), options.maskColor || "#F0F"));
|
|
247
|
+
await progress.race(Promise.all(promises));
|
|
248
|
+
return cleanup;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
cleanup().catch(() => {
|
|
251
|
+
});
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
245
254
|
}
|
|
246
255
|
async _screenshot(progress, format, documentRect, viewportRect, fitsViewport, options) {
|
|
247
256
|
if (options.__testHookBeforeScreenshot)
|
|
248
257
|
await progress.race(options.__testHookBeforeScreenshot());
|
|
249
258
|
const shouldSetDefaultBackground = options.omitBackground && format === "png";
|
|
250
|
-
if (shouldSetDefaultBackground)
|
|
251
|
-
progress.cleanupWhenAborted(() => this._page.delegate.setBackgroundColor());
|
|
259
|
+
if (shouldSetDefaultBackground)
|
|
252
260
|
await progress.race(this._page.delegate.setBackgroundColor({ r: 0, g: 0, b: 0, a: 0 }));
|
|
253
|
-
}
|
|
254
261
|
const cleanupHighlight = await this._maskElements(progress, options);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
try {
|
|
263
|
+
const quality = format === "jpeg" ? options.quality ?? 80 : void 0;
|
|
264
|
+
const buffer = await this._page.delegate.takeScreenshot(progress, format, documentRect, viewportRect, quality, fitsViewport, options.scale || "device");
|
|
265
|
+
await cleanupHighlight();
|
|
266
|
+
if (shouldSetDefaultBackground)
|
|
267
|
+
await this._page.delegate.setBackgroundColor();
|
|
268
|
+
if (options.__testHookAfterScreenshot)
|
|
269
|
+
await progress.race(options.__testHookAfterScreenshot());
|
|
270
|
+
return buffer;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
cleanupHighlight().catch(() => {
|
|
273
|
+
});
|
|
274
|
+
if (shouldSetDefaultBackground)
|
|
275
|
+
this._page.delegate.setBackgroundColor().catch(() => {
|
|
276
|
+
});
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
263
279
|
}
|
|
264
280
|
}
|
|
265
281
|
class TaskQueue {
|
|
@@ -44,6 +44,7 @@ var import_browserContext = require("./browserContext");
|
|
|
44
44
|
var import_network = require("./utils/network");
|
|
45
45
|
var import_debugLogger = require("./utils/debugLogger");
|
|
46
46
|
var import_happyEyeballs = require("./utils/happyEyeballs");
|
|
47
|
+
var import_utilsBundle = require("../utilsBundle");
|
|
47
48
|
let dummyServerTlsOptions = void 0;
|
|
48
49
|
function loadDummyServerCertsIfNeeded() {
|
|
49
50
|
if (dummyServerTlsOptions)
|
|
@@ -84,7 +85,7 @@ class ALPNCache {
|
|
|
84
85
|
}
|
|
85
86
|
class SocksProxyConnection {
|
|
86
87
|
constructor(socksProxy, uid, host, port) {
|
|
87
|
-
this.
|
|
88
|
+
this._firstPackageReceived = false;
|
|
88
89
|
this._closed = false;
|
|
89
90
|
this.socksProxy = socksProxy;
|
|
90
91
|
this.uid = uid;
|
|
@@ -92,55 +93,57 @@ class SocksProxyConnection {
|
|
|
92
93
|
this.port = port;
|
|
93
94
|
this._targetCloseEventListener = () => {
|
|
94
95
|
this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid });
|
|
95
|
-
this.
|
|
96
|
+
this._internalTLS?.destroy();
|
|
96
97
|
this._dummyServer?.close();
|
|
97
98
|
};
|
|
99
|
+
this._internal = new import_stream.default.Duplex({
|
|
100
|
+
read: () => {
|
|
101
|
+
},
|
|
102
|
+
write: (data, encoding, callback) => {
|
|
103
|
+
this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data });
|
|
104
|
+
callback();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
98
107
|
}
|
|
99
108
|
async connect() {
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
const proxyAgent = this.socksProxy.getProxyAgent(this.host, this.port);
|
|
110
|
+
if (proxyAgent)
|
|
111
|
+
this._target = await proxyAgent.callback(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
|
|
102
112
|
else
|
|
103
|
-
this.
|
|
104
|
-
this.
|
|
105
|
-
this.
|
|
113
|
+
this._target = await (0, import_happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
|
|
114
|
+
this._target.once("close", this._targetCloseEventListener);
|
|
115
|
+
this._target.once("error", (error) => this.socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message }));
|
|
106
116
|
if (this._closed) {
|
|
107
|
-
this.
|
|
117
|
+
this._target.destroy();
|
|
108
118
|
return;
|
|
109
119
|
}
|
|
110
120
|
this.socksProxy._socksProxy.socketConnected({
|
|
111
121
|
uid: this.uid,
|
|
112
|
-
host: this.
|
|
113
|
-
port: this.
|
|
122
|
+
host: this._target.localAddress,
|
|
123
|
+
port: this._target.localPort
|
|
114
124
|
});
|
|
115
125
|
}
|
|
116
126
|
onClose() {
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
127
|
+
this._target.destroy();
|
|
128
|
+
this._internalTLS?.destroy();
|
|
119
129
|
this._dummyServer?.close();
|
|
120
130
|
this._closed = true;
|
|
121
131
|
}
|
|
122
132
|
onData(data) {
|
|
123
|
-
if (!this.
|
|
124
|
-
this.
|
|
133
|
+
if (!this._firstPackageReceived) {
|
|
134
|
+
this._firstPackageReceived = true;
|
|
125
135
|
if (data[0] === 22)
|
|
126
|
-
this.
|
|
136
|
+
this._establishTlsTunnel(this._internal, data);
|
|
127
137
|
else
|
|
128
|
-
this.
|
|
138
|
+
this._establishPlaintextTunnel(this._internal);
|
|
129
139
|
}
|
|
130
|
-
|
|
131
|
-
this.internal.push(data);
|
|
132
|
-
else
|
|
133
|
-
this.target.write(data);
|
|
140
|
+
this._internal.push(data);
|
|
134
141
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data });
|
|
141
|
-
callback();
|
|
142
|
-
}
|
|
143
|
-
});
|
|
142
|
+
_establishPlaintextTunnel(internal) {
|
|
143
|
+
internal.pipe(this._target);
|
|
144
|
+
this._target.pipe(internal);
|
|
145
|
+
}
|
|
146
|
+
_establishTlsTunnel(internal, clientHello) {
|
|
144
147
|
this.socksProxy.alpnCache.get(rewriteToLocalhostIfNeeded(this.host), this.port, (alpnProtocolChosenByServer) => {
|
|
145
148
|
import_debugLogger.debugLogger.log("client-certificates", `Proxy->Target ${this.host}:${this.port} chooses ALPN ${alpnProtocolChosenByServer}`);
|
|
146
149
|
if (this._closed)
|
|
@@ -149,9 +152,9 @@ class SocksProxyConnection {
|
|
|
149
152
|
...dummyServerTlsOptions,
|
|
150
153
|
ALPNProtocols: alpnProtocolChosenByServer === "h2" ? ["h2", "http/1.1"] : ["http/1.1"]
|
|
151
154
|
});
|
|
152
|
-
this._dummyServer.emit("connection", this.
|
|
155
|
+
this._dummyServer.emit("connection", this._internal);
|
|
153
156
|
this._dummyServer.once("secureConnection", (internalTLS) => {
|
|
154
|
-
this.
|
|
157
|
+
this._internalTLS = internalTLS;
|
|
155
158
|
import_debugLogger.debugLogger.log("client-certificates", `Browser->Proxy ${this.host}:${this.port} chooses ALPN ${internalTLS.alpnProtocol}`);
|
|
156
159
|
let targetTLS = void 0;
|
|
157
160
|
const handleError = (error) => {
|
|
@@ -159,10 +162,10 @@ class SocksProxyConnection {
|
|
|
159
162
|
const responseBody = (0, import_utils.escapeHTML)("Playwright client-certificate error: " + error.message).replaceAll("\n", " <br>");
|
|
160
163
|
if (internalTLS?.alpnProtocol === "h2") {
|
|
161
164
|
if ("performServerHandshake" in import_http2.default) {
|
|
162
|
-
this.
|
|
165
|
+
this._target.removeListener("close", this._targetCloseEventListener);
|
|
163
166
|
const session = import_http2.default.performServerHandshake(internalTLS);
|
|
164
167
|
session.on("error", () => {
|
|
165
|
-
this.
|
|
168
|
+
this._target.destroy();
|
|
166
169
|
this._targetCloseEventListener();
|
|
167
170
|
});
|
|
168
171
|
session.once("stream", (stream2) => {
|
|
@@ -172,14 +175,14 @@ class SocksProxyConnection {
|
|
|
172
175
|
});
|
|
173
176
|
const cleanup = () => {
|
|
174
177
|
session.close();
|
|
175
|
-
this.
|
|
178
|
+
this._target.destroy();
|
|
176
179
|
this._targetCloseEventListener();
|
|
177
180
|
};
|
|
178
181
|
stream2.end(responseBody, cleanup);
|
|
179
182
|
stream2.once("error", cleanup);
|
|
180
183
|
});
|
|
181
184
|
} else {
|
|
182
|
-
this.
|
|
185
|
+
this._target.destroy();
|
|
183
186
|
}
|
|
184
187
|
} else {
|
|
185
188
|
internalTLS.end([
|
|
@@ -189,7 +192,7 @@ class SocksProxyConnection {
|
|
|
189
192
|
"",
|
|
190
193
|
responseBody
|
|
191
194
|
].join("\r\n"));
|
|
192
|
-
this.
|
|
195
|
+
this._target.destroy();
|
|
193
196
|
}
|
|
194
197
|
};
|
|
195
198
|
if (this._closed) {
|
|
@@ -197,7 +200,7 @@ class SocksProxyConnection {
|
|
|
197
200
|
return;
|
|
198
201
|
}
|
|
199
202
|
targetTLS = import_tls.default.connect({
|
|
200
|
-
socket: this.
|
|
203
|
+
socket: this._target,
|
|
201
204
|
host: this.host,
|
|
202
205
|
port: this.port,
|
|
203
206
|
rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
|
|
@@ -209,7 +212,7 @@ class SocksProxyConnection {
|
|
|
209
212
|
internalTLS.pipe(targetTLS);
|
|
210
213
|
targetTLS.pipe(internalTLS);
|
|
211
214
|
});
|
|
212
|
-
internalTLS.once("error", () => this.
|
|
215
|
+
internalTLS.once("error", () => this._target.destroy());
|
|
213
216
|
targetTLS.once("error", handleError);
|
|
214
217
|
});
|
|
215
218
|
});
|
|
@@ -222,7 +225,7 @@ class ClientCertificatesProxy {
|
|
|
222
225
|
(0, import_browserContext.verifyClientCertificates)(contextOptions.clientCertificates);
|
|
223
226
|
this.alpnCache = new ALPNCache();
|
|
224
227
|
this.ignoreHTTPSErrors = contextOptions.ignoreHTTPSErrors;
|
|
225
|
-
this.
|
|
228
|
+
this._proxy = contextOptions.proxy;
|
|
226
229
|
this._initSecureContexts(contextOptions.clientCertificates);
|
|
227
230
|
this._socksProxy = new import_socksProxy.SocksProxy();
|
|
228
231
|
this._socksProxy.setPattern("*");
|
|
@@ -236,7 +239,7 @@ class ClientCertificatesProxy {
|
|
|
236
239
|
this._socksProxy.socketFailed({ uid: payload.uid, errorCode: error.code });
|
|
237
240
|
}
|
|
238
241
|
});
|
|
239
|
-
this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksData,
|
|
242
|
+
this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksData, (payload) => {
|
|
240
243
|
this._connections.get(payload.uid)?.onData(payload.data);
|
|
241
244
|
});
|
|
242
245
|
this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksClosed, (payload) => {
|
|
@@ -245,6 +248,14 @@ class ClientCertificatesProxy {
|
|
|
245
248
|
});
|
|
246
249
|
loadDummyServerCertsIfNeeded();
|
|
247
250
|
}
|
|
251
|
+
getProxyAgent(host, port) {
|
|
252
|
+
const proxyFromOptions = (0, import_network.createProxyAgent)(this._proxy);
|
|
253
|
+
if (proxyFromOptions)
|
|
254
|
+
return proxyFromOptions;
|
|
255
|
+
const proxyFromEnv = (0, import_utilsBundle.getProxyForUrl)(`https://${host}:${port}`);
|
|
256
|
+
if (proxyFromEnv)
|
|
257
|
+
return (0, import_network.createProxyAgent)({ server: proxyFromEnv });
|
|
258
|
+
}
|
|
248
259
|
_initSecureContexts(clientCertificates) {
|
|
249
260
|
const origin2certs = /* @__PURE__ */ new Map();
|
|
250
261
|
for (const cert of clientCertificates || []) {
|
|
@@ -262,10 +273,15 @@ class ClientCertificatesProxy {
|
|
|
262
273
|
}
|
|
263
274
|
}
|
|
264
275
|
}
|
|
265
|
-
static async create(contextOptions) {
|
|
276
|
+
static async create(progress, contextOptions) {
|
|
266
277
|
const proxy = new ClientCertificatesProxy(contextOptions);
|
|
267
|
-
|
|
268
|
-
|
|
278
|
+
try {
|
|
279
|
+
await progress.race(proxy._socksProxy.listen(0, "127.0.0.1"));
|
|
280
|
+
return proxy;
|
|
281
|
+
} catch (error) {
|
|
282
|
+
await proxy.close();
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
269
285
|
}
|
|
270
286
|
proxySettings() {
|
|
271
287
|
return { server: `socks5://127.0.0.1:${this._socksProxy.port()}` };
|
package/lib/server/transport.js
CHANGED
|
@@ -97,11 +97,10 @@ class WebSocketTransport {
|
|
|
97
97
|
const logUrl = stripQueryParams(url);
|
|
98
98
|
progress?.log(`<ws connecting> ${logUrl}`);
|
|
99
99
|
const transport = new WebSocketTransport(progress, url, logUrl, { ...options, followRedirects: !!options.followRedirects && hadRedirects });
|
|
100
|
-
progress?.cleanupWhenAborted(() => transport.closeAndWait());
|
|
101
100
|
const resultPromise = new Promise((fulfill, reject) => {
|
|
102
101
|
transport._ws.on("open", async () => {
|
|
103
102
|
progress?.log(`<ws connected> ${logUrl}`);
|
|
104
|
-
fulfill({
|
|
103
|
+
fulfill({});
|
|
105
104
|
});
|
|
106
105
|
transport._ws.on("error", (event) => {
|
|
107
106
|
progress?.log(`<ws connect error> ${logUrl} ${event.message}`);
|
|
@@ -130,20 +129,25 @@ ${Buffer.concat(chunks)}` : errorPrefix;
|
|
|
130
129
|
});
|
|
131
130
|
});
|
|
132
131
|
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
try {
|
|
133
|
+
const result = progress ? await progress.race(resultPromise) : await resultPromise;
|
|
134
|
+
if (result.redirect) {
|
|
135
|
+
const newHeaders = Object.fromEntries(Object.entries(options.headers || {}).filter(([name]) => {
|
|
136
|
+
return !name.includes("access-key") && name.toLowerCase() !== "authorization";
|
|
137
|
+
}));
|
|
138
|
+
return WebSocketTransport._connect(
|
|
139
|
+
progress,
|
|
140
|
+
result.redirect.headers.location,
|
|
141
|
+
{ ...options, headers: newHeaders },
|
|
142
|
+
true
|
|
143
|
+
/* hadRedirects */
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return transport;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
await transport.closeAndWait();
|
|
149
|
+
throw error;
|
|
145
150
|
}
|
|
146
|
-
return transport;
|
|
147
151
|
}
|
|
148
152
|
send(message) {
|
|
149
153
|
this._ws.send(JSON.stringify(message));
|
|
@@ -44,6 +44,7 @@ var import_https = __toESM(require("https"));
|
|
|
44
44
|
var import_url = __toESM(require("url"));
|
|
45
45
|
var import_utilsBundle = require("../../utilsBundle");
|
|
46
46
|
var import_happyEyeballs = require("./happyEyeballs");
|
|
47
|
+
var import_manualPromise = require("../../utils/isomorphic/manualPromise");
|
|
47
48
|
const NET_DEFAULT_TIMEOUT = 3e4;
|
|
48
49
|
function httpRequest(params, onResponse, onError) {
|
|
49
50
|
const parsedUrl = import_url.default.parse(params.url);
|
|
@@ -90,26 +91,36 @@ function httpRequest(params, onResponse, onError) {
|
|
|
90
91
|
request.abort();
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
|
-
cancelRequest = (e) =>
|
|
94
|
+
cancelRequest = (e) => {
|
|
95
|
+
try {
|
|
96
|
+
request.destroy(e);
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
};
|
|
94
100
|
request.end(params.data);
|
|
95
101
|
return { cancel: (e) => cancelRequest(e) };
|
|
96
102
|
}
|
|
97
|
-
function fetchData(progress, params, onError) {
|
|
98
|
-
const promise = new
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
103
|
+
async function fetchData(progress, params, onError) {
|
|
104
|
+
const promise = new import_manualPromise.ManualPromise();
|
|
105
|
+
const { cancel } = httpRequest(params, async (response) => {
|
|
106
|
+
if (response.statusCode !== 200) {
|
|
107
|
+
const error = onError ? await onError(params, response) : new Error(`fetch failed: server returned code ${response.statusCode}. URL: ${params.url}`);
|
|
108
|
+
promise.reject(error);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
let body = "";
|
|
112
|
+
response.on("data", (chunk) => body += chunk);
|
|
113
|
+
response.on("error", (error) => promise.reject(error));
|
|
114
|
+
response.on("end", () => promise.resolve(body));
|
|
115
|
+
}, (error) => promise.reject(error));
|
|
116
|
+
if (!progress)
|
|
117
|
+
return promise;
|
|
118
|
+
try {
|
|
119
|
+
return await progress.race(promise);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
cancel(error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
113
124
|
}
|
|
114
125
|
function shouldBypassProxy(url2, bypass) {
|
|
115
126
|
if (!bypass)
|
|
@@ -132,7 +132,10 @@ async function launchProcess(options) {
|
|
|
132
132
|
spawnedProcess.once("error", (error) => {
|
|
133
133
|
failed(new Error("Failed to launch: " + error));
|
|
134
134
|
});
|
|
135
|
-
return failedPromise.then((
|
|
135
|
+
return failedPromise.then(async (error) => {
|
|
136
|
+
await cleanup();
|
|
137
|
+
throw error;
|
|
138
|
+
});
|
|
136
139
|
}
|
|
137
140
|
options.log(`<launched> pid=${spawnedProcess.pid}`);
|
|
138
141
|
const stdout = readline.createInterface({ input: spawnedProcess.stdout });
|
|
@@ -20,13 +20,14 @@ var ariaSnapshot_exports = {};
|
|
|
20
20
|
__export(ariaSnapshot_exports, {
|
|
21
21
|
KeyParser: () => KeyParser,
|
|
22
22
|
ParserError: () => ParserError,
|
|
23
|
+
findNewElementRef: () => findNewElementRef,
|
|
23
24
|
parseAriaSnapshot: () => parseAriaSnapshot,
|
|
24
25
|
parseAriaSnapshotUnsafe: () => parseAriaSnapshotUnsafe,
|
|
25
26
|
valueOrRegex: () => valueOrRegex
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(ariaSnapshot_exports);
|
|
28
|
-
function parseAriaSnapshotUnsafe(yaml, text) {
|
|
29
|
-
const result = parseAriaSnapshot(yaml, text);
|
|
29
|
+
function parseAriaSnapshotUnsafe(yaml, text, options = {}) {
|
|
30
|
+
const result = parseAriaSnapshot(yaml, text, options);
|
|
30
31
|
if (result.errors.length)
|
|
31
32
|
throw new Error(result.errors[0].message);
|
|
32
33
|
return result.fragment;
|
|
@@ -187,7 +188,7 @@ function valueOrRegex(value) {
|
|
|
187
188
|
class KeyParser {
|
|
188
189
|
static parse(text, options, errors) {
|
|
189
190
|
try {
|
|
190
|
-
return new KeyParser(text.value)._parse();
|
|
191
|
+
return new KeyParser(text.value, options)._parse();
|
|
191
192
|
} catch (e) {
|
|
192
193
|
if (e instanceof ParserError) {
|
|
193
194
|
const message = options.prettyErrors === false ? e.message : e.message + ":\n\n" + text.value + "\n" + " ".repeat(e.pos) + "^\n";
|
|
@@ -200,10 +201,11 @@ class KeyParser {
|
|
|
200
201
|
throw e;
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
|
-
constructor(input) {
|
|
204
|
+
constructor(input, options) {
|
|
204
205
|
this._input = input;
|
|
205
206
|
this._pos = 0;
|
|
206
207
|
this._length = input.length;
|
|
208
|
+
this._options = options;
|
|
207
209
|
}
|
|
208
210
|
_peek() {
|
|
209
211
|
return this._input[this._pos] || "";
|
|
@@ -331,6 +333,10 @@ class KeyParser {
|
|
|
331
333
|
return result;
|
|
332
334
|
}
|
|
333
335
|
_applyAttribute(node, key, value, errorPos) {
|
|
336
|
+
if (this._options.allowRef && key === "ref") {
|
|
337
|
+
node.ref = value;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
334
340
|
if (key === "checked") {
|
|
335
341
|
this._assert(value === "true" || value === "false" || value === "mixed", 'Value of "checked" attribute must be a boolean or "mixed"', errorPos);
|
|
336
342
|
node.checked = value === "true" ? true : value === "false" ? false : "mixed";
|
|
@@ -366,6 +372,8 @@ class KeyParser {
|
|
|
366
372
|
node.selected = value === "true";
|
|
367
373
|
return;
|
|
368
374
|
}
|
|
375
|
+
if (this._options.allowUnknownAttributes)
|
|
376
|
+
return;
|
|
369
377
|
this._assert(false, `Unsupported attribute [${key}]`, errorPos);
|
|
370
378
|
}
|
|
371
379
|
_assert(value, message, valuePos) {
|
|
@@ -379,10 +387,56 @@ class ParserError extends Error {
|
|
|
379
387
|
this.pos = pos;
|
|
380
388
|
}
|
|
381
389
|
}
|
|
390
|
+
function findNewElementRef(yaml, fromSnapshot, toSnapshot) {
|
|
391
|
+
function fillMap(root, map, position) {
|
|
392
|
+
let size = 1;
|
|
393
|
+
let childPosition = position + size;
|
|
394
|
+
for (const child of root.children || []) {
|
|
395
|
+
if (child.kind === "role") {
|
|
396
|
+
size += fillMap(child, map, childPosition);
|
|
397
|
+
childPosition += size;
|
|
398
|
+
} else {
|
|
399
|
+
size++;
|
|
400
|
+
childPosition++;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (!["none", "presentation", "fragment", "iframe", "generic"].includes(root.role) && typeof root.name === "string" && root.name) {
|
|
404
|
+
let byRole = map.get(root.role);
|
|
405
|
+
if (!byRole) {
|
|
406
|
+
byRole = /* @__PURE__ */ new Map();
|
|
407
|
+
map.set(root.role, byRole);
|
|
408
|
+
}
|
|
409
|
+
const existing = byRole.get(root.name);
|
|
410
|
+
const sizeAndPosition = size * 100 - position;
|
|
411
|
+
if (!existing || existing.sizeAndPosition < sizeAndPosition)
|
|
412
|
+
byRole.set(root.name, { node: root, sizeAndPosition });
|
|
413
|
+
}
|
|
414
|
+
return size;
|
|
415
|
+
}
|
|
416
|
+
const fromMap = /* @__PURE__ */ new Map();
|
|
417
|
+
const from = parseAriaSnapshotUnsafe(yaml, fromSnapshot, { allowRef: true, allowUnknownAttributes: true });
|
|
418
|
+
if (from.kind === "role")
|
|
419
|
+
fillMap(from, fromMap, 0);
|
|
420
|
+
const toMap = /* @__PURE__ */ new Map();
|
|
421
|
+
const to = parseAriaSnapshotUnsafe(yaml, toSnapshot, { allowRef: true, allowUnknownAttributes: true });
|
|
422
|
+
if (to.kind === "role")
|
|
423
|
+
fillMap(to, toMap, 0);
|
|
424
|
+
const result = [];
|
|
425
|
+
for (const [role, byRole] of toMap) {
|
|
426
|
+
for (const [name, byName] of byRole) {
|
|
427
|
+
const inFrom = fromMap.get(role)?.get(name);
|
|
428
|
+
if (!inFrom)
|
|
429
|
+
result.push(byName);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
result.sort((a, b) => b.sizeAndPosition - a.sizeAndPosition);
|
|
433
|
+
return result.find((r) => r.node.ref)?.node.ref;
|
|
434
|
+
}
|
|
382
435
|
// Annotate the CommonJS export names for ESM import in node:
|
|
383
436
|
0 && (module.exports = {
|
|
384
437
|
KeyParser,
|
|
385
438
|
ParserError,
|
|
439
|
+
findNewElementRef,
|
|
386
440
|
parseAriaSnapshot,
|
|
387
441
|
parseAriaSnapshotUnsafe,
|
|
388
442
|
valueOrRegex
|