playwright-core 1.58.0-alpha-2025-12-07 → 1.58.0-alpha-2025-12-09
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 +3 -3
- package/lib/client/browserContext.js +7 -0
- package/lib/client/page.js +4 -3
- package/lib/client/platform.js +3 -0
- package/lib/protocol/validator.js +29 -10
- package/lib/server/agent/actionRunner.js +68 -0
- package/lib/server/agent/actions.js +16 -0
- package/lib/server/agent/agent.js +122 -0
- package/lib/server/agent/backend.js +77 -0
- package/lib/server/agent/context.js +115 -0
- package/lib/server/agent/tools.js +229 -0
- package/lib/server/bidi/bidiNetworkManager.js +1 -1
- package/lib/server/bidi/bidiPage.js +3 -1
- package/lib/server/browserContext.js +2 -2
- package/lib/server/chromium/chromium.js +1 -3
- package/lib/server/chromium/chromiumSwitches.js +0 -2
- package/lib/server/chromium/crBrowser.js +1 -1
- package/lib/server/chromium/crNetworkManager.js +39 -2
- package/lib/server/chromium/crPage.js +14 -81
- package/lib/server/deviceDescriptorsSource.json +2 -2
- package/lib/server/dispatchers/browserDispatcher.js +1 -0
- package/lib/server/dispatchers/pageDispatcher.js +7 -0
- package/lib/server/firefox/ffNetworkManager.js +2 -2
- package/lib/server/firefox/ffPage.js +9 -8
- package/lib/server/frames.js +2 -2
- package/lib/server/network.js +3 -0
- package/lib/server/page.js +5 -65
- package/lib/server/progress.js +3 -2
- package/lib/server/registry/index.js +1 -1
- package/lib/server/screencast.js +191 -0
- package/lib/server/trace/recorder/tracing.js +5 -5
- package/lib/server/utils/nodePlatform.js +2 -0
- package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +3 -3
- package/lib/server/webkit/wkBrowser.js +1 -1
- package/lib/server/webkit/wkInterceptableRequest.js +29 -1
- package/lib/server/webkit/wkPage.js +20 -40
- package/lib/utils/isomorphic/protocolMetainfo.js +2 -0
- package/lib/vite/traceViewer/assets/{codeMirrorModule-JphNwIdM.js → codeMirrorModule-CPNe-I5g.js} +1 -1
- package/lib/vite/traceViewer/assets/{defaultSettingsView-C7iHYOsw.js → defaultSettingsView-V7hnXDpz.js} +3 -3
- package/lib/vite/traceViewer/{index.C5w1selH.js → index.YskCIlQ-.js} +1 -1
- package/lib/vite/traceViewer/index.html +2 -2
- package/lib/vite/traceViewer/{uiMode.CCu4MMfA.js → uiMode.CmFFBCQb.js} +1 -1
- package/lib/vite/traceViewer/uiMode.html +2 -2
- package/package.json +1 -1
- package/types/types.d.ts +10 -5
package/lib/server/page.js
CHANGED
|
@@ -53,6 +53,7 @@ var import_manualPromise = require("../utils/isomorphic/manualPromise");
|
|
|
53
53
|
var import_utilityScriptSerializers = require("../utils/isomorphic/utilityScriptSerializers");
|
|
54
54
|
var import_callLog = require("./callLog");
|
|
55
55
|
var rawBindingsControllerSource = __toESM(require("../generated/bindingsControllerSource"));
|
|
56
|
+
var import_screencast = require("./screencast");
|
|
56
57
|
class Page extends import_instrumentation.SdkObject {
|
|
57
58
|
constructor(delegate, browserContext) {
|
|
58
59
|
super(browserContext, "page");
|
|
@@ -74,9 +75,6 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
74
75
|
this._lastLocatorHandlerUid = 0;
|
|
75
76
|
this._locatorHandlerRunningCounter = 0;
|
|
76
77
|
this._networkRequests = [];
|
|
77
|
-
// Aiming at 25 fps by default - each frame is 40ms, but we give some slack with 35ms.
|
|
78
|
-
// When throttling for tracing, 200ms between frames, except for 10 frames around the action.
|
|
79
|
-
this._frameThrottler = new FrameThrottler(10, 35, 200);
|
|
80
78
|
this.attribution.page = this;
|
|
81
79
|
this.delegate = delegate;
|
|
82
80
|
this.browserContext = browserContext;
|
|
@@ -85,6 +83,7 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
85
83
|
this.touchscreen = new input.Touchscreen(delegate.rawTouchscreen, this);
|
|
86
84
|
this.screenshotter = new import_screenshotter.Screenshotter(this);
|
|
87
85
|
this.frameManager = new frames.FrameManager(this);
|
|
86
|
+
this.screencast = new import_screencast.Screencast(this);
|
|
88
87
|
if (delegate.pdf)
|
|
89
88
|
this.pdf = delegate.pdf.bind(delegate);
|
|
90
89
|
this.coverage = delegate.coverage ? delegate.coverage() : null;
|
|
@@ -158,7 +157,7 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
158
157
|
}
|
|
159
158
|
_didClose() {
|
|
160
159
|
this.frameManager.dispose();
|
|
161
|
-
this.
|
|
160
|
+
this.screencast.stopFrameThrottler();
|
|
162
161
|
(0, import_utils.assert)(this._closedState !== "closed", "Page closed twice");
|
|
163
162
|
this._closedState = "closed";
|
|
164
163
|
this.emit(Page.Events.Close);
|
|
@@ -168,7 +167,7 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
168
167
|
}
|
|
169
168
|
_didCrash() {
|
|
170
169
|
this.frameManager.dispose();
|
|
171
|
-
this.
|
|
170
|
+
this.screencast.stopFrameThrottler();
|
|
172
171
|
this.emit(Page.Events.Crash);
|
|
173
172
|
this._crashed = true;
|
|
174
173
|
this.instrumentation.onPageClose(this);
|
|
@@ -641,16 +640,6 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
641
640
|
getBinding(name) {
|
|
642
641
|
return this._pageBindings.get(name) || this.browserContext._pageBindings.get(name);
|
|
643
642
|
}
|
|
644
|
-
setScreencastOptions(options) {
|
|
645
|
-
this.delegate.setScreencastOptions(options).catch((e) => import_debugLogger.debugLogger.log("error", e));
|
|
646
|
-
this._frameThrottler.setThrottlingEnabled(!!options);
|
|
647
|
-
}
|
|
648
|
-
throttleScreencastFrameAck(ack) {
|
|
649
|
-
this._frameThrottler.ack(ack);
|
|
650
|
-
}
|
|
651
|
-
temporarilyDisableTracingScreencastThrottling() {
|
|
652
|
-
this._frameThrottler.recharge();
|
|
653
|
-
}
|
|
654
643
|
async safeNonStallingEvaluateInAllFrames(expression, world, options = {}) {
|
|
655
644
|
await Promise.all(this.frames().map(async (frame) => {
|
|
656
645
|
try {
|
|
@@ -665,7 +654,7 @@ class Page extends import_instrumentation.SdkObject {
|
|
|
665
654
|
await Promise.all(this.frames().map((frame) => frame.hideHighlight().catch(() => {
|
|
666
655
|
})));
|
|
667
656
|
}
|
|
668
|
-
async snapshotForAI(progress, options) {
|
|
657
|
+
async snapshotForAI(progress, options = {}) {
|
|
669
658
|
const snapshot = await snapshotFrameForAI(progress, this.mainFrame(), options);
|
|
670
659
|
return { full: snapshot.full.join("\n"), incremental: snapshot.incremental?.join("\n") };
|
|
671
660
|
}
|
|
@@ -763,55 +752,6 @@ class InitScript {
|
|
|
763
752
|
})();`;
|
|
764
753
|
}
|
|
765
754
|
}
|
|
766
|
-
class FrameThrottler {
|
|
767
|
-
constructor(nonThrottledFrames, defaultInterval, throttlingInterval) {
|
|
768
|
-
this._acks = [];
|
|
769
|
-
this._throttlingEnabled = false;
|
|
770
|
-
this._nonThrottledFrames = nonThrottledFrames;
|
|
771
|
-
this._budget = nonThrottledFrames;
|
|
772
|
-
this._defaultInterval = defaultInterval;
|
|
773
|
-
this._throttlingInterval = throttlingInterval;
|
|
774
|
-
this._tick();
|
|
775
|
-
}
|
|
776
|
-
dispose() {
|
|
777
|
-
if (this._timeoutId) {
|
|
778
|
-
clearTimeout(this._timeoutId);
|
|
779
|
-
this._timeoutId = void 0;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
setThrottlingEnabled(enabled) {
|
|
783
|
-
this._throttlingEnabled = enabled;
|
|
784
|
-
}
|
|
785
|
-
recharge() {
|
|
786
|
-
for (const ack of this._acks)
|
|
787
|
-
ack();
|
|
788
|
-
this._acks = [];
|
|
789
|
-
this._budget = this._nonThrottledFrames;
|
|
790
|
-
if (this._timeoutId) {
|
|
791
|
-
clearTimeout(this._timeoutId);
|
|
792
|
-
this._tick();
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
ack(ack) {
|
|
796
|
-
if (!this._timeoutId) {
|
|
797
|
-
ack();
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
|
-
this._acks.push(ack);
|
|
801
|
-
}
|
|
802
|
-
_tick() {
|
|
803
|
-
const ack = this._acks.shift();
|
|
804
|
-
if (ack) {
|
|
805
|
-
--this._budget;
|
|
806
|
-
ack();
|
|
807
|
-
}
|
|
808
|
-
if (this._throttlingEnabled && this._budget <= 0) {
|
|
809
|
-
this._timeoutId = setTimeout(() => this._tick(), this._throttlingInterval);
|
|
810
|
-
} else {
|
|
811
|
-
this._timeoutId = setTimeout(() => this._tick(), this._defaultInterval);
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
755
|
async function snapshotFrameForAI(progress, frame, options) {
|
|
816
756
|
const snapshot = await frame.retryWithProgressAndTimeouts(progress, [1e3, 2e3, 4e3, 8e3], async (continuePolling) => {
|
|
817
757
|
try {
|
package/lib/server/progress.js
CHANGED
|
@@ -53,9 +53,10 @@ class ProgressController {
|
|
|
53
53
|
this._onCallLog?.(message);
|
|
54
54
|
},
|
|
55
55
|
metadata: this.metadata,
|
|
56
|
-
race: (promise) => {
|
|
56
|
+
race: (promise, options) => {
|
|
57
57
|
const promises = Array.isArray(promise) ? promise : [promise];
|
|
58
|
-
|
|
58
|
+
const timerPromise = options?.timeout ? new Promise((f) => setTimeout(f, options.timeout)) : null;
|
|
59
|
+
return Promise.race([...promises, ...timerPromise ? [timerPromise] : [], this._forceAbortPromise]);
|
|
59
60
|
},
|
|
60
61
|
wait: async (timeout2) => {
|
|
61
62
|
let timer2;
|
|
@@ -1296,7 +1296,7 @@ ${e.stack}`);
|
|
|
1296
1296
|
faultyArguments.push(arg);
|
|
1297
1297
|
else
|
|
1298
1298
|
executables.push(executable);
|
|
1299
|
-
if (executable?.browserName
|
|
1299
|
+
if (executable?.browserName)
|
|
1300
1300
|
executables.push(this.findExecutable("ffmpeg"));
|
|
1301
1301
|
};
|
|
1302
1302
|
for (const alias of aliases) {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var screencast_exports = {};
|
|
30
|
+
__export(screencast_exports, {
|
|
31
|
+
Screencast: () => Screencast
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(screencast_exports);
|
|
34
|
+
var import_path = __toESM(require("path"));
|
|
35
|
+
var import_utils = require("../utils");
|
|
36
|
+
var import_utils2 = require("../utils");
|
|
37
|
+
var import_videoRecorder = require("./videoRecorder");
|
|
38
|
+
var import_page = require("./page");
|
|
39
|
+
var import_registry = require("./registry");
|
|
40
|
+
class Screencast {
|
|
41
|
+
constructor(page) {
|
|
42
|
+
this._videoRecorder = null;
|
|
43
|
+
this._screencastId = null;
|
|
44
|
+
this._screencastClients = /* @__PURE__ */ new Set();
|
|
45
|
+
// Aiming at 25 fps by default - each frame is 40ms, but we give some slack with 35ms.
|
|
46
|
+
// When throttling for tracing, 200ms between frames, except for 10 frames around the action.
|
|
47
|
+
this._frameThrottler = new FrameThrottler(10, 35, 200);
|
|
48
|
+
this._page = page;
|
|
49
|
+
}
|
|
50
|
+
stopFrameThrottler() {
|
|
51
|
+
this._frameThrottler.dispose();
|
|
52
|
+
}
|
|
53
|
+
setOptions(options) {
|
|
54
|
+
this._setOptions(options).catch((e) => import_utils2.debugLogger.log("error", e));
|
|
55
|
+
this._frameThrottler.setThrottlingEnabled(!!options);
|
|
56
|
+
}
|
|
57
|
+
throttleFrameAck(ack) {
|
|
58
|
+
this._frameThrottler.ack(ack);
|
|
59
|
+
}
|
|
60
|
+
temporarilyDisableThrottling() {
|
|
61
|
+
this._frameThrottler.recharge();
|
|
62
|
+
}
|
|
63
|
+
async initializeVideoRecorder() {
|
|
64
|
+
const recordVideo = this._page.browserContext._options.recordVideo;
|
|
65
|
+
if (!recordVideo)
|
|
66
|
+
return void 0;
|
|
67
|
+
const screencastId = (0, import_utils.createGuid)();
|
|
68
|
+
const outputFile = import_path.default.join(recordVideo.dir, screencastId + ".webm");
|
|
69
|
+
const screencastOptions = {
|
|
70
|
+
// validateBrowserContextOptions ensures correct video size.
|
|
71
|
+
...recordVideo.size,
|
|
72
|
+
outputFile
|
|
73
|
+
};
|
|
74
|
+
await (0, import_utils.mkdirIfNeeded)(import_path.default.join(recordVideo.dir, "dummy"));
|
|
75
|
+
await this._createVideoRecorder(screencastId, screencastOptions);
|
|
76
|
+
this._page.waitForInitializedOrError().then((p) => {
|
|
77
|
+
if (p instanceof Error)
|
|
78
|
+
this.stopVideoRecording().catch(() => {
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
return screencastOptions;
|
|
82
|
+
}
|
|
83
|
+
async startVideoRecording(options) {
|
|
84
|
+
const screencastId = this._screencastId;
|
|
85
|
+
(0, import_utils.assert)(screencastId);
|
|
86
|
+
this._page.once(import_page.Page.Events.Close, () => this.stopVideoRecording().catch(() => {
|
|
87
|
+
}));
|
|
88
|
+
const gotFirstFrame = new Promise((f) => this._page.once(import_page.Page.Events.ScreencastFrame, f));
|
|
89
|
+
await this._startScreencast(this._videoRecorder, {
|
|
90
|
+
quality: 90,
|
|
91
|
+
width: options.width,
|
|
92
|
+
height: options.height
|
|
93
|
+
});
|
|
94
|
+
gotFirstFrame.then(() => {
|
|
95
|
+
this._page.browserContext._browser._videoStarted(this._page.browserContext, screencastId, options.outputFile, this._page.waitForInitializedOrError());
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async stopVideoRecording() {
|
|
99
|
+
if (!this._screencastId)
|
|
100
|
+
return;
|
|
101
|
+
const screencastId = this._screencastId;
|
|
102
|
+
this._screencastId = null;
|
|
103
|
+
const recorder = this._videoRecorder;
|
|
104
|
+
this._videoRecorder = null;
|
|
105
|
+
await this._stopScreencast(recorder);
|
|
106
|
+
await recorder.stop().catch(() => {
|
|
107
|
+
});
|
|
108
|
+
const video = this._page.browserContext._browser._takeVideo(screencastId);
|
|
109
|
+
video?.reportFinished();
|
|
110
|
+
}
|
|
111
|
+
async _setOptions(options) {
|
|
112
|
+
if (options)
|
|
113
|
+
await this._startScreencast(this, options);
|
|
114
|
+
else
|
|
115
|
+
await this._stopScreencast(this);
|
|
116
|
+
}
|
|
117
|
+
async _startScreencast(client, options) {
|
|
118
|
+
this._screencastClients.add(client);
|
|
119
|
+
if (this._screencastClients.size === 1) {
|
|
120
|
+
await this._page.delegate.startScreencast({
|
|
121
|
+
width: options.width,
|
|
122
|
+
height: options.height,
|
|
123
|
+
quality: options.quality
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async _stopScreencast(client) {
|
|
128
|
+
this._screencastClients.delete(client);
|
|
129
|
+
if (!this._screencastClients.size)
|
|
130
|
+
await this._page.delegate.stopScreencast();
|
|
131
|
+
}
|
|
132
|
+
async _createVideoRecorder(screencastId, options) {
|
|
133
|
+
(0, import_utils.assert)(!this._screencastId);
|
|
134
|
+
const ffmpegPath = import_registry.registry.findExecutable("ffmpeg").executablePathOrDie(this._page.browserContext._browser.sdkLanguage());
|
|
135
|
+
this._videoRecorder = await import_videoRecorder.VideoRecorder.launch(this._page, ffmpegPath, options);
|
|
136
|
+
this._screencastId = screencastId;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
class FrameThrottler {
|
|
140
|
+
constructor(nonThrottledFrames, defaultInterval, throttlingInterval) {
|
|
141
|
+
this._acks = [];
|
|
142
|
+
this._throttlingEnabled = false;
|
|
143
|
+
this._nonThrottledFrames = nonThrottledFrames;
|
|
144
|
+
this._budget = nonThrottledFrames;
|
|
145
|
+
this._defaultInterval = defaultInterval;
|
|
146
|
+
this._throttlingInterval = throttlingInterval;
|
|
147
|
+
this._tick();
|
|
148
|
+
}
|
|
149
|
+
dispose() {
|
|
150
|
+
if (this._timeoutId) {
|
|
151
|
+
clearTimeout(this._timeoutId);
|
|
152
|
+
this._timeoutId = void 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
setThrottlingEnabled(enabled) {
|
|
156
|
+
this._throttlingEnabled = enabled;
|
|
157
|
+
}
|
|
158
|
+
recharge() {
|
|
159
|
+
for (const ack of this._acks)
|
|
160
|
+
ack();
|
|
161
|
+
this._acks = [];
|
|
162
|
+
this._budget = this._nonThrottledFrames;
|
|
163
|
+
if (this._timeoutId) {
|
|
164
|
+
clearTimeout(this._timeoutId);
|
|
165
|
+
this._tick();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
ack(ack) {
|
|
169
|
+
if (!this._timeoutId) {
|
|
170
|
+
ack();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this._acks.push(ack);
|
|
174
|
+
}
|
|
175
|
+
_tick() {
|
|
176
|
+
const ack = this._acks.shift();
|
|
177
|
+
if (ack) {
|
|
178
|
+
--this._budget;
|
|
179
|
+
ack();
|
|
180
|
+
}
|
|
181
|
+
if (this._throttlingEnabled && this._budget <= 0) {
|
|
182
|
+
this._timeoutId = setTimeout(() => this._tick(), this._throttlingInterval);
|
|
183
|
+
} else {
|
|
184
|
+
this._timeoutId = setTimeout(() => this._tick(), this._defaultInterval);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
189
|
+
0 && (module.exports = {
|
|
190
|
+
Screencast
|
|
191
|
+
});
|
|
@@ -222,7 +222,7 @@ class Tracing extends import_instrumentation.SdkObject {
|
|
|
222
222
|
if (!(this._context instanceof import_browserContext.BrowserContext))
|
|
223
223
|
return;
|
|
224
224
|
for (const page of this._context.pages())
|
|
225
|
-
page.
|
|
225
|
+
page.screencast.setOptions(null);
|
|
226
226
|
}
|
|
227
227
|
_allocateNewTraceFile(state) {
|
|
228
228
|
const suffix = state.chunkOrdinal ? `-chunk${state.chunkOrdinal}` : ``;
|
|
@@ -341,7 +341,7 @@ class Tracing extends import_instrumentation.SdkObject {
|
|
|
341
341
|
const event = createBeforeActionTraceEvent(metadata, this._currentGroupId());
|
|
342
342
|
if (!event)
|
|
343
343
|
return Promise.resolve();
|
|
344
|
-
sdkObject.attribution.page?.
|
|
344
|
+
sdkObject.attribution.page?.screencast.temporarilyDisableThrottling();
|
|
345
345
|
event.beforeSnapshot = `before@${metadata.id}`;
|
|
346
346
|
this._state?.callIds.add(metadata.id);
|
|
347
347
|
this._appendTraceEvent(event);
|
|
@@ -353,7 +353,7 @@ class Tracing extends import_instrumentation.SdkObject {
|
|
|
353
353
|
const event = createInputActionTraceEvent(metadata);
|
|
354
354
|
if (!event)
|
|
355
355
|
return Promise.resolve();
|
|
356
|
-
sdkObject.attribution.page?.
|
|
356
|
+
sdkObject.attribution.page?.screencast.temporarilyDisableThrottling();
|
|
357
357
|
event.inputSnapshot = `input@${metadata.id}`;
|
|
358
358
|
this._appendTraceEvent(event);
|
|
359
359
|
return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata);
|
|
@@ -376,7 +376,7 @@ class Tracing extends import_instrumentation.SdkObject {
|
|
|
376
376
|
const event = createAfterActionTraceEvent(metadata);
|
|
377
377
|
if (!event)
|
|
378
378
|
return;
|
|
379
|
-
sdkObject.attribution.page?.
|
|
379
|
+
sdkObject.attribution.page?.screencast.temporarilyDisableThrottling();
|
|
380
380
|
event.afterSnapshot = `after@${metadata.id}`;
|
|
381
381
|
this._appendTraceEvent(event);
|
|
382
382
|
return this._captureSnapshot(event.afterSnapshot, sdkObject, metadata);
|
|
@@ -484,7 +484,7 @@ class Tracing extends import_instrumentation.SdkObject {
|
|
|
484
484
|
this._appendTraceEvent(event);
|
|
485
485
|
}
|
|
486
486
|
_startScreencastInPage(page) {
|
|
487
|
-
page.
|
|
487
|
+
page.screencast.setOptions(kScreencastOptions);
|
|
488
488
|
const prefix = page.guid;
|
|
489
489
|
this._screencastListeners.push(
|
|
490
490
|
import_eventsHelper.eventsHelper.addEventListener(page, import_page.Page.Events.ScreencastFrame, (params) => {
|
|
@@ -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,7 @@ const nodePlatform = {
|
|
|
105
106
|
streamWritable: (channel) => {
|
|
106
107
|
return new WritableStreamImpl(channel);
|
|
107
108
|
},
|
|
109
|
+
zodToJsonSchema: import_mcpBundle.zodToJsonSchema,
|
|
108
110
|
zones: {
|
|
109
111
|
current: () => new NodeZone((0, import_zones.currentZone)()),
|
|
110
112
|
empty: new NodeZone(import_zones.emptyZone)
|
|
@@ -21,9 +21,9 @@ __export(videoRecorder_exports, {
|
|
|
21
21
|
VideoRecorder: () => VideoRecorder
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(videoRecorder_exports);
|
|
24
|
-
var import_utils = require("
|
|
25
|
-
var import_page = require("
|
|
26
|
-
var import_processLauncher = require("
|
|
24
|
+
var import_utils = require("../utils");
|
|
25
|
+
var import_page = require("./page");
|
|
26
|
+
var import_processLauncher = require("./utils/processLauncher");
|
|
27
27
|
const fps = 25;
|
|
28
28
|
class VideoRecorder {
|
|
29
29
|
constructor(page, ffmpegPath) {
|
|
@@ -315,7 +315,7 @@ class WKBrowserContext extends import_browserContext.BrowserContext {
|
|
|
315
315
|
}
|
|
316
316
|
async doClose(reason) {
|
|
317
317
|
if (!this._browserContextId) {
|
|
318
|
-
await Promise.all(this._wkPages().map((wkPage) => wkPage.
|
|
318
|
+
await Promise.all(this._wkPages().map((wkPage) => wkPage._page.screencast.stopVideoRecording()));
|
|
319
319
|
await this._browser.close({ reason });
|
|
320
320
|
} else {
|
|
321
321
|
await this._browser._browserSession.send("Playwright.deleteContext", { browserContextId: this._browserContextId });
|
|
@@ -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,
|
|
@@ -31,10 +31,8 @@ __export(wkPage_exports, {
|
|
|
31
31
|
WKPage: () => WKPage
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(wkPage_exports);
|
|
34
|
-
var import_path = __toESM(require("path"));
|
|
35
34
|
var import_utils = require("../../utils");
|
|
36
35
|
var import_headers = require("../../utils/isomorphic/headers");
|
|
37
|
-
var import_crypto = require("../utils/crypto");
|
|
38
36
|
var import_eventsHelper = require("../utils/eventsHelper");
|
|
39
37
|
var import_hostPlatform = require("../utils/hostPlatform");
|
|
40
38
|
var import_stackTrace = require("../../utils/isomorphic/stackTrace");
|
|
@@ -66,7 +64,6 @@ class WKPage {
|
|
|
66
64
|
};
|
|
67
65
|
this._lastConsoleMessage = null;
|
|
68
66
|
this._requestIdToResponseReceivedPayloadEvent = /* @__PURE__ */ new Map();
|
|
69
|
-
this._recordingVideoFile = null;
|
|
70
67
|
this._screencastGeneration = 0;
|
|
71
68
|
this._pageProxySession = pageProxySession;
|
|
72
69
|
this._opener = opener;
|
|
@@ -116,16 +113,7 @@ class WKPage {
|
|
|
116
113
|
for (const [key, value] of this._browserContext._permissions)
|
|
117
114
|
promises.push(this._grantPermissions(key, value));
|
|
118
115
|
}
|
|
119
|
-
|
|
120
|
-
const outputFile = import_path.default.join(this._browserContext._options.recordVideo.dir, (0, import_crypto.createGuid)() + ".webm");
|
|
121
|
-
promises.push(this._browserContext._ensureVideosPath().then(() => {
|
|
122
|
-
return this._startVideo({
|
|
123
|
-
// validateBrowserContextOptions ensures correct video size.
|
|
124
|
-
...this._browserContext._options.recordVideo.size,
|
|
125
|
-
outputFile
|
|
126
|
-
});
|
|
127
|
-
}));
|
|
128
|
-
}
|
|
116
|
+
promises.push(this._initializeVideoRecording());
|
|
129
117
|
await Promise.all(promises);
|
|
130
118
|
}
|
|
131
119
|
_setSession(session) {
|
|
@@ -748,7 +736,6 @@ class WKPage {
|
|
|
748
736
|
await this._updateState("Page.setBootstrapScript", { source: this._calculateBootstrapScript() });
|
|
749
737
|
}
|
|
750
738
|
async closePage(runBeforeUnload) {
|
|
751
|
-
await this._stopVideo();
|
|
752
739
|
await this._pageProxySession.sendMayFail("Target.close", {
|
|
753
740
|
targetId: this._session.sessionId,
|
|
754
741
|
runBeforeUnload
|
|
@@ -762,22 +749,10 @@ class WKPage {
|
|
|
762
749
|
return import_hostPlatform.hostPlatform === "mac10.15" ? 55 : 59;
|
|
763
750
|
return 0;
|
|
764
751
|
}
|
|
765
|
-
async
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
width: options.width,
|
|
770
|
-
height: options.height,
|
|
771
|
-
toolbarHeight: this._toolbarHeight()
|
|
772
|
-
});
|
|
773
|
-
this._recordingVideoFile = options.outputFile;
|
|
774
|
-
this._browserContext._browser._videoStarted(this._browserContext, screencastId, options.outputFile, this._page.waitForInitializedOrError());
|
|
775
|
-
}
|
|
776
|
-
async _stopVideo() {
|
|
777
|
-
if (!this._recordingVideoFile)
|
|
778
|
-
return;
|
|
779
|
-
await this._pageProxySession.sendMayFail("Screencast.stopVideo");
|
|
780
|
-
this._recordingVideoFile = null;
|
|
752
|
+
async _initializeVideoRecording() {
|
|
753
|
+
const screencastOptions = await this._page.screencast.initializeVideoRecorder();
|
|
754
|
+
if (screencastOptions)
|
|
755
|
+
await this._page.screencast.startVideoRecording(screencastOptions);
|
|
781
756
|
}
|
|
782
757
|
validateScreenshotDimension(side, omitDeviceScaleFactor) {
|
|
783
758
|
if (process.platform === "darwin")
|
|
@@ -845,23 +820,28 @@ class WKPage {
|
|
|
845
820
|
throw e;
|
|
846
821
|
});
|
|
847
822
|
}
|
|
848
|
-
async
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
823
|
+
async startScreencast(options) {
|
|
824
|
+
const { generation } = await this._pageProxySession.send("Screencast.startScreencast", {
|
|
825
|
+
quality: options.quality,
|
|
826
|
+
width: options.width,
|
|
827
|
+
height: options.height,
|
|
828
|
+
toolbarHeight: this._toolbarHeight()
|
|
829
|
+
});
|
|
830
|
+
this._screencastGeneration = generation;
|
|
831
|
+
}
|
|
832
|
+
async stopScreencast() {
|
|
833
|
+
await this._pageProxySession.sendMayFail("Screencast.stopScreencast");
|
|
856
834
|
}
|
|
857
835
|
_onScreencastFrame(event) {
|
|
858
836
|
const generation = this._screencastGeneration;
|
|
859
|
-
this._page.
|
|
837
|
+
this._page.screencast.throttleFrameAck(() => {
|
|
860
838
|
this._pageProxySession.send("Screencast.screencastFrameAck", { generation }).catch((e) => import_debugLogger.debugLogger.log("error", e));
|
|
861
839
|
});
|
|
862
840
|
const buffer = Buffer.from(event.data, "base64");
|
|
863
841
|
this._page.emit(import_page.Page.Events.ScreencastFrame, {
|
|
864
842
|
buffer,
|
|
843
|
+
frameSwapWallTime: event.timestamp * 1e3,
|
|
844
|
+
// timestamp is in seconds, we need to convert to milliseconds.
|
|
865
845
|
width: event.deviceWidth,
|
|
866
846
|
height: event.deviceHeight
|
|
867
847
|
});
|
|
@@ -886,7 +866,7 @@ class WKPage {
|
|
|
886
866
|
const pageProxyId = this._pageProxySession.sessionId;
|
|
887
867
|
const objectId = handle._objectId;
|
|
888
868
|
if (this._browserContext._browser?.options.channel === "webkit-wsl")
|
|
889
|
-
paths = await Promise.all(paths.map((
|
|
869
|
+
paths = await Promise.all(paths.map((path) => (0, import_webkit.translatePathToWSL)(path)));
|
|
890
870
|
await Promise.all([
|
|
891
871
|
this._pageProxySession.connection.browserSession.send("Playwright.grantFileReadAccess", { pageProxyId, paths }),
|
|
892
872
|
this._session.send("DOM.setInputFiles", { objectId, paths })
|
|
@@ -143,6 +143,8 @@ const methodMetainfo = /* @__PURE__ */ new Map([
|
|
|
143
143
|
["Page.stopCSSCoverage", { title: "Stop CSS coverage", group: "configuration" }],
|
|
144
144
|
["Page.bringToFront", { title: "Bring to front" }],
|
|
145
145
|
["Page.updateSubscription", { internal: true }],
|
|
146
|
+
["Page.perform", { internal: true }],
|
|
147
|
+
["Page.extract", { internal: true }],
|
|
146
148
|
["Frame.evalOnSelector", { title: "Evaluate", snapshot: true, pausesBeforeAction: true }],
|
|
147
149
|
["Frame.evalOnSelectorAll", { title: "Evaluate", snapshot: true, pausesBeforeAction: true }],
|
|
148
150
|
["Frame.addScriptTag", { title: "Add script tag", snapshot: true, pausesBeforeAction: true }],
|