"use strict"; /** * Copyright 2017 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CdpBrowserContext = exports.CdpBrowser = void 0; const Browser_js_1 = require("../api/Browser.js"); const BrowserContext_js_1 = require("../api/BrowserContext.js"); const CDPSession_js_1 = require("../api/CDPSession.js"); const environment_js_1 = require("../environment.js"); const assert_js_1 = require("../util/assert.js"); const ChromeTargetManager_js_1 = require("./ChromeTargetManager.js"); const FirefoxTargetManager_js_1 = require("./FirefoxTargetManager.js"); const Target_js_1 = require("./Target.js"); /** * @internal */ class CdpBrowser extends Browser_js_1.Browser { static async _create(product, connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets = true, useTabTarget = environment_js_1.USE_TAB_TARGET) { const browser = new CdpBrowser(product, connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets, useTabTarget); await browser._attach(); return browser; } #ignoreHTTPSErrors; #defaultViewport; #process; #connection; #closeCallback; #targetFilterCallback; #isPageTargetCallback; #defaultContext; #contexts = new Map(); #targetManager; get _targets() { return this.#targetManager.getAvailableTargets(); } constructor(product, connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets = true, useTabTarget = environment_js_1.USE_TAB_TARGET) { super(); product = product || 'chrome'; this.#ignoreHTTPSErrors = ignoreHTTPSErrors; this.#defaultViewport = defaultViewport; this.#process = process; this.#connection = connection; this.#closeCallback = closeCallback || function () { }; this.#targetFilterCallback = targetFilterCallback || (() => { return true; }); this.#setIsPageTargetCallback(isPageTargetCallback); if (product === 'firefox') { this.#targetManager = new FirefoxTargetManager_js_1.FirefoxTargetManager(connection, this.#createTarget, this.#targetFilterCallback); } else { this.#targetManager = new ChromeTargetManager_js_1.ChromeTargetManager(connection, this.#createTarget, this.#targetFilterCallback, waitForInitiallyDiscoveredTargets, useTabTarget); } this.#defaultContext = new CdpBrowserContext(this.#connection, this); for (const contextId of contextIds) { this.#contexts.set(contextId, new CdpBrowserContext(this.#connection, this, contextId)); } } #emitDisconnected = () => { this.emit("disconnected" /* BrowserEvent.Disconnected */, undefined); }; async _attach() { this.#connection.on(CDPSession_js_1.CDPSessionEvent.Disconnected, this.#emitDisconnected); this.#targetManager.on("targetAvailable" /* TargetManagerEvent.TargetAvailable */, this.#onAttachedToTarget); this.#targetManager.on("targetGone" /* TargetManagerEvent.TargetGone */, this.#onDetachedFromTarget); this.#targetManager.on("targetChanged" /* TargetManagerEvent.TargetChanged */, this.#onTargetChanged); this.#targetManager.on("targetDiscovered" /* TargetManagerEvent.TargetDiscovered */, this.#onTargetDiscovered); await this.#targetManager.initialize(); } _detach() { this.#connection.off(CDPSession_js_1.CDPSessionEvent.Disconnected, this.#emitDisconnected); this.#targetManager.off("targetAvailable" /* TargetManagerEvent.TargetAvailable */, this.#onAttachedToTarget); this.#targetManager.off("targetGone" /* TargetManagerEvent.TargetGone */, this.#onDetachedFromTarget); this.#targetManager.off("targetChanged" /* TargetManagerEvent.TargetChanged */, this.#onTargetChanged); this.#targetManager.off("targetDiscovered" /* TargetManagerEvent.TargetDiscovered */, this.#onTargetDiscovered); } process() { return this.#process ?? null; } _targetManager() { return this.#targetManager; } #setIsPageTargetCallback(isPageTargetCallback) { this.#isPageTargetCallback = isPageTargetCallback || ((target) => { return (target.type() === 'page' || target.type() === 'background_page' || target.type() === 'webview'); }); } _getIsPageTargetCallback() { return this.#isPageTargetCallback; } async createIncognitoBrowserContext(options = {}) { const { proxyServer, proxyBypassList } = options; const { browserContextId } = await this.#connection.send('Target.createBrowserContext', { proxyServer, proxyBypassList: proxyBypassList && proxyBypassList.join(','), }); const context = new CdpBrowserContext(this.#connection, this, browserContextId); this.#contexts.set(browserContextId, context); return context; } browserContexts() { return [this.#defaultContext, ...Array.from(this.#contexts.values())]; } defaultBrowserContext() { return this.#defaultContext; } async _disposeContext(contextId) { if (!contextId) { return; } await this.#connection.send('Target.disposeBrowserContext', { browserContextId: contextId, }); this.#contexts.delete(contextId); } #createTarget = (targetInfo, session) => { const { browserContextId } = targetInfo; const context = browserContextId && this.#contexts.has(browserContextId) ? this.#contexts.get(browserContextId) : this.#defaultContext; if (!context) { throw new Error('Missing browser context'); } const createSession = (isAutoAttachEmulated) => { return this.#connection._createSession(targetInfo, isAutoAttachEmulated); }; const otherTarget = new Target_js_1.OtherTarget(targetInfo, session, context, this.#targetManager, createSession); if (targetInfo.url?.startsWith('devtools://')) { return new Target_js_1.DevToolsTarget(targetInfo, session, context, this.#targetManager, createSession, this.#ignoreHTTPSErrors, this.#defaultViewport ?? null); } if (this.#isPageTargetCallback(otherTarget)) { return new Target_js_1.PageTarget(targetInfo, session, context, this.#targetManager, createSession, this.#ignoreHTTPSErrors, this.#defaultViewport ?? null); } if (targetInfo.type === 'service_worker' || targetInfo.type === 'shared_worker') { return new Target_js_1.WorkerTarget(targetInfo, session, context, this.#targetManager, createSession); } return otherTarget; }; #onAttachedToTarget = async (target) => { if ((await target._initializedDeferred.valueOrThrow()) === Target_js_1.InitializationStatus.SUCCESS) { this.emit("targetcreated" /* BrowserEvent.TargetCreated */, target); target.browserContext().emit("targetcreated" /* BrowserContextEvent.TargetCreated */, target); } }; #onDetachedFromTarget = async (target) => { target._initializedDeferred.resolve(Target_js_1.InitializationStatus.ABORTED); target._isClosedDeferred.resolve(); if ((await target._initializedDeferred.valueOrThrow()) === Target_js_1.InitializationStatus.SUCCESS) { this.emit("targetdestroyed" /* BrowserEvent.TargetDestroyed */, target); target.browserContext().emit("targetdestroyed" /* BrowserContextEvent.TargetDestroyed */, target); } }; #onTargetChanged = ({ target }) => { this.emit("targetchanged" /* BrowserEvent.TargetChanged */, target); target.browserContext().emit("targetchanged" /* BrowserContextEvent.TargetChanged */, target); }; #onTargetDiscovered = (targetInfo) => { this.emit("targetdiscovered" /* BrowserEvent.TargetDiscovered */, targetInfo); }; wsEndpoint() { return this.#connection.url(); } async newPage() { return await this.#defaultContext.newPage(); } async _createPageInContext(contextId) { const { targetId } = await this.#connection.send('Target.createTarget', { url: 'about:blank', browserContextId: contextId || undefined, }); const target = (await this.waitForTarget(t => { return t._targetId === targetId; })); if (!target) { throw new Error(`Missing target for page (id = ${targetId})`); } const initialized = (await target._initializedDeferred.valueOrThrow()) === Target_js_1.InitializationStatus.SUCCESS; if (!initialized) { throw new Error(`Failed to create target for page (id = ${targetId})`); } const page = await target.page(); if (!page) { throw new Error(`Failed to create a page for context (id = ${contextId})`); } return page; } targets() { return Array.from(this.#targetManager.getAvailableTargets().values()).filter(target => { return (target._initializedDeferred.value() === Target_js_1.InitializationStatus.SUCCESS); }); } target() { const browserTarget = this.targets().find(target => { return target.type() === 'browser'; }); if (!browserTarget) { throw new Error('Browser target is not found'); } return browserTarget; } async version() { const version = await this.#getVersion(); return version.product; } async userAgent() { const version = await this.#getVersion(); return version.userAgent; } async close() { await this.#closeCallback.call(null); this.disconnect(); } disconnect() { this.#targetManager.dispose(); this.#connection.dispose(); this._detach(); } get connected() { return !this.#connection._closed; } #getVersion() { return this.#connection.send('Browser.getVersion'); } } exports.CdpBrowser = CdpBrowser; /** * @internal */ class CdpBrowserContext extends BrowserContext_js_1.BrowserContext { #connection; #browser; #id; constructor(connection, browser, contextId) { super(); this.#connection = connection; this.#browser = browser; this.#id = contextId; } get id() { return this.#id; } targets() { return this.#browser.targets().filter(target => { return target.browserContext() === this; }); } waitForTarget(predicate, options = {}) { return this.#browser.waitForTarget(target => { return target.browserContext() === this && predicate(target); }, options); } async pages() { const pages = await Promise.all(this.targets() .filter(target => { return (target.type() === 'page' || (target.type() === 'other' && this.#browser._getIsPageTargetCallback()?.(target))); }) .map(target => { return target.page(); })); return pages.filter((page) => { return !!page; }); } isIncognito() { return !!this.#id; } async overridePermissions(origin, permissions) { const protocolPermissions = permissions.map(permission => { const protocolPermission = Browser_js_1.WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission); if (!protocolPermission) { throw new Error('Unknown permission: ' + permission); } return protocolPermission; }); await this.#connection.send('Browser.grantPermissions', { origin, browserContextId: this.#id || undefined, permissions: protocolPermissions, }); } async clearPermissionOverrides() { await this.#connection.send('Browser.resetPermissions', { browserContextId: this.#id || undefined, }); } newPage() { return this.#browser._createPageInContext(this.#id); } browser() { return this.#browser; } async close() { (0, assert_js_1.assert)(this.#id, 'Non-incognito profiles cannot be closed!'); await this.#browser._disposeContext(this.#id); } } exports.CdpBrowserContext = CdpBrowserContext; //# sourceMappingURL=Browser.js.map