@push.rocks/smartpuppeteer 2.7.0 → 2.8.1
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/assets/livevideo/background.js +17 -0
- package/assets/livevideo/capture.html +3 -0
- package/assets/livevideo/capture.js +193 -0
- package/assets/livevideo/manifest.json +11 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.livevideo.d.ts +33 -0
- package/dist_ts/classes.livevideo.js +175 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces.livevideo.d.ts +58 -0
- package/dist_ts/interfaces.livevideo.js +45 -0
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.d.ts +11 -0
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.js +137 -16
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.d.ts +5 -0
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.js +1 -1
- package/dist_ts/smartpuppeteer.plugins.d.ts +3 -1
- package/dist_ts/smartpuppeteer.plugins.js +4 -2
- package/package.json +3 -3
- package/readme.md +36 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.livevideo.ts +210 -0
- package/ts/index.ts +1 -0
- package/ts/interfaces.livevideo.ts +103 -0
- package/ts/smartpuppeteer.classes.livebrowsersession.ts +140 -17
- package/ts/smartpuppeteer.interfaces.livebrowser.ts +5 -0
- package/ts/smartpuppeteer.plugins.ts +3 -1
- package/readme.hints.md +0 -20
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Only host-triggered extension actions enter this worker. The private
|
|
2
|
+
// offscreen document retains authority across normal MV3 worker retirement.
|
|
3
|
+
chrome.action.onClicked.addListener(async tab => {
|
|
4
|
+
if (!await chrome.offscreen.hasDocument()) {
|
|
5
|
+
await chrome.offscreen.createDocument({ url: 'capture.html', reasons: ['USER_MEDIA'],
|
|
6
|
+
justification: 'Transmit the host-authorized browser tab as private video.' });
|
|
7
|
+
}
|
|
8
|
+
const request = await chrome.runtime.sendMessage({ type: 'takeCaptureRequest' });
|
|
9
|
+
if (!request) return;
|
|
10
|
+
try {
|
|
11
|
+
const streamId = await chrome.tabCapture.getMediaStreamId({ targetTabId: tab.id });
|
|
12
|
+
await chrome.runtime.sendMessage({ type: 'capture', requestId: request.requestId, streamId });
|
|
13
|
+
} catch (error) {
|
|
14
|
+
await chrome.runtime.sendMessage({ type: 'captureFailure', requestId: request.requestId,
|
|
15
|
+
error: String(error.message ?? error) });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// This private extension document owns native tab capture and WebRTC. Visited
|
|
2
|
+
// pages never receive a reference to its stream, peers, ICE services or controls.
|
|
3
|
+
const peers = new Map();
|
|
4
|
+
const failures = new Map();
|
|
5
|
+
let captureEpoch = 0;
|
|
6
|
+
let pendingCapture;
|
|
7
|
+
let captureResult;
|
|
8
|
+
let source;
|
|
9
|
+
let options;
|
|
10
|
+
let captureFailure;
|
|
11
|
+
|
|
12
|
+
const stopSource = () => {
|
|
13
|
+
for (const track of source?.getTracks() ?? []) track.stop();
|
|
14
|
+
source = undefined;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const closePeer = peerId => {
|
|
18
|
+
failures.delete(peerId);
|
|
19
|
+
const peer = peers.get(peerId);
|
|
20
|
+
if (!peer) return;
|
|
21
|
+
peers.delete(peerId);
|
|
22
|
+
clearInterval(peer.timer);
|
|
23
|
+
clearTimeout(peer.negotiationTimer);
|
|
24
|
+
peer.pc.close();
|
|
25
|
+
peer.track.stop();
|
|
26
|
+
if (![...peers.values()].some(candidate => candidate.visible)) stopSource();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const failPeer = (peer, message) => {
|
|
30
|
+
if (peers.get(peer.id) !== peer) return;
|
|
31
|
+
closePeer(peer.id);
|
|
32
|
+
failures.set(peer.id, message);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const gather = pc => new Promise((resolve, reject) => {
|
|
36
|
+
const finish = error => {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
pc.removeEventListener('icegatheringstatechange', changed);
|
|
39
|
+
pc.removeEventListener('connectionstatechange', changed);
|
|
40
|
+
error ? reject(error) : resolve();
|
|
41
|
+
};
|
|
42
|
+
const changed = () => {
|
|
43
|
+
if (pc.connectionState === 'closed') finish(new Error('Video connection closed during negotiation.'));
|
|
44
|
+
else if (pc.iceGatheringState === 'complete') finish();
|
|
45
|
+
};
|
|
46
|
+
const timer = setTimeout(() => finish(new Error('Video ICE gathering timed out.')), 10000);
|
|
47
|
+
pc.addEventListener('icegatheringstatechange', changed);
|
|
48
|
+
pc.addEventListener('connectionstatechange', changed);
|
|
49
|
+
changed();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const statistics = async peer => {
|
|
53
|
+
const reports = await peer.pc.getStats();
|
|
54
|
+
const result = { connectionState: peer.pc.connectionState, visible: peer.visible, framesEncoded: 0, bytesSent: 0 };
|
|
55
|
+
reports.forEach(report => {
|
|
56
|
+
if (report.type === 'outbound-rtp' && report.kind === 'video') {
|
|
57
|
+
for (const key of ['framesEncoded', 'bytesSent', 'frameWidth', 'frameHeight', 'framesPerSecond',
|
|
58
|
+
'encoderImplementation', 'powerEfficientEncoder', 'qualityLimitationReason']) {
|
|
59
|
+
if (report[key] !== undefined) result[key] = report[key];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (report.type === 'candidate-pair' && report.state === 'succeeded' && report.nominated) {
|
|
63
|
+
result.roundTripTime = report.currentRoundTripTime;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return result;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const adapt = async peer => {
|
|
70
|
+
if (peer.adapting || peer.pc.connectionState !== 'connected' || !peer.visible) return;
|
|
71
|
+
peer.adapting = true;
|
|
72
|
+
try {
|
|
73
|
+
const stats = await statistics(peer);
|
|
74
|
+
if (peers.get(peer.id) !== peer) return;
|
|
75
|
+
const parameters = peer.sender.getParameters();
|
|
76
|
+
const encoding = parameters.encodings[0];
|
|
77
|
+
if (!encoding) return;
|
|
78
|
+
// Congestion control owns bandwidth adaptation. CPU pressure additionally
|
|
79
|
+
// reduces per-viewer resolution; sustained recovery restores sharpness.
|
|
80
|
+
peer.healthySamples = stats.qualityLimitationReason === 'cpu' ? 0 : peer.healthySamples + 1;
|
|
81
|
+
const scale = encoding.scaleResolutionDownBy ?? 1;
|
|
82
|
+
const nextScale = stats.qualityLimitationReason === 'cpu' ? Math.min(4, scale * 1.25)
|
|
83
|
+
: peer.healthySamples >= 5 ? Math.max(1, scale / 1.25) : scale;
|
|
84
|
+
if (nextScale !== scale) {
|
|
85
|
+
encoding.scaleResolutionDownBy = nextScale;
|
|
86
|
+
await peer.sender.setParameters(parameters);
|
|
87
|
+
peer.healthySamples = 0;
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
failPeer(peer, String(error.message ?? error));
|
|
91
|
+
} finally { peer.adapting = false; }
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
globalThis.smartpuppeteerVideo = {
|
|
95
|
+
arm(input) {
|
|
96
|
+
if (peers.size) throw new Error('Retire video peers before changing the captured tab.');
|
|
97
|
+
pendingCapture = { ...input, taken: false };
|
|
98
|
+
captureResult = null;
|
|
99
|
+
},
|
|
100
|
+
result(requestId) { return captureResult?.requestId === requestId ? captureResult : null; },
|
|
101
|
+
async offer(input) {
|
|
102
|
+
if (!source?.active || captureFailure) throw new Error(captureFailure ?? 'Video capture is unavailable.');
|
|
103
|
+
failures.delete(input.peerId);
|
|
104
|
+
if (peers.has(input.peerId)) closePeer(input.peerId);
|
|
105
|
+
if (peers.size >= options.maxViewers) throw new Error('Video viewer capacity reached.');
|
|
106
|
+
const pc = new RTCPeerConnection({ iceServers: options.iceServers, iceTransportPolicy: options.iceTransportPolicy });
|
|
107
|
+
const track = source.getVideoTracks()[0].clone();
|
|
108
|
+
track.contentHint = 'detail';
|
|
109
|
+
const transceiver = pc.addTransceiver(track, { direction: 'sendonly', streams: [new MediaStream([track])],
|
|
110
|
+
sendEncodings: [{ maxBitrate: options.maxBitrate, maxFramerate: options.maxFrameRate, scaleResolutionDownBy: 1 }] });
|
|
111
|
+
const peer = { id: input.peerId, pc, track, sender: transceiver.sender, visible: true, healthySamples: 0 };
|
|
112
|
+
peers.set(peer.id, peer);
|
|
113
|
+
pc.addEventListener('connectionstatechange', () => {
|
|
114
|
+
if (pc.connectionState === 'connected') clearTimeout(peer.negotiationTimer);
|
|
115
|
+
if (pc.connectionState === 'failed') failPeer(peer, 'Video connection failed.');
|
|
116
|
+
});
|
|
117
|
+
try {
|
|
118
|
+
const parameters = peer.sender.getParameters();
|
|
119
|
+
parameters.degradationPreference = 'balanced';
|
|
120
|
+
await peer.sender.setParameters(parameters);
|
|
121
|
+
await pc.setLocalDescription(await pc.createOffer());
|
|
122
|
+
await gather(pc);
|
|
123
|
+
peer.negotiationTimer = setTimeout(() => failPeer(peer, 'Video connection setup timed out.'), 30000);
|
|
124
|
+
peer.timer = setInterval(() => { void adapt(peer); }, 1000);
|
|
125
|
+
return { type: 'offer', sdp: pc.localDescription.sdp };
|
|
126
|
+
} catch (error) { closePeer(peer.id); throw error; }
|
|
127
|
+
},
|
|
128
|
+
async answer(input) {
|
|
129
|
+
const peer = peers.get(input.peerId);
|
|
130
|
+
if (!peer) throw new Error(failures.get(input.peerId) ?? 'Video peer is unavailable.');
|
|
131
|
+
await peer.pc.setRemoteDescription(input.description);
|
|
132
|
+
},
|
|
133
|
+
async stats(input) {
|
|
134
|
+
const peer = peers.get(input.peerId);
|
|
135
|
+
if (!peer) throw new Error(failures.get(input.peerId) ?? 'Video peer is unavailable.');
|
|
136
|
+
return statistics(peer);
|
|
137
|
+
},
|
|
138
|
+
close(input) { closePeer(input.peerId); },
|
|
139
|
+
stop() { pendingCapture = null; captureEpoch++; for (const id of [...peers.keys()]) closePeer(id); failures.clear(); stopSource(); },
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
chrome.runtime.onMessage.addListener((message, sender, respond) => {
|
|
143
|
+
if (sender.id !== chrome.runtime.id) return;
|
|
144
|
+
if (message.type === 'takeCaptureRequest') {
|
|
145
|
+
const request = pendingCapture && !pendingCapture.taken ? pendingCapture : null;
|
|
146
|
+
if (request) request.taken = true;
|
|
147
|
+
respond(request ? { requestId: request.requestId } : null);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (!pendingCapture || message.requestId !== pendingCapture.requestId) return;
|
|
151
|
+
if (message.type === 'captureFailure') {
|
|
152
|
+
captureResult = { requestId: message.requestId, error: message.error };
|
|
153
|
+
respond({});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (message.type !== 'capture') return;
|
|
157
|
+
const request = pendingCapture;
|
|
158
|
+
(async () => {
|
|
159
|
+
try {
|
|
160
|
+
if (peers.size) throw new Error('Retire video peers before changing the captured tab.');
|
|
161
|
+
stopSource();
|
|
162
|
+
captureFailure = undefined;
|
|
163
|
+
options = request.options;
|
|
164
|
+
const epoch = ++captureEpoch;
|
|
165
|
+
let timeout;
|
|
166
|
+
const capture = navigator.mediaDevices.getUserMedia({ audio: false, video: { mandatory: {
|
|
167
|
+
chromeMediaSource: 'tab', chromeMediaSourceId: message.streamId,
|
|
168
|
+
maxWidth: options.maxWidth, maxHeight: options.maxHeight, maxFrameRate: options.maxFrameRate,
|
|
169
|
+
} } }).then(stream => {
|
|
170
|
+
if (epoch !== captureEpoch) {
|
|
171
|
+
stream.getTracks().forEach(track => track.stop());
|
|
172
|
+
throw new Error('Video capture startup was cancelled.');
|
|
173
|
+
}
|
|
174
|
+
return stream;
|
|
175
|
+
});
|
|
176
|
+
try {
|
|
177
|
+
source = await Promise.race([capture, new Promise((_, reject) => {
|
|
178
|
+
timeout = setTimeout(() => { captureEpoch++; reject(new Error('Video capture startup timed out.')); }, 8000);
|
|
179
|
+
})]);
|
|
180
|
+
} finally { clearTimeout(timeout); }
|
|
181
|
+
source.getVideoTracks()[0].addEventListener('ended', () => {
|
|
182
|
+
captureFailure = 'The captured browser tab closed.';
|
|
183
|
+
globalThis.smartpuppeteerVideo.stop();
|
|
184
|
+
});
|
|
185
|
+
captureResult = { requestId: request.requestId, ready: true };
|
|
186
|
+
respond({ ready: true });
|
|
187
|
+
} catch (error) {
|
|
188
|
+
captureResult = { requestId: request.requestId, error: String(error.message ?? error) };
|
|
189
|
+
respond({ error: captureResult.error });
|
|
190
|
+
}
|
|
191
|
+
})();
|
|
192
|
+
return true;
|
|
193
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "SmartPuppeteer private browser video",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"permissions": ["tabCapture", "offscreen", "activeTab"],
|
|
6
|
+
"action": {},
|
|
7
|
+
"background": { "service_worker": "background.js" },
|
|
8
|
+
"content_security_policy": {
|
|
9
|
+
"extension_pages": "default-src 'none'; script-src 'self'; media-src 'self' blob:; connect-src 'none'; object-src 'none'; frame-src 'none'"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartpuppeteer',
|
|
6
|
-
version: '2.
|
|
6
|
+
version: '2.8.1',
|
|
7
7
|
description: 'Provides simplified access to Puppeteer for automation and testing purposes.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSw0QkFBNEI7SUFDbEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhFQUE4RTtDQUM1RixDQUFBIn0=
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as plugins from './smartpuppeteer.plugins.js';
|
|
2
|
+
import { type ILiveVideoOptions, type ILiveVideoSource, type ILiveVideoOffer, type ILiveVideoDescription, type ILiveVideoStatistics, type ILiveVideoAcceleration } from './interfaces.livevideo.js';
|
|
3
|
+
/** Private extension bridge; never evaluates in a visited page or exposes CDP. */
|
|
4
|
+
export declare class LiveBrowserVideo {
|
|
5
|
+
private browser;
|
|
6
|
+
readonly options: Required<ILiveVideoOptions>;
|
|
7
|
+
private extensionId?;
|
|
8
|
+
private capturePage?;
|
|
9
|
+
private captureSource?;
|
|
10
|
+
private readonly peers;
|
|
11
|
+
private operation;
|
|
12
|
+
private closed;
|
|
13
|
+
private pendingOperations;
|
|
14
|
+
private acceleration?;
|
|
15
|
+
constructor(browser: plugins.puppeteer.Browser, options: ILiveVideoOptions);
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
getAcceleration(): ILiveVideoAcceleration | undefined;
|
|
18
|
+
ownsTarget(target: plugins.puppeteer.Target): boolean;
|
|
19
|
+
hasPeer(peerId: string): boolean;
|
|
20
|
+
open(peerId: string, page: plugins.puppeteer.Page, source: ILiveVideoSource, signal?: AbortSignal): Promise<ILiveVideoOffer>;
|
|
21
|
+
answer(peerId: string, negotiationId: string, description: ILiveVideoDescription): Promise<void>;
|
|
22
|
+
getStatistics(peerId: string): Promise<ILiveVideoStatistics>;
|
|
23
|
+
close(peerId: string): Promise<void>;
|
|
24
|
+
/** Retires media before changing tab/viewport identity. Control stays independent. */
|
|
25
|
+
invalidate(): Promise<void>;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
private enqueue;
|
|
28
|
+
private sameSource;
|
|
29
|
+
private requirePeer;
|
|
30
|
+
private closeInternal;
|
|
31
|
+
private stopCapture;
|
|
32
|
+
private capture;
|
|
33
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as plugins from './smartpuppeteer.plugins.js';
|
|
2
|
+
import { normalizeLiveVideoOptions, validateLiveVideoDescription, } from './interfaces.livevideo.js';
|
|
3
|
+
/** Private extension bridge; never evaluates in a visited page or exposes CDP. */
|
|
4
|
+
export class LiveBrowserVideo {
|
|
5
|
+
constructor(browser, options) {
|
|
6
|
+
this.browser = browser;
|
|
7
|
+
this.peers = new Map();
|
|
8
|
+
this.operation = Promise.resolve();
|
|
9
|
+
this.closed = false;
|
|
10
|
+
this.pendingOperations = 0;
|
|
11
|
+
this.options = normalizeLiveVideoOptions(options);
|
|
12
|
+
}
|
|
13
|
+
async start() {
|
|
14
|
+
this.extensionId = await this.browser.installExtension(plugins.url.fileURLToPath(new URL('../assets/livevideo/', import.meta.url)));
|
|
15
|
+
const session = await this.browser.target().createCDPSession();
|
|
16
|
+
try {
|
|
17
|
+
const { gpu } = await session.send('SystemInfo.getInfo');
|
|
18
|
+
const attributes = gpu.auxAttributes;
|
|
19
|
+
const features = gpu.featureStatus;
|
|
20
|
+
this.acceleration = {
|
|
21
|
+
renderer: String(attributes?.glRenderer ?? 'unknown'),
|
|
22
|
+
compositing: String(features?.gpu_compositing ?? 'unknown'),
|
|
23
|
+
videoEncoding: String(features?.video_encode ?? 'unknown'),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
await session.detach();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
getAcceleration() {
|
|
31
|
+
return this.acceleration ? { ...this.acceleration } : undefined;
|
|
32
|
+
}
|
|
33
|
+
ownsTarget(target) {
|
|
34
|
+
return !!this.extensionId && target.url().startsWith(`chrome-extension://${this.extensionId}/`);
|
|
35
|
+
}
|
|
36
|
+
hasPeer(peerId) { return this.peers.has(peerId); }
|
|
37
|
+
open(peerId, page, source, signal) {
|
|
38
|
+
return this.enqueue(async () => {
|
|
39
|
+
signal?.throwIfAborted();
|
|
40
|
+
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(peerId))
|
|
41
|
+
throw new Error('Invalid video peer identity.');
|
|
42
|
+
if (this.peers.has(peerId))
|
|
43
|
+
await this.closeInternal(peerId);
|
|
44
|
+
if (this.peers.size >= this.options.maxViewers)
|
|
45
|
+
throw new Error('Video viewer capacity reached.');
|
|
46
|
+
try {
|
|
47
|
+
if (!this.sameSource(source))
|
|
48
|
+
await this.stopCapture();
|
|
49
|
+
if (!this.captureSource)
|
|
50
|
+
await this.capture(page, source);
|
|
51
|
+
signal?.throwIfAborted();
|
|
52
|
+
const description = await this.capturePage.evaluate(async (input) => (globalThis.smartpuppeteerVideo.offer(input)), { peerId });
|
|
53
|
+
validateLiveVideoDescription(description, 'offer');
|
|
54
|
+
signal?.throwIfAborted();
|
|
55
|
+
const negotiationId = plugins.crypto.randomUUID();
|
|
56
|
+
this.peers.set(peerId, negotiationId);
|
|
57
|
+
return { peerId, negotiationId, source: structuredClone(source), description,
|
|
58
|
+
iceServers: structuredClone(this.options.iceServers), iceTransportPolicy: this.options.iceTransportPolicy };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
await this.closeInternal(peerId);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
answer(peerId, negotiationId, description) {
|
|
67
|
+
validateLiveVideoDescription(description, 'answer');
|
|
68
|
+
return this.enqueue(async () => {
|
|
69
|
+
this.requirePeer(peerId);
|
|
70
|
+
if (this.peers.get(peerId) !== negotiationId)
|
|
71
|
+
throw new Error('Video negotiation is stale.');
|
|
72
|
+
await this.capturePage.evaluate(async (input) => (globalThis.smartpuppeteerVideo.answer(input)), { peerId, description });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
getStatistics(peerId) {
|
|
76
|
+
return this.enqueue(async () => {
|
|
77
|
+
this.requirePeer(peerId);
|
|
78
|
+
return this.capturePage.evaluate(async (input) => (globalThis.smartpuppeteerVideo.stats(input)), { peerId });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
close(peerId) { return this.enqueue(() => this.closeInternal(peerId)); }
|
|
82
|
+
/** Retires media before changing tab/viewport identity. Control stays independent. */
|
|
83
|
+
invalidate() { return this.enqueue(() => this.stopCapture()); }
|
|
84
|
+
async stop() {
|
|
85
|
+
if (this.closed)
|
|
86
|
+
return;
|
|
87
|
+
this.closed = true;
|
|
88
|
+
await this.operation;
|
|
89
|
+
await this.stopCapture();
|
|
90
|
+
this.capturePage = undefined;
|
|
91
|
+
// The extension is process-local and the owning browser closes immediately
|
|
92
|
+
// afterward; no extension or media profile is installed into a user's browser.
|
|
93
|
+
}
|
|
94
|
+
enqueue(operation) {
|
|
95
|
+
if (this.closed)
|
|
96
|
+
return Promise.reject(new Error('Browser video is closed.'));
|
|
97
|
+
if (this.pendingOperations >= 128)
|
|
98
|
+
return Promise.reject(new Error('Browser video operation capacity reached.'));
|
|
99
|
+
this.pendingOperations++;
|
|
100
|
+
const task = this.operation.then(operation).finally(() => { this.pendingOperations--; });
|
|
101
|
+
this.operation = task.then(() => undefined, () => undefined);
|
|
102
|
+
return task;
|
|
103
|
+
}
|
|
104
|
+
sameSource(source) {
|
|
105
|
+
return this.captureSource?.tabId === source.tabId && this.captureSource.generation === source.generation
|
|
106
|
+
&& this.captureSource.viewportRevision === source.viewportRevision;
|
|
107
|
+
}
|
|
108
|
+
requirePeer(peerId) {
|
|
109
|
+
if (!this.peers.has(peerId) || !this.capturePage || this.capturePage.isClosed()) {
|
|
110
|
+
throw new Error('Video peer is unavailable.');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async closeInternal(peerId) {
|
|
114
|
+
if (this.capturePage && !this.capturePage.isClosed()) {
|
|
115
|
+
await this.capturePage.evaluate(input => (globalThis.smartpuppeteerVideo.close(input)), { peerId });
|
|
116
|
+
}
|
|
117
|
+
this.peers.delete(peerId);
|
|
118
|
+
if (!this.peers.size)
|
|
119
|
+
await this.stopCapture();
|
|
120
|
+
}
|
|
121
|
+
async stopCapture() {
|
|
122
|
+
if (this.capturePage && !this.capturePage.isClosed()) {
|
|
123
|
+
await this.capturePage.evaluate(() => (globalThis.smartpuppeteerVideo.stop()));
|
|
124
|
+
}
|
|
125
|
+
this.peers.clear();
|
|
126
|
+
this.captureSource = undefined;
|
|
127
|
+
}
|
|
128
|
+
async capture(page, source) {
|
|
129
|
+
if (!this.extensionId)
|
|
130
|
+
throw new Error('Private browser video extension is not initialized.');
|
|
131
|
+
const extension = (await this.browser.extensions()).get(this.extensionId);
|
|
132
|
+
if (!extension)
|
|
133
|
+
throw new Error('Private browser video extension is unavailable.');
|
|
134
|
+
// The action wakes MV3 workers. Capture authority lives in the offscreen
|
|
135
|
+
// document so ordinary worker retirement cannot strand a saved CDP context.
|
|
136
|
+
if (!this.capturePage || this.capturePage.isClosed()) {
|
|
137
|
+
await page.triggerExtensionAction(extension);
|
|
138
|
+
const target = await this.browser.waitForTarget(candidate => (candidate.url() === `chrome-extension://${this.extensionId}/capture.html`), { timeout: 10_000 });
|
|
139
|
+
this.capturePage = await target.asPage();
|
|
140
|
+
await this.capturePage.waitForFunction(() => (!!globalThis.smartpuppeteerVideo), { timeout: 10_000 });
|
|
141
|
+
}
|
|
142
|
+
const requestId = plugins.crypto.randomUUID();
|
|
143
|
+
try {
|
|
144
|
+
await this.capturePage.evaluate(input => (globalThis.smartpuppeteerVideo.arm(input)), { requestId, options: { ...this.options,
|
|
145
|
+
maxWidth: Math.min(this.options.maxWidth, Math.round(source.viewport.width * source.viewport.deviceScaleFactor)),
|
|
146
|
+
maxHeight: Math.min(this.options.maxHeight, Math.round(source.viewport.height * source.viewport.deviceScaleFactor)),
|
|
147
|
+
} });
|
|
148
|
+
await page.triggerExtensionAction(extension);
|
|
149
|
+
const result = await this.capturePage.evaluate(async (expected) => {
|
|
150
|
+
const api = globalThis.smartpuppeteerVideo;
|
|
151
|
+
const deadline = Date.now() + 10_000;
|
|
152
|
+
while (Date.now() < deadline) {
|
|
153
|
+
const result = api.result(expected);
|
|
154
|
+
if (result)
|
|
155
|
+
return result;
|
|
156
|
+
await new Promise(resolve => setTimeout(resolve, 25));
|
|
157
|
+
}
|
|
158
|
+
throw new Error('Private browser video capture startup timed out.');
|
|
159
|
+
}, requestId);
|
|
160
|
+
if (result.error || !result.ready)
|
|
161
|
+
throw new Error(result.error ?? 'Browser video capture failed.');
|
|
162
|
+
this.captureSource = structuredClone(source);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
try {
|
|
166
|
+
await this.stopCapture();
|
|
167
|
+
}
|
|
168
|
+
catch (cleanupError) {
|
|
169
|
+
throw new AggregateError([error, cleanupError], 'Browser video capture and cleanup failed.');
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5saXZldmlkZW8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmxpdmV2aWRlby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDZCQUE2QixDQUFDO0FBQ3ZELE9BQU8sRUFDTCx5QkFBeUIsRUFBRSw0QkFBNEIsR0FHeEQsTUFBTSwyQkFBMkIsQ0FBQztBQVluQyxrRkFBa0Y7QUFDbEYsTUFBTSxPQUFPLGdCQUFnQjtJQVczQixZQUFvQixPQUFrQyxFQUFFLE9BQTBCO1FBQTlELFlBQU8sR0FBUCxPQUFPLENBQTJCO1FBTnJDLFVBQUssR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUMzQyxjQUFTLEdBQXFCLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNoRCxXQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ2Ysc0JBQWlCLEdBQUcsQ0FBQyxDQUFDO1FBSTVCLElBQUksQ0FBQyxPQUFPLEdBQUcseUJBQXlCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVNLEtBQUssQ0FBQyxLQUFLO1FBQ2hCLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQzVFLENBQUM7UUFDRixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUMvRCxJQUFJLENBQUM7WUFDSCxNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDekQsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLGFBQW9ELENBQUM7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
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export * from './smartpuppeteer.classes.smartpuppeteer.js';
|
|
|
2
2
|
export * from './smartpuppeteer.classes.incognitobrowser.js';
|
|
3
3
|
export * from './smartpuppeteer.interfaces.livebrowser.js';
|
|
4
4
|
export * from './smartpuppeteer.classes.livebrowsersession.js';
|
|
5
|
+
export * from './interfaces.livevideo.js';
|
|
5
6
|
import { puppeteer } from './smartpuppeteer.plugins.js';
|
|
6
7
|
export { puppeteer };
|
package/dist_ts/index.js
CHANGED
|
@@ -3,7 +3,8 @@ export * from './smartpuppeteer.classes.smartpuppeteer.js';
|
|
|
3
3
|
export * from './smartpuppeteer.classes.incognitobrowser.js';
|
|
4
4
|
export * from './smartpuppeteer.interfaces.livebrowser.js';
|
|
5
5
|
export * from './smartpuppeteer.classes.livebrowsersession.js';
|
|
6
|
+
export * from './interfaces.livevideo.js';
|
|
6
7
|
// direct exports
|
|
7
8
|
import { puppeteer } from './smartpuppeteer.plugins.js';
|
|
8
9
|
export { puppeteer };
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxpQkFBaUI7QUFFakIsY0FBYyw0Q0FBNEMsQ0FBQztBQUMzRCxjQUFjLDhDQUE4QyxDQUFDO0FBQzdELGNBQWMsNENBQTRDLENBQUM7QUFDM0QsY0FBYyxnREFBZ0QsQ0FBQztBQUMvRCxjQUFjLDJCQUEyQixDQUFDO0FBRTFDLGlCQUFpQjtBQUNqQixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxDQUFDIn0=
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Host-provided ICE services. Never accept relay configuration from a visited page. */
|
|
2
|
+
export interface ILiveVideoIceServer {
|
|
3
|
+
urls: string | string[];
|
|
4
|
+
username?: string;
|
|
5
|
+
credential?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ILiveVideoOptions {
|
|
8
|
+
iceServers?: ILiveVideoIceServer[];
|
|
9
|
+
iceTransportPolicy?: 'all' | 'relay';
|
|
10
|
+
maxViewers?: number;
|
|
11
|
+
maxWidth?: number;
|
|
12
|
+
maxHeight?: number;
|
|
13
|
+
maxFrameRate?: number;
|
|
14
|
+
maxBitrate?: number;
|
|
15
|
+
gpu?: 'auto' | 'disabled';
|
|
16
|
+
}
|
|
17
|
+
export interface ILiveVideoSource {
|
|
18
|
+
tabId: string;
|
|
19
|
+
generation: number;
|
|
20
|
+
viewportRevision: number;
|
|
21
|
+
viewport: {
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
deviceScaleFactor: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface ILiveVideoDescription {
|
|
28
|
+
type: 'offer' | 'answer';
|
|
29
|
+
sdp: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ILiveVideoOffer {
|
|
32
|
+
peerId: string;
|
|
33
|
+
negotiationId: string;
|
|
34
|
+
source: ILiveVideoSource;
|
|
35
|
+
description: ILiveVideoDescription;
|
|
36
|
+
iceServers: ILiveVideoIceServer[];
|
|
37
|
+
iceTransportPolicy: 'all' | 'relay';
|
|
38
|
+
}
|
|
39
|
+
export interface ILiveVideoStatistics {
|
|
40
|
+
connectionState: string;
|
|
41
|
+
visible: boolean;
|
|
42
|
+
framesEncoded: number;
|
|
43
|
+
bytesSent: number;
|
|
44
|
+
frameWidth?: number;
|
|
45
|
+
frameHeight?: number;
|
|
46
|
+
framesPerSecond?: number;
|
|
47
|
+
encoderImplementation?: string;
|
|
48
|
+
powerEfficientEncoder?: boolean;
|
|
49
|
+
qualityLimitationReason?: string;
|
|
50
|
+
roundTripTime?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ILiveVideoAcceleration {
|
|
53
|
+
renderer: string;
|
|
54
|
+
compositing: string;
|
|
55
|
+
videoEncoding: string;
|
|
56
|
+
}
|
|
57
|
+
export declare const normalizeLiveVideoOptions: (input: ILiveVideoOptions) => Required<ILiveVideoOptions>;
|
|
58
|
+
export declare const validateLiveVideoDescription: (description: ILiveVideoDescription, type: "offer" | "answer") => void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const normalizeLiveVideoOptions = (input) => {
|
|
2
|
+
const integer = (value, fallback, min, max) => {
|
|
3
|
+
const result = value ?? fallback;
|
|
4
|
+
if (!Number.isSafeInteger(result) || result < min || result > max) {
|
|
5
|
+
throw new Error(`Video option must be an integer between ${min} and ${max}.`);
|
|
6
|
+
}
|
|
7
|
+
return result;
|
|
8
|
+
};
|
|
9
|
+
if (input.gpu !== undefined && !['auto', 'disabled'].includes(input.gpu))
|
|
10
|
+
throw new Error('Invalid video GPU mode.');
|
|
11
|
+
if (input.iceTransportPolicy !== undefined && !['all', 'relay'].includes(input.iceTransportPolicy)) {
|
|
12
|
+
throw new Error('Invalid video ICE transport policy.');
|
|
13
|
+
}
|
|
14
|
+
if (input.iceServers !== undefined && (!Array.isArray(input.iceServers) || input.iceServers.length > 8)) {
|
|
15
|
+
throw new Error('Video supports at most eight ICE services.');
|
|
16
|
+
}
|
|
17
|
+
const iceServers = (input.iceServers ?? []).map(server => {
|
|
18
|
+
const urls = typeof server.urls === 'string' ? [server.urls] : server.urls;
|
|
19
|
+
if (!Array.isArray(urls) || !urls.length || urls.length > 8 || urls.some(url => (typeof url !== 'string' || url.length > 2048 || !/^(stun|stuns|turn|turns):[^\s@]+$/.test(url))))
|
|
20
|
+
throw new Error('Invalid video ICE service URL.');
|
|
21
|
+
for (const value of [server.username, server.credential]) {
|
|
22
|
+
if (value !== undefined && (typeof value !== 'string' || value.length > 2048))
|
|
23
|
+
throw new Error('Invalid video ICE credentials.');
|
|
24
|
+
}
|
|
25
|
+
return { urls: [...urls], ...(server.username === undefined ? {} : { username: server.username }),
|
|
26
|
+
...(server.credential === undefined ? {} : { credential: server.credential }) };
|
|
27
|
+
});
|
|
28
|
+
if (input.iceTransportPolicy === 'relay' && !iceServers.some(server => server.urls.some(url => /^turns?:/.test(url)))) {
|
|
29
|
+
throw new Error('Relay-only video requires a TURN service.');
|
|
30
|
+
}
|
|
31
|
+
return { iceServers, iceTransportPolicy: input.iceTransportPolicy ?? 'all',
|
|
32
|
+
maxViewers: integer(input.maxViewers, 8, 1, 32), maxWidth: integer(input.maxWidth, 2560, 320, 4096),
|
|
33
|
+
maxHeight: integer(input.maxHeight, 1600, 240, 4096), maxFrameRate: integer(input.maxFrameRate, 30, 1, 60),
|
|
34
|
+
maxBitrate: integer(input.maxBitrate, 8_000_000, 100_000, 50_000_000), gpu: input.gpu ?? 'auto' };
|
|
35
|
+
};
|
|
36
|
+
export const validateLiveVideoDescription = (description, type) => {
|
|
37
|
+
if (!description || description.type !== type || typeof description.sdp !== 'string'
|
|
38
|
+
|| description.sdp.length > 48 * 1024 || !description.sdp.startsWith('v=0\r\n')) {
|
|
39
|
+
throw new Error('Invalid video session description.');
|
|
40
|
+
}
|
|
41
|
+
if ((description.sdp.match(/^m=/gm) ?? []).length !== 1 || !/^m=video /m.test(description.sdp)) {
|
|
42
|
+
throw new Error('Video negotiation accepts only a video media section.');
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5saXZldmlkZW8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbnRlcmZhY2VzLmxpdmV2aWRlby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUEyREEsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxLQUF3QixFQUErQixFQUFFO0lBQ2pHLE1BQU0sT0FBTyxHQUFHLENBQUMsS0FBeUIsRUFBRSxRQUFnQixFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQVUsRUFBRTtRQUNoRyxNQUFNLE1BQU0sR0FBRyxLQUFLLElBQUksUUFBUSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sR0FBRyxHQUFHLElBQUksTUFBTSxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQ2xFLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLEdBQUcsUUFBUSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ2hGLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7SUFDRixJQUFJLEtBQUssQ0FBQyxHQUFHLEtBQUssU0FBUyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFDckgsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssU0FBUyxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7UUFDbkcsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFDRCxJQUFJLEtBQUssQ0FBQyxVQUFVLEtBQUssU0FBUyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUss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
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ILiveVideoDescription, type ILiveVideoOffer, type ILiveVideoStatistics } from './interfaces.livevideo.js';
|
|
1
2
|
import type { ILiveBrowserClickOptions, ILiveBrowserCreateTabOptions, ILiveBrowserEvaluateOptions, ILiveBrowserFillOptions, ILiveBrowserFrameAcknowledgement, ILiveBrowserFrameAcknowledgementRequest, ILiveBrowserFrameIdentity, ILiveBrowserInsertTextInput, ILiveBrowserKeyInput, ILiveBrowserMouseInput, ILiveBrowserNavigateOptions, ILiveBrowserNavigationOptions, ILiveBrowserObservation, ILiveBrowserObserveOptions, ILiveBrowserOperationOptions, ILiveBrowserPressOptions, ILiveBrowserProcessState, ILiveBrowserScreencastUpdateOptions, ILiveBrowserSessionOptions, ILiveBrowserSnapshot, ILiveBrowserSnapshotOptions, ILiveBrowserState, ILiveBrowserTabState, ILiveBrowserTerminationOptions, ILiveBrowserTerminationResult, ILiveBrowserViewport, ILiveBrowserWheelInput, TLiveBrowserEventListener, TLiveBrowserJsonValue } from './smartpuppeteer.interfaces.livebrowser.js';
|
|
2
3
|
export declare class LiveBrowserSession {
|
|
3
4
|
private readonly options;
|
|
@@ -8,6 +9,8 @@ export declare class LiveBrowserSession {
|
|
|
8
9
|
private readonly cdpFramesBeingAcknowledged;
|
|
9
10
|
private readonly maxOutstandingFrames;
|
|
10
11
|
private browser?;
|
|
12
|
+
private video?;
|
|
13
|
+
private frameCaptureEnabled;
|
|
11
14
|
private browserContext?;
|
|
12
15
|
private browserLifetimeController?;
|
|
13
16
|
private browserDisconnectedListener?;
|
|
@@ -56,6 +59,12 @@ export declare class LiveBrowserSession {
|
|
|
56
59
|
stop(): Promise<void>;
|
|
57
60
|
acknowledgeFrame(acknowledgement: ILiveBrowserFrameAcknowledgementRequest): Promise<ILiveBrowserFrameAcknowledgement>;
|
|
58
61
|
refreshScreencast(operationOptions?: ILiveBrowserOperationOptions): Promise<ILiveBrowserFrameIdentity>;
|
|
62
|
+
private videoLaunchArguments;
|
|
63
|
+
setFrameCaptureEnabled(enabled: boolean, options?: ILiveBrowserOperationOptions): Promise<void>;
|
|
64
|
+
openVideoPeer(peerId: string, options?: ILiveBrowserOperationOptions): Promise<ILiveVideoOffer>;
|
|
65
|
+
answerVideoPeer(peerId: string, negotiationId: string, description: ILiveVideoDescription, options?: ILiveBrowserOperationOptions): Promise<void>;
|
|
66
|
+
closeVideoPeer(peerId: string): Promise<void>;
|
|
67
|
+
getVideoStatistics(peerId: string): Promise<ILiveVideoStatistics>;
|
|
59
68
|
updateScreencastOptions(optionsArg: ILiveBrowserScreencastUpdateOptions, operationOptions?: ILiveBrowserOperationOptions): Promise<ILiveBrowserFrameIdentity | null>;
|
|
60
69
|
private restartActiveScreencast;
|
|
61
70
|
private abandonScreencastRestart;
|
|
@@ -105,6 +114,7 @@ export declare class LiveBrowserSession {
|
|
|
105
114
|
private configureProxySecuritySession;
|
|
106
115
|
private verifyProxySecuritySessionDetached;
|
|
107
116
|
private waitForProxySecurityTargetCoverage;
|
|
117
|
+
private reconcileClosedProxyRequest;
|
|
108
118
|
private removeProxySecuritySession;
|
|
109
119
|
private detachOwnedProxySecuritySession;
|
|
110
120
|
private forgetOwnedProxySecuritySession;
|
|
@@ -141,6 +151,7 @@ export declare class LiveBrowserSession {
|
|
|
141
151
|
private waitForScreencastAuthority;
|
|
142
152
|
private invalidateScreencast;
|
|
143
153
|
private waitForScreencastFrame;
|
|
154
|
+
private screencastParameters;
|
|
144
155
|
private stopScreencast;
|
|
145
156
|
private handleScreencastFrame;
|
|
146
157
|
private acknowledgeCdpFrame;
|