@crawlee/basic 4.0.0-beta.80 → 4.0.0-beta.81

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.
@@ -1,4 +1,4 @@
1
- import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, AutoscaledPoolOptions, Configuration, CrawleeLogger, CrawlingContext, DatasetExportOptions, EnqueueLinksOptions, EventManager, FinalStatistics, GetUserDataFromRequest, IRequestLoader, IRequestManager, ProxyConfiguration, Request, RequestsLike, RouterHandler, RouterRoutes, SkippedRequestCallback, Source, StatisticsOptions, StatisticState, StorageIdentifier } from '@crawlee/core';
1
+ import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, AutoscaledPoolOptions, Configuration, CrawleeLogger, CrawlingContext, DatasetExportOptions, EnqueueLinksOptions, EventManager, FinalStatistics, GetUserDataFromRequest, IProxyConfiguration, IRequestLoader, IRequestManager, Request, RequestsLike, RouterHandler, RouterRoutes, SkippedRequestCallback, Source, StatisticsOptions, StatisticState, StorageIdentifier } from '@crawlee/core';
2
2
  import { AutoscaledPool, ContextPipeline, Dataset, RequestQueue, Statistics } from '@crawlee/core';
3
3
  import type { Awaitable, BaseHttpClient, BatchAddRequestsResult, Dictionary, ISession, ISessionPool, ProxyInfo, SetStatusMessageOptions, StorageBackend } from '@crawlee/types';
4
4
  import { RobotsTxtFile } from '@crawlee/utils';
@@ -252,7 +252,7 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
252
252
  * If set, the crawler will be configured for all connections to use
253
253
  * the Proxy URLs provided and rotated according to the configuration.
254
254
  */
255
- proxyConfiguration?: ProxyConfiguration;
255
+ proxyConfiguration?: IProxyConfiguration;
256
256
  /**
257
257
  * Custom configuration to use for this crawler.
258
258
  * If provided, the crawler will use its own ServiceLocator instance instead of the global one.
@@ -409,7 +409,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
409
409
  * A reference to the underlying session pool that manages the crawler's {@link Session|sessions}. Typed as
410
410
  * {@link ISessionPool} so custom implementations can be plugged in via the `sessionPool` constructor option.
411
411
  */
412
- sessionPool: ISessionPool;
412
+ readonly sessionPool: ISessionPool;
413
413
  /**
414
414
  * Set when the crawler constructed its own {@link SessionPool} (no `sessionPool` option was provided).
415
415
  * Holds the same instance as `sessionPool`, but typed as the concrete class so the crawler can call
@@ -438,10 +438,10 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
438
438
  */
439
439
  autoscaledPool?: AutoscaledPool;
440
440
  /**
441
- * A reference to the underlying {@link ProxyConfiguration} class that manages the crawler's proxies.
441
+ * A reference to the underlying {@link IProxyConfiguration} instance that manages the crawler's proxies.
442
442
  * Only available if used by the crawler.
443
443
  */
444
- proxyConfiguration?: ProxyConfiguration;
444
+ readonly proxyConfiguration?: IProxyConfiguration;
445
445
  /**
446
446
  * Default {@link Router} instance that will be used if we don't specify any {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
447
447
  * See {@link Router.addHandler|`router.addHandler()`} and {@link Router.addDefaultHandler|`router.addDefaultHandler()`}.
@@ -463,33 +463,29 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
463
463
  get contextPipeline(): ContextPipeline<CrawlingContext, ExtendedContext>;
464
464
  running: boolean;
465
465
  hasFinishedBefore: boolean;
466
- protected unexpectedStop: boolean;
466
+ private unexpectedStop;
467
467
  get log(): CrawleeLogger;
468
- protected requestHandler: RequestHandler<ExtendedContext>;
469
- protected errorHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
470
- protected failedRequestHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
471
- protected requestHandlerTimeoutMillis: number;
472
- protected internalTimeoutMillis: number;
473
- protected maxRequestRetries: number;
474
- protected maxCrawlDepth?: number;
475
- protected sameDomainDelayMillis: number;
476
- protected domainAccessedTime: Map<string, number>;
477
- protected maxRequestsPerCrawl?: number;
478
- protected get handledRequestsCount(): number;
479
- /** @deprecated Setting `handledRequestsCount` directly is no longer supported. The count is now derived from `this.stats`. */
480
- protected set handledRequestsCount(_value: number);
481
- protected statusMessageLoggingInterval: number;
482
- protected statusMessageCallback?: StatusMessageCallback;
468
+ protected readonly requestHandler: RequestHandler<ExtendedContext>;
469
+ protected readonly errorHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
470
+ protected readonly failedRequestHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
471
+ private requestHandlerTimeoutMillis;
472
+ protected readonly internalTimeoutMillis: number;
473
+ protected readonly maxRequestRetries: number;
474
+ protected readonly maxCrawlDepth?: number;
475
+ private sameDomainDelayMillis;
476
+ private domainAccessedTime;
477
+ protected readonly maxRequestsPerCrawl?: number;
478
+ private get handledRequestsCount();
479
+ private statusMessageLoggingInterval;
480
+ private statusMessageCallback?;
483
481
  protected blockedStatusCodes: Set<number>;
484
- protected additionalHttpErrorStatusCodes: Set<number>;
485
- protected ignoreHttpErrorStatusCodes: Set<number>;
486
- protected autoscaledPoolOptions: AutoscaledPoolOptions;
487
- protected httpClient: BaseHttpClient;
488
- protected retryOnBlocked: boolean;
489
- protected respectRobotsTxtFile: boolean | {
490
- userAgent?: string;
491
- };
492
- protected onSkippedRequest?: SkippedRequestCallback;
482
+ protected readonly additionalHttpErrorStatusCodes: Set<number>;
483
+ private ignoreHttpErrorStatusCodes;
484
+ private autoscaledPoolOptions;
485
+ protected readonly httpClient: BaseHttpClient;
486
+ protected readonly retryOnBlocked: boolean;
487
+ private respectRobotsTxtFile;
488
+ protected readonly onSkippedRequest?: SkippedRequestCallback;
493
489
  private _closeEvents?;
494
490
  private loggedPerRun;
495
491
  private readonly robotsTxtFileCache;
@@ -580,9 +576,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
580
576
  * Builds the basic context pipeline that transforms `{ request }` into a full `CrawlingContext`.
581
577
  * This handles base context creation, session resolution, and context helpers.
582
578
  */
583
- protected buildBasicContextPipeline(): ContextPipeline<{
584
- request: Request;
585
- }, CrawlingContext>;
579
+ private buildBasicContextPipeline;
586
580
  private checkRobotsTxt;
587
581
  /**
588
582
  * Builds the subclass-specific context pipeline that transforms a `CrawlingContext` into the crawler's target context type.
@@ -662,7 +656,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
662
656
  * the request's label. Applied by the crawler on the add paths it owns — `crawler.addRequests`,
663
657
  * `crawler.run`, `context.addRequests` and `context.enqueueLinks`.
664
658
  */
665
- protected validateRequestUserData(source: Source | string): Promise<void>;
659
+ private validateRequestUserData;
666
660
  useState<State extends Dictionary = Dictionary>(defaultValue?: State): Promise<State>;
667
661
  protected getPendingRequestCountApproximation(): Promise<number>;
668
662
  protected calculateEnqueuedRequestLimit(explicitLimit?: number): Promise<number | undefined>;
@@ -708,19 +702,19 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
708
702
  protected _throwOnBlockedRequest(statusCode: number): void;
709
703
  private isAllowedBasedOnRobotsTxtFile;
710
704
  protected getRobotsTxtFileForUrl(url: string): Promise<RobotsTxtFile | undefined>;
711
- protected _pauseOnMigration(): Promise<void>;
705
+ private pauseOnMigration;
712
706
  /**
713
707
  * Fetches the next request to process from the underlying request provider.
714
708
  */
715
- protected _fetchNextRequest(): Promise<Request<Dictionary> | null>;
709
+ private fetchNextRequest;
716
710
  /**
717
711
  * Delays processing of the request based on the `sameDomainDelaySecs` option,
718
712
  * adding it back to the queue after the timeout passes. Returns `true` if the request
719
713
  * should be ignored and will be reclaimed to the queue once ready.
720
714
  */
721
- protected delayRequest(request: Request, source: IRequestManager): boolean;
715
+ private delayRequest;
722
716
  /** Handles a single request - runs the request handler with retries, error handling, and lifecycle management. */
723
- protected handleRequest(crawlingContext: ExtendedContext, requestSource: IRequestManager, request: Request): Promise<void>;
717
+ private handleRequest;
724
718
  /**
725
719
  * Wrapper around the crawling context's `enqueueLinks` method:
726
720
  * - Injects `crawlDepth` to each request being added based on the crawling context request.
@@ -738,15 +732,15 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
738
732
  * Run async callback with given timeout and retry. Returns the result of the callback.
739
733
  * @ignore
740
734
  */
741
- protected _timeoutAndRetry<T>(handler: () => Promise<T>, timeout: number, error: Error | string, maxRetries?: number, retried?: number): Promise<T>;
735
+ private timeoutAndRetry;
742
736
  /**
743
737
  * Returns true if either RequestList or RequestQueue have a request ready for processing.
744
738
  */
745
- protected _isTaskReadyFunction(): Promise<boolean>;
739
+ private isTaskReadyFunction;
746
740
  /**
747
741
  * Returns true if both RequestList and RequestQueue have all requests finished.
748
742
  */
749
- protected _defaultIsFinishedFunction(): Promise<boolean>;
743
+ private defaultIsFinishedFunction;
750
744
  /**
751
745
  * Unwraps errors thrown by the context pipeline to get the actual user error.
752
746
  * RequestHandlerError and ContextPipelineInitializationError wrap the actual error.
@@ -757,16 +751,15 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
757
751
  *
758
752
  * @param request The request object, passed separately to circumvent potential dynamic logic in crawlingContext.request
759
753
  */
760
- protected _requestFunctionErrorHandler(error: Error, crawlingContext: CrawlingContext, request: Request, source: IRequestManager): Promise<void>;
761
- protected _tagUserHandlerError<T>(cb: () => unknown): Promise<T>;
762
- protected _handleFailedRequestHandler(crawlingContext: CrawlingContext, error: Error): Promise<void>;
754
+ private requestFunctionErrorHandler;
755
+ private handleFailedRequestHandler;
763
756
  /**
764
757
  * Resolves the most verbose error message from a thrown error
765
758
  * @param error The error received
766
759
  * @returns The message to be logged
767
760
  */
768
761
  protected _getMessageFromError(error: Error, forceStack?: boolean): string | TimeoutError | undefined;
769
- protected _canRequestBeRetried(request: Request, error: Error): boolean;
762
+ private canRequestBeRetried;
770
763
  /**
771
764
  * Stops the crawler immediately.
772
765
  *
@@ -93,7 +93,7 @@ export class BasicCrawler {
93
93
  */
94
94
  autoscaledPool;
95
95
  /**
96
- * A reference to the underlying {@link ProxyConfiguration} class that manages the crawler's proxies.
96
+ * A reference to the underlying {@link IProxyConfiguration} instance that manages the crawler's proxies.
97
97
  * Only available if used by the crawler.
98
98
  */
99
99
  proxyConfiguration;
@@ -144,11 +144,6 @@ export class BasicCrawler {
144
144
  get handledRequestsCount() {
145
145
  return this.stats.state.requestsFinished + this.stats.state.requestsFailed;
146
146
  }
147
- /** @deprecated Setting `handledRequestsCount` directly is no longer supported. The count is now derived from `this.stats`. */
148
- set handledRequestsCount(_value) {
149
- throw new Error('Setting `handledRequestsCount` directly is no longer supported. ' +
150
- 'The count is now derived from `this.stats.state.requestsFinished` and `this.stats.state.requestsFailed`.');
151
- }
152
147
  statusMessageLoggingInterval;
153
148
  statusMessageCallback;
154
149
  blockedStatusCodes = new Set();
@@ -357,7 +352,7 @@ export class BasicCrawler {
357
352
  // (e.g., doesn't match enqueue strategy after redirect). Just return gracefully.
358
353
  if (error instanceof ContextPipelineInterruptedError) {
359
354
  this.stats.discardJob(request.id || request.uniqueKey);
360
- await this._timeoutAndRetry(async () => this.requestManager?.markRequestAsHandled(request), this.internalTimeoutMillis, `Marking request ${crawlingContext.request.url} (${crawlingContext.request.id}) as handled timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
355
+ await this.timeoutAndRetry(async () => this.requestManager?.markRequestAsHandled(request), this.internalTimeoutMillis, `Marking request ${crawlingContext.request.url} (${crawlingContext.request.id}) as handled timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
361
356
  return;
362
357
  }
363
358
  // If the error happened during pipeline initialization (e.g., navigation timeout, session/proxy error,
@@ -365,8 +360,8 @@ export class BasicCrawler {
365
360
  const isPipelineError = error instanceof ContextPipelineInitializationError || error instanceof SessionError;
366
361
  if (isPipelineError) {
367
362
  const unwrappedError = this.unwrapError(error);
368
- await this._requestFunctionErrorHandler(unwrappedError, crawlingContext, request, this.requestManager);
369
- // SessionError already retired the session in `_requestFunctionErrorHandler`;
363
+ await this.requestFunctionErrorHandler(unwrappedError, crawlingContext, request, this.requestManager);
364
+ // SessionError already retired the session in `requestFunctionErrorHandler`;
370
365
  // skip `markBad` to avoid double-counting usage/error score.
371
366
  if (!(unwrappedError instanceof SessionError)) {
372
367
  crawlingContext.session?.markBad();
@@ -392,7 +387,7 @@ export class BasicCrawler {
392
387
  'Ongoing requests will be allowed to complete.');
393
388
  return false;
394
389
  }
395
- return isTaskReadyFunction ? await isTaskReadyFunction() : await this._isTaskReadyFunction();
390
+ return isTaskReadyFunction ? await isTaskReadyFunction() : await this.isTaskReadyFunction();
396
391
  },
397
392
  isFinishedFunction: async () => {
398
393
  if (isMaxPagesExceeded()) {
@@ -407,7 +402,7 @@ export class BasicCrawler {
407
402
  }
408
403
  const isFinished = isFinishedFunction
409
404
  ? await isFinishedFunction()
410
- : await this._defaultIsFinishedFunction();
405
+ : await this.defaultIsFinishedFunction();
411
406
  if (isFinished) {
412
407
  const reason = isFinishedFunction
413
408
  ? "Crawler's custom isFinishedFunction() returned true, the crawler will shut down."
@@ -481,7 +476,7 @@ export class BasicCrawler {
481
476
  };
482
477
  }
483
478
  async resolveRequest() {
484
- const request = await this._timeoutAndRetry(this._fetchNextRequest.bind(this), this.internalTimeoutMillis, `Fetching next request timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
479
+ const request = await this.timeoutAndRetry(this.fetchNextRequest.bind(this), this.internalTimeoutMillis, `Fetching next request timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
485
480
  // Reset loadedUrl so an old one is not carried over to retries.
486
481
  if (request) {
487
482
  request.loadedUrl = undefined;
@@ -489,7 +484,7 @@ export class BasicCrawler {
489
484
  return request;
490
485
  }
491
486
  async resolveSession({ request }) {
492
- const session = await this._timeoutAndRetry(async () => {
487
+ const session = await this.timeoutAndRetry(async () => {
493
488
  const existingSession = await this.sessionPool.getSession(request.sessionId);
494
489
  if (!existingSession) {
495
490
  throw new ContextPipelineInitializationError(new MissingSessionError(request.sessionId));
@@ -654,11 +649,11 @@ export class BasicCrawler {
654
649
  this.setStatusMessage('Starting the crawler.', { level: 'INFO' });
655
650
  const sigintHandler = async () => {
656
651
  this.log.warning('Pausing... Press CTRL+C again to force exit. To resume, do: CRAWLEE_PURGE_ON_START=0 npm start');
657
- await this._pauseOnMigration();
652
+ await this.pauseOnMigration();
658
653
  await this.autoscaledPool.abort();
659
654
  };
660
655
  // Attach a listener to handle migration and aborting events gracefully.
661
- const boundPauseOnMigration = this._pauseOnMigration.bind(this);
656
+ const boundPauseOnMigration = this.pauseOnMigration.bind(this);
662
657
  process.once('SIGINT', sigintHandler);
663
658
  const eventManager = serviceLocator.getEventManager();
664
659
  eventManager.on("migrating" /* EventType.MIGRATING */, boundPauseOnMigration);
@@ -1021,7 +1016,7 @@ export class BasicCrawler {
1021
1016
  return undefined;
1022
1017
  }
1023
1018
  }
1024
- async _pauseOnMigration() {
1019
+ async pauseOnMigration() {
1025
1020
  if (this.autoscaledPool) {
1026
1021
  // if run wasn't called, this is going to crash
1027
1022
  await this.autoscaledPool.pause(SAFE_MIGRATION_WAIT_MILLIS).catch((err) => {
@@ -1058,9 +1053,9 @@ export class BasicCrawler {
1058
1053
  /**
1059
1054
  * Fetches the next request to process from the underlying request provider.
1060
1055
  */
1061
- async _fetchNextRequest() {
1056
+ async fetchNextRequest() {
1062
1057
  if (this.requestManager === undefined) {
1063
- throw new Error(`_fetchNextRequest called on an uninitialized crawler`);
1058
+ throw new Error(`fetchNextRequest called on an uninitialized crawler`);
1064
1059
  }
1065
1060
  return this.requestManager.fetchNextRequest();
1066
1061
  }
@@ -1095,7 +1090,7 @@ export class BasicCrawler {
1095
1090
  try {
1096
1091
  request.state = RequestState.REQUEST_HANDLER;
1097
1092
  await this.runRequestHandler(crawlingContext);
1098
- await this._timeoutAndRetry(async () => requestSource.markRequestAsHandled(request), this.internalTimeoutMillis, `Marking request ${request.url} (${request.id}) as handled timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
1093
+ await this.timeoutAndRetry(async () => requestSource.markRequestAsHandled(request), this.internalTimeoutMillis, `Marking request ${request.url} (${request.id}) as handled timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
1099
1094
  isRequestLocked = false; // markRequestAsHandled succeeded and unlocked the request
1100
1095
  this.stats.finishJob(statisticsId, request.retryCount);
1101
1096
  // reclaim session if request finishes successfully
@@ -1106,9 +1101,9 @@ export class BasicCrawler {
1106
1101
  const err = this.unwrapError(rawError);
1107
1102
  try {
1108
1103
  request.state = RequestState.ERROR_HANDLER;
1109
- await addTimeoutToPromise(async () => this._requestFunctionErrorHandler(err, crawlingContext, request, requestSource), this.internalTimeoutMillis, `Handling request failure of ${request.url} (${request.id}) timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
1104
+ await addTimeoutToPromise(async () => this.requestFunctionErrorHandler(err, crawlingContext, request, requestSource), this.internalTimeoutMillis, `Handling request failure of ${request.url} (${request.id}) timed out after ${this.internalTimeoutMillis / 1e3} seconds.`);
1110
1105
  if (!(err instanceof CriticalError)) {
1111
- isRequestLocked = false; // _requestFunctionErrorHandler calls either markRequestAsHandled or reclaimRequest
1106
+ isRequestLocked = false; // requestFunctionErrorHandler calls either markRequestAsHandled or reclaimRequest
1112
1107
  }
1113
1108
  request.state = RequestState.DONE;
1114
1109
  }
@@ -1211,7 +1206,7 @@ export class BasicCrawler {
1211
1206
  * Run async callback with given timeout and retry. Returns the result of the callback.
1212
1207
  * @ignore
1213
1208
  */
1214
- async _timeoutAndRetry(handler, timeout, error, maxRetries = 3, retried = 1) {
1209
+ async timeoutAndRetry(handler, timeout, error, maxRetries = 3, retried = 1) {
1215
1210
  try {
1216
1211
  return await addTimeoutToPromise(handler, timeout, error);
1217
1212
  }
@@ -1219,7 +1214,7 @@ export class BasicCrawler {
1219
1214
  if (retried <= maxRetries) {
1220
1215
  // we retry on any error, not just timeout
1221
1216
  this.log.warning(`${e.message} (retrying ${retried}/${maxRetries})`);
1222
- return this._timeoutAndRetry(handler, timeout, error, maxRetries, retried + 1);
1217
+ return this.timeoutAndRetry(handler, timeout, error, maxRetries, retried + 1);
1223
1218
  }
1224
1219
  throw e;
1225
1220
  }
@@ -1227,13 +1222,13 @@ export class BasicCrawler {
1227
1222
  /**
1228
1223
  * Returns true if either RequestList or RequestQueue have a request ready for processing.
1229
1224
  */
1230
- async _isTaskReadyFunction() {
1225
+ async isTaskReadyFunction() {
1231
1226
  return this.requestManager !== undefined && !(await this.requestManager.isEmpty());
1232
1227
  }
1233
1228
  /**
1234
1229
  * Returns true if both RequestList and RequestQueue have all requests finished.
1235
1230
  */
1236
- async _defaultIsFinishedFunction() {
1231
+ async defaultIsFinishedFunction() {
1237
1232
  return !this.requestManager || (await this.requestManager.isFinished());
1238
1233
  }
1239
1234
  /**
@@ -1253,12 +1248,12 @@ export class BasicCrawler {
1253
1248
  *
1254
1249
  * @param request The request object, passed separately to circumvent potential dynamic logic in crawlingContext.request
1255
1250
  */
1256
- async _requestFunctionErrorHandler(error, crawlingContext, request, source) {
1251
+ async requestFunctionErrorHandler(error, crawlingContext, request, source) {
1257
1252
  request.pushErrorMessage(error);
1258
1253
  if (error instanceof CriticalError) {
1259
1254
  throw error;
1260
1255
  }
1261
- const shouldRetryRequest = this._canRequestBeRetried(request, error);
1256
+ const shouldRetryRequest = this.canRequestBeRetried(request, error);
1262
1257
  if (shouldRetryRequest) {
1263
1258
  await this.stats.errorTrackerRetry.addAsync(error, crawlingContext);
1264
1259
  await this.errorHandler?.(crawlingContext, // valid cast - ExtendedContext transitively extends CrawlingContext
@@ -1299,18 +1294,9 @@ export class BasicCrawler {
1299
1294
  // Mark the request as failed and do not retry.
1300
1295
  await source.markRequestAsHandled(request);
1301
1296
  this.stats.failJob(request.id || request.uniqueKey, request.retryCount);
1302
- await this._handleFailedRequestHandler(crawlingContext, error); // This function prints an error message.
1303
- }
1304
- async _tagUserHandlerError(cb) {
1305
- try {
1306
- return (await cb());
1307
- }
1308
- catch (e) {
1309
- Object.defineProperty(e, 'triggeredFromUserHandler', { value: true });
1310
- throw e;
1311
- }
1297
+ await this.handleFailedRequestHandler(crawlingContext, error); // This function prints an error message.
1312
1298
  }
1313
- async _handleFailedRequestHandler(crawlingContext, error) {
1299
+ async handleFailedRequestHandler(crawlingContext, error) {
1314
1300
  // Always log the last error regardless if the user provided a failedRequestHandler
1315
1301
  const { id, url, method, uniqueKey } = crawlingContext.request;
1316
1302
  const message = this._getMessageFromError(error, true);
@@ -1339,7 +1325,7 @@ export class BasicCrawler {
1339
1325
  ? (error.stack ?? [error.message || error, ...stackLines].join('\n'))
1340
1326
  : [error.message || error, userLine].join('\n');
1341
1327
  }
1342
- _canRequestBeRetried(request, error) {
1328
+ canRequestBeRetried(request, error) {
1343
1329
  // Request should never be retried, or the error encountered makes it not able to be retried.
1344
1330
  if (request.noRetry || error instanceof NonRetryableError) {
1345
1331
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/basic",
3
- "version": "4.0.0-beta.80",
3
+ "version": "4.0.0-beta.81",
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"
@@ -42,10 +42,10 @@
42
42
  "@apify/datastructures": "^2.0.0",
43
43
  "@apify/timeout": "^0.3.2",
44
44
  "@apify/utilities": "^2.15.5",
45
- "@crawlee/core": "4.0.0-beta.80",
46
- "@crawlee/http-client": "4.0.0-beta.80",
47
- "@crawlee/types": "4.0.0-beta.80",
48
- "@crawlee/utils": "4.0.0-beta.80",
45
+ "@crawlee/core": "4.0.0-beta.81",
46
+ "@crawlee/http-client": "4.0.0-beta.81",
47
+ "@crawlee/types": "4.0.0-beta.81",
48
+ "@crawlee/utils": "4.0.0-beta.81",
49
49
  "csv-stringify": "^6.5.2",
50
50
  "fs-extra": "^11.3.0",
51
51
  "ow": "^2.0.0",
@@ -54,7 +54,7 @@
54
54
  "type-fest": "^4.41.0"
55
55
  },
56
56
  "optionalDependencies": {
57
- "@crawlee/impit-client": "^4.0.0-beta.80"
57
+ "@crawlee/impit-client": "^4.0.0-beta.81"
58
58
  },
59
59
  "lerna": {
60
60
  "command": {
@@ -63,5 +63,5 @@
63
63
  }
64
64
  }
65
65
  },
66
- "gitHead": "96c57b4a0c999e4b2bd198792490af28db7aa42d"
66
+ "gitHead": "80dc6b4fc82237e63a51a71153809ec8dfd0cc50"
67
67
  }