"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BrowserContextDispatcher = void 0; var _browserContext = require("../browserContext"); var _dispatcher = require("./dispatcher"); var _pageDispatcher = require("./pageDispatcher"); var _networkDispatchers = require("./networkDispatchers"); var _crBrowser = require("../chromium/crBrowser"); var _cdpSessionDispatcher = require("./cdpSessionDispatcher"); var _recorder = require("../recorder"); var _artifactDispatcher = require("./artifactDispatcher"); var _tracingDispatcher = require("./tracingDispatcher"); var fs = _interopRequireWildcard(require("fs")); var path = _interopRequireWildcard(require("path")); var _utils = require("../../utils"); var _writableStreamDispatcher = require("./writableStreamDispatcher"); var _dialogDispatcher = require("./dialogDispatcher"); var _errors = require("../errors"); var _elementHandlerDispatcher = require("./elementHandlerDispatcher"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * Copyright (c) Microsoft Corporation. * * 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. */ class BrowserContextDispatcher extends _dispatcher.Dispatcher { constructor(parentScope, context) { // We will reparent these to the context below. const requestContext = _networkDispatchers.APIRequestContextDispatcher.from(parentScope, context.fetchRequest); const tracing = _tracingDispatcher.TracingDispatcher.from(parentScope, context.tracing); super(parentScope, context, 'BrowserContext', { isChromium: context._browser.options.isChromium, isLocalBrowserOnServer: context._browser._isCollocatedWithServer, requestContext, tracing }); this._type_EventTarget = true; this._type_BrowserContext = true; this._context = void 0; this._subscriptions = new Set(); this.adopt(requestContext); this.adopt(tracing); this._context = context; // Note: when launching persistent context, dispatcher is created very late, // so we can already have pages, videos and everything else. const onVideo = artifact => { // Note: Video must outlive Page and BrowserContext, so that client can saveAs it // after closing the context. We use |scope| for it. const artifactDispatcher = _artifactDispatcher.ArtifactDispatcher.from(parentScope, artifact); this._dispatchEvent('video', { artifact: artifactDispatcher }); }; this.addObjectListener(_browserContext.BrowserContext.Events.VideoStarted, onVideo); for (const video of context._browser._idToVideo.values()) { if (video.context === context) onVideo(video.artifact); } for (const page of context.pages()) this._dispatchEvent('page', { page: _pageDispatcher.PageDispatcher.from(this, page) }); this.addObjectListener(_browserContext.BrowserContext.Events.Page, page => { this._dispatchEvent('page', { page: _pageDispatcher.PageDispatcher.from(this, page) }); }); this.addObjectListener(_browserContext.BrowserContext.Events.Close, () => { this._dispatchEvent('close'); this._dispose(); }); this.addObjectListener(_browserContext.BrowserContext.Events.PageError, (error, page) => { this._dispatchEvent('pageError', { error: (0, _errors.serializeError)(error), page: _pageDispatcher.PageDispatcher.from(this, page) }); }); this.addObjectListener(_browserContext.BrowserContext.Events.Console, message => { if (this._shouldDispatchEvent(message.page(), 'console')) { const pageDispatcher = _pageDispatcher.PageDispatcher.from(this, message.page()); this._dispatchEvent('console', { page: pageDispatcher, type: message.type(), text: message.text(), args: message.args().map(a => _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(pageDispatcher, a)), location: message.location() }); } }); this.addObjectListener(_browserContext.BrowserContext.Events.Dialog, dialog => { if (this._shouldDispatchEvent(dialog.page(), 'dialog')) this._dispatchEvent('dialog', { dialog: new _dialogDispatcher.DialogDispatcher(this, dialog) });else dialog.close().catch(() => {}); }); if (context._browser.options.name === 'chromium') { for (const page of context.backgroundPages()) this._dispatchEvent('backgroundPage', { page: _pageDispatcher.PageDispatcher.from(this, page) }); this.addObjectListener(_crBrowser.CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('backgroundPage', { page: _pageDispatcher.PageDispatcher.from(this, page) })); for (const serviceWorker of context.serviceWorkers()) this._dispatchEvent('serviceWorker', { worker: new _pageDispatcher.WorkerDispatcher(this, serviceWorker) }); this.addObjectListener(_crBrowser.CRBrowserContext.CREvents.ServiceWorker, serviceWorker => this._dispatchEvent('serviceWorker', { worker: new _pageDispatcher.WorkerDispatcher(this, serviceWorker) })); } this.addObjectListener(_browserContext.BrowserContext.Events.Request, request => { var _request$frame; // Create dispatcher, if: // - There are listeners to the requests. // - We are redirected from a reported request so that redirectedTo was updated on client. // - We are a navigation request and dispatcher will be reported as a part of the goto return value and newDocument param anyways. // By the time requestFinished is triggered to update the request, we should have a request on the client already. const redirectFromDispatcher = request.redirectedFrom() && (0, _dispatcher.existingDispatcher)(request.redirectedFrom()); if (!redirectFromDispatcher && !this._shouldDispatchNetworkEvent(request, 'request') && !request.isNavigationRequest()) return; const requestDispatcher = _networkDispatchers.RequestDispatcher.from(this, request); this._dispatchEvent('request', { request: requestDispatcher, page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame = request.frame()) === null || _request$frame === void 0 ? void 0 : _request$frame._page.initializedOrUndefined()) }); }); this.addObjectListener(_browserContext.BrowserContext.Events.Response, response => { var _response$frame; const requestDispatcher = (0, _dispatcher.existingDispatcher)(response.request()); if (!requestDispatcher && !this._shouldDispatchNetworkEvent(response.request(), 'response')) return; this._dispatchEvent('response', { response: _networkDispatchers.ResponseDispatcher.from(this, response), page: _pageDispatcher.PageDispatcher.fromNullable(this, (_response$frame = response.frame()) === null || _response$frame === void 0 ? void 0 : _response$frame._page.initializedOrUndefined()) }); }); this.addObjectListener(_browserContext.BrowserContext.Events.RequestFailed, request => { var _request$frame2; const requestDispatcher = (0, _dispatcher.existingDispatcher)(request); if (!requestDispatcher && !this._shouldDispatchNetworkEvent(request, 'requestFailed')) return; this._dispatchEvent('requestFailed', { request: _networkDispatchers.RequestDispatcher.from(this, request), failureText: request._failureText || undefined, responseEndTiming: request._responseEndTiming, page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame2 = request.frame()) === null || _request$frame2 === void 0 ? void 0 : _request$frame2._page.initializedOrUndefined()) }); }); this.addObjectListener(_browserContext.BrowserContext.Events.RequestFinished, ({ request, response }) => { var _request$frame3; const requestDispatcher = (0, _dispatcher.existingDispatcher)(request); if (!requestDispatcher && !this._shouldDispatchNetworkEvent(request, 'requestFinished')) return; this._dispatchEvent('requestFinished', { request: _networkDispatchers.RequestDispatcher.from(this, request), response: _networkDispatchers.ResponseDispatcher.fromNullable(this, response), responseEndTiming: request._responseEndTiming, page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame3 = request.frame()) === null || _request$frame3 === void 0 ? void 0 : _request$frame3._page.initializedOrUndefined()) }); }); } _shouldDispatchNetworkEvent(request, event) { var _request$frame4, _request$frame4$_page; return this._shouldDispatchEvent((_request$frame4 = request.frame()) === null || _request$frame4 === void 0 ? void 0 : (_request$frame4$_page = _request$frame4._page) === null || _request$frame4$_page === void 0 ? void 0 : _request$frame4$_page.initializedOrUndefined(), event); } _shouldDispatchEvent(page, event) { if (this._subscriptions.has(event)) return true; const pageDispatcher = page ? (0, _dispatcher.existingDispatcher)(page) : undefined; if (pageDispatcher !== null && pageDispatcher !== void 0 && pageDispatcher._subscriptions.has(event)) return true; return false; } async createTempFile(params) { const dir = this._context._browser.options.artifactsDir; const tmpDir = path.join(dir, 'upload-' + (0, _utils.createGuid)()); await fs.promises.mkdir(tmpDir); this._context._tempDirs.push(tmpDir); const file = fs.createWriteStream(path.join(tmpDir, params.name)); return { writableStream: new _writableStreamDispatcher.WritableStreamDispatcher(this, file, params.lastModifiedMs) }; } async setDefaultNavigationTimeoutNoReply(params) { this._context.setDefaultNavigationTimeout(params.timeout); } async setDefaultTimeoutNoReply(params) { this._context.setDefaultTimeout(params.timeout); } async exposeBinding(params) { await this._context.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => { // When reusing the context, we might have some bindings called late enough, // after context and page dispatchers have been disposed. if (this._disposed) return; const pageDispatcher = _pageDispatcher.PageDispatcher.from(this, source.page); const binding = new _pageDispatcher.BindingCallDispatcher(pageDispatcher, params.name, !!params.needsHandle, source, args); this._dispatchEvent('bindingCall', { binding }); return binding.promise(); }); } async newPage(params, metadata) { return { page: _pageDispatcher.PageDispatcher.from(this, await this._context.newPage(metadata)) }; } async cookies(params) { return { cookies: await this._context.cookies(params.urls) }; } async addCookies(params) { await this._context.addCookies(params.cookies); } async clearCookies() { await this._context.clearCookies(); } async grantPermissions(params) { await this._context.grantPermissions(params.permissions, params.origin); } async clearPermissions() { await this._context.clearPermissions(); } async setGeolocation(params) { await this._context.setGeolocation(params.geolocation); } async setExtraHTTPHeaders(params) { await this._context.setExtraHTTPHeaders(params.headers); } async setOffline(params) { await this._context.setOffline(params.offline); } async setHTTPCredentials(params) { await this._context.setHTTPCredentials(params.httpCredentials); } async addInitScript(params) { await this._context.addInitScript(params.source); } async setNetworkInterceptionPatterns(params) { if (!params.patterns.length) { await this._context.setRequestInterceptor(undefined); return; } const urlMatchers = params.patterns.map(pattern => pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob); await this._context.setRequestInterceptor((route, request) => { const matchesSome = urlMatchers.some(urlMatch => (0, _utils.urlMatches)(this._context._options.baseURL, request.url(), urlMatch)); if (!matchesSome) return false; this._dispatchEvent('route', { route: _networkDispatchers.RouteDispatcher.from(_networkDispatchers.RequestDispatcher.from(this, request), route) }); return true; }); } async storageState(params, metadata) { return await this._context.storageState(); } async close(params, metadata) { metadata.potentiallyClosesScope = true; await this._context.close(params); } async recorderSupplementEnable(params) { await _recorder.Recorder.show(this._context, params); } async pause(params, metadata) { // Debugger will take care of this. } async newCDPSession(params) { if (!this._object._browser.options.isChromium) throw new Error(`CDP session is only available in Chromium`); if (!params.page && !params.frame || params.page && params.frame) throw new Error(`CDP session must be initiated with either Page or Frame, not none or both`); const crBrowserContext = this._object; return { session: new _cdpSessionDispatcher.CDPSessionDispatcher(this, await crBrowserContext.newCDPSession((params.page ? params.page : params.frame)._object)) }; } async harStart(params) { const harId = await this._context._harStart(params.page ? params.page._object : null, params.options); return { harId }; } async harExport(params) { const artifact = await this._context._harExport(params.harId); if (!artifact) throw new Error('No HAR artifact. Ensure record.harPath is set.'); return { artifact: _artifactDispatcher.ArtifactDispatcher.from(this, artifact) }; } async updateSubscription(params) { if (params.enabled) this._subscriptions.add(params.event);else this._subscriptions.delete(params.event); } _onDispose() { // Avoid protocol calls for the closed context. if (!this._context.isClosingOrClosed()) this._context.setRequestInterceptor(undefined).catch(() => {}); } } exports.BrowserContextDispatcher = BrowserContextDispatcher;