puppeteer-core
Version:
A high-level API to control headless Chrome over the DevTools Protocol
102 lines (87 loc) • 2.56 kB
text/typescript
/**
* @license
* Copyright 2026 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import type {Page, Target, WebWorker} from '../api/api.js';
import {Extension} from '../api/api.js';
import {debugError} from '../common/util.js';
import {isErrorLike} from '../util/ErrorLike.js';
import type {CdpBrowser} from './Browser.js';
import {isTargetClosedError} from './Connection.js';
export class CdpExtension extends Extension {
// needed to access the CDPSession to trigger an extension action.
#browser: CdpBrowser;
/*
* @internal
*/
constructor(id: string, version: string, name: string, browser: CdpBrowser) {
super(id, version, name);
this.#browser = browser;
}
async workers(): Promise<WebWorker[]> {
const targets = this.#browser.targets();
const extensionWorkers = targets.filter((target: Target) => {
const targetUrl = target.url();
return (
target.type() === 'service_worker' &&
targetUrl.startsWith('chrome-extension://' + this.id)
);
});
const workers: WebWorker[] = [];
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(): Promise<Page[]> {
const targets = this.#browser.targets();
const extensionPages = targets.filter((target: 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): page is Page => {
return page !== null;
});
}
async triggerAction(page: Page): Promise<void> {
await this.#browser._connection.send('Extensions.triggerAction', {
id: this.id,
targetId: page._tabId,
});
}
#canIgnoreError(error: unknown): boolean {
return (
isErrorLike(error) &&
(isTargetClosedError(error) ||
error.message.includes('No target with given id found'))
);
}
}