@crawlee/browser 4.0.0-beta.80 → 4.0.0-beta.82

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.
@@ -31,8 +31,8 @@ export interface BrowserCrawlingContext<Page extends CommonPage = CommonPage, Re
31
31
  */
32
32
  enqueueLinks: (options?: EnqueueLinksOptions) => Promise<BatchAddRequestsResult>;
33
33
  }
34
- export type BrowserHook<Context = BrowserCrawlingContext> = (crawlingContext: Context) => Awaitable<void | Partial<Context>>;
35
- export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Response extends BaseResponse = BaseResponse, Context extends BrowserCrawlingContext<Page, Response, Dictionary> = BrowserCrawlingContext<Page, Response, Dictionary>, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, __BrowserPlugins extends BrowserPlugin[] = InferBrowserPluginArray<InternalBrowserPoolOptions['browserPlugins']>, __BrowserControllerReturn extends BrowserController = ReturnType<__BrowserPlugins[number]['createController']>, __LaunchContextReturn extends LaunchContext = ReturnType<__BrowserPlugins[number]['createLaunchContext']>> extends Omit<BasicCrawlerOptions<Context, ExtendedContext>, 'requestHandler' | 'failedRequestHandler' | 'errorHandler'> {
34
+ export type BrowserHook<Context = BrowserCrawlingContext, ContextExtension = {}> = (crawlingContext: Context & ContextExtension) => Awaitable<void | Partial<Context>>;
35
+ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Response extends BaseResponse = BaseResponse, Context extends BrowserCrawlingContext<Page, Response, Dictionary> = BrowserCrawlingContext<Page, Response, Dictionary>, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, __BrowserPlugins extends BrowserPlugin[] = InferBrowserPluginArray<InternalBrowserPoolOptions['browserPlugins']>, __BrowserControllerReturn extends BrowserController = ReturnType<__BrowserPlugins[number]['createController']>, __LaunchContextReturn extends LaunchContext = ReturnType<__BrowserPlugins[number]['createLaunchContext']>> extends Omit<BasicCrawlerOptions<Context, ContextExtension, ExtendedContext>, 'requestHandler' | 'failedRequestHandler' | 'errorHandler'> {
36
36
  launchContext?: BrowserLaunchContext<any, any>;
37
37
  /**
38
38
  * An existing browser pool instance to use. When provided, the crawler will use this pool directly instead of
@@ -124,8 +124,13 @@ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Res
124
124
  *
125
125
  * A hook may optionally return a partial object whose properties are merged into the crawling context,
126
126
  * allowing the hook to override context members for subsequent hooks and pipeline stages.
127
+ *
128
+ * The context is built up in the following order: base context (`request`, `session`, helpers, ...) ->
129
+ * `extendContext` -> `preNavigationHooks` -> navigation -> `postNavigationHooks` -> `requestHandler`.
130
+ * This means the members added by `extendContext` are already available here, but navigation-dependent
131
+ * members (e.g. `page`, `response`) are not.
127
132
  */
128
- preNavigationHooks?: BrowserHook<Context>[];
133
+ preNavigationHooks?: BrowserHook<Context, ContextExtension>[];
129
134
  /**
130
135
  * Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
131
136
  * The function accepts `crawlingContext` as the only parameter.
@@ -151,7 +156,7 @@ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Res
151
156
  * ]
152
157
  * ```
153
158
  */
154
- postNavigationHooks?: BrowserHook<Context>[];
159
+ postNavigationHooks?: BrowserHook<Context, ContextExtension>[];
155
160
  /**
156
161
  * Timeout in which page navigation needs to finish, in seconds.
157
162
  */
@@ -233,10 +238,10 @@ export declare abstract class BrowserCrawler<Page extends CommonPage = CommonPag
233
238
  launchContext: BrowserLaunchContext<LaunchOptions, unknown>;
234
239
  protected readonly ignoreShadowRoots: boolean;
235
240
  protected readonly ignoreIframes: boolean;
236
- protected navigationTimeoutMillis: number;
237
- protected preNavigationHooks: BrowserHook<Context>[];
238
- protected postNavigationHooks: BrowserHook<Context>[];
239
- protected saveResponseCookies: boolean;
241
+ private readonly navigationTimeoutMillis;
242
+ private readonly preNavigationHooks;
243
+ private readonly postNavigationHooks;
244
+ private readonly saveResponseCookies;
240
245
  protected static optionsShape: {
241
246
  // @ts-ignore optional peer dependency or compatibility with es2022
242
247
  navigationTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
@@ -333,22 +338,22 @@ export declare abstract class BrowserCrawler<Page extends CommonPage = CommonPag
333
338
  });
334
339
  protected buildContextPipeline(): ContextPipeline<CrawlingContext, BrowserCrawlingContext<Page, Response, Dictionary>>;
335
340
  private containsSelectors;
336
- protected isRequestBlocked(crawlingContext: BrowserCrawlingContext<Page, Response>): Promise<string | false>;
341
+ private isRequestBlocked;
337
342
  private preparePage;
338
343
  private prepareNavigation;
339
344
  private navigate;
340
345
  private finalizeNavigation;
341
346
  private handleBlockedRequestByContent;
342
347
  private restoreRequestState;
343
- protected _applyCookies({ session, request, page }: BrowserCrawlingContext<Page, Response>, preHooksCookies: string, postHooksCookies: string): Promise<void>;
348
+ private applyCookies;
344
349
  /**
345
350
  * Marks session bad on navigation timeout, and stops in-flight page loading on any navigation error.
346
351
  */
347
- protected _handleNavigationTimeout(crawlingContext: BrowserCrawlingContext, error: Error): Promise<void>;
352
+ private handleNavigationTimeout;
348
353
  /**
349
354
  * Transforms proxy-related errors to `SessionError`.
350
355
  */
351
- protected _throwIfProxyError(error: Error): void;
356
+ private throwIfProxyError;
352
357
  protected abstract _navigationHandler(crawlingContext: BrowserCrawlingContext<Page, Response>, gotoOptions: GoToOptions): Promise<Context['response'] | null | undefined>;
353
358
  private processResponse;
354
359
  /**
@@ -104,10 +104,13 @@ export class BrowserCrawler extends BasicCrawler {
104
104
  .compose({ action: this.handleBlockedRequestByContent.bind(this) })
105
105
  .compose({ action: this.restoreRequestState.bind(this) });
106
106
  },
107
- extendContext: extendContext,
107
+ extendContext,
108
108
  });
109
109
  this.launchContext = launchContext;
110
110
  this.navigationTimeoutMillis = navigationTimeoutSecs * 1000;
111
+ // The public option hooks are extension-aware; internal storage uses the base context type
112
+ // (the pipeline composes hooks against the concrete context, which does not statically carry
113
+ // `ContextExtension`). The extension members are present at runtime regardless.
111
114
  this.preNavigationHooks = preNavigationHooks;
112
115
  this.postNavigationHooks = postNavigationHooks;
113
116
  this.ignoreIframes = ignoreIframes;
@@ -247,15 +250,15 @@ export class BrowserCrawler extends BasicCrawler {
247
250
  const gotoOptions = crawlingContext.gotoOptions;
248
251
  const cookiesBeforeHooks = readContextField(crawlingContext, COOKIES_BEFORE_HOOKS);
249
252
  const cookiesAfterHooks = this._getCookieHeaderFromRequest(crawlingContext.request);
250
- await this._applyCookies(crawlingContext, cookiesBeforeHooks, cookiesAfterHooks);
253
+ await this.applyCookies(crawlingContext, cookiesBeforeHooks, cookiesAfterHooks);
251
254
  let response;
252
255
  try {
253
256
  response = (await this._navigationHandler(crawlingContext, gotoOptions)) ?? undefined;
254
257
  }
255
258
  catch (error) {
256
- await this._handleNavigationTimeout(crawlingContext, error);
259
+ await this.handleNavigationTimeout(crawlingContext, error);
257
260
  crawlingContext.request.state = RequestState.ERROR;
258
- this._throwIfProxyError(error);
261
+ this.throwIfProxyError(error);
259
262
  throw error;
260
263
  }
261
264
  tryCancel();
@@ -304,7 +307,7 @@ export class BrowserCrawler extends BasicCrawler {
304
307
  crawlingContext.request.state = RequestState.REQUEST_HANDLER;
305
308
  return {};
306
309
  }
307
- async _applyCookies({ session, request, page }, preHooksCookies, postHooksCookies) {
310
+ async applyCookies({ session, request, page }, preHooksCookies, postHooksCookies) {
308
311
  const sessionCookie = session?.cookieJar.getCookiesSync(request.url).map(toughCookieToBrowserPoolCookie) ?? [];
309
312
  const parsedPreHooksCookies = preHooksCookies.split(/ *; */).map((c) => cookieStringToToughCookie(c));
310
313
  const parsedPostHooksCookies = postHooksCookies.split(/ *; */).map((c) => cookieStringToToughCookie(c));
@@ -316,7 +319,7 @@ export class BrowserCrawler extends BasicCrawler {
316
319
  /**
317
320
  * Marks session bad on navigation timeout, and stops in-flight page loading on any navigation error.
318
321
  */
319
- async _handleNavigationTimeout(crawlingContext, error) {
322
+ async handleNavigationTimeout(crawlingContext, error) {
320
323
  const { session, page } = crawlingContext;
321
324
  if (error?.constructor.name === 'TimeoutError') {
322
325
  handleRequestTimeout({ session, errorMessage: error.message });
@@ -328,7 +331,7 @@ export class BrowserCrawler extends BasicCrawler {
328
331
  /**
329
332
  * Transforms proxy-related errors to `SessionError`.
330
333
  */
331
- _throwIfProxyError(error) {
334
+ throwIfProxyError(error) {
332
335
  if (this.isProxyError(error)) {
333
336
  throw new SessionError(this._getMessageFromError(error));
334
337
  }
@@ -110,11 +110,11 @@ export declare abstract class BrowserLauncher<Plugin extends BrowserPlugin, Laun
110
110
  */
111
111
  launch(): LaunchResult;
112
112
  createLaunchOptions(): Dictionary;
113
- protected _getDefaultHeadlessOption(): boolean;
114
- protected _getChromeExecutablePath(): string;
113
+ protected getDefaultHeadlessOption(): boolean;
114
+ private getChromeExecutablePath;
115
115
  /**
116
116
  * Gets a typical path to Chrome executable, depending on the current operating system.
117
117
  */
118
- protected _getTypicalChromeExecutablePath(): string;
119
- protected _validateProxyUrlProtocol(proxyUrl?: string): void;
118
+ private getTypicalChromeExecutablePath;
119
+ private validateProxyUrlProtocol;
120
120
  }
@@ -54,7 +54,7 @@ export class BrowserLauncher {
54
54
  constructor(launchContext, config = Configuration.getGlobalConfig()) {
55
55
  this.config = config;
56
56
  const { launcher, proxyUrl, useChrome, userAgent, launchOptions = {}, ...otherLaunchContextProps } = launchContext;
57
- this._validateProxyUrlProtocol(proxyUrl);
57
+ this.validateProxyUrlProtocol(proxyUrl);
58
58
  // those need to be reassigned otherwise they are {} in types
59
59
  this.launcher = launcher;
60
60
  this.proxyUrl = proxyUrl;
@@ -95,23 +95,23 @@ export class BrowserLauncher {
95
95
  launchOptions.args.push(`--user-agent=${this.userAgent}`);
96
96
  }
97
97
  if (launchOptions.headless == null) {
98
- launchOptions.headless = this._getDefaultHeadlessOption();
98
+ launchOptions.headless = this.getDefaultHeadlessOption();
99
99
  }
100
100
  if (this.useChrome && !launchOptions.executablePath) {
101
- launchOptions.executablePath = this._getChromeExecutablePath();
101
+ launchOptions.executablePath = this.getChromeExecutablePath();
102
102
  }
103
103
  return launchOptions;
104
104
  }
105
- _getDefaultHeadlessOption() {
105
+ getDefaultHeadlessOption() {
106
106
  return this.config.headless && !this.config.xvfb;
107
107
  }
108
- _getChromeExecutablePath() {
109
- return this.config.chromeExecutablePath ?? this._getTypicalChromeExecutablePath();
108
+ getChromeExecutablePath() {
109
+ return this.config.chromeExecutablePath ?? this.getTypicalChromeExecutablePath();
110
110
  }
111
111
  /**
112
112
  * Gets a typical path to Chrome executable, depending on the current operating system.
113
113
  */
114
- _getTypicalChromeExecutablePath() {
114
+ getTypicalChromeExecutablePath() {
115
115
  /**
116
116
  * Returns path of Chrome executable by its OS environment variable to deal with non-english language OS.
117
117
  * Taking also into account the old [chrome 380177 issue](https://bugs.chromium.org/p/chromium/issues/detail?id=380177).
@@ -139,7 +139,7 @@ export class BrowserLauncher {
139
139
  return '/usr/bin/google-chrome';
140
140
  }
141
141
  }
142
- _validateProxyUrlProtocol(proxyUrl) {
142
+ validateProxyUrlProtocol(proxyUrl) {
143
143
  if (!proxyUrl)
144
144
  return;
145
145
  if (!/^(http|https|socks4|socks5)/i.test(proxyUrl)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/browser",
3
- "version": "4.0.0-beta.80",
3
+ "version": "4.0.0-beta.82",
4
4
  "description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
5
5
  "engines": {
6
6
  "node": ">=22.0.0"
@@ -48,10 +48,10 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@apify/timeout": "^0.3.2",
51
- "@crawlee/basic": "4.0.0-beta.80",
52
- "@crawlee/browser-pool": "4.0.0-beta.80",
53
- "@crawlee/types": "4.0.0-beta.80",
54
- "@crawlee/utils": "4.0.0-beta.80",
51
+ "@crawlee/basic": "4.0.0-beta.82",
52
+ "@crawlee/browser-pool": "4.0.0-beta.82",
53
+ "@crawlee/types": "4.0.0-beta.82",
54
+ "@crawlee/utils": "4.0.0-beta.82",
55
55
  "ow": "^2.0.0",
56
56
  "tslib": "^2.8.1",
57
57
  "type-fest": "^4.41.0"
@@ -75,5 +75,5 @@
75
75
  }
76
76
  }
77
77
  },
78
- "gitHead": "96c57b4a0c999e4b2bd198792490af28db7aa42d"
78
+ "gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
79
79
  }