@crawlee/core 4.0.0-beta.13 → 4.0.0-beta.131

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 (280) hide show
  1. package/README.md +17 -13
  2. package/autoscaling/autoscaled_pool.d.ts +67 -172
  3. package/autoscaling/autoscaled_pool.js +182 -329
  4. package/autoscaling/concurrency_system.d.ts +268 -0
  5. package/autoscaling/concurrency_system.js +362 -0
  6. package/autoscaling/cpu_load_signal.d.ts +43 -0
  7. package/autoscaling/cpu_load_signal.js +47 -0
  8. package/autoscaling/event_loop_load_signal.d.ts +51 -0
  9. package/autoscaling/event_loop_load_signal.js +60 -0
  10. package/autoscaling/index.d.ts +6 -1
  11. package/autoscaling/index.js +6 -1
  12. package/autoscaling/load_signal.d.ts +100 -0
  13. package/autoscaling/load_signal.js +105 -0
  14. package/autoscaling/memory_load_signal.d.ts +47 -0
  15. package/autoscaling/memory_load_signal.js +106 -0
  16. package/autoscaling/snapshotter.d.ts +58 -163
  17. package/autoscaling/snapshotter.js +45 -263
  18. package/autoscaling/storage_backend_load_signal.d.ts +56 -0
  19. package/autoscaling/storage_backend_load_signal.js +73 -0
  20. package/autoscaling/system_status.d.ts +67 -89
  21. package/autoscaling/system_status.js +92 -122
  22. package/autoscaling/weighted_avg.d.ts +5 -0
  23. package/autoscaling/weighted_avg.js +14 -0
  24. package/byte_utils.d.ts +17 -0
  25. package/byte_utils.js +42 -0
  26. package/configuration.d.ts +96 -223
  27. package/configuration.js +170 -222
  28. package/cookie_utils.d.ts +3 -2
  29. package/cookie_utils.js +18 -7
  30. package/crawlers/context_pipeline.d.ts +10 -1
  31. package/crawlers/context_pipeline.js +31 -8
  32. package/crawlers/crawler_commons.d.ts +90 -129
  33. package/crawlers/crawler_commons.js +1 -116
  34. package/crawlers/error_snapshotter.d.ts +2 -5
  35. package/crawlers/error_snapshotter.js +7 -8
  36. package/crawlers/error_tracker.d.ts +0 -1
  37. package/crawlers/error_tracker.js +0 -1
  38. package/crawlers/index.d.ts +1 -3
  39. package/crawlers/index.js +0 -3
  40. package/crawlers/internals/types.d.ts +0 -1
  41. package/crawlers/internals/types.js +0 -1
  42. package/crawlers/statistics.d.ts +187 -63
  43. package/crawlers/statistics.js +354 -164
  44. package/debug.d.ts +36 -0
  45. package/debug.js +70 -0
  46. package/enqueue_links/enqueue_links.d.ts +68 -154
  47. package/enqueue_links/enqueue_links.js +38 -210
  48. package/enqueue_links/index.d.ts +0 -1
  49. package/enqueue_links/index.js +0 -1
  50. package/enqueue_links/shared.d.ts +52 -26
  51. package/enqueue_links/shared.js +115 -66
  52. package/errors.d.ts +72 -4
  53. package/errors.js +89 -5
  54. package/events/event_manager.d.ts +35 -9
  55. package/events/event_manager.js +12 -13
  56. package/events/index.d.ts +0 -1
  57. package/events/index.js +0 -1
  58. package/events/local_event_manager.d.ts +15 -3
  59. package/events/local_event_manager.js +39 -13
  60. package/http.d.ts +9 -0
  61. package/http.js +28 -0
  62. package/index.d.ts +7 -4
  63. package/index.js +6 -3
  64. package/iterables.d.ts +79 -0
  65. package/iterables.js +134 -0
  66. package/log.d.ts +82 -3
  67. package/log.js +106 -1
  68. package/memory-storage/consts.d.ts +4 -0
  69. package/memory-storage/consts.js +4 -0
  70. package/memory-storage/index.d.ts +1 -0
  71. package/memory-storage/index.js +1 -0
  72. package/memory-storage/memory-storage.d.ts +38 -0
  73. package/memory-storage/memory-storage.js +130 -0
  74. package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
  75. package/memory-storage/resource-clients/common/base-client.js +6 -0
  76. package/memory-storage/resource-clients/dataset.d.ts +40 -0
  77. package/memory-storage/resource-clients/dataset.js +108 -0
  78. package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
  79. package/memory-storage/resource-clients/key-value-store.js +201 -0
  80. package/memory-storage/resource-clients/request-queue.d.ts +77 -0
  81. package/memory-storage/resource-clients/request-queue.js +409 -0
  82. package/memory-storage/utils.d.ts +16 -0
  83. package/memory-storage/utils.js +41 -0
  84. package/owned_or_injected.d.ts +58 -0
  85. package/owned_or_injected.js +98 -0
  86. package/package.json +14 -13
  87. package/proxy_configuration.d.ts +24 -132
  88. package/proxy_configuration.js +32 -147
  89. package/recoverable_state.d.ts +155 -0
  90. package/recoverable_state.js +231 -0
  91. package/request.d.ts +80 -16
  92. package/request.js +147 -68
  93. package/router.d.ts +193 -21
  94. package/router.js +188 -43
  95. package/serialization.d.ts +0 -1
  96. package/serialization.js +15 -15
  97. package/service_locator.d.ts +165 -0
  98. package/service_locator.js +253 -0
  99. package/session_pool/consts.d.ts +1 -2
  100. package/session_pool/consts.js +1 -2
  101. package/session_pool/errors.d.ts +0 -1
  102. package/session_pool/errors.js +0 -1
  103. package/session_pool/fingerprint.d.ts +9 -0
  104. package/session_pool/fingerprint.js +30 -0
  105. package/session_pool/index.d.ts +0 -2
  106. package/session_pool/index.js +0 -2
  107. package/session_pool/session.d.ts +35 -88
  108. package/session_pool/session.js +101 -159
  109. package/session_pool/session_pool.d.ts +73 -91
  110. package/session_pool/session_pool.js +172 -165
  111. package/storages/batched_adds.d.ts +37 -0
  112. package/storages/batched_adds.js +73 -0
  113. package/storages/dataset.d.ts +114 -54
  114. package/storages/dataset.js +291 -148
  115. package/storages/index.d.ts +10 -8
  116. package/storages/index.js +8 -8
  117. package/storages/key_value_store.d.ts +185 -42
  118. package/storages/key_value_store.js +445 -169
  119. package/storages/key_value_store_codec.d.ts +32 -0
  120. package/storages/key_value_store_codec.js +113 -0
  121. package/storages/request_dedup_cache.d.ts +22 -0
  122. package/storages/request_dedup_cache.js +48 -0
  123. package/storages/request_list.d.ts +52 -115
  124. package/storages/request_list.js +183 -152
  125. package/storages/request_loader.d.ts +101 -0
  126. package/storages/request_loader.js +1 -0
  127. package/storages/request_manager.d.ts +33 -0
  128. package/storages/request_manager.js +1 -0
  129. package/storages/request_manager_tandem.d.ts +97 -0
  130. package/storages/request_manager_tandem.js +197 -0
  131. package/storages/request_queue.d.ts +290 -47
  132. package/storages/request_queue.js +762 -216
  133. package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +45 -89
  134. package/storages/sitemap_request_loader.js +438 -0
  135. package/storages/storage_instance_manager.d.ts +87 -0
  136. package/storages/storage_instance_manager.js +256 -0
  137. package/storages/storage_stats.d.ts +48 -0
  138. package/storages/storage_stats.js +29 -0
  139. package/storages/throttling_request_manager.d.ts +239 -0
  140. package/storages/throttling_request_manager.js +646 -0
  141. package/storages/transaction.d.ts +252 -0
  142. package/storages/transaction.js +251 -0
  143. package/storages/utils.d.ts +59 -11
  144. package/storages/utils.js +75 -15
  145. package/system-info/cpu-info.d.ts +67 -0
  146. package/system-info/cpu-info.js +216 -0
  147. package/system-info/memory-info.d.ts +31 -0
  148. package/system-info/memory-info.js +115 -0
  149. package/system-info/ps-tree.d.ts +17 -0
  150. package/system-info/ps-tree.js +144 -0
  151. package/system-info/runtime.d.ts +14 -0
  152. package/system-info/runtime.js +80 -0
  153. package/typedefs.d.ts +0 -6
  154. package/typedefs.js +0 -1
  155. package/url.d.ts +9 -0
  156. package/url.js +11 -0
  157. package/validators.d.ts +22 -18
  158. package/validators.js +13 -18
  159. package/autoscaling/autoscaled_pool.d.ts.map +0 -1
  160. package/autoscaling/autoscaled_pool.js.map +0 -1
  161. package/autoscaling/index.d.ts.map +0 -1
  162. package/autoscaling/index.js.map +0 -1
  163. package/autoscaling/snapshotter.d.ts.map +0 -1
  164. package/autoscaling/snapshotter.js.map +0 -1
  165. package/autoscaling/system_status.d.ts.map +0 -1
  166. package/autoscaling/system_status.js.map +0 -1
  167. package/configuration.d.ts.map +0 -1
  168. package/configuration.js.map +0 -1
  169. package/cookie_utils.d.ts.map +0 -1
  170. package/cookie_utils.js.map +0 -1
  171. package/crawlers/context_pipeline.d.ts.map +0 -1
  172. package/crawlers/context_pipeline.js.map +0 -1
  173. package/crawlers/crawler_commons.d.ts.map +0 -1
  174. package/crawlers/crawler_commons.js.map +0 -1
  175. package/crawlers/crawler_utils.d.ts +0 -10
  176. package/crawlers/crawler_utils.d.ts.map +0 -1
  177. package/crawlers/crawler_utils.js +0 -12
  178. package/crawlers/crawler_utils.js.map +0 -1
  179. package/crawlers/error_snapshotter.d.ts.map +0 -1
  180. package/crawlers/error_snapshotter.js.map +0 -1
  181. package/crawlers/error_tracker.d.ts.map +0 -1
  182. package/crawlers/error_tracker.js.map +0 -1
  183. package/crawlers/index.d.ts.map +0 -1
  184. package/crawlers/index.js.map +0 -1
  185. package/crawlers/internals/types.d.ts.map +0 -1
  186. package/crawlers/internals/types.js.map +0 -1
  187. package/crawlers/statistics.d.ts.map +0 -1
  188. package/crawlers/statistics.js.map +0 -1
  189. package/enqueue_links/enqueue_links.d.ts.map +0 -1
  190. package/enqueue_links/enqueue_links.js.map +0 -1
  191. package/enqueue_links/index.d.ts.map +0 -1
  192. package/enqueue_links/index.js.map +0 -1
  193. package/enqueue_links/shared.d.ts.map +0 -1
  194. package/enqueue_links/shared.js.map +0 -1
  195. package/errors.d.ts.map +0 -1
  196. package/errors.js.map +0 -1
  197. package/events/event_manager.d.ts.map +0 -1
  198. package/events/event_manager.js.map +0 -1
  199. package/events/index.d.ts.map +0 -1
  200. package/events/index.js.map +0 -1
  201. package/events/local_event_manager.d.ts.map +0 -1
  202. package/events/local_event_manager.js.map +0 -1
  203. package/http_clients/base-http-client.d.ts +0 -140
  204. package/http_clients/base-http-client.d.ts.map +0 -1
  205. package/http_clients/base-http-client.js +0 -40
  206. package/http_clients/base-http-client.js.map +0 -1
  207. package/http_clients/form-data-like.d.ts +0 -67
  208. package/http_clients/form-data-like.d.ts.map +0 -1
  209. package/http_clients/form-data-like.js +0 -5
  210. package/http_clients/form-data-like.js.map +0 -1
  211. package/http_clients/got-scraping-http-client.d.ts +0 -20
  212. package/http_clients/got-scraping-http-client.d.ts.map +0 -1
  213. package/http_clients/got-scraping-http-client.js +0 -82
  214. package/http_clients/got-scraping-http-client.js.map +0 -1
  215. package/http_clients/index.d.ts +0 -3
  216. package/http_clients/index.d.ts.map +0 -1
  217. package/http_clients/index.js +0 -3
  218. package/http_clients/index.js.map +0 -1
  219. package/index.d.ts.map +0 -1
  220. package/index.js.map +0 -1
  221. package/log.d.ts.map +0 -1
  222. package/log.js.map +0 -1
  223. package/proxy_configuration.d.ts.map +0 -1
  224. package/proxy_configuration.js.map +0 -1
  225. package/request.d.ts.map +0 -1
  226. package/request.js.map +0 -1
  227. package/router.d.ts.map +0 -1
  228. package/router.js.map +0 -1
  229. package/serialization.d.ts.map +0 -1
  230. package/serialization.js.map +0 -1
  231. package/session_pool/consts.d.ts.map +0 -1
  232. package/session_pool/consts.js.map +0 -1
  233. package/session_pool/errors.d.ts.map +0 -1
  234. package/session_pool/errors.js.map +0 -1
  235. package/session_pool/events.d.ts +0 -3
  236. package/session_pool/events.d.ts.map +0 -1
  237. package/session_pool/events.js +0 -3
  238. package/session_pool/events.js.map +0 -1
  239. package/session_pool/index.d.ts.map +0 -1
  240. package/session_pool/index.js.map +0 -1
  241. package/session_pool/session.d.ts.map +0 -1
  242. package/session_pool/session.js.map +0 -1
  243. package/session_pool/session_pool.d.ts.map +0 -1
  244. package/session_pool/session_pool.js.map +0 -1
  245. package/storages/access_checking.d.ts +0 -13
  246. package/storages/access_checking.d.ts.map +0 -1
  247. package/storages/access_checking.js +0 -14
  248. package/storages/access_checking.js.map +0 -1
  249. package/storages/dataset.d.ts.map +0 -1
  250. package/storages/dataset.js.map +0 -1
  251. package/storages/index.d.ts.map +0 -1
  252. package/storages/index.js.map +0 -1
  253. package/storages/key_value_store.d.ts.map +0 -1
  254. package/storages/key_value_store.js.map +0 -1
  255. package/storages/request_list.d.ts.map +0 -1
  256. package/storages/request_list.js.map +0 -1
  257. package/storages/request_provider.d.ts +0 -308
  258. package/storages/request_provider.d.ts.map +0 -1
  259. package/storages/request_provider.js +0 -555
  260. package/storages/request_provider.js.map +0 -1
  261. package/storages/request_queue.d.ts.map +0 -1
  262. package/storages/request_queue.js.map +0 -1
  263. package/storages/request_queue_v2.d.ts +0 -87
  264. package/storages/request_queue_v2.d.ts.map +0 -1
  265. package/storages/request_queue_v2.js +0 -438
  266. package/storages/request_queue_v2.js.map +0 -1
  267. package/storages/sitemap_request_list.d.ts.map +0 -1
  268. package/storages/sitemap_request_list.js +0 -430
  269. package/storages/sitemap_request_list.js.map +0 -1
  270. package/storages/storage_manager.d.ts +0 -58
  271. package/storages/storage_manager.d.ts.map +0 -1
  272. package/storages/storage_manager.js +0 -105
  273. package/storages/storage_manager.js.map +0 -1
  274. package/storages/utils.d.ts.map +0 -1
  275. package/storages/utils.js.map +0 -1
  276. package/tsconfig.build.tsbuildinfo +0 -1
  277. package/typedefs.d.ts.map +0 -1
  278. package/typedefs.js.map +0 -1
  279. package/validators.d.ts.map +0 -1
  280. package/validators.js.map +0 -1
package/request.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { BinaryLike } from 'node:crypto';
2
- import type { Dictionary } from '@crawlee/types';
3
- import type { EnqueueLinksOptions } from './enqueue_links/enqueue_links.js';
4
- import type { AllowedHttpMethods } from './typedefs.js';
2
+ import type { AllowedHttpMethods, Dictionary } from '@crawlee/types';
3
+ import type { EnqueueStrategyOption } from './enqueue_links/enqueue_links.js';
4
+ import type { SkippedRequestReason } from './enqueue_links/shared.js';
5
5
  export declare enum RequestState {
6
6
  UNPROCESSED = 0,
7
7
  BEFORE_NAV = 1,
@@ -44,6 +44,7 @@ export declare enum RequestState {
44
44
  * @category Sources
45
45
  */
46
46
  declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
47
+ #private;
47
48
  /** Request ID */
48
49
  id?: string;
49
50
  /** URL of the web page to crawl. */
@@ -74,9 +75,12 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
74
75
  errorMessages: string[];
75
76
  /** Object with HTTP headers. Key is header name, value is the value. */
76
77
  headers?: Record<string, string>;
77
- /** Private store for the custom user data assigned to the request. */
78
- private _userData;
79
- /** Custom user data assigned to the request. */
78
+ /**
79
+ * Custom user data assigned to the request.
80
+ *
81
+ * All data stored in `userData` must be JSON-serializable.
82
+ * Storing non-serializable values (e.g. functions, symbols) may result in unexpected results.
83
+ */
80
84
  userData: UserData;
81
85
  /**
82
86
  * ISO datetime string that indicates the time when the request has been processed.
@@ -92,14 +96,35 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
92
96
  * @returns The native `fetch` API Request object.
93
97
  */
94
98
  intoFetchAPIRequest(): Request;
95
- /** Tells the crawler processing this request to skip the navigation and process the request directly. */
99
+ /**
100
+ * Tells the crawler processing this request to skip the navigation and process the request directly.
101
+ *
102
+ * When this is set to `true`, the crawling context will not contain the results of the navigation
103
+ * (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
104
+ * Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
105
+ */
96
106
  get skipNavigation(): boolean;
97
- /** Tells the crawler processing this request to skip the navigation and process the request directly. */
107
+ /**
108
+ * Tells the crawler processing this request to skip the navigation and process the request directly.
109
+ *
110
+ * When this is set to `true`, the crawling context will not contain the results of the navigation
111
+ * (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
112
+ * Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
113
+ */
98
114
  set skipNavigation(value: boolean);
99
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
100
- get sessionRotationCount(): number;
101
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
102
- set sessionRotationCount(value: number);
115
+ /**
116
+ * Depth of the request in the current crawl tree.
117
+ * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
118
+ */
119
+ get crawlDepth(): number;
120
+ /**
121
+ * Depth of the request in the current crawl tree.
122
+ * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
123
+ */
124
+ set crawlDepth(value: number);
125
+ /** ID of a session to use for this request. When set, the crawler will fetch this session from the session pool instead of creating a new one. */
126
+ get sessionId(): string | undefined;
127
+ set sessionId(value: string | undefined);
103
128
  /** shortcut for getting `request.userData.label` */
104
129
  get label(): string | undefined;
105
130
  /** shortcut for setting `request.userData.label` */
@@ -112,6 +137,14 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
112
137
  get state(): RequestState;
113
138
  /** Describes the request's current lifecycle state. */
114
139
  set state(value: RequestState);
140
+ /**
141
+ * Reason for skipping this request.
142
+ */
143
+ get skippedReason(): SkippedRequestReason | undefined;
144
+ /**
145
+ * Reason for skipping this request.
146
+ */
147
+ set skippedReason(value: SkippedRequestReason | undefined);
115
148
  private get enqueueStrategy();
116
149
  private set enqueueStrategy(value);
117
150
  /**
@@ -129,7 +162,7 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
129
162
  */
130
163
  pushErrorMessage(errorOrMessage: unknown, options?: PushErrorMessageOptions): void;
131
164
  /** @internal */
132
- static computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey, }: ComputeUniqueKeyOptions): string;
165
+ static computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey, alwaysEnqueue, }: ComputeUniqueKeyOptions): string;
133
166
  /** @internal */
134
167
  static hashPayload(payload: BinaryLike): string;
135
168
  }
@@ -150,7 +183,7 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
150
183
  * The `keepUrlFragment` option determines whether URL hash fragment is included in the `uniqueKey` or not.
151
184
  *
152
185
  * The `useExtendedUniqueKey` options determines whether method and payload are included in the `uniqueKey`,
153
- * producing a `uniqueKey` in the following format: `METHOD(payloadHash):normalizedUrl`. This is useful
186
+ * producing a `uniqueKey` in the following format: `METHOD|payloadHash|normalizedUrl`. This is useful
154
187
  * when requests point to the same URL, but with different methods and payloads. For example: form submits.
155
188
  *
156
189
  * Pass an arbitrary non-empty text value to the `uniqueKey` property
@@ -174,6 +207,9 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
174
207
  /**
175
208
  * Custom user data assigned to the request. Use this to save any request related data to the
176
209
  * request's scope, keeping them accessible on retries, failures etc.
210
+ *
211
+ * All data stored in `userData` must be JSON-serializable.
212
+ * Storing non-serializable values (e.g. functions, symbols) may result in unexpected results.
177
213
  */
178
214
  userData?: UserData;
179
215
  /**
@@ -195,17 +231,45 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
195
231
  * @default false
196
232
  */
197
233
  useExtendedUniqueKey?: boolean;
234
+ /**
235
+ * If `true` then a random value is included in the `uniqueKey` computation, ensuring the request
236
+ * is always enqueued even if a request with the same URL (and method/payload) is already present
237
+ * in the queue. Cannot be used together with a custom `uniqueKey`.
238
+ * @default false
239
+ */
240
+ alwaysEnqueue?: boolean;
198
241
  /**
199
242
  * The `true` value indicates that the request will not be automatically retried on error.
200
243
  * @default false
201
244
  */
202
245
  noRetry?: boolean;
246
+ /**
247
+ * ID of a session from the crawler's `SessionPool` to use for this request.
248
+ * When set, the crawler will fetch this session from the pool instead of creating a new one.
249
+ */
250
+ sessionId?: string;
203
251
  /**
204
252
  * If set to `true` then the crawler processing this request evaluates
205
253
  * the `requestHandler` immediately without prior browser navigation.
254
+ *
255
+ * When enabled, the crawling context will not contain the results of the navigation
256
+ * (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
257
+ * Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
206
258
  * @default false
207
259
  */
208
260
  skipNavigation?: boolean;
261
+ /**
262
+ * Depth of the request in the current crawl tree.
263
+ * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
264
+ * @default 0
265
+ */
266
+ crawlDepth?: number;
267
+ /**
268
+ * Reason for skipping this request.
269
+ * This is used to provide more information about why the request was skipped.
270
+ * @internal
271
+ */
272
+ skippedReason?: SkippedRequestReason;
209
273
  /**
210
274
  * Maximum number of retries for this request. Allows to override the global `maxRequestRetries` option of `BasicCrawler`.
211
275
  */
@@ -217,7 +281,7 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
217
281
  /** @internal */
218
282
  lockExpiresAt?: Date;
219
283
  /** @internal */
220
- enqueueStrategy?: EnqueueLinksOptions['strategy'];
284
+ enqueueStrategy?: EnqueueStrategyOption;
221
285
  }
222
286
  export interface PushErrorMessageOptions {
223
287
  /**
@@ -232,6 +296,7 @@ interface ComputeUniqueKeyOptions {
232
296
  payload?: string | Buffer;
233
297
  keepUrlFragment?: boolean;
234
298
  useExtendedUniqueKey?: boolean;
299
+ alwaysEnqueue?: boolean;
235
300
  }
236
301
  export type Source = (Partial<RequestOptions> & {
237
302
  requestsFromUrl?: string;
@@ -243,4 +308,3 @@ export interface InternalSource {
243
308
  regex?: RegExp;
244
309
  }
245
310
  export { CrawleeRequest as Request };
246
- //# sourceMappingURL=request.d.ts.map
package/request.js CHANGED
@@ -1,31 +1,13 @@
1
1
  import crypto from 'node:crypto';
2
2
  import util from 'node:util';
3
- import ow from 'ow';
4
- import { normalizeUrl } from '@apify/utilities';
5
- import { log as defaultLog } from './log.js';
3
+ import { z } from 'zod';
4
+ import { cryptoRandomObjectId, normalizeUrl } from '@apify/utilities';
5
+ import { serviceLocator } from './service_locator.js';
6
6
  import { keys } from './typedefs.js';
7
- // new properties on the Request object breaks serialization
8
- const log = defaultLog.child({ prefix: 'Request' });
9
- const requestOptionalPredicates = {
10
- id: ow.optional.string,
11
- loadedUrl: ow.optional.string.url,
12
- uniqueKey: ow.optional.string,
13
- method: ow.optional.string,
14
- payload: ow.optional.any(ow.string, ow.uint8Array),
15
- noRetry: ow.optional.boolean,
16
- retryCount: ow.optional.number,
17
- sessionRotationCount: ow.optional.number,
18
- maxRetries: ow.optional.number,
19
- errorMessages: ow.optional.array.ofType(ow.string),
20
- headers: ow.optional.object,
21
- userData: ow.optional.object,
22
- label: ow.optional.string,
23
- handledAt: ow.optional.any(ow.string.date, ow.date),
24
- keepUrlFragment: ow.optional.boolean,
25
- useExtendedUniqueKey: ow.optional.boolean,
26
- skipNavigation: ow.optional.boolean,
27
- state: ow.optional.number.greaterThanOrEqual(0).lessThanOrEqual(6),
28
- };
7
+ import { parseArgument, schemas } from './validators.js';
8
+ const dateString = z.string().refine((value) => !Number.isNaN(Date.parse(value)), {
9
+ message: 'Invalid input: expected a date string',
10
+ });
29
11
  export var RequestState;
30
12
  (function (RequestState) {
31
13
  RequestState[RequestState["UNPROCESSED"] = 0] = "UNPROCESSED";
@@ -37,6 +19,34 @@ export var RequestState;
37
19
  RequestState[RequestState["ERROR"] = 6] = "ERROR";
38
20
  RequestState[RequestState["SKIPPED"] = 7] = "SKIPPED";
39
21
  })(RequestState || (RequestState = {}));
22
+ const requestUrlSchema = z.object({ url: z.string() });
23
+ // new properties on the Request object breaks serialization
24
+ const requestOptionalSchemaShapes = {
25
+ id: z.string().optional(),
26
+ loadedUrl: z.url().optional(),
27
+ uniqueKey: z.string().optional(),
28
+ method: z.string().optional(),
29
+ payload: z.union([z.string(), z.instanceof(Uint8Array)]).optional(),
30
+ noRetry: z.boolean().optional(),
31
+ retryCount: schemas.anyNumber.optional(),
32
+ sessionId: z.string().optional(),
33
+ maxRetries: schemas.anyNumber.optional(),
34
+ errorMessages: schemas.arrayOf(z.string(), 'strings').optional(),
35
+ headers: z.looseObject({}).optional(),
36
+ userData: z.looseObject({}).optional(),
37
+ label: z.string().optional(),
38
+ handledAt: z.union([dateString, z.date()]).optional(),
39
+ keepUrlFragment: z.boolean().optional(),
40
+ useExtendedUniqueKey: z.boolean().optional(),
41
+ alwaysEnqueue: z.boolean().optional(),
42
+ skipNavigation: z.boolean().optional(),
43
+ crawlDepth: schemas.anyNumber
44
+ .refine((value) => value >= 0, 'Expected a number greater than or equal to 0')
45
+ .optional(),
46
+ state: z.enum(RequestState).optional(),
47
+ };
48
+ // Each schema is wrapped in a single-key object so validation errors carry the property name.
49
+ const requestOptionalSchemas = Object.fromEntries(Object.entries(requestOptionalSchemaShapes).map(([key, schema]) => [key, z.object({ [key]: schema })]));
40
50
  /**
41
51
  * Represents a URL to be crawled, optionally including HTTP method, headers, payload and other metadata.
42
52
  * The `Request` object also stores information about errors that occurred during processing of the request.
@@ -100,8 +110,13 @@ class CrawleeRequest {
100
110
  /** Object with HTTP headers. Key is header name, value is the value. */
101
111
  headers;
102
112
  /** Private store for the custom user data assigned to the request. */
103
- _userData = {};
104
- /** Custom user data assigned to the request. */
113
+ #userData = {};
114
+ /**
115
+ * Custom user data assigned to the request.
116
+ *
117
+ * All data stored in `userData` must be JSON-serializable.
118
+ * Storing non-serializable values (e.g. functions, symbols) may result in unexpected results.
119
+ */
105
120
  userData = {};
106
121
  /**
107
122
  * ISO datetime string that indicates the time when the request has been processed.
@@ -112,76 +127,89 @@ class CrawleeRequest {
112
127
  * `Request` parameters including the URL, HTTP method and headers, and others.
113
128
  */
114
129
  constructor(options) {
115
- ow(options, 'RequestOptions', ow.object);
116
- ow(options.url, 'RequestOptions.url', ow.string);
117
- // 'ow' validation is slow, because it checks all predicates
130
+ // A bare URL is a common slip — point at the object form instead of a generic type error.
131
+ if (typeof options === 'string') {
132
+ throw new TypeError(`\`Request\` options must be an object, got the string '${options}'. ` +
133
+ 'Did you mean `new Request({ url })`?');
134
+ }
135
+ parseArgument(options, schemas.anyObject, 'RequestOptions');
136
+ parseArgument(options, requestUrlSchema, 'RequestOptions');
137
+ // Full-shape validation is slow, because it checks all predicates
118
138
  // even if the validated object has only 1 property.
119
139
  // This custom validation loop iterates only over existing
120
140
  // properties and speeds up the validation cca 3-fold.
121
- // See https://github.com/sindresorhus/ow/issues/193
122
141
  keys(options).forEach((prop) => {
123
142
  // skip url, because it is validated above
124
143
  if (prop === 'url') {
125
144
  return;
126
145
  }
127
- const predicate = requestOptionalPredicates[prop];
146
+ const schema = requestOptionalSchemas[prop];
128
147
  const value = options[prop];
129
- if (predicate) {
130
- ow(value, `RequestOptions.${prop}`, predicate);
148
+ if (schema) {
149
+ parseArgument({ [prop]: value }, schema, 'RequestOptions');
131
150
  }
132
151
  });
133
- const { id, url, loadedUrl, uniqueKey, payload, noRetry = false, retryCount = 0, sessionRotationCount = 0, maxRetries, errorMessages = [], headers = {}, userData = {}, label, handledAt, keepUrlFragment = false, useExtendedUniqueKey = false, skipNavigation, enqueueStrategy, } = options;
152
+ const { id, url, loadedUrl, uniqueKey, payload, noRetry = false, retryCount = 0, sessionId, maxRetries, errorMessages = [], headers = {}, userData = {}, label, handledAt, keepUrlFragment = false, useExtendedUniqueKey = false, alwaysEnqueue = false, skipNavigation, enqueueStrategy, crawlDepth, } = options;
134
153
  let { method = 'GET' } = options;
135
154
  method = method.toUpperCase();
136
155
  if (method === 'GET' && payload)
137
156
  throw new Error('Request with GET method cannot have a payload.');
157
+ if (uniqueKey && alwaysEnqueue) {
158
+ throw new Error('`alwaysEnqueue` cannot be used together with a custom `uniqueKey`.');
159
+ }
138
160
  this.id = id;
139
161
  this.url = url;
140
162
  this.loadedUrl = loadedUrl;
141
163
  this.uniqueKey =
142
164
  uniqueKey ||
143
- CrawleeRequest.computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey });
165
+ CrawleeRequest.computeUniqueKey({
166
+ url,
167
+ method,
168
+ payload,
169
+ keepUrlFragment,
170
+ useExtendedUniqueKey,
171
+ alwaysEnqueue,
172
+ });
144
173
  this.method = method;
145
174
  this.payload = payload;
146
175
  this.noRetry = noRetry;
147
176
  this.retryCount = retryCount;
148
- this.sessionRotationCount = sessionRotationCount;
149
177
  this.errorMessages = [...errorMessages];
150
178
  this.headers = { ...headers };
151
179
  this.handledAt = handledAt instanceof Date ? handledAt.toISOString() : handledAt;
152
180
  if (label) {
153
181
  userData.label = label;
154
182
  }
183
+ // Read `__crawlee` explicitly - on a `userData` coming from another Request instance the
184
+ // bag is non-enumerable, so the spread alone would silently drop the internal state
185
+ // (e.g. `skipNavigation`) when a request is re-wrapped after a storage round trip.
186
+ this.#userData = { __crawlee: userData.__crawlee ?? {}, ...userData };
187
+ // `userData` must stay an enumerable own accessor — serialization in the storages relies on it
155
188
  Object.defineProperties(this, {
156
- _userData: {
157
- value: { __crawlee: {}, ...userData },
158
- enumerable: false,
159
- writable: true,
160
- },
161
189
  userData: {
162
- get: () => this._userData,
190
+ get: () => this.#userData,
163
191
  set: (value) => {
164
192
  Object.defineProperties(value, {
165
193
  __crawlee: {
166
- value: this._userData.__crawlee,
194
+ value: this.#userData.__crawlee,
167
195
  enumerable: false,
168
196
  writable: true,
169
197
  },
170
198
  toJSON: {
171
199
  value: () => {
172
- if (Object.keys(this._userData.__crawlee).length > 0) {
200
+ if (Object.keys(this.#userData.__crawlee).length > 0) {
173
201
  return {
174
- ...this._userData,
175
- __crawlee: this._userData.__crawlee,
202
+ ...this.#userData,
203
+ __crawlee: this.#userData.__crawlee,
176
204
  };
177
205
  }
178
- return this._userData;
206
+ return this.#userData;
179
207
  },
180
208
  enumerable: false,
181
209
  writable: true,
182
210
  },
183
211
  });
184
- this._userData = value;
212
+ this.#userData = value;
185
213
  },
186
214
  enumerable: true,
187
215
  },
@@ -192,6 +220,10 @@ class CrawleeRequest {
192
220
  this.skipNavigation = skipNavigation;
193
221
  if (maxRetries != null)
194
222
  this.maxRetries = maxRetries;
223
+ if (crawlDepth != null)
224
+ this.userData.__crawlee.crawlDepth ??= crawlDepth;
225
+ if (sessionId)
226
+ this.sessionId = sessionId;
195
227
  // If it's already set, don't override it (for instance when fetching from storage)
196
228
  if (enqueueStrategy) {
197
229
  this.enqueueStrategy ??= enqueueStrategy;
@@ -208,11 +240,23 @@ class CrawleeRequest {
208
240
  body: this.payload,
209
241
  });
210
242
  }
211
- /** Tells the crawler processing this request to skip the navigation and process the request directly. */
243
+ /**
244
+ * Tells the crawler processing this request to skip the navigation and process the request directly.
245
+ *
246
+ * When this is set to `true`, the crawling context will not contain the results of the navigation
247
+ * (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
248
+ * Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
249
+ */
212
250
  get skipNavigation() {
213
251
  return this.userData.__crawlee?.skipNavigation ?? false;
214
252
  }
215
- /** Tells the crawler processing this request to skip the navigation and process the request directly. */
253
+ /**
254
+ * Tells the crawler processing this request to skip the navigation and process the request directly.
255
+ *
256
+ * When this is set to `true`, the crawling context will not contain the results of the navigation
257
+ * (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
258
+ * Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
259
+ */
216
260
  set skipNavigation(value) {
217
261
  if (!this.userData.__crawlee) {
218
262
  this.userData.__crawlee = { skipNavigation: value };
@@ -221,18 +265,28 @@ class CrawleeRequest {
221
265
  this.userData.__crawlee.skipNavigation = value;
222
266
  }
223
267
  }
224
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
225
- get sessionRotationCount() {
226
- return this.userData.__crawlee?.sessionRotationCount ?? 0;
268
+ /**
269
+ * Depth of the request in the current crawl tree.
270
+ * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
271
+ */
272
+ get crawlDepth() {
273
+ return this.userData.__crawlee?.crawlDepth ?? 0;
227
274
  }
228
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
229
- set sessionRotationCount(value) {
230
- if (!this.userData.__crawlee) {
231
- this.userData.__crawlee = { sessionRotationCount: value };
232
- }
233
- else {
234
- this.userData.__crawlee.sessionRotationCount = value;
235
- }
275
+ /**
276
+ * Depth of the request in the current crawl tree.
277
+ * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
278
+ */
279
+ set crawlDepth(value) {
280
+ this.userData.__crawlee ??= {};
281
+ this.userData.__crawlee.crawlDepth = value;
282
+ }
283
+ /** ID of a session to use for this request. When set, the crawler will fetch this session from the session pool instead of creating a new one. */
284
+ get sessionId() {
285
+ return this.userData.__crawlee?.sessionId;
286
+ }
287
+ set sessionId(value) {
288
+ this.userData.__crawlee ??= {};
289
+ this.userData.__crawlee.sessionId = value;
236
290
  }
237
291
  /** shortcut for getting `request.userData.label` */
238
292
  get label() {
@@ -268,6 +322,23 @@ class CrawleeRequest {
268
322
  this.userData.__crawlee.state = value;
269
323
  }
270
324
  }
325
+ /**
326
+ * Reason for skipping this request.
327
+ */
328
+ get skippedReason() {
329
+ return this.userData.__crawlee?.skippedReason;
330
+ }
331
+ /**
332
+ * Reason for skipping this request.
333
+ */
334
+ set skippedReason(value) {
335
+ if (!this.userData.__crawlee) {
336
+ this.userData.__crawlee = { skippedReason: value };
337
+ }
338
+ else {
339
+ this.userData.__crawlee.skippedReason = value;
340
+ }
341
+ }
271
342
  get enqueueStrategy() {
272
343
  return this.userData.__crawlee?.enqueueStrategy;
273
344
  }
@@ -330,19 +401,28 @@ class CrawleeRequest {
330
401
  this.errorMessages.push(message);
331
402
  }
332
403
  /** @internal */
333
- static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, }) {
404
+ static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, alwaysEnqueue = false, }) {
334
405
  const normalizedMethod = method.toUpperCase();
335
406
  const normalizedUrl = normalizeUrl(url, keepUrlFragment) || url; // It returns null when url is invalid, causing weird errors.
407
+ let uniqueKey;
336
408
  if (!useExtendedUniqueKey) {
337
409
  if (normalizedMethod !== 'GET' && payload) {
338
- log.warningOnce(`We've encountered a ${normalizedMethod} Request with a payload. ` +
410
+ serviceLocator
411
+ .getLogger()
412
+ .warningOnce(`We've encountered a ${normalizedMethod} Request with a payload. ` +
339
413
  'This is fine. Just letting you know that if your requests point to the same URL ' +
340
414
  'and differ only in method and payload, you should see the "useExtendedUniqueKey" option of Request constructor.');
341
415
  }
342
- return normalizedUrl;
416
+ uniqueKey = normalizedUrl;
417
+ }
418
+ else {
419
+ const payloadHash = payload ? CrawleeRequest.hashPayload(payload) : '';
420
+ uniqueKey = `${normalizedMethod}|${payloadHash}|${normalizedUrl}`;
421
+ }
422
+ if (alwaysEnqueue) {
423
+ uniqueKey = `${cryptoRandomObjectId(17)}|${uniqueKey}`;
343
424
  }
344
- const payloadHash = payload ? CrawleeRequest.hashPayload(payload) : '';
345
- return `${normalizedMethod}(${payloadHash}):${normalizedUrl}`;
425
+ return uniqueKey;
346
426
  }
347
427
  /** @internal */
348
428
  static hashPayload(payload) {
@@ -350,4 +430,3 @@ class CrawleeRequest {
350
430
  }
351
431
  }
352
432
  export { CrawleeRequest as Request };
353
- //# sourceMappingURL=request.js.map