first commit

This commit is contained in:
2026-06-02 20:24:26 -03:00
commit 7b8a8d722d
3354 changed files with 627959 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
import { launch } from '@puppeteer/browsers';
import type { Browser, BrowserCloseCallback } from '../api/Browser.js';
import { Connection } from '../cdp/Connection.js';
import type { SupportedBrowser } from '../common/SupportedBrowser.js';
import type { Viewport } from '../common/Viewport.js';
import { type GetIdFn } from '../util/incremental-id-generator.js';
import type { ChromeReleaseChannel, LaunchOptions } from './LaunchOptions.js';
import type { PuppeteerNode } from './PuppeteerNode.js';
/**
* @internal
*/
export interface ResolvedLaunchArgs {
isTempUserDataDir: boolean;
userDataDir: string;
executablePath: string;
args: string[];
}
/**
* Describes a launcher - a class that is able to create and launch a browser instance.
*
* @public
*/
export declare abstract class BrowserLauncher {
#private;
/**
* @internal
*/
puppeteer: PuppeteerNode;
/**
* @internal
*/
constructor(puppeteer: PuppeteerNode, browser: SupportedBrowser);
get browser(): SupportedBrowser;
launch(options?: LaunchOptions): Promise<Browser>;
abstract executablePath(channel?: ChromeReleaseChannel, validatePath?: boolean): Promise<string>;
abstract defaultArgs(object: LaunchOptions): string[];
/**
* @internal
*/
protected abstract computeLaunchArguments(options: LaunchOptions): Promise<ResolvedLaunchArgs>;
/**
* @internal
*/
protected abstract cleanUserDataDir(path: string, opts: {
isTemp: boolean;
}): Promise<void>;
/**
* @internal
*/
protected closeBrowser(browserProcess: ReturnType<typeof launch>, cdpConnection?: Connection): Promise<void>;
/**
* @internal
*/
protected waitForPageTarget(browser: Browser, timeout: number): Promise<void>;
/**
* @internal
*/
protected createCdpSocketConnection(browserProcess: ReturnType<typeof launch>, opts: {
timeout: number;
protocolTimeout: number | undefined;
slowMo: number;
idGenerator: GetIdFn;
}): Promise<Connection>;
/**
* @internal
*/
protected createCdpPipeConnection(browserProcess: ReturnType<typeof launch>, opts: {
timeout: number;
protocolTimeout: number | undefined;
slowMo: number;
idGenerator: GetIdFn;
}): Promise<Connection>;
/**
* @internal
*/
protected createBiDiOverCdpBrowser(browserProcess: ReturnType<typeof launch>, cdpConnection: Connection, closeCallback: BrowserCloseCallback, opts: {
defaultViewport: Viewport | null;
acceptInsecureCerts?: boolean;
networkEnabled: boolean;
issuesEnabled: boolean;
}): Promise<Browser>;
/**
* @internal
*/
protected createBiDiBrowser(browserProcess: ReturnType<typeof launch>, closeCallback: BrowserCloseCallback, opts: {
timeout: number;
protocolTimeout: number | undefined;
slowMo: number;
idGenerator: GetIdFn;
defaultViewport: Viewport | null;
acceptInsecureCerts?: boolean;
networkEnabled?: boolean;
issuesEnabled?: boolean;
}): Promise<Browser>;
/**
* @internal
*/
protected getProfilePath(): Promise<string>;
/**
* @internal
*/
resolveExecutablePath(headless?: boolean | 'shell', validatePath?: boolean): Promise<string>;
}
//# sourceMappingURL=BrowserLauncher.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserLauncher.d.ts","sourceRoot":"","sources":["../../../src/node/BrowserLauncher.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,324 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { existsSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { Browser as InstalledBrowser, CDP_WEBSOCKET_ENDPOINT_REGEX, launch, TimeoutError as BrowsersTimeoutError, WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, computeExecutablePath, } from '@puppeteer/browsers';
import { firstValueFrom, from, map, race, timer, } from '../../third_party/rxjs/rxjs.js';
import { CdpBrowser } from '../cdp/Browser.js';
import { Connection } from '../cdp/Connection.js';
import { assertSupportedUrlRestrictions } from '../common/BrowserConnector.js';
import { TimeoutError } from '../common/Errors.js';
import { debugError, DEFAULT_VIEWPORT } from '../common/util.js';
import { createIncrementalIdGenerator, } from '../util/incremental-id-generator.js';
import { NodeWebSocketTransport as WebSocketTransport } from './NodeWebSocketTransport.js';
import { PipeTransport } from './PipeTransport.js';
/**
* Describes a launcher - a class that is able to create and launch a browser instance.
*
* @public
*/
export class BrowserLauncher {
#browser;
/**
* @internal
*/
puppeteer;
/**
* @internal
*/
constructor(puppeteer, browser) {
this.puppeteer = puppeteer;
this.#browser = browser;
}
get browser() {
return this.#browser;
}
async launch(options = {}) {
const { dumpio = false, enableExtensions = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, acceptInsecureCerts = false, networkEnabled = true, issuesEnabled = true, defaultViewport = DEFAULT_VIEWPORT, downloadBehavior, slowMo = 0, timeout = 30000, waitForInitialPage = true, protocolTimeout, handleDevToolsAsPage, idGenerator = createIncrementalIdGenerator(), blocklist, allowlist, } = options;
let { protocol } = options;
// Default to 'webDriverBiDi' for Firefox.
if (this.#browser === 'firefox' && protocol === undefined) {
protocol = 'webDriverBiDi';
}
assertSupportedUrlRestrictions({
allowlist,
blocklist,
protocol,
});
if (this.#browser === 'firefox' && protocol === 'cdp') {
throw new Error('Connecting to Firefox using CDP is no longer supported');
}
const launchArgs = await this.computeLaunchArguments({
...options,
protocol,
});
if (!existsSync(launchArgs.executablePath)) {
throw new Error(`Browser was not found at the configured executablePath (${launchArgs.executablePath})`);
}
const usePipe = launchArgs.args.includes('--remote-debugging-pipe');
const onProcessExit = async () => {
await this.cleanUserDataDir(launchArgs.userDataDir, {
isTemp: launchArgs.isTempUserDataDir,
});
};
if (this.#browser === 'firefox' &&
protocol === 'webDriverBiDi' &&
usePipe) {
throw new Error('Pipe connections are not supported with Firefox and WebDriver BiDi');
}
const browserProcess = launch({
executablePath: launchArgs.executablePath,
args: launchArgs.args,
handleSIGHUP,
handleSIGTERM,
handleSIGINT,
dumpio,
env,
pipe: usePipe,
onExit: onProcessExit,
signal: options.signal,
});
let browser;
let cdpConnection;
let closing = false;
const browserCloseCallback = async () => {
if (closing) {
return;
}
closing = true;
await this.closeBrowser(browserProcess, cdpConnection);
};
try {
if (this.#browser === 'firefox') {
browser = await this.createBiDiBrowser(browserProcess, browserCloseCallback, {
timeout,
protocolTimeout,
slowMo,
defaultViewport,
acceptInsecureCerts,
networkEnabled,
idGenerator,
});
}
else {
if (usePipe) {
cdpConnection = await this.createCdpPipeConnection(browserProcess, {
timeout,
protocolTimeout,
slowMo,
idGenerator,
});
}
else {
cdpConnection = await this.createCdpSocketConnection(browserProcess, {
timeout,
protocolTimeout,
slowMo,
idGenerator,
});
}
if (protocol === 'webDriverBiDi') {
browser = await this.createBiDiOverCdpBrowser(browserProcess, cdpConnection, browserCloseCallback, {
defaultViewport,
acceptInsecureCerts,
networkEnabled,
issuesEnabled,
});
}
else {
browser = await CdpBrowser._create(cdpConnection, [], acceptInsecureCerts, defaultViewport, downloadBehavior, browserProcess.nodeProcess, browserCloseCallback, options.targetFilter, undefined, undefined, networkEnabled, issuesEnabled, handleDevToolsAsPage, blocklist, allowlist);
}
}
}
catch (error) {
void browserCloseCallback();
const logs = browserProcess.getRecentLogs().join('\n');
if (logs.includes('Failed to create a ProcessSingleton for your profile directory') ||
// On Windows we will not get logs due to the singleton process handover. See
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/process_singleton_win.cc;l=46;drc=fc7952f0422b5073515a205a04ec9c3a1ae81658
(process.platform === 'win32' &&
existsSync(join(launchArgs.userDataDir, 'lockfile')))) {
throw new Error(`The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`);
}
if (logs.includes('Missing X server') && options.headless === false) {
throw new Error(`Missing X server to start the headful browser. Either set headless to true or use xvfb-run to run your Puppeteer script.`);
}
if (error instanceof BrowsersTimeoutError) {
throw new TimeoutError(error.message);
}
throw error;
}
if (Array.isArray(enableExtensions)) {
if (this.#browser === 'chrome' && !usePipe) {
throw new Error('To use `enableExtensions` with a list of paths in Chrome, you must be connected with `--remote-debugging-pipe` (`pipe: true`).');
}
await Promise.all([
enableExtensions.map(path => {
return browser.installExtension(path);
}),
]);
}
if (waitForInitialPage) {
await this.waitForPageTarget(browser, timeout);
}
return browser;
}
/**
* @internal
*/
async closeBrowser(browserProcess, cdpConnection) {
if (cdpConnection) {
// Attempt to close the browser gracefully
try {
await cdpConnection.closeBrowser();
await browserProcess.hasClosed();
}
catch (error) {
debugError(error);
await browserProcess.close();
}
}
else {
// Wait for a possible graceful shutdown.
await firstValueFrom(race(from(browserProcess.hasClosed()), timer(5000).pipe(map(() => {
return from(browserProcess.close());
}))));
}
}
/**
* @internal
*/
async waitForPageTarget(browser, timeout) {
try {
await browser.waitForTarget(t => {
return t.type() === 'page';
}, { timeout });
}
catch (error) {
await browser.close();
throw error;
}
}
/**
* @internal
*/
async createCdpSocketConnection(browserProcess, opts) {
const browserWSEndpoint = await browserProcess.waitForLineOutput(CDP_WEBSOCKET_ENDPOINT_REGEX, opts.timeout);
const transport = await WebSocketTransport.create(browserWSEndpoint);
return new Connection(browserWSEndpoint, transport, opts.slowMo, opts.protocolTimeout,
/* rawErrors */ false, opts.idGenerator);
}
/**
* @internal
*/
async createCdpPipeConnection(browserProcess, opts) {
// stdio was assigned during start(), and the 'pipe' option there adds the
// 4th and 5th items to stdio array
const { 3: pipeWrite, 4: pipeRead } = browserProcess.nodeProcess.stdio;
const transport = new PipeTransport(pipeWrite, pipeRead);
return new Connection('', transport, opts.slowMo, opts.protocolTimeout,
/* rawErrors */ false, opts.idGenerator);
}
/**
* @internal
*/
async createBiDiOverCdpBrowser(browserProcess, cdpConnection, closeCallback, opts) {
const bidiOnly = process.env['PUPPETEER_WEBDRIVER_BIDI_ONLY'] === 'true';
const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = await BiDi.connectBidiOverCdp(cdpConnection);
return await BiDi.BidiBrowser.create({
connection: bidiConnection,
// Do not provide CDP connection to Browser, if BiDi-only mode is enabled. This
// would restrict Browser to use only BiDi endpoint.
cdpConnection: bidiOnly ? undefined : cdpConnection,
closeCallback,
process: browserProcess.nodeProcess,
defaultViewport: opts.defaultViewport,
acceptInsecureCerts: opts.acceptInsecureCerts,
networkEnabled: opts.networkEnabled,
issuesEnabled: opts.issuesEnabled,
});
}
/**
* @internal
*/
async createBiDiBrowser(browserProcess, closeCallback, opts) {
const browserWSEndpoint = (await browserProcess.waitForLineOutput(WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX, opts.timeout)) + '/session';
const transport = await WebSocketTransport.create(browserWSEndpoint);
const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
const bidiConnection = new BiDi.BidiConnection(browserWSEndpoint, transport, opts.idGenerator, opts.slowMo, opts.protocolTimeout);
return await BiDi.BidiBrowser.create({
connection: bidiConnection,
closeCallback,
process: browserProcess.nodeProcess,
defaultViewport: opts.defaultViewport,
acceptInsecureCerts: opts.acceptInsecureCerts,
networkEnabled: opts.networkEnabled ?? true,
issuesEnabled: opts.issuesEnabled ?? true,
});
}
/**
* @internal
*/
async getProfilePath() {
const config = await this.puppeteer.configuration();
return join(config.temporaryDirectory ?? tmpdir(), `puppeteer_dev_${this.browser}_profile-`);
}
/**
* @internal
*/
async resolveExecutablePath(headless, validatePath = true) {
const config = await this.puppeteer.configuration();
let executablePath = config.executablePath;
if (executablePath) {
if (validatePath && !existsSync(executablePath)) {
throw new Error(`Tried to find the browser at the configured path (${executablePath}), but no executable was found.`);
}
return executablePath;
}
function puppeteerBrowserToInstalledBrowser(browser, headless) {
switch (browser) {
case 'chrome':
if (headless === 'shell') {
return InstalledBrowser.CHROMEHEADLESSSHELL;
}
return InstalledBrowser.CHROME;
case 'firefox':
return InstalledBrowser.FIREFOX;
}
return InstalledBrowser.CHROME;
}
const browserType = puppeteerBrowserToInstalledBrowser(this.browser, headless);
const defaultDownloadPath = await this.puppeteer.defaultDownloadPath();
const browserVersion = await this.puppeteer.browserVersion();
executablePath = computeExecutablePath({
cacheDir: defaultDownloadPath,
browser: browserType,
buildId: browserVersion,
});
if (validatePath && !existsSync(executablePath)) {
const configVersion = config?.[this.browser]?.version;
if (configVersion) {
throw new Error(`Tried to find the browser at the configured path (${executablePath}) for version ${configVersion}, but no executable was found.`);
}
switch (this.browser) {
case 'chrome':
throw new Error(`Could not find Chrome (ver. ${browserVersion}). This can occur if either\n` +
` 1. you did not perform an installation before running the script (e.g. \`npx puppeteer browsers install ${browserType}\`) or\n` +
` 2. your cache path is incorrectly configured (which is: ${config.cacheDirectory}).\n` +
'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');
case 'firefox':
throw new Error(`Could not find Firefox (rev. ${browserVersion}). This can occur if either\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: ${config.cacheDirectory}).\n` +
'For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.');
}
}
return executablePath;
}
}
//# sourceMappingURL=BrowserLauncher.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Browser } from '../api/Browser.js';
import { BrowserLauncher, type ResolvedLaunchArgs } from './BrowserLauncher.js';
import { type ChromeReleaseChannel, type LaunchOptions } from './LaunchOptions.js';
import type { PuppeteerNode } from './PuppeteerNode.js';
/**
* @internal
*/
export declare class ChromeLauncher extends BrowserLauncher {
constructor(puppeteer: PuppeteerNode);
launch(options?: LaunchOptions): Promise<Browser>;
/**
* @internal
*/
computeLaunchArguments(options?: LaunchOptions): Promise<ResolvedLaunchArgs>;
/**
* @internal
*/
cleanUserDataDir(path: string, opts: {
isTemp: boolean;
}): Promise<void>;
defaultArgs(options?: LaunchOptions): string[];
executablePath(channel?: ChromeReleaseChannel, validatePath?: boolean): Promise<string>;
}
/**
* Extracts all features from the given command-line flag
* (e.g. `--enable-features`, `--enable-features=`).
*
* Example input:
* ["--enable-features=NetworkService,NetworkServiceInProcess", "--enable-features=Foo"]
*
* Example output:
* ["NetworkService", "NetworkServiceInProcess", "Foo"]
*
* @internal
*/
export declare function getFeatures(flag: string, options?: string[]): string[];
/**
* Removes all elements in-place from the given string array
* that match the given command-line flag.
*
* @internal
*/
export declare function removeMatchingFlags(array: string[], flag: string): string[];
//# sourceMappingURL=ChromeLauncher.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ChromeLauncher.d.ts","sourceRoot":"","sources":["../../../src/node/ChromeLauncher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAC;AAI/C,OAAO,EAAC,eAAe,EAAE,KAAK,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAGtD;;GAEG;AACH,qBAAa,cAAe,SAAQ,eAAe;gBACrC,SAAS,EAAE,aAAa;IAIrB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAyBpE;;OAEG;IACY,sBAAsB,CACnC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,kBAAkB,CAAC;IA4E9B;;OAEG;IACY,gBAAgB,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QAAC,MAAM,EAAE,OAAO,CAAA;KAAC,GACtB,OAAO,CAAC,IAAI,CAAC;IAWP,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,EAAE;IAoI5C,cAAc,CAC3B,OAAO,CAAC,EAAE,oBAAoB,EAC9B,YAAY,UAAO,GAClB,OAAO,CAAC,MAAM,CAAC;CAUnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAkB1E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW3E"}

View File

@@ -0,0 +1,273 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { mkdtemp } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { computeSystemExecutablePath, Browser as SupportedBrowsers, } from '@puppeteer/browsers';
import { debugError } from '../common/util.js';
import { assert } from '../util/assert.js';
import { BrowserLauncher } from './BrowserLauncher.js';
import { convertPuppeteerChannelToBrowsersChannel, } from './LaunchOptions.js';
import { rm } from './util/fs.js';
/**
* @internal
*/
export class ChromeLauncher extends BrowserLauncher {
constructor(puppeteer) {
super(puppeteer, 'chrome');
}
async launch(options = {}) {
const config = await this.puppeteer.configuration();
if (config.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 await super.launch(options);
}
/**
* @internal
*/
async computeLaunchArguments(options = {}) {
const { ignoreDefaultArgs = false, args = [], pipe = false, debuggingPort, channel, executablePath, } = options;
const chromeArguments = [];
if (!ignoreDefaultArgs) {
chromeArguments.push(...this.defaultArgs(options));
}
else if (Array.isArray(ignoreDefaultArgs)) {
chromeArguments.push(...this.defaultArgs(options).filter(arg => {
return !ignoreDefaultArgs.includes(arg);
}));
}
else {
chromeArguments.push(...args);
}
if (!chromeArguments.some(argument => {
return argument.startsWith('--remote-debugging-');
})) {
if (pipe) {
assert(!debuggingPort, 'Browser should be launched with either pipe or debugging port - not both.');
chromeArguments.push('--remote-debugging-pipe');
}
else {
chromeArguments.push(`--remote-debugging-port=${debuggingPort || 0}`);
}
}
let isTempUserDataDir = false;
// Check for the user data dir argument, which will always be set even
// with a custom directory specified via the userDataDir option.
let userDataDirIndex = chromeArguments.findIndex(arg => {
return arg.startsWith('--user-data-dir');
});
if (userDataDirIndex < 0) {
isTempUserDataDir = true;
chromeArguments.push(`--user-data-dir=${await mkdtemp(await this.getProfilePath())}`);
userDataDirIndex = chromeArguments.length - 1;
}
const userDataDir = chromeArguments[userDataDirIndex].split('=', 2)[1];
assert(typeof userDataDir === 'string', '`--user-data-dir` is malformed');
let chromeExecutable = executablePath;
if (!chromeExecutable) {
assert(channel || !this.puppeteer._isPuppeteerCore, `An \`executablePath\` or \`channel\` must be specified for \`puppeteer-core\``);
chromeExecutable = channel
? await this.executablePath(channel)
: await this.resolveExecutablePath(options.headless ?? true);
}
return {
executablePath: chromeExecutable,
args: chromeArguments,
isTempUserDataDir,
userDataDir,
};
}
/**
* @internal
*/
async cleanUserDataDir(path, opts) {
if (opts.isTemp) {
try {
await rm(path);
}
catch (error) {
debugError(error);
throw error;
}
}
}
defaultArgs(options = {}) {
// See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
const userDisabledFeatures = getFeatures('--disable-features', options.args);
if (options.args && userDisabledFeatures.length > 0) {
removeMatchingFlags(options.args, '--disable-features');
}
const turnOnExperimentalFeaturesForTesting = process.env['PUPPETEER_TEST_EXPERIMENTAL_CHROME_FEATURES'] === 'true';
const userEnabledFeatures = getFeatures('--enable-features', options.args);
if (options.args && userEnabledFeatures.length > 0) {
removeMatchingFlags(options.args, '--enable-features');
}
// Merge default enabled features with user-provided ones, if any.
const enabledFeatures = [
'PdfOopif',
// Add features to enable by default here.
...userEnabledFeatures,
].filter(feature => {
return feature !== '';
});
// Merge default disabled features with user-provided ones, if any.
const disabledFeatures = [
'Translate',
// AcceptCHFrame disabled because of crbug.com/1348106.
'AcceptCHFrame',
'MediaRouter',
'OptimizationHints',
'WebUIReloadButton',
...(turnOnExperimentalFeaturesForTesting
? []
: [
// https://crbug.com/1492053
'ProcessPerSiteUpToMainFrameThreshold',
// https://github.com/puppeteer/puppeteer/issues/10715
'IsolateSandboxedIframes',
]),
...userDisabledFeatures,
]
.filter(feature => {
return feature !== '';
})
.filter(disabledFeature => {
return !enabledFeatures.includes(disabledFeature);
});
const chromeArguments = [
'--allow-pre-commit-input',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-breakpad',
'--disable-client-side-phishing-detection',
'--disable-component-extensions-with-background-pages',
'--disable-crash-reporter', // No crash reporting in CfT.
'--disable-default-apps',
'--disable-dev-shm-usage',
'--disable-hang-monitor',
'--disable-infobars',
'--disable-ipc-flooding-protection',
'--disable-popup-blocking',
'--disable-prompt-on-repost',
'--disable-renderer-backgrounding',
'--disable-search-engine-choice-screen',
'--disable-sync',
'--enable-automation',
'--export-tagged-pdf',
'--force-color-profile=srgb',
'--generate-pdf-document-outline',
'--metrics-recording-only',
'--no-first-run',
'--password-store=basic',
'--use-mock-keychain',
`--disable-features=${disabledFeatures.join(',')}`,
`--enable-features=${enabledFeatures.join(',')}`,
].filter(arg => {
return arg !== '';
});
const { devtools = false, headless = !devtools, args = [], userDataDir, enableExtensions = false, } = options;
if (process.env['PUPPETEER_DANGEROUS_NO_SANDBOX'] === 'true' &&
!args.includes('--no-sandbox')) {
chromeArguments.push('--no-sandbox');
}
if (userDataDir) {
// If absolute (for any platform) path is given, we should not resolve it.
chromeArguments.push(`--user-data-dir=${path.posix.isAbsolute(userDataDir) || path.win32.isAbsolute(userDataDir) ? userDataDir : path.resolve(userDataDir)}`);
}
if (devtools) {
chromeArguments.push('--auto-open-devtools-for-tabs');
}
if (headless) {
chromeArguments.push(headless === 'shell' ? '--headless' : '--headless=new', '--hide-scrollbars', '--mute-audio');
}
chromeArguments.push(enableExtensions
? '--enable-unsafe-extension-debugging'
: '--disable-extensions');
if (args.every(arg => {
return arg.startsWith('-');
})) {
chromeArguments.push('about:blank');
}
chromeArguments.push(...args);
return chromeArguments;
}
async executablePath(channel, validatePath = true) {
if (channel) {
return computeSystemExecutablePath({
browser: SupportedBrowsers.CHROME,
channel: convertPuppeteerChannelToBrowsersChannel(channel),
});
}
else {
return await this.resolveExecutablePath(undefined, validatePath);
}
}
}
/**
* Extracts all features from the given command-line flag
* (e.g. `--enable-features`, `--enable-features=`).
*
* Example input:
* ["--enable-features=NetworkService,NetworkServiceInProcess", "--enable-features=Foo"]
*
* Example output:
* ["NetworkService", "NetworkServiceInProcess", "Foo"]
*
* @internal
*/
export function getFeatures(flag, options = []) {
const prefix = flag.endsWith('=') ? flag : `${flag}=`;
return options
.filter(s => {
return s.startsWith(prefix);
})
.flatMap(s => {
return s
.substring(s.indexOf('=') + 1)
.trim()
.split(',')
.map(feature => {
return feature.trim();
});
})
.filter(s => {
return s;
});
}
/**
* Removes all elements in-place from the given string array
* that match the given command-line flag.
*
* @internal
*/
export function removeMatchingFlags(array, flag) {
const prefix = flag.endsWith('=') ? flag : `${flag}=`;
let i = 0;
while (i < array.length) {
if (array[i].startsWith(prefix)) {
array.splice(i, 1);
}
else {
i++;
}
}
return array;
}
//# sourceMappingURL=ChromeLauncher.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { BrowserLauncher, type ResolvedLaunchArgs } from './BrowserLauncher.js';
import type { LaunchOptions } from './LaunchOptions.js';
import type { PuppeteerNode } from './PuppeteerNode.js';
/**
* @internal
*/
export declare class FirefoxLauncher extends BrowserLauncher {
constructor(puppeteer: PuppeteerNode);
static getPreferences(extraPrefsFirefox?: Record<string, unknown>): Record<string, unknown>;
/**
* @internal
*/
computeLaunchArguments(options?: LaunchOptions): Promise<ResolvedLaunchArgs>;
/**
* @internal
*/
cleanUserDataDir(userDataDir: string, opts: {
isTemp: boolean;
}): Promise<void>;
executablePath(_: unknown, validatePath?: boolean): Promise<string>;
defaultArgs(options?: LaunchOptions): string[];
}
//# sourceMappingURL=FirefoxLauncher.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FirefoxLauncher.d.ts","sourceRoot":"","sources":["../../../src/node/FirefoxLauncher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,EAAC,eAAe,EAAE,KAAK,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAGtD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,eAAe;gBACtC,SAAS,EAAE,aAAa;IAIpC,MAAM,CAAC,cAAc,CACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAU1B;;OAEG;IACY,sBAAsB,CACnC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,kBAAkB,CAAC;IAsF9B;;OAEG;IACY,gBAAgB,CAC7B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;QAAC,MAAM,EAAE,OAAO,CAAA;KAAC,GACtB,OAAO,CAAC,IAAI,CAAC;IAkCD,cAAc,CAC3B,CAAC,EAAE,OAAO,EACV,YAAY,UAAO,GAClB,OAAO,CAAC,MAAM,CAAC;IAOT,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,EAAE;CAsC5D"}

View File

@@ -0,0 +1,167 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import fs from 'node:fs';
import { rename, unlink, mkdtemp } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { Browser as SupportedBrowsers, createProfile } from '@puppeteer/browsers';
import { debugError } from '../common/util.js';
import { assert } from '../util/assert.js';
import { BrowserLauncher } from './BrowserLauncher.js';
import { rm } from './util/fs.js';
/**
* @internal
*/
export class FirefoxLauncher extends BrowserLauncher {
constructor(puppeteer) {
super(puppeteer, 'firefox');
}
static getPreferences(extraPrefsFirefox) {
return {
...extraPrefsFirefox,
// Force all web content to use a single content process. TODO: remove
// this once Firefox supports mouse event dispatch from the main frame
// context. See https://bugzilla.mozilla.org/show_bug.cgi?id=1773393.
'fission.webContentIsolationStrategy': 0,
};
}
/**
* @internal
*/
async computeLaunchArguments(options = {}) {
const { ignoreDefaultArgs = false, args = [], executablePath, pipe = false, extraPrefsFirefox = {}, debuggingPort = null, } = options;
const firefoxArguments = [];
if (!ignoreDefaultArgs) {
firefoxArguments.push(...this.defaultArgs(options));
}
else if (Array.isArray(ignoreDefaultArgs)) {
firefoxArguments.push(...this.defaultArgs(options).filter(arg => {
return !ignoreDefaultArgs.includes(arg);
}));
}
else {
firefoxArguments.push(...args);
}
if (!firefoxArguments.some(argument => {
return argument.startsWith('--remote-debugging-');
})) {
if (pipe) {
assert(debuggingPort === null, 'Browser should be launched with either pipe or debugging port - not both.');
}
firefoxArguments.push(`--remote-debugging-port=${debuggingPort || 0}`);
}
let userDataDir;
let isTempUserDataDir = true;
// Check for the profile argument, which will always be set even
// with a custom directory specified via the userDataDir option.
const profileArgIndex = firefoxArguments.findIndex(arg => {
return ['-profile', '--profile'].includes(arg);
});
if (profileArgIndex !== -1) {
userDataDir = firefoxArguments[profileArgIndex + 1];
if (!userDataDir) {
throw new Error(`Missing value for profile command line argument`);
}
// When using a custom Firefox profile it needs to be populated
// with required preferences.
isTempUserDataDir = false;
}
else {
const profilePath = await this.getProfilePath();
userDataDir = await mkdtemp(profilePath);
firefoxArguments.push('--profile');
firefoxArguments.push(userDataDir);
}
await createProfile(SupportedBrowsers.FIREFOX, {
path: userDataDir,
preferences: FirefoxLauncher.getPreferences(extraPrefsFirefox),
});
let firefoxExecutable;
if (this.puppeteer._isPuppeteerCore || executablePath) {
assert(executablePath, `An \`executablePath\` must be specified for \`puppeteer-core\``);
firefoxExecutable = executablePath;
}
else {
firefoxExecutable = await this.executablePath(undefined);
}
return {
isTempUserDataDir,
userDataDir,
args: firefoxArguments,
executablePath: firefoxExecutable,
};
}
/**
* @internal
*/
async cleanUserDataDir(userDataDir, opts) {
if (opts.isTemp) {
try {
await rm(userDataDir);
}
catch (error) {
debugError(error);
throw error;
}
}
else {
try {
const backupSuffix = '.puppeteer';
const backupFiles = ['prefs.js', 'user.js'];
const results = await Promise.allSettled(backupFiles.map(async (file) => {
const prefsBackupPath = path.join(userDataDir, file + backupSuffix);
if (fs.existsSync(prefsBackupPath)) {
const prefsPath = path.join(userDataDir, file);
await unlink(prefsPath);
await rename(prefsBackupPath, prefsPath);
}
}));
for (const result of results) {
if (result.status === 'rejected') {
throw result.reason;
}
}
}
catch (error) {
debugError(error);
}
}
}
async executablePath(_, validatePath = true) {
return await this.resolveExecutablePath(undefined,
/* validatePath=*/ validatePath);
}
defaultArgs(options = {}) {
const { devtools = false, headless = !devtools, args = [], userDataDir = null, } = options;
const firefoxArguments = [];
switch (os.platform()) {
case 'darwin':
firefoxArguments.push('--foreground');
break;
case 'win32':
firefoxArguments.push('--wait-for-browser');
break;
}
if (userDataDir) {
firefoxArguments.push('--profile');
firefoxArguments.push(userDataDir);
}
if (headless) {
firefoxArguments.push('--headless');
}
if (devtools) {
firefoxArguments.push('--devtools');
}
if (args.every(arg => {
return arg.startsWith('-');
})) {
firefoxArguments.push('about:blank');
}
firefoxArguments.push(...args);
return firefoxArguments;
}
}
//# sourceMappingURL=FirefoxLauncher.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FirefoxLauncher.js","sourceRoot":"","sources":["../../../src/node/FirefoxLauncher.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,142 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { ChromeReleaseChannel as BrowsersChromeReleaseChannel } from '@puppeteer/browsers';
import type { ChromeReleaseChannel, ConnectOptions } from '../common/ConnectOptions.js';
import type { SupportedBrowser } from '../common/SupportedBrowser.js';
export type { ChromeReleaseChannel };
/**
* @internal
*/
export declare function convertPuppeteerChannelToBrowsersChannel(channel: ChromeReleaseChannel): BrowsersChromeReleaseChannel;
/**
* Generic launch options that can be passed when launching any browser.
* @public
*/
export interface LaunchOptions extends ConnectOptions {
/**
* If specified for Chrome, looks for a regular Chrome installation at a known
* system location instead of using the bundled Chrome binary.
*/
channel?: ChromeReleaseChannel;
/**
* Path to a browser executable to use instead of the bundled browser. Note
* that Puppeteer is only guaranteed to work with the bundled browser, so use
* this setting at your own risk.
*
* @remarks
* When using this is recommended to set the `browser` property as well
* as Puppeteer will default to `chrome` by default.
*/
executablePath?: string;
/**
* If `true`, do not use `puppeteer.defaultArgs()` when creating a browser. If
* an array is provided, these args will be filtered out. Use this with care -
* you probably want the default arguments Puppeteer uses.
* @defaultValue `false`
*/
ignoreDefaultArgs?: boolean | string[];
/**
* If `true`, avoids passing default arguments to the browser that would
* prevent extensions from being enabled. Passing a list of strings will
* load the provided paths as unpacked extensions.
*/
enableExtensions?: boolean | string[];
/**
* Close the browser process on `Ctrl+C`.
* @defaultValue `true`
*/
handleSIGINT?: boolean;
/**
* Close the browser process on `SIGTERM`.
* @defaultValue `true`
*/
handleSIGTERM?: boolean;
/**
* Close the browser process on `SIGHUP`.
* @defaultValue `true`
*/
handleSIGHUP?: boolean;
/**
* Maximum time in milliseconds to wait for the browser to start.
* Pass `0` to disable the timeout.
* @defaultValue `30_000` (30 seconds).
*/
timeout?: number;
/**
* If true, pipes the browser process stdout and stderr to `process.stdout`
* and `process.stderr`.
* @defaultValue `false`
*/
dumpio?: boolean;
/**
* Specify environment variables that will be visible to the browser.
* @defaultValue The contents of `process.env`.
*/
env?: Record<string, string | undefined>;
/**
* Connect to a browser over a pipe instead of a WebSocket. Only supported
* with Chrome.
*
* @defaultValue `false`
*/
pipe?: boolean;
/**
* Which browser to launch.
* @defaultValue `chrome`
*/
browser?: SupportedBrowser;
/**
* {@link https://searchfox.org/mozilla-release/source/modules/libpref/init/all.js | Additional preferences } that can be passed when launching with Firefox.
*/
extraPrefsFirefox?: Record<string, unknown>;
/**
* Whether to wait for the initial page to be ready.
* Useful when a user explicitly disables that (e.g. `--no-startup-window` for Chrome).
* @defaultValue `true`
*/
waitForInitialPage?: boolean;
/**
* Whether to run the browser in headless mode.
*
* @remarks
*
* - `true` launches the browser in the
* {@link https://developer.chrome.com/articles/new-headless/ | new headless}
* mode.
*
* - `'shell'` launches
* {@link https://developer.chrome.com/blog/chrome-headless-shell | shell}
* known as the old headless mode.
*
* @defaultValue `true`
*/
headless?: boolean | 'shell';
/**
* Path to a user data directory.
* {@link https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/user_data_dir.md | see the Chromium docs}
* for more info.
*/
userDataDir?: string;
/**
* Whether to auto-open a DevTools panel for each tab. If this is set to
* `true`, then `headless` will be forced to `false`.
* @defaultValue `false`
*/
devtools?: boolean;
/**
* Specify the debugging port number to use
*/
debuggingPort?: number;
/**
* Additional command line arguments to pass to the browser instance.
*/
args?: string[];
/**
* If provided, the browser will be closed when the signal is aborted.
*/
signal?: AbortSignal;
}
//# sourceMappingURL=LaunchOptions.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"LaunchOptions.d.ts","sourceRoot":"","sources":["../../../src/node/LaunchOptions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,oBAAoB,IAAI,4BAA4B,EAAC,MAAM,qBAAqB,CAAC;AAEzF,OAAO,KAAK,EACV,oBAAoB,EACpB,cAAc,EACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAEpE,YAAY,EAAC,oBAAoB,EAAC,CAAC;AAEnC;;GAEG;AACH,wBAAgB,wCAAwC,CACtD,OAAO,EAAE,oBAAoB,GAC5B,4BAA4B,CAW9B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD;;;OAGG;IACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IACvC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IACtC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB"}

View File

@@ -0,0 +1,22 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { ChromeReleaseChannel as BrowsersChromeReleaseChannel } from '@puppeteer/browsers';
/**
* @internal
*/
export function convertPuppeteerChannelToBrowsersChannel(channel) {
switch (channel) {
case 'chrome':
return BrowsersChromeReleaseChannel.STABLE;
case 'chrome-dev':
return BrowsersChromeReleaseChannel.DEV;
case 'chrome-beta':
return BrowsersChromeReleaseChannel.BETA;
case 'chrome-canary':
return BrowsersChromeReleaseChannel.CANARY;
}
}
//# sourceMappingURL=LaunchOptions.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"LaunchOptions.js","sourceRoot":"","sources":["../../../src/node/LaunchOptions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,oBAAoB,IAAI,4BAA4B,EAAC,MAAM,qBAAqB,CAAC;AAUzF;;GAEG;AACH,MAAM,UAAU,wCAAwC,CACtD,OAA6B;IAE7B,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,4BAA4B,CAAC,MAAM,CAAC;QAC7C,KAAK,YAAY;YACf,OAAO,4BAA4B,CAAC,GAAG,CAAC;QAC1C,KAAK,aAAa;YAChB,OAAO,4BAA4B,CAAC,IAAI,CAAC;QAC3C,KAAK,eAAe;YAClB,OAAO,4BAA4B,CAAC,MAAM,CAAC;IAC/C,CAAC;AACH,CAAC"}

View File

@@ -0,0 +1,20 @@
/**
* @license
* Copyright 2018 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import NodeWebSocket from 'ws';
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
/**
* @internal
*/
export declare class NodeWebSocketTransport implements ConnectionTransport {
#private;
static create(url: string, headers?: Record<string, string>): Promise<NodeWebSocketTransport>;
onmessage?: (message: NodeWebSocket.Data) => void;
onclose?: () => void;
constructor(ws: NodeWebSocket);
send(message: string): void;
close(): void;
}
//# sourceMappingURL=NodeWebSocketTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NodeWebSocketTransport.d.ts","sourceRoot":"","sources":["../../../src/node/NodeWebSocketTransport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,aAAa,MAAM,IAAI,CAAC;AAE/B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AAI1E;;GAEG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;;IAChE,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,sBAAsB,CAAC;IAqBlC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;gBAET,EAAE,EAAE,aAAa;IAgB7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,IAAI,IAAI;CAGd"}

View File

@@ -0,0 +1,56 @@
/**
* @license
* Copyright 2018 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import NodeWebSocket from 'ws';
import { debugError } from '../common/util.js';
import { packageVersion } from '../util/version.js';
/**
* @internal
*/
export class NodeWebSocketTransport {
static create(url, headers) {
return new Promise((resolve, reject) => {
const ws = new NodeWebSocket(url, [], {
followRedirects: true,
perMessageDeflate: false,
allowSynchronousEvents: false,
maxPayload: 256 * 1024 * 1024, // 256Mb
headers: {
'User-Agent': `Puppeteer ${packageVersion}`,
...headers,
},
});
ws.addEventListener('open', () => {
return resolve(new NodeWebSocketTransport(ws));
});
ws.addEventListener('error', reject);
});
}
#ws;
onmessage;
onclose;
constructor(ws) {
this.#ws = ws;
this.#ws.addEventListener('message', event => {
if (this.onmessage) {
this.onmessage.call(null, event.data);
}
});
this.#ws.addEventListener('close', () => {
if (this.onclose) {
this.onclose.call(null);
}
});
// Silently log all errors - we don't know what to do with them.
this.#ws.addEventListener('error', debugError);
}
send(message) {
this.#ws.send(message);
}
close() {
this.#ws.close();
}
}
//# sourceMappingURL=NodeWebSocketTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NodeWebSocketTransport.js","sourceRoot":"","sources":["../../../src/node/NodeWebSocketTransport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,aAAa,MAAM,IAAI,CAAC;AAG/B,OAAO,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAElD;;GAEG;AACH,MAAM,OAAO,sBAAsB;IACjC,MAAM,CAAC,MAAM,CACX,GAAW,EACX,OAAgC;QAEhC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE;gBACpC,eAAe,EAAE,IAAI;gBACrB,iBAAiB,EAAE,KAAK;gBACxB,sBAAsB,EAAE,KAAK;gBAC7B,UAAU,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;gBACvC,OAAO,EAAE;oBACP,YAAY,EAAE,aAAa,cAAc,EAAE;oBAC3C,GAAG,OAAO;iBACX;aACF,CAAC,CAAC;YAEH,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC/B,OAAO,OAAO,CAAC,IAAI,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;YACH,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAgB;IACnB,SAAS,CAAyC;IAClD,OAAO,CAAc;IAErB,YAAY,EAAiB;QAC3B,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE;YAC3C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACtC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC,CAAC;QACH,gEAAgE;QAChE,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;CACF"}

View File

@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2018 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
/**
* @internal
*/
export declare class PipeTransport implements ConnectionTransport {
#private;
onclose?: () => void;
onmessage?: (value: string) => void;
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream);
send(message: string): void;
close(): void;
}
//# sourceMappingURL=PipeTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"PipeTransport.d.ts","sourceRoot":"","sources":["../../../src/node/PipeTransport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AAM1E;;GAEG;AACH,qBAAa,aAAc,YAAW,mBAAmB;;IAOvD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;gBAGlC,SAAS,EAAE,MAAM,CAAC,cAAc,EAChC,QAAQ,EAAE,MAAM,CAAC,cAAc;IA6BjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAmC3B,KAAK,IAAI,IAAI;CAId"}

View File

@@ -0,0 +1,72 @@
import { EventEmitter } from '../common/EventEmitter.js';
import { debugError } from '../common/util.js';
import { assert } from '../util/assert.js';
import { DisposableStack } from '../util/disposable.js';
/**
* @internal
*/
export class PipeTransport {
#pipeWrite;
#subscriptions = new DisposableStack();
#isClosed = false;
#pendingMessage = [];
onclose;
onmessage;
constructor(pipeWrite, pipeRead) {
this.#pipeWrite = pipeWrite;
const pipeReadEmitter = this.#subscriptions.use(
// NodeJS event emitters don't support `*` so we need to typecast
// As long as we don't use it we should be OK.
new EventEmitter(pipeRead));
pipeReadEmitter.on('data', buffer => {
return this.#dispatch(buffer);
});
pipeReadEmitter.on('close', () => {
if (this.onclose) {
this.onclose.call(null);
}
});
pipeReadEmitter.on('error', debugError);
const pipeWriteEmitter = this.#subscriptions.use(
// NodeJS event emitters don't support `*` so we need to typecast
// As long as we don't use it we should be OK.
new EventEmitter(pipeWrite));
pipeWriteEmitter.on('error', debugError);
}
send(message) {
assert(!this.#isClosed, '`PipeTransport` is closed.');
this.#pipeWrite.write(message);
this.#pipeWrite.write('\0');
}
#dispatch(buffer) {
assert(!this.#isClosed, '`PipeTransport` is closed.');
this.#pendingMessage.push(buffer);
if (buffer.indexOf('\0') === -1) {
return;
}
const concatBuffer = Buffer.concat(this.#pendingMessage);
let start = 0;
let end = concatBuffer.indexOf('\0');
while (end !== -1) {
const message = concatBuffer.toString(undefined, start, end);
setImmediate(() => {
if (this.onmessage) {
this.onmessage.call(null, message);
}
});
start = end + 1;
end = concatBuffer.indexOf('\0', start);
}
if (start >= concatBuffer.length) {
this.#pendingMessage = [];
}
else {
this.#pendingMessage = [concatBuffer.subarray(start)];
}
}
close() {
this.#isClosed = true;
this.#subscriptions.dispose();
}
}
//# sourceMappingURL=PipeTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"PipeTransport.js","sourceRoot":"","sources":["../../../src/node/PipeTransport.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,153 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Browser } from '../api/Browser.js';
import type { Configuration } from '../common/Configuration.js';
import type { ConnectOptions } from '../common/ConnectOptions.js';
import { type CommonPuppeteerSettings, Puppeteer } from '../common/Puppeteer.js';
import type { SupportedBrowser } from '../common/SupportedBrowser.js';
import type { ChromeReleaseChannel, LaunchOptions } from './LaunchOptions.js';
/**
* Extends the main {@link Puppeteer} class with Node specific behaviour for
* fetching and downloading browsers.
*
* If you're using Puppeteer in a Node environment, this is the class you'll get
* when you run `require('puppeteer')` (or the equivalent ES `import`).
*
* @remarks
* The most common method to use is {@link PuppeteerNode.launch | launch}, which
* is used to launch and connect to a new browser instance.
*
* See {@link Puppeteer | the main Puppeteer class} for methods common to all
* environments, such as {@link Puppeteer.connect}.
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
*
* ```ts
* import puppeteer from 'puppeteer';
*
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* @public
*/
export declare class PuppeteerNode extends Puppeteer {
#private;
configuration: () => Promise<Configuration>;
/**
* @internal
*/
constructor(settings: {
configuration?: () => Promise<Configuration>;
} & CommonPuppeteerSettings);
/**
* This method attaches Puppeteer to an existing browser instance.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
connect(options: ConnectOptions): Promise<Browser>;
/**
* Launches a browser instance with given arguments and options when
* specified.
*
* When using with `puppeteer-core`,
* {@link LaunchOptions.executablePath | options.executablePath} or
* {@link LaunchOptions.channel | options.channel} must be provided.
*
* @example
* You can use {@link LaunchOptions.ignoreDefaultArgs | options.ignoreDefaultArgs}
* to filter out `--mute-audio` from default arguments:
*
* ```ts
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio'],
* });
* ```
*
* @remarks
* Puppeteer can also be used to control the Chrome browser, but it works best
* with the version of Chrome for Testing downloaded by default.
* There is no guarantee it will work with any other version. If Google Chrome
* (rather than Chrome for Testing) is preferred, a
* {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary}
* or
* {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel}
* build is suggested. See
* {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article}
* for a description of the differences between Chromium and Chrome.
* {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article}
* describes some differences for Linux users. See
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.
*
* @param options - Options to configure launching behavior.
*/
launch(options?: LaunchOptions): Promise<Browser>;
/**
* The default executable path for a given ChromeReleaseChannel.
*/
executablePath(channel: ChromeReleaseChannel): Promise<string>;
/**
* The default executable path given LaunchOptions.
*/
executablePath(options: LaunchOptions): Promise<string>;
/**
* The default executable path.
*/
executablePath(): Promise<string>;
/**
* @internal
*/
browserVersion(): Promise<string>;
/**
* The default download path for puppeteer. For puppeteer-core, this
* code should never be called as it is never defined.
*
* @internal
*/
defaultDownloadPath(): Promise<string | undefined>;
/**
* The name of the browser that was last launched.
*/
lastLaunchedBrowser(): Promise<SupportedBrowser>;
/**
* The name of the browser that will be launched by default. For
* `puppeteer`, this is influenced by your configuration. Otherwise, it's
* `chrome`.
*/
defaultBrowser(): Promise<SupportedBrowser>;
/**
* @param options - Set of configurable options to set on the browser.
*
* @returns The default arguments that the browser will be launched with.
*/
defaultArgs(options?: LaunchOptions): Promise<string[]>;
/**
* Removes all non-current Firefox and Chrome binaries in the cache directory
* identified by the provided Puppeteer configuration. The current browser
* version is determined by resolving PUPPETEER_REVISIONS from Puppeteer
* unless `configuration.browserRevision` is provided.
*
* @remarks
*
* Note that the method does not check if any other Puppeteer versions
* installed on the host that use the same cache directory require the
* non-current binaries.
*
* @public
*/
trimCache(): Promise<void>;
}
//# sourceMappingURL=PuppeteerNode.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"PuppeteerNode.d.ts","sourceRoot":"","sources":["../../../src/node/PuppeteerNode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAC,KAAK,uBAAuB,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAC/E,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAMpE,OAAO,KAAK,EAAC,oBAAoB,EAAE,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,aAAc,SAAQ,SAAS;;IAG1C,aAAa,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;IAE5C;;OAEG;gBAED,QAAQ,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;KAC9C,GAAG,uBAAuB;IAmB7B;;;;;OAKG;IACM,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACG,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IA2B3D;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9D;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IACvD;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAoBjC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAMvC;;;;;OAKG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKxD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAItD;;;;OAIG;IACG,cAAc,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAKjD;;;;OAIG;IACG,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMjE;;;;;;;;;;;;;OAaG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyEjC"}

View File

@@ -0,0 +1,254 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { Browser as browsers_SupportedBrowser, resolveBuildId, detectBrowserPlatform, getInstalledBrowsers, uninstall, } from '@puppeteer/browsers';
import { Puppeteer } from '../common/Puppeteer.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { ChromeLauncher } from './ChromeLauncher.js';
import { FirefoxLauncher } from './FirefoxLauncher.js';
/**
* Extends the main {@link Puppeteer} class with Node specific behaviour for
* fetching and downloading browsers.
*
* If you're using Puppeteer in a Node environment, this is the class you'll get
* when you run `require('puppeteer')` (or the equivalent ES `import`).
*
* @remarks
* The most common method to use is {@link PuppeteerNode.launch | launch}, which
* is used to launch and connect to a new browser instance.
*
* See {@link Puppeteer | the main Puppeteer class} for methods common to all
* environments, such as {@link Puppeteer.connect}.
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
*
* ```ts
* import puppeteer from 'puppeteer';
*
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* @public
*/
export class PuppeteerNode extends Puppeteer {
#launcher;
#lastLaunchedBrowser;
configuration;
/**
* @internal
*/
constructor(settings) {
const { configuration, ...commonSettings } = settings;
super(commonSettings);
if (configuration) {
this.configuration = configuration;
}
else {
this.configuration = () => {
return Promise.resolve({});
};
}
this.connect = this.connect.bind(this);
this.launch = this.launch.bind(this);
this.executablePath = this.executablePath.bind(this);
this.defaultArgs = this.defaultArgs.bind(this);
this.trimCache = this.trimCache.bind(this);
}
/**
* This method attaches Puppeteer to an existing browser instance.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
connect(options) {
return super.connect(options);
}
/**
* Launches a browser instance with given arguments and options when
* specified.
*
* When using with `puppeteer-core`,
* {@link LaunchOptions.executablePath | options.executablePath} or
* {@link LaunchOptions.channel | options.channel} must be provided.
*
* @example
* You can use {@link LaunchOptions.ignoreDefaultArgs | options.ignoreDefaultArgs}
* to filter out `--mute-audio` from default arguments:
*
* ```ts
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio'],
* });
* ```
*
* @remarks
* Puppeteer can also be used to control the Chrome browser, but it works best
* with the version of Chrome for Testing downloaded by default.
* There is no guarantee it will work with any other version. If Google Chrome
* (rather than Chrome for Testing) is preferred, a
* {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary}
* or
* {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel}
* build is suggested. See
* {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article}
* for a description of the differences between Chromium and Chrome.
* {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article}
* describes some differences for Linux users. See
* {@link https://developer.chrome.com/blog/chrome-for-testing/ | this doc} for the description
* of Chrome for Testing.
*
* @param options - Options to configure launching behavior.
*/
async launch(options = {}) {
const { browser = await this.defaultBrowser() } = options;
this.#lastLaunchedBrowser = browser;
if (!['chrome', 'firefox'].includes(browser)) {
throw new Error(`Unknown product: ${browser}`);
}
this.#launcher = this.#getLauncher(browser);
return await this.#launcher.launch(options);
}
/**
* @internal
*/
#getLauncher(browser) {
if (this.#launcher && this.#launcher.browser === browser) {
return this.#launcher;
}
switch (browser) {
case 'chrome':
return new ChromeLauncher(this);
case 'firefox':
return new FirefoxLauncher(this);
default:
throw new Error(`Unknown product: ${browser}`);
}
}
async executablePath(optsOrChannel) {
if (optsOrChannel === undefined) {
return await this.#getLauncher(await this.lastLaunchedBrowser()).executablePath(undefined, /* validatePath= */ false);
}
if (typeof optsOrChannel === 'string') {
return await this.#getLauncher('chrome').executablePath(optsOrChannel,
/* validatePath= */ false);
}
return await this.#getLauncher(optsOrChannel.browser ?? (await this.lastLaunchedBrowser())).resolveExecutablePath(optsOrChannel.headless, /* validatePath= */ false);
}
/**
* @internal
*/
async browserVersion() {
const config = await this.configuration();
const lastLaunched = await this.lastLaunchedBrowser();
return config?.[lastLaunched]?.version ?? PUPPETEER_REVISIONS[lastLaunched];
}
/**
* The default download path for puppeteer. For puppeteer-core, this
* code should never be called as it is never defined.
*
* @internal
*/
async defaultDownloadPath() {
const config = await this.configuration();
return config.cacheDirectory;
}
/**
* The name of the browser that was last launched.
*/
async lastLaunchedBrowser() {
return this.#lastLaunchedBrowser ?? (await this.defaultBrowser());
}
/**
* The name of the browser that will be launched by default. For
* `puppeteer`, this is influenced by your configuration. Otherwise, it's
* `chrome`.
*/
async defaultBrowser() {
const config = await this.configuration();
return config.defaultBrowser ?? 'chrome';
}
/**
* @param options - Set of configurable options to set on the browser.
*
* @returns The default arguments that the browser will be launched with.
*/
async defaultArgs(options = {}) {
return this.#getLauncher(options.browser ?? (await this.lastLaunchedBrowser())).defaultArgs(options);
}
/**
* Removes all non-current Firefox and Chrome binaries in the cache directory
* identified by the provided Puppeteer configuration. The current browser
* version is determined by resolving PUPPETEER_REVISIONS from Puppeteer
* unless `configuration.browserRevision` is provided.
*
* @remarks
*
* Note that the method does not check if any other Puppeteer versions
* installed on the host that use the same cache directory require the
* non-current binaries.
*
* @public
*/
async trimCache() {
const platform = detectBrowserPlatform();
if (!platform) {
throw new Error('The current platform is not supported.');
}
const config = await this.configuration();
const cacheDir = config.cacheDirectory;
const installedBrowsers = await getInstalledBrowsers({
cacheDir,
});
const puppeteerBrowsers = [
{
product: 'chrome',
browser: browsers_SupportedBrowser.CHROME,
currentBuildId: '',
},
{
product: 'firefox',
browser: browsers_SupportedBrowser.FIREFOX,
currentBuildId: '',
},
];
// Resolve current buildIds.
await Promise.all(puppeteerBrowsers.map(async (item) => {
const tag = config?.[item.product]?.version ?? PUPPETEER_REVISIONS[item.product];
item.currentBuildId = await resolveBuildId(item.browser, platform, tag);
}));
const currentBrowserBuilds = new Set(puppeteerBrowsers.map(browser => {
return `${browser.browser}_${browser.currentBuildId}`;
}));
const currentBrowsers = new Set(puppeteerBrowsers.map(browser => {
return browser.browser;
}));
for (const installedBrowser of installedBrowsers) {
// Don't uninstall browsers that are not managed by Puppeteer yet.
if (!currentBrowsers.has(installedBrowser.browser)) {
continue;
}
// Keep the browser build used by the current Puppeteer installation.
if (currentBrowserBuilds.has(`${installedBrowser.browser}_${installedBrowser.buildId}`)) {
continue;
}
await uninstall({
browser: installedBrowser.browser,
platform,
cacheDir,
buildId: installedBrowser.buildId,
});
}
}
}
//# sourceMappingURL=PuppeteerNode.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { PassThrough } from 'node:stream';
import type { BoundingBox } from '../api/ElementHandle.js';
import type { Page, VideoFormat } from '../api/Page.js';
import { asyncDisposeSymbol } from '../util/disposable.js';
/**
* @internal
*/
export interface ScreenRecorderOptions {
ffmpegPath?: string;
speed?: number;
crop?: BoundingBox;
format?: VideoFormat;
fps?: number;
loop?: number;
delay?: number;
quality?: number;
colors?: number;
scale?: number;
path?: `${string}.${VideoFormat}`;
overwrite?: boolean;
}
/**
* @public
*/
export declare class ScreenRecorder extends PassThrough {
#private;
/**
* @internal
*/
constructor(page: Page, width: number, height: number, { ffmpegPath, speed, scale, crop, format, fps, loop, delay, quality, colors, path, overwrite, }?: ScreenRecorderOptions);
/**
* Stops the recorder.
*
* @public
*/
stop(): Promise<void>;
/**
* @internal
*/
[asyncDisposeSymbol](): Promise<void>;
}
//# sourceMappingURL=ScreenRecorder.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ScreenRecorder.d.ts","sourceRoot":"","sources":["../../../src/node/ScreenRecorder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAexC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAC,IAAI,EAAE,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAItD,OAAO,EAAC,kBAAkB,EAAC,MAAM,uBAAuB,CAAC;AAOzD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,MAAM,IAAI,WAAW,EAAE,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,WAAW;;IAU7C;;OAEG;gBAED,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,EACE,UAAU,EACV,KAAK,EACL,KAAK,EACL,IAAI,EACJ,MAAM,EACN,GAAG,EACH,IAAI,EACJ,KAAK,EACL,OAAO,EACP,MAAM,EACN,IAAI,EACJ,SAAS,GACV,GAAE,qBAA0B;IA0N/B;;;;OAIG;IAEG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B3B;;OAEG;IACY,CAAC,kBAAkB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAIrD"}

View File

@@ -0,0 +1,280 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
import { spawn, spawnSync } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import { dirname } from 'node:path';
import { PassThrough } from 'node:stream';
import { bufferCount, concatMap, filter, from, fromEvent, lastValueFrom, map, takeUntil, tap, } from '../../third_party/rxjs/rxjs.js';
import { CDPSessionEvent } from '../api/CDPSession.js';
import { debug } from '../common/Debug.js';
import { debugError, fromEmitterEvent } from '../common/util.js';
import { guarded } from '../util/decorators.js';
import { asyncDisposeSymbol } from '../util/disposable.js';
const CRF_VALUE = 30;
const DEFAULT_FPS = 30;
const debugFfmpeg = debug('puppeteer:ffmpeg');
/**
* @public
*/
let ScreenRecorder = (() => {
let _classSuper = PassThrough;
let _instanceExtraInitializers = [];
let _private_writeFrame_decorators;
let _private_writeFrame_descriptor;
let _stop_decorators;
return class ScreenRecorder extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
__esDecorate(this, _private_writeFrame_descriptor = { value: __setFunctionName(async function (buffer) {
const error = await new Promise(resolve => {
this.#process.stdin.write(buffer, resolve);
});
if (error) {
console.log(`ffmpeg failed to write: ${error.message}.`);
}
}, "#writeFrame") }, _private_writeFrame_decorators, { kind: "method", name: "#writeFrame", static: false, private: true, access: { has: obj => #writeFrame in obj, get: obj => obj.#writeFrame }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _stop_decorators, { kind: "method", name: "stop", static: false, private: false, access: { has: obj => "stop" in obj, get: obj => obj.stop }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
#page = __runInitializers(this, _instanceExtraInitializers);
#process;
#controller = new AbortController();
#lastFrame;
#fps;
/**
* @internal
*/
constructor(page, width, height, { ffmpegPath, speed, scale, crop, format, fps, loop, delay, quality, colors, path, overwrite, } = {}) {
super({ allowHalfOpen: false });
ffmpegPath ??= 'ffmpeg';
format ??= 'webm';
fps ??= DEFAULT_FPS;
// Maps 0 to -1 as ffmpeg maps 0 to infinity.
loop ||= -1;
delay ??= -1;
quality ??= CRF_VALUE;
colors ??= 256;
overwrite ??= true;
this.#fps = fps;
// Tests if `ffmpeg` exists.
const { error } = spawnSync(ffmpegPath);
if (error) {
throw error;
}
const filters = [
`crop='min(${width},iw):min(${height},ih):0:0'`,
`pad=${width}:${height}:0:0`,
];
if (speed) {
filters.push(`setpts=${1 / speed}*PTS`);
}
if (crop) {
filters.push(`crop=${crop.width}:${crop.height}:${crop.x}:${crop.y}`);
}
if (scale) {
filters.push(`scale=iw*${scale}:-1:flags=lanczos`);
}
const formatArgs = this.#getFormatArgs(format, fps, loop, delay, quality, colors);
const vf = formatArgs.indexOf('-vf');
if (vf !== -1) {
filters.push(formatArgs.splice(vf, 2).at(-1) ?? '');
}
// Ensure provided output directory path exists.
if (path) {
fs.mkdirSync(dirname(path), { recursive: overwrite });
}
this.#process = spawn(ffmpegPath,
// See https://trac.ffmpeg.org/wiki/Encode/VP9 for more information on flags.
[
['-loglevel', 'error'],
// Reduces general buffering.
['-avioflags', 'direct'],
// Reduces initial buffering while analyzing input fps and other stats.
[
'-fpsprobesize',
'0',
'-probesize',
'32',
'-analyzeduration',
'0',
'-fflags',
'nobuffer',
],
// Forces input to be read from standard input, and forces png input
// image format.
['-f', 'image2pipe', '-vcodec', 'png', '-i', 'pipe:0'],
// No audio
['-an'],
// This drastically reduces stalling when cpu is overbooked. By default
// VP9 tries to use all available threads?
['-threads', '1'],
// Specifies the frame rate we are giving ffmpeg.
['-framerate', `${fps}`],
// Disable bitrate.
['-b:v', '0'],
// Specifies the encoding and format we are using.
formatArgs,
// Filters to ensure the images are piped correctly,
// combined with any format-specific filters.
['-vf', filters.join()],
// Overwrite output, or exit immediately if file already exists.
[overwrite ? '-y' : '-n'],
'pipe:1',
].flat(), { stdio: ['pipe', 'pipe', 'pipe'] });
this.#process.stdout.pipe(this);
this.#process.stderr.on('data', (data) => {
debugFfmpeg(data.toString('utf8'));
});
this.#page = page;
const { client } = this.#page.mainFrame();
client.once(CDPSessionEvent.Disconnected, () => {
void this.stop().catch(debugError);
});
this.#lastFrame = lastValueFrom(fromEmitterEvent(client, 'Page.screencastFrame').pipe(tap(event => {
void client.send('Page.screencastFrameAck', {
sessionId: event.sessionId,
});
}), filter(event => {
return event.metadata.timestamp !== undefined;
}), map(event => {
return {
buffer: Buffer.from(event.data, 'base64'),
timestamp: event.metadata.timestamp,
};
}), bufferCount(2, 1), concatMap(([{ timestamp: previousTimestamp, buffer }, { timestamp }]) => {
return from(Array(Math.round(fps * Math.max(timestamp - previousTimestamp, 0))).fill(buffer));
}), map(buffer => {
void this.#writeFrame(buffer);
return [buffer, performance.now()];
}), takeUntil(fromEvent(this.#controller.signal, 'abort'))), { defaultValue: [Buffer.from([]), performance.now()] });
}
#getFormatArgs(format, fps, loop, delay, quality, colors) {
const libvpx = [
['-vcodec', 'vp9'],
// Sets the quality. Lower the better.
['-crf', `${quality}`],
// Sets the quality and how efficient the compression will be.
[
'-deadline',
'realtime',
'-cpu-used',
`${Math.min(os.cpus().length / 2, 8)}`,
],
];
switch (format) {
case 'webm':
return [
...libvpx,
// Sets the format
['-f', 'webm'],
].flat();
case 'gif':
fps = DEFAULT_FPS === fps ? 20 : 'source_fps';
if (loop === Infinity) {
loop = 0;
}
if (delay !== -1) {
// ms to cs
delay /= 10;
}
return [
// Sets the frame rate and uses a custom palette generated from the
// input.
[
'-vf',
`fps=${fps},split[s0][s1];[s0]palettegen=stats_mode=diff:max_colors=${colors}[p];[s1][p]paletteuse=dither=bayer`,
],
// Sets the number of times to loop playback.
['-loop', `${loop}`],
// Sets the delay between iterations of a loop.
['-final_delay', `${delay}`],
// Sets the format
['-f', 'gif'],
].flat();
case 'mp4':
return [
...libvpx,
// Fragment file during stream to avoid errors.
['-movflags', 'hybrid_fragmented'],
// Sets the format
['-f', 'mp4'],
].flat();
}
}
get #writeFrame() { return _private_writeFrame_descriptor.value; }
/**
* Stops the recorder.
*
* @public
*/
async stop() {
if (this.#controller.signal.aborted) {
return;
}
// Stopping the screencast will flush the frames.
await this.#page._stopScreencast().catch(debugError);
this.#controller.abort();
// Repeat the last frame for the remaining frames.
const [buffer, timestamp] = await this.#lastFrame;
await Promise.all(Array(Math.max(1, Math.round((this.#fps * (performance.now() - timestamp)) / 1000)))
.fill(buffer)
.map(this.#writeFrame.bind(this)));
// Close stdin to notify FFmpeg we are done.
this.#process.stdin.end();
await new Promise(resolve => {
this.#process.once('close', resolve);
});
}
/**
* @internal
*/
async [(_private_writeFrame_decorators = [guarded()], _stop_decorators = [guarded()], asyncDisposeSymbol)]() {
await this.stop();
await super[asyncDisposeSymbol]();
}
};
})();
export { ScreenRecorder };
//# sourceMappingURL=ScreenRecorder.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,13 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
export * from './ChromeLauncher.js';
export * from './FirefoxLauncher.js';
export type * from './LaunchOptions.js';
export * from './PipeTransport.js';
export * from './BrowserLauncher.js';
export * from './PuppeteerNode.js';
export * from './ScreenRecorder.js';
//# sourceMappingURL=node.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/node/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,mBAAmB,oBAAoB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}

12
node_modules/puppeteer-core/lib/puppeteer/node/node.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
export * from './ChromeLauncher.js';
export * from './FirefoxLauncher.js';
export * from './PipeTransport.js';
export * from './BrowserLauncher.js';
export * from './PuppeteerNode.js';
export * from './ScreenRecorder.js';
//# sourceMappingURL=node.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../src/node/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAErC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}

View File

@@ -0,0 +1,14 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @internal
*/
export declare function rm(path: string): Promise<void>;
/**
* @internal
*/
export declare function rmSync(path: string): void;
//# sourceMappingURL=fs.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../src/node/util/fs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH;;GAEG;AACH,wBAAsB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEzC"}

View File

@@ -0,0 +1,24 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import fs from 'node:fs';
const rmOptions = {
force: true,
recursive: true,
maxRetries: 5,
};
/**
* @internal
*/
export async function rm(path) {
await fs.promises.rm(path, rmOptions);
}
/**
* @internal
*/
export function rmSync(path) {
fs.rmSync(path, rmOptions);
}
//# sourceMappingURL=fs.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../../src/node/util/fs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,SAAS,GAAG;IAChB,KAAK,EAAE,IAAI;IACX,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,IAAY;IACnC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AAC7B,CAAC"}