@push.rocks/smartpuppeteer 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.d.ts +4 -0
- package/dist_ts/smartpuppeteer.classes.livebrowsersession.js +81 -23
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.d.ts +3 -0
- package/dist_ts/smartpuppeteer.interfaces.livebrowser.js +3 -2
- package/package.json +1 -1
- package/readme.hints.md +1 -1
- package/readme.md +5 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/smartpuppeteer.classes.livebrowsersession.ts +104 -29
- package/ts/smartpuppeteer.interfaces.livebrowser.ts +4 -0
|
@@ -3,6 +3,8 @@ export type TLiveBrowserStatus = 'stopped' | 'starting' | 'running' | 'stopping'
|
|
|
3
3
|
export type TLiveBrowserImageFormat = 'jpeg' | 'png';
|
|
4
4
|
export type TLiveBrowserTabStatus = 'open' | 'crashed';
|
|
5
5
|
export type TLiveBrowserWaitUntil = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';
|
|
6
|
+
export declare const liveBrowserDefaultMaxOutstandingFrames = 3;
|
|
7
|
+
export declare const liveBrowserMaxOutstandingFrames = 64;
|
|
6
8
|
export interface ILiveBrowserViewport {
|
|
7
9
|
width: number;
|
|
8
10
|
height: number;
|
|
@@ -14,6 +16,7 @@ export interface ILiveBrowserScreencastOptions {
|
|
|
14
16
|
maxWidth?: number;
|
|
15
17
|
maxHeight?: number;
|
|
16
18
|
everyNthFrame?: number;
|
|
19
|
+
maxOutstandingFrames?: number;
|
|
17
20
|
}
|
|
18
21
|
export interface ILiveBrowserSecurityOptions {
|
|
19
22
|
denyDownloads?: boolean;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
1
|
+
export const liveBrowserDefaultMaxOutstandingFrames = 3;
|
|
2
|
+
export const liveBrowserMaxOutstandingFrames = 64;
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwdXBwZXRlZXIuaW50ZXJmYWNlcy5saXZlYnJvd3Nlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0cHVwcGV0ZWVyLmludGVyZmFjZXMubGl2ZWJyb3dzZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsTUFBTSxDQUFDLE1BQU0sc0NBQXNDLEdBQUcsQ0FBQyxDQUFDO0FBQ3hELE1BQU0sQ0FBQyxNQUFNLCtCQUErQixHQUFHLEVBQUUsQ0FBQyJ9
|
package/package.json
CHANGED
package/readme.hints.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- `getEnvAwareBrowserInstance()` is the only Chromium launch path. Merge caller arguments before adding environment-required sandbox arguments, retain the pipe default, and do not run executable discovery when the caller selected a browser, channel, or executable.
|
|
4
4
|
- `LiveBrowserSession` uses the browser's default context so all tabs and popups share one profile. Omitting both `launchOptions.userDataDir` and a `--user-data-dir` argument intentionally relies on Puppeteer's ephemeral profile lifecycle.
|
|
5
5
|
- CDP is private to the live runtime. Public contracts contain transport-neutral values and `Uint8Array` image data, never `CDPSession`, raw CDP frame IDs, or base64 image strings.
|
|
6
|
-
- Every published screencast frame has one private sequence-to-CDP acknowledgement entry. Public acknowledgement requires matching tab ID, sequence, generation, and viewport revision.
|
|
6
|
+
- Every published screencast frame has one private sequence-to-CDP acknowledgement entry. Public acknowledgement requires matching tab ID, sequence, generation, and viewport revision. `screencast.maxOutstandingFrames` bounds those entries independently of any application transport window; overflow retires oldest-first. Drops and all stream invalidation paths must issue each CDP acknowledgement at most once and await in-flight acknowledgements before detaching the CDP session.
|
|
7
7
|
- Activation, viewport changes, navigation, tab closure, snapshots, observations, semantic actions, and shutdown share one bounded operation scheduler. Raw input and frame acknowledgement remain direct, but must validate active tab, generation, and viewport revision. Repeated internal navigation/load state updates are coalesced per tab, and shutdown cancels queued work.
|
|
8
8
|
- Retain the scheduler-owned launch `AbortController` for the full browser lifetime. Shutdown aborts both the active operation and Chromium itself so a non-signal-aware Puppeteer command or disabled protocol timeout cannot retain the browser ahead of queued cleanup.
|
|
9
9
|
- Viewport revision starts at 1 and advances only after `Page.setViewport()` succeeds. Stop and flush the active screencast before applying a viewport or navigation mutation, then restart it with a new generation.
|
package/readme.md
CHANGED
|
@@ -120,6 +120,8 @@ const session = new LiveBrowserSession({
|
|
|
120
120
|
quality: 80,
|
|
121
121
|
maxWidth: 1280,
|
|
122
122
|
maxHeight: 720,
|
|
123
|
+
everyNthFrame: 1,
|
|
124
|
+
maxOutstandingFrames: 3,
|
|
123
125
|
},
|
|
124
126
|
launchOptions: {
|
|
125
127
|
headless: true,
|
|
@@ -168,7 +170,9 @@ try {
|
|
|
168
170
|
}
|
|
169
171
|
```
|
|
170
172
|
|
|
171
|
-
Only the active tab is streamed. Frames carry a session-monotonic sequence, tab/CDP generation, viewport revision, viewport, MIME type, encoded dimensions, screencast metadata, and binary `Uint8Array` data. Every delivered frame must be acknowledged with all four identity fields. A delivered frame remains pending until it is acknowledged, dropped, or retired by the runtime; mismatched, duplicate, stale, retired, or operationally failed acknowledgements return `{ accepted: false }`. Operational acknowledgement failures also emit an `error` event whose code is `frame_acknowledgement_failed`.
|
|
173
|
+
Only the active tab is streamed. Frames carry a session-monotonic sequence, tab/CDP generation, viewport revision, viewport, MIME type, encoded dimensions, screencast metadata, and binary `Uint8Array` data. Every delivered frame must be acknowledged with all four identity fields. A delivered frame remains pending until it is acknowledged, dropped, or retired by the runtime; mismatched, duplicate, stale, retired, or operationally failed acknowledgements return `{ accepted: false }`. Operational acknowledgement failures also emit an `error` event whose code is `frame_acknowledgement_failed`. `screencast.maxOutstandingFrames` is an integer from 1 through `liveBrowserMaxOutstandingFrames` (64) and defaults to `liveBrowserDefaultMaxOutstandingFrames` (3). At capacity, SmartPuppeteer retires and CDP-acknowledges the oldest pending frame before publishing the next one. Tab switches, navigation, resize, page cleanup, disconnect, and shutdown also retire pending frames and await their single CDP acknowledgement attempt before detaching the screencast session.
|
|
174
|
+
|
|
175
|
+
The SmartPuppeteer outstanding-frame bound covers only the private frame-to-`Page.screencastFrameAck` lifecycle. It is not a binary transport window, and `acknowledgeFrame()` is not an application transport acknowledgement. A higher-level runtime must maintain and bound its application frame window separately. Screencast `format` accepts `jpeg` or `png`, `quality` accepts integers from 0 through 100, `maxWidth` and `maxHeight` accept integers from 1 through 4096 subject to an 8,294,400-pixel combined ceiling, and `everyNthFrame` accepts integers from 1 through 100.
|
|
172
176
|
|
|
173
177
|
The live API includes:
|
|
174
178
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { getEnvAwareBrowserInstance } from './smartpuppeteer.classes.smartpuppeteer.js';
|
|
2
|
+
import {
|
|
3
|
+
liveBrowserDefaultMaxOutstandingFrames,
|
|
4
|
+
liveBrowserMaxOutstandingFrames,
|
|
5
|
+
} from './smartpuppeteer.interfaces.livebrowser.js';
|
|
2
6
|
import {
|
|
3
7
|
delay,
|
|
4
8
|
type IOwnedProcessIdentity,
|
|
@@ -59,7 +63,7 @@ const maxSelectorLength = 4096;
|
|
|
59
63
|
const maxTextLength = 32768;
|
|
60
64
|
const maxUrlLength = 16384;
|
|
61
65
|
const maxTimeoutMs = 60000;
|
|
62
|
-
const
|
|
66
|
+
const frameAcknowledgementTimeoutMs = 5000;
|
|
63
67
|
const maxQueuedPublicOperations = 64;
|
|
64
68
|
const maxQueuedInternalOperations = 128;
|
|
65
69
|
const maxEvaluationScriptBytes = 262144;
|
|
@@ -143,12 +147,17 @@ interface IPrivateLiveBrowserTab {
|
|
|
143
147
|
removeListeners: Array<() => void>;
|
|
144
148
|
}
|
|
145
149
|
|
|
146
|
-
interface
|
|
150
|
+
interface ICdpScreencastFrame {
|
|
147
151
|
tabId: string;
|
|
148
152
|
generation: number;
|
|
149
153
|
viewportRevision: number;
|
|
150
154
|
cdpSessionId: number;
|
|
151
155
|
cdpSession: plugins.puppeteer.CDPSession;
|
|
156
|
+
acknowledgementPromise?: Promise<boolean>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
interface IOutstandingFrame extends ICdpScreencastFrame {
|
|
160
|
+
sequence: number;
|
|
152
161
|
}
|
|
153
162
|
|
|
154
163
|
interface IImageDimensions {
|
|
@@ -367,6 +376,8 @@ export class LiveBrowserSession {
|
|
|
367
376
|
private readonly tabs = new Map<string, IPrivateLiveBrowserTab>();
|
|
368
377
|
private readonly tabIdsByPage = new WeakMap<plugins.puppeteer.Page, string>();
|
|
369
378
|
private readonly outstandingFrames = new Map<number, IOutstandingFrame>();
|
|
379
|
+
private readonly cdpFramesBeingAcknowledged = new Set<ICdpScreencastFrame>();
|
|
380
|
+
private readonly maxOutstandingFrames: number;
|
|
370
381
|
|
|
371
382
|
private browser?: plugins.puppeteer.Browser;
|
|
372
383
|
private browserContext?: plugins.puppeteer.BrowserContext;
|
|
@@ -392,6 +403,7 @@ export class LiveBrowserSession {
|
|
|
392
403
|
private admittedPublicOperations = 0;
|
|
393
404
|
private admittedInternalOperations = 0;
|
|
394
405
|
private shutdownPromise?: Promise<void>;
|
|
406
|
+
private shutdownFrameDrainPromise?: Promise<void>;
|
|
395
407
|
private status: 'stopped' | 'starting' | 'running' | 'stopping' = 'stopped';
|
|
396
408
|
private activeTabId: string | null = null;
|
|
397
409
|
private viewport: ILiveBrowserViewport = { ...defaultViewport };
|
|
@@ -418,6 +430,16 @@ export class LiveBrowserSession {
|
|
|
418
430
|
if (optionsArg.launchOptions && 'signal' in optionsArg.launchOptions) {
|
|
419
431
|
throw new Error('LiveBrowserSession owns launch cancellation; launchOptions.signal is unsupported');
|
|
420
432
|
}
|
|
433
|
+
if (
|
|
434
|
+
optionsArg.screencast !== undefined
|
|
435
|
+
&& (
|
|
436
|
+
!optionsArg.screencast
|
|
437
|
+
|| typeof optionsArg.screencast !== 'object'
|
|
438
|
+
|| Array.isArray(optionsArg.screencast)
|
|
439
|
+
)
|
|
440
|
+
) {
|
|
441
|
+
throw new Error('screencast must be an object');
|
|
442
|
+
}
|
|
421
443
|
validateOptionalBoolean(optionsArg.allowEvaluation, 'allowEvaluation');
|
|
422
444
|
for (const name of [
|
|
423
445
|
'denyDownloads',
|
|
@@ -477,6 +499,8 @@ export class LiveBrowserSession {
|
|
|
477
499
|
};
|
|
478
500
|
this.viewport = { ...viewport };
|
|
479
501
|
this.validateScreencastOptions();
|
|
502
|
+
this.maxOutstandingFrames = this.options.screencast?.maxOutstandingFrames
|
|
503
|
+
?? liveBrowserDefaultMaxOutstandingFrames;
|
|
480
504
|
}
|
|
481
505
|
|
|
482
506
|
public onEvent(listener: TLiveBrowserEventListener): () => void {
|
|
@@ -1747,15 +1771,27 @@ export class LiveBrowserSession {
|
|
|
1747
1771
|
this.emitState();
|
|
1748
1772
|
}
|
|
1749
1773
|
const shutdownError = new Error('LiveBrowserSession is stopping');
|
|
1750
|
-
|
|
1774
|
+
const activeOperation = this.activeOperation;
|
|
1775
|
+
const shouldAbortActiveOperation = Boolean(
|
|
1751
1776
|
abortActiveOperation
|
|
1752
|
-
&&
|
|
1753
|
-
&&
|
|
1754
|
-
)
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1777
|
+
&& activeOperation
|
|
1778
|
+
&& activeOperation.kind !== 'shutdown'
|
|
1779
|
+
);
|
|
1780
|
+
if (shouldAbortActiveOperation && activeOperation) {
|
|
1781
|
+
const browserLifetimeController = this.browserLifetimeController;
|
|
1782
|
+
const frameDrainPromise = (async () => {
|
|
1783
|
+
try {
|
|
1784
|
+
await this.retireOutstandingFrames(() => true);
|
|
1785
|
+
await this.waitForCdpFrameAcknowledgements();
|
|
1786
|
+
} finally {
|
|
1787
|
+
if (browserLifetimeController && !browserLifetimeController.signal.aborted) {
|
|
1788
|
+
browserLifetimeController.abort(shutdownError);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
})();
|
|
1792
|
+
this.shutdownFrameDrainPromise = frameDrainPromise;
|
|
1793
|
+
void frameDrainPromise.catch(() => {});
|
|
1794
|
+
activeOperation.controller.abort(shutdownError);
|
|
1759
1795
|
}
|
|
1760
1796
|
this.cancelQueuedOperations(shutdownError);
|
|
1761
1797
|
}
|
|
@@ -2126,10 +2162,6 @@ export class LiveBrowserSession {
|
|
|
2126
2162
|
this.lastError = { ...error };
|
|
2127
2163
|
}
|
|
2128
2164
|
this.emitState();
|
|
2129
|
-
if (this.browserLifetimeController && !this.browserLifetimeController.signal.aborted) {
|
|
2130
|
-
this.browserLifetimeController.abort(new Error('LiveBrowserSession is stopping'));
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
2165
|
const browser = this.browser;
|
|
2134
2166
|
if (browser && this.browserTargetCreatedListener) {
|
|
2135
2167
|
browser.off('targetcreated', this.browserTargetCreatedListener);
|
|
@@ -2141,6 +2173,15 @@ export class LiveBrowserSession {
|
|
|
2141
2173
|
this.browserDisconnectedListener = undefined;
|
|
2142
2174
|
|
|
2143
2175
|
const shutdownErrors: unknown[] = [];
|
|
2176
|
+
const shutdownFrameDrainPromise = this.shutdownFrameDrainPromise;
|
|
2177
|
+
this.shutdownFrameDrainPromise = undefined;
|
|
2178
|
+
if (shutdownFrameDrainPromise) {
|
|
2179
|
+
try {
|
|
2180
|
+
await shutdownFrameDrainPromise;
|
|
2181
|
+
} catch (cleanupError) {
|
|
2182
|
+
shutdownErrors.push(cleanupError);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2144
2185
|
try {
|
|
2145
2186
|
await this.teardownProxySecurity();
|
|
2146
2187
|
} catch (cleanupError) {
|
|
@@ -2173,6 +2214,10 @@ export class LiveBrowserSession {
|
|
|
2173
2214
|
} catch (cleanupError) {
|
|
2174
2215
|
shutdownErrors.push(cleanupError);
|
|
2175
2216
|
}
|
|
2217
|
+
await this.waitForCdpFrameAcknowledgements();
|
|
2218
|
+
if (this.browserLifetimeController && !this.browserLifetimeController.signal.aborted) {
|
|
2219
|
+
this.browserLifetimeController.abort(new Error('LiveBrowserSession is stopping'));
|
|
2220
|
+
}
|
|
2176
2221
|
|
|
2177
2222
|
if (browser) {
|
|
2178
2223
|
try {
|
|
@@ -3321,6 +3366,8 @@ export class LiveBrowserSession {
|
|
|
3321
3366
|
plugins.puppeteer.CDPSessionEvent.SessionDetached,
|
|
3322
3367
|
cdpSessionDetachedListener,
|
|
3323
3368
|
);
|
|
3369
|
+
await this.retireOutstandingFrames((frame) => frame.cdpSession === cdpSession);
|
|
3370
|
+
await this.waitForCdpFrameAcknowledgements(cdpSession);
|
|
3324
3371
|
if (!cdpSession.detached) {
|
|
3325
3372
|
try {
|
|
3326
3373
|
await cdpSession.detach();
|
|
@@ -3365,6 +3412,7 @@ export class LiveBrowserSession {
|
|
|
3365
3412
|
cdpSessionDetachedListener,
|
|
3366
3413
|
);
|
|
3367
3414
|
}
|
|
3415
|
+
await this.waitForCdpFrameAcknowledgements(cdpSession);
|
|
3368
3416
|
if (!cdpSession.detached) {
|
|
3369
3417
|
try {
|
|
3370
3418
|
await cdpSession.detach();
|
|
@@ -3409,12 +3457,13 @@ export class LiveBrowserSession {
|
|
|
3409
3457
|
const sequence = ++this.frameSequence;
|
|
3410
3458
|
const outstandingFrame: IOutstandingFrame = {
|
|
3411
3459
|
tabId: tab.id,
|
|
3460
|
+
sequence,
|
|
3412
3461
|
generation,
|
|
3413
3462
|
viewportRevision: this.viewportRevision,
|
|
3414
3463
|
cdpSessionId: event.sessionId,
|
|
3415
3464
|
cdpSession,
|
|
3416
3465
|
};
|
|
3417
|
-
while (this.outstandingFrames.size >= maxOutstandingFrames) {
|
|
3466
|
+
while (this.outstandingFrames.size >= this.maxOutstandingFrames) {
|
|
3418
3467
|
const oldestFrameEntry = this.outstandingFrames.entries().next().value as
|
|
3419
3468
|
| [number, IOutstandingFrame]
|
|
3420
3469
|
| undefined;
|
|
@@ -3450,31 +3499,40 @@ export class LiveBrowserSession {
|
|
|
3450
3499
|
this.emitEvent({ type: 'frame', frame });
|
|
3451
3500
|
}
|
|
3452
3501
|
|
|
3453
|
-
private
|
|
3454
|
-
if (frame.
|
|
3455
|
-
|
|
3456
|
-
frame,
|
|
3457
|
-
new Error('CDP session detached before frame acknowledgement'),
|
|
3458
|
-
);
|
|
3459
|
-
return false;
|
|
3502
|
+
private acknowledgeCdpFrame(frame: ICdpScreencastFrame): Promise<boolean> {
|
|
3503
|
+
if (frame.acknowledgementPromise) {
|
|
3504
|
+
return frame.acknowledgementPromise;
|
|
3460
3505
|
}
|
|
3461
|
-
|
|
3506
|
+
let resolveAcknowledgement!: (accepted: boolean) => void;
|
|
3507
|
+
const acknowledgementPromise = new Promise<boolean>((resolve) => {
|
|
3508
|
+
resolveAcknowledgement = resolve;
|
|
3509
|
+
});
|
|
3510
|
+
frame.acknowledgementPromise = acknowledgementPromise;
|
|
3511
|
+
this.cdpFramesBeingAcknowledged.add(frame);
|
|
3512
|
+
void (async (): Promise<boolean> => {
|
|
3513
|
+
if (frame.cdpSession.detached) {
|
|
3514
|
+
throw new Error('CDP session detached before frame acknowledgement');
|
|
3515
|
+
}
|
|
3462
3516
|
await frame.cdpSession.send('Page.screencastFrameAck', {
|
|
3463
3517
|
sessionId: frame.cdpSessionId,
|
|
3464
|
-
});
|
|
3518
|
+
}, { timeout: frameAcknowledgementTimeoutMs });
|
|
3465
3519
|
return true;
|
|
3466
|
-
}
|
|
3520
|
+
})().then(resolveAcknowledgement, (error) => {
|
|
3467
3521
|
this.handleFrameAcknowledgementFailure(frame, error);
|
|
3468
|
-
|
|
3469
|
-
}
|
|
3522
|
+
resolveAcknowledgement(false);
|
|
3523
|
+
});
|
|
3524
|
+
void acknowledgementPromise.then(() => {
|
|
3525
|
+
this.cdpFramesBeingAcknowledged.delete(frame);
|
|
3526
|
+
});
|
|
3527
|
+
return acknowledgementPromise;
|
|
3470
3528
|
}
|
|
3471
3529
|
|
|
3472
|
-
private acknowledgeCdpFrameInBackground(frame:
|
|
3530
|
+
private acknowledgeCdpFrameInBackground(frame: ICdpScreencastFrame): void {
|
|
3473
3531
|
void this.acknowledgeCdpFrame(frame);
|
|
3474
3532
|
}
|
|
3475
3533
|
|
|
3476
3534
|
private handleFrameAcknowledgementFailure(
|
|
3477
|
-
frame:
|
|
3535
|
+
frame: ICdpScreencastFrame,
|
|
3478
3536
|
error: unknown,
|
|
3479
3537
|
): void {
|
|
3480
3538
|
const tab = this.tabs.get(frame.tabId);
|
|
@@ -3514,6 +3572,15 @@ export class LiveBrowserSession {
|
|
|
3514
3572
|
await Promise.all(acknowledgements);
|
|
3515
3573
|
}
|
|
3516
3574
|
|
|
3575
|
+
private async waitForCdpFrameAcknowledgements(
|
|
3576
|
+
cdpSession?: plugins.puppeteer.CDPSession,
|
|
3577
|
+
): Promise<void> {
|
|
3578
|
+
const acknowledgements = [...this.cdpFramesBeingAcknowledged]
|
|
3579
|
+
.filter((frame) => !cdpSession || frame.cdpSession === cdpSession)
|
|
3580
|
+
.map((frame) => frame.acknowledgementPromise!);
|
|
3581
|
+
await Promise.all(acknowledgements);
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3517
3584
|
private handlePossibleCdpDisconnection(
|
|
3518
3585
|
tab: IPrivateLiveBrowserTab,
|
|
3519
3586
|
cdpSession: plugins.puppeteer.CDPSession,
|
|
@@ -3972,5 +4039,13 @@ export class LiveBrowserSession {
|
|
|
3972
4039
|
if (options.everyNthFrame !== undefined) {
|
|
3973
4040
|
validateInteger(options.everyNthFrame, 'screencast.everyNthFrame', 1, 100);
|
|
3974
4041
|
}
|
|
4042
|
+
if (options.maxOutstandingFrames !== undefined) {
|
|
4043
|
+
validateInteger(
|
|
4044
|
+
options.maxOutstandingFrames,
|
|
4045
|
+
'screencast.maxOutstandingFrames',
|
|
4046
|
+
1,
|
|
4047
|
+
liveBrowserMaxOutstandingFrames,
|
|
4048
|
+
);
|
|
4049
|
+
}
|
|
3975
4050
|
}
|
|
3976
4051
|
}
|
|
@@ -9,6 +9,9 @@ export type TLiveBrowserWaitUntil =
|
|
|
9
9
|
| 'networkidle0'
|
|
10
10
|
| 'networkidle2';
|
|
11
11
|
|
|
12
|
+
export const liveBrowserDefaultMaxOutstandingFrames = 3;
|
|
13
|
+
export const liveBrowserMaxOutstandingFrames = 64;
|
|
14
|
+
|
|
12
15
|
export interface ILiveBrowserViewport {
|
|
13
16
|
width: number;
|
|
14
17
|
height: number;
|
|
@@ -21,6 +24,7 @@ export interface ILiveBrowserScreencastOptions {
|
|
|
21
24
|
maxWidth?: number;
|
|
22
25
|
maxHeight?: number;
|
|
23
26
|
everyNthFrame?: number;
|
|
27
|
+
maxOutstandingFrames?: number;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
export interface ILiveBrowserSecurityOptions {
|