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,225 @@
/**
* @license
* Copyright 2018 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ElementHandle } from '../api/ElementHandle.js';
import type { Realm } from '../api/Realm.js';
/**
* Represents a Node and the properties of it that are relevant to Accessibility.
* @public
*/
export interface SerializedAXNode {
/**
* The {@link https://www.w3.org/TR/wai-aria/#usage_intro | role} of the node.
*/
role: string;
/**
* A human readable name for the node.
*/
name?: string;
/**
* The current value of the node.
*/
value?: string | number;
/**
* An additional human readable description of the node.
*/
description?: string;
/**
* Any keyboard shortcuts associated with this node.
*/
keyshortcuts?: string;
/**
* A human readable alternative to the role.
*/
roledescription?: string;
/**
* A description of the current value.
*/
valuetext?: string;
disabled?: boolean;
expanded?: boolean;
focused?: boolean;
modal?: boolean;
multiline?: boolean;
/**
* Whether more than one child can be selected.
*/
multiselectable?: boolean;
readonly?: boolean;
required?: boolean;
selected?: boolean;
/**
* Whether the checkbox is checked, or in a
* {@link https://www.w3.org/TR/wai-aria-practices/examples/checkbox/checkbox-2/checkbox-2.html | mixed state}.
*/
checked?: boolean | 'mixed';
/**
* Whether the node is checked or in a mixed state.
*/
pressed?: boolean | 'mixed';
/**
* The level of a heading.
*/
level?: number;
valuemin?: number;
valuemax?: number;
autocomplete?: string;
haspopup?: string;
/**
* Whether and in what way this node's value is invalid.
*/
invalid?: string;
orientation?: string;
/**
* Whether the node is {@link https://www.w3.org/TR/wai-aria/#aria-busy | busy}.
*/
busy?: boolean;
/**
* The {@link https://www.w3.org/TR/wai-aria/#aria-live | live} status of the
* node.
*/
live?: string;
/**
* Whether the live region is
* {@link https://www.w3.org/TR/wai-aria/#aria-atomic | atomic}.
*/
atomic?: boolean;
/**
* The {@link https://www.w3.org/TR/wai-aria/#aria-relevant | relevant}
* changes for the live region.
*/
relevant?: string;
/**
* The {@link https://www.w3.org/TR/wai-aria/#aria-errormessage | error message}
* for the node.
*/
errormessage?: string;
/**
* The {@link https://www.w3.org/TR/wai-aria/#aria-details | details} for the
* node.
*/
details?: string;
/**
* Url for link elements.
*/
url?: string;
/**
* Children of this node, if there are any.
*/
children?: SerializedAXNode[];
/**
* CDP-specific ID to reference the DOM node.
*
* @internal
*/
backendNodeId?: number;
/**
* CDP-specific documentId.
*
* @internal
*/
loaderId: string;
/**
* Get an ElementHandle for this AXNode if available.
*
* If the underlying DOM element has been disposed, the method might return an
* error.
*/
elementHandle(): Promise<ElementHandle | null>;
}
/**
* @public
*/
export interface SnapshotOptions {
/**
* Prune uninteresting nodes from the tree.
* @defaultValue `true`
*/
interestingOnly?: boolean;
/**
* If true, gets accessibility trees for each of the iframes in the frame
* subtree.
*
* @defaultValue `false`
*/
includeIframes?: boolean;
/**
* Root node to get the accessibility tree for
* @defaultValue The root node of the entire page.
*/
root?: ElementHandle<Node>;
}
/**
* The Accessibility class provides methods for inspecting the browser's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
export declare class Accessibility {
#private;
/**
* @internal
*/
constructor(realm: Realm, frameId?: string);
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chrome accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
*
* ```ts
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
*
* ```ts
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused) return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*/
snapshot(options?: SnapshotOptions): Promise<SerializedAXNode | null>;
private serializeTree;
private collectInterestingNodes;
}
//# sourceMappingURL=Accessibility.d.ts.map

View File

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

View File

@@ -0,0 +1,591 @@
/**
* @license
* Copyright 2018 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (r = env.stack.pop()) {
try {
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { debugError } from '../common/util.js';
/**
* The Accessibility class provides methods for inspecting the browser's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
export class Accessibility {
#realm;
#frameId;
/**
* @internal
*/
constructor(realm, frameId = '') {
this.#realm = realm;
this.#frameId = frameId;
}
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chrome accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
*
* ```ts
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
*
* ```ts
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused) return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*/
async snapshot(options = {}) {
const { interestingOnly = true, root = null, includeIframes = false, } = options;
const { nodes } = await this.#realm.environment.client.send('Accessibility.getFullAXTree', {
frameId: this.#frameId,
});
let backendNodeId;
if (root) {
const { node } = await this.#realm.environment.client.send('DOM.describeNode', {
objectId: root.id,
});
backendNodeId = node.backendNodeId;
}
const defaultRoot = AXNode.createTree(this.#realm, nodes);
const populateIframes = async (root) => {
if (root.payload.role?.value === 'Iframe') {
const env_1 = { stack: [], error: void 0, hasError: false };
try {
if (!root.payload.backendDOMNodeId) {
return;
}
const handle = __addDisposableResource(env_1, (await this.#realm.adoptBackendNode(root.payload.backendDOMNodeId)), false);
if (!handle || !('contentFrame' in handle)) {
return;
}
const frame = await handle.contentFrame();
if (!frame) {
return;
}
try {
const iframeSnapshot = await frame.accessibility.snapshot(options);
root.iframeSnapshot = iframeSnapshot ?? undefined;
}
catch (error) {
// Frames can get detached at any time resulting in errors.
debugError(error);
}
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
}
for (const child of root.children) {
await populateIframes(child);
}
};
let needle = defaultRoot;
if (!defaultRoot) {
return null;
}
if (includeIframes) {
await populateIframes(defaultRoot);
}
if (backendNodeId) {
needle = defaultRoot.find(node => {
return node.payload.backendDOMNodeId === backendNodeId;
});
}
if (!needle) {
return null;
}
if (!interestingOnly) {
return this.serializeTree(needle)[0] ?? null;
}
const interestingNodes = new Set();
this.collectInterestingNodes(interestingNodes, defaultRoot, false);
return this.serializeTree(needle, interestingNodes)[0] ?? null;
}
serializeTree(node, interestingNodes) {
const children = [];
for (const child of node.children) {
children.push(...this.serializeTree(child, interestingNodes));
}
if (interestingNodes && !interestingNodes.has(node)) {
return children;
}
const serializedNode = node.serialize();
if (children.length) {
serializedNode.children = children;
}
if (node.iframeSnapshot) {
if (!serializedNode.children) {
serializedNode.children = [];
}
serializedNode.children.push(node.iframeSnapshot);
}
return [serializedNode];
}
collectInterestingNodes(collection, node, insideControl) {
if (node.isInteresting(insideControl) || node.iframeSnapshot) {
collection.add(node);
}
if (node.isLeafNode()) {
return;
}
insideControl = insideControl || node.isControl();
for (const child of node.children) {
this.collectInterestingNodes(collection, child, insideControl);
}
}
}
class AXNode {
payload;
children = [];
iframeSnapshot;
#richlyEditable = false;
#editable = false;
#focusable = false;
#hidden = false;
#busy = false;
#modal = false;
#hasErrormessage = false;
#hasDetails = false;
#name;
#role;
#description;
#roledescription;
#live;
#ignored;
#cachedHasFocusableChild;
#realm;
constructor(realm, payload) {
this.payload = payload;
this.#role = this.payload.role ? this.payload.role.value : 'Unknown';
this.#ignored = this.payload.ignored;
this.#name = this.payload.name ? this.payload.name.value : '';
this.#description = this.payload.description
? this.payload.description.value
: undefined;
this.#realm = realm;
for (const property of this.payload.properties || []) {
if (property.name === 'editable') {
this.#richlyEditable = property.value.value === 'richtext';
this.#editable = true;
}
if (property.name === 'focusable') {
this.#focusable = property.value.value;
}
if (property.name === 'hidden') {
this.#hidden = property.value.value;
}
if (property.name === 'busy') {
this.#busy = property.value.value;
}
if (property.name === 'live') {
this.#live = property.value.value;
}
if (property.name === 'modal') {
this.#modal = property.value.value;
}
if (property.name === 'roledescription') {
this.#roledescription = property.value.value;
}
if (property.name === 'errormessage') {
this.#hasErrormessage = true;
}
if (property.name === 'details') {
this.#hasDetails = true;
}
}
}
#isPlainTextField() {
if (this.#richlyEditable) {
return false;
}
if (this.#editable) {
return true;
}
return this.#role === 'textbox' || this.#role === 'searchbox';
}
#isTextOnlyObject() {
const role = this.#role;
return (role === 'LineBreak' ||
role === 'text' ||
role === 'InlineTextBox' ||
role === 'StaticText');
}
#hasFocusableChild() {
if (this.#cachedHasFocusableChild === undefined) {
this.#cachedHasFocusableChild = false;
for (const child of this.children) {
if (child.#focusable || child.#hasFocusableChild()) {
this.#cachedHasFocusableChild = true;
break;
}
}
}
return this.#cachedHasFocusableChild;
}
find(predicate) {
if (predicate(this)) {
return this;
}
for (const child of this.children) {
const result = child.find(predicate);
if (result) {
return result;
}
}
return null;
}
isLeafNode() {
if (!this.children.length) {
return true;
}
// These types of objects may have children that we use as internal
// implementation details, but we want to expose them as leaves to platform
// accessibility APIs because screen readers might be confused if they find
// any children.
if (this.#isPlainTextField() || this.#isTextOnlyObject()) {
return true;
}
// Roles whose children are only presentational according to the ARIA and
// HTML5 Specs should be hidden from screen readers.
// (Note that whilst ARIA buttons can have only presentational children, HTML5
// buttons are allowed to have content.)
switch (this.#role) {
case 'doc-cover':
case 'graphics-symbol':
case 'img':
case 'image':
case 'Meter':
case 'scrollbar':
case 'slider':
case 'separator':
case 'progressbar':
return true;
default:
break;
}
if (this.#hasFocusableChild()) {
return false;
}
if (this.#role === 'heading' && this.#name) {
return true;
}
return false;
}
isControl() {
switch (this.#role) {
case 'button':
case 'checkbox':
case 'ColorWell':
case 'combobox':
case 'DisclosureTriangle':
case 'listbox':
case 'menu':
case 'menubar':
case 'menuitem':
case 'menuitemcheckbox':
case 'menuitemradio':
case 'radio':
case 'scrollbar':
case 'searchbox':
case 'slider':
case 'spinbutton':
case 'switch':
case 'tab':
case 'textbox':
case 'tree':
case 'treeitem':
return true;
default:
return false;
}
}
isLandmark() {
switch (this.#role) {
case 'banner':
case 'complementary':
case 'contentinfo':
case 'form':
case 'main':
case 'navigation':
case 'region':
case 'search':
return true;
default:
return false;
}
}
isInteresting(insideControl) {
const role = this.#role;
if (role === 'Ignored' || this.#hidden || this.#ignored) {
return false;
}
if (this.isLandmark()) {
return true;
}
if (this.#focusable ||
this.#richlyEditable ||
this.#busy ||
(this.#live && this.#live !== 'off') ||
this.#modal ||
this.#hasErrormessage ||
this.#hasDetails ||
this.#roledescription) {
return true;
}
// If it's not focusable but has a control role, then it's interesting.
if (this.isControl()) {
return true;
}
// A non focusable child of a control is not interesting
if (insideControl) {
return false;
}
return this.isLeafNode() && (!!this.#name || !!this.#description);
}
serialize() {
const properties = new Map();
for (const property of this.payload.properties || []) {
properties.set(property.name.toLowerCase(), property.value.value);
}
if (this.payload.name) {
properties.set('name', this.payload.name.value);
}
if (this.payload.value) {
properties.set('value', this.payload.value.value);
}
if (this.payload.description) {
properties.set('description', this.payload.description.value);
}
const node = {
role: this.#role,
elementHandle: async () => {
const env_2 = { stack: [], error: void 0, hasError: false };
try {
if (!this.payload.backendDOMNodeId) {
return null;
}
const handle = __addDisposableResource(env_2, await this.#realm.adoptBackendNode(this.payload.backendDOMNodeId), false);
// Since Text nodes are not elements, we want to
// return a handle to the parent element for them.
return (await handle.evaluateHandle(node => {
return node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
}));
}
catch (e_2) {
env_2.error = e_2;
env_2.hasError = true;
}
finally {
__disposeResources(env_2);
}
},
backendNodeId: this.payload.backendDOMNodeId,
// LoaderId is an experimental mechanism to establish unique IDs across
// navigations.
loaderId: this.#realm.environment._loaderId,
};
const userStringProperties = [
'name',
'value',
'description',
'keyshortcuts',
'roledescription',
'valuetext',
'url',
];
const getUserStringPropertyValue = (key) => {
return properties.get(key);
};
for (const userStringProperty of userStringProperties) {
if (!properties.has(userStringProperty)) {
continue;
}
node[userStringProperty] = getUserStringPropertyValue(userStringProperty);
}
const booleanProperties = [
'disabled',
'expanded',
'focused',
'modal',
'multiline',
'multiselectable',
'readonly',
'required',
'selected',
'busy',
'atomic',
];
const getBooleanPropertyValue = (key) => {
return !!properties.get(key);
};
for (const booleanProperty of booleanProperties) {
// RootWebArea's treat focus differently than other nodes. They report whether
// their frame has focus, not whether focus is specifically on the root
// node.
if (booleanProperty === 'focused' && this.#role === 'RootWebArea') {
continue;
}
if (!properties.has(booleanProperty)) {
continue;
}
node[booleanProperty] = getBooleanPropertyValue(booleanProperty);
}
const tristateProperties = ['checked', 'pressed'];
for (const tristateProperty of tristateProperties) {
if (!properties.has(tristateProperty)) {
continue;
}
const value = properties.get(tristateProperty);
node[tristateProperty] =
value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
}
const numericalProperties = [
'level',
'valuemax',
'valuemin',
];
const getNumericalPropertyValue = (key) => {
return properties.get(key);
};
for (const numericalProperty of numericalProperties) {
if (!properties.has(numericalProperty)) {
continue;
}
node[numericalProperty] = getNumericalPropertyValue(numericalProperty);
}
const tokenProperties = [
'autocomplete',
'haspopup',
'invalid',
'orientation',
'live',
'relevant',
'errormessage',
'details',
];
const getTokenPropertyValue = (key) => {
return properties.get(key);
};
for (const tokenProperty of tokenProperties) {
const value = getTokenPropertyValue(tokenProperty);
if (!value || value === 'false') {
continue;
}
node[tokenProperty] = getTokenPropertyValue(tokenProperty);
}
return node;
}
static createTree(realm, payloads) {
const nodeById = new Map();
for (const payload of payloads) {
nodeById.set(payload.nodeId, new AXNode(realm, payload));
}
for (const node of nodeById.values()) {
for (const childId of node.payload.childIds || []) {
const child = nodeById.get(childId);
if (child) {
node.children.push(child);
}
}
}
return nodeById.values().next().value ?? null;
}
}
//# sourceMappingURL=Accessibility.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
import type { ExecutionContext } from './ExecutionContext.js';
/**
* @internal
*/
export declare class Binding {
#private;
constructor(name: string, fn: (...args: unknown[]) => unknown, initSource: string);
get name(): string;
get initSource(): string;
/**
* @param context - Context to run the binding in; the context should have
* the binding added to it beforehand.
* @param id - ID of the call. This should come from the CDP
* `onBindingCalled` response.
* @param args - Plain arguments from CDP.
*/
run(context: ExecutionContext, id: number, args: unknown[], isTrivial: boolean): Promise<void>;
}
//# sourceMappingURL=Binding.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Binding.d.ts","sourceRoot":"","sources":["../../../src/cdp/Binding.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAE5D;;GAEG;AACH,qBAAa,OAAO;;gBAKhB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACnC,UAAU,EAAE,MAAM;IAOpB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;;OAMG;IACG,GAAG,CACP,OAAO,EAAE,gBAAgB,EACzB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,EAAE,EACf,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,IAAI,CAAC;CAmFjB"}

View File

@@ -0,0 +1,162 @@
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (r = env.stack.pop()) {
try {
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { JSHandle } from '../api/JSHandle.js';
import { debugError } from '../common/util.js';
import { DisposableStack } from '../util/disposable.js';
import { isErrorLike } from '../util/ErrorLike.js';
/**
* @internal
*/
export class Binding {
#name;
#fn;
#initSource;
constructor(name, fn, initSource) {
this.#name = name;
this.#fn = fn;
this.#initSource = initSource;
}
get name() {
return this.#name;
}
get initSource() {
return this.#initSource;
}
/**
* @param context - Context to run the binding in; the context should have
* the binding added to it beforehand.
* @param id - ID of the call. This should come from the CDP
* `onBindingCalled` response.
* @param args - Plain arguments from CDP.
*/
async run(context, id, args, isTrivial) {
const stack = new DisposableStack();
try {
if (!isTrivial) {
const env_1 = { stack: [], error: void 0, hasError: false };
try {
// Getting non-trivial arguments.
const handles = __addDisposableResource(env_1, await context.evaluateHandle((name, seq) => {
// @ts-expect-error Code is evaluated in a different context.
return globalThis[name].args.get(seq);
}, this.#name, id), false);
const properties = await handles.getProperties();
for (const [index, handle] of properties) {
// This is not straight-forward since some arguments can stringify, but
// aren't plain objects so add subtypes when the use-case arises.
if (index in args) {
switch (handle.remoteObject().subtype) {
case 'node':
args[+index] = handle;
break;
default:
stack.use(handle);
}
}
else {
stack.use(handle);
}
}
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
}
await context.evaluate((name, seq, result) => {
// @ts-expect-error Code is evaluated in a different context.
const callbacks = globalThis[name].callbacks;
callbacks.get(seq).resolve(result);
callbacks.delete(seq);
}, this.#name, id, await this.#fn(...args));
for (const arg of args) {
if (arg instanceof JSHandle) {
stack.use(arg);
}
}
}
catch (error) {
if (isErrorLike(error)) {
await context
.evaluate((name, seq, message, stack) => {
const error = new Error(message);
error.stack = stack;
// @ts-expect-error Code is evaluated in a different context.
const callbacks = globalThis[name].callbacks;
callbacks.get(seq).reject(error);
callbacks.delete(seq);
}, this.#name, id, error.message, error.stack)
.catch(debugError);
}
else {
await context
.evaluate((name, seq, error) => {
// @ts-expect-error Code is evaluated in a different context.
const callbacks = globalThis[name].callbacks;
callbacks.get(seq).reject(error);
callbacks.delete(seq);
}, this.#name, id, error)
.catch(debugError);
}
}
}
}
//# sourceMappingURL=Binding.js.map

View File

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

View File

@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2025 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { AdapterState, BluetoothEmulation, PreconnectedPeripheral } from '../api/BluetoothEmulation.js';
import type { Connection } from './Connection.js';
/**
* @internal
*/
export declare class CdpBluetoothEmulation implements BluetoothEmulation {
#private;
constructor(connection: Connection);
emulateAdapter(state: AdapterState, leSupported?: boolean): Promise<void>;
disableEmulation(): Promise<void>;
simulatePreconnectedPeripheral(preconnectedPeripheral: PreconnectedPeripheral): Promise<void>;
}
//# sourceMappingURL=BluetoothEmulation.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BluetoothEmulation.d.ts","sourceRoot":"","sources":["../../../src/cdp/BluetoothEmulation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAEhD;;GAEG;AACH,qBAAa,qBAAsB,YAAW,kBAAkB;;gBAGlD,UAAU,EAAE,UAAU;IAI5B,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,WAAW,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtE,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,8BAA8B,CAClC,sBAAsB,EAAE,sBAAsB,GAC7C,OAAO,CAAC,IAAI,CAAC;CAMjB"}

View File

@@ -0,0 +1,26 @@
/**
* @internal
*/
export class CdpBluetoothEmulation {
#connection;
constructor(connection) {
this.#connection = connection;
}
async emulateAdapter(state, leSupported = true) {
// Bluetooth spec requires overriding the existing adapter (step 6). From the CDP
// perspective, it means disabling the emulation first.
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth-simulateAdapter-command
await this.#connection.send('BluetoothEmulation.disable');
await this.#connection.send('BluetoothEmulation.enable', {
state,
leSupported,
});
}
async disableEmulation() {
await this.#connection.send('BluetoothEmulation.disable');
}
async simulatePreconnectedPeripheral(preconnectedPeripheral) {
await this.#connection.send('BluetoothEmulation.simulatePreconnectedPeripheral', preconnectedPeripheral);
}
}
//# sourceMappingURL=BluetoothEmulation.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BluetoothEmulation.js","sourceRoot":"","sources":["../../../src/cdp/BluetoothEmulation.ts"],"names":[],"mappings":"AAaA;;GAEG;AACH,MAAM,OAAO,qBAAqB;IAChC,WAAW,CAAa;IAExB,YAAY,UAAsB;QAChC,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,KAAmB,EAAE,WAAW,GAAG,IAAI;QAC1D,iFAAiF;QACjF,uDAAuD;QACvD,oFAAoF;QACpF,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1D,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,2BAA2B,EAAE;YACvD,KAAK;YACL,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,8BAA8B,CAClC,sBAA8C;QAE9C,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CACzB,mDAAmD,EACnD,sBAAsB,CACvB,CAAC;IACJ,CAAC;CACF"}

View File

@@ -0,0 +1,63 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ChildProcess } from 'node:child_process';
import type { CreatePageOptions, DebugInfo } from '../api/Browser.js';
import { Browser as BrowserBase, type BrowserCloseCallback, type BrowserContextOptions, type IsPageTargetCallback, type TargetFilterCallback, type ScreenInfo, type AddScreenParams, type WindowBounds, type WindowId } from '../api/Browser.js';
import type { Extension } from '../api/Extension.js';
import type { Page } from '../api/Page.js';
import type { DownloadBehavior } from '../common/DownloadBehavior.js';
import type { Viewport } from '../common/Viewport.js';
import { CdpBrowserContext } from './BrowserContext.js';
import type { Connection } from './Connection.js';
import { type CdpTarget } from './Target.js';
import { TargetManager } from './TargetManager.js';
/**
* @internal
*/
export declare class CdpBrowser extends BrowserBase {
#private;
readonly protocol = "cdp";
static _create(connection: Connection, contextIds: string[], acceptInsecureCerts: boolean, defaultViewport?: Viewport | null, downloadBehavior?: DownloadBehavior, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback, isPageTargetCallback?: IsPageTargetCallback, waitForInitiallyDiscoveredTargets?: boolean, networkEnabled?: boolean, issuesEnabled?: boolean, handleDevToolsAsPage?: boolean, blocklist?: string[], allowlist?: string[]): Promise<CdpBrowser>;
constructor(connection: Connection, contextIds: string[], defaultViewport?: Viewport | null, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback, isPageTargetCallback?: IsPageTargetCallback, waitForInitiallyDiscoveredTargets?: boolean, networkEnabled?: boolean, issuesEnabled?: boolean, handleDevToolsAsPage?: boolean, blocklist?: string[], allowlist?: string[]);
_attach(downloadBehavior: DownloadBehavior | undefined): Promise<void>;
_detach(): void;
process(): ChildProcess | null;
_targetManager(): TargetManager;
_getIsPageTargetCallback(): IsPageTargetCallback | undefined;
createBrowserContext(options?: BrowserContextOptions): Promise<CdpBrowserContext>;
browserContexts(): CdpBrowserContext[];
defaultBrowserContext(): CdpBrowserContext;
_disposeContext(contextId?: string): Promise<void>;
wsEndpoint(): string;
newPage(options?: CreatePageOptions): Promise<Page>;
_createPageInContext(contextId?: string, options?: CreatePageOptions): Promise<Page>;
_createDevToolsPage(pageTargetId: string): Promise<Page>;
_getDevToolsTargetPage(devtoolsTargetId: string): Promise<Page>;
_hasDevToolsTarget(pageTargetId: string): Promise<string | undefined>;
installExtension(path: string): Promise<string>;
uninstallExtension(id: string): Promise<void>;
screens(): Promise<ScreenInfo[]>;
addScreen(params: AddScreenParams): Promise<ScreenInfo>;
removeScreen(screenId: string): Promise<void>;
getWindowBounds(windowId: WindowId): Promise<WindowBounds>;
setWindowBounds(windowId: WindowId, windowBounds: WindowBounds): Promise<void>;
targets(): CdpTarget[];
target(): CdpTarget;
version(): Promise<string>;
userAgent(): Promise<string>;
close(): Promise<void>;
disconnect(): Promise<void>;
/**
* @internal
*/
get _connection(): Connection;
get connected(): boolean;
get debugInfo(): DebugInfo;
isNetworkEnabled(): boolean;
extensions(): Promise<Map<string, Extension>>;
isIssuesEnabled(): boolean;
}
//# sourceMappingURL=Browser.d.ts.map

View File

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

View File

@@ -0,0 +1,390 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { Browser as BrowserBase, } from '../api/Browser.js';
import { CDPSessionEvent } from '../api/CDPSession.js';
import { CdpBrowserContext } from './BrowserContext.js';
import { CdpExtension } from './Extension.js';
import { DevToolsTarget, InitializationStatus, OtherTarget, PageTarget, WorkerTarget, } from './Target.js';
import { TargetManager } from './TargetManager.js';
/**
* @internal
*/
function isDevToolsPageTarget(url) {
return url.startsWith('devtools://devtools/bundled/devtools_app.html');
}
/**
* @internal
*/
export class CdpBrowser extends BrowserBase {
protocol = 'cdp';
static async _create(connection, contextIds, acceptInsecureCerts, defaultViewport, downloadBehavior, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets = true, networkEnabled = true, issuesEnabled = true, handleDevToolsAsPage = false, blocklist, allowlist) {
const browser = new CdpBrowser(connection, contextIds, defaultViewport, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets, networkEnabled, issuesEnabled, handleDevToolsAsPage, blocklist, allowlist);
if (allowlist) {
const version = await browser.#getVersion();
const majorVersion = parseInt(version.product.match(/\d+/)?.[0] ?? '0', 10);
if (majorVersion < 149) {
throw new Error('The allowlist option require Chrome 149 or greater.');
}
}
if (acceptInsecureCerts) {
await connection.send('Security.setIgnoreCertificateErrors', {
ignore: true,
});
}
await browser._attach(downloadBehavior);
return browser;
}
#defaultViewport;
#process;
#connection;
#closeCallback;
#targetFilterCallback;
#isPageTargetCallback;
#defaultContext;
#contexts = new Map();
#networkEnabled = true;
#issuesEnabled = true;
#targetManager;
#handleDevToolsAsPage = false;
#extensions = new Map();
constructor(connection, contextIds, defaultViewport, process, closeCallback, targetFilterCallback, isPageTargetCallback, waitForInitiallyDiscoveredTargets = true, networkEnabled = true, issuesEnabled = true, handleDevToolsAsPage = false, blocklist, allowlist) {
super();
this.#networkEnabled = networkEnabled;
this.#issuesEnabled = issuesEnabled;
this.#defaultViewport = defaultViewport;
this.#process = process;
this.#connection = connection;
this.#closeCallback = closeCallback || (() => { });
this.#targetFilterCallback =
targetFilterCallback ||
(() => {
return true;
});
this.#handleDevToolsAsPage = handleDevToolsAsPage;
this.#setIsPageTargetCallback(isPageTargetCallback);
connection.rejectEmulateNetworkConditionsCalls = Boolean((blocklist && blocklist.length > 0) ||
(allowlist && allowlist.length > 0));
this.#targetManager = new TargetManager(connection, this.#createTarget, this.#targetFilterCallback, waitForInitiallyDiscoveredTargets, blocklist, allowlist);
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(downloadBehavior) {
this.#connection.on(CDPSessionEvent.Disconnected, this.#emitDisconnected);
if (downloadBehavior) {
await this.#defaultContext.setDownloadBehavior(downloadBehavior);
}
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(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' ||
(this.#handleDevToolsAsPage &&
target.type() === 'other' &&
isDevToolsPageTarget(target.url())));
});
}
_getIsPageTargetCallback() {
return this.#isPageTargetCallback;
}
async createBrowserContext(options = {}) {
const { proxyServer, proxyBypassList, downloadBehavior } = options;
const { browserContextId } = await this.#connection.send('Target.createBrowserContext', {
proxyServer,
proxyBypassList: proxyBypassList && proxyBypassList.join(','),
});
const context = new CdpBrowserContext(this.#connection, this, browserContextId);
if (downloadBehavior) {
await context.setDownloadBehavior(downloadBehavior);
}
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 OtherTarget(targetInfo, session, context, this.#targetManager, createSession);
if (targetInfo.url && isDevToolsPageTarget(targetInfo.url)) {
return new DevToolsTarget(targetInfo, session, context, this.#targetManager, createSession, this.#defaultViewport ?? null);
}
if (this.#isPageTargetCallback(otherTarget)) {
return new PageTarget(targetInfo, session, context, this.#targetManager, createSession, this.#defaultViewport ?? null);
}
if (targetInfo.type === 'service_worker' ||
targetInfo.type === 'shared_worker') {
return new WorkerTarget(targetInfo, session, context, this.#targetManager, createSession);
}
return otherTarget;
};
#onAttachedToTarget = async (target) => {
if (target._isTargetExposed() &&
(await target._initializedDeferred.valueOrThrow()) ===
InitializationStatus.SUCCESS) {
this.emit("targetcreated" /* BrowserEvent.TargetCreated */, target);
target.browserContext().emit("targetcreated" /* BrowserContextEvent.TargetCreated */, target);
}
};
#onDetachedFromTarget = async (target) => {
target._initializedDeferred.resolve(InitializationStatus.ABORTED);
target._isClosedDeferred.resolve();
if (target._isTargetExposed() &&
(await target._initializedDeferred.valueOrThrow()) ===
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(options) {
return await this.#defaultContext.newPage(options);
}
async _createPageInContext(contextId, options) {
const hasTargets = this.targets().filter(t => {
return t.browserContext().id === contextId;
}).length > 0;
const windowBounds = options?.type === 'window' ? options.windowBounds : undefined;
const { targetId } = await this.#connection.send('Target.createTarget', {
url: 'about:blank',
browserContextId: contextId || undefined,
left: windowBounds?.left,
top: windowBounds?.top,
width: windowBounds?.width,
height: windowBounds?.height,
windowState: windowBounds?.windowState,
// Works around crbug.com/454825274.
newWindow: hasTargets && options?.type === 'window' ? true : undefined,
background: options?.background,
});
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()) ===
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;
}
async _createDevToolsPage(pageTargetId) {
const openDevToolsResponse = await this.#connection.send('Target.openDevTools', {
targetId: pageTargetId,
});
return await this._getDevToolsTargetPage(openDevToolsResponse.targetId);
}
async _getDevToolsTargetPage(devtoolsTargetId) {
const target = (await this.waitForTarget(t => {
return t._targetId === devtoolsTargetId;
}));
if (!target) {
throw new Error(`Missing target for DevTools page (id = ${devtoolsTargetId})`);
}
const initialized = (await target._initializedDeferred.valueOrThrow()) ===
InitializationStatus.SUCCESS;
if (!initialized) {
throw new Error(`Failed to create target for DevTools page (id = ${devtoolsTargetId})`);
}
const page = await target.page();
if (!page) {
throw new Error(`Failed to create a DevTools Page for target (id = ${devtoolsTargetId})`);
}
return page;
}
async _hasDevToolsTarget(pageTargetId) {
const response = await this.#connection.send('Target.getDevToolsTarget', {
targetId: pageTargetId,
});
return response.targetId;
}
async installExtension(path) {
const { id } = await this.#connection.send('Extensions.loadUnpacked', { path });
this.#extensions.delete(id);
return id;
}
async uninstallExtension(id) {
await this.#connection.send('Extensions.uninstall', { id });
// Currently sending the Extensions.uninstall command does not trigger
// the Target.targetDestroyed event for service workers. This causes
// flakiness in the extension tests.
// TODO(nroscino): Remove this once the event is correctly emitted.
const targetDestroyedPromises = [];
for (const [targetId, targetInfo] of this._targetManager()
.getDiscoveredTargetInfos()
.entries()) {
if (targetInfo.url.includes(id) && targetInfo.type === 'service_worker') {
this._targetManager().addToIgnoreTarget(targetId);
targetDestroyedPromises.push(new Promise(resolve => {
return setTimeout(() => {
this.#connection.emit('Target.targetDestroyed', {
targetId: targetId,
});
resolve(null);
}, 0);
}));
}
}
await Promise.all(targetDestroyedPromises);
this.#extensions.delete(id);
}
async screens() {
const { screenInfos } = await this.#connection.send('Emulation.getScreenInfos');
return screenInfos;
}
async addScreen(params) {
const { screenInfo } = await this.#connection.send('Emulation.addScreen', params);
return screenInfo;
}
async removeScreen(screenId) {
return await this.#connection.send('Emulation.removeScreen', { screenId });
}
async getWindowBounds(windowId) {
const { bounds } = await this.#connection.send('Browser.getWindowBounds', {
windowId: Number(windowId),
});
return bounds;
}
async setWindowBounds(windowId, windowBounds) {
await this.#connection.send('Browser.setWindowBounds', {
windowId: Number(windowId),
bounds: windowBounds,
});
}
targets() {
return Array.from(this.#targetManager.getAvailableTargets().values()).filter(target => {
return (target._isTargetExposed() &&
target._initializedDeferred.value() === 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);
await this.disconnect();
}
disconnect() {
this.#targetManager.dispose();
this.#connection.dispose();
this._detach();
return Promise.resolve();
}
/**
* @internal
*/
get _connection() {
return this.#connection;
}
get connected() {
return !this.#connection._closed;
}
#getVersion() {
return this.#connection.send('Browser.getVersion');
}
get debugInfo() {
return {
pendingProtocolErrors: this.#connection.getPendingProtocolErrors(),
};
}
isNetworkEnabled() {
return this.#networkEnabled;
}
async extensions() {
const response = await this.#connection.send('Extensions.getExtensions');
const extensionsMap = new Map();
for (const currExtension of response.extensions) {
if (this.#extensions.has(currExtension.id)) {
extensionsMap.set(currExtension.id, this.#extensions.get(currExtension.id));
}
else {
const newExtension = new CdpExtension(currExtension.id, currExtension.version, currExtension.name, currExtension.path, currExtension.enabled, this);
extensionsMap.set(currExtension.id, newExtension);
}
}
this.#extensions = extensionsMap;
return this.#extensions;
}
isIssuesEnabled() {
return this.#issuesEnabled;
}
}
//# sourceMappingURL=Browser.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
import type { ConnectOptions } from '../common/ConnectOptions.js';
import { CdpBrowser } from './Browser.js';
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'cdp'`.
*
* @internal
*/
export declare function _connectToCdpBrowser(connectionTransport: ConnectionTransport, url: string, options: ConnectOptions): Promise<CdpBrowser>;
//# sourceMappingURL=BrowserConnector.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.d.ts","sourceRoot":"","sources":["../../../src/cdp/BrowserConnector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAIhE,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AAGxC;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,mBAAmB,EAAE,mBAAmB,EACxC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC,CAiDrB"}

View File

@@ -0,0 +1,26 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { debugError, DEFAULT_VIEWPORT } from '../common/util.js';
import { createIncrementalIdGenerator } from '../util/incremental-id-generator.js';
import { CdpBrowser } from './Browser.js';
import { Connection } from './Connection.js';
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect` with `protocol: 'cdp'`.
*
* @internal
*/
export async function _connectToCdpBrowser(connectionTransport, url, options) {
const { acceptInsecureCerts = false, networkEnabled = true, issuesEnabled = true, defaultViewport = DEFAULT_VIEWPORT, downloadBehavior, targetFilter, _isPageTarget: isPageTarget, slowMo = 0, protocolTimeout, handleDevToolsAsPage, idGenerator = createIncrementalIdGenerator(), blocklist, allowlist, } = options;
const connection = new Connection(url, connectionTransport, slowMo, protocolTimeout,
/* rawErrors */ false, idGenerator);
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
const browser = await CdpBrowser._create(connection, browserContextIds, acceptInsecureCerts, defaultViewport, downloadBehavior, undefined, () => {
return connection.send('Browser.close').catch(debugError);
}, targetFilter, isPageTarget, undefined, networkEnabled, issuesEnabled, handleDevToolsAsPage, blocklist, allowlist);
return browser;
}
//# sourceMappingURL=BrowserConnector.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.js","sourceRoot":"","sources":["../../../src/cdp/BrowserConnector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAC,UAAU,EAAE,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAC,4BAA4B,EAAC,MAAM,qCAAqC,CAAC;AAEjF,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AACxC,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,mBAAwC,EACxC,GAAW,EACX,OAAuB;IAEvB,MAAM,EACJ,mBAAmB,GAAG,KAAK,EAC3B,cAAc,GAAG,IAAI,EACrB,aAAa,GAAG,IAAI,EACpB,eAAe,GAAG,gBAAgB,EAClC,gBAAgB,EAChB,YAAY,EACZ,aAAa,EAAE,YAAY,EAC3B,MAAM,GAAG,CAAC,EACV,eAAe,EACf,oBAAoB,EACpB,WAAW,GAAG,4BAA4B,EAAE,EAC5C,SAAS,EACT,SAAS,GACV,GAAG,OAAO,CAAC;IAEZ,MAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,GAAG,EACH,mBAAmB,EACnB,MAAM,EACN,eAAe;IACf,eAAe,CAAC,KAAK,EACrB,WAAW,CACZ,CAAC;IAEF,MAAM,EAAC,iBAAiB,EAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAC/C,2BAA2B,CAC5B,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,OAAO,CACtC,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,GAAG,EAAE;QACH,OAAO,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC,EACD,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,SAAS,CACV,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC"}

View File

@@ -0,0 +1,37 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { CreatePageOptions } from '../api/Browser.js';
import { type Permission, type PermissionDescriptor, type PermissionState } from '../api/Browser.js';
import { BrowserContext } from '../api/BrowserContext.js';
import type { Page } from '../api/Page.js';
import type { Cookie, CookieData } from '../common/Cookie.js';
import type { DownloadBehavior } from '../common/DownloadBehavior.js';
import type { CdpBrowser } from './Browser.js';
import type { Connection } from './Connection.js';
import type { CdpTarget } from './Target.js';
/**
* @internal
*/
export declare class CdpBrowserContext extends BrowserContext {
#private;
constructor(connection: Connection, browser: CdpBrowser, contextId?: string);
get id(): string | undefined;
targets(): CdpTarget[];
pages(includeAll?: boolean): Promise<Page[]>;
overridePermissions(origin: string, permissions: Permission[]): Promise<void>;
setPermission(origin: string | '*', ...permissions: Array<{
permission: PermissionDescriptor;
state: PermissionState;
}>): Promise<void>;
clearPermissionOverrides(): Promise<void>;
newPage(options?: CreatePageOptions): Promise<Page>;
browser(): CdpBrowser;
close(): Promise<void>;
cookies(): Promise<Cookie[]>;
setCookie(...cookies: CookieData[]): Promise<void>;
setDownloadBehavior(downloadBehavior: DownloadBehavior): Promise<void>;
}
//# sourceMappingURL=BrowserContext.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserContext.d.ts","sourceRoot":"","sources":["../../../src/cdp/BrowserContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAC,MAAM,EAAE,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAGpE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAKhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;;gBAKvC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM;IAO3E,IAAa,EAAE,IAAI,MAAM,GAAG,SAAS,CAEpC;IAEQ,OAAO,IAAI,SAAS,EAAE;IAMhB,KAAK,CAAC,UAAU,UAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAmB1C,mBAAmB,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC;IAgBD,aAAa,CAC1B,MAAM,EAAE,MAAM,GAAG,GAAG,EACpB,GAAG,WAAW,EAAE,KAAK,CAAC;QACpB,UAAU,EAAE,oBAAoB,CAAC;QACjC,KAAK,EAAE,eAAe,CAAC;KACxB,CAAC,GACD,OAAO,CAAC,IAAI,CAAC;IAqBD,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAMzC,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzD,OAAO,IAAI,UAAU;IAIf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAiB5B,SAAS,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAepD,mBAAmB,CAC9B,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,IAAI,CAAC;CAOjB"}

View File

@@ -0,0 +1,190 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (r = env.stack.pop()) {
try {
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { WEB_PERMISSION_TO_PROTOCOL_PERMISSION, } from '../api/Browser.js';
import { BrowserContext } from '../api/BrowserContext.js';
import { assert } from '../util/assert.js';
import { convertCookiesPartitionKeyFromPuppeteerToCdp, convertSameSiteFromPuppeteerToCdp, } from './Page.js';
/**
* @internal
*/
export class CdpBrowserContext extends 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;
});
}
async pages(includeAll = false) {
const pages = await Promise.all(this.targets()
.filter(target => {
return (target.type() === 'page' ||
((target.type() === 'other' || includeAll) &&
this.#browser._getIsPageTargetCallback()?.(target)));
})
.map(target => {
return target.page();
}));
return pages.filter(page => {
return !!page;
});
}
async overridePermissions(origin, permissions) {
const protocolPermissions = permissions.map(permission => {
const protocolPermission = 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 setPermission(origin, ...permissions) {
await Promise.all(permissions.map(async (permission) => {
const protocolPermission = {
name: permission.permission.name,
userVisibleOnly: permission.permission.userVisibleOnly,
sysex: permission.permission.sysex,
allowWithoutSanitization: permission.permission.allowWithoutSanitization,
panTiltZoom: permission.permission.panTiltZoom,
};
await this.#connection.send('Browser.setPermission', {
origin: origin === '*' ? undefined : origin,
browserContextId: this.#id || undefined,
permission: protocolPermission,
setting: permission.state,
});
}));
}
async clearPermissionOverrides() {
await this.#connection.send('Browser.resetPermissions', {
browserContextId: this.#id || undefined,
});
}
async newPage(options) {
const env_1 = { stack: [], error: void 0, hasError: false };
try {
const _guard = __addDisposableResource(env_1, await this.waitForScreenshotOperations(), false);
return await this.#browser._createPageInContext(this.#id, options);
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
}
browser() {
return this.#browser;
}
async close() {
assert(this.#id, 'Default BrowserContext cannot be closed!');
await this.#browser._disposeContext(this.#id);
}
async cookies() {
const { cookies } = await this.#connection.send('Storage.getCookies', {
browserContextId: this.#id,
});
return cookies.map(cookie => {
return {
...cookie,
partitionKey: cookie.partitionKey
? {
sourceOrigin: cookie.partitionKey.topLevelSite,
hasCrossSiteAncestor: cookie.partitionKey.hasCrossSiteAncestor,
}
: undefined,
};
});
}
async setCookie(...cookies) {
return await this.#connection.send('Storage.setCookies', {
browserContextId: this.#id,
cookies: cookies.map(cookie => {
return {
...cookie,
partitionKey: convertCookiesPartitionKeyFromPuppeteerToCdp(cookie.partitionKey),
sameSite: convertSameSiteFromPuppeteerToCdp(cookie.sameSite),
};
}),
});
}
async setDownloadBehavior(downloadBehavior) {
await this.#connection.send('Browser.setDownloadBehavior', {
behavior: downloadBehavior.policy,
downloadPath: downloadBehavior.downloadPath,
browserContextId: this.#id,
});
}
}
//# sourceMappingURL=BrowserContext.js.map

View File

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

View File

@@ -0,0 +1,17 @@
/**
* @license
* Copyright 2026 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { Issue } from '../api/Issue.js';
/**
* @internal
*/
export declare class CdpIssue implements Issue {
#private;
constructor(issue: Protocol.Audits.InspectorIssue);
get code(): Protocol.Audits.InspectorIssueCode;
get details(): Protocol.Audits.InspectorIssueDetails;
}
//# sourceMappingURL=CdpIssue.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CdpIssue.d.ts","sourceRoot":"","sources":["../../../src/cdp/CdpIssue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAE3C;;GAEG;AACH,qBAAa,QAAS,YAAW,KAAK;;gBAIxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc;IAKjD,IAAI,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAE7C;IAED,IAAI,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAEnD;CACF"}

View File

@@ -0,0 +1,23 @@
/**
* @license
* Copyright 2026 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @internal
*/
export class CdpIssue {
#code;
#details;
constructor(issue) {
this.#code = issue.code;
this.#details = issue.details;
}
get code() {
return this.#code;
}
get details() {
return this.#details;
}
}
//# sourceMappingURL=CdpIssue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CdpIssue.js","sourceRoot":"","sources":["../../../src/cdp/CdpIssue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;GAEG;AACH,MAAM,OAAO,QAAQ;IACnB,KAAK,CAAqC;IAC1C,QAAQ,CAAwC;IAEhD,YAAY,KAAqC;QAC/C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}

View File

@@ -0,0 +1,18 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { CdpFrame } from './Frame.js';
/**
* @internal
*/
export declare class CdpPreloadScript {
#private;
constructor(mainFrame: CdpFrame, id: string, source: string);
get id(): string;
get source(): string;
getIdForFrame(frame: CdpFrame): string | undefined;
setIdForFrame(frame: CdpFrame, identifier: string): void;
}
//# sourceMappingURL=CdpPreloadScript.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CdpPreloadScript.d.ts","sourceRoot":"","sources":["../../../src/cdp/CdpPreloadScript.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AAEzC;;GAEG;AACH,qBAAa,gBAAgB;;gBAaf,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAM3D,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS;IAIlD,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAGzD"}

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @internal
*/
export class CdpPreloadScript {
/**
* This is the ID of the preload script returned by
* Page.addScriptToEvaluateOnNewDocument in the main frame.
*
* Sub-frames would get a different CDP ID because
* addScriptToEvaluateOnNewDocument is called for each subframe. But
* users only see this ID and subframe IDs are internal to Puppeteer.
*/
#id;
#source;
#frameToId = new WeakMap();
constructor(mainFrame, id, source) {
this.#id = id;
this.#source = source;
this.#frameToId.set(mainFrame, id);
}
get id() {
return this.#id;
}
get source() {
return this.#source;
}
getIdForFrame(frame) {
return this.#frameToId.get(frame);
}
setIdForFrame(frame, identifier) {
this.#frameToId.set(frame, identifier);
}
}
//# sourceMappingURL=CdpPreloadScript.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CdpPreloadScript.js","sourceRoot":"","sources":["../../../src/cdp/CdpPreloadScript.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAC3B;;;;;;;OAOG;IACH,GAAG,CAAS;IACZ,OAAO,CAAS;IAChB,UAAU,GAAG,IAAI,OAAO,EAAoB,CAAC;IAE7C,YAAY,SAAmB,EAAE,EAAU,EAAE,MAAc;QACzD,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,aAAa,CAAC,KAAe;QAC3B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,aAAa,CAAC,KAAe,EAAE,UAAkB;QAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;CACF"}

View File

@@ -0,0 +1,71 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { type CDPEvents, CDPSession, type CommandOptions } from '../api/CDPSession.js';
import type { Connection } from './Connection.js';
import type { CdpTarget } from './Target.js';
/**
* @internal
*/
export declare class CdpCDPSession extends CDPSession {
#private;
/**
* @internal
*/
constructor(connection: Connection, targetType: string, sessionId: string, parentSessionId: string | undefined, rawErrors: boolean);
/**
* Sets the {@link CdpTarget} associated with the session instance.
*
* @internal
*/
setTarget(target: CdpTarget): void;
/**
* Gets the {@link CdpTarget} associated with the session instance.
*
* @internal
*/
target(): CdpTarget;
connection(): Connection;
get detached(): boolean;
parentSession(): CDPSession | undefined;
send<T extends keyof ProtocolMapping.Commands>(method: T, params?: ProtocolMapping.Commands[T]['paramsType'][0], options?: CommandOptions): Promise<ProtocolMapping.Commands[T]['returnType']>;
/**
* @internal
*/
onMessage(object: {
id?: number;
method: keyof CDPEvents;
params: CDPEvents[keyof CDPEvents];
error: {
message: string;
data: any;
code: number;
};
result?: any;
}): void;
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
detach(): Promise<void>;
/**
* @internal
*/
onClosed(): void;
/**
* Returns the session's id.
*/
id(): string;
/**
* @internal
*/
hasCallback(id: number): boolean;
/**
* @internal
*/
getPendingProtocolErrors(): Error[];
}
//# sourceMappingURL=CdpSession.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CdpSession.d.ts","sourceRoot":"","sources":["../../../src/cdp/CdpSession.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,6CAA6C,CAAC;AAEjF,OAAO,EACL,KAAK,SAAS,EACd,UAAU,EAEV,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;GAEG;AAEH,qBAAa,aAAc,SAAQ,UAAU;;IAS3C;;OAEG;gBAED,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,SAAS,EAAE,OAAO;IAWpB;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIlC;;;;OAIG;IACH,MAAM,IAAI,SAAS;IAKV,UAAU,IAAI,UAAU;IAIjC,IAAa,QAAQ,IAAI,OAAO,CAE/B;IAEQ,aAAa,IAAI,UAAU,GAAG,SAAS;IAUvC,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EACpD,MAAM,EAAE,CAAC,EACT,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EACrD,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAuBrD;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE;QAChB,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,SAAS,CAAC;QACxB,MAAM,EAAE,SAAS,CAAC,MAAM,SAAS,CAAC,CAAC;QACnC,KAAK,EAAE;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,GAAG,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAC;QAClD,MAAM,CAAC,EAAE,GAAG,CAAC;KACd,GAAG,IAAI;IAqBR;;;OAGG;IACY,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAMhB;;OAEG;IACM,EAAE,IAAI,MAAM;IAIrB;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIhC;;OAEG;IACH,wBAAwB,IAAI,KAAK,EAAE;CAGpC"}

View File

@@ -0,0 +1,144 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { CDPSession, CDPSessionEvent, } from '../api/CDPSession.js';
import { CallbackRegistry } from '../common/CallbackRegistry.js';
import { TargetCloseError } from '../common/Errors.js';
import { assert } from '../util/assert.js';
import { createProtocolErrorMessage } from '../util/ErrorLike.js';
/**
* @internal
*/
export class CdpCDPSession extends CDPSession {
#sessionId;
#targetType;
#callbacks;
#connection;
#parentSessionId;
#target;
#rawErrors = false;
#detached = false;
/**
* @internal
*/
constructor(connection, targetType, sessionId, parentSessionId, rawErrors) {
super();
this.#connection = connection;
this.#targetType = targetType;
this.#callbacks = new CallbackRegistry(connection._idGenerator);
this.#sessionId = sessionId;
this.#parentSessionId = parentSessionId;
this.#rawErrors = rawErrors;
}
/**
* Sets the {@link CdpTarget} associated with the session instance.
*
* @internal
*/
setTarget(target) {
this.#target = target;
}
/**
* Gets the {@link CdpTarget} associated with the session instance.
*
* @internal
*/
target() {
assert(this.#target, 'Target must exist');
return this.#target;
}
connection() {
return this.#connection;
}
get detached() {
return this.#connection._closed || this.#detached;
}
parentSession() {
if (!this.#parentSessionId) {
// In some cases, e.g., DevTools pages there is no parent session. In this
// case, we treat the current session as the parent session.
return this;
}
const parent = this.#connection?.session(this.#parentSessionId);
return parent ?? undefined;
}
send(method, params, options) {
if (this.detached) {
return Promise.reject(new TargetCloseError(`Protocol error (${method}): Session closed. Most likely the ${this.#targetType} has been closed.`));
}
return this.#connection
._rawSend(this.#callbacks, method, params, this.#sessionId, options)
.catch(error => {
if (error instanceof Error &&
error.message.includes('Session with given id not found')) {
this.onClosed();
throw new TargetCloseError(`Protocol error (${method}): Session with given id not found.`);
}
throw error;
});
}
/**
* @internal
*/
onMessage(object) {
if (object.id) {
if (object.error) {
if (this.#rawErrors) {
this.#callbacks.rejectRaw(object.id, object.error);
}
else {
this.#callbacks.reject(object.id, createProtocolErrorMessage(object), object.error.message);
}
}
else {
this.#callbacks.resolve(object.id, object.result);
}
}
else {
assert(!object.id);
this.emit(object.method, object.params);
}
}
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
async detach() {
if (this.detached) {
throw new Error(`Session already detached. Most likely the ${this.#targetType} has been closed.`);
}
await this.#connection.send('Target.detachFromTarget', {
sessionId: this.#sessionId,
});
this.#detached = true;
}
/**
* @internal
*/
onClosed() {
this.#callbacks.clear();
this.#detached = true;
this.emit(CDPSessionEvent.Disconnected, undefined);
}
/**
* Returns the session's id.
*/
id() {
return this.#sessionId;
}
/**
* @internal
*/
hasCallback(id) {
return this.#callbacks.has(id);
}
/**
* @internal
*/
getPendingProtocolErrors() {
return this.#callbacks.getPendingProtocolErrors();
}
}
//# sourceMappingURL=CdpSession.js.map

View File

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

View File

@@ -0,0 +1,92 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import type { CommandOptions } from '../api/CDPSession.js';
import { type CDPSession, type CDPSessionEvents } from '../api/CDPSession.js';
import { CallbackRegistry } from '../common/CallbackRegistry.js';
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { type GetIdFn } from '../util/incremental-id-generator.js';
import { CdpCDPSession } from './CdpSession.js';
/**
* @public
*/
export declare class Connection extends EventEmitter<CDPSessionEvents> {
#private;
constructor(url: string, transport: ConnectionTransport, delay?: number, timeout?: number, rawErrors?: boolean, idGenerator?: () => number);
static fromSession(session: CDPSession): Connection | undefined;
/**
* @internal
*/
get delay(): number;
get timeout(): number;
/**
* @internal
*/
get rejectEmulateNetworkConditionsCalls(): boolean;
set rejectEmulateNetworkConditionsCalls(value: boolean);
/**
* @internal
*/
get _closed(): boolean;
/**
* @internal
*/
get _idGenerator(): GetIdFn;
/**
* @internal
*/
get _sessions(): Map<string, CdpCDPSession>;
/**
* @internal
*/
_session(sessionId: string): CdpCDPSession | null;
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId: string): CDPSession | null;
url(): string;
send<T extends keyof ProtocolMapping.Commands>(method: T, params?: ProtocolMapping.Commands[T]['paramsType'][0], options?: CommandOptions): Promise<ProtocolMapping.Commands[T]['returnType']>;
/**
* @internal
*/
_rawSend<T extends keyof ProtocolMapping.Commands>(callbacks: CallbackRegistry, method: T, params: ProtocolMapping.Commands[T]['paramsType'][0], sessionId?: string, options?: CommandOptions): Promise<ProtocolMapping.Commands[T]['returnType']>;
/**
* @internal
*/
closeBrowser(): Promise<void>;
/**
* @internal
*/
protected onMessage(message: string): Promise<void>;
dispose(): void;
/**
* @internal
*/
isAutoAttached(targetId: string): boolean;
/**
* @internal
*/
_createSession(targetInfo: {
targetId: string;
}, isAutoAttachEmulated?: boolean): Promise<CdpCDPSession>;
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
createSession(targetInfo: Protocol.Target.TargetInfo): Promise<CDPSession>;
/**
* @internal
*/
getPendingProtocolErrors(): Error[];
}
/**
* @internal
*/
export declare function isTargetClosedError(error: Error): boolean;
//# sourceMappingURL=Connection.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../../../src/cdp/Connection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,6CAA6C,CAAC;AAEjF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAC/D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AAG1E,OAAO,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAEvD,OAAO,EAEL,KAAK,OAAO,EACb,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAK9C;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;;gBAc1D,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,EAC9B,KAAK,SAAI,EACT,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,UAAQ,EACjB,WAAW,GAAE,MAAM,MAAuC;IAe5D,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS;IAI/D;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,IAAI,mCAAmC,IAAI,OAAO,CAEjD;IAED,IAAI,mCAAmC,CAAC,KAAK,EAAE,OAAO,EAErD;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAE1C;IAED;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAIjD;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAI7C,GAAG,IAAI,MAAM;IAIb,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EACrD,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAUrD;;OAEG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC/C,SAAS,EAAE,gBAAgB,EAC3B,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EACpD,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IA0BrD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC;;OAEG;cACa,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmFzD,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIzC;;OAEG;IACG,cAAc,CAClB,UAAU,EAAE;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,EAC9B,oBAAoB,UAAO,GAC1B,OAAO,CAAC,aAAa,CAAC;IAgBzB;;;OAGG;IACG,aAAa,CACjB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,GACrC,OAAO,CAAC,UAAU,CAAC;IAItB;;OAEG;IACH,wBAAwB,IAAI,KAAK,EAAE;CAQpC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAEzD"}

View File

@@ -0,0 +1,268 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { CDPSessionEvent, } from '../api/CDPSession.js';
import { CallbackRegistry } from '../common/CallbackRegistry.js';
import { debug } from '../common/Debug.js';
import { ConnectionClosedError, TargetCloseError } from '../common/Errors.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { createProtocolErrorMessage } from '../util/ErrorLike.js';
import { createIncrementalIdGenerator, } from '../util/incremental-id-generator.js';
import { CdpCDPSession } from './CdpSession.js';
const debugProtocolSend = debug('puppeteer:protocol:SEND ►');
const debugProtocolReceive = debug('puppeteer:protocol:RECV ◀');
/**
* @public
*/
export class Connection extends EventEmitter {
#url;
#transport;
#delay;
#timeout;
#sessions = new Map();
#closed = false;
#manuallyAttached = new Set();
#rejectEmulateNetworkConditionsCalls = false;
#callbacks;
#rawErrors = false;
#idGenerator;
constructor(url, transport, delay = 0, timeout, rawErrors = false, idGenerator = createIncrementalIdGenerator()) {
super();
this.#rawErrors = rawErrors;
this.#idGenerator = idGenerator;
this.#callbacks = new CallbackRegistry(idGenerator);
this.#url = url;
this.#delay = delay;
this.#timeout = timeout ?? 180_000;
this.#transport = transport;
this.#transport.onmessage = this.onMessage.bind(this);
this.#transport.onclose = this.#onClose.bind(this);
}
static fromSession(session) {
return session.connection();
}
/**
* @internal
*/
get delay() {
return this.#delay;
}
get timeout() {
return this.#timeout;
}
/**
* @internal
*/
get rejectEmulateNetworkConditionsCalls() {
return this.#rejectEmulateNetworkConditionsCalls;
}
set rejectEmulateNetworkConditionsCalls(value) {
this.#rejectEmulateNetworkConditionsCalls = value;
}
/**
* @internal
*/
get _closed() {
return this.#closed;
}
/**
* @internal
*/
get _idGenerator() {
return this.#idGenerator;
}
/**
* @internal
*/
get _sessions() {
return this.#sessions;
}
/**
* @internal
*/
_session(sessionId) {
return this.#sessions.get(sessionId) || null;
}
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId) {
return this._session(sessionId);
}
url() {
return this.#url;
}
send(method, params, options) {
// There is only ever 1 param arg passed, but the Protocol defines it as an
// array of 0 or 1 items See this comment:
// https://github.com/ChromeDevTools/devtools-protocol/pull/113#issuecomment-412603285
// which explains why the protocol defines the params this way for better
// type-inference.
// So now we check if there are any params or not and deal with them accordingly.
return this._rawSend(this.#callbacks, method, params, undefined, options);
}
/**
* @internal
*/
_rawSend(callbacks, method, params, sessionId, options) {
if (this.#closed) {
return Promise.reject(new ConnectionClosedError('Connection closed.'));
}
if (method === 'Network.emulateNetworkConditions' &&
this.rejectEmulateNetworkConditionsCalls) {
return Promise.reject(new Error('Cannot reset network conditions: rule-based emulation is enabled.'));
}
return callbacks.create(method, options?.timeout ?? this.#timeout, id => {
const stringifiedMessage = JSON.stringify({
method,
params,
id,
sessionId,
});
debugProtocolSend(stringifiedMessage);
this.#transport.send(stringifiedMessage);
});
}
/**
* @internal
*/
async closeBrowser() {
await this.send('Browser.close');
}
/**
* @internal
*/
async onMessage(message) {
if (this.#delay) {
await new Promise(r => {
return setTimeout(r, this.#delay);
});
}
debugProtocolReceive(message);
const object = JSON.parse(message);
if (object.method === 'Target.attachedToTarget') {
const sessionId = object.params.sessionId;
const session = new CdpCDPSession(this, object.params.targetInfo.type, sessionId, object.sessionId, this.#rawErrors);
this.#sessions.set(sessionId, session);
this.emit(CDPSessionEvent.SessionAttached, session);
const parentSession = this.#sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit(CDPSessionEvent.SessionAttached, session);
}
}
else if (object.method === 'Target.detachedFromTarget') {
const session = this.#sessions.get(object.params.sessionId);
if (session) {
session.onClosed();
this.#sessions.delete(object.params.sessionId);
this.emit(CDPSessionEvent.SessionDetached, session);
const parentSession = this.#sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit(CDPSessionEvent.SessionDetached, session);
}
}
}
if (object.sessionId) {
const session = this.#sessions.get(object.sessionId);
if (session) {
session.onMessage(object);
}
}
else if (object.id) {
if (this.#callbacks.has(object.id)) {
if (object.error) {
if (this.#rawErrors) {
this.#callbacks.rejectRaw(object.id, object.error);
}
else {
this.#callbacks.reject(object.id, createProtocolErrorMessage(object), object.error.message);
}
}
else {
this.#callbacks.resolve(object.id, object.result);
}
}
else {
for (const session of this.#sessions.values()) {
if (session.hasCallback(object.id)) {
session.onMessage(object);
break;
}
}
}
}
else {
this.emit(object.method, object.params);
}
}
#onClose() {
if (this.#closed) {
return;
}
this.#closed = true;
this.#transport.onmessage = undefined;
this.#transport.onclose = undefined;
this.#callbacks.clear();
for (const session of this.#sessions.values()) {
session.onClosed();
}
this.#sessions.clear();
this.emit(CDPSessionEvent.Disconnected, undefined);
}
dispose() {
this.#onClose();
this.#transport.close();
}
/**
* @internal
*/
isAutoAttached(targetId) {
return !this.#manuallyAttached.has(targetId);
}
/**
* @internal
*/
async _createSession(targetInfo, isAutoAttachEmulated = true) {
if (!isAutoAttachEmulated) {
this.#manuallyAttached.add(targetInfo.targetId);
}
const { sessionId } = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId,
flatten: true,
});
this.#manuallyAttached.delete(targetInfo.targetId);
const session = this.#sessions.get(sessionId);
if (!session) {
throw new Error('CDPSession creation failed.');
}
return session;
}
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
async createSession(targetInfo) {
return await this._createSession(targetInfo, false);
}
/**
* @internal
*/
getPendingProtocolErrors() {
const result = [];
result.push(...this.#callbacks.getPendingProtocolErrors());
for (const session of this.#sessions.values()) {
result.push(...session.getPendingProtocolErrors());
}
return result;
}
}
/**
* @internal
*/
export function isTargetClosedError(error) {
return error instanceof TargetCloseError;
}
//# sourceMappingURL=Connection.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,195 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
/**
* The CoverageEntry class represents one entry of the coverage report.
* @public
*/
export interface CoverageEntry {
/**
* The URL of the style sheet or script.
*/
url: string;
/**
* The content of the style sheet or script.
*/
text: string;
/**
* The covered range as start and end positions.
*/
ranges: Array<{
start: number;
end: number;
}>;
}
/**
* The CoverageEntry class for JavaScript
* @public
*/
export interface JSCoverageEntry extends CoverageEntry {
/**
* Raw V8 script coverage entry.
*/
rawScriptCoverage?: Protocol.Profiler.ScriptCoverage;
}
/**
* Set of configurable options for JS coverage.
* @public
*/
export interface JSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
/**
* Whether anonymous scripts generated by the page should be reported.
*/
reportAnonymousScripts?: boolean;
/**
* Whether the result includes raw V8 script coverage entries.
*/
includeRawScriptCoverage?: boolean;
/**
* Whether to collect coverage information at the block level.
* If true, coverage will be collected at the block level (this is the default).
* If false, coverage will be collected at the function level.
*/
useBlockCoverage?: boolean;
}
/**
* Set of configurable options for CSS coverage.
* @public
*/
export interface CSSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
}
/**
* The Coverage class provides methods to gather information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
*
* ```ts
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage(),
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges) usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${(usedBytes / totalBytes) * 100}%`);
* ```
*
* @public
*/
export declare class Coverage {
#private;
/**
* @internal
*/
constructor(client: CDPSession);
/**
* @internal
*/
updateClient(client: CDPSession): void;
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false,`
* `includeRawScriptCoverage : false, useBlockCoverage : true`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts URL will start with `debugger://VM` (unless a magic //# sourceURL
* comment is present, in which case that will the be URL).
*/
startJSCoverage(options?: JSCoverageOptions): Promise<void>;
/**
* Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
stopJSCoverage(): Promise<JSCoverageEntry[]>;
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
startCSSCoverage(options?: CSSCoverageOptions): Promise<void>;
/**
* Promise that resolves to the array of coverage reports
* for all stylesheets.
*
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
stopCSSCoverage(): Promise<CoverageEntry[]>;
}
/**
* @public
*/
export declare class JSCoverage {
#private;
/**
* @internal
*/
constructor(client: CDPSession);
/**
* @internal
*/
updateClient(client: CDPSession): void;
start(options?: {
resetOnNavigation?: boolean;
reportAnonymousScripts?: boolean;
includeRawScriptCoverage?: boolean;
useBlockCoverage?: boolean;
}): Promise<void>;
stop(): Promise<JSCoverageEntry[]>;
}
/**
* @public
*/
export declare class CSSCoverage {
#private;
constructor(client: CDPSession);
/**
* @internal
*/
updateClient(client: CDPSession): void;
start(options?: {
resetOnNavigation?: boolean;
}): Promise<void>;
stop(): Promise<CoverageEntry[]>;
}
//# sourceMappingURL=Coverage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Coverage.d.ts","sourceRoot":"","sources":["../../../src/cdp/Coverage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAMrD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD;;OAEG;IACH,iBAAiB,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC;CACtD;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;OAEG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;OAEG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,QAAQ;;IAInB;;OAEG;gBACS,MAAM,EAAE,UAAU;IAK9B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAKtC;;;;;;;;;;;;OAYG;IACG,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrE;;;;;;;OAOG;IACG,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIlD;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;;;;;;OAOG;IACG,eAAe,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CAGlD;AAED;;GAEG;AACH,qBAAa,UAAU;;IAUrB;;OAEG;gBACS,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIhC,KAAK,CACT,OAAO,GAAE;QACP,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACvB,GACL,OAAO,CAAC,IAAI,CAAC;IAiEV,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;CAsCzC;AAED;;GAEG;AACH,qBAAa,WAAW;;gBAQV,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIhC,KAAK,CAAC,OAAO,GAAE;QAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDjE,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CA+CvC"}

View File

@@ -0,0 +1,372 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { EventEmitter } from '../common/EventEmitter.js';
import { debugError, PuppeteerURL } from '../common/util.js';
import { assert } from '../util/assert.js';
import { DisposableStack } from '../util/disposable.js';
/**
* The Coverage class provides methods to gather information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
*
* ```ts
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage(),
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges) usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${(usedBytes / totalBytes) * 100}%`);
* ```
*
* @public
*/
export class Coverage {
#jsCoverage;
#cssCoverage;
/**
* @internal
*/
constructor(client) {
this.#jsCoverage = new JSCoverage(client);
this.#cssCoverage = new CSSCoverage(client);
}
/**
* @internal
*/
updateClient(client) {
this.#jsCoverage.updateClient(client);
this.#cssCoverage.updateClient(client);
}
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false,`
* `includeRawScriptCoverage : false, useBlockCoverage : true`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts URL will start with `debugger://VM` (unless a magic //# sourceURL
* comment is present, in which case that will the be URL).
*/
async startJSCoverage(options = {}) {
return await this.#jsCoverage.start(options);
}
/**
* Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
async stopJSCoverage() {
return await this.#jsCoverage.stop();
}
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
async startCSSCoverage(options = {}) {
return await this.#cssCoverage.start(options);
}
/**
* Promise that resolves to the array of coverage reports
* for all stylesheets.
*
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
async stopCSSCoverage() {
return await this.#cssCoverage.stop();
}
}
/**
* @public
*/
export class JSCoverage {
#client;
#enabled = false;
#scriptURLs = new Map();
#scriptSources = new Map();
#subscriptions;
#resetOnNavigation = false;
#reportAnonymousScripts = false;
#includeRawScriptCoverage = false;
/**
* @internal
*/
constructor(client) {
this.#client = client;
}
/**
* @internal
*/
updateClient(client) {
this.#client = client;
}
async start(options = {}) {
assert(!this.#enabled, 'JSCoverage is already enabled');
const { resetOnNavigation = true, reportAnonymousScripts = false, includeRawScriptCoverage = false, useBlockCoverage = true, } = options;
this.#resetOnNavigation = resetOnNavigation;
this.#reportAnonymousScripts = reportAnonymousScripts;
this.#includeRawScriptCoverage = includeRawScriptCoverage;
this.#enabled = true;
this.#scriptURLs.clear();
this.#scriptSources.clear();
this.#subscriptions = new DisposableStack();
const clientEmitter = this.#subscriptions.use(new EventEmitter(this.#client));
clientEmitter.on('Debugger.scriptParsed', this.#onScriptParsed.bind(this));
clientEmitter.on('Runtime.executionContextsCleared', this.#onExecutionContextsCleared.bind(this));
await Promise.all([
this.#client.send('Profiler.enable'),
this.#client.send('Profiler.startPreciseCoverage', {
callCount: this.#includeRawScriptCoverage,
detailed: useBlockCoverage,
}),
this.#client.send('Debugger.enable'),
this.#client.send('Debugger.setSkipAllPauses', { skip: true }),
]);
}
#onExecutionContextsCleared() {
if (!this.#resetOnNavigation) {
return;
}
this.#scriptURLs.clear();
this.#scriptSources.clear();
}
async #onScriptParsed(event) {
// Ignore puppeteer-injected scripts
if (PuppeteerURL.isPuppeteerURL(event.url)) {
return;
}
// Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
if (!event.url && !this.#reportAnonymousScripts) {
return;
}
try {
const response = await this.#client.send('Debugger.getScriptSource', {
scriptId: event.scriptId,
});
this.#scriptURLs.set(event.scriptId, event.url);
this.#scriptSources.set(event.scriptId, response.scriptSource);
}
catch (error) {
// This might happen if the page has already navigated away.
debugError(error);
}
}
async stop() {
assert(this.#enabled, 'JSCoverage is not enabled');
this.#enabled = false;
const result = await Promise.all([
this.#client.send('Profiler.takePreciseCoverage'),
this.#client.send('Profiler.stopPreciseCoverage'),
this.#client.send('Profiler.disable'),
this.#client.send('Debugger.disable'),
]);
this.#subscriptions?.dispose();
const coverage = [];
const profileResponse = result[0];
for (const entry of profileResponse.result) {
let url = this.#scriptURLs.get(entry.scriptId);
if (!url && this.#reportAnonymousScripts) {
url = 'debugger://VM' + entry.scriptId;
}
const text = this.#scriptSources.get(entry.scriptId);
if (text === undefined || url === undefined) {
continue;
}
const flattenRanges = [];
for (const func of entry.functions) {
flattenRanges.push(...func.ranges);
}
const ranges = convertToDisjointRanges(flattenRanges);
if (!this.#includeRawScriptCoverage) {
coverage.push({ url, ranges, text });
}
else {
coverage.push({ url, ranges, text, rawScriptCoverage: entry });
}
}
return coverage;
}
}
/**
* @public
*/
export class CSSCoverage {
#client;
#enabled = false;
#stylesheetURLs = new Map();
#stylesheetSources = new Map();
#eventListeners;
#resetOnNavigation = false;
constructor(client) {
this.#client = client;
}
/**
* @internal
*/
updateClient(client) {
this.#client = client;
}
async start(options = {}) {
assert(!this.#enabled, 'CSSCoverage is already enabled');
const { resetOnNavigation = true } = options;
this.#resetOnNavigation = resetOnNavigation;
this.#enabled = true;
this.#stylesheetURLs.clear();
this.#stylesheetSources.clear();
this.#eventListeners = new DisposableStack();
const clientEmitter = this.#eventListeners.use(new EventEmitter(this.#client));
clientEmitter.on('CSS.styleSheetAdded', this.#onStyleSheet.bind(this));
clientEmitter.on('Runtime.executionContextsCleared', this.#onExecutionContextsCleared.bind(this));
await Promise.all([
this.#client.send('DOM.enable'),
this.#client.send('CSS.enable'),
this.#client.send('CSS.startRuleUsageTracking'),
]);
}
#onExecutionContextsCleared() {
if (!this.#resetOnNavigation) {
return;
}
this.#stylesheetURLs.clear();
this.#stylesheetSources.clear();
}
async #onStyleSheet(event) {
const header = event.header;
// Ignore anonymous scripts
if (!header.sourceURL) {
return;
}
try {
const response = await this.#client.send('CSS.getStyleSheetText', {
styleSheetId: header.styleSheetId,
});
this.#stylesheetURLs.set(header.styleSheetId, header.sourceURL);
this.#stylesheetSources.set(header.styleSheetId, response.text);
}
catch (error) {
// This might happen if the page has already navigated away.
debugError(error);
}
}
async stop() {
assert(this.#enabled, 'CSSCoverage is not enabled');
this.#enabled = false;
const ruleTrackingResponse = await this.#client.send('CSS.stopRuleUsageTracking');
await Promise.all([
this.#client.send('CSS.disable'),
this.#client.send('DOM.disable'),
]);
this.#eventListeners?.dispose();
// aggregate by styleSheetId
const styleSheetIdToCoverage = new Map();
for (const entry of ruleTrackingResponse.ruleUsage) {
let ranges = styleSheetIdToCoverage.get(entry.styleSheetId);
if (!ranges) {
ranges = [];
styleSheetIdToCoverage.set(entry.styleSheetId, ranges);
}
ranges.push({
startOffset: entry.startOffset,
endOffset: entry.endOffset,
count: entry.used ? 1 : 0,
});
}
const coverage = [];
for (const styleSheetId of this.#stylesheetURLs.keys()) {
const url = this.#stylesheetURLs.get(styleSheetId);
assert(typeof url !== 'undefined', `Stylesheet URL is undefined (styleSheetId=${styleSheetId})`);
const text = this.#stylesheetSources.get(styleSheetId);
assert(typeof text !== 'undefined', `Stylesheet text is undefined (styleSheetId=${styleSheetId})`);
const ranges = convertToDisjointRanges(styleSheetIdToCoverage.get(styleSheetId) || []);
coverage.push({ url, ranges, text });
}
return coverage;
}
}
function convertToDisjointRanges(nestedRanges) {
const points = [];
for (const range of nestedRanges) {
points.push({ offset: range.startOffset, type: 0, range });
points.push({ offset: range.endOffset, type: 1, range });
}
// Sort points to form a valid parenthesis sequence.
points.sort((a, b) => {
// Sort with increasing offsets.
if (a.offset !== b.offset) {
return a.offset - b.offset;
}
// All "end" points should go before "start" points.
if (a.type !== b.type) {
return b.type - a.type;
}
const aLength = a.range.endOffset - a.range.startOffset;
const bLength = b.range.endOffset - b.range.startOffset;
// For two "start" points, the one with longer range goes first.
if (a.type === 0) {
return bLength - aLength;
}
// For two "end" points, the one with shorter range goes first.
return aLength - bLength;
});
const hitCountStack = [];
const results = [];
let lastOffset = 0;
// Run scanning line to intersect all ranges.
for (const point of points) {
if (hitCountStack.length &&
lastOffset < point.offset &&
hitCountStack[hitCountStack.length - 1] > 0) {
const lastResult = results[results.length - 1];
if (lastResult && lastResult.end === lastOffset) {
lastResult.end = point.offset;
}
else {
results.push({ start: lastOffset, end: point.offset });
}
}
lastOffset = point.offset;
if (point.type === 0) {
hitCountStack.push(point.range.count);
}
else {
hitCountStack.pop();
}
}
// Filter out empty ranges.
return results.filter(range => {
return range.end - range.start > 0;
});
}
//# sourceMappingURL=Coverage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,30 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type Protocol from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import { DeviceRequestPrompt } from '../api/DeviceRequestPrompt.js';
import type { DeviceRequestPromptDevice } from '../api/DeviceRequestPrompt.js';
import type { WaitTimeoutOptions } from '../api/Page.js';
import type { TimeoutSettings } from '../common/TimeoutSettings.js';
/**
* @internal
*/
export declare class CdpDeviceRequestPrompt extends DeviceRequestPrompt {
#private;
constructor(client: CDPSession, timeoutSettings: TimeoutSettings, firstEvent: Protocol.DeviceAccess.DeviceRequestPromptedEvent);
waitForDevice(filter: (device: DeviceRequestPromptDevice) => boolean, options?: WaitTimeoutOptions): Promise<DeviceRequestPromptDevice>;
select(device: DeviceRequestPromptDevice): Promise<void>;
cancel(): Promise<void>;
}
/**
* @internal
*/
export declare class CdpDeviceRequestPromptManager {
#private;
constructor(client: CDPSession, timeoutSettings: TimeoutSettings);
waitForDevicePrompt(options?: WaitTimeoutOptions): Promise<DeviceRequestPrompt>;
}
//# sourceMappingURL=DeviceRequestPrompt.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DeviceRequestPrompt.d.ts","sourceRoot":"","sources":["../../../src/cdp/DeviceRequestPrompt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAC,mBAAmB,EAAC,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,+BAA+B,CAAC;AAC7E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAIlE;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,mBAAmB;;gBAY3D,MAAM,EAAE,UAAU,EAClB,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,QAAQ,CAAC,YAAY,CAAC,0BAA0B;IA2CxD,aAAa,CACjB,MAAM,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,OAAO,EACtD,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,yBAAyB,CAAC;IAgC/B,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB9B;AAED;;GAEG;AACH,qBAAa,6BAA6B;;gBAK5B,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe;IAY1D,mBAAmB,CACvB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,mBAAmB,CAAC;CAyDhC"}

View File

@@ -0,0 +1,151 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { DeviceRequestPrompt } from '../api/DeviceRequestPrompt.js';
import { assert } from '../util/assert.js';
import { Deferred } from '../util/Deferred.js';
/**
* @internal
*/
export class CdpDeviceRequestPrompt extends DeviceRequestPrompt {
#client;
#timeoutSettings;
#id;
#handled = false;
#updateDevicesHandle = this.#updateDevices.bind(this);
#waitForDevicePromises = new Set();
constructor(client, timeoutSettings, firstEvent) {
super();
this.#client = client;
this.#timeoutSettings = timeoutSettings;
this.#id = firstEvent.id;
this.#client.on('DeviceAccess.deviceRequestPrompted', this.#updateDevicesHandle);
this.#client.on('Target.detachedFromTarget', () => {
this.#client = null;
});
this.#updateDevices(firstEvent);
}
#updateDevices(event) {
if (event.id !== this.#id) {
return;
}
for (const rawDevice of event.devices) {
if (this.devices.some(device => {
return device.id === rawDevice.id;
})) {
continue;
}
const newDevice = { id: rawDevice.id, name: rawDevice.name };
this.devices.push(newDevice);
for (const waitForDevicePromise of this.#waitForDevicePromises) {
if (waitForDevicePromise.filter(newDevice)) {
waitForDevicePromise.promise.resolve(newDevice);
}
}
}
}
async waitForDevice(filter, options = {}) {
for (const device of this.devices) {
if (filter(device)) {
return device;
}
}
const { timeout = this.#timeoutSettings.timeout() } = options;
const deferred = Deferred.create({
message: `Waiting for \`DeviceRequestPromptDevice\` failed: ${timeout}ms exceeded`,
timeout,
});
if (options.signal) {
options.signal.addEventListener('abort', () => {
deferred.reject(options.signal?.reason);
}, { once: true });
}
const handle = { filter, promise: deferred };
this.#waitForDevicePromises.add(handle);
try {
return await deferred.valueOrThrow();
}
finally {
this.#waitForDevicePromises.delete(handle);
}
}
async select(device) {
assert(this.#client !== null, 'Cannot select device through detached session!');
assert(this.devices.includes(device), 'Cannot select unknown device!');
assert(!this.#handled, 'Cannot select DeviceRequestPrompt which is already handled!');
this.#client.off('DeviceAccess.deviceRequestPrompted', this.#updateDevicesHandle);
this.#handled = true;
return await this.#client.send('DeviceAccess.selectPrompt', {
id: this.#id,
deviceId: device.id,
});
}
async cancel() {
assert(this.#client !== null, 'Cannot cancel prompt through detached session!');
assert(!this.#handled, 'Cannot cancel DeviceRequestPrompt which is already handled!');
this.#client.off('DeviceAccess.deviceRequestPrompted', this.#updateDevicesHandle);
this.#handled = true;
return await this.#client.send('DeviceAccess.cancelPrompt', { id: this.#id });
}
}
/**
* @internal
*/
export class CdpDeviceRequestPromptManager {
#client;
#timeoutSettings;
#deviceRequestPromptDeferreds = new Set();
constructor(client, timeoutSettings) {
this.#client = client;
this.#timeoutSettings = timeoutSettings;
this.#client.on('DeviceAccess.deviceRequestPrompted', event => {
this.#onDeviceRequestPrompted(event);
});
this.#client.on('Target.detachedFromTarget', () => {
this.#client = null;
});
}
async waitForDevicePrompt(options = {}) {
assert(this.#client !== null, 'Cannot wait for device prompt through detached session!');
const needsEnable = this.#deviceRequestPromptDeferreds.size === 0;
let enablePromise;
if (needsEnable) {
enablePromise = this.#client.send('DeviceAccess.enable');
}
const { timeout = this.#timeoutSettings.timeout() } = options;
const deferred = Deferred.create({
message: `Waiting for \`DeviceRequestPrompt\` failed: ${timeout}ms exceeded`,
timeout,
});
if (options.signal) {
options.signal.addEventListener('abort', () => {
deferred.reject(options.signal?.reason);
}, { once: true });
}
this.#deviceRequestPromptDeferreds.add(deferred);
try {
const [result] = await Promise.all([
deferred.valueOrThrow(),
enablePromise,
]);
return result;
}
finally {
this.#deviceRequestPromptDeferreds.delete(deferred);
}
}
#onDeviceRequestPrompted(event) {
if (!this.#deviceRequestPromptDeferreds.size) {
return;
}
assert(this.#client !== null);
const devicePrompt = new CdpDeviceRequestPrompt(this.#client, this.#timeoutSettings, event);
for (const promise of this.#deviceRequestPromptDeferreds) {
promise.resolve(devicePrompt);
}
this.#deviceRequestPromptDeferreds.clear();
}
}
//# sourceMappingURL=DeviceRequestPrompt.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import { Dialog } from '../api/Dialog.js';
/**
* @internal
*/
export declare class CdpDialog extends Dialog {
#private;
constructor(client: CDPSession, type: Protocol.Page.DialogType, message: string, defaultValue?: string);
handle(options: {
accept: boolean;
text?: string;
}): Promise<void>;
}
//# sourceMappingURL=Dialog.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../src/cdp/Dialog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAC;AAExC;;GAEG;AACH,qBAAa,SAAU,SAAQ,MAAM;;gBAIjC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,SAAK;IAMJ,MAAM,CAAC,OAAO,EAAE;QAC7B,MAAM,EAAE,OAAO,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,IAAI,CAAC;CAMlB"}

View File

@@ -0,0 +1,23 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { Dialog } from '../api/Dialog.js';
/**
* @internal
*/
export class CdpDialog extends Dialog {
#client;
constructor(client, type, message, defaultValue = '') {
super(type, message, defaultValue);
this.#client = client;
}
async handle(options) {
await this.#client.send('Page.handleJavaScriptDialog', {
accept: options.accept,
promptText: options.text,
});
}
}
//# sourceMappingURL=Dialog.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../../src/cdp/Dialog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAC;AAExC;;GAEG;AACH,MAAM,OAAO,SAAU,SAAQ,MAAM;IACnC,OAAO,CAAa;IAEpB,YACE,MAAkB,EAClB,IAA8B,EAC9B,OAAe,EACf,YAAY,GAAG,EAAE;QAEjB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAEQ,KAAK,CAAC,MAAM,CAAC,OAGrB;QACC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACrD,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,OAAO,CAAC,IAAI;SACzB,CAAC,CAAC;IACL,CAAC;CACF"}

View File

@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2019 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import { ElementHandle, type AutofillData } from '../api/ElementHandle.js';
import type { AwaitableIterable } from '../common/types.js';
import type { CdpFrame } from './Frame.js';
import type { IsolatedWorld } from './IsolatedWorld.js';
import { CdpJSHandle } from './JSHandle.js';
/**
* The CdpElementHandle extends ElementHandle now to keep compatibility
* with `instanceof` because of that we need to have methods for
* CdpJSHandle to in this implementation as well.
*
* @internal
*/
export declare class CdpElementHandle<ElementType extends Node = Element> extends ElementHandle<ElementType> {
#private;
protected readonly handle: CdpJSHandle<ElementType>;
constructor(world: IsolatedWorld, remoteObject: Protocol.Runtime.RemoteObject);
get realm(): IsolatedWorld;
get client(): CDPSession;
remoteObject(): Protocol.Runtime.RemoteObject;
get frame(): CdpFrame;
contentFrame(this: ElementHandle<HTMLIFrameElement>): Promise<CdpFrame>;
scrollIntoView(this: CdpElementHandle<Element>): Promise<void>;
uploadFile(this: CdpElementHandle<HTMLInputElement>, ...files: string[]): Promise<void>;
autofill(data: AutofillData): Promise<void>;
queryAXTree(name?: string | undefined, role?: string | undefined): AwaitableIterable<ElementHandle<Node>>;
backendNodeId(): Promise<number>;
}
//# sourceMappingURL=ElementHandle.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ElementHandle.d.ts","sourceRoot":"","sources":["../../../src/cdp/ElementHandle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAEL,aAAa,EACb,KAAK,YAAY,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAO1D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AAEzC,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C;;;;;;GAMG;AACH,qBAAa,gBAAgB,CAC3B,WAAW,SAAS,IAAI,GAAG,OAAO,CAClC,SAAQ,aAAa,CAAC,WAAW,CAAC;;IAClC,mBAA2B,MAAM,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;gBAI1D,KAAK,EAAE,aAAa,EACpB,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY;IAK7C,IAAa,KAAK,IAAI,aAAa,CAElC;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAEQ,YAAY,IAAI,QAAQ,CAAC,OAAO,CAAC,YAAY;IAQtD,IAAa,KAAK,IAAI,QAAQ,CAE7B;IAEc,YAAY,CACzB,IAAI,EAAE,aAAa,CAAC,iBAAiB,CAAC,GACrC,OAAO,CAAC,QAAQ,CAAC;IAeL,cAAc,CAC3B,IAAI,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAeD,UAAU,CACvB,IAAI,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,EACxC,GAAG,KAAK,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,IAAI,CAAC;IAyDD,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAc1C,WAAW,CACzB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GACxB,iBAAiB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IA2B1B,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;CAUhD"}

View File

@@ -0,0 +1,207 @@
/**
* @license
* Copyright 2019 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;
};
import { bindIsolatedHandle, ElementHandle, } from '../api/ElementHandle.js';
import { debugError } from '../common/util.js';
import { environment } from '../environment.js';
import { assert } from '../util/assert.js';
import { AsyncIterableUtil } from '../util/AsyncIterableUtil.js';
import { throwIfDisposed } from '../util/decorators.js';
import { CdpJSHandle } from './JSHandle.js';
const NON_ELEMENT_NODE_ROLES = new Set(['StaticText', 'InlineTextBox']);
/**
* The CdpElementHandle extends ElementHandle now to keep compatibility
* with `instanceof` because of that we need to have methods for
* CdpJSHandle to in this implementation as well.
*
* @internal
*/
let CdpElementHandle = (() => {
let _classSuper = ElementHandle;
let _instanceExtraInitializers = [];
let _contentFrame_decorators;
let _scrollIntoView_decorators;
let _uploadFile_decorators;
let _autofill_decorators;
return class CdpElementHandle extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_contentFrame_decorators = [throwIfDisposed()];
_scrollIntoView_decorators = [throwIfDisposed(), bindIsolatedHandle];
_uploadFile_decorators = [throwIfDisposed(), bindIsolatedHandle];
_autofill_decorators = [throwIfDisposed()];
__esDecorate(this, null, _contentFrame_decorators, { kind: "method", name: "contentFrame", static: false, private: false, access: { has: obj => "contentFrame" in obj, get: obj => obj.contentFrame }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _scrollIntoView_decorators, { kind: "method", name: "scrollIntoView", static: false, private: false, access: { has: obj => "scrollIntoView" in obj, get: obj => obj.scrollIntoView }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _uploadFile_decorators, { kind: "method", name: "uploadFile", static: false, private: false, access: { has: obj => "uploadFile" in obj, get: obj => obj.uploadFile }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _autofill_decorators, { kind: "method", name: "autofill", static: false, private: false, access: { has: obj => "autofill" in obj, get: obj => obj.autofill }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
#backendNodeId = __runInitializers(this, _instanceExtraInitializers);
constructor(world, remoteObject) {
super(new CdpJSHandle(world, remoteObject));
}
get realm() {
return this.handle.realm;
}
get client() {
return this.handle.client;
}
remoteObject() {
return this.handle.remoteObject();
}
get #frameManager() {
return this.frame._frameManager;
}
get frame() {
return this.realm.environment;
}
async contentFrame() {
const nodeInfo = await this.client.send('DOM.describeNode', {
objectId: this.id,
});
if (typeof nodeInfo.node.frameId !== 'string') {
return null;
}
return this.#frameManager.frame(nodeInfo.node.frameId);
}
async scrollIntoView() {
await this.assertConnectedElement();
try {
await this.client.send('DOM.scrollIntoViewIfNeeded', {
objectId: this.id,
});
}
catch (error) {
debugError(error);
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
await super.scrollIntoView();
}
}
async uploadFile(...files) {
const isMultiple = await this.evaluate(element => {
return element.multiple;
});
assert(files.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
// Locate all files and confirm that they exist.
const path = environment.value.path;
if (path) {
files = files.map(filePath => {
if (path.win32.isAbsolute(filePath) ||
path.posix.isAbsolute(filePath)) {
return filePath;
}
else {
return path.resolve(filePath);
}
});
}
/**
* The zero-length array is a special case, it seems that
* DOM.setFileInputFiles does not actually update the files in that case, so
* the solution is to eval the element value to a new FileList directly.
*/
if (files.length === 0) {
// XXX: These events should converted to trusted events. Perhaps do this
// in `DOM.setFileInputFiles`?
await this.evaluate(element => {
element.files = new DataTransfer().files;
// Dispatch events for this case because it should behave akin to a user action.
element.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
});
return;
}
const { node: { backendNodeId }, } = await this.client.send('DOM.describeNode', {
objectId: this.id,
});
await this.client.send('DOM.setFileInputFiles', {
objectId: this.id,
files,
backendNodeId,
});
}
async autofill(data) {
const nodeInfo = await this.client.send('DOM.describeNode', {
objectId: this.handle.id,
});
const fieldId = nodeInfo.node.backendNodeId;
const frameId = this.frame._id;
await this.client.send('Autofill.trigger', {
fieldId,
frameId,
card: data.creditCard,
address: data.address,
});
}
async *queryAXTree(name, role) {
const { nodes } = await this.client.send('Accessibility.queryAXTree', {
objectId: this.id,
accessibleName: name,
role,
});
const results = nodes.filter(node => {
if (node.ignored) {
return false;
}
if (!node.role) {
return false;
}
if (NON_ELEMENT_NODE_ROLES.has(node.role.value)) {
return false;
}
return true;
});
return yield* AsyncIterableUtil.map(results, node => {
return this.realm.adoptBackendNode(node.backendDOMNodeId);
});
}
async backendNodeId() {
if (this.#backendNodeId) {
return this.#backendNodeId;
}
const { node } = await this.client.send('DOM.describeNode', {
objectId: this.handle.id,
});
this.#backendNodeId = node.backendNodeId;
return this.#backendNodeId;
}
};
})();
export { CdpElementHandle };
//# sourceMappingURL=ElementHandle.js.map

View File

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

View File

@@ -0,0 +1,62 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import { type CDPSession } from '../api/CDPSession.js';
import type { GeolocationOptions, MediaFeature } from '../api/Page.js';
import type { Viewport } from '../common/Viewport.js';
/**
* @internal
*/
export interface ClientProvider {
clients(): CDPSession[];
registerState(state: EmulatedState<any>): void;
}
/**
* @internal
*/
export declare class EmulatedState<T extends {
active: boolean;
}> {
#private;
constructor(initialState: T, clientProvider: ClientProvider, updater: (client: CDPSession, state: T) => Promise<void>);
setState(state: T): Promise<void>;
get state(): T;
sync(): Promise<void>;
}
/**
* @internal
*/
export declare class EmulationManager implements ClientProvider {
#private;
constructor(client: CDPSession);
updateClient(client: CDPSession): void;
registerState(state: EmulatedState<any>): void;
clients(): CDPSession[];
registerSpeculativeSession(client: CDPSession): Promise<void>;
get javascriptEnabled(): boolean;
emulateViewport(viewport: Viewport | null): Promise<boolean>;
emulateIdleState(overrides?: {
isUserActive: boolean;
isScreenUnlocked: boolean;
}): Promise<void>;
emulateTimezone(timezoneId?: string): Promise<void>;
emulateVisionDeficiency(type?: Protocol.Emulation.SetEmulatedVisionDeficiencyRequest['type']): Promise<void>;
emulateCPUThrottling(factor: number | null): Promise<void>;
emulateMediaFeatures(features?: MediaFeature[]): Promise<void>;
emulateMediaType(type?: string): Promise<void>;
setGeolocation(options: GeolocationOptions): Promise<void>;
/**
* Resets default white background
*/
resetDefaultBackgroundColor(): Promise<void>;
/**
* Hides default white background
*/
setTransparentBackgroundColor(): Promise<void>;
setJavaScriptEnabled(enabled: boolean): Promise<void>;
emulateFocus(enabled: boolean): Promise<void>;
}
//# sourceMappingURL=EmulationManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EmulationManager.d.ts","sourceRoot":"","sources":["../../../src/cdp/EmulationManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAC,KAAK,UAAU,EAAkB,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAC,kBAAkB,EAAE,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAErE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AA+DpD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,IAAI,UAAU,EAAE,CAAC;IACxB,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;CAChD;AAED;;GAEG;AACH,qBAAa,aAAa,CAAC,CAAC,SAAS;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC;;gBAMlD,YAAY,EAAE,CAAC,EACf,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;IAQpD,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC,IAAI,KAAK,IAAI,CAAC,CAEb;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAO5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,YAAW,cAAc;;gBA0FzC,MAAM,EAAE,UAAU;IAI9B,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAKtC,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAI9C,OAAO,IAAI,UAAU,EAAE;IAIjB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnE,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAEK,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IA2E5D,gBAAgB,CAAC,SAAS,CAAC,EAAE;QACjC,YAAY,EAAE,OAAO,CAAC;QACtB,gBAAgB,EAAE,OAAO,CAAC;KAC3B,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CX,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnD,uBAAuB,CAC3B,IAAI,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,kCAAkC,CAAC,MAAM,CAAC,GACnE,OAAO,CAAC,IAAI,CAAC;IAmCV,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB1D,oBAAoB,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B9D,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC9C,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwChE;;OAEG;IACG,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;IAOlD;;OAEG;IACG,6BAA6B,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB9C,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrD,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAMpD"}

View File

@@ -0,0 +1,458 @@
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 { CDPSessionEvent } from '../api/CDPSession.js';
import { debugError } from '../common/util.js';
import { assert } from '../util/assert.js';
import { invokeAtMostOnceForArguments } from '../util/decorators.js';
import { isErrorLike } from '../util/ErrorLike.js';
/**
* @internal
*/
export class EmulatedState {
#state;
#clientProvider;
#updater;
constructor(initialState, clientProvider, updater) {
this.#state = initialState;
this.#clientProvider = clientProvider;
this.#updater = updater;
this.#clientProvider.registerState(this);
}
async setState(state) {
this.#state = state;
await this.sync();
}
get state() {
return this.#state;
}
async sync() {
await Promise.all(this.#clientProvider.clients().map(client => {
return this.#updater(client, this.#state);
}));
}
}
/**
* @internal
*/
let EmulationManager = (() => {
let _instanceExtraInitializers = [];
let _private_applyViewport_decorators;
let _private_applyViewport_descriptor;
let _private_emulateIdleState_decorators;
let _private_emulateIdleState_descriptor;
let _private_emulateTimezone_decorators;
let _private_emulateTimezone_descriptor;
let _private_emulateVisionDeficiency_decorators;
let _private_emulateVisionDeficiency_descriptor;
let _private_emulateCpuThrottling_decorators;
let _private_emulateCpuThrottling_descriptor;
let _private_emulateMediaFeatures_decorators;
let _private_emulateMediaFeatures_descriptor;
let _private_emulateMediaType_decorators;
let _private_emulateMediaType_descriptor;
let _private_setGeolocation_decorators;
let _private_setGeolocation_descriptor;
let _private_setDefaultBackgroundColor_decorators;
let _private_setDefaultBackgroundColor_descriptor;
let _private_setJavaScriptEnabled_decorators;
let _private_setJavaScriptEnabled_descriptor;
let _private_emulateFocus_decorators;
let _private_emulateFocus_descriptor;
return class EmulationManager {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
_private_applyViewport_decorators = [invokeAtMostOnceForArguments];
_private_emulateIdleState_decorators = [invokeAtMostOnceForArguments];
_private_emulateTimezone_decorators = [invokeAtMostOnceForArguments];
_private_emulateVisionDeficiency_decorators = [invokeAtMostOnceForArguments];
_private_emulateCpuThrottling_decorators = [invokeAtMostOnceForArguments];
_private_emulateMediaFeatures_decorators = [invokeAtMostOnceForArguments];
_private_emulateMediaType_decorators = [invokeAtMostOnceForArguments];
_private_setGeolocation_decorators = [invokeAtMostOnceForArguments];
_private_setDefaultBackgroundColor_decorators = [invokeAtMostOnceForArguments];
_private_setJavaScriptEnabled_decorators = [invokeAtMostOnceForArguments];
_private_emulateFocus_decorators = [invokeAtMostOnceForArguments];
__esDecorate(this, _private_applyViewport_descriptor = { value: __setFunctionName(async function (client, viewportState) {
if (!viewportState.viewport) {
await Promise.all([
client.send('Emulation.clearDeviceMetricsOverride'),
client.send('Emulation.setTouchEmulationEnabled', {
enabled: false,
}),
]).catch(debugError);
return;
}
const { viewport } = viewportState;
const mobile = viewport.isMobile || false;
const width = viewport.width;
const height = viewport.height;
const deviceScaleFactor = viewport.deviceScaleFactor ?? 1;
const screenOrientation = viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const hasTouch = viewport.hasTouch || false;
await Promise.all([
client
.send('Emulation.setDeviceMetricsOverride', {
mobile,
width,
height,
deviceScaleFactor,
screenOrientation,
})
.catch(err => {
if (err.message.includes('Target does not support metrics override')) {
debugError(err);
return;
}
throw err;
}),
client.send('Emulation.setTouchEmulationEnabled', {
enabled: hasTouch,
}),
]);
}, "#applyViewport") }, _private_applyViewport_decorators, { kind: "method", name: "#applyViewport", static: false, private: true, access: { has: obj => #applyViewport in obj, get: obj => obj.#applyViewport }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateIdleState_descriptor = { value: __setFunctionName(async function (client, idleStateState) {
if (!idleStateState.active) {
return;
}
if (idleStateState.overrides) {
await client.send('Emulation.setIdleOverride', {
isUserActive: idleStateState.overrides.isUserActive,
isScreenUnlocked: idleStateState.overrides.isScreenUnlocked,
});
}
else {
await client.send('Emulation.clearIdleOverride');
}
}, "#emulateIdleState") }, _private_emulateIdleState_decorators, { kind: "method", name: "#emulateIdleState", static: false, private: true, access: { has: obj => #emulateIdleState in obj, get: obj => obj.#emulateIdleState }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateTimezone_descriptor = { value: __setFunctionName(async function (client, timezoneState) {
if (!timezoneState.active) {
return;
}
try {
await client.send('Emulation.setTimezoneOverride', {
timezoneId: timezoneState.timezoneId || '',
});
}
catch (error) {
if (isErrorLike(error) && error.message.includes('Invalid timezone')) {
throw new Error(`Invalid timezone ID: ${timezoneState.timezoneId}`);
}
throw error;
}
}, "#emulateTimezone") }, _private_emulateTimezone_decorators, { kind: "method", name: "#emulateTimezone", static: false, private: true, access: { has: obj => #emulateTimezone in obj, get: obj => obj.#emulateTimezone }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateVisionDeficiency_descriptor = { value: __setFunctionName(async function (client, visionDeficiency) {
if (!visionDeficiency.active) {
return;
}
await client.send('Emulation.setEmulatedVisionDeficiency', {
type: visionDeficiency.visionDeficiency || 'none',
});
}, "#emulateVisionDeficiency") }, _private_emulateVisionDeficiency_decorators, { kind: "method", name: "#emulateVisionDeficiency", static: false, private: true, access: { has: obj => #emulateVisionDeficiency in obj, get: obj => obj.#emulateVisionDeficiency }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateCpuThrottling_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setCPUThrottlingRate', {
rate: state.factor ?? 1,
});
}, "#emulateCpuThrottling") }, _private_emulateCpuThrottling_decorators, { kind: "method", name: "#emulateCpuThrottling", static: false, private: true, access: { has: obj => #emulateCpuThrottling in obj, get: obj => obj.#emulateCpuThrottling }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateMediaFeatures_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setEmulatedMedia', {
features: state.mediaFeatures,
});
}, "#emulateMediaFeatures") }, _private_emulateMediaFeatures_decorators, { kind: "method", name: "#emulateMediaFeatures", static: false, private: true, access: { has: obj => #emulateMediaFeatures in obj, get: obj => obj.#emulateMediaFeatures }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateMediaType_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setEmulatedMedia', {
media: state.type || '',
});
}, "#emulateMediaType") }, _private_emulateMediaType_decorators, { kind: "method", name: "#emulateMediaType", static: false, private: true, access: { has: obj => #emulateMediaType in obj, get: obj => obj.#emulateMediaType }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_setGeolocation_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setGeolocationOverride', state.geoLocation
? {
longitude: state.geoLocation.longitude,
latitude: state.geoLocation.latitude,
accuracy: state.geoLocation.accuracy,
}
: undefined);
}, "#setGeolocation") }, _private_setGeolocation_decorators, { kind: "method", name: "#setGeolocation", static: false, private: true, access: { has: obj => #setGeolocation in obj, get: obj => obj.#setGeolocation }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_setDefaultBackgroundColor_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setDefaultBackgroundColorOverride', {
color: state.color,
});
}, "#setDefaultBackgroundColor") }, _private_setDefaultBackgroundColor_decorators, { kind: "method", name: "#setDefaultBackgroundColor", static: false, private: true, access: { has: obj => #setDefaultBackgroundColor in obj, get: obj => obj.#setDefaultBackgroundColor }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_setJavaScriptEnabled_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setScriptExecutionDisabled', {
value: !state.javaScriptEnabled,
});
}, "#setJavaScriptEnabled") }, _private_setJavaScriptEnabled_decorators, { kind: "method", name: "#setJavaScriptEnabled", static: false, private: true, access: { has: obj => #setJavaScriptEnabled in obj, get: obj => obj.#setJavaScriptEnabled }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, _private_emulateFocus_descriptor = { value: __setFunctionName(async function (client, state) {
if (!state.active) {
return;
}
await client.send('Emulation.setFocusEmulationEnabled', {
enabled: state.enabled,
});
}, "#emulateFocus") }, _private_emulateFocus_decorators, { kind: "method", name: "#emulateFocus", static: false, private: true, access: { has: obj => #emulateFocus in obj, get: obj => obj.#emulateFocus }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
#client = __runInitializers(this, _instanceExtraInitializers);
#emulatingMobile = false;
#hasTouch = false;
#states = [];
#viewportState = new EmulatedState({
active: false,
}, this, this.#applyViewport);
#idleOverridesState = new EmulatedState({
active: false,
}, this, this.#emulateIdleState);
#timezoneState = new EmulatedState({
active: false,
}, this, this.#emulateTimezone);
#visionDeficiencyState = new EmulatedState({
active: false,
}, this, this.#emulateVisionDeficiency);
#cpuThrottlingState = new EmulatedState({
active: false,
}, this, this.#emulateCpuThrottling);
#mediaFeaturesState = new EmulatedState({
active: false,
}, this, this.#emulateMediaFeatures);
#mediaTypeState = new EmulatedState({
active: false,
}, this, this.#emulateMediaType);
#geoLocationState = new EmulatedState({
active: false,
}, this, this.#setGeolocation);
#defaultBackgroundColorState = new EmulatedState({
active: false,
}, this, this.#setDefaultBackgroundColor);
#javascriptEnabledState = new EmulatedState({
javaScriptEnabled: true,
active: false,
}, this, this.#setJavaScriptEnabled);
#focusState = new EmulatedState({
enabled: true,
active: false,
}, this, this.#emulateFocus);
#secondaryClients = new Set();
constructor(client) {
this.#client = client;
}
updateClient(client) {
this.#client = client;
this.#secondaryClients.delete(client);
}
registerState(state) {
this.#states.push(state);
}
clients() {
return [this.#client, ...Array.from(this.#secondaryClients)];
}
async registerSpeculativeSession(client) {
this.#secondaryClients.add(client);
client.once(CDPSessionEvent.Disconnected, () => {
this.#secondaryClients.delete(client);
});
// We don't await here because we want to register all state changes before
// the target is unpaused.
void Promise.all(this.#states.map(s => {
return s.sync().catch(debugError);
}));
}
get javascriptEnabled() {
return this.#javascriptEnabledState.state.javaScriptEnabled;
}
async emulateViewport(viewport) {
const currentState = this.#viewportState.state;
if (!viewport && !currentState.active) {
return false;
}
await this.#viewportState.setState(viewport
? {
viewport,
active: true,
}
: {
active: false,
});
const mobile = viewport?.isMobile || false;
const hasTouch = viewport?.hasTouch || false;
const reloadNeeded = this.#emulatingMobile !== mobile || this.#hasTouch !== hasTouch;
this.#emulatingMobile = mobile;
this.#hasTouch = hasTouch;
return reloadNeeded;
}
get #applyViewport() { return _private_applyViewport_descriptor.value; }
async emulateIdleState(overrides) {
await this.#idleOverridesState.setState({
active: true,
overrides,
});
}
get #emulateIdleState() { return _private_emulateIdleState_descriptor.value; }
get #emulateTimezone() { return _private_emulateTimezone_descriptor.value; }
async emulateTimezone(timezoneId) {
await this.#timezoneState.setState({
timezoneId,
active: true,
});
}
get #emulateVisionDeficiency() { return _private_emulateVisionDeficiency_descriptor.value; }
async emulateVisionDeficiency(type) {
const visionDeficiencies = new Set([
'none',
'achromatopsia',
'blurredVision',
'deuteranopia',
'protanopia',
'reducedContrast',
'tritanopia',
]);
assert(!type || visionDeficiencies.has(type), `Unsupported vision deficiency: ${type}`);
await this.#visionDeficiencyState.setState({
active: true,
visionDeficiency: type,
});
}
get #emulateCpuThrottling() { return _private_emulateCpuThrottling_descriptor.value; }
async emulateCPUThrottling(factor) {
assert(factor === null || factor >= 1, 'Throttling rate should be greater or equal to 1');
await this.#cpuThrottlingState.setState({
active: true,
factor: factor ?? undefined,
});
}
get #emulateMediaFeatures() { return _private_emulateMediaFeatures_descriptor.value; }
async emulateMediaFeatures(features) {
if (Array.isArray(features)) {
for (const mediaFeature of features) {
const name = mediaFeature.name;
assert(/^(?:prefers-(?:color-scheme|reduced-motion)|color-gamut)$/.test(name), 'Unsupported media feature: ' + name);
}
}
await this.#mediaFeaturesState.setState({
active: true,
mediaFeatures: features,
});
}
get #emulateMediaType() { return _private_emulateMediaType_descriptor.value; }
async emulateMediaType(type) {
assert(type === 'screen' ||
type === 'print' ||
(type ?? undefined) === undefined, 'Unsupported media type: ' + type);
await this.#mediaTypeState.setState({
type,
active: true,
});
}
get #setGeolocation() { return _private_setGeolocation_descriptor.value; }
async setGeolocation(options) {
const { longitude, latitude, accuracy = 0 } = options;
if (longitude < -180 || longitude > 180) {
throw new Error(`Invalid longitude "${longitude}": precondition -180 <= LONGITUDE <= 180 failed.`);
}
if (latitude < -90 || latitude > 90) {
throw new Error(`Invalid latitude "${latitude}": precondition -90 <= LATITUDE <= 90 failed.`);
}
if (accuracy < 0) {
throw new Error(`Invalid accuracy "${accuracy}": precondition 0 <= ACCURACY failed.`);
}
await this.#geoLocationState.setState({
active: true,
geoLocation: {
longitude,
latitude,
accuracy,
},
});
}
get #setDefaultBackgroundColor() { return _private_setDefaultBackgroundColor_descriptor.value; }
/**
* Resets default white background
*/
async resetDefaultBackgroundColor() {
await this.#defaultBackgroundColorState.setState({
active: true,
color: undefined,
});
}
/**
* Hides default white background
*/
async setTransparentBackgroundColor() {
await this.#defaultBackgroundColorState.setState({
active: true,
color: { r: 0, g: 0, b: 0, a: 0 },
});
}
get #setJavaScriptEnabled() { return _private_setJavaScriptEnabled_descriptor.value; }
async setJavaScriptEnabled(enabled) {
await this.#javascriptEnabledState.setState({
active: true,
javaScriptEnabled: enabled,
});
}
get #emulateFocus() { return _private_emulateFocus_descriptor.value; }
async emulateFocus(enabled) {
await this.#focusState.setState({
active: true,
enabled,
});
}
};
})();
export { EmulationManager };
//# sourceMappingURL=EmulationManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,121 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import { type CDPSession } from '../api/CDPSession.js';
import type { JSHandle } from '../api/JSHandle.js';
import { EventEmitter } from '../common/EventEmitter.js';
import type { EvaluateFunc, HandleFor } from '../common/types.js';
import type { PuppeteerInjectedUtil } from '../injected/injected.js';
import { disposeSymbol } from '../util/disposable.js';
import type { IsolatedWorld } from './IsolatedWorld.js';
/**
* @internal
*/
export declare class ExecutionContext extends EventEmitter<{
/** Emitted when this execution context is disposed. */
disposed: undefined;
consoleapicalled: Protocol.Runtime.ConsoleAPICalledEvent;
/** Emitted when a binding that is not installed by the ExecutionContext is called. */
bindingcalled: Protocol.Runtime.BindingCalledEvent;
}> implements Disposable {
#private;
constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: IsolatedWorld);
get id(): number;
get puppeteerUtil(): Promise<JSHandle<PuppeteerInjectedUtil>>;
/**
* Evaluates the given function.
*
* @example
*
* ```ts
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function:
*
* ```ts
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* Handles can also be passed as `args`. They resolve to their referenced object:
*
* ```ts
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b,
* oneHandle,
* twoHandle,
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
*
* @param pageFunction - The function to evaluate.
* @param args - Additional arguments to pass into the function.
* @returns The result of evaluating the function. If the result is an object,
* a vanilla object containing the serializable properties of the result is
* returned.
*/
evaluate<Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>>(pageFunction: Func | string, ...args: Params): Promise<Awaited<ReturnType<Func>>>;
/**
* Evaluates the given function.
*
* Unlike {@link ExecutionContext.evaluate | evaluate}, this method returns a
* handle to the result of the function.
*
* This method may be better suited if the object cannot be serialized (e.g.
* `Map`) and requires further manipulation.
*
* @example
*
* ```ts
* const context = await page.mainFrame().executionContext();
* const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(
* () => Promise.resolve(self),
* );
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```ts
* const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* Handles can also be passed as `args`. They resolve to their referenced object:
*
* ```ts
* const bodyHandle: ElementHandle<HTMLBodyElement> =
* await context.evaluateHandle(() => {
* return document.body;
* });
* const stringHandle: JSHandle<string> = await context.evaluateHandle(
* body => body.innerHTML,
* body,
* );
* console.log(await stringHandle.jsonValue()); // prints body's innerHTML
* // Always dispose your garbage! :)
* await bodyHandle.dispose();
* await stringHandle.dispose();
* ```
*
* @param pageFunction - The function to evaluate.
* @param args - Additional arguments to pass into the function.
* @returns A {@link JSHandle | handle} to the result of evaluating the
* function. If the result is a `Node`, then this will return an
* {@link ElementHandle | element handle}.
*/
evaluateHandle<Params extends unknown[], Func extends EvaluateFunc<Params> = EvaluateFunc<Params>>(pageFunction: Func | string, ...args: Params): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
[disposeSymbol](): void;
}
//# sourceMappingURL=ExecutionContext.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExecutionContext.d.ts","sourceRoot":"","sources":["../../../src/cdp/ExecutionContext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAkB,KAAK,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAEtE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAGvD,OAAO,KAAK,EAAiB,YAAY,EAAE,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAShF,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAkB,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAMrE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAgCtD;;GAEG;AACH,qBAAa,gBACX,SAAQ,YAAY,CAAC;IACnB,uDAAuD;IACvD,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC;IACzD,sFAAsF;IACtF,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,kBAAkB,CAAC;CACpD,CACD,YAAW,UAAU;;gBAUnB,MAAM,EAAE,UAAU,EAClB,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,2BAA2B,EAC5D,KAAK,EAAE,aAAa;IA+GtB,IAAI,EAAE,IAAI,MAAM,CAEf;IAWD,IAAI,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAsB5D;IAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IACG,QAAQ,CACZ,MAAM,SAAS,OAAO,EAAE,EACxB,IAAI,SAAS,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,EAExD,YAAY,EAAE,IAAI,GAAG,MAAM,EAC3B,GAAG,IAAI,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAIrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACG,cAAc,CAClB,MAAM,SAAS,OAAO,EAAE,EACxB,IAAI,SAAS,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,EAExD,YAAY,EAAE,IAAI,GAAG,MAAM,EAC3B,GAAG,IAAI,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IA+KvC,CAAC,aAAa,CAAC,IAAI,IAAI;CAKjC"}

View File

@@ -0,0 +1,458 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (r = env.stack.pop()) {
try {
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { CDPSessionEvent } from '../api/CDPSession.js';
import { ARIAQueryHandler } from '../common/AriaQueryHandler.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { LazyArg } from '../common/LazyArg.js';
import { scriptInjector } from '../common/ScriptInjector.js';
import { PuppeteerURL, SOURCE_URL_REGEX, debugError, getSourcePuppeteerURLIfAvailable, getSourceUrlComment, isString, } from '../common/util.js';
import { AsyncIterableUtil } from '../util/AsyncIterableUtil.js';
import { DisposableStack, disposeSymbol } from '../util/disposable.js';
import { stringifyFunction } from '../util/Function.js';
import { Mutex } from '../util/Mutex.js';
import { Binding } from './Binding.js';
import { CdpElementHandle } from './ElementHandle.js';
import { CdpJSHandle } from './JSHandle.js';
import { addPageBinding, CDP_BINDING_PREFIX, createEvaluationError, valueFromPrimitiveRemoteObject, } from './utils.js';
const ariaQuerySelectorBinding = new Binding('__ariaQuerySelector', ARIAQueryHandler.queryOne, '');
const ariaQuerySelectorAllBinding = new Binding('__ariaQuerySelectorAll', (async (element, selector) => {
const results = ARIAQueryHandler.queryAll(element, selector);
return await element.realm.evaluateHandle((...elements) => {
return elements;
}, ...(await AsyncIterableUtil.collect(results)));
}), '');
/**
* @internal
*/
export class ExecutionContext extends EventEmitter {
#client;
#world;
#id;
#name;
#disposables = new DisposableStack();
constructor(client, contextPayload, world) {
super();
this.#client = client;
this.#world = world;
this.#id = contextPayload.id;
if (contextPayload.name) {
this.#name = contextPayload.name;
}
const clientEmitter = this.#disposables.use(new EventEmitter(this.#client));
clientEmitter.on('Runtime.bindingCalled', this.#onBindingCalled.bind(this));
clientEmitter.on('Runtime.executionContextDestroyed', async (event) => {
if (event.executionContextId === this.#id) {
this[disposeSymbol]();
}
});
clientEmitter.on('Runtime.executionContextsCleared', async () => {
this[disposeSymbol]();
});
clientEmitter.on('Runtime.consoleAPICalled', this.#onConsoleAPI.bind(this));
clientEmitter.on(CDPSessionEvent.Disconnected, () => {
this[disposeSymbol]();
});
}
// Contains mapping from functions that should be bound to Puppeteer functions.
#bindings = new Map();
// If multiple waitFor are set up asynchronously, we need to wait for the
// first one to set up the binding in the page before running the others.
#mutex = new Mutex();
async #addBinding(binding) {
const env_1 = { stack: [], error: void 0, hasError: false };
try {
if (this.#bindings.has(binding.name)) {
return;
}
const _ = __addDisposableResource(env_1, await this.#mutex.acquire(), false);
try {
await this.#client.send('Runtime.addBinding', this.#name
? {
name: CDP_BINDING_PREFIX + binding.name,
executionContextName: this.#name,
}
: {
name: CDP_BINDING_PREFIX + binding.name,
executionContextId: this.#id,
});
await this.evaluate(addPageBinding, 'internal', binding.name, CDP_BINDING_PREFIX);
this.#bindings.set(binding.name, binding);
}
catch (error) {
// We could have tried to evaluate in a context which was already
// destroyed. This happens, for example, if the page is navigated while
// we are trying to add the binding
if (error instanceof Error) {
// Destroyed context.
if (error.message.includes('Execution context was destroyed')) {
return;
}
// Missing context.
if (error.message.includes('Cannot find context with specified id')) {
return;
}
}
debugError(error);
}
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
}
}
async #onBindingCalled(event) {
if (event.executionContextId !== this.#id) {
return;
}
let payload;
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args, isTrivial } = payload;
if (type !== 'internal') {
this.emit('bindingcalled', event);
return;
}
if (!this.#bindings.has(name)) {
this.emit('bindingcalled', event);
return;
}
try {
const binding = this.#bindings.get(name);
await binding?.run(this, seq, args, isTrivial);
}
catch (err) {
debugError(err);
}
}
get id() {
return this.#id;
}
#onConsoleAPI(event) {
if (event.executionContextId !== this.#id) {
return;
}
this.emit('consoleapicalled', event);
}
#bindingsInstalled = false;
#puppeteerUtil;
get puppeteerUtil() {
let promise = Promise.resolve();
if (!this.#bindingsInstalled) {
promise = Promise.all([
this.#addBindingWithoutThrowing(ariaQuerySelectorBinding),
this.#addBindingWithoutThrowing(ariaQuerySelectorAllBinding),
]);
this.#bindingsInstalled = true;
}
scriptInjector.inject(script => {
if (this.#puppeteerUtil) {
void this.#puppeteerUtil.then(handle => {
void handle.dispose();
});
}
this.#puppeteerUtil = promise.then(() => {
return this.evaluateHandle(script);
});
}, !this.#puppeteerUtil);
return this.#puppeteerUtil;
}
async #addBindingWithoutThrowing(binding) {
try {
await this.#addBinding(binding);
}
catch (err) {
// If the binding cannot be added, the context is broken. We cannot
// recover so we ignore the error.
debugError(err);
}
}
/**
* Evaluates the given function.
*
* @example
*
* ```ts
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function:
*
* ```ts
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* Handles can also be passed as `args`. They resolve to their referenced object:
*
* ```ts
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b,
* oneHandle,
* twoHandle,
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
*
* @param pageFunction - The function to evaluate.
* @param args - Additional arguments to pass into the function.
* @returns The result of evaluating the function. If the result is an object,
* a vanilla object containing the serializable properties of the result is
* returned.
*/
async evaluate(pageFunction, ...args) {
return await this.#evaluate(true, pageFunction, ...args);
}
/**
* Evaluates the given function.
*
* Unlike {@link ExecutionContext.evaluate | evaluate}, this method returns a
* handle to the result of the function.
*
* This method may be better suited if the object cannot be serialized (e.g.
* `Map`) and requires further manipulation.
*
* @example
*
* ```ts
* const context = await page.mainFrame().executionContext();
* const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(
* () => Promise.resolve(self),
* );
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```ts
* const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* Handles can also be passed as `args`. They resolve to their referenced object:
*
* ```ts
* const bodyHandle: ElementHandle<HTMLBodyElement> =
* await context.evaluateHandle(() => {
* return document.body;
* });
* const stringHandle: JSHandle<string> = await context.evaluateHandle(
* body => body.innerHTML,
* body,
* );
* console.log(await stringHandle.jsonValue()); // prints body's innerHTML
* // Always dispose your garbage! :)
* await bodyHandle.dispose();
* await stringHandle.dispose();
* ```
*
* @param pageFunction - The function to evaluate.
* @param args - Additional arguments to pass into the function.
* @returns A {@link JSHandle | handle} to the result of evaluating the
* function. If the result is a `Node`, then this will return an
* {@link ElementHandle | element handle}.
*/
async evaluateHandle(pageFunction, ...args) {
return await this.#evaluate(false, pageFunction, ...args);
}
async #evaluate(returnByValue, pageFunction, ...args) {
const sourceUrlComment = getSourceUrlComment(getSourcePuppeteerURLIfAvailable(pageFunction)?.toString() ??
PuppeteerURL.INTERNAL_URL);
if (isString(pageFunction)) {
const contextId = this.#id;
const expression = pageFunction;
const expressionWithSourceUrl = SOURCE_URL_REGEX.test(expression)
? expression
: `${expression}\n${sourceUrlComment}\n`;
const { exceptionDetails, result: remoteObject } = await this.#client
.send('Runtime.evaluate', {
expression: expressionWithSourceUrl,
contextId,
returnByValue,
awaitPromise: true,
userGesture: true,
})
.catch(rewriteError);
if (exceptionDetails) {
throw createEvaluationError(exceptionDetails);
}
if (returnByValue) {
return valueFromPrimitiveRemoteObject(remoteObject);
}
return this.#world.createCdpHandle(remoteObject);
}
const functionDeclaration = stringifyFunction(pageFunction);
const functionDeclarationWithSourceUrl = SOURCE_URL_REGEX.test(functionDeclaration)
? functionDeclaration
: `${functionDeclaration}\n${sourceUrlComment}\n`;
let callFunctionOnPromise;
try {
callFunctionOnPromise = this.#client.send('Runtime.callFunctionOn', {
functionDeclaration: functionDeclarationWithSourceUrl,
executionContextId: this.#id,
// LazyArgs are used only internally and should not affect the order
// evaluate calls for the public APIs.
arguments: args.some(arg => {
return arg instanceof LazyArg;
})
? await Promise.all(args.map(arg => {
return convertArgumentAsync(this, arg);
}))
: args.map(arg => {
return convertArgument(this, arg);
}),
returnByValue,
awaitPromise: true,
userGesture: true,
});
}
catch (error) {
if (error instanceof TypeError &&
error.message.startsWith('Converting circular structure to JSON')) {
error.message += ' Recursive objects are not allowed.';
}
throw error;
}
const { exceptionDetails, result: remoteObject } = await callFunctionOnPromise.catch(rewriteError);
if (exceptionDetails) {
throw createEvaluationError(exceptionDetails);
}
if (returnByValue) {
return valueFromPrimitiveRemoteObject(remoteObject);
}
return this.#world.createCdpHandle(remoteObject);
async function convertArgumentAsync(context, arg) {
if (arg instanceof LazyArg) {
arg = await arg.get(context);
}
return convertArgument(context, arg);
}
function convertArgument(context, arg) {
if (typeof arg === 'bigint') {
return { unserializableValue: `${arg.toString()}n` };
}
if (Object.is(arg, -0)) {
return { unserializableValue: '-0' };
}
if (Object.is(arg, Infinity)) {
return { unserializableValue: 'Infinity' };
}
if (Object.is(arg, -Infinity)) {
return { unserializableValue: '-Infinity' };
}
if (Object.is(arg, NaN)) {
return { unserializableValue: 'NaN' };
}
const objectHandle = arg && (arg instanceof CdpJSHandle || arg instanceof CdpElementHandle)
? arg
: null;
if (objectHandle) {
if (objectHandle.realm !== context.#world) {
throw new Error('JSHandles can be evaluated only in the context they were created!');
}
if (objectHandle.disposed) {
throw new Error('JSHandle is disposed!');
}
if (objectHandle.remoteObject().unserializableValue) {
return {
unserializableValue: objectHandle.remoteObject().unserializableValue,
};
}
if (!objectHandle.remoteObject().objectId) {
return { value: objectHandle.remoteObject().value };
}
return { objectId: objectHandle.remoteObject().objectId };
}
return { value: arg };
}
}
[disposeSymbol]() {
this.#disposables.dispose();
this.emit('disposed', undefined);
super[disposeSymbol]();
}
}
const rewriteError = (error) => {
if (error.message.includes('Object reference chain is too long')) {
return { result: { type: 'undefined' } };
}
if (error.message.includes("Object couldn't be returned by value")) {
return { result: { type: 'undefined' } };
}
if (error.message.endsWith('Cannot find context with specified id') ||
error.message.endsWith('Inspected target navigated or closed')) {
throw new Error('Execution context was destroyed, most likely because of a navigation.');
}
throw error;
};
//# sourceMappingURL=ExecutionContext.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
/**
* @license
* Copyright 2026 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Page, WebWorker } from '../api/api.js';
import { Extension } from '../api/api.js';
import type { CdpBrowser } from './Browser.js';
export declare class CdpExtension extends Extension {
#private;
constructor(id: string, version: string, name: string, path: string, enabled: boolean, browser: CdpBrowser);
workers(): Promise<WebWorker[]>;
pages(): Promise<Page[]>;
triggerAction(page: Page): Promise<void>;
}
//# sourceMappingURL=Extension.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Extension.d.ts","sourceRoot":"","sources":["../../../src/cdp/Extension.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,IAAI,EAAU,SAAS,EAAC,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AAG7C,qBAAa,YAAa,SAAQ,SAAS;;gBAQvC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,UAAU;IAMf,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+B/B,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IA8BxB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAc/C"}

View File

@@ -0,0 +1,75 @@
import { Extension } from '../api/api.js';
import { debugError } from '../common/util.js';
import { isErrorLike } from '../util/ErrorLike.js';
import { isTargetClosedError } from './Connection.js';
export class CdpExtension extends Extension {
// needed to access the CDPSession to trigger an extension action.
#browser;
/*
* @internal
*/
constructor(id, version, name, path, enabled, browser) {
super(id, version, name, path, enabled);
this.#browser = browser;
}
async workers() {
const targets = this.#browser.targets();
const extensionWorkers = targets.filter((target) => {
const targetUrl = target.url();
return (target.type() === 'service_worker' &&
targetUrl.startsWith('chrome-extension://' + this.id));
});
const workers = [];
for (const target of extensionWorkers) {
try {
const worker = await target.worker();
if (worker) {
workers.push(worker);
}
}
catch (err) {
if (this.#canIgnoreError(err)) {
debugError(err);
continue;
}
throw err;
}
}
return workers;
}
async pages() {
const targets = this.#browser.targets();
const extensionPages = targets.filter((target) => {
const targetUrl = target.url();
return ((target.type() === 'page' || target.type() === 'background_page') &&
targetUrl.startsWith('chrome-extension://' + this.id));
});
const pages = await Promise.all(extensionPages.map(async (target) => {
try {
return await target.asPage();
}
catch (err) {
if (this.#canIgnoreError(err)) {
debugError(err);
return null;
}
throw err;
}
}));
return pages.filter((page) => {
return page !== null;
});
}
async triggerAction(page) {
await this.#browser._connection.send('Extensions.triggerAction', {
id: this.id,
targetId: page._tabId,
});
}
#canIgnoreError(error) {
return (isErrorLike(error) &&
(isTargetClosedError(error) ||
error.message.includes('No target with given id found')));
}
}
//# sourceMappingURL=Extension.js.map

View File

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

View File

@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2024 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { ConnectionTransport } from '../common/ConnectionTransport.js';
/**
* Experimental ExtensionTransport allows establishing a connection via
* chrome.debugger API if Puppeteer runs in an extension. Since Chrome
* DevTools Protocol is restricted for extensions, the transport
* implements missing commands and events.
*
* @experimental
* @public
*/
export declare class ExtensionTransport implements ConnectionTransport {
#private;
static connectTab(tabId: number): Promise<ExtensionTransport>;
onmessage?: (message: string) => void;
onclose?: () => void;
/**
* @internal
*/
constructor(tabId: number);
send(message: string): void;
close(): void;
}
//# sourceMappingURL=ExtensionTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExtensionTransport.d.ts","sourceRoot":"","sources":["../../../src/cdp/ExtensionTransport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,kCAAkC,CAAC;AAoB1E;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;;WAC/C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKnE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAIrB;;OAEG;gBACS,KAAK,EAAE,MAAM;IA4BzB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAoH3B,KAAK,IAAI,IAAI;CAId"}

View File

@@ -0,0 +1,175 @@
const tabTargetInfo = {
targetId: 'tabTargetId',
type: 'tab',
title: 'tab',
url: 'about:blank',
attached: false,
canAccessOpener: false,
};
const pageTargetInfo = {
targetId: 'pageTargetId',
type: 'page',
title: 'page',
url: 'about:blank',
attached: false,
canAccessOpener: false,
};
/**
* Experimental ExtensionTransport allows establishing a connection via
* chrome.debugger API if Puppeteer runs in an extension. Since Chrome
* DevTools Protocol is restricted for extensions, the transport
* implements missing commands and events.
*
* @experimental
* @public
*/
export class ExtensionTransport {
static async connectTab(tabId) {
await chrome.debugger.attach({ tabId }, '1.3');
return new ExtensionTransport(tabId);
}
onmessage;
onclose;
#tabId;
/**
* @internal
*/
constructor(tabId) {
this.#tabId = tabId;
chrome.debugger.onEvent.addListener(this.#debuggerEventHandler);
}
#debuggerEventHandler = (source, method, params) => {
if (source.tabId !== this.#tabId) {
return;
}
this.#dispatchResponse({
// @ts-expect-error sessionId is not in stable yet.
sessionId: source.sessionId ?? 'pageTargetSessionId',
method: method,
params: params,
});
};
#dispatchResponse(message) {
// Dispatch in a new task like other transports.
setTimeout(() => {
this.onmessage?.(JSON.stringify(message));
}, 0);
}
send(message) {
const parsed = JSON.parse(message);
switch (parsed.method) {
case 'Browser.getVersion': {
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId,
method: parsed.method,
result: {
protocolVersion: '1.3',
product: 'chrome',
revision: 'unknown',
userAgent: 'chrome',
jsVersion: 'unknown',
},
});
return;
}
case 'Target.getBrowserContexts': {
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId,
method: parsed.method,
result: {
browserContextIds: [],
},
});
return;
}
case 'Target.setDiscoverTargets': {
this.#dispatchResponse({
method: 'Target.targetCreated',
params: {
targetInfo: tabTargetInfo,
},
});
this.#dispatchResponse({
method: 'Target.targetCreated',
params: {
targetInfo: pageTargetInfo,
},
});
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId,
method: parsed.method,
result: {},
});
return;
}
case 'Target.setAutoAttach': {
if (parsed.sessionId === 'tabTargetSessionId') {
this.#dispatchResponse({
method: 'Target.attachedToTarget',
sessionId: 'tabTargetSessionId',
params: {
targetInfo: pageTargetInfo,
sessionId: 'pageTargetSessionId',
},
});
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId,
method: parsed.method,
result: {},
});
return;
}
else if (!parsed.sessionId) {
this.#dispatchResponse({
method: 'Target.attachedToTarget',
params: {
targetInfo: tabTargetInfo,
sessionId: 'tabTargetSessionId',
},
});
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId,
method: parsed.method,
result: {},
});
return;
}
}
}
if (parsed.sessionId === 'pageTargetSessionId') {
delete parsed.sessionId;
}
chrome.debugger
.sendCommand({ tabId: this.#tabId, sessionId: parsed.sessionId }, parsed.method, parsed.params)
.then(response => {
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId ?? 'pageTargetSessionId',
method: parsed.method,
result: response,
});
})
.catch(err => {
this.#dispatchResponse({
id: parsed.id,
sessionId: parsed.sessionId ?? 'pageTargetSessionId',
method: parsed.method,
error: {
code: err?.code,
data: err?.data,
message: err?.message ?? 'CDP error had no message',
},
});
});
}
close() {
chrome.debugger.onEvent.removeListener(this.#debuggerEventHandler);
void chrome.debugger.detach({ tabId: this.#tabId });
}
}
//# sourceMappingURL=ExtensionTransport.js.map

View File

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

View File

@@ -0,0 +1,91 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import type { DeviceRequestPrompt } from '../api/DeviceRequestPrompt.js';
import type { ElementHandle } from '../api/ElementHandle.js';
import type { SetContentWaitForOptions, WaitForOptions } from '../api/Frame.js';
import { Frame } from '../api/Frame.js';
import type { HTTPResponse } from '../api/HTTPResponse.js';
import type { WaitTimeoutOptions } from '../api/Page.js';
import type { Realm } from '../puppeteer-core.js';
import { disposeSymbol } from '../util/disposable.js';
import { Accessibility } from './Accessibility.js';
import type { Binding } from './Binding.js';
import type { CdpPreloadScript } from './CdpPreloadScript.js';
import type { FrameManager } from './FrameManager.js';
import type { IsolatedWorldChart } from './IsolatedWorld.js';
import { IsolatedWorld } from './IsolatedWorld.js';
import { type PuppeteerLifeCycleEvent } from './LifecycleWatcher.js';
import type { CdpPage } from './Page.js';
/**
* @internal
*/
export declare class CdpFrame extends Frame {
#private;
_frameManager: FrameManager;
_loaderId: string;
_lifecycleEvents: Set<string>;
_id: string;
_parentId?: string;
accessibility: Accessibility;
worlds: IsolatedWorldChart;
extensionWorlds: Record<string, IsolatedWorld>;
constructor(frameManager: FrameManager, frameId: string, parentFrameId: string | undefined, client: CDPSession);
/**
* @internal
*/
registerWorldListeners(world: IsolatedWorld): void;
/**
* This is used internally in DevTools.
*
* @internal
*/
_client(): CDPSession;
/**
* Updates the frame ID with the new ID. This happens when the main frame is
* replaced by a different frame.
*/
updateId(id: string): void;
updateClient(client: CDPSession): void;
page(): CdpPage;
goto(url: string, options?: {
referer?: string;
referrerPolicy?: string;
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
waitForNavigation(options?: WaitForOptions): Promise<HTTPResponse | null>;
get client(): CDPSession;
mainRealm(): IsolatedWorld;
isolatedRealm(): IsolatedWorld;
setContent(html: string, options?: SetContentWaitForOptions): Promise<void>;
url(): string;
parentFrame(): CdpFrame | null;
childFrames(): CdpFrame[];
addPreloadScript(preloadScript: CdpPreloadScript): Promise<void>;
addExposedFunctionBinding(binding: Binding): Promise<void>;
removeExposedFunctionBinding(binding: Binding): Promise<void>;
waitForDevicePrompt(options?: WaitTimeoutOptions): Promise<DeviceRequestPrompt>;
_navigated(framePayload: Protocol.Page.Frame): void;
_navigatedWithinDocument(url: string): void;
_onLifecycleEvent(loaderId: string, name: string): void;
_onLoadingStopped(): void;
_onLoadingStarted(): void;
get detached(): boolean;
[disposeSymbol](): void;
exposeFunction(): never;
frameElement(): Promise<ElementHandle<HTMLIFrameElement> | null>;
/**
* @public
*/
extensionRealms(): Realm[];
}
/**
* @internal
*/
export declare function referrerPolicyToProtocol(referrerPolicy: string): Protocol.Page.ReferrerPolicy;
//# sourceMappingURL=Frame.d.ts.map

View File

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

373
node_modules/puppeteer-core/lib/puppeteer/cdp/Frame.js generated vendored Normal file
View File

@@ -0,0 +1,373 @@
/**
* @license
* Copyright 2017 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;
};
import { Frame, FrameEvent, throwIfDetached } from '../api/Frame.js';
import { UnsupportedOperation } from '../common/Errors.js';
import { debugError } from '../common/util.js';
import { Deferred } from '../util/Deferred.js';
import { disposeSymbol } from '../util/disposable.js';
import { isErrorLike } from '../util/ErrorLike.js';
import { Accessibility } from './Accessibility.js';
import { FrameManagerEvent } from './FrameManagerEvents.js';
import { IsolatedWorld } from './IsolatedWorld.js';
import { MAIN_WORLD, PUPPETEER_WORLD } from './IsolatedWorlds.js';
import { LifecycleWatcher, } from './LifecycleWatcher.js';
import { CDP_BINDING_PREFIX } from './utils.js';
/**
* @internal
*/
let CdpFrame = (() => {
let _classSuper = Frame;
let _instanceExtraInitializers = [];
let _goto_decorators;
let _waitForNavigation_decorators;
let _setContent_decorators;
let _addPreloadScript_decorators;
let _addExposedFunctionBinding_decorators;
let _removeExposedFunctionBinding_decorators;
let _waitForDevicePrompt_decorators;
return class CdpFrame extends _classSuper {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
__esDecorate(this, null, _goto_decorators, { kind: "method", name: "goto", static: false, private: false, access: { has: obj => "goto" in obj, get: obj => obj.goto }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _waitForNavigation_decorators, { kind: "method", name: "waitForNavigation", static: false, private: false, access: { has: obj => "waitForNavigation" in obj, get: obj => obj.waitForNavigation }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _setContent_decorators, { kind: "method", name: "setContent", static: false, private: false, access: { has: obj => "setContent" in obj, get: obj => obj.setContent }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _addPreloadScript_decorators, { kind: "method", name: "addPreloadScript", static: false, private: false, access: { has: obj => "addPreloadScript" in obj, get: obj => obj.addPreloadScript }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _addExposedFunctionBinding_decorators, { kind: "method", name: "addExposedFunctionBinding", static: false, private: false, access: { has: obj => "addExposedFunctionBinding" in obj, get: obj => obj.addExposedFunctionBinding }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _removeExposedFunctionBinding_decorators, { kind: "method", name: "removeExposedFunctionBinding", static: false, private: false, access: { has: obj => "removeExposedFunctionBinding" in obj, get: obj => obj.removeExposedFunctionBinding }, metadata: _metadata }, null, _instanceExtraInitializers);
__esDecorate(this, null, _waitForDevicePrompt_decorators, { kind: "method", name: "waitForDevicePrompt", static: false, private: false, access: { has: obj => "waitForDevicePrompt" in obj, get: obj => obj.waitForDevicePrompt }, metadata: _metadata }, null, _instanceExtraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
#url = (__runInitializers(this, _instanceExtraInitializers), '');
#detached = false;
#client;
_frameManager;
_loaderId = '';
_lifecycleEvents = new Set();
_id;
_parentId;
accessibility;
worlds;
extensionWorlds = {};
constructor(frameManager, frameId, parentFrameId, client) {
super();
this._frameManager = frameManager;
this.#url = '';
this._id = frameId;
this._parentId = parentFrameId;
this.#detached = false;
this.#client = client;
this._loaderId = '';
this.worlds = {
[MAIN_WORLD]: new IsolatedWorld(this, this._frameManager.timeoutSettings, MAIN_WORLD),
[PUPPETEER_WORLD]: new IsolatedWorld(this, this._frameManager.timeoutSettings, PUPPETEER_WORLD),
};
this.accessibility = new Accessibility(this.worlds[MAIN_WORLD], frameId);
this.on(FrameEvent.FrameSwappedByActivation, () => {
// Emulate loading process for swapped frames.
this._onLoadingStarted();
this._onLoadingStopped();
});
this.registerWorldListeners(this.worlds[MAIN_WORLD]);
}
/**
* @internal
*/
registerWorldListeners(world) {
world.emitter.on('consoleapicalled', event => {
this._frameManager.emit(FrameManagerEvent.ConsoleApiCalled, [
world,
event,
]);
});
world.emitter.on('bindingcalled', event => {
this._frameManager.emit(FrameManagerEvent.BindingCalled, [world, event]);
});
}
/**
* This is used internally in DevTools.
*
* @internal
*/
_client() {
return this.#client;
}
/**
* Updates the frame ID with the new ID. This happens when the main frame is
* replaced by a different frame.
*/
updateId(id) {
this._id = id;
}
updateClient(client) {
this.#client = client;
}
page() {
return this._frameManager.page();
}
async goto(url, options = {}) {
if (!this.page()._isUrlAllowed(url)) {
throw new Error(`Navigation to ${url} is blocked by blocklist/allowlist rules`);
}
const { referer = this._frameManager.networkManager.extraHTTPHeaders()['referer'], referrerPolicy = this._frameManager.networkManager.extraHTTPHeaders()['referer-policy'], waitUntil = ['load'], timeout = this._frameManager.timeoutSettings.navigationTimeout(), } = options;
let ensureNewDocumentNavigation = false;
const watcher = new LifecycleWatcher(this._frameManager.networkManager, this, waitUntil, timeout);
let error = await Deferred.race([
navigate(this.#client, url, referer, referrerPolicy ? referrerPolicyToProtocol(referrerPolicy) : undefined, this._id),
watcher.terminationPromise(),
]);
if (!error) {
error = await Deferred.race([
watcher.terminationPromise(),
ensureNewDocumentNavigation
? watcher.newDocumentNavigationPromise()
: watcher.sameDocumentNavigationPromise(),
]);
}
try {
if (error) {
throw error;
}
return await watcher.navigationResponse();
}
finally {
watcher.dispose();
}
async function navigate(client, url, referrer, referrerPolicy, frameId) {
try {
const response = await client.send('Page.navigate', {
url,
referrer,
frameId,
referrerPolicy,
});
ensureNewDocumentNavigation = !!response.loaderId;
if (response.errorText === 'net::ERR_HTTP_RESPONSE_CODE_FAILURE') {
return null;
}
return response.errorText
? new Error(`${response.errorText} at ${url}`)
: null;
}
catch (error) {
if (isErrorLike(error)) {
return error;
}
throw error;
}
}
}
async waitForNavigation(options = {}) {
const { waitUntil = ['load'], timeout = this._frameManager.timeoutSettings.navigationTimeout(), signal, } = options;
const watcher = new LifecycleWatcher(this._frameManager.networkManager, this, waitUntil, timeout, signal);
const error = await Deferred.race([
watcher.terminationPromise(),
...(options.ignoreSameDocumentNavigation
? []
: [watcher.sameDocumentNavigationPromise()]),
watcher.newDocumentNavigationPromise(),
]);
try {
if (error) {
throw error;
}
const result = await Deferred.race([watcher.terminationPromise(), watcher.navigationResponse()]);
if (result instanceof Error) {
throw error;
}
return result || null;
}
finally {
watcher.dispose();
}
}
get client() {
return this.#client;
}
mainRealm() {
return this.worlds[MAIN_WORLD];
}
isolatedRealm() {
return this.worlds[PUPPETEER_WORLD];
}
async setContent(html, options = {}) {
const { waitUntil = ['load'], timeout = this._frameManager.timeoutSettings.navigationTimeout(), } = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.setFrameContent(html);
const watcher = new LifecycleWatcher(this._frameManager.networkManager, this, waitUntil, timeout);
const error = await Deferred.race([
watcher.terminationPromise(),
watcher.lifecyclePromise(),
]);
watcher.dispose();
if (error) {
throw error;
}
}
url() {
return this.#url;
}
parentFrame() {
return this._frameManager._frameTree.parentFrame(this._id) || null;
}
childFrames() {
return this._frameManager._frameTree.childFrames(this._id);
}
#deviceRequestPromptManager() {
return this._frameManager._deviceRequestPromptManager(this.#client);
}
async addPreloadScript(preloadScript) {
const parentFrame = this.parentFrame();
if (parentFrame && this.#client === parentFrame.client) {
return;
}
if (preloadScript.getIdForFrame(this)) {
return;
}
const { identifier } = await this.#client.send('Page.addScriptToEvaluateOnNewDocument', {
source: preloadScript.source,
});
preloadScript.setIdForFrame(this, identifier);
}
async addExposedFunctionBinding(binding) {
// If a frame has not started loading, it might never start. Rely on
// addScriptToEvaluateOnNewDocument in that case.
if (this !== this._frameManager.mainFrame() && !this._hasStartedLoading) {
return;
}
await Promise.all([
this.#client.send('Runtime.addBinding', {
name: CDP_BINDING_PREFIX + binding.name,
}),
this.evaluate(binding.initSource).catch(debugError),
]);
}
async removeExposedFunctionBinding(binding) {
// If a frame has not started loading, it might never start. Rely on
// addScriptToEvaluateOnNewDocument in that case.
if (this !== this._frameManager.mainFrame() && !this._hasStartedLoading) {
return;
}
await Promise.all([
this.#client.send('Runtime.removeBinding', {
name: CDP_BINDING_PREFIX + binding.name,
}),
this.evaluate(name => {
// Removes the dangling Puppeteer binding wrapper.
// @ts-expect-error: In a different context.
globalThis[name] = undefined;
}, binding.name).catch(debugError),
]);
}
async waitForDevicePrompt(options = {}) {
return await this.#deviceRequestPromptManager().waitForDevicePrompt(options);
}
_navigated(framePayload) {
this._name = framePayload.name;
this.#url = `${framePayload.url}${framePayload.urlFragment || ''}`;
}
_navigatedWithinDocument(url) {
this.#url = url;
}
_onLifecycleEvent(loaderId, name) {
if (name === 'init') {
this._loaderId = loaderId;
this._lifecycleEvents.clear();
}
this._lifecycleEvents.add(name);
}
_onLoadingStopped() {
this._lifecycleEvents.add('DOMContentLoaded');
this._lifecycleEvents.add('load');
}
_onLoadingStarted() {
this._hasStartedLoading = true;
}
get detached() {
return this.#detached;
}
[(_goto_decorators = [throwIfDetached], _waitForNavigation_decorators = [throwIfDetached], _setContent_decorators = [throwIfDetached], _addPreloadScript_decorators = [throwIfDetached], _addExposedFunctionBinding_decorators = [throwIfDetached], _removeExposedFunctionBinding_decorators = [throwIfDetached], _waitForDevicePrompt_decorators = [throwIfDetached], disposeSymbol)]() {
if (this.#detached) {
return;
}
this.#detached = true;
this.worlds[MAIN_WORLD][disposeSymbol]();
this.worlds[PUPPETEER_WORLD][disposeSymbol]();
for (const extensionWorld of Object.values(this.extensionWorlds)) {
extensionWorld[disposeSymbol]();
}
super[disposeSymbol]();
}
exposeFunction() {
throw new UnsupportedOperation();
}
async frameElement() {
const parent = this.parentFrame();
if (!parent) {
return null;
}
const { backendNodeId } = await parent.client.send('DOM.getFrameOwner', {
frameId: this._id,
});
return (await parent
.mainRealm()
.adoptBackendNode(backendNodeId));
}
/**
* @public
*/
extensionRealms() {
return Object.values(this.extensionWorlds);
}
};
})();
export { CdpFrame };
/**
* @internal
*/
export function referrerPolicyToProtocol(referrerPolicy) {
// See
// https://chromedevtools.github.io/devtools-protocol/tot/Page/#type-ReferrerPolicy
// We need to conver from Web-facing phase to CDP's camelCase.
return referrerPolicy.replaceAll(/-./g, match => {
return match[1].toUpperCase();
});
}
//# sourceMappingURL=Frame.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,51 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { type CDPSession } from '../api/CDPSession.js';
import { type NewDocumentScriptEvaluation } from '../api/Page.js';
import { EventEmitter } from '../common/EventEmitter.js';
import type { TimeoutSettings } from '../common/TimeoutSettings.js';
import type { Binding } from './Binding.js';
import type { CdpCDPSession } from './CdpSession.js';
import { CdpDeviceRequestPromptManager } from './DeviceRequestPrompt.js';
import { CdpFrame } from './Frame.js';
import type { FrameManagerEvents } from './FrameManagerEvents.js';
import { FrameTree } from './FrameTree.js';
import { NetworkManager } from './NetworkManager.js';
import type { CdpPage } from './Page.js';
import type { CdpTarget } from './Target.js';
/**
* A frame manager manages the frames for a given {@link Page | page}.
*
* @internal
*/
export declare class FrameManager extends EventEmitter<FrameManagerEvents> {
#private;
_frameTree: FrameTree<CdpFrame>;
get timeoutSettings(): TimeoutSettings;
get networkManager(): NetworkManager;
get client(): CdpCDPSession;
constructor(client: CdpCDPSession, page: CdpPage, timeoutSettings: TimeoutSettings);
/**
* When the main frame is replaced by another main frame,
* we maintain the main frame object identity while updating
* its frame tree and ID.
*/
swapFrameTree(client: CdpCDPSession): Promise<void>;
registerSpeculativeSession(client: CdpCDPSession): Promise<void>;
private setupEventListeners;
initialize(client: CDPSession, frame?: CdpFrame | null): Promise<void>;
page(): CdpPage;
mainFrame(): CdpFrame;
frames(): CdpFrame[];
frame(frameId: string): CdpFrame | null;
addExposedFunctionBinding(binding: Binding): Promise<void>;
removeExposedFunctionBinding(binding: Binding): Promise<void>;
evaluateOnNewDocument(source: string): Promise<NewDocumentScriptEvaluation>;
removeScriptToEvaluateOnNewDocument(identifier: string): Promise<void>;
onAttachedToTarget(target: CdpTarget): void;
_deviceRequestPromptManager(client: CDPSession): CdpDeviceRequestPromptManager;
}
//# sourceMappingURL=FrameManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FrameManager.d.ts","sourceRoot":"","sources":["../../../src/cdp/FrameManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAC,KAAK,UAAU,EAAkB,MAAM,sBAAsB,CAAC;AAEtE,OAAO,EAAY,KAAK,2BAA2B,EAAC,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAOlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAC,6BAA6B,EAAC,MAAM,0BAA0B,CAAC;AAEvE,OAAO,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAGzC,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAI3C;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;;IAShE,UAAU,sBAA6B;IAgBvC,IAAI,eAAe,IAAI,eAAe,CAErC;IAED,IAAI,cAAc,IAAI,cAAc,CAEnC;IAED,IAAI,MAAM,IAAI,aAAa,CAE1B;gBAGC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,OAAO,EACb,eAAe,EAAE,eAAe;IAmDlC;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnD,0BAA0B,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,OAAO,CAAC,mBAAmB;IA6CrB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC5E,IAAI,IAAI,OAAO;IAIf,SAAS,IAAI,QAAQ;IAMrB,MAAM,IAAI,QAAQ,EAAE;IAIpB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAIjC,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7D,qBAAqB,CACzB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,2BAA2B,CAAC;IAwBjC,mCAAmC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B5E,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAa3C,2BAA2B,CACzB,MAAM,EAAE,UAAU,GACjB,6BAA6B;CA+QjC"}

View File

@@ -0,0 +1,495 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { CDPSessionEvent } from '../api/CDPSession.js';
import { FrameEvent } from '../api/Frame.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { debugError, PuppeteerURL, UTILITY_WORLD_NAME } from '../common/util.js';
import { assert } from '../util/assert.js';
import { Deferred } from '../util/Deferred.js';
import { disposeSymbol } from '../util/disposable.js';
import { isErrorLike } from '../util/ErrorLike.js';
import { CdpIssue } from './CdpIssue.js';
import { CdpPreloadScript } from './CdpPreloadScript.js';
import { isTargetClosedError } from './Connection.js';
import { CdpDeviceRequestPromptManager } from './DeviceRequestPrompt.js';
import { ExecutionContext } from './ExecutionContext.js';
import { CdpFrame } from './Frame.js';
import { FrameManagerEvent } from './FrameManagerEvents.js';
import { FrameTree } from './FrameTree.js';
import { IsolatedWorld } from './IsolatedWorld.js';
import { MAIN_WORLD, PUPPETEER_WORLD } from './IsolatedWorlds.js';
import { NetworkManager } from './NetworkManager.js';
const TIME_FOR_WAITING_FOR_SWAP = 100; // ms.
const CHROME_EXTENSION_PREFIX = 'chrome-extension://';
/**
* A frame manager manages the frames for a given {@link Page | page}.
*
* @internal
*/
export class FrameManager extends EventEmitter {
#page;
#networkManager;
#timeoutSettings;
#isolatedWorlds = new Set();
#client;
#scriptsToEvaluateOnNewDocument = new Map();
#bindings = new Set();
_frameTree = new FrameTree();
/**
* Set of frame IDs stored to indicate if a frame has received a
* frameNavigated event so that frame tree responses could be ignored as the
* frameNavigated event usually contains the latest information.
*/
#frameNavigatedReceived = new Set();
#deviceRequestPromptManagerMap = new WeakMap();
#frameTreeHandled;
get timeoutSettings() {
return this.#timeoutSettings;
}
get networkManager() {
return this.#networkManager;
}
get client() {
return this.#client;
}
constructor(client, page, timeoutSettings) {
super();
this.#client = client;
this.#page = page;
this.#networkManager = new NetworkManager(this, page.browser().isNetworkEnabled());
this.#timeoutSettings = timeoutSettings;
this.setupEventListeners(this.#client);
client.once(CDPSessionEvent.Disconnected, () => {
this.#onClientDisconnect().catch(debugError);
});
}
/**
* Called when the frame's client is disconnected. We don't know if the
* disconnect means that the frame is removed or if it will be replaced by a
* new frame. Therefore, we wait for a swap event.
*/
async #onClientDisconnect() {
const mainFrame = this._frameTree.getMainFrame();
if (!mainFrame) {
return;
}
if (!this.#page.browser().connected) {
// If the browser is not connected we know
// that activation will not happen
this.#removeFramesRecursively(mainFrame);
return;
}
for (const child of mainFrame.childFrames()) {
this.#removeFramesRecursively(child);
}
const swapped = Deferred.create({
timeout: TIME_FOR_WAITING_FOR_SWAP,
message: 'Frame was not swapped',
});
mainFrame.once(FrameEvent.FrameSwappedByActivation, () => {
swapped.resolve();
});
try {
await swapped.valueOrThrow();
}
catch {
this.#removeFramesRecursively(mainFrame);
}
}
/**
* When the main frame is replaced by another main frame,
* we maintain the main frame object identity while updating
* its frame tree and ID.
*/
async swapFrameTree(client) {
this.#client = client;
const frame = this._frameTree.getMainFrame();
if (frame) {
this.#frameNavigatedReceived.add(this.#client.target()._targetId);
this._frameTree.removeFrame(frame);
frame.updateId(this.#client.target()._targetId);
this._frameTree.addFrame(frame);
frame.updateClient(client);
}
this.setupEventListeners(client);
client.once(CDPSessionEvent.Disconnected, () => {
this.#onClientDisconnect().catch(debugError);
});
await this.initialize(client, frame);
await this.#networkManager.addClient(client);
if (frame) {
frame.emit(FrameEvent.FrameSwappedByActivation, undefined);
}
}
async registerSpeculativeSession(client) {
await this.#networkManager.addClient(client);
}
setupEventListeners(session) {
session.on('Page.frameAttached', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onFrameAttached(session, event.frameId, event.parentFrameId);
});
session.on('Page.frameNavigated', async (event) => {
this.#frameNavigatedReceived.add(event.frame.id);
await this.#frameTreeHandled?.valueOrThrow();
void this.#onFrameNavigated(event.frame, event.type);
});
session.on('Page.navigatedWithinDocument', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onFrameNavigatedWithinDocument(event.frameId, event.url);
});
session.on('Page.frameDetached', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onFrameDetached(event.frameId, event.reason);
});
session.on('Page.frameStartedLoading', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onFrameStartedLoading(event.frameId);
});
session.on('Page.frameStoppedLoading', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onFrameStoppedLoading(event.frameId);
});
session.on('Runtime.executionContextCreated', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onExecutionContextCreated(event.context, session);
});
session.on('Page.lifecycleEvent', async (event) => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onLifecycleEvent(event);
});
session.on('Audits.issueAdded', event => {
this.#page.emit("issue" /* PageEvent.Issue */, new CdpIssue(event.issue));
});
}
async initialize(client, frame) {
try {
this.#frameTreeHandled?.resolve();
this.#frameTreeHandled = Deferred.create();
// We need to schedule all these commands while the target is paused,
// therefore, it needs to happen synchronously. At the same time we
// should not start processing execution context and frame events before
// we received the initial information about the frame tree.
await Promise.all([
this.#networkManager.addClient(client),
client.send('Page.enable'),
client.send('Page.getFrameTree').then(({ frameTree }) => {
this.#handleFrameTree(client, frameTree);
this.#frameTreeHandled?.resolve();
}),
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
client.send('Runtime.enable').then(() => {
return this.#createIsolatedWorld(client, UTILITY_WORLD_NAME);
}),
...(frame
? Array.from(this.#scriptsToEvaluateOnNewDocument.values())
: []).map(script => {
return frame?.addPreloadScript(script);
}),
...(frame ? Array.from(this.#bindings.values()) : []).map(binding => {
return frame?.addExposedFunctionBinding(binding);
}),
this.#page.browser().isIssuesEnabled() && client.send('Audits.enable'),
]);
}
catch (error) {
this.#frameTreeHandled?.resolve();
// The target might have been closed before the initialization finished.
if (isErrorLike(error) && isTargetClosedError(error)) {
return;
}
throw error;
}
}
page() {
return this.#page;
}
mainFrame() {
const mainFrame = this._frameTree.getMainFrame();
assert(mainFrame, 'Requesting main frame too early!');
return mainFrame;
}
frames() {
return Array.from(this._frameTree.frames());
}
frame(frameId) {
return this._frameTree.getById(frameId) || null;
}
async addExposedFunctionBinding(binding) {
this.#bindings.add(binding);
await Promise.all(this.frames().map(async (frame) => {
return await frame.addExposedFunctionBinding(binding);
}));
}
async removeExposedFunctionBinding(binding) {
this.#bindings.delete(binding);
await Promise.all(this.frames().map(async (frame) => {
return await frame.removeExposedFunctionBinding(binding);
}));
}
async evaluateOnNewDocument(source) {
const { identifier } = await this.mainFrame()
._client()
.send('Page.addScriptToEvaluateOnNewDocument', {
source,
});
const preloadScript = new CdpPreloadScript(this.mainFrame(), identifier, source);
this.#scriptsToEvaluateOnNewDocument.set(identifier, preloadScript);
await Promise.all(this.frames().map(async (frame) => {
return await frame.addPreloadScript(preloadScript);
}));
return { identifier };
}
async removeScriptToEvaluateOnNewDocument(identifier) {
const preloadScript = this.#scriptsToEvaluateOnNewDocument.get(identifier);
if (!preloadScript) {
throw new Error(`Script to evaluate on new document with id ${identifier} not found`);
}
this.#scriptsToEvaluateOnNewDocument.delete(identifier);
await Promise.all(this.frames().map(frame => {
const identifier = preloadScript.getIdForFrame(frame);
if (!identifier) {
return;
}
return frame
._client()
.send('Page.removeScriptToEvaluateOnNewDocument', {
identifier,
})
.catch(debugError);
}));
}
onAttachedToTarget(target) {
if (target._getTargetInfo().type !== 'iframe') {
return;
}
const frame = this.frame(target._getTargetInfo().targetId);
if (frame) {
frame.updateClient(target._session());
}
this.setupEventListeners(target._session());
void this.initialize(target._session(), frame).catch(debugError);
}
_deviceRequestPromptManager(client) {
let manager = this.#deviceRequestPromptManagerMap.get(client);
if (manager === undefined) {
manager = new CdpDeviceRequestPromptManager(client, this.#timeoutSettings);
this.#deviceRequestPromptManagerMap.set(client, manager);
}
return manager;
}
#onLifecycleEvent(event) {
const frame = this.frame(event.frameId);
if (!frame) {
return;
}
frame._onLifecycleEvent(event.loaderId, event.name);
this.emit(FrameManagerEvent.LifecycleEvent, frame);
frame.emit(FrameEvent.LifecycleEvent, undefined);
}
#onFrameStartedLoading(frameId) {
const frame = this.frame(frameId);
if (!frame) {
return;
}
frame._onLoadingStarted();
}
#onFrameStoppedLoading(frameId) {
const frame = this.frame(frameId);
if (!frame) {
return;
}
frame._onLoadingStopped();
this.emit(FrameManagerEvent.LifecycleEvent, frame);
frame.emit(FrameEvent.LifecycleEvent, undefined);
}
#handleFrameTree(session, frameTree) {
if (frameTree.frame.parentId) {
this.#onFrameAttached(session, frameTree.frame.id, frameTree.frame.parentId);
}
if (!this.#frameNavigatedReceived.has(frameTree.frame.id)) {
void this.#onFrameNavigated(frameTree.frame, 'Navigation');
}
else {
this.#frameNavigatedReceived.delete(frameTree.frame.id);
}
if (!frameTree.childFrames) {
return;
}
for (const child of frameTree.childFrames) {
this.#handleFrameTree(session, child);
}
}
#onFrameAttached(session, frameId, parentFrameId) {
let frame = this.frame(frameId);
if (frame) {
const parentFrame = this.frame(parentFrameId);
if (session && parentFrame && frame.client !== parentFrame?.client) {
// If an OOP iframes becomes a normal iframe
// again it is first attached to the parent frame before the
// target is removed.
frame.updateClient(session);
}
return;
}
frame = new CdpFrame(this, frameId, parentFrameId, session);
this._frameTree.addFrame(frame);
this.emit(FrameManagerEvent.FrameAttached, frame);
}
async #onFrameNavigated(framePayload, navigationType) {
const frameId = framePayload.id;
const isMainFrame = !framePayload.parentId;
let frame = this._frameTree.getById(frameId);
// Detach all child frames first.
if (frame) {
for (const child of frame.childFrames()) {
this.#removeFramesRecursively(child);
}
}
// Update or create main frame.
if (isMainFrame) {
if (frame) {
// Update frame id to retain frame identity on cross-process navigation.
this._frameTree.removeFrame(frame);
frame._id = frameId;
}
else {
// Initial main frame navigation.
frame = new CdpFrame(this, frameId, undefined, this.#client);
}
this._frameTree.addFrame(frame);
}
frame = await this._frameTree.waitForFrame(frameId);
frame._navigated(framePayload);
this.emit(FrameManagerEvent.FrameNavigated, frame);
frame.emit(FrameEvent.FrameNavigated, navigationType);
}
async #createIsolatedWorld(session, name) {
const key = `${session.id()}:${name}`;
if (this.#isolatedWorlds.has(key)) {
return;
}
await session.send('Page.addScriptToEvaluateOnNewDocument', {
source: `//# sourceURL=${PuppeteerURL.INTERNAL_URL}`,
worldName: name,
});
await Promise.all(this.frames()
.filter(frame => {
return frame.client === session;
})
.map(frame => {
// Frames might be removed before we send this, so we don't want to
// throw an error.
return session
.send('Page.createIsolatedWorld', {
frameId: frame._id,
worldName: name,
grantUniveralAccess: true,
})
.catch(debugError);
}));
this.#isolatedWorlds.add(key);
}
#onFrameNavigatedWithinDocument(frameId, url) {
const frame = this.frame(frameId);
if (!frame) {
return;
}
frame._navigatedWithinDocument(url);
this.emit(FrameManagerEvent.FrameNavigatedWithinDocument, frame);
frame.emit(FrameEvent.FrameNavigatedWithinDocument, undefined);
this.emit(FrameManagerEvent.FrameNavigated, frame);
frame.emit(FrameEvent.FrameNavigated, 'Navigation');
}
#onFrameDetached(frameId, reason) {
const frame = this.frame(frameId);
if (!frame) {
return;
}
switch (reason) {
case 'remove':
// Only remove the frame if the reason for the detached event is
// an actual removement of the frame.
// For frames that become OOP iframes, the reason would be 'swap'.
this.#removeFramesRecursively(frame);
break;
case 'swap':
this.emit(FrameManagerEvent.FrameSwapped, frame);
frame.emit(FrameEvent.FrameSwapped, undefined);
break;
}
}
#isExtensionOrigin(origin) {
return origin.startsWith(CHROME_EXTENSION_PREFIX);
}
#extractExtensionId(origin) {
if (!origin || !this.#isExtensionOrigin(origin)) {
return null;
}
const pathPart = origin.substring(CHROME_EXTENSION_PREFIX.length);
const slashIndex = pathPart.indexOf('/');
// if there's no / it means that pathPart is now the extensionId, otherwise
// we take everything until the first /
return slashIndex === -1 ? pathPart : pathPart.substring(0, slashIndex);
}
#onExecutionContextCreated(contextPayload, session) {
const auxData = contextPayload.auxData;
const origin = contextPayload.origin;
const frameId = auxData && auxData.frameId;
const frame = typeof frameId === 'string' ? this.frame(frameId) : undefined;
let world;
if (frame) {
// Only care about execution contexts created for the current session.
if (frame.client !== session) {
return;
}
if (contextPayload.auxData && contextPayload.auxData['isDefault']) {
world = frame.worlds[MAIN_WORLD];
}
else if (contextPayload.name === UTILITY_WORLD_NAME) {
// In case of multiple sessions to the same target, there's a race between
// connections so we might end up creating multiple isolated worlds.
// We can use either.
world = frame.worlds[PUPPETEER_WORLD];
}
else if (this.#isExtensionOrigin(origin)) {
const extId = this.#extractExtensionId(origin);
if (!extId) {
debugError('Error while parsing extension id');
return;
}
if (frame.extensionWorlds[extId]) {
world = frame.extensionWorlds[extId];
}
else {
world = new IsolatedWorld(frame, this.timeoutSettings, extId);
frame.extensionWorlds[extId] = world;
frame.registerWorldListeners(world);
world.origin = origin;
world.setWorldId(extId);
}
}
}
// If there is no world, the context is not meant to be handled by us.
if (!world) {
return;
}
const context = new ExecutionContext(frame?.client || this.#client, contextPayload, world);
world.setContext(context);
}
#removeFramesRecursively(frame) {
for (const child of frame.childFrames()) {
this.#removeFramesRecursively(child);
}
this._frameTree.removeFrame(frame);
this.emit(FrameManagerEvent.FrameDetached, frame);
frame.emit(FrameEvent.FrameDetached, frame);
// Needs to be last to ensure events
// sent before handlers are cleared.
frame[disposeSymbol]();
}
}
//# sourceMappingURL=FrameManager.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,45 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type Protocol from 'devtools-protocol';
import type { EventType } from '../common/EventEmitter.js';
import type { CdpFrame } from './Frame.js';
import type { IsolatedWorld } from './IsolatedWorld.js';
/**
* We use symbols to prevent external parties listening to these events.
* They are internal to Puppeteer.
*
* @internal
*/
export declare namespace FrameManagerEvent {
const FrameAttached: unique symbol;
const FrameNavigated: unique symbol;
const FrameDetached: unique symbol;
const FrameSwapped: unique symbol;
const LifecycleEvent: unique symbol;
const FrameNavigatedWithinDocument: unique symbol;
const ConsoleApiCalled: unique symbol;
const BindingCalled: unique symbol;
}
/**
* @internal
*/
export interface FrameManagerEvents extends Record<EventType, unknown> {
[FrameManagerEvent.FrameAttached]: CdpFrame;
[FrameManagerEvent.FrameNavigated]: CdpFrame;
[FrameManagerEvent.FrameDetached]: CdpFrame;
[FrameManagerEvent.FrameSwapped]: CdpFrame;
[FrameManagerEvent.LifecycleEvent]: CdpFrame;
[FrameManagerEvent.FrameNavigatedWithinDocument]: CdpFrame;
[FrameManagerEvent.ConsoleApiCalled]: [
IsolatedWorld,
Protocol.Runtime.ConsoleAPICalledEvent
];
[FrameManagerEvent.BindingCalled]: [
IsolatedWorld,
Protocol.Runtime.BindingCalledEvent
];
}
//# sourceMappingURL=FrameManagerEvents.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FrameManagerEvents.d.ts","sourceRoot":"","sources":["../../../src/cdp/FrameManagerEvents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAEzD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAEtD;;;;;GAKG;AAEH,yBAAiB,iBAAiB,CAAC;IAC1B,MAAM,aAAa,eAAuC,CAAC;IAC3D,MAAM,cAAc,eAAwC,CAAC;IAC7D,MAAM,aAAa,eAAuC,CAAC;IAC3D,MAAM,YAAY,eAAsC,CAAC;IACzD,MAAM,cAAc,eAAwC,CAAC;IAC7D,MAAM,4BAA4B,eAExC,CAAC;IACK,MAAM,gBAAgB,eAA0C,CAAC;IACjE,MAAM,aAAa,eAAuC,CAAC;CACnE;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;IACpE,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC;IAC5C,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC7C,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC;IAC5C,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC;IAC3C,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC7C,CAAC,iBAAiB,CAAC,4BAA4B,CAAC,EAAE,QAAQ,CAAC;IAE3D,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE;QACpC,aAAa;QACb,QAAQ,CAAC,OAAO,CAAC,qBAAqB;KACvC,CAAC;IACF,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE;QACjC,aAAa;QACb,QAAQ,CAAC,OAAO,CAAC,kBAAkB;KACpC,CAAC;CACH"}

View File

@@ -0,0 +1,24 @@
/**
* @license
* Copyright 2023 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* We use symbols to prevent external parties listening to these events.
* They are internal to Puppeteer.
*
* @internal
*/
// eslint-disable-next-line @typescript-eslint/no-namespace
export var FrameManagerEvent;
(function (FrameManagerEvent) {
FrameManagerEvent.FrameAttached = Symbol('FrameManager.FrameAttached');
FrameManagerEvent.FrameNavigated = Symbol('FrameManager.FrameNavigated');
FrameManagerEvent.FrameDetached = Symbol('FrameManager.FrameDetached');
FrameManagerEvent.FrameSwapped = Symbol('FrameManager.FrameSwapped');
FrameManagerEvent.LifecycleEvent = Symbol('FrameManager.LifecycleEvent');
FrameManagerEvent.FrameNavigatedWithinDocument = Symbol('FrameManager.FrameNavigatedWithinDocument');
FrameManagerEvent.ConsoleApiCalled = Symbol('FrameManager.ConsoleApiCalled');
FrameManagerEvent.BindingCalled = Symbol('FrameManager.BindingCalled');
})(FrameManagerEvent || (FrameManagerEvent = {}));
//# sourceMappingURL=FrameManagerEvents.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FrameManagerEvents.js","sourceRoot":"","sources":["../../../src/cdp/FrameManagerEvents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH;;;;;GAKG;AACH,2DAA2D;AAC3D,MAAM,KAAW,iBAAiB,CAWjC;AAXD,WAAiB,iBAAiB;IACnB,+BAAa,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;IACrD,gCAAc,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;IACvD,+BAAa,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;IACrD,8BAAY,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACnD,gCAAc,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;IACvD,8CAA4B,GAAG,MAAM,CAChD,2CAA2C,CAC5C,CAAC;IACW,kCAAgB,GAAG,MAAM,CAAC,+BAA+B,CAAC,CAAC;IAC3D,+BAAa,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AACpE,CAAC,EAXgB,iBAAiB,KAAjB,iBAAiB,QAWjC"}

View File

@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Frame } from '../api/Frame.js';
/**
* Keeps track of the page frame tree and it's is managed by
* {@link FrameManager}. FrameTree uses frame IDs to reference frame and it
* means that referenced frames might not be in the tree anymore. Thus, the tree
* structure is eventually consistent.
* @internal
*/
export declare class FrameTree<FrameType extends Frame> {
#private;
getMainFrame(): FrameType | undefined;
getById(frameId: string): FrameType | undefined;
/**
* Returns a promise that is resolved once the frame with
* the given ID is added to the tree.
*/
waitForFrame(frameId: string): Promise<FrameType>;
frames(): FrameType[];
addFrame(frame: FrameType): void;
removeFrame(frame: FrameType): void;
childFrames(frameId: string): FrameType[];
parentFrame(frameId: string): FrameType | undefined;
}
//# sourceMappingURL=FrameTree.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FrameTree.d.ts","sourceRoot":"","sources":["../../../src/cdp/FrameTree.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAG3C;;;;;;GAMG;AACH,qBAAa,SAAS,CAAC,SAAS,SAAS,KAAK;;IAU5C,YAAY,IAAI,SAAS,GAAG,SAAS;IAIrC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI/C;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAYjD,MAAM,IAAI,SAAS,EAAE;IAIrB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAiBhC,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAUnC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE;IAczC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;CAIpD"}

View File

@@ -0,0 +1,91 @@
/**
* @license
* Copyright 2022 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { Deferred } from '../util/Deferred.js';
/**
* Keeps track of the page frame tree and it's is managed by
* {@link FrameManager}. FrameTree uses frame IDs to reference frame and it
* means that referenced frames might not be in the tree anymore. Thus, the tree
* structure is eventually consistent.
* @internal
*/
export class FrameTree {
#frames = new Map();
// frameID -> parentFrameID
#parentIds = new Map();
// frameID -> childFrameIDs
#childIds = new Map();
#mainFrame;
#isMainFrameStale = false;
#waitRequests = new Map();
getMainFrame() {
return this.#mainFrame;
}
getById(frameId) {
return this.#frames.get(frameId);
}
/**
* Returns a promise that is resolved once the frame with
* the given ID is added to the tree.
*/
waitForFrame(frameId) {
const frame = this.getById(frameId);
if (frame) {
return Promise.resolve(frame);
}
const deferred = Deferred.create();
const callbacks = this.#waitRequests.get(frameId) || new Set();
callbacks.add(deferred);
return deferred.valueOrThrow();
}
frames() {
return Array.from(this.#frames.values());
}
addFrame(frame) {
this.#frames.set(frame._id, frame);
if (frame._parentId) {
this.#parentIds.set(frame._id, frame._parentId);
if (!this.#childIds.has(frame._parentId)) {
this.#childIds.set(frame._parentId, new Set());
}
this.#childIds.get(frame._parentId).add(frame._id);
}
else if (!this.#mainFrame || this.#isMainFrameStale) {
this.#mainFrame = frame;
this.#isMainFrameStale = false;
}
this.#waitRequests.get(frame._id)?.forEach(request => {
return request.resolve(frame);
});
}
removeFrame(frame) {
this.#frames.delete(frame._id);
this.#parentIds.delete(frame._id);
if (frame._parentId) {
this.#childIds.get(frame._parentId)?.delete(frame._id);
}
else {
this.#isMainFrameStale = true;
}
}
childFrames(frameId) {
const childIds = this.#childIds.get(frameId);
if (!childIds) {
return [];
}
return Array.from(childIds)
.map(id => {
return this.getById(id);
})
.filter((frame) => {
return frame !== undefined;
});
}
parentFrame(frameId) {
const parentId = this.#parentIds.get(frameId);
return parentId ? this.getById(parentId) : undefined;
}
}
//# sourceMappingURL=FrameTree.js.map

View File

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

View File

@@ -0,0 +1,71 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import type { Frame } from '../api/Frame.js';
import { type ContinueRequestOverrides, HTTPRequest, type ResourceType, type ResponseForRequest } from '../api/HTTPRequest.js';
import type { CdpHTTPResponse } from './HTTPResponse.js';
/**
* @internal
*/
export declare class CdpHTTPRequest extends HTTPRequest {
#private;
id: string;
_redirectChain: CdpHTTPRequest[];
_response: CdpHTTPResponse | null;
get client(): CDPSession;
set client(newClient: CDPSession);
constructor(client: CDPSession, frame: Frame | null, interceptionId: string | undefined, allowInterception: boolean, data: {
/**
* Request identifier.
*/
requestId: Protocol.Network.RequestId;
/**
* Loader identifier. Empty string if the request is fetched from worker.
*/
loaderId?: Protocol.Network.LoaderId;
/**
* URL of the document this request is loaded for.
*/
documentURL?: string;
/**
* Request data.
*/
request: Protocol.Network.Request;
/**
* Request initiator.
*/
initiator?: Protocol.Network.Initiator;
/**
* Type of this resource.
*/
type?: Protocol.Network.ResourceType;
}, redirectChain: CdpHTTPRequest[]);
updateHeaders(headers: Protocol.Network.Headers): void;
url(): string;
resourceType(): ResourceType;
method(): string;
postData(): string | undefined;
hasPostData(): boolean;
fetchPostData(): Promise<string | undefined>;
headers(): Record<string, string>;
response(): CdpHTTPResponse | null;
frame(): Frame | null;
isNavigationRequest(): boolean;
initiator(): Protocol.Network.Initiator | undefined;
redirectChain(): CdpHTTPRequest[];
failure(): {
errorText: string;
} | null;
protected canBeIntercepted(): boolean;
/**
* @internal
*/
_continue(overrides?: ContinueRequestOverrides): Promise<void>;
_respond(response: Partial<ResponseForRequest>): Promise<void>;
_abort(errorReason: Protocol.Network.ErrorReason | null): Promise<void>;
}
//# sourceMappingURL=HTTPRequest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPRequest.d.ts","sourceRoot":"","sources":["../../../src/cdp/HTTPRequest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,KAAK,wBAAwB,EAE7B,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,kBAAkB,EAGxB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAEvD;;GAEG;AACH,qBAAa,cAAe,SAAQ,WAAW;;IACpC,EAAE,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAe1C,IAAa,MAAM,IAAI,UAAU,CAEhC;IAED,IAAa,MAAM,CAAC,SAAS,EAAE,UAAU,EAExC;gBAGC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,iBAAiB,EAAE,OAAO,EAC1B,IAAI,EAAE;QACJ;;WAEG;QACH,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;QACtC;;WAEG;QACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;QACrC;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;WAEG;QACH,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC;QAClC;;WAEG;QACH,SAAS,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;QACvC;;WAEG;QACH,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC;KACtC,EACD,aAAa,EAAE,cAAc,EAAE;IAuCjC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI;IAM7C,GAAG,IAAI,MAAM;IAIb,YAAY,IAAI,YAAY;IAI5B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,WAAW,IAAI,OAAO;IAIhB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAYlD,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAKjC,QAAQ,IAAI,eAAe,GAAG,IAAI;IAIlC,KAAK,IAAI,KAAK,GAAG,IAAI;IAIrB,mBAAmB,IAAI,OAAO;IAI9B,SAAS,IAAI,QAAQ,CAAC,OAAO,CAAC,SAAS,GAAG,SAAS;IAInD,aAAa,IAAI,cAAc,EAAE;IAIjC,OAAO,IAAI;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,GAAG,IAAI;IAS9C,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC;;OAEG;IACG,SAAS,CAAC,SAAS,GAAE,wBAA6B,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BlE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoD9D,MAAM,CACV,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,IAAI,GAC/C,OAAO,CAAC,IAAI,CAAC;CAcjB"}

View File

@@ -0,0 +1,195 @@
import { headersArray, HTTPRequest, STATUS_TEXTS, handleError, } from '../api/HTTPRequest.js';
import { debugError } from '../common/util.js';
import { mergeUint8Arrays, stringToBase64, stringToTypedArray, } from '../util/encoding.js';
/**
* @internal
*/
export class CdpHTTPRequest extends HTTPRequest {
id;
#client;
#isNavigationRequest;
#url;
#resourceType;
#method;
#hasPostData = false;
#postData;
#headers = {};
#frame;
#initiator;
get client() {
return this.#client;
}
set client(newClient) {
this.#client = newClient;
}
constructor(client, frame, interceptionId, allowInterception, data, redirectChain) {
super();
this.#client = client;
this.id = data.requestId;
this.#isNavigationRequest =
data.requestId === data.loaderId && data.type === 'Document';
this._interceptionId = interceptionId;
this.#url = data.request.url + (data.request.urlFragment ?? '');
this.#resourceType = (data.type || 'other').toLowerCase();
this.#method = data.request.method;
if (data.request.postDataEntries &&
data.request.postDataEntries.length > 0) {
this.#postData = new TextDecoder().decode(mergeUint8Arrays(data.request.postDataEntries
.map(entry => {
return entry.bytes ? stringToTypedArray(entry.bytes, true) : null;
})
.filter((entry) => {
return entry !== null;
})));
}
else {
this.#postData = data.request.postData;
}
this.#hasPostData = data.request.hasPostData ?? false;
this.#frame = frame;
this._redirectChain = redirectChain;
this.#initiator = data.initiator;
this.interception.enabled = allowInterception;
this.updateHeaders(data.request.headers);
}
updateHeaders(headers) {
for (const [key, value] of Object.entries(headers)) {
this.#headers[key.toLowerCase()] = value;
}
}
url() {
return this.#url;
}
resourceType() {
return this.#resourceType;
}
method() {
return this.#method;
}
postData() {
return this.#postData;
}
hasPostData() {
return this.#hasPostData;
}
async fetchPostData() {
try {
const result = await this.#client.send('Network.getRequestPostData', {
requestId: this.id,
});
return result.postData;
}
catch (err) {
debugError(err);
return;
}
}
headers() {
// Callers should not be allowed to mutate internal structure.
return structuredClone(this.#headers);
}
response() {
return this._response;
}
frame() {
return this.#frame;
}
isNavigationRequest() {
return this.#isNavigationRequest;
}
initiator() {
return this.#initiator;
}
redirectChain() {
return this._redirectChain.slice();
}
failure() {
if (!this._failureText) {
return null;
}
return {
errorText: this._failureText,
};
}
canBeIntercepted() {
return !this.url().startsWith('data:') && !this._fromMemoryCache;
}
/**
* @internal
*/
async _continue(overrides = {}) {
const { url, method, postData, headers } = overrides;
this.interception.handled = true;
const postDataBinaryBase64 = postData
? stringToBase64(postData)
: undefined;
if (this._interceptionId === undefined) {
throw new Error('HTTPRequest is missing _interceptionId needed for Fetch.continueRequest');
}
await this.#client
.send('Fetch.continueRequest', {
requestId: this._interceptionId,
url,
method,
postData: postDataBinaryBase64,
headers: headers ? headersArray(headers) : undefined,
})
.catch(error => {
this.interception.handled = false;
return handleError(error);
});
}
async _respond(response) {
this.interception.handled = true;
let parsedBody;
if (response.body) {
parsedBody = HTTPRequest.getResponse(response.body);
}
const responseHeaders = {};
if (response.headers) {
for (const header of Object.keys(response.headers)) {
const value = response.headers[header];
responseHeaders[header.toLowerCase()] = Array.isArray(value)
? value.map(item => {
return String(item);
})
: String(value);
}
}
if (response.contentType) {
responseHeaders['content-type'] = response.contentType;
}
if (parsedBody?.contentLength && !('content-length' in responseHeaders)) {
responseHeaders['content-length'] = String(parsedBody.contentLength);
}
const status = response.status || 200;
if (this._interceptionId === undefined) {
throw new Error('HTTPRequest is missing _interceptionId needed for Fetch.fulfillRequest');
}
await this.#client
.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: status,
responsePhrase: STATUS_TEXTS[status],
responseHeaders: headersArray(responseHeaders),
body: parsedBody?.base64,
})
.catch(error => {
this.interception.handled = false;
return handleError(error);
});
}
async _abort(errorReason) {
this.interception.handled = true;
if (this._interceptionId === undefined) {
throw new Error('HTTPRequest is missing _interceptionId needed for Fetch.failRequest');
}
await this.#client
.send('Fetch.failRequest', {
requestId: this._interceptionId,
errorReason: errorReason || 'Failed',
})
.catch(handleError);
}
}
//# sourceMappingURL=HTTPRequest.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
/**
* @license
* Copyright 2020 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { Frame } from '../api/Frame.js';
import { HTTPResponse, type RemoteAddress } from '../api/HTTPResponse.js';
import { SecurityDetails } from '../common/SecurityDetails.js';
import type { CdpHTTPRequest } from './HTTPRequest.js';
/**
* @internal
*/
export declare class CdpHTTPResponse extends HTTPResponse {
#private;
constructor(request: CdpHTTPRequest, responsePayload: Protocol.Network.Response, extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null);
_resolveBody(err?: Error): void;
remoteAddress(): RemoteAddress;
url(): string;
status(): number;
statusText(): string;
headers(): Record<string, string>;
securityDetails(): SecurityDetails | null;
timing(): Protocol.Network.ResourceTiming | null;
content(): Promise<Uint8Array>;
request(): CdpHTTPRequest;
fromCache(): boolean;
fromServiceWorker(): boolean;
frame(): Frame | null;
}
//# sourceMappingURL=HTTPResponse.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPResponse.d.ts","sourceRoot":"","sources":["../../../src/cdp/HTTPResponse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAC,YAAY,EAAE,KAAK,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAK7D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;gBAc7C,OAAO,EAAE,cAAc,EACvB,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAC1C,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,8BAA8B,GAAG,IAAI;IAgDnE,YAAY,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI;IAOtB,aAAa,IAAI,aAAa;IAI9B,GAAG,IAAI,MAAM;IAIb,MAAM,IAAI,MAAM;IAIhB,UAAU,IAAI,MAAM;IAIpB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjC,eAAe,IAAI,eAAe,GAAG,IAAI;IAIzC,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI;IAIhD,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAkC9B,OAAO,IAAI,cAAc;IAIzB,SAAS,IAAI,OAAO;IAIpB,iBAAiB,IAAI,OAAO;IAI5B,KAAK,IAAI,KAAK,GAAG,IAAI;CAG/B"}

View File

@@ -0,0 +1,127 @@
import { HTTPResponse } from '../api/HTTPResponse.js';
import { ProtocolError } from '../common/Errors.js';
import { SecurityDetails } from '../common/SecurityDetails.js';
import { Deferred } from '../util/Deferred.js';
import { stringToTypedArray } from '../util/encoding.js';
import { normalizeHeaderValue } from '../util/httpUtils.js';
/**
* @internal
*/
export class CdpHTTPResponse extends HTTPResponse {
#request;
#contentPromise = null;
#bodyLoadedDeferred = Deferred.create();
#remoteAddress;
#status;
#statusText;
#fromDiskCache;
#fromServiceWorker;
#headers = {};
#securityDetails;
#timing;
constructor(request, responsePayload, extraInfo) {
super();
this.#request = request;
this.#remoteAddress = {
ip: responsePayload.remoteIPAddress,
port: responsePayload.remotePort,
};
this.#statusText =
this.#parseStatusTextFromExtraInfo(extraInfo) ||
responsePayload.statusText;
this.#fromDiskCache = !!responsePayload.fromDiskCache;
this.#fromServiceWorker = !!responsePayload.fromServiceWorker;
this.#status = extraInfo ? extraInfo.statusCode : responsePayload.status;
const headers = extraInfo ? extraInfo.headers : responsePayload.headers;
for (const [key, value] of Object.entries(headers)) {
this.#headers[key.toLowerCase()] = normalizeHeaderValue(value);
}
this.#securityDetails = responsePayload.securityDetails
? new SecurityDetails(responsePayload.securityDetails)
: null;
this.#timing = responsePayload.timing || null;
}
#parseStatusTextFromExtraInfo(extraInfo) {
if (!extraInfo || !extraInfo.headersText) {
return;
}
const firstLine = extraInfo.headersText.split('\r', 1)[0];
if (!firstLine || firstLine.length > 1_000) {
return;
}
const match = firstLine.match(/[^ ]* [^ ]* (.*)/);
if (!match) {
return;
}
const statusText = match[1];
if (!statusText) {
return;
}
return statusText;
}
_resolveBody(err) {
if (err) {
return this.#bodyLoadedDeferred.reject(err);
}
return this.#bodyLoadedDeferred.resolve();
}
remoteAddress() {
return this.#remoteAddress;
}
url() {
return this.#request.url();
}
status() {
return this.#status;
}
statusText() {
return this.#statusText;
}
headers() {
return this.#headers;
}
securityDetails() {
return this.#securityDetails;
}
timing() {
return this.#timing;
}
content() {
if (!this.#contentPromise) {
this.#contentPromise = this.#bodyLoadedDeferred
.valueOrThrow()
.then(async () => {
try {
// Use CDPSession from corresponding request to retrieve body, as it's client
// might have been updated (e.g. for an adopted OOPIF).
const response = await this.#request.client.send('Network.getResponseBody', {
requestId: this.#request.id,
});
return stringToTypedArray(response.body, response.base64Encoded);
}
catch (error) {
if (error instanceof ProtocolError &&
error.originalMessage ===
'No resource with given identifier found') {
throw new ProtocolError('Could not load response body for this request. This might happen if the request is a preflight request.');
}
throw error;
}
});
}
return this.#contentPromise;
}
request() {
return this.#request;
}
fromCache() {
return this.#fromDiskCache || this.#request._fromMemoryCache;
}
fromServiceWorker() {
return this.#fromServiceWorker;
}
frame() {
return this.#request.frame();
}
}
//# sourceMappingURL=HTTPResponse.js.map

View File

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

View File

@@ -0,0 +1,68 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type { Protocol } from 'devtools-protocol';
import type { CDPSession } from '../api/CDPSession.js';
import type { Point } from '../api/ElementHandle.js';
import { Keyboard, Mouse, Touchscreen, type TouchHandle, type KeyDownOptions, type KeyPressOptions, type KeyboardTypeOptions, type MouseClickOptions, type MouseMoveOptions, type MouseOptions, type MouseWheelOptions } from '../api/Input.js';
import { type KeyInput } from '../common/USKeyboardLayout.js';
/**
* @internal
*/
export declare class CdpKeyboard extends Keyboard {
#private;
_modifiers: number;
constructor(client: CDPSession);
updateClient(client: CDPSession): void;
down(key: KeyInput, options?: Readonly<KeyDownOptions>): Promise<void>;
up(key: KeyInput): Promise<void>;
sendCharacter(char: string): Promise<void>;
private charIsKey;
type(text: string, options?: Readonly<KeyboardTypeOptions>): Promise<void>;
press(key: KeyInput, options?: Readonly<KeyPressOptions>): Promise<void>;
}
/**
* @internal
*/
export declare class CdpMouse extends Mouse {
#private;
constructor(client: CDPSession, keyboard: CdpKeyboard);
updateClient(client: CDPSession): void;
reset(): Promise<void>;
move(x: number, y: number, options?: Readonly<MouseMoveOptions>): Promise<void>;
down(options?: Readonly<MouseOptions>): Promise<void>;
up(options?: Readonly<MouseOptions>): Promise<void>;
click(x: number, y: number, options?: Readonly<MouseClickOptions>): Promise<void>;
wheel(options?: Readonly<MouseWheelOptions>): Promise<void>;
drag(start: Point, target: Point): Promise<Protocol.Input.DragData>;
dragEnter(target: Point, data: Protocol.Input.DragData): Promise<void>;
dragOver(target: Point, data: Protocol.Input.DragData): Promise<void>;
drop(target: Point, data: Protocol.Input.DragData): Promise<void>;
dragAndDrop(start: Point, target: Point, options?: {
delay?: number;
}): Promise<void>;
}
/**
* @internal
*/
export declare class CdpTouchHandle implements TouchHandle {
#private;
constructor(client: CDPSession, touchScreen: CdpTouchscreen, keyboard: CdpKeyboard, touchPoint: Protocol.Input.TouchPoint);
updateClient(client: CDPSession): void;
start(): Promise<void>;
move(x: number, y: number): Promise<void>;
end(): Promise<void>;
}
/**
* @internal
*/
export declare class CdpTouchscreen extends Touchscreen {
#private;
touches: CdpTouchHandle[];
constructor(client: CDPSession, keyboard: CdpKeyboard);
updateClient(client: CDPSession): void;
touchStart(x: number, y: number): Promise<TouchHandle>;
}
//# sourceMappingURL=Input.d.ts.map

View File

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

497
node_modules/puppeteer-core/lib/puppeteer/cdp/Input.js generated vendored Normal file
View File

@@ -0,0 +1,497 @@
/**
* @license
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import { Keyboard, Mouse, MouseButton, Touchscreen, } from '../api/Input.js';
import { TouchError } from '../common/Errors.js';
import { _keyDefinitions, } from '../common/USKeyboardLayout.js';
import { assert } from '../util/assert.js';
/**
* @internal
*/
export class CdpKeyboard extends Keyboard {
#client;
#pressedKeys = new Set();
_modifiers = 0;
constructor(client) {
super();
this.#client = client;
}
updateClient(client) {
this.#client = client;
}
async down(key, options = {
text: undefined,
commands: [],
}) {
const description = this.#keyDescriptionForString(key);
const autoRepeat = this.#pressedKeys.has(description.code);
this.#pressedKeys.add(description.code);
this._modifiers |= this.#modifierBit(description.key);
const text = options.text === undefined ? description.text : options.text;
await this.#client.send('Input.dispatchKeyEvent', {
type: text ? 'keyDown' : 'rawKeyDown',
modifiers: this._modifiers,
windowsVirtualKeyCode: description.keyCode,
code: description.code,
key: description.key,
text: text,
unmodifiedText: text,
autoRepeat,
location: description.location,
isKeypad: description.location === 3,
commands: options.commands,
});
}
#modifierBit(key) {
if (key === 'Alt') {
return 1;
}
if (key === 'Control') {
return 2;
}
if (key === 'Meta') {
return 4;
}
if (key === 'Shift') {
return 8;
}
return 0;
}
#keyDescriptionForString(keyString) {
const shift = this._modifiers & 8;
const description = {
key: '',
keyCode: 0,
code: '',
text: '',
location: 0,
};
const definition = _keyDefinitions[keyString];
assert(definition, `Unknown key: "${keyString}"`);
if (definition.key) {
description.key = definition.key;
}
if (shift && definition.shiftKey) {
description.key = definition.shiftKey;
}
if (definition.keyCode) {
description.keyCode = definition.keyCode;
}
if (shift && definition.shiftKeyCode) {
description.keyCode = definition.shiftKeyCode;
}
if (definition.code) {
description.code = definition.code;
}
if (definition.location) {
description.location = definition.location;
}
if (description.key.length === 1) {
description.text = description.key;
}
if (definition.text) {
description.text = definition.text;
}
if (shift && definition.shiftText) {
description.text = definition.shiftText;
}
// if any modifiers besides shift are pressed, no text should be sent
if (this._modifiers & ~8) {
description.text = '';
}
return description;
}
async up(key) {
const description = this.#keyDescriptionForString(key);
this._modifiers &= ~this.#modifierBit(description.key);
this.#pressedKeys.delete(description.code);
await this.#client.send('Input.dispatchKeyEvent', {
type: 'keyUp',
modifiers: this._modifiers,
key: description.key,
windowsVirtualKeyCode: description.keyCode,
code: description.code,
location: description.location,
});
}
async sendCharacter(char) {
await this.#client.send('Input.insertText', { text: char });
}
charIsKey(char) {
return !!_keyDefinitions[char];
}
async type(text, options = {}) {
const delay = options.delay || undefined;
for (const char of text) {
if (this.charIsKey(char)) {
await this.press(char, { delay });
}
else {
if (delay) {
await new Promise(f => {
return setTimeout(f, delay);
});
}
await this.sendCharacter(char);
}
}
}
async press(key, options = {}) {
const { delay = null } = options;
await this.down(key, options);
if (delay) {
await new Promise(f => {
return setTimeout(f, options.delay);
});
}
await this.up(key);
}
}
const getFlag = (button) => {
switch (button) {
case MouseButton.Left:
return 1 /* MouseButtonFlag.Left */;
case MouseButton.Right:
return 2 /* MouseButtonFlag.Right */;
case MouseButton.Middle:
return 4 /* MouseButtonFlag.Middle */;
case MouseButton.Back:
return 8 /* MouseButtonFlag.Back */;
case MouseButton.Forward:
return 16 /* MouseButtonFlag.Forward */;
}
};
/**
* This should match
* https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/browser/renderer_host/input/web_input_event_builders_mac.mm;drc=a61b95c63b0b75c1cfe872d9c8cdf927c226046e;bpv=1;bpt=1;l=221.
*/
const getButtonFromPressedButtons = (buttons) => {
if (buttons & 1 /* MouseButtonFlag.Left */) {
return MouseButton.Left;
}
else if (buttons & 2 /* MouseButtonFlag.Right */) {
return MouseButton.Right;
}
else if (buttons & 4 /* MouseButtonFlag.Middle */) {
return MouseButton.Middle;
}
else if (buttons & 8 /* MouseButtonFlag.Back */) {
return MouseButton.Back;
}
else if (buttons & 16 /* MouseButtonFlag.Forward */) {
return MouseButton.Forward;
}
return 'none';
};
/**
* @internal
*/
export class CdpMouse extends Mouse {
#client;
#keyboard;
constructor(client, keyboard) {
super();
this.#client = client;
this.#keyboard = keyboard;
}
updateClient(client) {
this.#client = client;
}
#_state = {
position: { x: 0, y: 0 },
buttons: 0 /* MouseButtonFlag.None */,
};
get #state() {
return Object.assign({ ...this.#_state }, ...this.#transactions);
}
// Transactions can run in parallel, so we store each of thme in this array.
#transactions = [];
#createTransaction() {
const transaction = {};
this.#transactions.push(transaction);
const popTransaction = () => {
this.#transactions.splice(this.#transactions.indexOf(transaction), 1);
};
return {
update: (updates) => {
Object.assign(transaction, updates);
},
commit: () => {
this.#_state = { ...this.#_state, ...transaction };
popTransaction();
},
rollback: popTransaction,
};
}
/**
* This is a shortcut for a typical update, commit/rollback lifecycle based on
* the error of the action.
*/
async #withTransaction(action) {
const { update, commit, rollback } = this.#createTransaction();
try {
await action(update);
commit();
}
catch (error) {
rollback();
throw error;
}
}
async reset() {
const actions = [];
for (const [flag, button] of [
[1 /* MouseButtonFlag.Left */, MouseButton.Left],
[4 /* MouseButtonFlag.Middle */, MouseButton.Middle],
[2 /* MouseButtonFlag.Right */, MouseButton.Right],
[16 /* MouseButtonFlag.Forward */, MouseButton.Forward],
[8 /* MouseButtonFlag.Back */, MouseButton.Back],
]) {
if (this.#state.buttons & flag) {
actions.push(this.up({ button: button }));
}
}
if (this.#state.position.x !== 0 || this.#state.position.y !== 0) {
actions.push(this.move(0, 0));
}
await Promise.all(actions);
}
async move(x, y, options = {}) {
const { steps = 1 } = options;
const from = this.#state.position;
const to = { x, y };
for (let i = 1; i <= steps; i++) {
await this.#withTransaction(updateState => {
updateState({
position: {
x: from.x + (to.x - from.x) * (i / steps),
y: from.y + (to.y - from.y) * (i / steps),
},
});
const { buttons, position } = this.#state;
return this.#client.send('Input.dispatchMouseEvent', {
type: 'mouseMoved',
modifiers: this.#keyboard._modifiers,
buttons,
button: getButtonFromPressedButtons(buttons),
...position,
});
});
}
}
async down(options = {}) {
const { button = MouseButton.Left, clickCount = 1 } = options;
const flag = getFlag(button);
if (!flag) {
throw new Error(`Unsupported mouse button: ${button}`);
}
if (this.#state.buttons & flag) {
throw new Error(`'${button}' is already pressed.`);
}
await this.#withTransaction(updateState => {
updateState({
buttons: this.#state.buttons | flag,
});
const { buttons, position } = this.#state;
return this.#client.send('Input.dispatchMouseEvent', {
type: 'mousePressed',
modifiers: this.#keyboard._modifiers,
clickCount,
buttons,
button,
...position,
});
});
}
async up(options = {}) {
const { button = MouseButton.Left, clickCount = 1 } = options;
const flag = getFlag(button);
if (!flag) {
throw new Error(`Unsupported mouse button: ${button}`);
}
if (!(this.#state.buttons & flag)) {
throw new Error(`'${button}' is not pressed.`);
}
await this.#withTransaction(updateState => {
updateState({
buttons: this.#state.buttons & ~flag,
});
const { buttons, position } = this.#state;
return this.#client.send('Input.dispatchMouseEvent', {
type: 'mouseReleased',
modifiers: this.#keyboard._modifiers,
clickCount,
buttons,
button,
...position,
});
});
}
async click(x, y, options = {}) {
const { delay, count = 1 } = options;
if (count < 1) {
throw new Error('Click must occur a positive number of times.');
}
const actions = [this.move(x, y)];
for (let i = 1; i < count; ++i) {
actions.push(this.down({ ...options, clickCount: i }), this.up({ ...options, clickCount: i }));
}
actions.push(this.down({ ...options, clickCount: count }));
if (typeof delay === 'number') {
await Promise.all(actions);
actions.length = 0;
await new Promise(resolve => {
setTimeout(resolve, delay);
});
}
actions.push(this.up({ ...options, clickCount: count }));
await Promise.all(actions);
}
async wheel(options = {}) {
const { deltaX = 0, deltaY = 0 } = options;
const { position, buttons } = this.#state;
await this.#client.send('Input.dispatchMouseEvent', {
type: 'mouseWheel',
pointerType: 'mouse',
modifiers: this.#keyboard._modifiers,
deltaY,
deltaX,
buttons,
...position,
});
}
async drag(start, target) {
const promise = new Promise(resolve => {
this.#client.once('Input.dragIntercepted', event => {
return resolve(event.data);
});
});
await this.move(start.x, start.y);
await this.down();
await this.move(target.x, target.y);
return await promise;
}
async dragEnter(target, data) {
await this.#client.send('Input.dispatchDragEvent', {
type: 'dragEnter',
x: target.x,
y: target.y,
modifiers: this.#keyboard._modifiers,
data,
});
}
async dragOver(target, data) {
await this.#client.send('Input.dispatchDragEvent', {
type: 'dragOver',
x: target.x,
y: target.y,
modifiers: this.#keyboard._modifiers,
data,
});
}
async drop(target, data) {
await this.#client.send('Input.dispatchDragEvent', {
type: 'drop',
x: target.x,
y: target.y,
modifiers: this.#keyboard._modifiers,
data,
});
}
async dragAndDrop(start, target, options = {}) {
const { delay = null } = options;
const data = await this.drag(start, target);
await this.dragEnter(target, data);
await this.dragOver(target, data);
if (delay) {
await new Promise(resolve => {
return setTimeout(resolve, delay);
});
}
await this.drop(target, data);
await this.up();
}
}
/**
* @internal
*/
export class CdpTouchHandle {
#started = false;
#touchScreen;
#touchPoint;
#client;
#keyboard;
constructor(client, touchScreen, keyboard, touchPoint) {
this.#client = client;
this.#touchScreen = touchScreen;
this.#keyboard = keyboard;
this.#touchPoint = touchPoint;
}
updateClient(client) {
this.#client = client;
}
async start() {
if (this.#started) {
throw new TouchError('Touch has already started');
}
await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchStart',
touchPoints: [this.#touchPoint],
modifiers: this.#keyboard._modifiers,
});
this.#started = true;
}
move(x, y) {
this.#touchPoint.x = Math.round(x);
this.#touchPoint.y = Math.round(y);
return this.#client.send('Input.dispatchTouchEvent', {
type: 'touchMove',
touchPoints: [this.#touchPoint],
modifiers: this.#keyboard._modifiers,
});
}
async end() {
await this.#client.send('Input.dispatchTouchEvent', {
type: 'touchEnd',
touchPoints: [this.#touchPoint],
modifiers: this.#keyboard._modifiers,
});
this.#touchScreen.removeHandle(this);
}
}
/**
* @internal
*/
export class CdpTouchscreen extends Touchscreen {
#client;
#keyboard;
constructor(client, keyboard) {
super();
this.#client = client;
this.#keyboard = keyboard;
}
updateClient(client) {
this.#client = client;
this.touches.forEach(t => {
t.updateClient(client);
});
}
async touchStart(x, y) {
const id = this.idGenerator();
const touchPoint = {
x: Math.round(x),
y: Math.round(y),
radiusX: 0.5,
radiusY: 0.5,
force: 0.5,
id,
};
const touch = new CdpTouchHandle(this.#client, this, this.#keyboard, touchPoint);
await touch.start();
this.touches.push(touch);
return touch;
}
}
//# sourceMappingURL=Input.js.map

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More