@crawlee/basic 4.0.0-beta.82 → 4.0.0-beta.83

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.
@@ -411,24 +411,19 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
411
411
  * via {@link BasicCrawler.getRequestManager|`getRequestManager()`}.
412
412
  */
413
413
  protected requestManager?: IRequestManager;
414
+ /** Backs the {@link BasicCrawler.sessionPool|`sessionPool`} getter. */
415
+ private sessionPoolDep;
414
416
  /**
415
417
  * A reference to the underlying session pool that manages the crawler's {@link Session|sessions}. Typed as
416
418
  * {@link ISessionPool} so custom implementations can be plugged in via the `sessionPool` constructor option.
417
419
  */
418
- readonly sessionPool: ISessionPool;
420
+ get sessionPool(): ISessionPool;
419
421
  /**
420
- * Set when the crawler constructed its own {@link SessionPool} (no `sessionPool` option was provided).
421
- * Holds the same instance as `sessionPool`, but typed as the concrete class so the crawler can call
422
- * lifecycle methods (`resetStore`, `teardown`) that aren't part of {@link ISessionPool}. A user-supplied
423
- * pool is never owned and never torn down by the crawler.
422
+ * Tracks **only** the queue the crawler opens for itself — not the {@link RequestManagerTandem} that may wrap it
423
+ * around a user-supplied `requestList` so the owned-only purge between repeated `run()` calls never reaches
424
+ * through to a borrowed loader. Filled lazily in {@link BasicCrawler.openOwnedRequestQueue|`openOwnedRequestQueue()`}.
424
425
  */
425
- private ownedSessionPool?;
426
- /**
427
- * Set when the crawler constructed its own request manager (no `requestManager`, `requestQueue`, or `requestList`
428
- * option was provided). The owned manager is purged (not dropped) between repeated `run()` calls.
429
- * A user-supplied manager is never purged by the crawler.
430
- */
431
- private ownedRequestManager?;
426
+ private ownedRequestQueue;
432
427
  /**
433
428
  * Whether the request-processing-time hint has already been forwarded to the request manager. The hint
434
429
  * derives only from `requestHandlerTimeoutMillis` (constant for the crawler's lifetime) and is raise-only,
@@ -643,7 +638,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
643
638
  getRequestQueue(): Promise<IRequestManager>;
644
639
  /**
645
640
  * Opens the default {@link RequestQueue}, applies the crawler's timeouts to it and records it as the
646
- * crawler-owned manager (so it gets purged between repeated `run()` calls).
641
+ * crawler-owned queue (so it gets purged between repeated `run()` calls).
647
642
  * @private
648
643
  */
649
644
  private openOwnedRequestQueue;
@@ -1,6 +1,6 @@
1
1
  import { writeFile } from 'node:fs/promises';
2
2
  import { dirname } from 'node:path';
3
- import { AutoscaledPool, bindMethodsToServiceLocator, BLOCKED_STATUS_CODES, ContextPipeline, ContextPipelineCleanupError, ContextPipelineInitializationError, ContextPipelineInterruptedError, CriticalError, Dataset, enqueueLinks, EnqueueStrategy, KeyValueStore, log, LogLevel, mergeCookies, MissingSessionError, NavigationSkippedError, NonRetryableError, purgeDefaultStorages, RequestHandlerError, RequestManagerTandem, RequestQueue, RequestState, RetryRequestError, Router, ServiceLocator, serviceLocator, Session, SessionError, SessionPool, Statistics, validateUserData, validators, } from '@crawlee/core';
3
+ import { AutoscaledPool, bindMethodsToServiceLocator, BLOCKED_STATUS_CODES, ContextPipeline, ContextPipelineCleanupError, ContextPipelineInitializationError, ContextPipelineInterruptedError, CriticalError, Dataset, enqueueLinks, EnqueueStrategy, KeyValueStore, log, LogLevel, mergeCookies, MissingSessionError, NavigationSkippedError, NonRetryableError, OwnedOrInjected, purgeDefaultStorages, RequestHandlerError, RequestManagerTandem, RequestQueue, RequestState, RetryRequestError, Router, ServiceLocator, serviceLocator, Session, SessionError, SessionPool, Statistics, validateUserData, validators, } from '@crawlee/core';
4
4
  import { FetchHttpClient } from '@crawlee/http-client';
5
5
  import { getObjectType, isAsyncIterable, isIterable, RobotsTxtFile, ROTATE_PROXY_ERRORS } from '@crawlee/utils';
6
6
  import { stringify } from 'csv-stringify/sync';
@@ -60,24 +60,21 @@ export class BasicCrawler {
60
60
  * via {@link BasicCrawler.getRequestManager|`getRequestManager()`}.
61
61
  */
62
62
  requestManager;
63
+ /** Backs the {@link BasicCrawler.sessionPool|`sessionPool`} getter. */
64
+ sessionPoolDep;
63
65
  /**
64
66
  * A reference to the underlying session pool that manages the crawler's {@link Session|sessions}. Typed as
65
67
  * {@link ISessionPool} so custom implementations can be plugged in via the `sessionPool` constructor option.
66
68
  */
67
- sessionPool;
68
- /**
69
- * Set when the crawler constructed its own {@link SessionPool} (no `sessionPool` option was provided).
70
- * Holds the same instance as `sessionPool`, but typed as the concrete class so the crawler can call
71
- * lifecycle methods (`resetStore`, `teardown`) that aren't part of {@link ISessionPool}. A user-supplied
72
- * pool is never owned and never torn down by the crawler.
73
- */
74
- ownedSessionPool;
69
+ get sessionPool() {
70
+ return this.sessionPoolDep.value;
71
+ }
75
72
  /**
76
- * Set when the crawler constructed its own request manager (no `requestManager`, `requestQueue`, or `requestList`
77
- * option was provided). The owned manager is purged (not dropped) between repeated `run()` calls.
78
- * A user-supplied manager is never purged by the crawler.
73
+ * Tracks **only** the queue the crawler opens for itself not the {@link RequestManagerTandem} that may wrap it
74
+ * around a user-supplied `requestList` so the owned-only purge between repeated `run()` calls never reaches
75
+ * through to a borrowed loader. Filled lazily in {@link BasicCrawler.openOwnedRequestQueue|`openOwnedRequestQueue()`}.
79
76
  */
80
- ownedRequestManager;
77
+ ownedRequestQueue = OwnedOrInjected.resolve();
81
78
  /**
82
79
  * Whether the request-processing-time hint has already been forwarded to the request manager. The hint
83
80
  * derives only from `requestHandlerTimeoutMillis` (constant for the crawler's lifetime) and is raise-only,
@@ -297,18 +294,12 @@ export class BasicCrawler {
297
294
  '`proxyInfo` they were created with. Configure proxies on the pool instead, ' +
298
295
  'e.g. via `addSession({ proxyInfo })` or a custom `createSessionFunction`.');
299
296
  }
300
- if (sessionPool) {
301
- this.sessionPool = sessionPool;
302
- }
303
- else {
304
- this.ownedSessionPool = new SessionPool({
305
- createSessionFunction: async (opts) => new Session({
306
- ...opts?.sessionOptions,
307
- proxyInfo: opts?.sessionOptions?.proxyInfo ?? (await this.proxyConfiguration?.newProxyInfo()),
308
- }),
309
- });
310
- this.sessionPool = this.ownedSessionPool;
311
- }
297
+ this.sessionPoolDep = OwnedOrInjected.resolve(sessionPool, () => new SessionPool({
298
+ createSessionFunction: async (opts) => new Session({
299
+ ...opts?.sessionOptions,
300
+ proxyInfo: opts?.sessionOptions?.proxyInfo ?? (await this.proxyConfiguration?.newProxyInfo()),
301
+ }),
302
+ }));
312
303
  this.blockedStatusCodes = new Set(blockedStatusCodesInput ?? BLOCKED_STATUS_CODES);
313
304
  const maxSignedInteger = 2 ** 31 - 1;
314
305
  if (this.requestHandlerTimeoutMillis > maxSignedInteger) {
@@ -634,17 +625,17 @@ export class BasicCrawler {
634
625
  // we need to purge the RQ to allow processing the same requests again — this is important so users can
635
626
  // pass in failed requests back to the `crawler.run()`, otherwise they would be considered as handled and
636
627
  // ignored — as a failed request is still handled.
637
- // By default (purgeRequestQueue unset or true), only the manager we created ourselves (ownedRequestManager) is purged.
628
+ // By default (`purgeRequestQueue` unset), only the queue we opened ourselves is purged.
638
629
  // When `purgeRequestQueue` is explicitly `true`, we also purge a user-supplied manager.
639
630
  // When `purgeRequestQueue` is explicitly `false`, nothing is purged.
640
631
  const shouldPurge = purgeRequestQueue !== false;
641
- const managerToPurge = this.ownedRequestManager ?? (purgeRequestQueue === true ? this.requestManager : undefined);
632
+ const managerToPurge = this.ownedRequestQueue.maybeValue ?? (purgeRequestQueue === true ? this.requestManager : undefined);
642
633
  if (managerToPurge?.purge && shouldPurge) {
643
634
  await managerToPurge.purge();
644
635
  }
645
636
  this.stats.reset();
646
637
  await this.stats.resetStore();
647
- await this.ownedSessionPool?.resetStore();
638
+ await this.sessionPoolDep.ifOwned((pool) => pool.resetStore());
648
639
  }
649
640
  this.unexpectedStop = false;
650
641
  this.running = true;
@@ -756,7 +747,7 @@ export class BasicCrawler {
756
747
  }
757
748
  /**
758
749
  * Opens the default {@link RequestQueue}, applies the crawler's timeouts to it and records it as the
759
- * crawler-owned manager (so it gets purged between repeated `run()` calls).
750
+ * crawler-owned queue (so it gets purged between repeated `run()` calls).
760
751
  * @private
761
752
  */
762
753
  async openOwnedRequestQueue() {
@@ -764,8 +755,7 @@ export class BasicCrawler {
764
755
  // subsequent instances get their own queue via a unique alias so they don't collide.
765
756
  const identifier = this.identity.instanceIndex === 0 ? null : { alias: `__default_${this.identity.id}__` };
766
757
  const requestQueue = await RequestQueue.open(identifier, { config: serviceLocator.getConfiguration() });
767
- this.ownedRequestManager = requestQueue;
768
- return requestQueue;
758
+ return this.ownedRequestQueue.set(requestQueue);
769
759
  }
770
760
  /**
771
761
  * Tells a request manager how long we expect to hold a fetched request, so that one backed by a
@@ -1364,7 +1354,7 @@ export class BasicCrawler {
1364
1354
  if (this._closeEvents) {
1365
1355
  await serviceLocator.getEventManager().close();
1366
1356
  }
1367
- await this.ownedSessionPool?.teardown();
1357
+ await this.sessionPoolDep.ifOwned((pool) => pool.teardown());
1368
1358
  await this.autoscaledPool?.abort();
1369
1359
  }
1370
1360
  _getCookieHeaderFromRequest(request) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/basic",
3
- "version": "4.0.0-beta.82",
3
+ "version": "4.0.0-beta.83",
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.82",
46
- "@crawlee/http-client": "4.0.0-beta.82",
47
- "@crawlee/types": "4.0.0-beta.82",
48
- "@crawlee/utils": "4.0.0-beta.82",
45
+ "@crawlee/core": "4.0.0-beta.83",
46
+ "@crawlee/http-client": "4.0.0-beta.83",
47
+ "@crawlee/types": "4.0.0-beta.83",
48
+ "@crawlee/utils": "4.0.0-beta.83",
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.82"
57
+ "@crawlee/impit-client": "^4.0.0-beta.83"
58
58
  },
59
59
  "lerna": {
60
60
  "command": {
@@ -63,5 +63,5 @@
63
63
  }
64
64
  }
65
65
  },
66
- "gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
66
+ "gitHead": "5f25b90c4914d7e097732cf761e440aeba799137"
67
67
  }