patchright-core 1.57.0 → 1.58.2
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/ThirdPartyNotices.txt +3223 -308
- package/browsers.json +21 -22
- package/lib/cli/program.js +4 -5
- package/lib/client/api.js +3 -0
- package/lib/client/browser.js +3 -5
- package/lib/client/browserContext.js +40 -4
- package/lib/client/browserType.js +4 -3
- package/lib/client/connection.js +4 -0
- package/lib/client/elementHandle.js +3 -0
- package/lib/client/events.js +3 -0
- package/lib/client/fetch.js +3 -4
- package/lib/client/frame.js +10 -1
- package/lib/client/locator.js +8 -0
- package/lib/client/network.js +5 -1
- package/lib/client/page.js +29 -1
- package/lib/client/pageAgent.js +64 -0
- package/lib/client/platform.js +3 -0
- package/lib/client/tracing.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/mcpBundle.js +84 -0
- package/lib/mcpBundleImpl/index.js +147 -0
- package/lib/protocol/serializers.js +5 -0
- package/lib/protocol/validator.js +88 -4
- package/lib/remote/playwrightServer.js +1 -2
- package/lib/server/agent/actionRunner.js +335 -0
- package/lib/server/agent/actions.js +128 -0
- package/lib/server/agent/codegen.js +111 -0
- package/lib/server/agent/context.js +150 -0
- package/lib/server/agent/expectTools.js +156 -0
- package/lib/server/agent/pageAgent.js +204 -0
- package/lib/server/agent/performTools.js +262 -0
- package/lib/server/agent/tool.js +109 -0
- package/lib/server/artifact.js +1 -1
- package/lib/server/bidi/bidiBrowser.js +56 -12
- package/lib/server/bidi/bidiChromium.js +8 -12
- package/lib/server/bidi/bidiConnection.js +1 -0
- package/lib/server/bidi/bidiDeserializer.js +116 -0
- package/lib/server/bidi/bidiExecutionContext.js +75 -29
- package/lib/server/bidi/bidiFirefox.js +6 -8
- package/lib/server/bidi/bidiNetworkManager.js +1 -1
- package/lib/server/bidi/bidiPage.js +39 -28
- package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
- package/lib/server/browserContext.js +34 -26
- package/lib/server/browserType.js +12 -4
- package/lib/server/chromium/chromium.js +14 -20
- package/lib/server/chromium/chromiumSwitches.js +2 -2
- package/lib/server/chromium/crBrowser.js +22 -12
- package/lib/server/chromium/crConnection.js +0 -5
- package/lib/server/chromium/crCoverage.js +13 -1
- package/lib/server/chromium/crDevTools.js +0 -2
- package/lib/server/chromium/crNetworkManager.js +92 -12
- package/lib/server/chromium/crPage.js +62 -116
- package/lib/server/codegen/javascript.js +6 -29
- package/lib/server/deviceDescriptorsSource.json +56 -56
- package/lib/server/dispatchers/browserContextDispatcher.js +3 -2
- package/lib/server/dispatchers/dispatcher.js +6 -13
- package/lib/server/dispatchers/frameDispatcher.js +1 -1
- package/lib/server/dispatchers/jsHandleDispatcher.js +2 -2
- package/lib/server/dispatchers/pageAgentDispatcher.js +96 -0
- package/lib/server/dispatchers/pageDispatcher.js +4 -0
- package/lib/server/dom.js +12 -3
- package/lib/server/electron/electron.js +5 -2
- package/lib/server/firefox/ffBrowser.js +10 -20
- package/lib/server/firefox/ffConnection.js +0 -5
- package/lib/server/firefox/ffNetworkManager.js +2 -2
- package/lib/server/firefox/ffPage.js +15 -18
- package/lib/server/firefox/firefox.js +6 -8
- package/lib/server/frameSelectors.js +16 -4
- package/lib/server/frames.js +251 -86
- package/lib/server/instrumentation.js +3 -0
- package/lib/server/javascript.js +8 -4
- package/lib/server/launchApp.js +2 -1
- package/lib/server/network.js +50 -12
- package/lib/server/page.js +61 -91
- package/lib/server/progress.js +26 -6
- package/lib/server/recorder/recorderApp.js +79 -100
- package/lib/server/registry/browserFetcher.js +6 -4
- package/lib/server/registry/index.js +172 -149
- package/lib/server/registry/oopDownloadBrowserMain.js +3 -0
- package/lib/server/screencast.js +190 -0
- package/lib/server/screenshotter.js +6 -0
- package/lib/server/trace/recorder/snapshotter.js +17 -8
- package/lib/server/trace/recorder/snapshotterInjected.js +30 -72
- package/lib/server/trace/recorder/tracing.js +29 -21
- package/lib/server/trace/viewer/traceParser.js +72 -0
- package/lib/server/trace/viewer/traceViewer.js +21 -17
- package/lib/server/utils/expectUtils.js +87 -2
- package/lib/server/utils/hostPlatform.js +15 -0
- package/lib/server/utils/httpServer.js +5 -20
- package/lib/server/utils/network.js +37 -28
- package/lib/server/utils/nodePlatform.js +6 -0
- package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +22 -13
- package/lib/server/webkit/webkit.js +4 -6
- package/lib/server/webkit/wkBrowser.js +2 -6
- package/lib/server/webkit/wkConnection.js +1 -6
- package/lib/server/webkit/wkInterceptableRequest.js +29 -1
- package/lib/server/webkit/wkPage.js +75 -46
- package/lib/utils/isomorphic/ariaSnapshot.js +60 -2
- package/lib/utils/isomorphic/lruCache.js +51 -0
- package/lib/utils/isomorphic/protocolMetainfo.js +9 -1
- package/lib/utils/isomorphic/stringUtils.js +49 -0
- package/lib/utils/isomorphic/trace/entries.js +16 -0
- package/lib/utils/isomorphic/trace/snapshotRenderer.js +499 -0
- package/lib/utils/isomorphic/trace/snapshotServer.js +120 -0
- package/lib/utils/isomorphic/trace/snapshotStorage.js +89 -0
- package/lib/utils/isomorphic/trace/traceLoader.js +131 -0
- package/lib/utils/isomorphic/trace/traceModel.js +365 -0
- package/lib/utils/isomorphic/trace/traceModernizer.js +400 -0
- package/lib/utils/isomorphic/trace/versions/traceV3.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV4.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV5.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV6.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV7.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV8.js +16 -0
- package/lib/utils/isomorphic/yaml.js +84 -0
- package/lib/utils.js +2 -0
- package/lib/utilsBundle.js +2 -5
- package/lib/utilsBundleImpl/index.js +165 -165
- package/lib/vite/htmlReport/index.html +21 -21
- package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
- package/lib/vite/{traceViewer/codeMirrorModule.C3UTv-Ge.css → recorder/assets/codeMirrorModule-DYBRYzYX.css} +1 -1
- package/lib/vite/recorder/assets/{index-Ri0uHF7I.css → index-BSjZa4pk.css} +1 -1
- package/lib/vite/recorder/assets/index-CVkBxsGf.js +193 -0
- package/lib/vite/recorder/index.html +2 -2
- package/lib/vite/traceViewer/assets/codeMirrorModule-BVA4h_ZY.js +32 -0
- package/lib/vite/traceViewer/assets/defaultSettingsView-CjfmcdOz.js +266 -0
- package/lib/vite/{recorder/assets/codeMirrorModule-C3UTv-Ge.css → traceViewer/codeMirrorModule.DYBRYzYX.css} +1 -1
- package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +1 -0
- package/lib/vite/traceViewer/index.BVu7tZDe.css +1 -0
- package/lib/vite/traceViewer/index.BtyWtaE-.js +2 -0
- package/lib/vite/traceViewer/index.html +4 -4
- package/lib/vite/traceViewer/sw.bundle.js +5 -3
- package/lib/vite/traceViewer/uiMode.fyrXARf2.js +5 -0
- package/lib/vite/traceViewer/uiMode.html +3 -3
- package/package.json +2 -1
- package/types/protocol.d.ts +738 -159
- package/types/types.d.ts +25 -38
- package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
- package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
- package/lib/vite/recorder/assets/codeMirrorModule-CBbSe-ZI.js +0 -25
- package/lib/vite/recorder/assets/index-CpZVd2nA.js +0 -193
- package/lib/vite/traceViewer/assets/codeMirrorModule-DHz0wP2C.js +0 -25
- package/lib/vite/traceViewer/assets/defaultSettingsView-WsZP88O6.js +0 -266
- package/lib/vite/traceViewer/defaultSettingsView.ConWv5KN.css +0 -1
- package/lib/vite/traceViewer/index.C4Y3Aw8n.css +0 -1
- package/lib/vite/traceViewer/index.C8xAeo93.js +0 -2
- package/lib/vite/traceViewer/uiMode.BltraIJB.js +0 -5
|
@@ -47,20 +47,21 @@ var import_launchApp2 = require("../../launchApp");
|
|
|
47
47
|
var import_playwright = require("../../playwright");
|
|
48
48
|
var import_progress = require("../../progress");
|
|
49
49
|
const tracesDirMarker = "traces.dir";
|
|
50
|
-
function
|
|
51
|
-
if (!
|
|
52
|
-
return
|
|
53
|
-
if (
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
function validateTraceUrlOrPath(traceFileOrUrl) {
|
|
51
|
+
if (!traceFileOrUrl)
|
|
52
|
+
return traceFileOrUrl;
|
|
53
|
+
if (traceFileOrUrl.startsWith("http://") || traceFileOrUrl.startsWith("https://"))
|
|
54
|
+
return traceFileOrUrl;
|
|
55
|
+
let traceFile = traceFileOrUrl;
|
|
56
|
+
if (traceFile.endsWith(".json"))
|
|
57
|
+
return toFilePathUrl(traceFile);
|
|
57
58
|
try {
|
|
58
|
-
const stat = import_fs.default.statSync(
|
|
59
|
+
const stat = import_fs.default.statSync(traceFile);
|
|
59
60
|
if (stat.isDirectory())
|
|
60
|
-
|
|
61
|
-
return
|
|
61
|
+
traceFile = import_path.default.join(traceFile, tracesDirMarker);
|
|
62
|
+
return toFilePathUrl(traceFile);
|
|
62
63
|
} catch {
|
|
63
|
-
throw new Error(`Trace file ${
|
|
64
|
+
throw new Error(`Trace file ${traceFileOrUrl} does not exist!`);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
async function startTraceViewerServer(options) {
|
|
@@ -126,7 +127,7 @@ async function installRootRedirect(server, traceUrl, options) {
|
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
129
|
async function runTraceViewerApp(traceUrl, browserName, options, exitOnClose) {
|
|
129
|
-
traceUrl =
|
|
130
|
+
traceUrl = validateTraceUrlOrPath(traceUrl);
|
|
130
131
|
const server = await startTraceViewerServer(options);
|
|
131
132
|
await installRootRedirect(server, traceUrl, options);
|
|
132
133
|
const page = await openTraceViewerApp(server.urlPrefix("precise"), browserName, options);
|
|
@@ -135,7 +136,7 @@ async function runTraceViewerApp(traceUrl, browserName, options, exitOnClose) {
|
|
|
135
136
|
return page;
|
|
136
137
|
}
|
|
137
138
|
async function runTraceInBrowser(traceUrl, options) {
|
|
138
|
-
traceUrl =
|
|
139
|
+
traceUrl = validateTraceUrlOrPath(traceUrl);
|
|
139
140
|
const server = await startTraceViewerServer(options);
|
|
140
141
|
await installRootRedirect(server, traceUrl, options);
|
|
141
142
|
await openTraceInBrowser(server.urlPrefix("human-readable"));
|
|
@@ -177,8 +178,8 @@ async function openTraceInBrowser(url) {
|
|
|
177
178
|
class StdinServer {
|
|
178
179
|
constructor() {
|
|
179
180
|
process.stdin.on("data", (data) => {
|
|
180
|
-
const url = data.toString().trim();
|
|
181
|
-
if (url === this._traceUrl)
|
|
181
|
+
const url = validateTraceUrlOrPath(data.toString().trim());
|
|
182
|
+
if (!url || url === this._traceUrl)
|
|
182
183
|
return;
|
|
183
184
|
if (url.endsWith(".json"))
|
|
184
185
|
this._pollLoadTrace(url);
|
|
@@ -221,15 +222,18 @@ function traceDescriptor(traceDir, tracePrefix) {
|
|
|
221
222
|
};
|
|
222
223
|
for (const name of import_fs.default.readdirSync(traceDir)) {
|
|
223
224
|
if (!tracePrefix || name.startsWith(tracePrefix))
|
|
224
|
-
result.entries.push({ name, path: import_path.default.join(traceDir, name) });
|
|
225
|
+
result.entries.push({ name, path: toFilePathUrl(import_path.default.join(traceDir, name)) });
|
|
225
226
|
}
|
|
226
227
|
const resourcesDir = import_path.default.join(traceDir, "resources");
|
|
227
228
|
if (import_fs.default.existsSync(resourcesDir)) {
|
|
228
229
|
for (const name of import_fs.default.readdirSync(resourcesDir))
|
|
229
|
-
result.entries.push({ name: "resources/" + name, path: import_path.default.join(resourcesDir, name) });
|
|
230
|
+
result.entries.push({ name: "resources/" + name, path: toFilePathUrl(import_path.default.join(resourcesDir, name)) });
|
|
230
231
|
}
|
|
231
232
|
return result;
|
|
232
233
|
}
|
|
234
|
+
function toFilePathUrl(filePath) {
|
|
235
|
+
return `file?path=${encodeURIComponent(filePath)}`;
|
|
236
|
+
}
|
|
233
237
|
// Annotate the CommonJS export names for ESM import in node:
|
|
234
238
|
0 && (module.exports = {
|
|
235
239
|
installRootRedirect,
|
|
@@ -18,10 +18,16 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var expectUtils_exports = {};
|
|
20
20
|
__export(expectUtils_exports, {
|
|
21
|
-
|
|
21
|
+
callLogText: () => callLogText,
|
|
22
|
+
formatMatcherMessage: () => formatMatcherMessage,
|
|
23
|
+
printReceivedStringContainExpectedResult: () => printReceivedStringContainExpectedResult,
|
|
24
|
+
printReceivedStringContainExpectedSubstring: () => printReceivedStringContainExpectedSubstring,
|
|
25
|
+
serializeExpectedTextValues: () => serializeExpectedTextValues,
|
|
26
|
+
simpleMatcherUtils: () => simpleMatcherUtils
|
|
22
27
|
});
|
|
23
28
|
module.exports = __toCommonJS(expectUtils_exports);
|
|
24
29
|
var import_rtti = require("../../utils/isomorphic/rtti");
|
|
30
|
+
var import_utilsBundle = require("../../utilsBundle");
|
|
25
31
|
function serializeExpectedTextValues(items, options = {}) {
|
|
26
32
|
return items.map((i) => ({
|
|
27
33
|
string: (0, import_rtti.isString)(i) ? i : void 0,
|
|
@@ -32,7 +38,86 @@ function serializeExpectedTextValues(items, options = {}) {
|
|
|
32
38
|
normalizeWhiteSpace: options.normalizeWhiteSpace
|
|
33
39
|
}));
|
|
34
40
|
}
|
|
41
|
+
const printSubstring = (val) => val.replace(/"|\\/g, "\\$&");
|
|
42
|
+
const printReceivedStringContainExpectedSubstring = (utils, received, start, length) => utils.RECEIVED_COLOR(
|
|
43
|
+
'"' + printSubstring(received.slice(0, start)) + utils.INVERTED_COLOR(printSubstring(received.slice(start, start + length))) + printSubstring(received.slice(start + length)) + '"'
|
|
44
|
+
);
|
|
45
|
+
const printReceivedStringContainExpectedResult = (utils, received, result) => result === null ? utils.printReceived(received) : printReceivedStringContainExpectedSubstring(
|
|
46
|
+
utils,
|
|
47
|
+
received,
|
|
48
|
+
result.index,
|
|
49
|
+
result[0].length
|
|
50
|
+
);
|
|
51
|
+
function formatMatcherMessage(utils, details) {
|
|
52
|
+
const receiver = details.receiver ?? (details.locator ? "locator" : "page");
|
|
53
|
+
let message = utils.DIM_COLOR("expect(") + utils.RECEIVED_COLOR(receiver) + utils.DIM_COLOR(")" + (details.promise ? "." + details.promise : "") + (details.isNot ? ".not" : "") + ".") + details.matcherName + utils.DIM_COLOR("(") + utils.EXPECTED_COLOR(details.expectation) + utils.DIM_COLOR(")") + " failed\n\n";
|
|
54
|
+
const diffLines = details.printedDiff?.split("\n");
|
|
55
|
+
if (diffLines?.length === 2) {
|
|
56
|
+
details.printedExpected = diffLines[0];
|
|
57
|
+
details.printedReceived = diffLines[1];
|
|
58
|
+
details.printedDiff = void 0;
|
|
59
|
+
}
|
|
60
|
+
const align = !details.errorMessage && details.printedExpected?.startsWith("Expected:") && (!details.printedReceived || details.printedReceived.startsWith("Received:"));
|
|
61
|
+
if (details.locator)
|
|
62
|
+
message += `Locator: ${align ? " " : ""}${details.locator}
|
|
63
|
+
`;
|
|
64
|
+
if (details.printedExpected)
|
|
65
|
+
message += details.printedExpected + "\n";
|
|
66
|
+
if (details.printedReceived)
|
|
67
|
+
message += details.printedReceived + "\n";
|
|
68
|
+
if (details.timedOut && details.timeout)
|
|
69
|
+
message += `Timeout: ${align ? " " : ""}${details.timeout}ms
|
|
70
|
+
`;
|
|
71
|
+
if (details.printedDiff)
|
|
72
|
+
message += details.printedDiff + "\n";
|
|
73
|
+
if (details.errorMessage) {
|
|
74
|
+
message += details.errorMessage;
|
|
75
|
+
if (!details.errorMessage.endsWith("\n"))
|
|
76
|
+
message += "\n";
|
|
77
|
+
}
|
|
78
|
+
message += callLogText(utils, details.log);
|
|
79
|
+
return message;
|
|
80
|
+
}
|
|
81
|
+
const callLogText = (utils, log) => {
|
|
82
|
+
if (!log || !log.some((l) => !!l))
|
|
83
|
+
return "";
|
|
84
|
+
return `
|
|
85
|
+
Call log:
|
|
86
|
+
${utils.DIM_COLOR(log.join("\n"))}
|
|
87
|
+
`;
|
|
88
|
+
};
|
|
89
|
+
function printValue(value) {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.stringify(value);
|
|
92
|
+
} catch {
|
|
93
|
+
return String(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function printReceived(value) {
|
|
97
|
+
return import_utilsBundle.colors.red(printValue(value));
|
|
98
|
+
}
|
|
99
|
+
function printExpected(value) {
|
|
100
|
+
return import_utilsBundle.colors.green(printValue(value));
|
|
101
|
+
}
|
|
102
|
+
const simpleMatcherUtils = {
|
|
103
|
+
DIM_COLOR: import_utilsBundle.colors.dim,
|
|
104
|
+
RECEIVED_COLOR: import_utilsBundle.colors.red,
|
|
105
|
+
EXPECTED_COLOR: import_utilsBundle.colors.green,
|
|
106
|
+
INVERTED_COLOR: import_utilsBundle.colors.inverse,
|
|
107
|
+
printReceived,
|
|
108
|
+
printExpected,
|
|
109
|
+
printDiffOrStringify: (expected, received, expectedLabel, receivedLabel) => {
|
|
110
|
+
const maxLength = Math.max(expectedLabel.length, receivedLabel.length) + 2;
|
|
111
|
+
return `${expectedLabel}: `.padEnd(maxLength) + printExpected(expected) + `
|
|
112
|
+
` + `${receivedLabel}: `.padEnd(maxLength) + printReceived(received);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
35
115
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36
116
|
0 && (module.exports = {
|
|
37
|
-
|
|
117
|
+
callLogText,
|
|
118
|
+
formatMatcherMessage,
|
|
119
|
+
printReceivedStringContainExpectedResult,
|
|
120
|
+
printReceivedStringContainExpectedSubstring,
|
|
121
|
+
serializeExpectedTextValues,
|
|
122
|
+
simpleMatcherUtils
|
|
38
123
|
});
|
|
@@ -28,11 +28,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var hostPlatform_exports = {};
|
|
30
30
|
__export(hostPlatform_exports, {
|
|
31
|
+
hasGpuMac: () => hasGpuMac,
|
|
31
32
|
hostPlatform: () => hostPlatform,
|
|
32
33
|
isOfficiallySupportedPlatform: () => isOfficiallySupportedPlatform,
|
|
33
34
|
shortPlatform: () => shortPlatform
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(hostPlatform_exports);
|
|
37
|
+
var import_child_process = require("child_process");
|
|
36
38
|
var import_os = __toESM(require("os"));
|
|
37
39
|
var import_linuxUtils = require("./linuxUtils");
|
|
38
40
|
function calculatePlatform() {
|
|
@@ -115,8 +117,21 @@ function toShortPlatform(hostPlatform2) {
|
|
|
115
117
|
return hostPlatform2.endsWith("arm64") ? "linux-arm64" : "linux-x64";
|
|
116
118
|
}
|
|
117
119
|
const shortPlatform = toShortPlatform(hostPlatform);
|
|
120
|
+
let hasGpuMacValue;
|
|
121
|
+
function hasGpuMac() {
|
|
122
|
+
try {
|
|
123
|
+
if (hasGpuMacValue === void 0) {
|
|
124
|
+
const output = (0, import_child_process.execSync)("system_profiler SPDisplaysDataType", { stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
125
|
+
hasGpuMacValue = output.includes("Metal: Supported") || output.includes("Metal Support: Metal");
|
|
126
|
+
}
|
|
127
|
+
return hasGpuMacValue;
|
|
128
|
+
} catch (e) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
118
132
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
133
|
0 && (module.exports = {
|
|
134
|
+
hasGpuMac,
|
|
120
135
|
hostPlatform,
|
|
121
136
|
isOfficiallySupportedPlatform,
|
|
122
137
|
shortPlatform
|
|
@@ -36,7 +36,6 @@ var import_path = __toESM(require("path"));
|
|
|
36
36
|
var import_utilsBundle = require("../../utilsBundle");
|
|
37
37
|
var import_crypto = require("./crypto");
|
|
38
38
|
var import_assert = require("../../utils/isomorphic/assert");
|
|
39
|
-
var import_manualPromise = require("../../utils/isomorphic/manualPromise");
|
|
40
39
|
var import_network = require("./network");
|
|
41
40
|
class HttpServer {
|
|
42
41
|
constructor() {
|
|
@@ -59,20 +58,6 @@ class HttpServer {
|
|
|
59
58
|
port() {
|
|
60
59
|
return this._port;
|
|
61
60
|
}
|
|
62
|
-
async _tryStart(port, host) {
|
|
63
|
-
const errorPromise = new import_manualPromise.ManualPromise();
|
|
64
|
-
const errorListener = (error) => errorPromise.reject(error);
|
|
65
|
-
this._server.on("error", errorListener);
|
|
66
|
-
try {
|
|
67
|
-
this._server.listen(port, host);
|
|
68
|
-
await Promise.race([
|
|
69
|
-
new Promise((cb) => this._server.once("listening", cb)),
|
|
70
|
-
errorPromise
|
|
71
|
-
]);
|
|
72
|
-
} finally {
|
|
73
|
-
this._server.removeListener("error", errorListener);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
61
|
createWebSocket(transport, guid) {
|
|
77
62
|
(0, import_assert.assert)(!this._wsGuid, "can only create one main websocket transport per server");
|
|
78
63
|
this._wsGuid = guid || (0, import_crypto.createGuid)();
|
|
@@ -100,17 +85,17 @@ class HttpServer {
|
|
|
100
85
|
async start(options = {}) {
|
|
101
86
|
(0, import_assert.assert)(!this._started, "server already started");
|
|
102
87
|
this._started = true;
|
|
103
|
-
const host = options.host
|
|
88
|
+
const host = options.host;
|
|
104
89
|
if (options.preferredPort) {
|
|
105
90
|
try {
|
|
106
|
-
await this.
|
|
91
|
+
await (0, import_network.startHttpServer)(this._server, { port: options.preferredPort, host });
|
|
107
92
|
} catch (e) {
|
|
108
93
|
if (!e || !e.message || !e.message.includes("EADDRINUSE"))
|
|
109
94
|
throw e;
|
|
110
|
-
await
|
|
95
|
+
await (0, import_network.startHttpServer)(this._server, { host });
|
|
111
96
|
}
|
|
112
97
|
} else {
|
|
113
|
-
await this.
|
|
98
|
+
await (0, import_network.startHttpServer)(this._server, { port: options.port, host });
|
|
114
99
|
}
|
|
115
100
|
const address = this._server.address();
|
|
116
101
|
(0, import_assert.assert)(address, "Could not bind server socket");
|
|
@@ -121,7 +106,7 @@ class HttpServer {
|
|
|
121
106
|
this._port = address.port;
|
|
122
107
|
const resolvedHost = address.family === "IPv4" ? address.address : `[${address.address}]`;
|
|
123
108
|
this._urlPrefixPrecise = `http://${resolvedHost}:${address.port}`;
|
|
124
|
-
this._urlPrefixHumanReadable = `http://${host}:${address.port}`;
|
|
109
|
+
this._urlPrefixHumanReadable = `http://${host ?? "localhost"}:${address.port}`;
|
|
125
110
|
}
|
|
126
111
|
}
|
|
127
112
|
async stop() {
|
|
@@ -35,22 +35,20 @@ __export(network_exports, {
|
|
|
35
35
|
createProxyAgent: () => createProxyAgent,
|
|
36
36
|
fetchData: () => fetchData,
|
|
37
37
|
httpRequest: () => httpRequest,
|
|
38
|
-
isURLAvailable: () => isURLAvailable
|
|
38
|
+
isURLAvailable: () => isURLAvailable,
|
|
39
|
+
startHttpServer: () => startHttpServer
|
|
39
40
|
});
|
|
40
41
|
module.exports = __toCommonJS(network_exports);
|
|
41
42
|
var import_http = __toESM(require("http"));
|
|
42
43
|
var import_http2 = __toESM(require("http2"));
|
|
43
44
|
var import_https = __toESM(require("https"));
|
|
44
|
-
var import_url = __toESM(require("url"));
|
|
45
45
|
var import_utilsBundle = require("../../utilsBundle");
|
|
46
46
|
var import_happyEyeballs = require("./happyEyeballs");
|
|
47
47
|
var import_manualPromise = require("../../utils/isomorphic/manualPromise");
|
|
48
48
|
const NET_DEFAULT_TIMEOUT = 3e4;
|
|
49
49
|
function httpRequest(params, onResponse, onError) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
...parsedUrl,
|
|
53
|
-
agent: parsedUrl.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent,
|
|
50
|
+
let url = new URL(params.url);
|
|
51
|
+
const options = {
|
|
54
52
|
method: params.method || "GET",
|
|
55
53
|
headers: params.headers
|
|
56
54
|
};
|
|
@@ -58,21 +56,16 @@ function httpRequest(params, onResponse, onError) {
|
|
|
58
56
|
options.rejectUnauthorized = params.rejectUnauthorized;
|
|
59
57
|
const proxyURL = (0, import_utilsBundle.getProxyForUrl)(params.url);
|
|
60
58
|
if (proxyURL) {
|
|
59
|
+
const parsedProxyURL = normalizeProxyURL(proxyURL);
|
|
61
60
|
if (params.url.startsWith("http:")) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
path: parsedUrl.href,
|
|
65
|
-
host: parsedProxyURL.hostname,
|
|
66
|
-
port: parsedProxyURL.port,
|
|
67
|
-
protocol: parsedProxyURL.protocol || "http:",
|
|
68
|
-
headers: options.headers,
|
|
69
|
-
method: options.method
|
|
70
|
-
};
|
|
61
|
+
parsedProxyURL.pathname = url.toString();
|
|
62
|
+
url = parsedProxyURL;
|
|
71
63
|
} else {
|
|
72
|
-
options.agent = new import_utilsBundle.HttpsProxyAgent(
|
|
64
|
+
options.agent = new import_utilsBundle.HttpsProxyAgent(parsedProxyURL);
|
|
73
65
|
options.rejectUnauthorized = false;
|
|
74
66
|
}
|
|
75
67
|
}
|
|
68
|
+
options.agent ??= url.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent;
|
|
76
69
|
let cancelRequest;
|
|
77
70
|
const requestCallback = (res) => {
|
|
78
71
|
const statusCode = res.statusCode || 0;
|
|
@@ -83,7 +76,7 @@ function httpRequest(params, onResponse, onError) {
|
|
|
83
76
|
onResponse(res);
|
|
84
77
|
}
|
|
85
78
|
};
|
|
86
|
-
const request =
|
|
79
|
+
const request = url.protocol === "https:" ? import_https.default.request(url, options, requestCallback) : import_http.default.request(url, options, requestCallback);
|
|
87
80
|
request.on("error", onError);
|
|
88
81
|
if (params.socketTimeout !== void 0) {
|
|
89
82
|
request.setTimeout(params.socketTimeout, () => {
|
|
@@ -122,7 +115,7 @@ async function fetchData(progress, params, onError) {
|
|
|
122
115
|
throw error;
|
|
123
116
|
}
|
|
124
117
|
}
|
|
125
|
-
function shouldBypassProxy(
|
|
118
|
+
function shouldBypassProxy(url, bypass) {
|
|
126
119
|
if (!bypass)
|
|
127
120
|
return false;
|
|
128
121
|
const domains = bypass.split(",").map((s) => {
|
|
@@ -131,7 +124,7 @@ function shouldBypassProxy(url2, bypass) {
|
|
|
131
124
|
s = "." + s;
|
|
132
125
|
return s;
|
|
133
126
|
});
|
|
134
|
-
const domain = "." +
|
|
127
|
+
const domain = "." + url.hostname;
|
|
135
128
|
return domains.some((d) => domain.endsWith(d));
|
|
136
129
|
}
|
|
137
130
|
function normalizeProxyURL(proxy) {
|
|
@@ -177,20 +170,35 @@ function createHttp2Server(...args) {
|
|
|
177
170
|
decorateServer(server);
|
|
178
171
|
return server;
|
|
179
172
|
}
|
|
180
|
-
async function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
173
|
+
async function startHttpServer(server, options) {
|
|
174
|
+
const { host = "localhost", port = 0 } = options;
|
|
175
|
+
const errorPromise = new import_manualPromise.ManualPromise();
|
|
176
|
+
const errorListener = (error) => errorPromise.reject(error);
|
|
177
|
+
server.on("error", errorListener);
|
|
178
|
+
try {
|
|
179
|
+
server.listen(port, host);
|
|
180
|
+
await Promise.race([
|
|
181
|
+
new Promise((cb) => server.once("listening", cb)),
|
|
182
|
+
errorPromise
|
|
183
|
+
]);
|
|
184
|
+
} finally {
|
|
185
|
+
server.removeListener("error", errorListener);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function isURLAvailable(url, ignoreHTTPSErrors, onLog, onStdErr) {
|
|
189
|
+
let statusCode = await httpStatusCode(url, ignoreHTTPSErrors, onLog, onStdErr);
|
|
190
|
+
if (statusCode === 404 && url.pathname === "/") {
|
|
191
|
+
const indexUrl = new URL(url);
|
|
184
192
|
indexUrl.pathname = "/index.html";
|
|
185
193
|
statusCode = await httpStatusCode(indexUrl, ignoreHTTPSErrors, onLog, onStdErr);
|
|
186
194
|
}
|
|
187
195
|
return statusCode >= 200 && statusCode < 404;
|
|
188
196
|
}
|
|
189
|
-
async function httpStatusCode(
|
|
197
|
+
async function httpStatusCode(url, ignoreHTTPSErrors, onLog, onStdErr) {
|
|
190
198
|
return new Promise((resolve) => {
|
|
191
|
-
onLog?.(`HTTP GET: ${
|
|
199
|
+
onLog?.(`HTTP GET: ${url}`);
|
|
192
200
|
httpRequest({
|
|
193
|
-
url:
|
|
201
|
+
url: url.toString(),
|
|
194
202
|
headers: { Accept: "*/*" },
|
|
195
203
|
rejectUnauthorized: !ignoreHTTPSErrors
|
|
196
204
|
}, (res) => {
|
|
@@ -201,7 +209,7 @@ async function httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr) {
|
|
|
201
209
|
}, (error) => {
|
|
202
210
|
if (error.code === "DEPTH_ZERO_SELF_SIGNED_CERT")
|
|
203
211
|
onStdErr?.(`[WebServer] Self-signed certificate detected. Try adding ignoreHTTPSErrors: true to config.webServer.`);
|
|
204
|
-
onLog?.(`Error while checking if ${
|
|
212
|
+
onLog?.(`Error while checking if ${url} is available: ${error.message}`);
|
|
205
213
|
resolve(0);
|
|
206
214
|
});
|
|
207
215
|
});
|
|
@@ -229,5 +237,6 @@ function decorateServer(server) {
|
|
|
229
237
|
createProxyAgent,
|
|
230
238
|
fetchData,
|
|
231
239
|
httpRequest,
|
|
232
|
-
isURLAvailable
|
|
240
|
+
isURLAvailable,
|
|
241
|
+
startHttpServer
|
|
233
242
|
});
|
|
@@ -42,6 +42,7 @@ var import_utilsBundle = require("../../utilsBundle");
|
|
|
42
42
|
var import_debugLogger = require("./debugLogger");
|
|
43
43
|
var import_zones = require("./zones");
|
|
44
44
|
var import_debug = require("./debug");
|
|
45
|
+
var import_mcpBundle = require("../../mcpBundle");
|
|
45
46
|
const pipelineAsync = util.promisify(import_stream.pipeline);
|
|
46
47
|
class NodeZone {
|
|
47
48
|
constructor(zone) {
|
|
@@ -105,6 +106,11 @@ const nodePlatform = {
|
|
|
105
106
|
streamWritable: (channel) => {
|
|
106
107
|
return new WritableStreamImpl(channel);
|
|
107
108
|
},
|
|
109
|
+
zodToJsonSchema: (schema) => {
|
|
110
|
+
if ("_zod" in schema)
|
|
111
|
+
return import_mcpBundle.z.toJSONSchema(schema);
|
|
112
|
+
return (0, import_mcpBundle.zodToJsonSchema)(schema);
|
|
113
|
+
},
|
|
108
114
|
zones: {
|
|
109
115
|
current: () => new NodeZone((0, import_zones.currentZone)()),
|
|
110
116
|
empty: new NodeZone(import_zones.emptyZone)
|
|
@@ -21,12 +21,11 @@ __export(videoRecorder_exports, {
|
|
|
21
21
|
VideoRecorder: () => VideoRecorder
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(videoRecorder_exports);
|
|
24
|
-
var import_utils = require("
|
|
25
|
-
var
|
|
26
|
-
var import_processLauncher = require("../utils/processLauncher");
|
|
24
|
+
var import_utils = require("../utils");
|
|
25
|
+
var import_processLauncher = require("./utils/processLauncher");
|
|
27
26
|
const fps = 25;
|
|
28
27
|
class VideoRecorder {
|
|
29
|
-
constructor(
|
|
28
|
+
constructor(ffmpegPath, options) {
|
|
30
29
|
this._process = null;
|
|
31
30
|
this._gracefullyClose = null;
|
|
32
31
|
this._lastWritePromise = Promise.resolve();
|
|
@@ -36,16 +35,12 @@ class VideoRecorder {
|
|
|
36
35
|
this._frameQueue = [];
|
|
37
36
|
this._isStopped = false;
|
|
38
37
|
this._ffmpegPath = ffmpegPath;
|
|
39
|
-
page.on(import_page.Page.Events.ScreencastFrame, (frame) => this.writeFrame(frame.buffer, frame.frameSwapWallTime / 1e3));
|
|
40
|
-
}
|
|
41
|
-
static async launch(page, ffmpegPath, options) {
|
|
42
38
|
if (!options.outputFile.endsWith(".webm"))
|
|
43
39
|
throw new Error("File must have .webm extension");
|
|
44
|
-
|
|
45
|
-
await recorder._launch(options);
|
|
46
|
-
return recorder;
|
|
40
|
+
this._launchPromise = this._launch(options).catch((e) => e);
|
|
47
41
|
}
|
|
48
42
|
async _launch(options) {
|
|
43
|
+
await (0, import_utils.mkdirIfNeeded)(options.outputFile);
|
|
49
44
|
const w = options.width;
|
|
50
45
|
const h = options.height;
|
|
51
46
|
const args = `-loglevel error -f image2pipe -avioflags direct -fpsprobesize 0 -probesize 32 -analyzeduration 0 -c:v mjpeg -i pipe:0 -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -deadline realtime -speed 8 -b:v 1M -threads 1 -vf pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`.split(" ");
|
|
@@ -74,6 +69,13 @@ class VideoRecorder {
|
|
|
74
69
|
this._gracefullyClose = gracefullyClose;
|
|
75
70
|
}
|
|
76
71
|
writeFrame(frame, timestamp) {
|
|
72
|
+
this._launchPromise.then((error) => {
|
|
73
|
+
if (error)
|
|
74
|
+
return;
|
|
75
|
+
this._writeFrame(frame, timestamp);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
_writeFrame(frame, timestamp) {
|
|
77
79
|
(0, import_utils.assert)(this._process);
|
|
78
80
|
if (this._isStopped)
|
|
79
81
|
return;
|
|
@@ -100,13 +102,20 @@ class VideoRecorder {
|
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
async stop() {
|
|
105
|
+
const error = await this._launchPromise;
|
|
106
|
+
if (error)
|
|
107
|
+
throw error;
|
|
103
108
|
if (this._isStopped || !this._lastFrame)
|
|
104
109
|
return;
|
|
105
110
|
const addTime = Math.max(((0, import_utils.monotonicTime)() - this._lastWriteNodeTime) / 1e3, 1);
|
|
106
|
-
this.
|
|
111
|
+
this._writeFrame(Buffer.from([]), this._lastFrame.timestamp + addTime);
|
|
107
112
|
this._isStopped = true;
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
try {
|
|
114
|
+
await this._lastWritePromise;
|
|
115
|
+
await this._gracefullyClose();
|
|
116
|
+
} catch (e) {
|
|
117
|
+
import_utils.debugLogger.log("error", `ffmpeg failed to stop: ${String(e)}`);
|
|
118
|
+
}
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
121
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -51,12 +51,10 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
51
51
|
CURL_COOKIE_JAR_PATH: process.platform === "win32" && isPersistent ? import_path.default.join(userDataDir, "cookiejar.db") : void 0
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
doRewriteStartupLog(
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
error.logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
|
|
59
|
-
return error;
|
|
54
|
+
doRewriteStartupLog(logs) {
|
|
55
|
+
if (logs.includes("Failed to open display") || logs.includes("cannot open display"))
|
|
56
|
+
logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
|
|
57
|
+
return logs;
|
|
60
58
|
}
|
|
61
59
|
attemptToGracefullyCloseBrowser(transport) {
|
|
62
60
|
transport.send({ method: "Playwright.close", params: {}, id: import_wkConnection.kBrowserCloseMessageId });
|
|
@@ -56,7 +56,6 @@ class WKBrowser extends import_browser.Browser {
|
|
|
56
56
|
this._browserSession.on("Playwright.downloadCreated", this._onDownloadCreated.bind(this));
|
|
57
57
|
this._browserSession.on("Playwright.downloadFilenameSuggested", this._onDownloadFilenameSuggested.bind(this));
|
|
58
58
|
this._browserSession.on("Playwright.downloadFinished", this._onDownloadFinished.bind(this));
|
|
59
|
-
this._browserSession.on("Playwright.screencastFinished", this._onScreencastFinished.bind(this));
|
|
60
59
|
this._browserSession.on(import_wkConnection.kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this));
|
|
61
60
|
}
|
|
62
61
|
static async connect(parent, transport, options) {
|
|
@@ -79,7 +78,7 @@ class WKBrowser extends import_browser.Browser {
|
|
|
79
78
|
wkPage.didClose();
|
|
80
79
|
this._wkPages.clear();
|
|
81
80
|
for (const video of this._idToVideo.values())
|
|
82
|
-
video.artifact.reportFinished(new import_errors.TargetClosedError());
|
|
81
|
+
video.artifact.reportFinished(new import_errors.TargetClosedError(this.closeReason()));
|
|
83
82
|
this._idToVideo.clear();
|
|
84
83
|
this._didClose();
|
|
85
84
|
}
|
|
@@ -131,9 +130,6 @@ class WKBrowser extends import_browser.Browser {
|
|
|
131
130
|
_onDownloadFinished(payload) {
|
|
132
131
|
this._downloadFinished(payload.uuid, payload.error);
|
|
133
132
|
}
|
|
134
|
-
_onScreencastFinished(payload) {
|
|
135
|
-
this._takeVideo(payload.screencastId)?.reportFinished();
|
|
136
|
-
}
|
|
137
133
|
_onPageProxyCreated(event) {
|
|
138
134
|
const pageProxyId = event.pageProxyId;
|
|
139
135
|
let context = null;
|
|
@@ -315,7 +311,7 @@ class WKBrowserContext extends import_browserContext.BrowserContext {
|
|
|
315
311
|
}
|
|
316
312
|
async doClose(reason) {
|
|
317
313
|
if (!this._browserContextId) {
|
|
318
|
-
await Promise.all(this._wkPages().map((wkPage) => wkPage.
|
|
314
|
+
await Promise.all(this._wkPages().map((wkPage) => wkPage._page.screencast.stopVideoRecording()));
|
|
319
315
|
await this._browser.close({ reason });
|
|
320
316
|
} else {
|
|
321
317
|
await this._browser._browserSession.send("Playwright.deleteContext", { browserContextId: this._browserContextId });
|
|
@@ -89,11 +89,6 @@ class WKSession extends import_events.EventEmitter {
|
|
|
89
89
|
this.connection = connection;
|
|
90
90
|
this.sessionId = sessionId;
|
|
91
91
|
this._rawSend = rawSend;
|
|
92
|
-
this.on = super.on;
|
|
93
|
-
this.off = super.removeListener;
|
|
94
|
-
this.addListener = super.addListener;
|
|
95
|
-
this.removeListener = super.removeListener;
|
|
96
|
-
this.once = super.once;
|
|
97
92
|
}
|
|
98
93
|
async send(method, params) {
|
|
99
94
|
if (this._crashed || this._disposed || this.connection._browserDisconnectedLogs)
|
|
@@ -134,7 +129,7 @@ class WKSession extends import_events.EventEmitter {
|
|
|
134
129
|
callback.resolve(object.result);
|
|
135
130
|
}
|
|
136
131
|
} else if (object.id && !object.error) {
|
|
137
|
-
(0, import_utils.assert)(this.isDisposed());
|
|
132
|
+
(0, import_utils.assert)(this.isDisposed(), JSON.stringify(object));
|
|
138
133
|
} else {
|
|
139
134
|
Promise.resolve().then(() => this.emit(object.method, object.params));
|
|
140
135
|
}
|
|
@@ -54,7 +54,7 @@ class WKInterceptableRequest {
|
|
|
54
54
|
constructor(session, frame, event, redirectedFrom, documentId) {
|
|
55
55
|
this._session = session;
|
|
56
56
|
this._requestId = event.requestId;
|
|
57
|
-
const resourceType = event.type ? event.type
|
|
57
|
+
const resourceType = event.type ? toResourceType(event.type) : redirectedFrom ? redirectedFrom.request.resourceType() : "other";
|
|
58
58
|
let postDataBuffer = null;
|
|
59
59
|
this._timestamp = event.timestamp;
|
|
60
60
|
this._wallTime = event.walltime * 1e3;
|
|
@@ -162,6 +162,34 @@ function wkMillisToRoundishMillis(value) {
|
|
|
162
162
|
}
|
|
163
163
|
return (value * 1e3 | 0) / 1e3;
|
|
164
164
|
}
|
|
165
|
+
function toResourceType(type) {
|
|
166
|
+
switch (type) {
|
|
167
|
+
case "Document":
|
|
168
|
+
return "document";
|
|
169
|
+
case "StyleSheet":
|
|
170
|
+
return "stylesheet";
|
|
171
|
+
case "Image":
|
|
172
|
+
return "image";
|
|
173
|
+
case "Font":
|
|
174
|
+
return "font";
|
|
175
|
+
case "Script":
|
|
176
|
+
return "script";
|
|
177
|
+
case "XHR":
|
|
178
|
+
return "xhr";
|
|
179
|
+
case "Fetch":
|
|
180
|
+
return "fetch";
|
|
181
|
+
case "Ping":
|
|
182
|
+
return "ping";
|
|
183
|
+
case "Beacon":
|
|
184
|
+
return "beacon";
|
|
185
|
+
case "WebSocket":
|
|
186
|
+
return "websocket";
|
|
187
|
+
case "EventSource":
|
|
188
|
+
return "eventsource";
|
|
189
|
+
default:
|
|
190
|
+
return "other";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
165
193
|
// Annotate the CommonJS export names for ESM import in node:
|
|
166
194
|
0 && (module.exports = {
|
|
167
195
|
WKInterceptableRequest,
|