@crawlee/basic 4.0.0-beta.2 → 4.0.0-beta.200

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.
Files changed (91) hide show
  1. package/README.md +17 -13
  2. package/index.d.ts +11 -2
  3. package/index.js +11 -2
  4. package/internals/autoscaling/autoscaled_pool.d.ts +198 -0
  5. package/internals/autoscaling/autoscaled_pool.js +388 -0
  6. package/internals/autoscaling/concurrency_system.d.ts +273 -0
  7. package/internals/autoscaling/concurrency_system.js +359 -0
  8. package/internals/autoscaling/cpu_load_signal.d.ts +43 -0
  9. package/internals/autoscaling/cpu_load_signal.js +46 -0
  10. package/internals/autoscaling/event_loop_load_signal.d.ts +51 -0
  11. package/internals/autoscaling/event_loop_load_signal.js +60 -0
  12. package/internals/autoscaling/index.d.ts +9 -0
  13. package/internals/autoscaling/index.js +9 -0
  14. package/internals/autoscaling/load_signal.d.ts +98 -0
  15. package/internals/autoscaling/load_signal.js +103 -0
  16. package/internals/autoscaling/memory_load_signal.d.ts +47 -0
  17. package/internals/autoscaling/memory_load_signal.js +104 -0
  18. package/internals/autoscaling/snapshotter.d.ts +84 -0
  19. package/internals/autoscaling/snapshotter.js +67 -0
  20. package/internals/autoscaling/storage_backend_load_signal.d.ts +56 -0
  21. package/internals/autoscaling/storage_backend_load_signal.js +73 -0
  22. package/internals/autoscaling/system_status.d.ts +122 -0
  23. package/internals/autoscaling/system_status.js +139 -0
  24. package/internals/autoscaling/weighted_avg.d.ts +5 -0
  25. package/internals/autoscaling/weighted_avg.js +14 -0
  26. package/internals/basic-crawler.d.ts +530 -346
  27. package/internals/basic-crawler.js +1484 -726
  28. package/internals/cookie_utils.d.ts +40 -0
  29. package/internals/cookie_utils.js +122 -0
  30. package/internals/crawler-run.d.ts +76 -0
  31. package/internals/crawler-run.js +142 -0
  32. package/internals/crawlers/context_pipeline.d.ts +71 -0
  33. package/internals/crawlers/context_pipeline.js +117 -0
  34. package/internals/crawlers/crawler_commons.d.ts +194 -0
  35. package/internals/crawlers/crawler_commons.js +1 -0
  36. package/internals/crawlers/error_snapshotter.d.ts +29 -0
  37. package/internals/crawlers/error_snapshotter.js +116 -0
  38. package/internals/crawlers/error_tracker.d.ts +52 -0
  39. package/internals/crawlers/error_tracker.js +316 -0
  40. package/internals/crawlers/index.d.ts +4 -0
  41. package/internals/crawlers/index.js +3 -0
  42. package/internals/crawlers/internals/types.d.ts +7 -0
  43. package/internals/crawlers/internals/types.js +1 -0
  44. package/internals/crawlers/statistics.d.ts +318 -0
  45. package/internals/crawlers/statistics.js +525 -0
  46. package/internals/crawling_request.d.ts +86 -0
  47. package/internals/crawling_request.js +127 -0
  48. package/internals/enqueue_links/enqueue_links.d.ts +152 -0
  49. package/internals/enqueue_links/enqueue_links.js +76 -0
  50. package/internals/enqueue_links/index.d.ts +3 -0
  51. package/internals/enqueue_links/index.js +3 -0
  52. package/internals/enqueue_links/shared.d.ts +104 -0
  53. package/internals/enqueue_links/shared.js +258 -0
  54. package/internals/errors.d.ts +55 -0
  55. package/internals/errors.js +67 -0
  56. package/internals/http.d.ts +9 -0
  57. package/internals/http.js +28 -0
  58. package/internals/request-timeout.d.ts +48 -0
  59. package/internals/request-timeout.js +73 -0
  60. package/internals/router.d.ts +308 -0
  61. package/internals/router.js +312 -0
  62. package/internals/send-request.d.ts +4 -6
  63. package/internals/send-request.js +22 -26
  64. package/internals/session_pool/consts.d.ts +1 -0
  65. package/internals/session_pool/consts.js +1 -0
  66. package/internals/session_pool/errors.d.ts +7 -0
  67. package/internals/session_pool/errors.js +11 -0
  68. package/internals/session_pool/fingerprint.d.ts +9 -0
  69. package/internals/session_pool/fingerprint.js +30 -0
  70. package/internals/session_pool/index.d.ts +4 -0
  71. package/internals/session_pool/index.js +4 -0
  72. package/internals/session_pool/session.d.ts +155 -0
  73. package/internals/session_pool/session.js +222 -0
  74. package/internals/session_pool/session_pool.d.ts +241 -0
  75. package/internals/session_pool/session_pool.js +439 -0
  76. package/internals/sitemap_request_loader.d.ts +197 -0
  77. package/internals/sitemap_request_loader.js +432 -0
  78. package/internals/throttling_request_manager.d.ts +230 -0
  79. package/internals/throttling_request_manager.js +843 -0
  80. package/package.json +19 -13
  81. package/index.d.ts.map +0 -1
  82. package/index.js.map +0 -1
  83. package/internals/basic-crawler.d.ts.map +0 -1
  84. package/internals/basic-crawler.js.map +0 -1
  85. package/internals/constants.d.ts +0 -7
  86. package/internals/constants.d.ts.map +0 -1
  87. package/internals/constants.js +0 -7
  88. package/internals/constants.js.map +0 -1
  89. package/internals/send-request.d.ts.map +0 -1
  90. package/internals/send-request.js.map +0 -1
  91. package/tsconfig.build.tsbuildinfo +0 -1
@@ -1,46 +1,43 @@
1
- import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, AutoscaledPoolOptions, BaseHttpClient, CrawlingContext, DatasetExportOptions, EnqueueLinksOptions, EventManager, FinalStatistics, GetUserDataFromRequest, IRequestList, LoadedContext, ProxyInfo, Request, RequestOptions, RestrictedCrawlingContext, RouterHandler, RouterRoutes, Session, SessionPoolOptions, SkippedRequestCallback, Source, StatisticsOptions, StatisticState } from '@crawlee/core';
2
- import { AutoscaledPool, Configuration, Dataset, RequestProvider, SessionPool, Statistics } from '@crawlee/core';
3
- import type { Awaitable, BatchAddRequestsResult, Dictionary, SetStatusMessageOptions } from '@crawlee/types';
1
+ import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, CrawleeLogger, DatasetExportOptions, IProxyConfiguration, IRequestLoader, IRequestManager, RequestsLike, Source, StorageIdentifier, StorageWritePolicy } from '@crawlee/core';
2
+ import { Configuration, Request, Dataset, EventManager, RequestQueue } from '@crawlee/core';
3
+ import { BaseHttpClient } from '@crawlee/http-client';
4
+ import type { Awaitable, Dictionary, ISessionPool, SetStatusMessageOptions, StorageBackend } from '@crawlee/types';
4
5
  import { RobotsTxtFile } from '@crawlee/utils';
5
- import type { SetRequired } from 'type-fest';
6
- import type { Log } from '@apify/log';
7
- import { TimeoutError } from '@apify/timeout';
8
- export interface BasicCrawlingContext<UserData extends Dictionary = Dictionary> extends CrawlingContext<BasicCrawler, UserData> {
9
- /**
10
- * This function automatically finds and enqueues links from the current page, adding them to the {@link RequestQueue}
11
- * currently used by the crawler.
12
- *
13
- * Optionally, the function allows you to filter the target links' URLs using an array of globs or regular expressions
14
- * and override settings of the enqueued {@link Request} objects.
15
- *
16
- * Check out the [Crawl a website with relative links](https://crawlee.dev/js/docs/examples/crawl-relative-links) example
17
- * for more details regarding its usage.
18
- *
19
- * **Example usage**
20
- *
21
- * ```ts
22
- * async requestHandler({ enqueueLinks }) {
23
- * await enqueueLinks({
24
- * urls: [...],
25
- * });
26
- * },
27
- * ```
28
- *
29
- * @param [options] All `enqueueLinks()` parameters are passed via an options object.
30
- * @returns Promise that resolves to {@link BatchAddRequestsResult} object.
31
- */
32
- enqueueLinks(options?: SetRequired<EnqueueLinksOptions, 'urls'>): Promise<BatchAddRequestsResult>;
6
+ import type { ReadonlyDeep } from 'type-fest';
7
+ import { z } from 'zod';
8
+ import type { TaskLoopOptions } from './autoscaling/autoscaled_pool.js';
9
+ import type { ConcurrencySystemOptions, IConcurrencySystem } from './autoscaling/concurrency_system.js';
10
+ import { ConcurrencySystem } from './autoscaling/concurrency_system.js';
11
+ import type { FinalStatistics } from './autoscaling/system_status.js';
12
+ import { ContextPipeline } from './crawlers/context_pipeline.js';
13
+ import type { CrawlingContext, TypedRequestsLike } from './crawlers/crawler_commons.js';
14
+ import type { IStatistics, StatisticState } from './crawlers/statistics.js';
15
+ import type { EnqueueUrlsOptions, SkippedRequestCallback } from './enqueue_links/index.js';
16
+ import type { GetUserDataFromRequest, RouterHandler, RouterRoutes } from './router.js';
17
+ export interface BasicCrawlingContext<UserData extends Dictionary = Dictionary> extends CrawlingContext<UserData> {
33
18
  }
34
- export type RequestHandler<Context extends CrawlingContext = LoadedContext<BasicCrawlingContext & RestrictedCrawlingContext>> = (inputs: LoadedContext<Context>) => Awaitable<void>;
35
- export type ErrorHandler<Context extends CrawlingContext = LoadedContext<BasicCrawlingContext & RestrictedCrawlingContext>> = (inputs: LoadedContext<Context>, error: Error) => Awaitable<void>;
36
- export interface StatusMessageCallbackParams<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any> = BasicCrawler<Context>> {
19
+ export { navigationDeadlineKey, remainingNavigationWindowMillis } from './request-timeout.js';
20
+ export type RequestHandler<Context extends CrawlingContext = CrawlingContext> = (inputs: Context) => Awaitable<void>;
21
+ /**
22
+ * An error handler receives the crawling context and the error that was thrown while processing the request.
23
+ *
24
+ * Unlike the {@link RequestHandler}, an error handler may run before the context pipeline has finished
25
+ * building the full context (e.g. when navigation or session setup fails). Therefore only `BaseContext` is
26
+ * guaranteed to be present, while the extra properties added by the pipeline and `extendContext` (the
27
+ * difference between `BaseContext` and `ExtendedContext`) are only available as a `Partial`.
28
+ */
29
+ export type ErrorHandler<BaseContext extends CrawlingContext = CrawlingContext, ExtendedContext extends BaseContext = BaseContext> = (inputs: BaseContext & Partial<ExtendedContext>, error: Error) => Awaitable<void>;
30
+ export interface StatusMessageCallbackParams<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any, any, any, any> = BasicCrawler<Context>> {
37
31
  state: StatisticState;
38
32
  crawler: Crawler;
39
33
  previousState: StatisticState;
40
34
  message: string;
41
35
  }
42
- export type StatusMessageCallback<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any> = BasicCrawler<Context>> = (params: StatusMessageCallbackParams<Context, Crawler>) => Awaitable<void>;
43
- export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCrawlingContext> {
36
+ export type StatusMessageCallback<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any, any, any, any> = BasicCrawler<Context>> = (params: StatusMessageCallbackParams<Context, Crawler>) => Awaitable<void>;
37
+ export type RequireContextPipeline<DefaultContextType extends CrawlingContext, FinalContextType extends DefaultContextType> = DefaultContextType extends FinalContextType ? {} : {
38
+ contextPipelineBuilder: () => ContextPipeline<CrawlingContext, FinalContextType>;
39
+ };
40
+ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>, StatisticStateExtension extends object = {}> {
44
41
  /**
45
42
  * User-provided function that performs the logic of the crawler. It is called for each URL to crawl.
46
43
  *
@@ -56,23 +53,66 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
56
53
  * To make this work, we should **always**
57
54
  * let our function throw exceptions rather than catch them.
58
55
  * The exceptions are logged to the request using the
59
- * {@link Request.pushErrorMessage|`Request.pushErrorMessage()`} function.
56
+ * {@link CrawlingRequest.pushErrorMessage|`request.pushErrorMessage()`} function.
57
+ */
58
+ requestHandler?: RouterHandler<ExtendedContext, Routes> | RequestHandler<ExtendedContext>;
59
+ /**
60
+ * Allows the user to extend the crawling context with custom functionality (helpers, references, etc.).
61
+ *
62
+ * `extendContext` runs *before* navigation, so the returned members are visible to the
63
+ * `preNavigationHooks`, `postNavigationHooks`, and the `requestHandler` alike. As a consequence,
64
+ * the `context` passed to `extendContext` is the pre-navigation {@link CrawlingContext} and does
65
+ * **not** include navigation-dependent members (e.g. `page`, `response`, `$`, `body`). If you need
66
+ * those, use a `postNavigationHook` or the `requestHandler` instead.
67
+ *
68
+ * **Example usage:**
69
+ *
70
+ * ```javascript
71
+ * import { BasicCrawler } from 'crawlee';
72
+ *
73
+ * // Create a crawler instance
74
+ * const crawler = new BasicCrawler({
75
+ * extendContext(context) => ({
76
+ * async customHelper() {
77
+ * await context.pushData({ url: context.request.url })
78
+ * }
79
+ * }),
80
+ * async requestHandler(context) {
81
+ * await context.customHelper();
82
+ * },
83
+ * });
84
+ * ```
85
+ */
86
+ extendContext?: (context: CrawlingContext) => Awaitable<ContextExtension>;
87
+ /**
88
+ * *Intended for BasicCrawler subclasses*. Prepares a context pipeline that transforms the initial crawling context into the shape given by the `Context` type parameter.
89
+ *
90
+ * The option is not required if your crawler subclass does not extend the crawling context with custom information or helpers.
60
91
  */
61
- requestHandler?: RequestHandler<LoadedContext<Context>>;
92
+ contextPipelineBuilder?: () => ContextPipeline<CrawlingContext, Context>;
62
93
  /**
63
94
  * Static list of URLs to be processed.
64
- * If not provided, the crawler will open the default request queue when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called.
65
- * > Alternatively, `requests` parameter of {@link BasicCrawler.run|`crawler.run()`} could be used to enqueue the initial requests -
66
- * it is a shortcut for running `crawler.addRequests()` before the `crawler.run()`.
95
+ *
96
+ * @deprecated Use the `requestManager` option instead. To combine a read-only loader (such as a `RequestList`)
97
+ * with a writable queue, build a tandem with {@link IRequestLoader.toTandem|`requestList.toTandem(requestQueue)`}
98
+ * and pass the result as `requestManager`. When both `requestList` and `requestQueue` are provided, they are
99
+ * combined into a tandem automatically.
67
100
  */
68
- requestList?: IRequestList;
101
+ requestList?: IRequestLoader;
69
102
  /**
70
103
  * Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
71
- * If not provided, the crawler will open the default request queue when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called.
72
- * > Alternatively, `requests` parameter of {@link BasicCrawler.run|`crawler.run()`} could be used to enqueue the initial requests -
73
- * it is a shortcut for running `crawler.addRequests()` before the `crawler.run()`.
104
+ *
105
+ * @deprecated Use the `requestManager` option instead. A `RequestQueue` is itself a request manager, so you can
106
+ * pass it directly as `requestManager`.
74
107
  */
75
- requestQueue?: RequestProvider;
108
+ requestQueue?: RequestQueue;
109
+ /**
110
+ * Manager of requests that should be processed by the crawler. Mutually exclusive with the deprecated
111
+ * `requestQueue` and `requestList` options.
112
+ *
113
+ * If not provided, the crawler will open the default {@link RequestQueue} when it is first needed.
114
+ */
115
+ requestManager?: IRequestManager;
76
116
  /**
77
117
  * Timeout in which the function passed as {@link BasicCrawlerOptions.requestHandler|`requestHandler`} needs to finish, in seconds.
78
118
  * @default 60
@@ -87,7 +127,7 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
87
127
  * Second argument is the `Error` instance that
88
128
  * represents the last error thrown during processing of the request.
89
129
  */
90
- errorHandler?: ErrorHandler<Context>;
130
+ errorHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
91
131
  /**
92
132
  * A function to handle requests that failed more than {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
93
133
  *
@@ -96,30 +136,24 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
96
136
  * Second argument is the `Error` instance that
97
137
  * represents the last error thrown during processing of the request.
98
138
  */
99
- failedRequestHandler?: ErrorHandler<Context>;
139
+ failedRequestHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
100
140
  /**
101
141
  * Specifies the maximum number of retries allowed for a request if its processing fails.
102
- * This includes retries due to navigation errors or errors thrown from user-supplied functions
103
- * (`requestHandler`, `preNavigationHooks`, `postNavigationHooks`).
104
- *
105
- * This limit does not apply to retries triggered by session rotation
106
- * (see {@link BasicCrawlerOptions.maxSessionRotations|`maxSessionRotations`}).
142
+ * This includes retries due to navigation errors, session/proxy errors, or errors thrown from user-supplied
143
+ * functions (`requestHandler`, `preNavigationHooks`, `postNavigationHooks`).
107
144
  * @default 3
108
145
  */
109
146
  maxRequestRetries?: number;
110
147
  /**
111
- * Indicates how much time (in seconds) to wait before crawling another same domain request.
148
+ * Indicates how much time (in seconds) to wait before crawling another same domain request. Subdomains are
149
+ * paced together with the site they belong to.
150
+ *
151
+ * Offered to the crawler's request manager as a `minIntervalEverywhere` {@link PacingSignal}; a manager that
152
+ * already paces every domain it dispatches to takes it, so no domain ends up with two clocks. Otherwise the
153
+ * crawler wraps its request manager in a {@link ThrottlingRequestManager} of its own.
112
154
  * @default 0
113
155
  */
114
156
  sameDomainDelaySecs?: number;
115
- /**
116
- * Maximum number of session rotations per request.
117
- * The crawler will automatically rotate the session in case of a proxy error or if it gets blocked by the website.
118
- *
119
- * The session rotations are not counted towards the {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} limit.
120
- * @default 10
121
- */
122
- maxSessionRotations?: number;
123
157
  /**
124
158
  * Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
125
159
  * This value should always be set in order to prevent infinite loops in misconfigured crawlers.
@@ -127,29 +161,62 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
127
161
  */
128
162
  maxRequestsPerCrawl?: number;
129
163
  /**
130
- * Custom options passed to the underlying {@link AutoscaledPool} constructor.
131
- * > *NOTE:* The {@link AutoscaledPoolOptions.runTaskFunction|`runTaskFunction`}
132
- * and {@link AutoscaledPoolOptions.isTaskReadyFunction|`isTaskReadyFunction`} options
133
- * are provided by the crawler and cannot be overridden.
134
- * However, we can provide a custom implementation of {@link AutoscaledPoolOptions.isFinishedFunction|`isFinishedFunction`}.
164
+ * Maximum depth of the crawl. If not set, the crawl will continue until all requests are processed.
165
+ * Setting this to `0` will only process the initial requests, skipping all links enqueued by `crawlingContext.enqueueLinks` and `crawlingContext.addRequests`.
166
+ * Passing `1` will process the initial requests and all links enqueued by `crawlingContext.enqueueLinks` and `crawlingContext.addRequests` in the handler for initial requests.
167
+ */
168
+ maxCrawlDepth?: number;
169
+ /**
170
+ * Lets you override the predicates that steer the crawler's task loop: `isTaskReadyFunction` (may another request
171
+ * start?) and `isFinishedFunction` (is the crawl over?). The task itself — fetching a request and running it
172
+ * through the pipeline — is owned by the crawler and cannot be overridden.
173
+ *
174
+ * Concurrency is configured elsewhere — through the `minConcurrency`/`maxConcurrency`/`maxRequestsPerMinute`
175
+ * shortcuts, or a {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} for finer control.
135
176
  */
136
- autoscaledPoolOptions?: AutoscaledPoolOptions;
177
+ taskLoopOptions?: TaskLoopOptions;
178
+ /**
179
+ * A pre-configured concurrency governor — the component that decides whether there is free compute for one more
180
+ * task. Typically a {@link ConcurrencySystem}, though any {@link IConcurrencySystem} is accepted. All
181
+ * scaling configuration (min/max/desired concurrency, scaling ratios, `maxTasksPerMinute`, snapshotter tuning)
182
+ * lives on the instance itself.
183
+ *
184
+ * Inject the *same* instance into several concurrent crawlers to cap their **combined** concurrency against a
185
+ * single budget. Each crawler still builds and drives its own {@link AutoscaledPool}; only the load/scaling
186
+ * accounting is shared.
187
+ *
188
+ * Mutually exclusive with the `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`maxRequestsPerMinute`
189
+ * shortcuts, which configure the default system this one replaces — combining the two throws.
190
+ *
191
+ * You own a supplied system's lifecycle: `start()` it before `run()` (which throws otherwise) and `stop()` it once
192
+ * every crawler borrowing it has finished. The crawler does neither on your behalf.
193
+ */
194
+ concurrencySystem?: IConcurrencySystem;
137
195
  /**
138
196
  * Sets the minimum concurrency (parallelism) for the crawl. Shortcut for the
139
- * AutoscaledPool {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} option.
197
+ * {@link ConcurrencySystemOptions.minConcurrency|`minConcurrency`} option of the crawler's default
198
+ * {@link ConcurrencySystem}.
140
199
  * > *WARNING:* If we set this value too high with respect to the available system memory and CPU, our crawler will run extremely slow or crash.
141
200
  * If not sure, it's better to keep the default value and the concurrency will scale up automatically.
142
201
  */
143
202
  minConcurrency?: number;
144
203
  /**
145
204
  * Sets the maximum concurrency (parallelism) for the crawl. Shortcut for the
146
- * AutoscaledPool {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} option.
205
+ * {@link ConcurrencySystemOptions.maxConcurrency|`maxConcurrency`} option of the crawler's default
206
+ * {@link ConcurrencySystem}.
147
207
  */
148
208
  maxConcurrency?: number;
209
+ /**
210
+ * Sets the concurrency (parallelism) the crawl starts with, before any scaling happens. Shortcut for the
211
+ * {@link ConcurrencySystemOptions.desiredConcurrency|`desiredConcurrency`} option of the crawler's default
212
+ * {@link ConcurrencySystem}. Defaults to `minConcurrency`.
213
+ */
214
+ initialConcurrency?: number;
149
215
  /**
150
216
  * The maximum number of requests per minute the crawler should run.
151
217
  * By default, this is set to `Infinity`, but we can pass any positive, non-zero integer.
152
- * Shortcut for the AutoscaledPool {@link AutoscaledPoolOptions.maxTasksPerMinute|`maxTasksPerMinute`} option.
218
+ * Shortcut for the {@link ConcurrencySystemOptions.maxTasksPerMinute|`maxTasksPerMinute`} option of the
219
+ * crawler's default {@link ConcurrencySystem}.
153
220
  */
154
221
  maxRequestsPerMinute?: number;
155
222
  /**
@@ -159,14 +226,14 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
159
226
  */
160
227
  keepAlive?: boolean;
161
228
  /**
162
- * Basic crawler will initialize the {@link SessionPool} with the corresponding {@link SessionPoolOptions|`sessionPoolOptions`}.
163
- * The session instance will be than available in the {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
164
- */
165
- useSessionPool?: boolean;
166
- /**
167
- * The configuration options for {@link SessionPool} to use.
229
+ * An existing session pool instance to use. When provided, the crawler will use this pool directly instead of
230
+ * creating a new one, enabling session sharing across multiple crawlers. The crawler will not tear down a shared
231
+ * pool — the caller is responsible for its lifecycle.
232
+ *
233
+ * Accepts the built-in {@link SessionPool} or any object implementing the {@link ISessionPool} interface,
234
+ * so custom session-management strategies can be plugged in.
168
235
  */
169
- sessionPoolOptions?: SessionPoolOptions;
236
+ sessionPool?: ISessionPool;
170
237
  /**
171
238
  * Defines the length of the interval for calling the `setStatusMessage` in seconds.
172
239
  */
@@ -188,6 +255,15 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
188
255
  * ```
189
256
  */
190
257
  statusMessageCallback?: StatusMessageCallback;
258
+ /**
259
+ * HTTP status codes that indicate the session should be retired.
260
+ *
261
+ * A 429 from a domain covered by a {@link ThrottlingRequestManager} is handled as a rate limit before
262
+ * this is consulted, so removing 429 here only affects domains that manager does not cover.
263
+ *
264
+ * @default [401, 403, 429]
265
+ */
266
+ blockedStatusCodes?: number[];
191
267
  /**
192
268
  * If set to `true`, the crawler will automatically try to bypass any detected bot protection.
193
269
  *
@@ -199,232 +275,252 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
199
275
  /**
200
276
  * If set to `true`, the crawler will automatically try to fetch the robots.txt file for each domain,
201
277
  * and skip those that are not allowed. This also prevents disallowed URLs to be added via `enqueueLinks`.
278
+ *
279
+ * If an object is provided, it may contain a `userAgent` property to specify which user-agent
280
+ * should be used when checking the robots.txt file. If not provided, the default user-agent `*` will be used.
202
281
  */
203
- respectRobotsTxtFile?: boolean;
282
+ respectRobotsTxtFile?: boolean | {
283
+ userAgent?: string;
284
+ };
204
285
  /**
205
286
  * When a request is skipped for some reason, you can use this callback to act on it.
206
- * This is currently fired only for requests skipped based on robots.txt file.
287
+ * This is currently fired for requests skipped
288
+ * 1. based on robots.txt file,
289
+ * 2. because they don't match enqueueLinks filters,
290
+ * 3. because they are redirected to a URL that doesn't match the enqueueLinks strategy,
291
+ * 4. or because the {@link BasicCrawlerOptions.maxRequestsPerCrawl|`maxRequestsPerCrawl`} limit has been reached
207
292
  */
208
293
  onSkippedRequest?: SkippedRequestCallback;
209
- /** @internal */
210
- log?: Log;
211
- /**
212
- * Enables experimental features of Crawlee, which can alter the behavior of the crawler.
213
- * WARNING: these options are not guaranteed to be stable and may change or be removed at any time.
214
- */
215
- experiments?: CrawlerExperiments;
216
294
  /**
217
- * Customize the way statistics collecting works, such as logging interval or
218
- * whether to output them to the Key-Value store.
295
+ * A preconfigured statistics instance. When provided, the crawler records into it instead of building its own and
296
+ * will not `reset()` it between `run()` calls. Accepts the built-in {@link Statistics} or any object
297
+ * implementing {@link IStatistics}.
298
+ *
299
+ * Custom fields declared via {@link StatisticsOptions.stateExtension|`stateExtension`} are carried over to
300
+ * {@link BasicCrawler.statistics|`crawler.statistics.state`}:
301
+ *
302
+ * ```ts
303
+ * const statistics = new Statistics({ stateExtension: { defaultState: { productsFound: 0 } } });
304
+ *
305
+ * const crawler = new BasicCrawler({
306
+ * statistics,
307
+ * requestHandler: async () => {
308
+ * statistics.state.productsFound++;
309
+ * },
310
+ * });
311
+ *
312
+ * await crawler.run();
313
+ * // the custom fields are typed on `crawler.statistics` too
314
+ * console.log(crawler.statistics.state.productsFound);
315
+ * ```
219
316
  */
220
- statisticsOptions?: StatisticsOptions;
317
+ statistics?: IStatistics<StatisticStateExtension>;
221
318
  /**
222
319
  * HTTP client implementation for the `sendRequest` context helper and for plain HTTP crawling.
223
- * Defaults to a new instance of {@link GotScrapingHttpClient}
320
+ * Defaults to {@link ImpitHttpClient} when `@crawlee/impit-client` is installed, otherwise {@link FetchHttpClient}.
224
321
  */
225
322
  httpClient?: BaseHttpClient;
226
- }
227
- /**
228
- * A set of options that you can toggle to enable experimental features in Crawlee.
229
- *
230
- * NOTE: These options will not respect semantic versioning and may be removed or changed at any time. Use at your own risk.
231
- * If you do use these and encounter issues, please report them to us.
232
- */
233
- export interface CrawlerExperiments {
234
323
  /**
235
- * @deprecated This experiment is now enabled by default, and this flag will be removed in a future release.
236
- * If you encounter issues due to this change, please:
237
- * - report it to us: https://github.com/apify/crawlee
238
- * - set `requestLocking` to `false` in the `experiments` option of the crawler
324
+ * If set, the crawler will be configured for all connections to use
325
+ * the Proxy URLs provided and rotated according to the configuration.
326
+ */
327
+ proxyConfiguration?: IProxyConfiguration;
328
+ /**
329
+ * Custom configuration to use for this crawler.
330
+ * If provided, the crawler will use its own ServiceLocator instance instead of the global one.
331
+ */
332
+ configuration?: Configuration;
333
+ /**
334
+ * Custom storage backend to use for this crawler.
335
+ * If provided, the crawler will use its own ServiceLocator instance instead of the global one.
336
+ */
337
+ storageBackend?: StorageBackend;
338
+ /**
339
+ * Custom event manager to use for this crawler.
340
+ * If provided, the crawler will use its own ServiceLocator instance instead of the global one.
341
+ */
342
+ eventManager?: EventManager;
343
+ /**
344
+ * Custom logger to use for this crawler.
345
+ * If provided, the crawler will use its own ServiceLocator instance instead of the global one.
346
+ */
347
+ logger?: CrawleeLogger;
348
+ /**
349
+ * A unique identifier for the crawler instance. This ID is used to isolate the state returned by
350
+ * {@link BasicCrawler.useState|`crawler.useState()`} from other crawler instances.
351
+ *
352
+ * When multiple crawler instances use `useState()` without an explicit `id`, they will share the same
353
+ * state object for backward compatibility. A warning will be logged in this case.
354
+ *
355
+ * To ensure each crawler has its own isolated state that also persists across script restarts
356
+ * (e.g., during Apify migrations), provide a stable, unique ID for each crawler instance.
357
+ *
358
+ */
359
+ id?: string;
360
+ /**
361
+ * Makes the storage writes performed while handling a request atomic with respect to the request
362
+ * succeeding: they are recorded in a {@link StorageTransaction} spanning the whole request
363
+ * lifecycle and only applied when the request handler succeeds, so a thrown handler leaves no partial
364
+ * writes behind and a retry does not double-write. Reads within the handler see its own writes.
365
+ *
366
+ * `false` disables the mechanism entirely; an object overrides the per-storage-type
367
+ * {@link StorageWritePolicy} (e.g. `{ requestQueue: 'deferred' }` for all-or-nothing enqueues).
368
+ * {@link withDirectStorageAccess} is the per-call-site escape hatch; `useState()` is deliberately
369
+ * *not* transactional.
370
+ *
371
+ * @default true
372
+ */
373
+ transactionalStorage?: boolean | Partial<StorageWritePolicy>;
374
+ /**
375
+ * An array of HTTP response [Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) to be excluded from error consideration.
376
+ * By default, status codes >= 500 trigger errors.
377
+ */
378
+ ignoreHttpErrorStatusCodes?: number[];
379
+ /**
380
+ * An array of additional HTTP response [Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) to be treated as errors.
381
+ * By default, status codes >= 500 trigger errors.
239
382
  */
240
- requestLocking?: boolean;
383
+ additionalHttpErrorStatusCodes?: number[];
241
384
  }
242
- /**
243
- * Provides a simple framework for parallel crawling of web pages.
244
- * The URLs to crawl are fed either from a static list of URLs
245
- * or from a dynamic queue of URLs enabling recursive crawling of websites.
246
- *
247
- * `BasicCrawler` is a low-level tool that requires the user to implement the page
248
- * download and data extraction functionality themselves.
249
- * If we want a crawler that already facilitates this functionality,
250
- * we should consider using {@link CheerioCrawler}, {@link PuppeteerCrawler} or {@link PlaywrightCrawler}.
251
- *
252
- * `BasicCrawler` invokes the user-provided {@link BasicCrawlerOptions.requestHandler|`requestHandler`}
253
- * for each {@link Request} object, which represents a single URL to crawl.
254
- * The {@link Request} objects are fed from the {@link RequestList} or {@link RequestQueue}
255
- * instances provided by the {@link BasicCrawlerOptions.requestList|`requestList`} or {@link BasicCrawlerOptions.requestQueue|`requestQueue`}
256
- * constructor options, respectively. If neither `requestList` nor `requestQueue` options are provided,
257
- * the crawler will open the default request queue either when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called,
258
- * or if `requests` parameter (representing the initial requests) of the {@link BasicCrawler.run|`crawler.run()`} function is provided.
259
- *
260
- * If both {@link BasicCrawlerOptions.requestList|`requestList`} and {@link BasicCrawlerOptions.requestQueue|`requestQueue`} options are used,
261
- * the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
262
- * to the {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
263
- *
264
- * The crawler finishes if there are no more {@link Request} objects to crawl.
265
- *
266
- * New requests are only dispatched when there is enough free CPU and memory available,
267
- * using the functionality provided by the {@link AutoscaledPool} class.
268
- * All {@link AutoscaledPool} configuration options can be passed to the {@link BasicCrawlerOptions.autoscaledPoolOptions|`autoscaledPoolOptions`}
269
- * parameter of the `BasicCrawler` constructor.
270
- * For user convenience, the {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} and
271
- * {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} options of the
272
- * underlying {@link AutoscaledPool} constructor are available directly in the `BasicCrawler` constructor.
273
- *
274
- * **Example usage:**
275
- *
276
- * ```javascript
277
- * import { BasicCrawler, Dataset } from 'crawlee';
278
- *
279
- * // Create a crawler instance
280
- * const crawler = new BasicCrawler({
281
- * async requestHandler({ request, sendRequest }) {
282
- * // 'request' contains an instance of the Request class
283
- * // Here we simply fetch the HTML of the page and store it to a dataset
284
- * const { body } = await sendRequest({
285
- * url: request.url,
286
- * method: request.method,
287
- * body: request.payload,
288
- * headers: request.headers,
289
- * });
290
- *
291
- * await Dataset.pushData({
292
- * url: request.url,
293
- * html: body,
294
- * })
295
- * },
296
- * });
297
- *
298
- * // Enqueue the initial requests and run the crawler
299
- * await crawler.run([
300
- * 'http://www.example.com/page-1',
301
- * 'http://www.example.com/page-2',
302
- * ]);
303
- * ```
304
- * @category Crawlers
305
- */
306
- export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlingContext> {
307
- readonly config: Configuration;
308
- protected static readonly CRAWLEE_STATE_KEY = "CRAWLEE_STATE";
385
+ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>, StatisticStateExtension extends object = {}> {
386
+ #private;
309
387
  /**
310
- * A reference to the underlying {@link Statistics} class that collects and logs run statistics for requests.
388
+ * The statistics instance collecting the crawler's run statistics - either the injected `statistics` option or a
389
+ * crawler-built default. Typed as {@link IStatistics} so custom implementations can be plugged in.
311
390
  */
312
- readonly stats: Statistics;
391
+ get statistics(): IStatistics<StatisticStateExtension>;
313
392
  /**
314
- * A reference to the underlying {@link RequestList} class that manages the crawler's {@link Request|requests}.
315
- * Only available if used by the crawler.
393
+ * The main request-handling component of the crawler. It manages the requests that the crawler processes,
394
+ * combining any provided request loader and/or queue. It's initialized during the crawler startup or lazily
395
+ * via {@link BasicCrawler.getRequestManager|`getRequestManager()`}.
316
396
  */
317
- requestList?: IRequestList;
397
+ protected get requestManager(): IRequestManager | undefined;
318
398
  /**
319
- * Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
320
- * A reference to the underlying {@link RequestQueue} class that manages the crawler's {@link Request|requests}.
321
- * Only available if used by the crawler.
399
+ * A reference to the underlying session pool that manages the crawler's {@link Session|sessions}. Typed as
400
+ * {@link ISessionPool} so custom implementations can be plugged in via the `sessionPool` constructor option.
322
401
  */
323
- requestQueue?: RequestProvider;
402
+ get sessionPool(): ISessionPool;
403
+ /** Whether a {@link BasicCrawler.run|`run()`} is in progress on this instance. */
404
+ get running(): boolean;
324
405
  /**
325
- * A reference to the underlying {@link SessionPool} class that manages the crawler's {@link Session|sessions}.
326
- * Only available if used by the crawler.
406
+ * The concurrency governor the run in progress is booking its requests against — either the
407
+ * {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} that was injected, or the default the
408
+ * crawler built for itself. Read it for telemetry: `desiredConcurrency`, `currentConcurrency`, `isRunning`.
409
+ *
410
+ * > *NOTE:* `undefined` outside a run, and a crawler-owned default is rebuilt for every run — so read it
411
+ * during a run rather than caching it across runs.
412
+ *
413
+ * {@link IConcurrencySystem} is deliberately read-only. Tuning concurrency *while a crawl is running* means
414
+ * owning the instance: build a {@link ConcurrencySystem} yourself and inject it, then set
415
+ * `minConcurrency`/`maxConcurrency`/`desiredConcurrency` on your own reference.
327
416
  */
328
- sessionPool?: SessionPool;
417
+ get concurrencySystem(): IConcurrencySystem | undefined;
329
418
  /**
330
- * A reference to the underlying {@link AutoscaledPool} class that manages the concurrency of the crawler.
331
- * > *NOTE:* This property is only initialized after calling the {@link BasicCrawler.run|`crawler.run()`} function.
332
- * We can use it to change the concurrency settings on the fly,
333
- * to pause the crawler by calling {@link AutoscaledPool.pause|`autoscaledPool.pause()`}
334
- * or to abort it by calling {@link AutoscaledPool.abort|`autoscaledPool.abort()`}.
419
+ * A reference to the underlying {@link IProxyConfiguration} instance that manages the crawler's proxies.
420
+ * Only available if used by the crawler.
335
421
  */
336
- autoscaledPool?: AutoscaledPool;
422
+ readonly proxyConfiguration?: IProxyConfiguration;
337
423
  /**
338
424
  * Default {@link Router} instance that will be used if we don't specify any {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
339
425
  * See {@link Router.addHandler|`router.addHandler()`} and {@link Router.addDefaultHandler|`router.addDefaultHandler()`}.
340
426
  */
341
- readonly router: RouterHandler<LoadedContext<Context>>;
342
- running: boolean;
343
- hasFinishedBefore: boolean;
344
- readonly log: Log;
345
- protected requestHandler: RequestHandler<Context>;
346
- protected errorHandler?: ErrorHandler<Context>;
347
- protected failedRequestHandler?: ErrorHandler<Context>;
348
- protected requestHandlerTimeoutMillis: number;
349
- protected internalTimeoutMillis: number;
350
- protected maxRequestRetries: number;
351
- protected sameDomainDelayMillis: number;
352
- protected domainAccessedTime: Map<string, number>;
353
- protected maxSessionRotations: number;
354
- protected handledRequestsCount: number;
355
- protected statusMessageLoggingInterval: number;
356
- protected statusMessageCallback?: StatusMessageCallback;
357
- protected sessionPoolOptions: SessionPoolOptions;
358
- protected useSessionPool: boolean;
359
- protected crawlingContexts: Map<string, Context>;
360
- protected autoscaledPoolOptions: AutoscaledPoolOptions;
361
- protected events: EventManager;
362
- protected httpClient: BaseHttpClient;
363
- protected retryOnBlocked: boolean;
364
- protected respectRobotsTxtFile: boolean;
365
- protected onSkippedRequest?: SkippedRequestCallback;
366
- private _closeEvents?;
367
- private experiments;
368
- private readonly robotsTxtFileCache;
369
- private _experimentWarnings;
427
+ readonly router: RouterHandler<Context, Routes>;
428
+ /** @internal */
429
+ get contextPipeline(): ContextPipeline<CrawlingContext, ExtendedContext>;
430
+ /** Whether a `run()` on this instance has already finished - a repeated one continues where it left off. */
431
+ get hasFinishedBefore(): boolean;
432
+ get log(): CrawleeLogger;
433
+ protected readonly requestHandler: RequestHandler<ExtendedContext>;
434
+ protected readonly internalTimeoutMillis: number;
435
+ private get handledRequestsCount();
436
+ protected blockedStatusCodes: Set<number>;
437
+ protected readonly additionalHttpErrorStatusCodes: Set<number>;
438
+ protected readonly httpClient: BaseHttpClient;
439
+ protected readonly retryOnBlocked: boolean;
440
+ /**
441
+ * @internal
442
+ */
370
443
  protected static optionsShape: {
371
- // @ts-ignore optional peer dependency or compatibility with es2022
372
- requestList: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
373
- // @ts-ignore optional peer dependency or compatibility with es2022
374
- requestQueue: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
375
- // @ts-ignore optional peer dependency or compatibility with es2022
376
- requestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
377
- // @ts-ignore optional peer dependency or compatibility with es2022
378
- requestHandlerTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
379
- // @ts-ignore optional peer dependency or compatibility with es2022
380
- errorHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
381
- // @ts-ignore optional peer dependency or compatibility with es2022
382
- failedRequestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
383
- // @ts-ignore optional peer dependency or compatibility with es2022
384
- maxRequestRetries: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
385
- // @ts-ignore optional peer dependency or compatibility with es2022
386
- sameDomainDelaySecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
387
- // @ts-ignore optional peer dependency or compatibility with es2022
388
- maxSessionRotations: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
389
- // @ts-ignore optional peer dependency or compatibility with es2022
390
- maxRequestsPerCrawl: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
391
- // @ts-ignore optional peer dependency or compatibility with es2022
392
- autoscaledPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
393
- // @ts-ignore optional peer dependency or compatibility with es2022
394
- sessionPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
395
- // @ts-ignore optional peer dependency or compatibility with es2022
396
- useSessionPool: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
397
- // @ts-ignore optional peer dependency or compatibility with es2022
398
- statusMessageLoggingInterval: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
399
- // @ts-ignore optional peer dependency or compatibility with es2022
400
- statusMessageCallback: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
401
- // @ts-ignore optional peer dependency or compatibility with es2022
402
- retryOnBlocked: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
403
- // @ts-ignore optional peer dependency or compatibility with es2022
404
- respectRobotsTxtFile: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
405
- // @ts-ignore optional peer dependency or compatibility with es2022
406
- onSkippedRequest: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
407
- // @ts-ignore optional peer dependency or compatibility with es2022
408
- httpClient: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
409
- // @ts-ignore optional peer dependency or compatibility with es2022
410
- minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
411
- // @ts-ignore optional peer dependency or compatibility with es2022
412
- maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
413
- // @ts-ignore optional peer dependency or compatibility with es2022
414
- maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
415
- // @ts-ignore optional peer dependency or compatibility with es2022
416
- keepAlive: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
417
- // @ts-ignore optional peer dependency or compatibility with es2022
418
- log: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
419
- // @ts-ignore optional peer dependency or compatibility with es2022
420
- experiments: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
421
- // @ts-ignore optional peer dependency or compatibility with es2022
422
- statisticsOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
444
+ contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
445
+ extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
446
+ requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
447
+ requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
448
+ requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
449
+ requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
450
+ requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
451
+ errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
452
+ failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
453
+ maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
454
+ sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
455
+ maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
456
+ maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
457
+ taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
458
+ concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
459
+ sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
460
+ proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
461
+ statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
462
+ statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
463
+ additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
464
+ ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
465
+ blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
466
+ retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
467
+ respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
468
+ transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
469
+ requestQueue: z.ZodOptional<z.ZodEnum<{
470
+ deferred: "deferred";
471
+ writeThrough: "writeThrough";
472
+ }>>;
473
+ }, z.core.$strict>]>>;
474
+ onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
475
+ httpClient: z.ZodOptional<z.ZodCustom<BaseHttpClient, BaseHttpClient>>;
476
+ configuration: z.ZodOptional<z.ZodCustom<Configuration, Configuration>>;
477
+ storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
478
+ eventManager: z.ZodOptional<z.ZodCustom<EventManager, EventManager>>;
479
+ logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
480
+ minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
481
+ maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
482
+ initialConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
483
+ maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
484
+ keepAlive: z.ZodOptional<z.ZodBoolean>;
485
+ statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
486
+ id: z.ZodOptional<z.ZodString>;
423
487
  };
424
488
  /**
425
489
  * All `BasicCrawler` parameters are passed via an options object.
426
490
  */
427
- constructor(options?: BasicCrawlerOptions<Context>, config?: Configuration);
491
+ constructor(options?: BasicCrawlerOptions<Context, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> & RequireContextPipeline<CrawlingContext, Context>);
492
+ /**
493
+ * Builds the crawler-owned default {@link ConcurrencySystem} from the resolved
494
+ * `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`maxRequestsPerMinute` shortcuts. Not called when a
495
+ * {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} was injected.
496
+ *
497
+ * Subclasses may override this to tune the default system (e.g. {@link HttpCrawler} raises the starting
498
+ * concurrency and relaxes the event loop signal) while still honouring the user's shortcuts.
499
+ */
500
+ protected createDefaultConcurrencySystem(options: ConcurrencySystemOptions): ConcurrencySystem;
501
+ /**
502
+ * Determines if the given HTTP status code is an error status code given
503
+ * the default behaviour and user-set preferences.
504
+ * @param status
505
+ * @returns `true` if the status code is considered an error, `false` otherwise
506
+ */
507
+ protected isErrorStatusCode(status: number): boolean;
508
+ /**
509
+ * Builds the basic context pipeline that transforms `{ request }` into a full `CrawlingContext`.
510
+ * This handles base context creation, session resolution, and context helpers.
511
+ */
512
+ private buildBasicContextPipeline;
513
+ private checkRobotsTxt;
514
+ private createBaseContext;
515
+ /**
516
+ * Fetches the next request and rebuilds it as a {@link CrawlingRequest}. A copy rather than the manager's
517
+ * instance: managers key on `uniqueKey`/`id`, and it is this copy that flows back into `reclaimRequest` /
518
+ * `markRequestAsHandled`, so nothing observes the difference.
519
+ */
520
+ private resolveRequest;
521
+ private resolveSession;
522
+ private createContextHelpers;
523
+ private buildFinalContextPipeline;
428
524
  /**
429
525
  * Checks if the given error is a proxy error by comparing its message to a list of known proxy error messages.
430
526
  * Used for retrying requests that failed due to proxy errors.
@@ -433,34 +529,84 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlin
433
529
  */
434
530
  protected isProxyError(error: Error): boolean;
435
531
  /**
436
- * Checks whether the given crawling context is getting blocked by anti-bot protection using several heuristics.
437
- * Returns `false` if the request is not blocked, otherwise returns a string with a description of the block reason.
438
- * @param _crawlingContext The crawling context to check.
439
- */
440
- protected isRequestBlocked(_crawlingContext: Context): Promise<string | false>;
441
- /**
532
+ * Sets the status message for the current crawler run.
533
+ *
442
534
  * This method is periodically called by the crawler, every `statusMessageLoggingInterval` seconds.
535
+ *
536
+ * The message is logged and broadcast via the {@link EventType.STATUS_MESSAGE|`statusMessage`}
537
+ * event. Integrations such as the Apify SDK subscribe to that event and forward the message to
538
+ * their status-reporting backend (e.g. the Apify platform).
443
539
  */
444
- setStatusMessage(message: string, options?: SetStatusMessageOptions): Promise<void>;
540
+ setStatusMessage(message: string, options?: SetStatusMessageOptions): void;
445
541
  private getPeriodicLogger;
446
542
  /**
447
- * Runs the crawler. Returns a promise that resolves once all the requests are processed
448
- * and `autoscaledPool.isFinished` returns `true`.
543
+ * Runs the crawler. Returns a promise that resolves once every request has been processed and the crawler's
544
+ * finished-check ({@link BasicCrawlerOptions.taskLoopOptions|`taskLoopOptions.isFinishedFunction`}, or the
545
+ * default "the request manager is empty") reports that the crawl is over.
449
546
  *
450
547
  * We can use the `requests` parameter to enqueue the initial requests — it is a shortcut for
451
548
  * running {@link BasicCrawler.addRequests|`crawler.addRequests()`} before {@link BasicCrawler.run|`crawler.run()`}.
452
549
  *
550
+ * Calling `run()` again on the same instance keeps crawling the same request manager - requests the previous
551
+ * run handled (a failed one counts as handled) are not processed again. Purge the queue or open a fresh one
552
+ * if that is what you want.
553
+ *
453
554
  * @param [requests] The requests to add.
454
- * @param [options] Options for the request queue.
555
+ * @param [options] Options for adding the initial requests.
455
556
  */
456
- run(requests?: (string | Request | RequestOptions)[], options?: CrawlerRunOptions): Promise<FinalStatistics>;
557
+ run(requests?: TypedRequestsLike<Routes>, options?: CrawlerRunOptions): Promise<FinalStatistics>;
457
558
  /**
458
559
  * Gracefully stops the current run of the crawler.
459
560
  *
460
561
  * All the tasks active at the time of calling this method will be allowed to finish.
562
+ *
563
+ * To stop the crawler immediately, use {@link BasicCrawler.teardown|`crawler.teardown()`} instead.
461
564
  */
462
- stop(message?: string): void;
463
- getRequestQueue(): Promise<RequestProvider>;
565
+ stop(reason?: string): void;
566
+ /**
567
+ * Stops dispatching new requests, letting the in-progress ones finish. Resolves once they have settled, or rejects
568
+ * after `timeoutSecs` if they take too long. Unlike {@link BasicCrawler.stop|`stop()`}, this does not end the
569
+ * run — {@link BasicCrawler.run|`run()`} stays pending until {@link BasicCrawler.resume|`resume()`}.
570
+ *
571
+ * > *NOTE:* The {@link BasicCrawler.concurrencySystem|concurrency system} keeps monitoring and autoscaling
572
+ * throughout, since a shared one may still be serving other crawlers.
573
+ */
574
+ pause(timeoutSecs?: number): Promise<void>;
575
+ /**
576
+ * Resumes a run suspended with {@link BasicCrawler.pause|`pause()`}, letting the crawler dispatch requests
577
+ * again. A no-op on a crawler that is not paused.
578
+ */
579
+ resume(): void;
580
+ /**
581
+ * Returns the crawler's {@link IRequestManager|request manager}, opening the default {@link RequestQueue}
582
+ * if none has been configured or opened yet.
583
+ */
584
+ getRequestManager(): Promise<IRequestManager>;
585
+ /**
586
+ * @deprecated Use {@link BasicCrawler.getRequestManager|`getRequestManager()`} instead. This returns the
587
+ * crawler's request manager, which is no longer guaranteed to be a {@link RequestQueue}.
588
+ */
589
+ getRequestQueue(): Promise<IRequestManager>;
590
+ /**
591
+ * Opens the default {@link RequestQueue} — the crawler's own, read from when the caller supplied nothing.
592
+ */
593
+ private openOwnedRequestQueue;
594
+ /**
595
+ * Tells a request manager how long we expect to hold a fetched request, so that one backed by a
596
+ * locking storage backend keeps it reserved for slightly longer than the request handler timeout
597
+ * (with some padding for overhead), but never for less than a minute. This prevents a long-running
598
+ * request from being handed out a second time while it is still being processed — and it works
599
+ * regardless of whether the manager is a plain {@link RequestQueue} or a `RequestManagerTandem`.
600
+ */
601
+ private applyRequestManagerTimeouts;
602
+ /**
603
+ * Validates a request source's `userData` against the {@link RouteSchemas|Standard Schema} registered
604
+ * for its label on the crawler's schema-router (if any), throwing a {@link RequestValidationError} on
605
+ * mismatch. A no-op when the user's request handler is not a schema-router, or no schema is registered for
606
+ * the request's label. Applied by the crawler on the add paths it owns — `crawler.addRequests`,
607
+ * `crawler.run`, `context.addRequests` and `context.enqueueLinks`.
608
+ */
609
+ private validateRequestUserData;
464
610
  useState<State extends Dictionary = Dictionary>(defaultValue?: State): Promise<State>;
465
611
  /**
466
612
  * Adds requests to the queue in batches. By default, it will resolve after the initial batch is added, and continue
@@ -468,20 +614,25 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlin
468
614
  * the batches via `waitBetweenBatchesMillis`. If you want to wait for all batches to be added to the queue, you can use
469
615
  * the `waitForAllRequestsToBeAdded` promise you get in the response object.
470
616
  *
617
+ * Optionally, the requests can be filtered using `include`/`exclude` glob or regexp patterns and an
618
+ * enqueue `strategy` (both AND-ed together, same as {@link CrawlingContext.enqueueLinks|`enqueueLinks`}),
619
+ * relative to `baseUrl`. Unlike `enqueueLinks`, there is no implicit "current page" to anchor the strategy
620
+ * to, so `strategy` defaults to {@link EnqueueStrategy.All|`all`} here.
621
+ *
471
622
  * This is an alias for calling `addRequestsBatched()` on the implicit `RequestQueue` for this crawler instance.
472
623
  *
473
624
  * @param requests The requests to add
474
625
  * @param options Options for the request queue
475
626
  */
476
- addRequests(requests: (string | Source)[], options?: CrawlerAddRequestsOptions): Promise<CrawlerAddRequestsResult>;
627
+ addRequests(requests: ReadonlyDeep<TypedRequestsLike<Routes>>, options?: CrawlerAddRequestsOptions): Promise<CrawlerAddRequestsResult>;
477
628
  /**
478
629
  * Pushes data to the specified {@link Dataset}, or the default crawler {@link Dataset} by calling {@link Dataset.pushData}.
479
630
  */
480
- pushData(data: Parameters<Dataset['pushData']>[0], datasetIdOrName?: string): Promise<void>;
631
+ pushData(data: Parameters<Dataset['pushData']>[0], datasetIdentifier?: string | StorageIdentifier): Promise<void>;
481
632
  /**
482
633
  * Retrieves the specified {@link Dataset}, or the default crawler {@link Dataset}.
483
634
  */
484
- getDataset(idOrName?: string): Promise<Dataset>;
635
+ getDataset(identifier?: string | StorageIdentifier): Promise<Dataset>;
485
636
  /**
486
637
  * Retrieves data from the default crawler {@link Dataset} by calling {@link Dataset.getData}.
487
638
  */
@@ -491,98 +642,131 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlin
491
642
  * Supported formats are currently 'json' and 'csv', and will be inferred from the `path` automatically.
492
643
  */
493
644
  exportData<Data>(path: string, format?: 'json' | 'csv', options?: DatasetExportOptions): Promise<Data[]>;
494
- protected _init(): Promise<void>;
495
- protected _runRequestHandler(crawlingContext: Context): Promise<void>;
496
645
  /**
497
- * Handles blocked request
646
+ * Initializes the crawler.
498
647
  */
499
- protected _throwOnBlockedRequest(session: Session, statusCode: number): void;
500
- private isAllowedBasedOnRobotsTxtFile;
501
- protected getRobotsTxtFileForUrl(url: string): Promise<RobotsTxtFile | undefined>;
502
- protected _pauseOnMigration(): Promise<void>;
648
+ protected init(): Promise<void>;
503
649
  /**
504
- * Fetches request from either RequestList or RequestQueue. If request comes from a RequestList
505
- * and RequestQueue is present then enqueues it to the queue first.
650
+ * The navigation timeout (pre-navigation hooks, navigation, and post-navigation hooks) in milliseconds, used
651
+ * to size the internal request timeout. `BasicCrawler` has no navigation phase, so this is 0; the HTTP and
652
+ * browser crawlers override it with their `navigationTimeoutSecs`.
506
653
  */
507
- protected _fetchNextRequest(): Promise<Request<Dictionary> | null | undefined>;
654
+ protected getNavigationTimeoutMillis(): number;
508
655
  /**
509
- * Executed when `errorHandler` finishes or the request is successful.
510
- * Can be used to clean up orphaned browser pages.
656
+ * Races the request against the internal timeout (see {@link raceWithTimeout}), sized to outlast the phases
657
+ * that have their own timeout - the navigation, its hooks, and the request handler - so a legitimately slow
658
+ * request, a per-route override, or a low `CRAWLEE_INTERNAL_TIMEOUT` is not cut short mid-phase. It takes
659
+ * whichever is larger: the configured internal timeout, or this request's combined phase budget.
511
660
  */
512
- protected _cleanupContext(_crawlingContext: Context): Promise<void>;
661
+ private withRequestTimeout;
513
662
  /**
514
- * Delays processing of the request based on the `sameDomainDelaySecs` option,
515
- * adding it back to the queue after the timeout passes. Returns `true` if the request
516
- * should be ignored and will be reclaimed to the queue once ready.
663
+ * The request handler timeout for a request with the given route label. A router route may override the
664
+ * crawler's own `requestHandlerTimeoutSecs`; anything else falls back to `fallbackMillis`.
665
+ *
666
+ * @param label The request's route label, or `undefined` for the default route / no specific request.
667
+ * @param fallbackMillis Timeout to use when no route overrides it.
668
+ */
669
+ private resolveRequestHandlerTimeoutMillis;
670
+ /**
671
+ * The timeout the router route with the given label asked for, or `undefined` when it did not override one
672
+ * (or the request handler is not a router at all).
517
673
  */
518
- protected delayRequest(request: Request, source: IRequestList | RequestProvider): boolean;
674
+ private getRouteTimeoutMillis;
675
+ protected runRequestHandler(crawlingContext: ExtendedContext): Promise<void>;
519
676
  /**
520
- * Wrapper around requestHandler that fetches requests from RequestList/RequestQueue
521
- * then retries them in a case of an error, etc.
677
+ * Runs `callback` inside a {@link StorageTransaction}, unless transactional storage is disabled.
678
+ * Deliberately does **not** commit on return - `handleRequest` swallows request handler failures, so
679
+ * a normal return says nothing about success. `handleRequest` owns the outcome.
522
680
  */
523
- protected _runTaskFunction(): Promise<void>;
681
+ private runInStorageTransaction;
524
682
  /**
525
- * Run async callback with given timeout and retry.
683
+ * Handles blocked request
684
+ */
685
+ protected throwOnBlockedRequest(statusCode: number): void;
686
+ private isAllowedBasedOnRobotsTxtFile;
687
+ /**
688
+ * Records an HTTP 429 against the URL's domain so the request manager can hold the retry back.
689
+ *
690
+ * @param retryAfterHeader The raw `Retry-After` response header, if the server sent one.
691
+ * @returns `true` if the manager took responsibility for the delay, in which case the caller should throw
692
+ * {@link RequestThrottledError} rather than treating the response as a blocked session.
693
+ */
694
+ protected recordDomainRateLimit(url: string, retryAfterHeader?: string | null): boolean;
695
+ /** Hands a robots.txt `Crawl-delay` to the request manager, warning if it will not be honoured. */
696
+ private applyCrawlDelay;
697
+ /** @internal */
698
+ protected getRobotsTxtFileForUrl(url: string): Promise<RobotsTxtFile | undefined>;
699
+ private pauseOnMigration;
700
+ /**
701
+ * Fetches the next request to process from the underlying request provider.
702
+ */
703
+ private fetchNextRequest;
704
+ /** Handles a single request - runs the request handler with retries, error handling, and lifecycle management. */
705
+ private handleRequest;
706
+ /**
707
+ * Generator function that yields requests injected with the given crawl depth.
708
+ * @internal
709
+ */
710
+ protected addCrawlDepthRequestGenerator(requests: RequestsLike, newRequestDepth: number): AsyncGenerator<Source, void, undefined>;
711
+ /**
712
+ * Run async callback with given timeout and retry. Returns the result of the callback.
526
713
  * @ignore
527
714
  */
528
- protected _timeoutAndRetry(handler: () => Promise<unknown>, timeout: number, error: Error | string, maxRetries?: number, retried?: number): Promise<void>;
715
+ private timeoutAndRetry;
529
716
  /**
530
- * Returns true if either RequestList or RequestQueue have a request ready for processing.
717
+ * Whether the request manager has a request ready for processing. A manager that is only `waiting` also gets a
718
+ * wake-up scheduled, so a paced crawl resumes on its clock rather than on the task loop's polling interval.
531
719
  */
532
- protected _isTaskReadyFunction(): Promise<boolean>;
720
+ private isTaskReadyFunction;
533
721
  /**
534
- * Returns true if both RequestList and RequestQueue have all requests finished.
722
+ * Unwraps errors thrown by the context pipeline to get the actual user error.
723
+ * RequestHandlerError and ContextPipelineCleanupError wrap the actual error.
535
724
  */
536
- protected _defaultIsFinishedFunction(): Promise<boolean>;
537
- private _rotateSession;
725
+ private unwrapError;
538
726
  /**
539
727
  * Handles errors thrown by user provided requestHandler()
728
+ *
729
+ * @param request The request object, passed separately to circumvent potential dynamic logic in crawlingContext.request
540
730
  */
541
- protected _requestFunctionErrorHandler(error: Error, crawlingContext: Context, source: IRequestList | RequestProvider): Promise<void>;
542
- protected _tagUserHandlerError<T>(cb: () => unknown): Promise<T>;
543
- protected _handleFailedRequestHandler(crawlingContext: Context, error: Error): Promise<void>;
731
+ private requestFunctionErrorHandler;
732
+ private handleFailedRequestHandler;
544
733
  /**
545
734
  * Resolves the most verbose error message from a thrown error
546
735
  * @param error The error received
547
736
  * @returns The message to be logged
548
737
  */
549
- protected _getMessageFromError(error: Error, forceStack?: boolean): string | TimeoutError | undefined;
550
- protected _canRequestBeRetried(request: Request, error: Error): boolean;
738
+ protected getMessageFromError(error: Error, forceStack?: boolean): string;
551
739
  /**
552
- * Updates handledRequestsCount from possibly stored counts,
553
- * usually after worker migration. Since one of the stores
554
- * needs to have priority when both are present,
555
- * it is the request queue, because generally, the request
556
- * list will first be dumped into the queue and then left
557
- * empty.
740
+ * Whether the session should be spared for this error - either because it was already retired, or because the
741
+ * failure says nothing about the session (a rate limit is a property of the domain).
558
742
  */
559
- protected _loadHandledRequestCount(): Promise<void>;
560
- protected _executeHooks<HookLike extends (...args: any[]) => Awaitable<void>>(hooks: HookLike[], ...args: Parameters<HookLike>): Promise<void>;
743
+ private errorAbsolvesSession;
744
+ private canRequestBeRetried;
561
745
  /**
562
- * Function for cleaning up after all request are processed.
563
- * @ignore
746
+ * Ends the run in progress immediately, without waiting for the requests already in flight.
747
+ *
748
+ * This runs at the end of every {@link BasicCrawler.run|`run()`}, so what it releases is per-run only, and
749
+ * a repeated `run()` has to find everything it needs either intact or re-establishable. What outlives a run is
750
+ * released by {@link BasicCrawler.destroy|`destroy()`} instead.
751
+ *
752
+ * To stop the crawler gracefully (waiting for all running requests to finish), use {@link BasicCrawler.stop|`crawler.stop()`} instead.
564
753
  */
565
754
  teardown(): Promise<void>;
566
- protected _getCookieHeaderFromRequest(request: Request): string;
567
- private _getRequestQueue;
568
- protected requestMatchesEnqueueStrategy(request: Request): boolean;
569
- }
570
- export interface CreateContextOptions {
571
- request: Request;
572
- session?: Session;
573
- proxyInfo?: ProxyInfo;
755
+ /**
756
+ * Releases what the crawler owns beyond a single run — in the browser crawlers, the browser pool. A finished
757
+ * `run()` has already released everything a run owns, so this is only needed before dropping a crawler you
758
+ * could otherwise have run again.
759
+ */
760
+ destroy(): Promise<void>;
761
+ [Symbol.asyncDispose](): Promise<void>;
762
+ protected getCookieHeaderFromRequest(request: Request): string;
763
+ private requestMatchesEnqueueStrategy;
574
764
  }
575
- export interface CrawlerAddRequestsOptions extends AddRequestsBatchedOptions {
765
+ export interface CrawlerAddRequestsOptions extends AddRequestsBatchedOptions, EnqueueUrlsOptions {
576
766
  }
577
767
  export interface CrawlerAddRequestsResult extends AddRequestsBatchedResult {
578
768
  }
579
769
  export interface CrawlerRunOptions extends CrawlerAddRequestsOptions {
580
- /**
581
- * Whether to purge the RequestQueue before running the crawler again. Defaults to true, so it is possible to reprocess failed requests.
582
- * When disabled, only new requests will be considered. Note that even a failed request is considered as handled.
583
- * @default true
584
- */
585
- purgeRequestQueue?: boolean;
586
770
  }
587
771
  /**
588
772
  * Creates new {@link Router} instance that works based on request labels.
@@ -608,5 +792,5 @@ export interface CrawlerRunOptions extends CrawlerAddRequestsOptions {
608
792
  * await crawler.run();
609
793
  * ```
610
794
  */
611
- export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, UserData>): RouterHandler<Context>;
612
- //# sourceMappingURL=basic-crawler.d.ts.map
795
+ export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>>(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>;
796
+ export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;