@crawlee/browser-pool 4.0.0-beta.99 → 4.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/abstract-classes/browser-controller.d.ts +31 -19
- package/abstract-classes/browser-controller.js +62 -13
- package/abstract-classes/browser-plugin.d.ts +11 -13
- package/abstract-classes/browser-plugin.js +13 -9
- package/anonymize-proxy.d.ts +1 -0
- package/browser-pool.d.ts +30 -41
- package/browser-pool.js +211 -147
- package/events.d.ts +2 -3
- package/events.js +0 -1
- package/fingerprinting/hooks.js +2 -1
- package/fingerprinting/types.d.ts +3 -33
- package/fingerprinting/types.js +0 -1
- package/fingerprinting/utils.js +5 -5
- package/index.d.ts +1 -1
- package/launch-context.d.ts +3 -3
- package/launch-context.js +11 -8
- package/package.json +9 -8
- package/playwright/playwright-browser.d.ts +3 -5
- package/playwright/playwright-browser.js +17 -16
- package/playwright/playwright-controller.d.ts +1 -0
- package/playwright/playwright-controller.js +4 -3
- package/playwright/playwright-plugin.d.ts +5 -4
- package/playwright/playwright-plugin.js +16 -12
- package/puppeteer/puppeteer-controller.d.ts +1 -0
- package/puppeteer/puppeteer-controller.js +13 -11
- package/puppeteer/puppeteer-plugin.d.ts +7 -3
- package/puppeteer/puppeteer-plugin.js +9 -5
- package/remote-browser-pool.d.ts +21 -21
- package/remote-browser-pool.js +63 -48
- package/container-proxy-server.d.ts +0 -11
- package/container-proxy-server.js +0 -42
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Crawlee is available as the [`crawlee`](https://www.npmjs.com/package/crawlee) N
|
|
|
34
34
|
|
|
35
35
|
We recommend visiting the [Introduction tutorial](https://crawlee.dev/js/docs/introduction) in Crawlee documentation for more information.
|
|
36
36
|
|
|
37
|
-
> Crawlee requires **Node.js
|
|
37
|
+
> Crawlee requires **Node.js 22.13 or higher**.
|
|
38
38
|
|
|
39
39
|
### With Crawlee CLI
|
|
40
40
|
|
|
@@ -80,7 +80,14 @@ export interface BrowserControllerEvents<Library extends CommonLibrary, LibraryO
|
|
|
80
80
|
* @hideconstructor
|
|
81
81
|
*/
|
|
82
82
|
export declare abstract class BrowserController<Library extends CommonLibrary = CommonLibrary, LibraryOptions extends Dictionary | undefined = Parameters<Library['launch']>[0], LaunchResult extends CommonBrowser = UnwrapPromise<ReturnType<Library['launch']>>, NewPageOptions = Parameters<LaunchResult['newPage']>[0], NewPageResult = UnwrapPromise<ReturnType<LaunchResult['newPage']>>> extends TypedEmitter<BrowserControllerEvents<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>> implements IBrowserController<NewPageResult> {
|
|
83
|
+
#private;
|
|
83
84
|
readonly id: string;
|
|
85
|
+
/**
|
|
86
|
+
* Kept `protected` rather than `#private` because the concrete controllers in this package are
|
|
87
|
+
* separate classes — an ES private field would not be visible to them.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
84
91
|
protected readonly log: CrawleeLogger;
|
|
85
92
|
/**
|
|
86
93
|
* The `BrowserPlugin` instance used to launch the browser.
|
|
@@ -99,14 +106,17 @@ export declare abstract class BrowserController<Library extends CommonLibrary =
|
|
|
99
106
|
* `undefined` if no proxy is used
|
|
100
107
|
*/
|
|
101
108
|
proxyUrl?: string;
|
|
109
|
+
/** @internal */
|
|
102
110
|
isActive: boolean;
|
|
103
111
|
activePages: number;
|
|
112
|
+
/** @internal */
|
|
104
113
|
totalPages: number;
|
|
114
|
+
/** @internal */
|
|
105
115
|
lastPageOpenedAt: number;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Returns a promise that resolves once the browser controller has been activated.
|
|
118
|
+
*/
|
|
119
|
+
waitForActive(): Promise<void>;
|
|
110
120
|
constructor(browserPlugin: BrowserPlugin<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>);
|
|
111
121
|
/**
|
|
112
122
|
* Activates the BrowserController. If you try to open new pages before
|
|
@@ -137,30 +147,32 @@ export declare abstract class BrowserController<Library extends CommonLibrary =
|
|
|
137
147
|
* @ignore
|
|
138
148
|
*/
|
|
139
149
|
newPage(pageOptions?: NewPageOptions): Promise<NewPageResult>;
|
|
140
|
-
setCookies(page: NewPageResult, cookies: Cookie[]): Promise<void>;
|
|
141
|
-
getCookies(page: NewPageResult): Promise<Cookie[]>;
|
|
142
150
|
/**
|
|
143
|
-
*
|
|
151
|
+
* Accounts for a page no longer being open. Callable from either side and safe to call twice:
|
|
152
|
+
* the page's own `close` event, or the pool when it gives up on a close that never settles.
|
|
153
|
+
* Tracked in a `WeakSet` rather than via `isClosed()`, because that reports the same event.
|
|
154
|
+
* @internal
|
|
144
155
|
*/
|
|
145
|
-
|
|
156
|
+
registerPageClosed(page: NewPageResult): void;
|
|
146
157
|
/**
|
|
147
|
-
*
|
|
158
|
+
* Registers cleanup belonging to a single page: an anonymizing proxy server, an incognito
|
|
159
|
+
* context. It runs from `registerPageClosed`, so it happens whether the page closed on its own
|
|
160
|
+
* or the pool gave up on a close that never settled, and it runs at most once.
|
|
161
|
+
*
|
|
162
|
+
* Hanging it off the page's `close` event instead leaks it in exactly the case this controller
|
|
163
|
+
* now handles, because that event does not arrive for a page the browser never destroyed.
|
|
164
|
+
* @ignore
|
|
148
165
|
*/
|
|
166
|
+
protected registerPageTeardown(page: NewPageResult, teardown: () => Promise<void>): void;
|
|
167
|
+
setCookies(page: NewPageResult, cookies: Cookie[]): Promise<void>;
|
|
168
|
+
getCookies(page: NewPageResult): Promise<Cookie[]>;
|
|
169
|
+
protected abstract _close(): Promise<void>;
|
|
149
170
|
protected abstract _kill(): Promise<void>;
|
|
150
|
-
/**
|
|
151
|
-
* @private
|
|
152
|
-
*/
|
|
153
171
|
protected abstract _newPage(pageOptions?: NewPageOptions): Promise<NewPageResult>;
|
|
154
|
-
/**
|
|
155
|
-
* @private
|
|
156
|
-
*/
|
|
157
172
|
protected abstract _setCookies(page: NewPageResult, cookies: Cookie[]): Promise<void>;
|
|
158
|
-
/**
|
|
159
|
-
* @private
|
|
160
|
-
*/
|
|
161
173
|
protected abstract _getCookies(page: NewPageResult): Promise<Cookie[]>;
|
|
162
174
|
/**
|
|
163
|
-
* @
|
|
175
|
+
* @internal
|
|
164
176
|
*/
|
|
165
177
|
abstract normalizeProxyOptions(proxyUrl: string | undefined, pageOptions: any): Record<string, unknown>;
|
|
166
178
|
}
|
|
@@ -2,6 +2,7 @@ import { serviceLocator } from '@crawlee/core';
|
|
|
2
2
|
import { nanoid } from 'nanoid';
|
|
3
3
|
import { TypedEmitter } from 'tiny-typed-emitter';
|
|
4
4
|
import { tryCancel } from '@apify/timeout';
|
|
5
|
+
import { BROWSER_CONTROLLER_EVENTS } from '../events.js';
|
|
5
6
|
const PROCESS_KILL_TIMEOUT_MILLIS = 5000;
|
|
6
7
|
/**
|
|
7
8
|
* The `BrowserController` serves two purposes. First, it is the base class that
|
|
@@ -13,6 +14,12 @@ const PROCESS_KILL_TIMEOUT_MILLIS = 5000;
|
|
|
13
14
|
*/
|
|
14
15
|
export class BrowserController extends TypedEmitter {
|
|
15
16
|
id = nanoid();
|
|
17
|
+
/**
|
|
18
|
+
* Kept `protected` rather than `#private` because the concrete controllers in this package are
|
|
19
|
+
* separate classes — an ES private field would not be visible to them.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
16
23
|
log;
|
|
17
24
|
/**
|
|
18
25
|
* The `BrowserPlugin` instance used to launch the browser.
|
|
@@ -31,17 +38,28 @@ export class BrowserController extends TypedEmitter {
|
|
|
31
38
|
* `undefined` if no proxy is used
|
|
32
39
|
*/
|
|
33
40
|
proxyUrl;
|
|
41
|
+
/** @internal */
|
|
34
42
|
isActive = false;
|
|
35
43
|
activePages = 0;
|
|
44
|
+
#closedPages = new WeakSet();
|
|
45
|
+
#pageTeardowns = new WeakMap();
|
|
46
|
+
/** @internal */
|
|
36
47
|
totalPages = 0;
|
|
48
|
+
/** @internal */
|
|
37
49
|
lastPageOpenedAt = Date.now();
|
|
38
|
-
|
|
39
|
-
isActivePromise = new Promise((resolve) => {
|
|
40
|
-
this
|
|
50
|
+
#activate;
|
|
51
|
+
#isActivePromise = new Promise((resolve) => {
|
|
52
|
+
this.#activate = resolve;
|
|
41
53
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Returns a promise that resolves once the browser controller has been activated.
|
|
56
|
+
*/
|
|
57
|
+
async waitForActive() {
|
|
58
|
+
await this.#isActivePromise;
|
|
59
|
+
}
|
|
60
|
+
#commitBrowser;
|
|
61
|
+
#hasBrowserPromise = new Promise((resolve) => {
|
|
62
|
+
this.#commitBrowser = resolve;
|
|
45
63
|
});
|
|
46
64
|
constructor(browserPlugin) {
|
|
47
65
|
super();
|
|
@@ -58,7 +76,7 @@ export class BrowserController extends TypedEmitter {
|
|
|
58
76
|
if (!this.browser) {
|
|
59
77
|
throw new Error('Cannot activate BrowserController without an assigned browser.');
|
|
60
78
|
}
|
|
61
|
-
this
|
|
79
|
+
this.#activate();
|
|
62
80
|
this.isActive = true;
|
|
63
81
|
}
|
|
64
82
|
/**
|
|
@@ -70,7 +88,7 @@ export class BrowserController extends TypedEmitter {
|
|
|
70
88
|
}
|
|
71
89
|
this.browser = browser;
|
|
72
90
|
this.launchContext = launchContext;
|
|
73
|
-
this
|
|
91
|
+
this.#commitBrowser();
|
|
74
92
|
}
|
|
75
93
|
/**
|
|
76
94
|
* Gracefully closes the browser and makes sure
|
|
@@ -79,7 +97,7 @@ export class BrowserController extends TypedEmitter {
|
|
|
79
97
|
* Emits 'browserClosed' event.
|
|
80
98
|
*/
|
|
81
99
|
async close() {
|
|
82
|
-
await this
|
|
100
|
+
await this.#hasBrowserPromise;
|
|
83
101
|
try {
|
|
84
102
|
await this._close();
|
|
85
103
|
// TODO: shouldn't this go in a finally instead?
|
|
@@ -88,7 +106,7 @@ export class BrowserController extends TypedEmitter {
|
|
|
88
106
|
catch (error) {
|
|
89
107
|
this.log.debug(`Could not close browser.\nCause: ${error.message}`, { id: this.id });
|
|
90
108
|
}
|
|
91
|
-
this.emit(
|
|
109
|
+
this.emit(BROWSER_CONTROLLER_EVENTS.BROWSER_CLOSED, this);
|
|
92
110
|
const killTimer = setTimeout(() => {
|
|
93
111
|
this._kill().catch((err) => {
|
|
94
112
|
this.log.debug(`Could not kill browser.\nCause: ${err.message}`, { id: this.id });
|
|
@@ -102,9 +120,9 @@ export class BrowserController extends TypedEmitter {
|
|
|
102
120
|
* Emits 'browserClosed' event.
|
|
103
121
|
*/
|
|
104
122
|
async kill() {
|
|
105
|
-
await this
|
|
123
|
+
await this.#hasBrowserPromise;
|
|
106
124
|
await this._kill();
|
|
107
|
-
this.emit(
|
|
125
|
+
this.emit(BROWSER_CONTROLLER_EVENTS.BROWSER_CLOSED, this);
|
|
108
126
|
}
|
|
109
127
|
/**
|
|
110
128
|
* Opens new browser page.
|
|
@@ -113,12 +131,43 @@ export class BrowserController extends TypedEmitter {
|
|
|
113
131
|
async newPage(pageOptions) {
|
|
114
132
|
this.activePages++;
|
|
115
133
|
this.totalPages++;
|
|
116
|
-
await this
|
|
134
|
+
await this.#isActivePromise;
|
|
117
135
|
const page = await this._newPage(pageOptions);
|
|
118
136
|
tryCancel();
|
|
119
137
|
this.lastPageOpenedAt = Date.now();
|
|
120
138
|
return page;
|
|
121
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Accounts for a page no longer being open. Callable from either side and safe to call twice:
|
|
142
|
+
* the page's own `close` event, or the pool when it gives up on a close that never settles.
|
|
143
|
+
* Tracked in a `WeakSet` rather than via `isClosed()`, because that reports the same event.
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
registerPageClosed(page) {
|
|
147
|
+
if (this.#closedPages.has(page))
|
|
148
|
+
return;
|
|
149
|
+
this.#closedPages.add(page);
|
|
150
|
+
this.activePages--;
|
|
151
|
+
const teardown = this.#pageTeardowns.get(page);
|
|
152
|
+
if (!teardown)
|
|
153
|
+
return;
|
|
154
|
+
this.#pageTeardowns.delete(page);
|
|
155
|
+
teardown().catch((error) => {
|
|
156
|
+
this.log.debug(`Could not clean up after a closed page.\nCause:${error.message}`, { id: this.id });
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Registers cleanup belonging to a single page: an anonymizing proxy server, an incognito
|
|
161
|
+
* context. It runs from `registerPageClosed`, so it happens whether the page closed on its own
|
|
162
|
+
* or the pool gave up on a close that never settled, and it runs at most once.
|
|
163
|
+
*
|
|
164
|
+
* Hanging it off the page's `close` event instead leaks it in exactly the case this controller
|
|
165
|
+
* now handles, because that event does not arrive for a page the browser never destroyed.
|
|
166
|
+
* @ignore
|
|
167
|
+
*/
|
|
168
|
+
registerPageTeardown(page, teardown) {
|
|
169
|
+
this.#pageTeardowns.set(page, teardown);
|
|
170
|
+
}
|
|
122
171
|
async setCookies(page, cookies) {
|
|
123
172
|
return this._setCookies(page, cookies);
|
|
124
173
|
}
|
|
@@ -12,8 +12,6 @@ import type { BrowserController } from './browser-controller.js';
|
|
|
12
12
|
* - without using a fingerprint,
|
|
13
13
|
* - without specifying a user agent.
|
|
14
14
|
* Last updated on 2022-05-05.
|
|
15
|
-
*
|
|
16
|
-
* After you update it here, please update it also in jsdom-crawler.ts
|
|
17
15
|
*/
|
|
18
16
|
export declare const DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36";
|
|
19
17
|
/**
|
|
@@ -83,7 +81,14 @@ export interface CreateLaunchContextOptions<Library extends CommonLibrary, Libra
|
|
|
83
81
|
* feed them to {@link BrowserPool} for use.
|
|
84
82
|
*/
|
|
85
83
|
export declare abstract class BrowserPlugin<Library extends CommonLibrary = CommonLibrary, LibraryOptions extends Dictionary | undefined = Parameters<Library['launch']>[0], LaunchResult extends CommonBrowser = UnwrapPromise<ReturnType<Library['launch']>>, NewPageOptions = Parameters<LaunchResult['newPage']>[0], NewPageResult = UnwrapPromise<ReturnType<LaunchResult['newPage']>>> {
|
|
84
|
+
#private;
|
|
86
85
|
readonly name: string;
|
|
86
|
+
/**
|
|
87
|
+
* Kept `protected` rather than `#private` because the concrete plugins in this package are separate
|
|
88
|
+
* classes — an ES private field would not be visible to them.
|
|
89
|
+
*
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
87
92
|
protected readonly log: CrawleeLogger;
|
|
88
93
|
readonly library: Library;
|
|
89
94
|
readonly launchOptions: LibraryOptions;
|
|
@@ -119,7 +124,7 @@ export declare abstract class BrowserPlugin<Library extends CommonLibrary = Comm
|
|
|
119
124
|
* Subclasses implement only the `connect` callback — the resolve / token / release / error-wrap scaffolding
|
|
120
125
|
* lives here so it stays identical across plugins.
|
|
121
126
|
*/
|
|
122
|
-
protected
|
|
127
|
+
protected connectToRemoteBrowser(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>, connect: (url: string) => Promise<LaunchResult>): Promise<LaunchResult>;
|
|
123
128
|
/**
|
|
124
129
|
* Creates a `LaunchContext` with all the information needed
|
|
125
130
|
* to launch a browser. Aside from library specific launch options,
|
|
@@ -132,16 +137,9 @@ export declare abstract class BrowserPlugin<Library extends CommonLibrary = Comm
|
|
|
132
137
|
* Launches the browser using provided launch context.
|
|
133
138
|
*/
|
|
134
139
|
launch(launchContext?: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): Promise<LaunchResult>;
|
|
135
|
-
|
|
136
|
-
protected
|
|
137
|
-
|
|
138
|
-
* @private
|
|
139
|
-
*/
|
|
140
|
-
protected abstract _addProxyToLaunchOptions(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): Promise<void>;
|
|
141
|
-
protected abstract _isChromiumBasedBrowser(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): boolean;
|
|
142
|
-
/**
|
|
143
|
-
* @private
|
|
144
|
-
*/
|
|
140
|
+
protected throwAugmentedLaunchError(cause: unknown, executablePath: string | undefined, dockerImage: string, moduleInstallCommand: string): never;
|
|
141
|
+
protected abstract addProxyToLaunchOptions(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): Promise<void>;
|
|
142
|
+
protected abstract isChromiumBasedBrowser(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): boolean;
|
|
145
143
|
protected abstract _launch(launchContext: LaunchContext<Library, LibraryOptions, LaunchResult, NewPageOptions, NewPageResult>): Promise<LaunchResult>;
|
|
146
144
|
}
|
|
147
145
|
export declare class BrowserLaunchError extends CriticalError {
|
|
@@ -9,8 +9,6 @@ import { sanitizeEndpointForLog } from '../utils.js';
|
|
|
9
9
|
* - without using a fingerprint,
|
|
10
10
|
* - without specifying a user agent.
|
|
11
11
|
* Last updated on 2022-05-05.
|
|
12
|
-
*
|
|
13
|
-
* After you update it here, please update it also in jsdom-crawler.ts
|
|
14
12
|
*/
|
|
15
13
|
export const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36';
|
|
16
14
|
/**
|
|
@@ -21,6 +19,12 @@ export const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_
|
|
|
21
19
|
*/
|
|
22
20
|
export class BrowserPlugin {
|
|
23
21
|
name = this.constructor.name;
|
|
22
|
+
/**
|
|
23
|
+
* Kept `protected` rather than `#private` because the concrete plugins in this package are separate
|
|
24
|
+
* classes — an ES private field would not be visible to them.
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
24
28
|
log;
|
|
25
29
|
library;
|
|
26
30
|
launchOptions;
|
|
@@ -69,7 +73,7 @@ export class BrowserPlugin {
|
|
|
69
73
|
* Subclasses implement only the `connect` callback — the resolve / token / release / error-wrap scaffolding
|
|
70
74
|
* lives here so it stays identical across plugins.
|
|
71
75
|
*/
|
|
72
|
-
async
|
|
76
|
+
async connectToRemoteBrowser(launchContext, connect) {
|
|
73
77
|
const connection = this.remoteConnection;
|
|
74
78
|
let url;
|
|
75
79
|
let token;
|
|
@@ -79,7 +83,7 @@ export class BrowserPlugin {
|
|
|
79
83
|
catch (cause) {
|
|
80
84
|
throw new BrowserLaunchError('Failed to resolve the remote browser endpoint.', { cause });
|
|
81
85
|
}
|
|
82
|
-
launchContext.
|
|
86
|
+
launchContext.remoteToken = token;
|
|
83
87
|
try {
|
|
84
88
|
return await connect(url);
|
|
85
89
|
}
|
|
@@ -117,11 +121,11 @@ export class BrowserPlugin {
|
|
|
117
121
|
launchContext.launchOptions ??= {};
|
|
118
122
|
const { proxyUrl, launchOptions } = launchContext;
|
|
119
123
|
if (proxyUrl && !launchContext.isRemote) {
|
|
120
|
-
await this.
|
|
124
|
+
await this.addProxyToLaunchOptions(launchContext);
|
|
121
125
|
}
|
|
122
|
-
if (!launchContext.isRemote && this.
|
|
126
|
+
if (!launchContext.isRemote && this.isChromiumBasedBrowser(launchContext)) {
|
|
123
127
|
// This will set the args for chromium based browsers to hide the webdriver.
|
|
124
|
-
launchOptions.args = this
|
|
128
|
+
launchOptions.args = this.#mergeArgsToHideWebdriver(launchOptions.args);
|
|
125
129
|
// When User-Agent is not set, and we're using Chromium in headless mode,
|
|
126
130
|
// it is better to use DEFAULT_USER_AGENT to reduce chance of detection,
|
|
127
131
|
// as otherwise 'HeadlessChrome' is present in User-Agent string.
|
|
@@ -135,7 +139,7 @@ export class BrowserPlugin {
|
|
|
135
139
|
}
|
|
136
140
|
return this._launch(launchContext);
|
|
137
141
|
}
|
|
138
|
-
|
|
142
|
+
#mergeArgsToHideWebdriver(originalArgs) {
|
|
139
143
|
if (!originalArgs?.length) {
|
|
140
144
|
return ['--disable-blink-features=AutomationControlled'];
|
|
141
145
|
}
|
|
@@ -148,7 +152,7 @@ export class BrowserPlugin {
|
|
|
148
152
|
}
|
|
149
153
|
return originalArgs;
|
|
150
154
|
}
|
|
151
|
-
|
|
155
|
+
throwAugmentedLaunchError(cause, executablePath, dockerImage, moduleInstallCommand) {
|
|
152
156
|
const errorMessage = ['Failed to launch browser. Please check the following:'];
|
|
153
157
|
if (executablePath) {
|
|
154
158
|
errorMessage.push(`- Check whether the provided executable path "${executablePath}" is correct.`);
|
package/anonymize-proxy.d.ts
CHANGED
package/browser-pool.d.ts
CHANGED
|
@@ -248,34 +248,21 @@ export interface BrowserPoolHooks<BC extends BrowserController, LC extends Launc
|
|
|
248
248
|
* ```
|
|
249
249
|
*/
|
|
250
250
|
export declare class BrowserPool<Options extends BrowserPoolOptions = BrowserPoolOptions, BrowserPlugins extends BrowserPlugin[] = InferBrowserPluginArray<Options['browserPlugins']>, BrowserControllerReturn extends BrowserController = ReturnType<BrowserPlugins[number]['createController']>, LaunchContextReturn extends LaunchContext = ReturnType<BrowserPlugins[number]['createLaunchContext']>, PageOptions = Parameters<BrowserControllerReturn['newPage']>[0], PageReturn extends UnwrapPromise<ReturnType<BrowserControllerReturn['newPage']>> = UnwrapPromise<ReturnType<BrowserControllerReturn['newPage']>>> extends TypedEmitter<BrowserPoolEvents<BrowserControllerReturn, PageReturn>> implements IBrowserPool<PageReturn> {
|
|
251
|
+
#private;
|
|
251
252
|
browserPlugins: BrowserPlugins;
|
|
252
|
-
|
|
253
|
+
/** @internal */
|
|
253
254
|
maxOpenBrowsers: number;
|
|
254
|
-
|
|
255
|
-
operationTimeoutMillis: number;
|
|
256
|
-
closeInactiveBrowserAfterMillis: number;
|
|
257
|
-
useFingerprints?: boolean;
|
|
255
|
+
/** @internal */
|
|
258
256
|
fingerprintOptions: FingerprintOptions;
|
|
259
|
-
|
|
260
|
-
postLaunchHooks: PostLaunchHook<BrowserControllerReturn>[];
|
|
261
|
-
prePageCreateHooks: PrePageCreateHook<BrowserControllerReturn, PageOptions>[];
|
|
262
|
-
postPageCreateHooks: PostPageCreateHook<BrowserControllerReturn, PageReturn>[];
|
|
263
|
-
prePageCloseHooks: PrePageCloseHook<BrowserControllerReturn, PageReturn>[];
|
|
264
|
-
postPageCloseHooks: PostPageCloseHook<BrowserControllerReturn>[];
|
|
265
|
-
pageCounter: number;
|
|
266
|
-
pages: Map<string, PageReturn>;
|
|
267
|
-
pageIds: WeakMap<PageReturn, string>;
|
|
268
|
-
startingBrowserControllers: Set<BrowserControllerReturn>;
|
|
269
|
-
activeBrowserControllers: Set<BrowserControllerReturn>;
|
|
270
|
-
retiredBrowserControllers: Set<BrowserControllerReturn>;
|
|
271
|
-
pageToBrowserController: WeakMap<PageReturn, BrowserControllerReturn>;
|
|
257
|
+
/** @internal */
|
|
272
258
|
fingerprintInjector?: FingerprintInjector;
|
|
273
259
|
fingerprintGenerator?: FingerprintGenerator;
|
|
260
|
+
/** @internal */
|
|
274
261
|
fingerprintCache?: QuickLRU<string, BrowserFingerprintWithHeaders>;
|
|
262
|
+
private pages;
|
|
263
|
+
private activeBrowserControllers;
|
|
264
|
+
private retiredBrowserControllers;
|
|
275
265
|
private browserKillerInterval?;
|
|
276
|
-
private browserRetireInterval?;
|
|
277
|
-
private limiter;
|
|
278
|
-
private log;
|
|
279
266
|
constructor(options: Options & BrowserPoolHooks<BrowserControllerReturn, LaunchContextReturn, PageReturn>);
|
|
280
267
|
/**
|
|
281
268
|
* Opens a new page in one of the running browsers or launches
|
|
@@ -350,7 +337,6 @@ export declare class BrowserPool<Options extends BrowserPoolOptions = BrowserPoo
|
|
|
350
337
|
* until it's closed.
|
|
351
338
|
*/
|
|
352
339
|
getPageId(page: PageReturn): string | undefined;
|
|
353
|
-
private _createPageForBrowser;
|
|
354
340
|
/**
|
|
355
341
|
* Removes a browser controller from the pool. The underlying
|
|
356
342
|
* browser will be closed after all its pages are closed.
|
|
@@ -364,8 +350,9 @@ export declare class BrowserPool<Options extends BrowserPoolOptions = BrowserPoo
|
|
|
364
350
|
retireBrowserByPage(page: PageReturn): void;
|
|
365
351
|
/**
|
|
366
352
|
* Releases a page back to the pool. The page is closed and, if the
|
|
367
|
-
* optional `error` is a {@link SessionError}
|
|
368
|
-
*
|
|
353
|
+
* optional `error` is a {@link SessionError} (including
|
|
354
|
+
* {@link SessionRetiredError}), the browser controller that served
|
|
355
|
+
* the page is retired so that the finished session's state (cookies,
|
|
369
356
|
* storage, etc.) cannot leak into future sessions.
|
|
370
357
|
*
|
|
371
358
|
* This is the primary way the crawler should return pages to the pool.
|
|
@@ -409,34 +396,36 @@ export declare class BrowserPool<Options extends BrowserPoolOptions = BrowserPoo
|
|
|
409
396
|
* @return {Promise<void>}
|
|
410
397
|
*/
|
|
411
398
|
closeAllBrowsers(): Promise<void>;
|
|
399
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
412
400
|
/**
|
|
413
|
-
* Closes
|
|
401
|
+
* Closes every managed browser and empties the pool, which stays usable afterwards — a crawler releases its
|
|
402
|
+
* browsers when a run ends and may start another run on the same pool.
|
|
414
403
|
*/
|
|
415
|
-
|
|
416
|
-
private _teardown;
|
|
417
|
-
private _getAllBrowserControllers;
|
|
418
|
-
private _launchBrowser;
|
|
404
|
+
releaseAllBrowsers(): Promise<void>;
|
|
419
405
|
/**
|
|
420
|
-
*
|
|
421
|
-
*
|
|
406
|
+
* Closes all managed browsers and tears the pool down for good: its intervals are cleared without being
|
|
407
|
+
* re-armed and its listeners are dropped, so it cannot be used again.
|
|
422
408
|
*/
|
|
423
|
-
|
|
424
|
-
private
|
|
425
|
-
private _closeInactiveRetiredBrowsers;
|
|
426
|
-
private _overridePageClose;
|
|
427
|
-
private _executeHooks;
|
|
428
|
-
private _closeRetiredBrowserWithNoPages;
|
|
409
|
+
destroy(): Promise<void>;
|
|
410
|
+
private closeInactiveRetiredBrowsers;
|
|
429
411
|
/**
|
|
430
|
-
* Returns `true` if the pool can accept a new browser launch without exceeding
|
|
431
|
-
*
|
|
412
|
+
* Returns `true` if the pool can accept a new browser launch without exceeding `maxOpenBrowsers`.
|
|
413
|
+
* Counts starting, active, and retired browsers.
|
|
414
|
+
*
|
|
415
|
+
* A plain `BrowserPool` leaves `maxOpenBrowsers` at `Infinity`, so this only returns `false` when something
|
|
416
|
+
* has set a cap — {@link RemoteBrowserPool} does, from its own
|
|
417
|
+
* {@link RemoteBrowserPoolOptions.maxOpenBrowsers|`maxOpenBrowsers`} option. There is no
|
|
418
|
+
* `BrowserPoolOptions` key for it.
|
|
419
|
+
*
|
|
420
|
+
* @internal
|
|
432
421
|
*/
|
|
433
422
|
hasFreeBrowserSlot(): boolean;
|
|
434
423
|
/**
|
|
435
424
|
* Returns `true` if any active browser has room for another page.
|
|
425
|
+
*
|
|
426
|
+
* @internal
|
|
436
427
|
*/
|
|
437
428
|
hasActiveBrowserWithFreeCapacity(): boolean;
|
|
438
|
-
private _initializeFingerprinting;
|
|
439
|
-
private _addFingerprintHooks;
|
|
440
429
|
}
|
|
441
430
|
export interface BrowserPoolNewPageOptions<PageOptions, BP extends BrowserPlugin> extends NewPageOptions {
|
|
442
431
|
/**
|