@crawlee/core 4.0.0-beta.15 → 4.0.0-beta.150

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 (287) hide show
  1. package/README.md +14 -14
  2. package/autoscaling/autoscaled_pool.d.ts +73 -177
  3. package/autoscaling/autoscaled_pool.js +182 -329
  4. package/autoscaling/concurrency_system.d.ts +268 -0
  5. package/autoscaling/concurrency_system.js +364 -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 +98 -0
  13. package/autoscaling/load_signal.js +103 -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 -126
  33. package/crawlers/crawler_commons.js +1 -108
  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 -64
  43. package/crawlers/statistics.js +354 -165
  44. package/debug.d.ts +36 -0
  45. package/debug.js +70 -0
  46. package/enqueue_links/enqueue_links.d.ts +61 -154
  47. package/enqueue_links/enqueue_links.js +40 -232
  48. package/enqueue_links/index.d.ts +0 -1
  49. package/enqueue_links/index.js +0 -1
  50. package/enqueue_links/shared.d.ts +55 -28
  51. package/enqueue_links/shared.js +116 -69
  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 -5
  63. package/index.js +8 -4
  64. package/iterables.d.ts +79 -0
  65. package/iterables.js +134 -0
  66. package/log.d.ts +77 -1
  67. package/log.js +104 -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 +44 -0
  73. package/memory-storage/memory-storage.js +160 -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 +106 -0
  78. package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
  79. package/memory-storage/resource-clients/key-value-store.js +199 -0
  80. package/memory-storage/resource-clients/request-queue.d.ts +77 -0
  81. package/memory-storage/resource-clients/request-queue.js +407 -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 +13 -12
  87. package/proxy_configuration.d.ts +22 -128
  88. package/proxy_configuration.js +32 -144
  89. package/recoverable_state.d.ts +83 -51
  90. package/recoverable_state.js +163 -72
  91. package/request.d.ts +57 -16
  92. package/request.js +130 -69
  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 +39 -89
  108. package/session_pool/session.js +102 -159
  109. package/session_pool/session_pool.d.ts +67 -91
  110. package/session_pool/session_pool.js +196 -187
  111. package/storages/batched_adds.d.ts +37 -0
  112. package/storages/batched_adds.js +73 -0
  113. package/storages/dataset.d.ts +109 -56
  114. package/storages/dataset.js +284 -149
  115. package/storages/index.d.ts +9 -9
  116. package/storages/index.js +7 -9
  117. package/storages/key_value_store.d.ts +183 -48
  118. package/storages/key_value_store.js +444 -171
  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 +53 -115
  124. package/storages/request_list.js +194 -167
  125. package/storages/request_loader.d.ts +133 -0
  126. package/storages/request_loader.js +36 -0
  127. package/storages/request_manager.d.ts +109 -0
  128. package/storages/request_manager.js +1 -0
  129. package/storages/request_manager_tandem.d.ts +55 -23
  130. package/storages/request_manager_tandem.js +139 -57
  131. package/storages/request_queue.d.ts +286 -48
  132. package/storages/request_queue.js +757 -218
  133. package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +43 -91
  134. package/storages/sitemap_request_loader.js +439 -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 +222 -0
  140. package/storages/throttling_request_manager.js +780 -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 -85
  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/recoverable_state.d.ts.map +0 -1
  226. package/recoverable_state.js.map +0 -1
  227. package/request.d.ts.map +0 -1
  228. package/request.js.map +0 -1
  229. package/router.d.ts.map +0 -1
  230. package/router.js.map +0 -1
  231. package/serialization.d.ts.map +0 -1
  232. package/serialization.js.map +0 -1
  233. package/session_pool/consts.d.ts.map +0 -1
  234. package/session_pool/consts.js.map +0 -1
  235. package/session_pool/errors.d.ts.map +0 -1
  236. package/session_pool/errors.js.map +0 -1
  237. package/session_pool/events.d.ts +0 -3
  238. package/session_pool/events.d.ts.map +0 -1
  239. package/session_pool/events.js +0 -3
  240. package/session_pool/events.js.map +0 -1
  241. package/session_pool/index.d.ts.map +0 -1
  242. package/session_pool/index.js.map +0 -1
  243. package/session_pool/session.d.ts.map +0 -1
  244. package/session_pool/session.js.map +0 -1
  245. package/session_pool/session_pool.d.ts.map +0 -1
  246. package/session_pool/session_pool.js.map +0 -1
  247. package/storages/access_checking.d.ts +0 -13
  248. package/storages/access_checking.d.ts.map +0 -1
  249. package/storages/access_checking.js +0 -14
  250. package/storages/access_checking.js.map +0 -1
  251. package/storages/dataset.d.ts.map +0 -1
  252. package/storages/dataset.js.map +0 -1
  253. package/storages/index.d.ts.map +0 -1
  254. package/storages/index.js.map +0 -1
  255. package/storages/key_value_store.d.ts.map +0 -1
  256. package/storages/key_value_store.js.map +0 -1
  257. package/storages/request_list.d.ts.map +0 -1
  258. package/storages/request_list.js.map +0 -1
  259. package/storages/request_list_adapter.d.ts +0 -58
  260. package/storages/request_list_adapter.d.ts.map +0 -1
  261. package/storages/request_list_adapter.js +0 -81
  262. package/storages/request_list_adapter.js.map +0 -1
  263. package/storages/request_manager_tandem.d.ts.map +0 -1
  264. package/storages/request_manager_tandem.js.map +0 -1
  265. package/storages/request_provider.d.ts +0 -371
  266. package/storages/request_provider.d.ts.map +0 -1
  267. package/storages/request_provider.js +0 -585
  268. package/storages/request_provider.js.map +0 -1
  269. package/storages/request_queue.d.ts.map +0 -1
  270. package/storages/request_queue.js.map +0 -1
  271. package/storages/request_queue_v2.d.ts +0 -87
  272. package/storages/request_queue_v2.d.ts.map +0 -1
  273. package/storages/request_queue_v2.js +0 -438
  274. package/storages/request_queue_v2.js.map +0 -1
  275. package/storages/sitemap_request_list.d.ts.map +0 -1
  276. package/storages/sitemap_request_list.js +0 -430
  277. package/storages/sitemap_request_list.js.map +0 -1
  278. package/storages/storage_manager.d.ts +0 -58
  279. package/storages/storage_manager.d.ts.map +0 -1
  280. package/storages/storage_manager.js +0 -105
  281. package/storages/storage_manager.js.map +0 -1
  282. package/storages/utils.d.ts.map +0 -1
  283. package/storages/utils.js.map +0 -1
  284. package/typedefs.d.ts.map +0 -1
  285. package/typedefs.js.map +0 -1
  286. package/validators.d.ts.map +0 -1
  287. package/validators.js.map +0 -1
package/request.d.ts CHANGED
@@ -1,8 +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';
2
+ import type { AllowedHttpMethods, Dictionary } from '@crawlee/types';
3
+ import type { EnqueueStrategyOption } from './enqueue_links/enqueue_links.js';
4
4
  import type { SkippedRequestReason } from './enqueue_links/shared.js';
5
- import type { AllowedHttpMethods } from './typedefs.js';
6
5
  export declare enum RequestState {
7
6
  UNPROCESSED = 0,
8
7
  BEFORE_NAV = 1,
@@ -45,6 +44,7 @@ export declare enum RequestState {
45
44
  * @category Sources
46
45
  */
47
46
  declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
47
+ #private;
48
48
  /** Request ID */
49
49
  id?: string;
50
50
  /** URL of the web page to crawl. */
@@ -75,9 +75,12 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
75
75
  errorMessages: string[];
76
76
  /** Object with HTTP headers. Key is header name, value is the value. */
77
77
  headers?: Record<string, string>;
78
- /** Private store for the custom user data assigned to the request. */
79
- private _userData;
80
- /** 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
+ */
81
84
  userData: UserData;
82
85
  /**
83
86
  * ISO datetime string that indicates the time when the request has been processed.
@@ -93,9 +96,21 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
93
96
  * @returns The native `fetch` API Request object.
94
97
  */
95
98
  intoFetchAPIRequest(): Request;
96
- /** 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
+ */
97
106
  get skipNavigation(): boolean;
98
- /** 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
+ */
99
114
  set skipNavigation(value: boolean);
100
115
  /**
101
116
  * Depth of the request in the current crawl tree.
@@ -107,10 +122,9 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
107
122
  * Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
108
123
  */
109
124
  set crawlDepth(value: number);
110
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
111
- get sessionRotationCount(): number;
112
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
113
- set sessionRotationCount(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);
114
128
  /** shortcut for getting `request.userData.label` */
115
129
  get label(): string | undefined;
116
130
  /** shortcut for setting `request.userData.label` */
@@ -123,6 +137,14 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
123
137
  get state(): RequestState;
124
138
  /** Describes the request's current lifecycle state. */
125
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);
126
148
  private get enqueueStrategy();
127
149
  private set enqueueStrategy(value);
128
150
  /**
@@ -140,7 +162,7 @@ declare class CrawleeRequest<UserData extends Dictionary = Dictionary> {
140
162
  */
141
163
  pushErrorMessage(errorOrMessage: unknown, options?: PushErrorMessageOptions): void;
142
164
  /** @internal */
143
- static computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey, }: ComputeUniqueKeyOptions): string;
165
+ static computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey, alwaysEnqueue, }: ComputeUniqueKeyOptions): string;
144
166
  /** @internal */
145
167
  static hashPayload(payload: BinaryLike): string;
146
168
  }
@@ -161,7 +183,7 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
161
183
  * The `keepUrlFragment` option determines whether URL hash fragment is included in the `uniqueKey` or not.
162
184
  *
163
185
  * The `useExtendedUniqueKey` options determines whether method and payload are included in the `uniqueKey`,
164
- * 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
165
187
  * when requests point to the same URL, but with different methods and payloads. For example: form submits.
166
188
  *
167
189
  * Pass an arbitrary non-empty text value to the `uniqueKey` property
@@ -185,6 +207,9 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
185
207
  /**
186
208
  * Custom user data assigned to the request. Use this to save any request related data to the
187
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.
188
213
  */
189
214
  userData?: UserData;
190
215
  /**
@@ -206,14 +231,30 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
206
231
  * @default false
207
232
  */
208
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;
209
241
  /**
210
242
  * The `true` value indicates that the request will not be automatically retried on error.
211
243
  * @default false
212
244
  */
213
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;
214
251
  /**
215
252
  * If set to `true` then the crawler processing this request evaluates
216
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.
217
258
  * @default false
218
259
  */
219
260
  skipNavigation?: boolean;
@@ -240,7 +281,7 @@ export interface RequestOptions<UserData extends Dictionary = Dictionary> {
240
281
  /** @internal */
241
282
  lockExpiresAt?: Date;
242
283
  /** @internal */
243
- enqueueStrategy?: EnqueueLinksOptions['strategy'];
284
+ enqueueStrategy?: EnqueueStrategyOption;
244
285
  }
245
286
  export interface PushErrorMessageOptions {
246
287
  /**
@@ -255,6 +296,7 @@ interface ComputeUniqueKeyOptions {
255
296
  payload?: string | Buffer;
256
297
  keepUrlFragment?: boolean;
257
298
  useExtendedUniqueKey?: boolean;
299
+ alwaysEnqueue?: boolean;
258
300
  }
259
301
  export type Source = (Partial<RequestOptions> & {
260
302
  requestsFromUrl?: string;
@@ -266,4 +308,3 @@ export interface InternalSource {
266
308
  regex?: RegExp;
267
309
  }
268
310
  export { CrawleeRequest as Request };
269
- //# sourceMappingURL=request.d.ts.map
package/request.js CHANGED
@@ -1,32 +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
- crawlDepth: ow.optional.number.greaterThanOrEqual(0),
28
- state: ow.optional.number.greaterThanOrEqual(0).lessThanOrEqual(6),
29
- };
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
+ });
30
11
  export var RequestState;
31
12
  (function (RequestState) {
32
13
  RequestState[RequestState["UNPROCESSED"] = 0] = "UNPROCESSED";
@@ -38,6 +19,34 @@ export var RequestState;
38
19
  RequestState[RequestState["ERROR"] = 6] = "ERROR";
39
20
  RequestState[RequestState["SKIPPED"] = 7] = "SKIPPED";
40
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 })]));
41
50
  /**
42
51
  * Represents a URL to be crawled, optionally including HTTP method, headers, payload and other metadata.
43
52
  * The `Request` object also stores information about errors that occurred during processing of the request.
@@ -101,8 +110,13 @@ class CrawleeRequest {
101
110
  /** Object with HTTP headers. Key is header name, value is the value. */
102
111
  headers;
103
112
  /** Private store for the custom user data assigned to the request. */
104
- _userData = {};
105
- /** 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
+ */
106
120
  userData = {};
107
121
  /**
108
122
  * ISO datetime string that indicates the time when the request has been processed.
@@ -113,76 +127,89 @@ class CrawleeRequest {
113
127
  * `Request` parameters including the URL, HTTP method and headers, and others.
114
128
  */
115
129
  constructor(options) {
116
- ow(options, 'RequestOptions', ow.object);
117
- ow(options.url, 'RequestOptions.url', ow.string);
118
- // '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
119
138
  // even if the validated object has only 1 property.
120
139
  // This custom validation loop iterates only over existing
121
140
  // properties and speeds up the validation cca 3-fold.
122
- // See https://github.com/sindresorhus/ow/issues/193
123
141
  keys(options).forEach((prop) => {
124
142
  // skip url, because it is validated above
125
143
  if (prop === 'url') {
126
144
  return;
127
145
  }
128
- const predicate = requestOptionalPredicates[prop];
146
+ const schema = requestOptionalSchemas[prop];
129
147
  const value = options[prop];
130
- if (predicate) {
131
- ow(value, `RequestOptions.${prop}`, predicate);
148
+ if (schema) {
149
+ parseArgument({ [prop]: value }, schema, 'RequestOptions');
132
150
  }
133
151
  });
134
- const { id, url, loadedUrl, uniqueKey, payload, noRetry = false, retryCount = 0, sessionRotationCount = 0, maxRetries, errorMessages = [], headers = {}, userData = {}, label, handledAt, keepUrlFragment = false, useExtendedUniqueKey = false, skipNavigation, enqueueStrategy, crawlDepth, } = 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;
135
153
  let { method = 'GET' } = options;
136
154
  method = method.toUpperCase();
137
155
  if (method === 'GET' && payload)
138
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
+ }
139
160
  this.id = id;
140
161
  this.url = url;
141
162
  this.loadedUrl = loadedUrl;
142
163
  this.uniqueKey =
143
164
  uniqueKey ||
144
- CrawleeRequest.computeUniqueKey({ url, method, payload, keepUrlFragment, useExtendedUniqueKey });
165
+ CrawleeRequest.computeUniqueKey({
166
+ url,
167
+ method,
168
+ payload,
169
+ keepUrlFragment,
170
+ useExtendedUniqueKey,
171
+ alwaysEnqueue,
172
+ });
145
173
  this.method = method;
146
174
  this.payload = payload;
147
175
  this.noRetry = noRetry;
148
176
  this.retryCount = retryCount;
149
- this.sessionRotationCount = sessionRotationCount;
150
177
  this.errorMessages = [...errorMessages];
151
178
  this.headers = { ...headers };
152
179
  this.handledAt = handledAt instanceof Date ? handledAt.toISOString() : handledAt;
153
180
  if (label) {
154
181
  userData.label = label;
155
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
156
188
  Object.defineProperties(this, {
157
- _userData: {
158
- value: { __crawlee: {}, ...userData },
159
- enumerable: false,
160
- writable: true,
161
- },
162
189
  userData: {
163
- get: () => this._userData,
190
+ get: () => this.#userData,
164
191
  set: (value) => {
165
192
  Object.defineProperties(value, {
166
193
  __crawlee: {
167
- value: this._userData.__crawlee,
194
+ value: this.#userData.__crawlee,
168
195
  enumerable: false,
169
196
  writable: true,
170
197
  },
171
198
  toJSON: {
172
199
  value: () => {
173
- if (Object.keys(this._userData.__crawlee).length > 0) {
200
+ if (Object.keys(this.#userData.__crawlee).length > 0) {
174
201
  return {
175
- ...this._userData,
176
- __crawlee: this._userData.__crawlee,
202
+ ...this.#userData,
203
+ __crawlee: this.#userData.__crawlee,
177
204
  };
178
205
  }
179
- return this._userData;
206
+ return this.#userData;
180
207
  },
181
208
  enumerable: false,
182
209
  writable: true,
183
210
  },
184
211
  });
185
- this._userData = value;
212
+ this.#userData = value;
186
213
  },
187
214
  enumerable: true,
188
215
  },
@@ -195,6 +222,8 @@ class CrawleeRequest {
195
222
  this.maxRetries = maxRetries;
196
223
  if (crawlDepth != null)
197
224
  this.userData.__crawlee.crawlDepth ??= crawlDepth;
225
+ if (sessionId)
226
+ this.sessionId = sessionId;
198
227
  // If it's already set, don't override it (for instance when fetching from storage)
199
228
  if (enqueueStrategy) {
200
229
  this.enqueueStrategy ??= enqueueStrategy;
@@ -211,11 +240,23 @@ class CrawleeRequest {
211
240
  body: this.payload,
212
241
  });
213
242
  }
214
- /** 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
+ */
215
250
  get skipNavigation() {
216
251
  return this.userData.__crawlee?.skipNavigation ?? false;
217
252
  }
218
- /** 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
+ */
219
260
  set skipNavigation(value) {
220
261
  if (!this.userData.__crawlee) {
221
262
  this.userData.__crawlee = { skipNavigation: value };
@@ -239,18 +280,13 @@ class CrawleeRequest {
239
280
  this.userData.__crawlee ??= {};
240
281
  this.userData.__crawlee.crawlDepth = value;
241
282
  }
242
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
243
- get sessionRotationCount() {
244
- return this.userData.__crawlee?.sessionRotationCount ?? 0;
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;
245
286
  }
246
- /** Indicates the number of times the crawling of the request has rotated the session due to a session or a proxy error. */
247
- set sessionRotationCount(value) {
248
- if (!this.userData.__crawlee) {
249
- this.userData.__crawlee = { sessionRotationCount: value };
250
- }
251
- else {
252
- this.userData.__crawlee.sessionRotationCount = value;
253
- }
287
+ set sessionId(value) {
288
+ this.userData.__crawlee ??= {};
289
+ this.userData.__crawlee.sessionId = value;
254
290
  }
255
291
  /** shortcut for getting `request.userData.label` */
256
292
  get label() {
@@ -286,6 +322,23 @@ class CrawleeRequest {
286
322
  this.userData.__crawlee.state = value;
287
323
  }
288
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
+ }
289
342
  get enqueueStrategy() {
290
343
  return this.userData.__crawlee?.enqueueStrategy;
291
344
  }
@@ -348,19 +401,28 @@ class CrawleeRequest {
348
401
  this.errorMessages.push(message);
349
402
  }
350
403
  /** @internal */
351
- static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, }) {
404
+ static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, alwaysEnqueue = false, }) {
352
405
  const normalizedMethod = method.toUpperCase();
353
406
  const normalizedUrl = normalizeUrl(url, keepUrlFragment) || url; // It returns null when url is invalid, causing weird errors.
407
+ let uniqueKey;
354
408
  if (!useExtendedUniqueKey) {
355
409
  if (normalizedMethod !== 'GET' && payload) {
356
- 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. ` +
357
413
  'This is fine. Just letting you know that if your requests point to the same URL ' +
358
414
  'and differ only in method and payload, you should see the "useExtendedUniqueKey" option of Request constructor.');
359
415
  }
360
- 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}`;
361
424
  }
362
- const payloadHash = payload ? CrawleeRequest.hashPayload(payload) : '';
363
- return `${normalizedMethod}(${payloadHash}):${normalizedUrl}`;
425
+ return uniqueKey;
364
426
  }
365
427
  /** @internal */
366
428
  static hashPayload(payload) {
@@ -368,4 +430,3 @@ class CrawleeRequest {
368
430
  }
369
431
  }
370
432
  export { CrawleeRequest as Request };
371
- //# sourceMappingURL=request.js.map