Socket
Socket
Sign inDemoInstall

puppeteer-core

Package Overview
Dependencies
Maintainers
2
Versions
239
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

puppeteer-core - npm Package Compare versions

Comparing version 21.5.2 to 21.6.0

lib/cjs/puppeteer/bidi/BrowserConnector.d.ts

12

lib/cjs/puppeteer/api/Browser.d.ts

@@ -19,2 +19,3 @@ /**

import type { Protocol } from 'devtools-protocol';
import type { ProtocolType } from '../common/ConnectOptions.js';
import { EventEmitter, type EventType } from '../common/EventEmitter.js';

@@ -163,3 +164,3 @@ import { asyncDisposeSymbol, disposeSymbol } from '../util/disposable.js';

* // Disconnect puppeteer from the browser.
* browser.disconnect();
* await browser.disconnect();
*

@@ -227,3 +228,3 @@ * // Use the endpoint to reestablish a connection

* You can find the debugger URL (`webSocketDebuggerUrl`) from
* `http://${host}:${port}/json/version`.
* `http://HOST:PORT/json/version`.
*

@@ -234,3 +235,3 @@ * See {@link

*
* @remarks The format is always `ws://${host}:${port}/devtools/browser/<id>`.
* @remarks The format is always `ws://HOST:PORT/devtools/browser/<id>`.
*/

@@ -300,2 +301,3 @@ abstract wsEndpoint(): string;

* {@link Page.setUserAgent}.
*
*/

@@ -312,3 +314,3 @@ abstract userAgent(): Promise<string>;

*/
abstract disconnect(): void;
abstract disconnect(): Promise<void>;
/**

@@ -331,4 +333,4 @@ * Whether Puppeteer is connected to this {@link Browser | browser}.

*/
abstract get protocol(): 'cdp' | 'webDriverBiDi';
abstract get protocol(): ProtocolType;
}
//# sourceMappingURL=Browser.d.ts.map

@@ -79,3 +79,3 @@ "use strict";

* // Disconnect puppeteer from the browser.
* browser.disconnect();
* await browser.disconnect();
*

@@ -82,0 +82,0 @@ * // Use the endpoint to reestablish a connection

@@ -87,3 +87,3 @@ /**

/**
* @defaultValue true
* @defaultValue `true`
*/

@@ -498,3 +498,2 @@ scrollIntoView?: boolean;

* absolute.
*
*/

@@ -501,0 +500,0 @@ abstract uploadFile(this: ElementHandle<HTMLInputElement>, ...paths: string[]): Promise<void>;

@@ -561,2 +561,6 @@ /**

/**
* @internal
*/
setFrameContent(content: string): Promise<void>;
/**
* The frame's `name` attribute as specified in the tag.

@@ -563,0 +567,0 @@ *

@@ -577,2 +577,12 @@ "use strict";

/**
* @internal
*/
async setFrameContent(content) {
return await this.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
/**
* The frame's `name` attribute as specified in the tag.

@@ -579,0 +589,0 @@ *

@@ -270,9 +270,2 @@ /// <reference types="node" />

*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example

@@ -293,16 +286,15 @@ *

* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
abstract continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
/**
* Fulfills a request with the given response.
* @param priority - If provided, intercept is resolved using cooperative
* handling rules. Otherwise, intercept is resolved immediately.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/
abstract continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
/**
* Fulfills a request with the given response.
*

@@ -330,2 +322,9 @@ * @example

* immediately.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/

@@ -336,11 +335,12 @@ abstract respond(response: Partial<ResponseForRequest>, priority?: number): Promise<void>;

*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*
* @remarks
*
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/

@@ -347,0 +347,0 @@ abstract abort(errorCode?: ErrorCode, priority?: number): Promise<void>;

@@ -200,7 +200,6 @@ /**

/**
* @deprecated Use {@link MouseClickOptions.count}.
*
* Determines the click count for the mouse event. This does not perform
* multiple clicks.
*
* @deprecated Use {@link MouseClickOptions.count}.
* @defaultValue `1`

@@ -207,0 +206,0 @@ */

@@ -21,3 +21,5 @@ /**

*/
export declare function connectBidiOverCdp(cdp: CdpConnection): Promise<BidiConnection>;
export declare function connectBidiOverCdp(cdp: CdpConnection, options: {
acceptInsecureCerts: boolean;
}): Promise<BidiConnection>;
//# sourceMappingURL=BidiOverCdp.d.ts.map

@@ -52,3 +52,6 @@ "use strict";

*/
async function connectBidiOverCdp(cdp) {
async function connectBidiOverCdp(cdp,
// TODO: replace with `BidiMapper.MapperOptions`, once it's exported in
// https://github.com/puppeteer/puppeteer/pull/11415.
options) {
const transportBiDi = new NoOpTransport();

@@ -64,2 +67,3 @@ const cdpConnectionAdapter = new CdpConnectionAdapter(cdp);

cdpConnectionAdapter.close();
cdp.dispose();
},

@@ -77,3 +81,3 @@ onmessage(_message) {

// TODO: most likely need a little bit of refactoring
cdpConnectionAdapter.browserClient(), '', undefined, bidiServerLogger);
cdpConnectionAdapter.browserClient(), '', options, undefined, bidiServerLogger);
return pptrBiDiConnection;

@@ -89,9 +93,9 @@ }

#adapters = new Map();
#browser;
#browserCdpConnection;
constructor(cdp) {
this.#cdp = cdp;
this.#browser = new CDPClientAdapter(cdp);
this.#browserCdpConnection = new CDPClientAdapter(cdp);
}
browserClient() {
return this.#browser;
return this.#browserCdpConnection;
}

@@ -104,3 +108,3 @@ getCdpClient(id) {

if (!this.#adapters.has(session)) {
const adapter = new CDPClientAdapter(session, id, this.#browser);
const adapter = new CDPClientAdapter(session, id, this.#browserCdpConnection);
this.#adapters.set(session, adapter);

@@ -112,3 +116,3 @@ return adapter;

close() {
this.#browser.close();
this.#browserCdpConnection.close();
for (const adapter of this.#adapters.values()) {

@@ -115,0 +119,0 @@ adapter.close();

@@ -64,4 +64,4 @@ /**

target(): Target;
disconnect(): void;
disconnect(): Promise<void>;
}
//# sourceMappingURL=Browser.d.ts.map

@@ -189,5 +189,6 @@ "use strict";

}
await this.#connection.send('browser.close', {});
// `browser.close` can close connection before the response is received.
await this.#connection.send('browser.close', {}).catch(util_js_1.debugError);
await this.#closeCallback?.call(null);
this.#connection.dispose();
await this.#closeCallback?.call(null);
}

@@ -246,4 +247,11 @@ get connected() {

}
disconnect() {
this;
async disconnect() {
try {
// Fail silently if the session cannot be ended.
await this.#connection.send('session.end', {});
}
catch (e) {
(0, util_js_1.debugError)(e);
}
this.#connection.dispose();
}

@@ -250,0 +258,0 @@ }

@@ -88,2 +88,6 @@ /**

};
'browsingContext.traverseHistory': {
params: Bidi.BrowsingContext.TraverseHistoryParameters;
returnType: Bidi.EmptyResult;
};
'input.performActions': {

@@ -97,2 +101,6 @@ params: Bidi.Input.PerformActionsParameters;

};
'session.end': {
params: Bidi.EmptyParams;
returnType: Bidi.EmptyResult;
};
'session.new': {

@@ -150,4 +158,13 @@ params: Bidi.Session.NewParameters;

unregisterBrowsingContexts(id: string): void;
/**
* Unbinds the connection, but keeps the transport open. Useful when the transport will
* be reused by other connection e.g. with different protocol.
* @internal
*/
unbind(): void;
/**
* Unbinds the connection and closes the transport.
*/
dispose(): void;
}
//# sourceMappingURL=Connection.d.ts.map

@@ -23,2 +23,3 @@ "use strict";

const util_js_1 = require("../common/util.js");
const assert_js_1 = require("../util/assert.js");
const BrowsingContext_js_1 = require("./BrowsingContext.js");

@@ -45,3 +46,3 @@ const debugProtocolSend = (0, Debug_js_1.debug)('puppeteer:webDriverBiDi:SEND ►');

this.#transport.onmessage = this.onMessage.bind(this);
this.#transport.onclose = this.#onClose.bind(this);
this.#transport.onclose = this.unbind.bind(this);
}

@@ -55,2 +56,3 @@ get closed() {

send(method, params) {
(0, assert_js_1.assert)(!this.#closed, 'Protocol error: Connection closed.');
return this.#callbacks.create(method, this.#timeout, id => {

@@ -89,2 +91,8 @@ const stringifiedMessage = JSON.stringify({

case 'event':
if (isCdpEvent(object)) {
BrowsingContext_js_1.cdpSessions
.get(object.params.session)
?.emit(object.params.event, object.params.params);
return;
}
this.#maybeEmitOnContext(object);

@@ -96,2 +104,7 @@ // SAFETY: We know the method and parameter still match here.

}
// Even if the response in not in BiDi protocol format but `id` is provided, reject
// the callback. This can happen if the endpoint supports CDP instead of BiDi.
if ('id' in object) {
this.#callbacks.reject(object.id, `Protocol Error. Message is not in BiDi protocol format: '${message}'`, object.message);
}
(0, util_js_1.debugError)(object);

@@ -110,7 +123,2 @@ }

}
else if (isCdpEvent(event)) {
BrowsingContext_js_1.cdpSessions
.get(event.params.session)
?.emit(event.params.event, event.params.params);
}
context?.emit(event.method, event.params);

@@ -145,3 +153,8 @@ }

}
#onClose() {
/**
* Unbinds the connection, but keeps the transport open. Useful when the transport will
* be reused by other connection e.g. with different protocol.
* @internal
*/
unbind() {
if (this.#closed) {

@@ -154,6 +167,10 @@ return;

this.#transport.onclose = () => { };
this.#browsingContexts.clear();
this.#callbacks.clear();
}
/**
* Unbinds the connection and closes the transport.
*/
dispose() {
this.#onClose();
this.unbind();
this.#transport.close();

@@ -160,0 +177,0 @@ }

@@ -17,5 +17,7 @@ /**

import type { CDPSession } from '../api/CDPSession.js';
import type { ElementHandle } from '../api/ElementHandle.js';
import { Frame, type GoToOptions, type WaitForOptions } from '../api/Frame.js';
import type { WaitForSelectorOptions } from '../api/Page.js';
import type { TimeoutSettings } from '../common/TimeoutSettings.js';
import type { Awaitable } from '../common/types.js';
import type { Awaitable, NodeFor } from '../common/types.js';
import { disposeSymbol } from '../util/disposable.js';

@@ -51,3 +53,4 @@ import type { BrowsingContext } from './BrowsingContext.js';

exposeFunction<Args extends unknown[], Ret>(name: string, apply: (...args: Args) => Awaitable<Ret>): Promise<void>;
waitForSelector<Selector extends string>(selector: Selector, options?: WaitForSelectorOptions): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
//# sourceMappingURL=Frame.d.ts.map

@@ -166,3 +166,3 @@ "use strict";

(0, rxjs_js_1.fromEvent)(this.#context, waitEvent).pipe((0, rxjs_js_1.first)()),
(0, rxjs_js_1.from)((0, util_js_1.setPageContent)(this, html)),
(0, rxjs_js_1.from)(this.setFrameContent(html)),
]).pipe((0, rxjs_js_1.map)(() => {

@@ -225,2 +225,8 @@ return null;

}
waitForSelector(selector, options) {
if (selector.startsWith('aria')) {
throw new Errors_js_1.UnsupportedOperation('ARIA selector is not supported for BiDi!');
}
return super.waitForSelector(selector, options);
}
};

@@ -227,0 +233,0 @@ })();

@@ -24,2 +24,3 @@ /**

import type { WaitForOptions } from '../api/Frame.js';
import type { HTTPResponse } from '../api/HTTPResponse.js';
import { Page, type GeolocationOptions, type MediaFeature, type NewDocumentScriptEvaluation, type ScreenshotOptions } from '../api/Page.js';

@@ -42,2 +43,3 @@ import { Accessibility } from '../cdp/Accessibility.js';

import type { BiDiNetworkIdle } from './lifecycle.js';
import type { BiDiPageTarget } from './Target.js';
/**

@@ -49,3 +51,3 @@ * @internal

_client(): CDPSession;
constructor(browsingContext: BrowsingContext, browserContext: BidiBrowserContext);
constructor(browsingContext: BrowsingContext, browserContext: BidiBrowserContext, target: BiDiPageTarget);
/**

@@ -77,3 +79,5 @@ * @internal

isClosed(): boolean;
close(): Promise<void>;
close(options?: {
runBeforeUnload?: boolean;
}): Promise<void>;
reload(options?: WaitForOptions): Promise<BidiHTTPResponse | null>;

@@ -126,3 +130,3 @@ setDefaultNavigationTimeout(timeout: number): void;

isServiceWorkerBypassed(): never;
target(): never;
target(): BiDiPageTarget;
waitForFileChooser(): never;

@@ -142,6 +146,6 @@ workers(): never;

metrics(): never;
goBack(): never;
goForward(): never;
goBack(options?: WaitForOptions): Promise<HTTPResponse | null>;
goForward(options?: WaitForOptions): Promise<HTTPResponse | null>;
waitForDevicePrompt(): never;
}
//# sourceMappingURL=Page.d.ts.map

@@ -101,2 +101,3 @@ "use strict";

const disposable_js_1 = require("../util/disposable.js");
const ErrorLike_js_1 = require("../util/ErrorLike.js");
const BrowsingContext_js_1 = require("./BrowsingContext.js");

@@ -180,9 +181,11 @@ const Deserializer_js_1 = require("./Deserializer.js");

#browserContext;
#target;
_client() {
return this.mainFrame().context().cdpSession;
}
constructor(browsingContext, browserContext) {
constructor(browsingContext, browserContext, target) {
super();
this.#browsingContext = browsingContext;
this.#browserContext = browserContext;
this.#target = target;
this.#connection = browsingContext.connection;

@@ -417,3 +420,3 @@ for (const [event, subscriber] of this.#browsingContextEvents) {

}
async close() {
async close(options) {
if (this.#closedDeferred.finished()) {

@@ -426,2 +429,3 @@ return;

context: this.mainFrame()._id,
promptUnload: options?.runBeforeUnload ?? false,
});

@@ -528,6 +532,3 @@ this.emit("close" /* PageEvent.Close */, undefined);

async _screenshot(options) {
const { clip, type, captureBeyondViewport, allowViewportExpansion, quality } = options;
if (captureBeyondViewport && !allowViewportExpansion) {
throw new Errors_js_1.UnsupportedOperation(`BiDi does not support 'captureBeyondViewport'. Use 'allowViewportExpansion'.`);
}
const { clip, type, captureBeyondViewport, quality } = options;
if (options.omitBackground !== undefined && options.omitBackground) {

@@ -542,2 +543,24 @@ throw new Errors_js_1.UnsupportedOperation(`BiDi does not support 'omitBackground'.`);

}
let box;
if (clip) {
if (captureBeyondViewport) {
box = clip;
}
else {
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
];
});
box = {
...clip,
x: clip.x - pageLeft,
y: clip.y - pageTop,
};
}
}
if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) {

@@ -548,10 +571,8 @@ throw new Errors_js_1.UnsupportedOperation(`BiDi does not support 'scale' in 'clip'.`);

context: this.mainFrame()._id,
origin: captureBeyondViewport ? 'document' : 'viewport',
format: {
type: `image/${type}`,
quality: quality ? quality / 100 : undefined,
...(quality !== undefined ? { quality: quality / 100 } : {}),
},
clip: clip && {
type: 'box',
...clip,
},
...(box ? { clip: { type: 'box', ...box } } : {}),
});

@@ -627,3 +648,3 @@ return data;

target() {
throw new Errors_js_1.UnsupportedOperation();
return this.#target;
}

@@ -673,8 +694,29 @@ waitForFileChooser() {

}
goBack() {
throw new Errors_js_1.UnsupportedOperation();
async goBack(options = {}) {
return await this.#go(-1, options);
}
goForward() {
throw new Errors_js_1.UnsupportedOperation();
async goForward(options = {}) {
return await this.#go(+1, options);
}
async #go(delta, options) {
try {
const result = await Promise.all([
this.waitForNavigation(options),
this.#connection.send('browsingContext.traverseHistory', {
delta,
context: this.mainFrame()._id,
}),
]);
return result[0];
}
catch (err) {
// TODO: waitForNavigation should be cancelled if an error happens.
if ((0, ErrorLike_js_1.isErrorLike)(err)) {
if (err.message.includes('no such history entry')) {
return null;
}
}
throw err;
}
}
waitForDevicePrompt() {

@@ -681,0 +723,0 @@ throw new Errors_js_1.UnsupportedOperation();

@@ -95,3 +95,3 @@ "use strict";

super(browserContext, browsingContext);
this.#page = new Page_js_1.BidiPage(browsingContext, browserContext);
this.#page = new Page_js_1.BidiPage(browsingContext, browserContext, this);
}

@@ -98,0 +98,0 @@ async page() {

@@ -51,3 +51,3 @@ /**

close(): Promise<void>;
disconnect(): void;
disconnect(): Promise<void>;
get connected(): boolean;

@@ -54,0 +54,0 @@ }

@@ -234,3 +234,3 @@ "use strict";

await this.#closeCallback.call(null);
this.disconnect();
await this.disconnect();
}

@@ -241,2 +241,3 @@ disconnect() {

this._detach();
return Promise.resolve();
}

@@ -243,0 +244,0 @@ get connected() {

@@ -16,3 +16,3 @@ /**

*/
import type { BidiBrowser } from '../bidi/Browser.js';
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
import type { BrowserConnectOptions, ConnectOptions } from '../common/ConnectOptions.js';

@@ -26,10 +26,3 @@ import { CdpBrowser } from './Browser.js';

*/
export declare function _connectToCdpBrowser(options: BrowserConnectOptions & ConnectOptions): Promise<CdpBrowser>;
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
*
* @internal
*/
export declare function _connectToBiDiOverCdpBrowser(options: BrowserConnectOptions & ConnectOptions): Promise<BidiBrowser>;
export declare function _connectToCdpBrowser(connectionTransport: ConnectionTransport, url: string, options: BrowserConnectOptions & ConnectOptions): Promise<CdpBrowser>;
//# sourceMappingURL=BrowserConnector.d.ts.map

@@ -17,42 +17,7 @@ "use strict";

*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports._connectToBiDiOverCdpBrowser = exports._connectToCdpBrowser = void 0;
const Errors_js_1 = require("../common/Errors.js");
const fetch_js_1 = require("../common/fetch.js");
exports._connectToCdpBrowser = void 0;
const util_js_1 = require("../common/util.js");
const environment_js_1 = require("../environment.js");
const assert_js_1 = require("../util/assert.js");
const ErrorLike_js_1 = require("../util/ErrorLike.js");
const Browser_js_1 = require("./Browser.js");
const Connection_js_1 = require("./Connection.js");
const DEFAULT_VIEWPORT = Object.freeze({ width: 800, height: 600 });
const getWebSocketTransportClass = async () => {
return environment_js_1.isNode
? (await Promise.resolve().then(() => __importStar(require('../node/NodeWebSocketTransport.js')))).NodeWebSocketTransport
: (await Promise.resolve().then(() => __importStar(require('../common/BrowserWebSocketTransport.js'))))
.BrowserWebSocketTransport;
};
/**

@@ -64,5 +29,5 @@ * Users should never call this directly; it's called when calling

*/
async function _connectToCdpBrowser(options) {
const { ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT, targetFilter, _isPageTarget: isPageTarget, } = options;
const connection = await getCdpConnection(options);
async function _connectToCdpBrowser(connectionTransport, url, options) {
const { ignoreHTTPSErrors = false, defaultViewport = util_js_1.DEFAULT_VIEWPORT, targetFilter, _isPageTarget: isPageTarget, slowMo = 0, protocolTimeout, } = options;
const connection = new Connection_js_1.Connection(url, connectionTransport, slowMo, protocolTimeout);
const version = await connection.send('Browser.getVersion');

@@ -79,75 +44,2 @@ const product = version.product.toLowerCase().includes('firefox')

exports._connectToCdpBrowser = _connectToCdpBrowser;
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
*
* @internal
*/
async function _connectToBiDiOverCdpBrowser(options) {
const { ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT } = options;
const connection = await getCdpConnection(options);
const version = await connection.send('Browser.getVersion');
if (version.product.toLowerCase().includes('firefox')) {
throw new Errors_js_1.UnsupportedOperation('Firefox is not supported in BiDi over CDP mode.');
}
// TODO: use other options too.
const BiDi = await Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ '../bidi/bidi.js')));
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiBrowser = await BiDi.BidiBrowser.create({
connection: bidiConnection,
closeCallback: () => {
return connection.send('Browser.close').catch(util_js_1.debugError);
},
process: undefined,
defaultViewport: defaultViewport,
ignoreHTTPSErrors: ignoreHTTPSErrors,
});
return bidiBrowser;
}
exports._connectToBiDiOverCdpBrowser = _connectToBiDiOverCdpBrowser;
async function getWSEndpoint(browserURL) {
const endpointURL = new URL('/json/version', browserURL);
const fetch = await (0, fetch_js_1.getFetch)();
try {
const result = await fetch(endpointURL.toString(), {
method: 'GET',
});
if (!result.ok) {
throw new Error(`HTTP ${result.statusText}`);
}
const data = await result.json();
return data.webSocketDebuggerUrl;
}
catch (error) {
if ((0, ErrorLike_js_1.isErrorLike)(error)) {
error.message =
`Failed to fetch browser webSocket URL from ${endpointURL}: ` +
error.message;
}
throw error;
}
}
/**
* Returns a CDP connection for the given options.
*/
async function getCdpConnection(options) {
const { browserWSEndpoint, browserURL, transport, headers = {}, slowMo = 0, protocolTimeout, } = options;
(0, assert_js_1.assert)(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
if (transport) {
return new Connection_js_1.Connection('', transport, slowMo, protocolTimeout);
}
else if (browserWSEndpoint) {
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(browserWSEndpoint, headers);
return new Connection_js_1.Connection(browserWSEndpoint, connectionTransport, slowMo, protocolTimeout);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(connectionURL);
return new Connection_js_1.Connection(connectionURL, connectionTransport, slowMo, protocolTimeout);
}
throw new Error('Invalid connection options');
}
//# sourceMappingURL=BrowserConnector.js.map

@@ -55,3 +55,2 @@ "use strict";

const Errors_js_1 = require("../common/Errors.js");
const util_js_1 = require("../common/util.js");
const Deferred_js_1 = require("../util/Deferred.js");

@@ -217,3 +216,5 @@ const disposable_js_1 = require("../util/disposable.js");

const { waitUntil = ['load'], timeout = this._frameManager.timeoutSettings.navigationTimeout(), } = options;
await (0, util_js_1.setPageContent)(this.isolatedRealm(), html);
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.setFrameContent(html);
const watcher = new LifecycleWatcher_js_1.LifecycleWatcher(this._frameManager.networkManager, this, waitUntil, timeout);

@@ -220,0 +221,0 @@ const error = await Deferred_js_1.Deferred.race([

@@ -139,3 +139,2 @@ "use strict";

}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_1, await this.#mutex.acquire(), false);

@@ -142,0 +141,0 @@ try {

@@ -5,2 +5,6 @@ import type { IsPageTargetCallback, TargetFilterCallback } from '../api/Browser.js';

/**
* @public
*/
export type ProtocolType = 'cdp' | 'webDriverBiDi';
/**
* Generic browser options that can be passed when launching any browser or when

@@ -18,2 +22,4 @@ * connecting to an existing browser instance.

* Sets the viewport for each page.
*
* @defaultValue '\{width: 800, height: 600\}'
*/

@@ -36,5 +42,5 @@ defaultViewport?: Viewport | null;

* @defaultValue 'cdp'
* @internal
* @public
*/
protocol?: 'cdp' | 'webDriverBiDi';
protocol?: ProtocolType;
/**

@@ -41,0 +47,0 @@ * Timeout setting for individual protocol (CDP) calls.

@@ -19,3 +19,3 @@ "use strict";

exports.Puppeteer = void 0;
const BrowserConnector_js_1 = require("../cdp/BrowserConnector.js");
const BrowserConnector_js_1 = require("./BrowserConnector.js");
const CustomQueryHandler_js_1 = require("./CustomQueryHandler.js");

@@ -107,8 +107,3 @@ /**

connect(options) {
if (options.protocol === 'webDriverBiDi') {
return (0, BrowserConnector_js_1._connectToBiDiOverCdpBrowser)(options);
}
else {
return (0, BrowserConnector_js_1._connectToCdpBrowser)(options);
}
return (0, BrowserConnector_js_1._connectToBrowser)(options);
}

@@ -115,0 +110,0 @@ }

@@ -25,3 +25,2 @@ /**

import type { CDPSession } from '../api/CDPSession.js';
import type { Page } from '../api/Page.js';
import type { Deferred } from '../util/Deferred.js';

@@ -37,2 +36,9 @@ import type { EventEmitter, EventType } from './EventEmitter.js';

*/
export declare const DEFAULT_VIEWPORT: Readonly<{
width: 800;
height: 600;
}>;
/**
* @internal
*/
export declare function createEvaluationError(details: Protocol.Runtime.ExceptionDetails): unknown;

@@ -115,6 +121,2 @@ /**

*/
export declare function setPageContent(page: Pick<Page, 'evaluate'>, content: string): Promise<void>;
/**
* @internal
*/
export declare function getPageContent(): string;

@@ -121,0 +123,0 @@ /**

@@ -41,3 +41,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.NETWORK_IDLE_TIME = exports.waitForHTTP = exports.getSourceUrlComment = exports.SOURCE_URL_REGEX = exports.UTILITY_WORLD_NAME = exports.timeout = exports.validateDialogType = exports.getPageContent = exports.setPageContent = exports.getReadableFromProtocolStream = exports.getReadableAsBuffer = exports.importFSPromises = exports.pageBindingInitString = exports.addPageBinding = exports.evaluationString = exports.isDate = exports.isRegExp = exports.isPlainObject = exports.isNumber = exports.isString = exports.valueFromRemoteObject = exports.getSourcePuppeteerURLIfAvailable = exports.withSourcePuppeteerURLIfNone = exports.PuppeteerURL = exports.createClientError = exports.createEvaluationError = exports.debugError = void 0;
exports.NETWORK_IDLE_TIME = exports.waitForHTTP = exports.getSourceUrlComment = exports.SOURCE_URL_REGEX = exports.UTILITY_WORLD_NAME = exports.timeout = exports.validateDialogType = exports.getPageContent = exports.getReadableFromProtocolStream = exports.getReadableAsBuffer = exports.importFSPromises = exports.pageBindingInitString = exports.addPageBinding = exports.evaluationString = exports.isDate = exports.isRegExp = exports.isPlainObject = exports.isNumber = exports.isString = exports.valueFromRemoteObject = exports.getSourcePuppeteerURLIfAvailable = exports.withSourcePuppeteerURLIfNone = exports.PuppeteerURL = exports.createClientError = exports.createEvaluationError = exports.DEFAULT_VIEWPORT = exports.debugError = void 0;
const rxjs_js_1 = require("../../third_party/rxjs/rxjs.js");

@@ -56,2 +56,6 @@ const environment_js_1 = require("../environment.js");

*/
exports.DEFAULT_VIEWPORT = Object.freeze({ width: 800, height: 600 });
/**
* @internal
*/
function createEvaluationError(details) {

@@ -447,15 +451,2 @@ let name;

*/
async function setPageContent(page, content) {
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
return await page.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
exports.setPageContent = setPageContent;
/**
* @internal
*/
function getPageContent() {

@@ -462,0 +453,0 @@ let content = '';

/**
* @internal
*/
export declare const packageVersion = "21.5.2";
export declare const packageVersion = "21.6.0";
//# sourceMappingURL=version.d.ts.map

@@ -7,3 +7,3 @@ "use strict";

*/
exports.packageVersion = '21.5.2';
exports.packageVersion = '21.6.0';
//# sourceMappingURL=version.js.map

@@ -40,3 +40,3 @@ /**

customQuerySelectors: {
"__#49622@#selectors": Map<string, CustomQuerySelectors.CustomQuerySelector>;
"__#49698@#selectors": Map<string, CustomQuerySelectors.CustomQuerySelector>;
register(name: string, handler: import("../puppeteer-core.js").CustomQueryHandler): void;

@@ -43,0 +43,0 @@ unregister(name: string): void;

@@ -23,2 +23,3 @@ "use strict";

const promises_1 = require("fs/promises");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));

@@ -52,2 +53,17 @@ const browsers_1 = require("@puppeteer/browsers");

}
if (this.puppeteer.configuration.logLevel === 'warn' &&
process.platform === 'darwin' &&
process.arch === 'x64') {
const cpus = os_1.default.cpus();
if (cpus[0]?.model.includes('Apple')) {
console.warn([
'\x1B[1m\x1B[43m\x1B[30m',
'Degraded performance warning:\x1B[0m\x1B[33m',
'Launching Chrome on Mac Silicon (arm64) from an x64 Node installation results in',
'Rosetta translating the Chrome binary, even if Chrome is already arm64. This would',
'result in huge performance issues. To resolve this, you must run Puppeteer with',
'a version of Node built for arm64.',
].join('\n '));
}
}
return super.launch(options);

@@ -54,0 +70,0 @@ }

@@ -86,3 +86,17 @@ "use strict";

path: userDataDir,
preferences: extraPrefsFirefox,
preferences: {
...extraPrefsFirefox,
...(options.protocol === 'cdp'
? {
// Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
'fission.bfcacheInParent': false,
}
: {}),
// Force all web content to use a single content process. TODO: remove
// this once Firefox supports mouse event dispatch from the main frame
// context. Once this happens, webContentIsolationStrategy should only
// be set for CDP. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1773393
'fission.webContentIsolationStrategy': 0,
},
});

@@ -89,0 +103,0 @@ let firefoxExecutable;

@@ -59,3 +59,3 @@ import { launch } from '@puppeteer/browsers';

*/
protected closeBrowser(browserProcess: ReturnType<typeof launch>, connection?: Connection): Promise<void>;
protected closeBrowser(browserProcess: ReturnType<typeof launch>, cdpConnection?: Connection): Promise<void>;
/**

@@ -62,0 +62,0 @@ * @internal

@@ -78,3 +78,3 @@ "use strict";

async launch(options = {}) {
const { dumpio = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, slowMo = 0, timeout = 30000, waitForInitialPage = true, protocol, protocolTimeout, } = options;
const { dumpio = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = util_js_1.DEFAULT_VIEWPORT, slowMo = 0, timeout = 30000, waitForInitialPage = true, protocolTimeout, protocol, } = options;
const launchArgs = await this.computeLaunchArguments(options);

@@ -99,3 +99,3 @@ const usePipe = launchArgs.args.includes('--remote-debugging-pipe');

let browser;
let connection;
let cdpConnection;
let closing = false;

@@ -107,3 +107,3 @@ const browserCloseCallback = async () => {

closing = true;
await this.closeBrowser(browserProcess, connection);
await this.closeBrowser(browserProcess, cdpConnection);
};

@@ -122,3 +122,3 @@ try {

if (usePipe) {
connection = await this.createCdpPipeConnection(browserProcess, {
cdpConnection = await this.createCdpPipeConnection(browserProcess, {
timeout,

@@ -130,3 +130,3 @@ protocolTimeout,

else {
connection = await this.createCdpSocketConnection(browserProcess, {
cdpConnection = await this.createCdpSocketConnection(browserProcess, {
timeout,

@@ -138,3 +138,3 @@ protocolTimeout,

if (protocol === 'webDriverBiDi') {
browser = await this.createBiDiOverCdpBrowser(browserProcess, connection, browserCloseCallback, {
browser = await this.createBiDiOverCdpBrowser(browserProcess, cdpConnection, browserCloseCallback, {
timeout,

@@ -148,3 +148,3 @@ protocolTimeout,

else {
browser = await Browser_js_1.CdpBrowser._create(this.product, connection, [], ignoreHTTPSErrors, defaultViewport, browserProcess.nodeProcess, browserCloseCallback, options.targetFilter);
browser = await Browser_js_1.CdpBrowser._create(this.product, cdpConnection, [], ignoreHTTPSErrors, defaultViewport, browserProcess.nodeProcess, browserCloseCallback, options.targetFilter);
}

@@ -176,7 +176,7 @@ }

*/
async closeBrowser(browserProcess, connection) {
if (connection) {
async closeBrowser(browserProcess, cdpConnection) {
if (cdpConnection) {
// Attempt to close the browser gracefully
try {
await connection.closeBrowser();
await cdpConnection.closeBrowser();
await browserProcess.hasClosed();

@@ -231,3 +231,5 @@ }

const BiDi = await Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ '../bidi/bidi.js')));
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiConnection = await BiDi.connectBidiOverCdp(connection, {
acceptInsecureCerts: opts.ignoreHTTPSErrors ?? false,
});
return await BiDi.BidiBrowser.create({

@@ -296,3 +298,3 @@ connection: bidiConnection,

throw new Error(`Could not find Chrome (ver. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation before running the script (e.g. `npm install`) or\n' +
' 1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -302,3 +304,3 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');

throw new Error(`Could not find Firefox (rev. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation for Firefox before running the script (e.g. `PUPPETEER_PRODUCT=firefox npm install`) or\n' +
' 1. you did not perform an installation for Firefox before running the script (e.g. `npx puppeteer browsers install firefox`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -305,0 +307,0 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');

@@ -118,3 +118,3 @@ /**

* describes some differences for Linux users. See
* {@link https://goo.gle/chrome-for-testing | this doc} for the description
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.

@@ -121,0 +121,0 @@ *

@@ -134,3 +134,3 @@ "use strict";

* describes some differences for Linux users. See
* {@link https://goo.gle/chrome-for-testing | this doc} for the description
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.

@@ -137,0 +137,0 @@ *

@@ -9,3 +9,3 @@ import { disposeSymbol } from './disposable.js';

new (mutex: Mutex): {
"__#49612@#mutex": Mutex;
"__#49688@#mutex": Mutex;
[Symbol.dispose](): void;

@@ -12,0 +12,0 @@ };

@@ -19,2 +19,3 @@ /**

import type { Protocol } from 'devtools-protocol';
import type { ProtocolType } from '../common/ConnectOptions.js';
import { EventEmitter, type EventType } from '../common/EventEmitter.js';

@@ -163,3 +164,3 @@ import { asyncDisposeSymbol, disposeSymbol } from '../util/disposable.js';

* // Disconnect puppeteer from the browser.
* browser.disconnect();
* await browser.disconnect();
*

@@ -227,3 +228,3 @@ * // Use the endpoint to reestablish a connection

* You can find the debugger URL (`webSocketDebuggerUrl`) from
* `http://${host}:${port}/json/version`.
* `http://HOST:PORT/json/version`.
*

@@ -234,3 +235,3 @@ * See {@link

*
* @remarks The format is always `ws://${host}:${port}/devtools/browser/<id>`.
* @remarks The format is always `ws://HOST:PORT/devtools/browser/<id>`.
*/

@@ -300,2 +301,3 @@ abstract wsEndpoint(): string;

* {@link Page.setUserAgent}.
*
*/

@@ -312,3 +314,3 @@ abstract userAgent(): Promise<string>;

*/
abstract disconnect(): void;
abstract disconnect(): Promise<void>;
/**

@@ -331,4 +333,4 @@ * Whether Puppeteer is connected to this {@link Browser | browser}.

*/
abstract get protocol(): 'cdp' | 'webDriverBiDi';
abstract get protocol(): ProtocolType;
}
//# sourceMappingURL=Browser.d.ts.map

@@ -76,3 +76,3 @@ /**

* // Disconnect puppeteer from the browser.
* browser.disconnect();
* await browser.disconnect();
*

@@ -79,0 +79,0 @@ * // Use the endpoint to reestablish a connection

@@ -87,3 +87,3 @@ /**

/**
* @defaultValue true
* @defaultValue `true`
*/

@@ -498,3 +498,2 @@ scrollIntoView?: boolean;

* absolute.
*
*/

@@ -501,0 +500,0 @@ abstract uploadFile(this: ElementHandle<HTMLInputElement>, ...paths: string[]): Promise<void>;

@@ -1190,42 +1190,22 @@ /**

async screenshot(options = {}) {
const env_6 = { stack: [], error: void 0, hasError: false };
try {
const { scrollIntoView = true, captureBeyondViewport = true, allowViewportExpansion = captureBeyondViewport, } = options;
let clip = await this.#nonEmptyVisibleBoundingBox();
const page = this.frame.page();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_6, allowViewportExpansion && clip
? await page._createTemporaryViewportContainingBox(clip)
: null, true);
if (scrollIntoView) {
await this.scrollIntoViewIfNeeded();
// We measure again just in case.
clip = await this.#nonEmptyVisibleBoundingBox();
const { scrollIntoView = true } = options;
let clip = await this.#nonEmptyVisibleBoundingBox();
const page = this.frame.page();
if (scrollIntoView) {
await this.scrollIntoViewIfNeeded();
// We measure again just in case.
clip = await this.#nonEmptyVisibleBoundingBox();
}
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
];
});
clip.x += pageLeft;
clip.y += pageTop;
return await page.screenshot({
...options,
captureBeyondViewport: false,
clip,
});
}
catch (e_6) {
env_6.error = e_6;
env_6.hasError = true;
}
finally {
const result_1 = __disposeResources(env_6);
if (result_1)
await result_1;
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
];
});
clip.x += pageLeft;
clip.y += pageTop;
return await page.screenshot({ ...options, clip });
}

@@ -1276,3 +1256,3 @@ async #nonEmptyVisibleBoundingBox() {

async isIntersectingViewport(options = {}) {
const env_7 = { stack: [], error: void 0, hasError: false };
const env_6 = { stack: [], error: void 0, hasError: false };
try {

@@ -1282,3 +1262,3 @@ await this.assertConnectedElement();

const handle = await this.#asSVGElementHandle();
const target = __addDisposableResource(env_7, handle && (await handle.#getOwnerSVGElement()), false);
const target = __addDisposableResource(env_6, handle && (await handle.#getOwnerSVGElement()), false);
return await (target ?? this).evaluate(async (element, threshold) => {

@@ -1295,8 +1275,8 @@ const visibleRatio = await new Promise(resolve => {

}
catch (e_7) {
env_7.error = e_7;
env_7.hasError = true;
catch (e_6) {
env_6.error = e_6;
env_6.hasError = true;
}
finally {
__disposeResources(env_7);
__disposeResources(env_6);
}

@@ -1303,0 +1283,0 @@ }

@@ -561,2 +561,6 @@ /**

/**
* @internal
*/
setFrameContent(content: string): Promise<void>;
/**
* The frame's `name` attribute as specified in the tag.

@@ -563,0 +567,0 @@ *

@@ -574,2 +574,12 @@ /**

/**
* @internal
*/
async setFrameContent(content) {
return await this.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
/**
* The frame's `name` attribute as specified in the tag.

@@ -576,0 +586,0 @@ *

@@ -270,9 +270,2 @@ /// <reference types="node" />

*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example

@@ -293,16 +286,15 @@ *

* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
abstract continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
/**
* Fulfills a request with the given response.
* @param priority - If provided, intercept is resolved using cooperative
* handling rules. Otherwise, intercept is resolved immediately.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/
abstract continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
/**
* Fulfills a request with the given response.
*

@@ -330,2 +322,9 @@ * @example

* immediately.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/

@@ -336,11 +335,12 @@ abstract respond(response: Partial<ResponseForRequest>, priority?: number): Promise<void>;

*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*
* @remarks
*
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/

@@ -347,0 +347,0 @@ abstract abort(errorCode?: ErrorCode, priority?: number): Promise<void>;

@@ -200,7 +200,6 @@ /**

/**
* @deprecated Use {@link MouseClickOptions.count}.
*
* Determines the click count for the mouse event. This does not perform
* multiple clicks.
*
* @deprecated Use {@link MouseClickOptions.count}.
* @defaultValue `1`

@@ -207,0 +206,0 @@ */

@@ -104,3 +104,3 @@ /**

import { guarded } from '../util/decorators.js';
import { AsyncDisposableStack, asyncDisposeSymbol, DisposableStack, disposeSymbol, } from '../util/disposable.js';
import { asyncDisposeSymbol, DisposableStack, disposeSymbol, } from '../util/disposable.js';
import { FunctionLocator, Locator, NodeLocator, } from './locators/locators.js';

@@ -118,3 +118,2 @@ /**

options.captureBeyondViewport ??= true;
options.allowViewportExpansion ??= options.captureBeyondViewport;
}

@@ -260,5 +259,8 @@ /**

* match the selector, the return value resolves to `[]`.
*
* @param selector - A `selector` to query page for
*
* @remarks
*
* Shortcut for {@link Frame.$$ | Page.mainFrame().$$(selector) }.
* @param selector - A `selector` to query page for
*/

@@ -493,4 +495,6 @@ async $$(selector) {

* The page's URL.
* @remarks Shortcut for
* {@link Frame.url | page.mainFrame().url()}.
*
* @remarks
*
* Shortcut for {@link Frame.url | page.mainFrame().url()}.
*/

@@ -511,3 +515,5 @@ url() {

* @param options - Parameters that has some properties.
*
* @remarks
*
* The parameter `options` might have the following options.

@@ -540,2 +546,3 @@ *

* @remarks
*
* Navigation to `about:blank` or navigation to the same URL with a different

@@ -590,2 +597,3 @@ * hash will succeed and return `null`.

* @remarks
*
* Usage of the

@@ -649,3 +657,2 @@ * {@link https://developer.mozilla.org/en-US/docs/Web/API/History_API | History API}

*
* @remarks
* This method will resize the page. A lot of websites don't expect phones to

@@ -740,9 +747,2 @@ * change size, so you should emulate before navigating to the page.

*
* @remarks
*
* All recordings will be {@link https://www.webmproject.org/ | WebM} format using
* the {@link https://www.webmproject.org/vp9/ | VP9} video codec. The FPS is 30.
*
* You must have {@link https://ffmpeg.org/ | ffmpeg} installed on your system.
*
* @example

@@ -777,2 +777,9 @@ * Recording a {@link Page | page}:

* @experimental
*
* @remarks
*
* All recordings will be {@link https://www.webmproject.org/ | WebM} format using
* the {@link https://www.webmproject.org/vp9/ | VP9} video codec. The FPS is 30.
*
* You must have {@link https://ffmpeg.org/ | ffmpeg} installed on your system.
*/

@@ -900,149 +907,67 @@ async screencast(options = {}) {

async screenshot(userOptions = {}) {
const env_2 = { stack: [], error: void 0, hasError: false };
try {
await this.bringToFront();
// TODO: use structuredClone after Node 16 support is dropped.«
const options = {
...userOptions,
clip: userOptions.clip
? {
...userOptions.clip,
}
: undefined,
};
if (options.type === undefined && options.path !== undefined) {
const filePath = options.path;
// Note we cannot use Node.js here due to browser compatability.
const extension = filePath
.slice(filePath.lastIndexOf('.') + 1)
.toLowerCase();
switch (extension) {
case 'png':
options.type = 'png';
break;
case 'jpeg':
case 'jpg':
options.type = 'jpeg';
break;
case 'webp':
options.type = 'webp';
break;
await this.bringToFront();
// TODO: use structuredClone after Node 16 support is dropped.
const options = {
...userOptions,
clip: userOptions.clip
? {
...userOptions.clip,
}
: undefined,
};
if (options.type === undefined && options.path !== undefined) {
const filePath = options.path;
// Note we cannot use Node.js here due to browser compatability.
const extension = filePath
.slice(filePath.lastIndexOf('.') + 1)
.toLowerCase();
switch (extension) {
case 'png':
options.type = 'png';
break;
case 'jpeg':
case 'jpg':
options.type = 'jpeg';
break;
case 'webp':
options.type = 'webp';
break;
}
if (options.quality !== undefined) {
if (options.quality < 0 && options.quality > 100) {
throw new Error(`Expected 'quality' (${options.quality}) to be between 0 and 100, inclusive.`);
}
if (options.type === undefined ||
!['jpeg', 'webp'].includes(options.type)) {
throw new Error(`${options.type ?? 'png'} screenshots do not support 'quality'.`);
}
}
if (options.quality !== undefined) {
if (options.quality < 0 && options.quality > 100) {
throw new Error(`Expected 'quality' (${options.quality}) to be between 0 and 100, inclusive.`);
}
assert(!options.clip || !options.fullPage, "'clip' and 'fullPage' are exclusive");
if (options.clip) {
if (options.clip.width <= 0) {
throw new Error("'width' in 'clip' must be positive.");
}
if (options.clip.height <= 0) {
throw new Error("'height' in 'clip' must be positive.");
}
if (options.type === undefined ||
!['jpeg', 'webp'].includes(options.type)) {
throw new Error(`${options.type ?? 'png'} screenshots do not support 'quality'.`);
}
setDefaultScreenshotOptions(options);
options.clip =
options.clip && roundRectangle(normalizeRectangle(options.clip));
const stack = __addDisposableResource(env_2, new AsyncDisposableStack(), true);
if (options.allowViewportExpansion || options.captureBeyondViewport) {
if (options.fullPage) {
const dimensions = await this.mainFrame()
.isolatedRealm()
.evaluate(() => {
const { scrollHeight, scrollWidth } = document.documentElement;
const { height: viewportHeight, width: viewportWidth } = window.visualViewport;
return {
height: Math.max(scrollHeight, viewportHeight),
width: Math.max(scrollWidth, viewportWidth),
};
});
options.clip = { ...dimensions, x: 0, y: 0 };
stack.use(await this._createTemporaryViewportContainingBox(options.clip));
}
else if (options.clip && !options.captureBeyondViewport) {
stack.use(options.clip &&
(await this._createTemporaryViewportContainingBox(options.clip)));
}
else if (!options.clip) {
options.captureBeyondViewport = false;
}
}
if (options.clip) {
if (options.clip.width <= 0) {
throw new Error("'width' in 'clip' must be positive.");
}
const data = await this._screenshot(options);
if (options.encoding === 'base64') {
return data;
if (options.clip.height <= 0) {
throw new Error("'height' in 'clip' must be positive.");
}
const buffer = Buffer.from(data, 'base64');
await this._maybeWriteBufferToFile(options.path, buffer);
return buffer;
}
catch (e_2) {
env_2.error = e_2;
env_2.hasError = true;
}
finally {
const result_1 = __disposeResources(env_2);
if (result_1)
await result_1;
}
}
/**
* @internal
*/
async _createTemporaryViewportContainingBox(clip) {
const env_3 = { stack: [], error: void 0, hasError: false };
try {
const viewport = await this.mainFrame()
.isolatedRealm()
.evaluate(() => {
return {
pageLeft: window.visualViewport.pageLeft,
pageTop: window.visualViewport.pageTop,
width: window.visualViewport.width,
height: window.visualViewport.height,
};
});
const stack = __addDisposableResource(env_3, new AsyncDisposableStack(), true);
if (clip.x < viewport.pageLeft || clip.y < viewport.pageTop) {
await this.evaluate((left, top) => {
window.scroll({ left, top, behavior: 'instant' });
}, Math.floor(clip.x), Math.floor(clip.y));
stack.defer(async () => {
await this.evaluate((left, top) => {
window.scroll({ left, top, behavior: 'instant' });
}, viewport.pageLeft, viewport.pageTop).catch(debugError);
});
setDefaultScreenshotOptions(options);
options.clip =
options.clip && roundRectangle(normalizeRectangle(options.clip));
if (options.fullPage) {
if (options.clip) {
throw new Error("'clip' and 'fullPage' are exclusive");
}
if (clip.width + clip.x > viewport.width ||
clip.height + clip.y > viewport.height) {
const originalViewport = this.viewport() ?? {
width: 0,
height: 0,
};
// We add 1 for fractional x and y.
await this.setViewport({
width: Math.max(viewport.width, Math.ceil(clip.width + clip.x)),
height: Math.max(viewport.height, Math.ceil(clip.height + clip.y)),
});
stack.defer(async () => {
await this.setViewport(originalViewport).catch(debugError);
});
}
return stack.move();
}
catch (e_3) {
env_3.error = e_3;
env_3.hasError = true;
else if (!options.clip &&
userOptions.captureBeyondViewport === undefined) {
options.captureBeyondViewport = false;
}
finally {
const result_2 = __disposeResources(env_3);
if (result_2)
await result_2;
const data = await this._screenshot(options);
if (options.encoding === 'base64') {
return data;
}
const buffer = Buffer.from(data, 'base64');
await this._maybeWriteBufferToFile(options.path, buffer);
return buffer;
}

@@ -1097,2 +1022,3 @@ /**

* @remarks
*
* Shortcut for {@link Frame.title | page.mainFrame().title()}.

@@ -1108,3 +1034,6 @@ */

* error.
* @remarks Bear in mind that if `click()` triggers a navigation event and
*
* @remarks
*
* Bear in mind that if `click()` triggers a navigation event and
* there's a separate `page.waitForNavigation()` promise to be resolved, you

@@ -1142,3 +1071,5 @@ * may end up with a race condition that yields unexpected results. The

* matching selector.
*
* @remarks
*
* Shortcut for {@link Frame.focus | page.mainFrame().focus(selector)}.

@@ -1161,3 +1092,5 @@ */

* `selector`.
*
* @remarks
*
* Shortcut for {@link Page.hover | page.mainFrame().hover(selector)}.

@@ -1189,2 +1122,3 @@ */

* @remarks
*
* Shortcut for {@link Frame.select | page.mainFrame().select()}

@@ -1204,4 +1138,5 @@ */

* selector, the first will be tapped.
* @returns
*
* @remarks
*
* Shortcut for {@link Frame.tap | page.mainFrame().tap(selector)}.

@@ -1234,3 +1169,2 @@ */

* @returns
* @remarks
*/

@@ -1246,2 +1180,3 @@ type(selector, text, options) {

* @remarks
*
* It's generally recommended to not wait for a number of seconds, but instead

@@ -1300,2 +1235,3 @@ * use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or

* selector is not found in DOM.
*
* @remarks

@@ -1302,0 +1238,0 @@ * The optional Parameter in Arguments `options` are:

@@ -21,3 +21,5 @@ /**

*/
export declare function connectBidiOverCdp(cdp: CdpConnection): Promise<BidiConnection>;
export declare function connectBidiOverCdp(cdp: CdpConnection, options: {
acceptInsecureCerts: boolean;
}): Promise<BidiConnection>;
//# sourceMappingURL=BidiOverCdp.d.ts.map

@@ -26,3 +26,6 @@ /**

*/
export async function connectBidiOverCdp(cdp) {
export async function connectBidiOverCdp(cdp,
// TODO: replace with `BidiMapper.MapperOptions`, once it's exported in
// https://github.com/puppeteer/puppeteer/pull/11415.
options) {
const transportBiDi = new NoOpTransport();

@@ -38,2 +41,3 @@ const cdpConnectionAdapter = new CdpConnectionAdapter(cdp);

cdpConnectionAdapter.close();
cdp.dispose();
},

@@ -51,3 +55,3 @@ onmessage(_message) {

// TODO: most likely need a little bit of refactoring
cdpConnectionAdapter.browserClient(), '', undefined, bidiServerLogger);
cdpConnectionAdapter.browserClient(), '', options, undefined, bidiServerLogger);
return pptrBiDiConnection;

@@ -62,9 +66,9 @@ }

#adapters = new Map();
#browser;
#browserCdpConnection;
constructor(cdp) {
this.#cdp = cdp;
this.#browser = new CDPClientAdapter(cdp);
this.#browserCdpConnection = new CDPClientAdapter(cdp);
}
browserClient() {
return this.#browser;
return this.#browserCdpConnection;
}

@@ -77,3 +81,3 @@ getCdpClient(id) {

if (!this.#adapters.has(session)) {
const adapter = new CDPClientAdapter(session, id, this.#browser);
const adapter = new CDPClientAdapter(session, id, this.#browserCdpConnection);
this.#adapters.set(session, adapter);

@@ -85,3 +89,3 @@ return adapter;

close() {
this.#browser.close();
this.#browserCdpConnection.close();
for (const adapter of this.#adapters.values()) {

@@ -88,0 +92,0 @@ adapter.close();

@@ -64,4 +64,4 @@ /**

target(): Target;
disconnect(): void;
disconnect(): Promise<void>;
}
//# sourceMappingURL=Browser.d.ts.map

@@ -186,5 +186,6 @@ /**

}
await this.#connection.send('browser.close', {});
// `browser.close` can close connection before the response is received.
await this.#connection.send('browser.close', {}).catch(debugError);
await this.#closeCallback?.call(null);
this.#connection.dispose();
await this.#closeCallback?.call(null);
}

@@ -243,6 +244,13 @@ get connected() {

}
disconnect() {
this;
async disconnect() {
try {
// Fail silently if the session cannot be ended.
await this.#connection.send('session.end', {});
}
catch (e) {
debugError(e);
}
this.#connection.dispose();
}
}
//# sourceMappingURL=Browser.js.map

@@ -88,2 +88,6 @@ /**

};
'browsingContext.traverseHistory': {
params: Bidi.BrowsingContext.TraverseHistoryParameters;
returnType: Bidi.EmptyResult;
};
'input.performActions': {

@@ -97,2 +101,6 @@ params: Bidi.Input.PerformActionsParameters;

};
'session.end': {
params: Bidi.EmptyParams;
returnType: Bidi.EmptyResult;
};
'session.new': {

@@ -150,4 +158,13 @@ params: Bidi.Session.NewParameters;

unregisterBrowsingContexts(id: string): void;
/**
* Unbinds the connection, but keeps the transport open. Useful when the transport will
* be reused by other connection e.g. with different protocol.
* @internal
*/
unbind(): void;
/**
* Unbinds the connection and closes the transport.
*/
dispose(): void;
}
//# sourceMappingURL=Connection.d.ts.map

@@ -20,2 +20,3 @@ /**

import { debugError } from '../common/util.js';
import { assert } from '../util/assert.js';
import { cdpSessions } from './BrowsingContext.js';

@@ -42,3 +43,3 @@ const debugProtocolSend = debug('puppeteer:webDriverBiDi:SEND ►');

this.#transport.onmessage = this.onMessage.bind(this);
this.#transport.onclose = this.#onClose.bind(this);
this.#transport.onclose = this.unbind.bind(this);
}

@@ -52,2 +53,3 @@ get closed() {

send(method, params) {
assert(!this.#closed, 'Protocol error: Connection closed.');
return this.#callbacks.create(method, this.#timeout, id => {

@@ -86,2 +88,8 @@ const stringifiedMessage = JSON.stringify({

case 'event':
if (isCdpEvent(object)) {
cdpSessions
.get(object.params.session)
?.emit(object.params.event, object.params.params);
return;
}
this.#maybeEmitOnContext(object);

@@ -93,2 +101,7 @@ // SAFETY: We know the method and parameter still match here.

}
// Even if the response in not in BiDi protocol format but `id` is provided, reject
// the callback. This can happen if the endpoint supports CDP instead of BiDi.
if ('id' in object) {
this.#callbacks.reject(object.id, `Protocol Error. Message is not in BiDi protocol format: '${message}'`, object.message);
}
debugError(object);

@@ -107,7 +120,2 @@ }

}
else if (isCdpEvent(event)) {
cdpSessions
.get(event.params.session)
?.emit(event.params.event, event.params.params);
}
context?.emit(event.method, event.params);

@@ -142,3 +150,8 @@ }

}
#onClose() {
/**
* Unbinds the connection, but keeps the transport open. Useful when the transport will
* be reused by other connection e.g. with different protocol.
* @internal
*/
unbind() {
if (this.#closed) {

@@ -151,6 +164,10 @@ return;

this.#transport.onclose = () => { };
this.#browsingContexts.clear();
this.#callbacks.clear();
}
/**
* Unbinds the connection and closes the transport.
*/
dispose() {
this.#onClose();
this.unbind();
this.#transport.close();

@@ -157,0 +174,0 @@ }

@@ -17,5 +17,7 @@ /**

import type { CDPSession } from '../api/CDPSession.js';
import type { ElementHandle } from '../api/ElementHandle.js';
import { Frame, type GoToOptions, type WaitForOptions } from '../api/Frame.js';
import type { WaitForSelectorOptions } from '../api/Page.js';
import type { TimeoutSettings } from '../common/TimeoutSettings.js';
import type { Awaitable } from '../common/types.js';
import type { Awaitable, NodeFor } from '../common/types.js';
import { disposeSymbol } from '../util/disposable.js';

@@ -51,3 +53,4 @@ import type { BrowsingContext } from './BrowsingContext.js';

exposeFunction<Args extends unknown[], Ret>(name: string, apply: (...args: Args) => Awaitable<Ret>): Promise<void>;
waitForSelector<Selector extends string>(selector: Selector, options?: WaitForSelectorOptions): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
//# sourceMappingURL=Frame.d.ts.map

@@ -54,3 +54,3 @@ /**

import { UnsupportedOperation } from '../common/Errors.js';
import { UTILITY_WORLD_NAME, setPageContent, timeout } from '../common/util.js';
import { UTILITY_WORLD_NAME, timeout } from '../common/util.js';
import { Deferred } from '../util/Deferred.js';

@@ -141,3 +141,3 @@ import { disposeSymbol } from '../util/disposable.js';

fromEvent(this.#context, waitEvent).pipe(first()),
from(setPageContent(this, html)),
from(this.setFrameContent(html)),
]).pipe(map(() => {

@@ -200,2 +200,8 @@ return null;

}
waitForSelector(selector, options) {
if (selector.startsWith('aria')) {
throw new UnsupportedOperation('ARIA selector is not supported for BiDi!');
}
return super.waitForSelector(selector, options);
}
};

@@ -202,0 +208,0 @@ })();

@@ -24,2 +24,3 @@ /**

import type { WaitForOptions } from '../api/Frame.js';
import type { HTTPResponse } from '../api/HTTPResponse.js';
import { Page, type GeolocationOptions, type MediaFeature, type NewDocumentScriptEvaluation, type ScreenshotOptions } from '../api/Page.js';

@@ -42,2 +43,3 @@ import { Accessibility } from '../cdp/Accessibility.js';

import type { BiDiNetworkIdle } from './lifecycle.js';
import type { BiDiPageTarget } from './Target.js';
/**

@@ -49,3 +51,3 @@ * @internal

_client(): CDPSession;
constructor(browsingContext: BrowsingContext, browserContext: BidiBrowserContext);
constructor(browsingContext: BrowsingContext, browserContext: BidiBrowserContext, target: BiDiPageTarget);
/**

@@ -77,3 +79,5 @@ * @internal

isClosed(): boolean;
close(): Promise<void>;
close(options?: {
runBeforeUnload?: boolean;
}): Promise<void>;
reload(options?: WaitForOptions): Promise<BidiHTTPResponse | null>;

@@ -126,3 +130,3 @@ setDefaultNavigationTimeout(timeout: number): void;

isServiceWorkerBypassed(): never;
target(): never;
target(): BiDiPageTarget;
waitForFileChooser(): never;

@@ -142,6 +146,6 @@ workers(): never;

metrics(): never;
goBack(): never;
goForward(): never;
goBack(options?: WaitForOptions): Promise<HTTPResponse | null>;
goForward(options?: WaitForOptions): Promise<HTTPResponse | null>;
waitForDevicePrompt(): never;
}
//# sourceMappingURL=Page.d.ts.map

@@ -75,2 +75,3 @@ /**

import { disposeSymbol } from '../util/disposable.js';
import { isErrorLike } from '../util/ErrorLike.js';
import { BrowsingContextEvent, CdpSessionWrapper, } from './BrowsingContext.js';

@@ -154,9 +155,11 @@ import { BidiDeserializer } from './Deserializer.js';

#browserContext;
#target;
_client() {
return this.mainFrame().context().cdpSession;
}
constructor(browsingContext, browserContext) {
constructor(browsingContext, browserContext, target) {
super();
this.#browsingContext = browsingContext;
this.#browserContext = browserContext;
this.#target = target;
this.#connection = browsingContext.connection;

@@ -391,3 +394,3 @@ for (const [event, subscriber] of this.#browsingContextEvents) {

}
async close() {
async close(options) {
if (this.#closedDeferred.finished()) {

@@ -400,2 +403,3 @@ return;

context: this.mainFrame()._id,
promptUnload: options?.runBeforeUnload ?? false,
});

@@ -502,6 +506,3 @@ this.emit("close" /* PageEvent.Close */, undefined);

async _screenshot(options) {
const { clip, type, captureBeyondViewport, allowViewportExpansion, quality } = options;
if (captureBeyondViewport && !allowViewportExpansion) {
throw new UnsupportedOperation(`BiDi does not support 'captureBeyondViewport'. Use 'allowViewportExpansion'.`);
}
const { clip, type, captureBeyondViewport, quality } = options;
if (options.omitBackground !== undefined && options.omitBackground) {

@@ -516,2 +517,24 @@ throw new UnsupportedOperation(`BiDi does not support 'omitBackground'.`);

}
let box;
if (clip) {
if (captureBeyondViewport) {
box = clip;
}
else {
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
];
});
box = {
...clip,
x: clip.x - pageLeft,
y: clip.y - pageTop,
};
}
}
if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) {

@@ -522,10 +545,8 @@ throw new UnsupportedOperation(`BiDi does not support 'scale' in 'clip'.`);

context: this.mainFrame()._id,
origin: captureBeyondViewport ? 'document' : 'viewport',
format: {
type: `image/${type}`,
quality: quality ? quality / 100 : undefined,
...(quality !== undefined ? { quality: quality / 100 } : {}),
},
clip: clip && {
type: 'box',
...clip,
},
...(box ? { clip: { type: 'box', ...box } } : {}),
});

@@ -601,3 +622,3 @@ return data;

target() {
throw new UnsupportedOperation();
return this.#target;
}

@@ -647,8 +668,29 @@ waitForFileChooser() {

}
goBack() {
throw new UnsupportedOperation();
async goBack(options = {}) {
return await this.#go(-1, options);
}
goForward() {
throw new UnsupportedOperation();
async goForward(options = {}) {
return await this.#go(+1, options);
}
async #go(delta, options) {
try {
const result = await Promise.all([
this.waitForNavigation(options),
this.#connection.send('browsingContext.traverseHistory', {
delta,
context: this.mainFrame()._id,
}),
]);
return result[0];
}
catch (err) {
// TODO: waitForNavigation should be cancelled if an error happens.
if (isErrorLike(err)) {
if (err.message.includes('no such history entry')) {
return null;
}
}
throw err;
}
}
waitForDevicePrompt() {

@@ -655,0 +697,0 @@ throw new UnsupportedOperation();

@@ -89,3 +89,3 @@ /**

super(browserContext, browsingContext);
this.#page = new BidiPage(browsingContext, browserContext);
this.#page = new BidiPage(browsingContext, browserContext, this);
}

@@ -92,0 +92,0 @@ async page() {

@@ -51,3 +51,3 @@ /**

close(): Promise<void>;
disconnect(): void;
disconnect(): Promise<void>;
get connected(): boolean;

@@ -54,0 +54,0 @@ }

@@ -231,3 +231,3 @@ /**

await this.#closeCallback.call(null);
this.disconnect();
await this.disconnect();
}

@@ -238,2 +238,3 @@ disconnect() {

this._detach();
return Promise.resolve();
}

@@ -240,0 +241,0 @@ get connected() {

@@ -16,3 +16,3 @@ /**

*/
import type { BidiBrowser } from '../bidi/Browser.js';
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
import type { BrowserConnectOptions, ConnectOptions } from '../common/ConnectOptions.js';

@@ -26,10 +26,3 @@ import { CdpBrowser } from './Browser.js';

*/
export declare function _connectToCdpBrowser(options: BrowserConnectOptions & ConnectOptions): Promise<CdpBrowser>;
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
*
* @internal
*/
export declare function _connectToBiDiOverCdpBrowser(options: BrowserConnectOptions & ConnectOptions): Promise<BidiBrowser>;
export declare function _connectToCdpBrowser(connectionTransport: ConnectionTransport, url: string, options: BrowserConnectOptions & ConnectOptions): Promise<CdpBrowser>;
//# sourceMappingURL=BrowserConnector.d.ts.map

@@ -16,17 +16,5 @@ /**

*/
import { UnsupportedOperation } from '../common/Errors.js';
import { getFetch } from '../common/fetch.js';
import { debugError } from '../common/util.js';
import { isNode } from '../environment.js';
import { assert } from '../util/assert.js';
import { isErrorLike } from '../util/ErrorLike.js';
import { debugError, DEFAULT_VIEWPORT } from '../common/util.js';
import { CdpBrowser } from './Browser.js';
import { Connection } from './Connection.js';
const DEFAULT_VIEWPORT = Object.freeze({ width: 800, height: 600 });
const getWebSocketTransportClass = async () => {
return isNode
? (await import('../node/NodeWebSocketTransport.js')).NodeWebSocketTransport
: (await import('../common/BrowserWebSocketTransport.js'))
.BrowserWebSocketTransport;
};
/**

@@ -38,5 +26,5 @@ * Users should never call this directly; it's called when calling

*/
export async function _connectToCdpBrowser(options) {
const { ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT, targetFilter, _isPageTarget: isPageTarget, } = options;
const connection = await getCdpConnection(options);
export async function _connectToCdpBrowser(connectionTransport, url, options) {
const { ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT, targetFilter, _isPageTarget: isPageTarget, slowMo = 0, protocolTimeout, } = options;
const connection = new Connection(url, connectionTransport, slowMo, protocolTimeout);
const version = await connection.send('Browser.getVersion');

@@ -52,74 +40,2 @@ const product = version.product.toLowerCase().includes('firefox')

}
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
*
* @internal
*/
export async function _connectToBiDiOverCdpBrowser(options) {
const { ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT } = options;
const connection = await getCdpConnection(options);
const version = await connection.send('Browser.getVersion');
if (version.product.toLowerCase().includes('firefox')) {
throw new UnsupportedOperation('Firefox is not supported in BiDi over CDP mode.');
}
// TODO: use other options too.
const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiBrowser = await BiDi.BidiBrowser.create({
connection: bidiConnection,
closeCallback: () => {
return connection.send('Browser.close').catch(debugError);
},
process: undefined,
defaultViewport: defaultViewport,
ignoreHTTPSErrors: ignoreHTTPSErrors,
});
return bidiBrowser;
}
async function getWSEndpoint(browserURL) {
const endpointURL = new URL('/json/version', browserURL);
const fetch = await getFetch();
try {
const result = await fetch(endpointURL.toString(), {
method: 'GET',
});
if (!result.ok) {
throw new Error(`HTTP ${result.statusText}`);
}
const data = await result.json();
return data.webSocketDebuggerUrl;
}
catch (error) {
if (isErrorLike(error)) {
error.message =
`Failed to fetch browser webSocket URL from ${endpointURL}: ` +
error.message;
}
throw error;
}
}
/**
* Returns a CDP connection for the given options.
*/
async function getCdpConnection(options) {
const { browserWSEndpoint, browserURL, transport, headers = {}, slowMo = 0, protocolTimeout, } = options;
assert(Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
if (transport) {
return new Connection('', transport, slowMo, protocolTimeout);
}
else if (browserWSEndpoint) {
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(browserWSEndpoint, headers);
return new Connection(browserWSEndpoint, connectionTransport, slowMo, protocolTimeout);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(connectionURL);
return new Connection(connectionURL, connectionTransport, slowMo, protocolTimeout);
}
throw new Error('Invalid connection options');
}
//# sourceMappingURL=BrowserConnector.js.map

@@ -52,3 +52,2 @@ /**

import { UnsupportedOperation } from '../common/Errors.js';
import { setPageContent } from '../common/util.js';
import { Deferred } from '../util/Deferred.js';

@@ -214,3 +213,5 @@ import { disposeSymbol } from '../util/disposable.js';

const { waitUntil = ['load'], timeout = this._frameManager.timeoutSettings.navigationTimeout(), } = options;
await setPageContent(this.isolatedRealm(), html);
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.setFrameContent(html);
const watcher = new LifecycleWatcher(this._frameManager.networkManager, this, waitUntil, timeout);

@@ -217,0 +218,0 @@ const error = await Deferred.race([

@@ -136,3 +136,2 @@ /**

}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = __addDisposableResource(env_1, await this.#mutex.acquire(), false);

@@ -139,0 +138,0 @@ try {

@@ -5,2 +5,6 @@ import type { IsPageTargetCallback, TargetFilterCallback } from '../api/Browser.js';

/**
* @public
*/
export type ProtocolType = 'cdp' | 'webDriverBiDi';
/**
* Generic browser options that can be passed when launching any browser or when

@@ -18,2 +22,4 @@ * connecting to an existing browser instance.

* Sets the viewport for each page.
*
* @defaultValue '\{width: 800, height: 600\}'
*/

@@ -36,5 +42,5 @@ defaultViewport?: Viewport | null;

* @defaultValue 'cdp'
* @internal
* @public
*/
protocol?: 'cdp' | 'webDriverBiDi';
protocol?: ProtocolType;
/**

@@ -41,0 +47,0 @@ * Timeout setting for individual protocol (CDP) calls.

@@ -16,3 +16,3 @@ /**

*/
import { _connectToBiDiOverCdpBrowser, _connectToCdpBrowser, } from '../cdp/BrowserConnector.js';
import { _connectToBrowser } from './BrowserConnector.js';
import { customQueryHandlers, } from './CustomQueryHandler.js';

@@ -104,10 +104,5 @@ /**

connect(options) {
if (options.protocol === 'webDriverBiDi') {
return _connectToBiDiOverCdpBrowser(options);
}
else {
return _connectToCdpBrowser(options);
}
return _connectToBrowser(options);
}
}
//# sourceMappingURL=Puppeteer.js.map

@@ -25,3 +25,2 @@ /**

import type { CDPSession } from '../api/CDPSession.js';
import type { Page } from '../api/Page.js';
import type { Deferred } from '../util/Deferred.js';

@@ -37,2 +36,9 @@ import type { EventEmitter, EventType } from './EventEmitter.js';

*/
export declare const DEFAULT_VIEWPORT: Readonly<{
width: 800;
height: 600;
}>;
/**
* @internal
*/
export declare function createEvaluationError(details: Protocol.Runtime.ExceptionDetails): unknown;

@@ -115,6 +121,2 @@ /**

*/
export declare function setPageContent(page: Pick<Page, 'evaluate'>, content: string): Promise<void>;
/**
* @internal
*/
export declare function getPageContent(): string;

@@ -121,0 +123,0 @@ /**

@@ -29,2 +29,6 @@ /**

*/
export const DEFAULT_VIEWPORT = Object.freeze({ width: 800, height: 600 });
/**
* @internal
*/
export function createEvaluationError(details) {

@@ -403,14 +407,2 @@ let name;

*/
export async function setPageContent(page, content) {
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
return await page.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
/**
* @internal
*/
export function getPageContent() {

@@ -417,0 +409,0 @@ let content = '';

/**
* @internal
*/
export declare const packageVersion = "21.5.2";
export declare const packageVersion = "21.6.0";
//# sourceMappingURL=version.d.ts.map
/**
* @internal
*/
export const packageVersion = '21.5.2';
export const packageVersion = '21.6.0';
//# sourceMappingURL=version.js.map

@@ -17,2 +17,3 @@ /**

import { mkdtemp } from 'fs/promises';
import os from 'os';
import path from 'path';

@@ -46,2 +47,17 @@ import { computeSystemExecutablePath, Browser as SupportedBrowsers, ChromeReleaseChannel as BrowsersChromeReleaseChannel, } from '@puppeteer/browsers';

}
if (this.puppeteer.configuration.logLevel === 'warn' &&
process.platform === 'darwin' &&
process.arch === 'x64') {
const cpus = os.cpus();
if (cpus[0]?.model.includes('Apple')) {
console.warn([
'\x1B[1m\x1B[43m\x1B[30m',
'Degraded performance warning:\x1B[0m\x1B[33m',
'Launching Chrome on Mac Silicon (arm64) from an x64 Node installation results in',
'Rosetta translating the Chrome binary, even if Chrome is already arm64. This would',
'result in huge performance issues. To resolve this, you must run Puppeteer with',
'a version of Node built for arm64.',
].join('\n '));
}
}
return super.launch(options);

@@ -48,0 +64,0 @@ }

@@ -80,3 +80,17 @@ /**

path: userDataDir,
preferences: extraPrefsFirefox,
preferences: {
...extraPrefsFirefox,
...(options.protocol === 'cdp'
? {
// Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
'fission.bfcacheInParent': false,
}
: {}),
// Force all web content to use a single content process. TODO: remove
// this once Firefox supports mouse event dispatch from the main frame
// context. Once this happens, webContentIsolationStrategy should only
// be set for CDP. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1773393
'fission.webContentIsolationStrategy': 0,
},
});

@@ -83,0 +97,0 @@ let firefoxExecutable;

@@ -59,3 +59,3 @@ import { launch } from '@puppeteer/browsers';

*/
protected closeBrowser(browserProcess: ReturnType<typeof launch>, connection?: Connection): Promise<void>;
protected closeBrowser(browserProcess: ReturnType<typeof launch>, cdpConnection?: Connection): Promise<void>;
/**

@@ -62,0 +62,0 @@ * @internal

@@ -23,3 +23,3 @@ /**

import { TimeoutError } from '../common/Errors.js';
import { debugError } from '../common/util.js';
import { debugError, DEFAULT_VIEWPORT } from '../common/util.js';
import { NodeWebSocketTransport as WebSocketTransport } from './NodeWebSocketTransport.js';

@@ -53,3 +53,3 @@ import { PipeTransport } from './PipeTransport.js';

async launch(options = {}) {
const { dumpio = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, slowMo = 0, timeout = 30000, waitForInitialPage = true, protocol, protocolTimeout, } = options;
const { dumpio = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT, slowMo = 0, timeout = 30000, waitForInitialPage = true, protocolTimeout, protocol, } = options;
const launchArgs = await this.computeLaunchArguments(options);

@@ -74,3 +74,3 @@ const usePipe = launchArgs.args.includes('--remote-debugging-pipe');

let browser;
let connection;
let cdpConnection;
let closing = false;

@@ -82,3 +82,3 @@ const browserCloseCallback = async () => {

closing = true;
await this.closeBrowser(browserProcess, connection);
await this.closeBrowser(browserProcess, cdpConnection);
};

@@ -97,3 +97,3 @@ try {

if (usePipe) {
connection = await this.createCdpPipeConnection(browserProcess, {
cdpConnection = await this.createCdpPipeConnection(browserProcess, {
timeout,

@@ -105,3 +105,3 @@ protocolTimeout,

else {
connection = await this.createCdpSocketConnection(browserProcess, {
cdpConnection = await this.createCdpSocketConnection(browserProcess, {
timeout,

@@ -113,3 +113,3 @@ protocolTimeout,

if (protocol === 'webDriverBiDi') {
browser = await this.createBiDiOverCdpBrowser(browserProcess, connection, browserCloseCallback, {
browser = await this.createBiDiOverCdpBrowser(browserProcess, cdpConnection, browserCloseCallback, {
timeout,

@@ -123,3 +123,3 @@ protocolTimeout,

else {
browser = await CdpBrowser._create(this.product, connection, [], ignoreHTTPSErrors, defaultViewport, browserProcess.nodeProcess, browserCloseCallback, options.targetFilter);
browser = await CdpBrowser._create(this.product, cdpConnection, [], ignoreHTTPSErrors, defaultViewport, browserProcess.nodeProcess, browserCloseCallback, options.targetFilter);
}

@@ -151,7 +151,7 @@ }

*/
async closeBrowser(browserProcess, connection) {
if (connection) {
async closeBrowser(browserProcess, cdpConnection) {
if (cdpConnection) {
// Attempt to close the browser gracefully
try {
await connection.closeBrowser();
await cdpConnection.closeBrowser();
await browserProcess.hasClosed();

@@ -206,3 +206,5 @@ }

const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiConnection = await BiDi.connectBidiOverCdp(connection, {
acceptInsecureCerts: opts.ignoreHTTPSErrors ?? false,
});
return await BiDi.BidiBrowser.create({

@@ -271,3 +273,3 @@ connection: bidiConnection,

throw new Error(`Could not find Chrome (ver. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation before running the script (e.g. `npm install`) or\n' +
' 1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -277,3 +279,3 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');

throw new Error(`Could not find Firefox (rev. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation for Firefox before running the script (e.g. `PUPPETEER_PRODUCT=firefox npm install`) or\n' +
' 1. you did not perform an installation for Firefox before running the script (e.g. `npx puppeteer browsers install firefox`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -280,0 +282,0 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');

@@ -118,3 +118,3 @@ /**

* describes some differences for Linux users. See
* {@link https://goo.gle/chrome-for-testing | this doc} for the description
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.

@@ -121,0 +121,0 @@ *

@@ -131,3 +131,3 @@ /**

* describes some differences for Linux users. See
* {@link https://goo.gle/chrome-for-testing | this doc} for the description
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.

@@ -134,0 +134,0 @@ *

{
"name": "puppeteer-core",
"version": "21.5.2",
"version": "21.6.0",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",

@@ -121,4 +121,4 @@ "keywords": [

"dependencies": {
"@puppeteer/browsers": "1.8.0",
"chromium-bidi": "0.4.33",
"@puppeteer/browsers": "1.9.0",
"chromium-bidi": "0.5.1",
"cross-fetch": "4.0.0",

@@ -132,3 +132,3 @@ "debug": "4.3.4",

"@types/node": "18.17.15",
"@types/ws": "8.5.9",
"@types/ws": "8.5.10",
"mitt": "3.0.1",

@@ -135,0 +135,0 @@ "parsel-js": "1.1.2",

@@ -49,3 +49,3 @@ # Puppeteer

When you install Puppeteer, it automatically downloads a recent version of
[Chrome for Testing](https://goo.gle/chrome-for-testing) (~170MB macOS, ~282MB Linux, ~280MB Windows) that is [guaranteed to
[Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) (~170MB macOS, ~282MB Linux, ~280MB Windows) that is [guaranteed to
work](https://pptr.dev/faq#q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy)

@@ -52,0 +52,0 @@ with Puppeteer. The browser is downloaded to the `$HOME/.cache/puppeteer` folder

@@ -30,2 +30,3 @@ /**

} from '../../third_party/rxjs/rxjs.js';
import type {ProtocolType} from '../common/ConnectOptions.js';
import {EventEmitter, type EventType} from '../common/EventEmitter.js';

@@ -231,3 +232,3 @@ import {debugError} from '../common/util.js';

* // Disconnect puppeteer from the browser.
* browser.disconnect();
* await browser.disconnect();
*

@@ -304,3 +305,3 @@ * // Use the endpoint to reestablish a connection

* You can find the debugger URL (`webSocketDebuggerUrl`) from
* `http://${host}:${port}/json/version`.
* `http://HOST:PORT/json/version`.
*

@@ -311,3 +312,3 @@ * See {@link

*
* @remarks The format is always `ws://${host}:${port}/devtools/browser/<id>`.
* @remarks The format is always `ws://HOST:PORT/devtools/browser/<id>`.
*/

@@ -406,2 +407,3 @@ abstract wsEndpoint(): string;

* {@link Page.setUserAgent}.
*
*/

@@ -420,3 +422,3 @@ abstract userAgent(): Promise<string>;

*/
abstract disconnect(): void;
abstract disconnect(): Promise<void>;

@@ -450,3 +452,3 @@ /**

*/
abstract get protocol(): 'cdp' | 'webDriverBiDi';
abstract get protocol(): ProtocolType;
}

@@ -112,3 +112,3 @@ /**

/**
* @defaultValue true
* @defaultValue `true`
*/

@@ -966,3 +966,2 @@ scrollIntoView?: boolean;

* absolute.
*
*/

@@ -1351,7 +1350,3 @@ abstract uploadFile(

): Promise<string | Buffer> {
const {
scrollIntoView = true,
captureBeyondViewport = true,
allowViewportExpansion = captureBeyondViewport,
} = options;
const {scrollIntoView = true} = options;

@@ -1362,8 +1357,2 @@ let clip = await this.#nonEmptyVisibleBoundingBox();

// eslint-disable-next-line @typescript-eslint/no-unused-vars
await using _ =
allowViewportExpansion && clip
? await page._createTemporaryViewportContainingBox(clip)
: null;
if (scrollIntoView) {

@@ -1388,7 +1377,3 @@ await this.scrollIntoViewIfNeeded();

return await page.screenshot({
...options,
captureBeyondViewport: false,
clip,
});
return await page.screenshot({...options, clip});
}

@@ -1395,0 +1380,0 @@

@@ -808,2 +808,13 @@ /**

/**
* @internal
*/
async setFrameContent(content: string): Promise<void> {
return await this.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
/**
* The frame's `name` attribute as specified in the tag.

@@ -810,0 +821,0 @@ *

@@ -297,9 +297,2 @@ /**

*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example

@@ -320,5 +313,11 @@ *

* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
* @param priority - If provided, intercept is resolved using cooperative
* handling rules. Otherwise, intercept is resolved immediately.
*
* @remarks
*
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/

@@ -333,9 +332,2 @@ abstract continue(

*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example

@@ -362,2 +354,9 @@ * An example of fulfilling all requests with 404 responses:

* immediately.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*/

@@ -372,11 +371,12 @@ abstract respond(

*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*
* @remarks
*
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/

@@ -383,0 +383,0 @@ abstract abort(errorCode?: ErrorCode, priority?: number): Promise<void>;

@@ -222,7 +222,6 @@ /**

/**
* @deprecated Use {@link MouseClickOptions.count}.
*
* Determines the click count for the mouse event. This does not perform
* multiple clicks.
*
* @deprecated Use {@link MouseClickOptions.count}.
* @defaultValue `1`

@@ -229,0 +228,0 @@ */

@@ -37,3 +37,6 @@ /**

export async function connectBidiOverCdp(
cdp: CdpConnection
cdp: CdpConnection,
// TODO: replace with `BidiMapper.MapperOptions`, once it's exported in
// https://github.com/puppeteer/puppeteer/pull/11415.
options: {acceptInsecureCerts: boolean}
): Promise<BidiConnection> {

@@ -50,2 +53,3 @@ const transportBiDi = new NoOpTransport();

cdpConnectionAdapter.close();
cdp.dispose();
},

@@ -67,2 +71,3 @@ onmessage(_message: string): void {

'',
options,
undefined,

@@ -81,11 +86,11 @@ bidiServerLogger

#adapters = new Map<CDPSession, CDPClientAdapter<CDPSession>>();
#browser: CDPClientAdapter<CdpConnection>;
#browserCdpConnection: CDPClientAdapter<CdpConnection>;
constructor(cdp: CdpConnection) {
this.#cdp = cdp;
this.#browser = new CDPClientAdapter(cdp);
this.#browserCdpConnection = new CDPClientAdapter(cdp);
}
browserClient(): CDPClientAdapter<CdpConnection> {
return this.#browser;
return this.#browserCdpConnection;
}

@@ -99,3 +104,7 @@

if (!this.#adapters.has(session)) {
const adapter = new CDPClientAdapter(session, id, this.#browser);
const adapter = new CDPClientAdapter(
session,
id,
this.#browserCdpConnection
);
this.#adapters.set(session, adapter);

@@ -108,3 +117,3 @@ return adapter;

close() {
this.#browser.close();
this.#browserCdpConnection.close();
for (const adapter of this.#adapters.values()) {

@@ -111,0 +120,0 @@ adapter.close();

@@ -256,5 +256,7 @@ /**

}
await this.#connection.send('browser.close', {});
// `browser.close` can close connection before the response is received.
await this.#connection.send('browser.close', {}).catch(debugError);
await this.#closeCallback?.call(null);
this.#connection.dispose();
await this.#closeCallback?.call(null);
}

@@ -327,5 +329,11 @@

override disconnect(): void {
this;
override async disconnect(): Promise<void> {
try {
// Fail silently if the session cannot be ended.
await this.#connection.send('session.end', {});
} catch (e) {
debugError(e);
}
this.#connection.dispose();
}
}

@@ -24,2 +24,3 @@ /**

import {debugError} from '../common/util.js';
import {assert} from '../util/assert.js';

@@ -101,2 +102,6 @@ import {type BrowsingContext, cdpSessions} from './BrowsingContext.js';

};
'browsingContext.traverseHistory': {
params: Bidi.BrowsingContext.TraverseHistoryParameters;
returnType: Bidi.EmptyResult;
};

@@ -112,2 +117,6 @@ 'input.performActions': {

'session.end': {
params: Bidi.EmptyParams;
returnType: Bidi.EmptyResult;
};
'session.new': {

@@ -174,3 +183,3 @@ params: Bidi.Session.NewParameters;

this.#transport.onmessage = this.onMessage.bind(this);
this.#transport.onclose = this.#onClose.bind(this);
this.#transport.onclose = this.unbind.bind(this);
}

@@ -190,2 +199,4 @@

): Promise<{result: Commands[T]['returnType']}> {
assert(!this.#closed, 'Protocol error: Connection closed.');
return this.#callbacks.create(method, this.#timeout, id => {

@@ -229,2 +240,8 @@ const stringifiedMessage = JSON.stringify({

case 'event':
if (isCdpEvent(object)) {
cdpSessions
.get(object.params.session)
?.emit(object.params.event, object.params.params);
return;
}
this.#maybeEmitOnContext(object);

@@ -239,2 +256,11 @@ // SAFETY: We know the method and parameter still match here.

}
// Even if the response in not in BiDi protocol format but `id` is provided, reject
// the callback. This can happen if the endpoint supports CDP instead of BiDi.
if ('id' in object) {
this.#callbacks.reject(
(object as {id: number}).id,
`Protocol Error. Message is not in BiDi protocol format: '${message}'`,
object.message
);
}
debugError(object);

@@ -254,6 +280,2 @@ }

context = this.#browsingContexts.get(event.params.source.context);
} else if (isCdpEvent(event)) {
cdpSessions
.get(event.params.session)
?.emit(event.params.event, event.params.params);
}

@@ -294,3 +316,8 @@ context?.emit(event.method, event.params);

#onClose(): void {
/**
* Unbinds the connection, but keeps the transport open. Useful when the transport will
* be reused by other connection e.g. with different protocol.
* @internal
*/
unbind(): void {
if (this.#closed) {

@@ -304,7 +331,11 @@ return;

this.#browsingContexts.clear();
this.#callbacks.clear();
}
/**
* Unbinds the connection and closes the transport.
*/
dispose(): void {
this.#onClose();
this.unbind();
this.#transport.close();

@@ -311,0 +342,0 @@ }

@@ -31,2 +31,3 @@ /**

import type {CDPSession} from '../api/CDPSession.js';
import type {ElementHandle} from '../api/ElementHandle.js';
import {

@@ -38,6 +39,7 @@ Frame,

} from '../api/Frame.js';
import type {WaitForSelectorOptions} from '../api/Page.js';
import {UnsupportedOperation} from '../common/Errors.js';
import type {TimeoutSettings} from '../common/TimeoutSettings.js';
import type {Awaitable} from '../common/types.js';
import {UTILITY_WORLD_NAME, setPageContent, timeout} from '../common/util.js';
import type {Awaitable, NodeFor} from '../common/types.js';
import {UTILITY_WORLD_NAME, timeout} from '../common/util.js';
import {Deferred} from '../util/Deferred.js';

@@ -177,3 +179,3 @@ import {disposeSymbol} from '../util/disposable.js';

fromEvent(this.#context, waitEvent).pipe(first()),
from(setPageContent(this, html)),
from(this.setFrameContent(html)),
]).pipe(

@@ -276,2 +278,15 @@ map(() => {

}
override waitForSelector<Selector extends string>(
selector: Selector,
options?: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null> {
if (selector.startsWith('aria')) {
throw new UnsupportedOperation(
'ARIA selector is not supported for BiDi!'
);
}
return super.waitForSelector(selector, options);
}
}

@@ -32,3 +32,5 @@ /**

import type {CDPSession} from '../api/CDPSession.js';
import type {BoundingBox} from '../api/ElementHandle.js';
import type {WaitForOptions} from '../api/Frame.js';
import type {HTTPResponse} from '../api/HTTPResponse.js';
import {

@@ -68,2 +70,3 @@ Page,

import {disposeSymbol} from '../util/disposable.js';
import {isErrorLike} from '../util/ErrorLike.js';

@@ -91,2 +94,3 @@ import type {BidiBrowser} from './Browser.js';

import {createBidiHandle} from './Realm.js';
import type {BiDiPageTarget} from './Target.js';

@@ -162,2 +166,3 @@ /**

#browserContext: BidiBrowserContext;
#target: BiDiPageTarget;

@@ -170,3 +175,4 @@ _client(): CDPSession {

browsingContext: BrowsingContext,
browserContext: BidiBrowserContext
browserContext: BidiBrowserContext,
target: BiDiPageTarget
) {

@@ -176,2 +182,3 @@ super();

this.#browserContext = browserContext;
this.#target = target;
this.#connection = browsingContext.connection;

@@ -482,3 +489,3 @@

override async close(): Promise<void> {
override async close(options?: {runBeforeUnload?: boolean}): Promise<void> {
if (this.#closedDeferred.finished()) {

@@ -493,2 +500,3 @@ return;

context: this.mainFrame()._id,
promptUnload: options?.runBeforeUnload ?? false,
});

@@ -657,9 +665,3 @@

): Promise<string> {
const {clip, type, captureBeyondViewport, allowViewportExpansion, quality} =
options;
if (captureBeyondViewport && !allowViewportExpansion) {
throw new UnsupportedOperation(
`BiDi does not support 'captureBeyondViewport'. Use 'allowViewportExpansion'.`
);
}
const {clip, type, captureBeyondViewport, quality} = options;
if (options.omitBackground !== undefined && options.omitBackground) {

@@ -676,2 +678,25 @@ throw new UnsupportedOperation(`BiDi does not support 'omitBackground'.`);

}
let box: BoundingBox | undefined;
if (clip) {
if (captureBeyondViewport) {
box = clip;
} else {
const [pageLeft, pageTop] = await this.evaluate(() => {
if (!window.visualViewport) {
throw new Error('window.visualViewport is not supported.');
}
return [
window.visualViewport.pageLeft,
window.visualViewport.pageTop,
] as const;
});
box = {
...clip,
x: clip.x - pageLeft,
y: clip.y - pageTop,
};
}
}
if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) {

@@ -687,10 +712,8 @@ throw new UnsupportedOperation(

context: this.mainFrame()._id,
origin: captureBeyondViewport ? 'document' : 'viewport',
format: {
type: `image/${type}`,
quality: quality ? quality / 100 : undefined,
...(quality !== undefined ? {quality: quality / 100} : {}),
},
clip: clip && {
type: 'box',
...clip,
},
...(box ? {clip: {type: 'box', ...box}} : {}),
});

@@ -841,4 +864,4 @@ return data;

override target(): never {
throw new UnsupportedOperation();
override target(): BiDiPageTarget {
return this.#target;
}

@@ -903,10 +926,38 @@

override goBack(): never {
throw new UnsupportedOperation();
override async goBack(
options: WaitForOptions = {}
): Promise<HTTPResponse | null> {
return await this.#go(-1, options);
}
override goForward(): never {
throw new UnsupportedOperation();
override async goForward(
options: WaitForOptions = {}
): Promise<HTTPResponse | null> {
return await this.#go(+1, options);
}
async #go(
delta: number,
options: WaitForOptions
): Promise<HTTPResponse | null> {
try {
const result = await Promise.all([
this.waitForNavigation(options),
this.#connection.send('browsingContext.traverseHistory', {
delta,
context: this.mainFrame()._id,
}),
]);
return result[0];
} catch (err) {
// TODO: waitForNavigation should be cancelled if an error happens.
if (isErrorLike(err)) {
if (err.message.includes('no such history entry')) {
return null;
}
}
throw err;
}
}
override waitForDevicePrompt(): never {

@@ -913,0 +964,0 @@ throw new UnsupportedOperation();

@@ -122,3 +122,3 @@ /**

this.#page = new BidiPage(browsingContext, browserContext);
this.#page = new BidiPage(browsingContext, browserContext, this);
}

@@ -125,0 +125,0 @@

@@ -413,9 +413,10 @@ /**

await this.#closeCallback.call(null);
this.disconnect();
await this.disconnect();
}
override disconnect(): void {
override disconnect(): Promise<void> {
this.#targetManager.dispose();
this.#connection.dispose();
this._detach();
return Promise.resolve();
}

@@ -422,0 +423,0 @@

@@ -17,3 +17,2 @@ /**

import type {BidiBrowser} from '../bidi/Browser.js';
import type {ConnectionTransport} from '../common/ConnectionTransport.js';

@@ -24,8 +23,3 @@ import type {

} from '../common/ConnectOptions.js';
import {UnsupportedOperation} from '../common/Errors.js';
import {getFetch} from '../common/fetch.js';
import {debugError} from '../common/util.js';
import {isNode} from '../environment.js';
import {assert} from '../util/assert.js';
import {isErrorLike} from '../util/ErrorLike.js';
import {debugError, DEFAULT_VIEWPORT} from '../common/util.js';

@@ -35,11 +29,2 @@ import {CdpBrowser} from './Browser.js';

const DEFAULT_VIEWPORT = Object.freeze({width: 800, height: 600});
const getWebSocketTransportClass = async () => {
return isNode
? (await import('../node/NodeWebSocketTransport.js')).NodeWebSocketTransport
: (await import('../common/BrowserWebSocketTransport.js'))
.BrowserWebSocketTransport;
};
/**

@@ -52,2 +37,4 @@ * Users should never call this directly; it's called when calling

export async function _connectToCdpBrowser(
connectionTransport: ConnectionTransport,
url: string,
options: BrowserConnectOptions & ConnectOptions

@@ -60,5 +47,12 @@ ): Promise<CdpBrowser> {

_isPageTarget: isPageTarget,
slowMo = 0,
protocolTimeout,
} = options;
const connection = await getCdpConnection(options);
const connection = new Connection(
url,
connectionTransport,
slowMo,
protocolTimeout
);

@@ -88,108 +82,1 @@ const version = await connection.send('Browser.getVersion');

}
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
*
* @internal
*/
export async function _connectToBiDiOverCdpBrowser(
options: BrowserConnectOptions & ConnectOptions
): Promise<BidiBrowser> {
const {ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT} =
options;
const connection = await getCdpConnection(options);
const version = await connection.send('Browser.getVersion');
if (version.product.toLowerCase().includes('firefox')) {
throw new UnsupportedOperation(
'Firefox is not supported in BiDi over CDP mode.'
);
}
// TODO: use other options too.
const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiBrowser = await BiDi.BidiBrowser.create({
connection: bidiConnection,
closeCallback: () => {
return connection.send('Browser.close').catch(debugError);
},
process: undefined,
defaultViewport: defaultViewport,
ignoreHTTPSErrors: ignoreHTTPSErrors,
});
return bidiBrowser;
}
async function getWSEndpoint(browserURL: string): Promise<string> {
const endpointURL = new URL('/json/version', browserURL);
const fetch = await getFetch();
try {
const result = await fetch(endpointURL.toString(), {
method: 'GET',
});
if (!result.ok) {
throw new Error(`HTTP ${result.statusText}`);
}
const data = await result.json();
return data.webSocketDebuggerUrl;
} catch (error) {
if (isErrorLike(error)) {
error.message =
`Failed to fetch browser webSocket URL from ${endpointURL}: ` +
error.message;
}
throw error;
}
}
/**
* Returns a CDP connection for the given options.
*/
async function getCdpConnection(
options: BrowserConnectOptions & ConnectOptions
): Promise<Connection> {
const {
browserWSEndpoint,
browserURL,
transport,
headers = {},
slowMo = 0,
protocolTimeout,
} = options;
assert(
Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
1,
'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
);
if (transport) {
return new Connection('', transport, slowMo, protocolTimeout);
} else if (browserWSEndpoint) {
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport: ConnectionTransport =
await WebSocketClass.create(browserWSEndpoint, headers);
return new Connection(
browserWSEndpoint,
connectionTransport,
slowMo,
protocolTimeout
);
} else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport: ConnectionTransport =
await WebSocketClass.create(connectionURL);
return new Connection(
connectionURL,
connectionTransport,
slowMo,
protocolTimeout
);
}
throw new Error('Invalid connection options');
}

@@ -24,3 +24,2 @@ /**

import {UnsupportedOperation} from '../common/Errors.js';
import {setPageContent} from '../common/util.js';
import {Deferred} from '../util/Deferred.js';

@@ -266,3 +265,5 @@ import {disposeSymbol} from '../util/disposable.js';

await setPageContent(this.isolatedRealm(), html);
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.setFrameContent(html);

@@ -269,0 +270,0 @@ const watcher = new LifecycleWatcher(

@@ -165,3 +165,2 @@ /**

// eslint-disable-next-line @typescript-eslint/no-unused-vars
using _ = await this.#mutex.acquire();

@@ -168,0 +167,0 @@ try {

@@ -26,2 +26,7 @@ /*

/**
* @public
*/
export type ProtocolType = 'cdp' | 'webDriverBiDi';
/**
* Generic browser options that can be passed when launching any browser or when

@@ -39,2 +44,4 @@ * connecting to an existing browser instance.

* Sets the viewport for each page.
*
* @defaultValue '\{width: 800, height: 600\}'
*/

@@ -55,7 +62,8 @@ defaultViewport?: Viewport | null;

_isPageTarget?: IsPageTargetCallback;
/**
* @defaultValue 'cdp'
* @internal
* @public
*/
protocol?: 'cdp' | 'webDriverBiDi';
protocol?: ProtocolType;
/**

@@ -62,0 +70,0 @@ * Timeout setting for individual protocol (CDP) calls.

@@ -18,7 +18,4 @@ /**

import type {Browser} from '../api/Browser.js';
import {
_connectToBiDiOverCdpBrowser,
_connectToCdpBrowser,
} from '../cdp/BrowserConnector.js';
import {_connectToBrowser} from './BrowserConnector.js';
import type {ConnectOptions} from './ConnectOptions.js';

@@ -135,8 +132,4 @@ import {

connect(options: ConnectOptions): Promise<Browser> {
if (options.protocol === 'webDriverBiDi') {
return _connectToBiDiOverCdpBrowser(options);
} else {
return _connectToCdpBrowser(options);
}
return _connectToBrowser(options);
}
}

@@ -34,3 +34,2 @@ /**

import type {CDPSession} from '../api/CDPSession.js';
import type {Page} from '../api/Page.js';
import {isNode} from '../environment.js';

@@ -54,2 +53,7 @@ import {assert} from '../util/assert.js';

*/
export const DEFAULT_VIEWPORT = Object.freeze({width: 800, height: 600});
/**
* @internal
*/
export function createEvaluationError(

@@ -512,18 +516,2 @@ details: Protocol.Runtime.ExceptionDetails

*/
export async function setPageContent(
page: Pick<Page, 'evaluate'>,
content: string
): Promise<void> {
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
return await page.evaluate(html => {
document.open();
document.write(html);
document.close();
}, content);
}
/**
* @internal
*/
export function getPageContent(): string {

@@ -530,0 +518,0 @@ let content = '';

/**
* @internal
*/
export const packageVersion = '21.5.2';
export const packageVersion = '21.6.0';

@@ -18,2 +18,3 @@ /**

import {mkdtemp} from 'fs/promises';
import os from 'os';
import path from 'path';

@@ -68,2 +69,22 @@

if (
this.puppeteer.configuration.logLevel === 'warn' &&
process.platform === 'darwin' &&
process.arch === 'x64'
) {
const cpus = os.cpus();
if (cpus[0]?.model.includes('Apple')) {
console.warn(
[
'\x1B[1m\x1B[43m\x1B[30m',
'Degraded performance warning:\x1B[0m\x1B[33m',
'Launching Chrome on Mac Silicon (arm64) from an x64 Node installation results in',
'Rosetta translating the Chrome binary, even if Chrome is already arm64. This would',
'result in huge performance issues. To resolve this, you must run Puppeteer with',
'a version of Node built for arm64.',
].join('\n ')
);
}
}
return super.launch(options);

@@ -70,0 +91,0 @@ }

@@ -116,3 +116,17 @@ /**

path: userDataDir,
preferences: extraPrefsFirefox,
preferences: {
...extraPrefsFirefox,
...(options.protocol === 'cdp'
? {
// Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
'fission.bfcacheInParent': false,
}
: {}),
// Force all web content to use a single content process. TODO: remove
// this once Firefox supports mouse event dispatch from the main frame
// context. Once this happens, webContentIsolationStrategy should only
// be set for CDP. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=1773393
'fission.webContentIsolationStrategy': 0,
},
});

@@ -119,0 +133,0 @@

@@ -34,3 +34,3 @@ /**

import type {Product} from '../common/Product.js';
import {debugError} from '../common/util.js';
import {debugError, DEFAULT_VIEWPORT} from '../common/util.js';
import type {Viewport} from '../common/Viewport.js';

@@ -95,8 +95,8 @@

ignoreHTTPSErrors = false,
defaultViewport = {width: 800, height: 600},
defaultViewport = DEFAULT_VIEWPORT,
slowMo = 0,
timeout = 30000,
waitForInitialPage = true,
protocolTimeout,
protocol,
protocolTimeout,
} = options;

@@ -127,6 +127,6 @@

let browser: Browser;
let connection: Connection;
let cdpConnection: Connection;
let closing = false;
const browserCloseCallback = async () => {
const browserCloseCallback: BrowserCloseCallback = async () => {
if (closing) {

@@ -136,3 +136,3 @@ return;

closing = true;
await this.closeBrowser(browserProcess, connection);
await this.closeBrowser(browserProcess, cdpConnection);
};

@@ -155,3 +155,3 @@

if (usePipe) {
connection = await this.createCdpPipeConnection(browserProcess, {
cdpConnection = await this.createCdpPipeConnection(browserProcess, {
timeout,

@@ -162,3 +162,3 @@ protocolTimeout,

} else {
connection = await this.createCdpSocketConnection(browserProcess, {
cdpConnection = await this.createCdpSocketConnection(browserProcess, {
timeout,

@@ -172,3 +172,3 @@ protocolTimeout,

browserProcess,
connection,
cdpConnection,
browserCloseCallback,

@@ -186,3 +186,3 @@ {

this.product,
connection,
cdpConnection,
[],

@@ -245,8 +245,8 @@ ignoreHTTPSErrors,

browserProcess: ReturnType<typeof launch>,
connection?: Connection
cdpConnection?: Connection
): Promise<void> {
if (connection) {
if (cdpConnection) {
// Attempt to close the browser gracefully
try {
await connection.closeBrowser();
await cdpConnection.closeBrowser();
await browserProcess.hasClosed();

@@ -336,3 +336,5 @@ } catch (error) {

const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
const bidiConnection = await BiDi.connectBidiOverCdp(connection, {
acceptInsecureCerts: opts.ignoreHTTPSErrors ?? false,
});
return await BiDi.BidiBrowser.create({

@@ -434,3 +436,3 @@ connection: bidiConnection,

`Could not find Chrome (ver. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation before running the script (e.g. `npm install`) or\n' +
' 1. you did not perform an installation before running the script (e.g. `npx puppeteer browsers install chrome`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -442,3 +444,3 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.'

`Could not find Firefox (rev. ${this.puppeteer.browserRevision}). This can occur if either\n` +
' 1. you did not perform an installation for Firefox before running the script (e.g. `PUPPETEER_PRODUCT=firefox npm install`) or\n' +
' 1. you did not perform an installation for Firefox before running the script (e.g. `npx puppeteer browsers install firefox`) or\n' +
` 2. your cache path is incorrectly configured (which is: ${this.puppeteer.configuration.cacheDirectory}).\n` +

@@ -445,0 +447,0 @@ 'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.'

@@ -175,3 +175,3 @@ /**

* describes some differences for Linux users. See
* {@link https://goo.gle/chrome-for-testing | this doc} for the description
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.

@@ -178,0 +178,0 @@ *

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc