@crawlee/core 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.
- package/README.md +17 -13
- package/byte_utils.d.ts +17 -0
- package/byte_utils.js +42 -0
- package/configuration.d.ts +88 -234
- package/configuration.js +162 -230
- package/debug.d.ts +36 -0
- package/debug.js +70 -0
- package/errors.d.ts +43 -10
- package/errors.js +57 -12
- package/events/event_manager.d.ts +35 -9
- package/events/event_manager.js +12 -13
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -5
- package/events/local_event_manager.js +39 -42
- package/events/system_info.d.ts +38 -0
- package/events/system_info.js +1 -0
- package/index.d.ts +8 -11
- package/index.js +9 -10
- package/internal.d.ts +8 -0
- package/internal.js +9 -0
- package/iterables.d.ts +79 -0
- package/iterables.js +134 -0
- package/log.d.ts +81 -3
- package/log.js +134 -1
- package/memory-storage/consts.d.ts +4 -0
- package/memory-storage/consts.js +4 -0
- package/memory-storage/index.d.ts +1 -0
- package/memory-storage/index.js +1 -0
- package/memory-storage/memory-storage.d.ts +43 -0
- package/memory-storage/memory-storage.js +158 -0
- package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
- package/memory-storage/resource-clients/common/base-client.js +6 -0
- package/memory-storage/resource-clients/dataset.d.ts +40 -0
- package/memory-storage/resource-clients/dataset.js +106 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +56 -0
- package/memory-storage/resource-clients/key-value-store.js +180 -0
- package/memory-storage/resource-clients/request-queue.d.ts +77 -0
- package/memory-storage/resource-clients/request-queue.js +414 -0
- package/memory-storage/utils.d.ts +16 -0
- package/memory-storage/utils.js +41 -0
- package/owned_or_injected.d.ts +58 -0
- package/owned_or_injected.js +98 -0
- package/package.json +19 -20
- package/proxy_configuration.d.ts +29 -155
- package/proxy_configuration.js +38 -183
- package/recoverable_state.d.ts +177 -0
- package/recoverable_state.js +268 -0
- package/request.d.ts +62 -81
- package/request.js +125 -220
- package/serialization.d.ts +0 -1
- package/serialization.js +18 -18
- package/service_locator.d.ts +168 -0
- package/service_locator.js +255 -0
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +120 -56
- package/storages/dataset.js +299 -148
- package/storages/index.d.ts +9 -8
- package/storages/index.js +5 -8
- package/storages/key_value_store.d.ts +192 -65
- package/storages/key_value_store.js +453 -193
- package/storages/key_value_store_codec.d.ts +32 -0
- package/storages/key_value_store_codec.js +113 -0
- package/storages/request_dedup_cache.d.ts +22 -0
- package/storages/request_dedup_cache.js +48 -0
- package/storages/request_list.d.ts +55 -137
- package/storages/request_list.js +272 -245
- package/storages/request_loader.d.ts +127 -0
- package/storages/request_loader.js +36 -0
- package/storages/request_manager.d.ts +119 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +94 -0
- package/storages/request_manager_tandem.js +200 -0
- package/storages/request_queue.d.ts +293 -48
- package/storages/request_queue.js +766 -216
- package/storages/storage_instance_manager.d.ts +86 -0
- package/storages/storage_instance_manager.js +256 -0
- package/storages/storage_stats.d.ts +48 -0
- package/storages/storage_stats.js +29 -0
- package/storages/transaction.d.ts +271 -0
- package/storages/transaction.js +296 -0
- package/storages/utils.d.ts +59 -11
- package/storages/utils.js +75 -15
- package/system-info/cpu-info.d.ts +67 -0
- package/system-info/cpu-info.js +216 -0
- package/system-info/memory-info.d.ts +31 -0
- package/system-info/memory-info.js +115 -0
- package/system-info/ps-tree.d.ts +17 -0
- package/system-info/ps-tree.js +144 -0
- package/system-info/runtime.d.ts +14 -0
- package/system-info/runtime.js +80 -0
- package/typedefs.d.ts +0 -6
- package/typedefs.js +0 -1
- package/url.d.ts +9 -0
- package/url.js +11 -0
- package/validators.d.ts +23 -18
- package/validators.js +14 -18
- package/autoscaling/autoscaled_pool.d.ts +0 -300
- package/autoscaling/autoscaled_pool.d.ts.map +0 -1
- package/autoscaling/autoscaled_pool.js +0 -533
- package/autoscaling/autoscaled_pool.js.map +0 -1
- package/autoscaling/index.d.ts +0 -4
- package/autoscaling/index.d.ts.map +0 -1
- package/autoscaling/index.js +0 -4
- package/autoscaling/index.js.map +0 -1
- package/autoscaling/snapshotter.d.ts +0 -189
- package/autoscaling/snapshotter.d.ts.map +0 -1
- package/autoscaling/snapshotter.js +0 -292
- package/autoscaling/snapshotter.js.map +0 -1
- package/autoscaling/system_status.d.ts +0 -181
- package/autoscaling/system_status.d.ts.map +0 -1
- package/autoscaling/system_status.js +0 -169
- package/autoscaling/system_status.js.map +0 -1
- package/configuration.d.ts.map +0 -1
- package/configuration.js.map +0 -1
- package/cookie_utils.d.ts +0 -43
- package/cookie_utils.d.ts.map +0 -1
- package/cookie_utils.js +0 -113
- package/cookie_utils.js.map +0 -1
- package/crawlers/crawler_commons.d.ts +0 -199
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.js +0 -116
- package/crawlers/crawler_commons.js.map +0 -1
- package/crawlers/crawler_extension.d.ts +0 -12
- package/crawlers/crawler_extension.d.ts.map +0 -1
- package/crawlers/crawler_extension.js +0 -14
- package/crawlers/crawler_extension.js.map +0 -1
- package/crawlers/crawler_utils.d.ts +0 -10
- package/crawlers/crawler_utils.d.ts.map +0 -1
- package/crawlers/crawler_utils.js +0 -12
- package/crawlers/crawler_utils.js.map +0 -1
- package/crawlers/error_snapshotter.d.ts +0 -59
- package/crawlers/error_snapshotter.d.ts.map +0 -1
- package/crawlers/error_snapshotter.js +0 -118
- package/crawlers/error_snapshotter.js.map +0 -1
- package/crawlers/error_tracker.d.ts +0 -54
- package/crawlers/error_tracker.d.ts.map +0 -1
- package/crawlers/error_tracker.js +0 -309
- package/crawlers/error_tracker.js.map +0 -1
- package/crawlers/index.d.ts +0 -7
- package/crawlers/index.d.ts.map +0 -1
- package/crawlers/index.js +0 -7
- package/crawlers/index.js.map +0 -1
- package/crawlers/statistics.d.ts +0 -204
- package/crawlers/statistics.d.ts.map +0 -1
- package/crawlers/statistics.js +0 -346
- package/crawlers/statistics.js.map +0 -1
- package/enqueue_links/enqueue_links.d.ts +0 -242
- package/enqueue_links/enqueue_links.d.ts.map +0 -1
- package/enqueue_links/enqueue_links.js +0 -250
- package/enqueue_links/enqueue_links.js.map +0 -1
- package/enqueue_links/index.d.ts +0 -3
- package/enqueue_links/index.d.ts.map +0 -1
- package/enqueue_links/index.js +0 -3
- package/enqueue_links/index.js.map +0 -1
- package/enqueue_links/shared.d.ts +0 -67
- package/enqueue_links/shared.d.ts.map +0 -1
- package/enqueue_links/shared.js +0 -190
- package/enqueue_links/shared.js.map +0 -1
- package/errors.d.ts.map +0 -1
- package/errors.js.map +0 -1
- package/events/event_manager.d.ts.map +0 -1
- package/events/event_manager.js.map +0 -1
- package/events/index.d.ts.map +0 -1
- package/events/index.js.map +0 -1
- package/events/local_event_manager.d.ts.map +0 -1
- package/events/local_event_manager.js.map +0 -1
- package/http_clients/base-http-client.d.ts +0 -134
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -33
- package/http_clients/base-http-client.js.map +0 -1
- package/http_clients/form-data-like.d.ts +0 -67
- package/http_clients/form-data-like.d.ts.map +0 -1
- package/http_clients/form-data-like.js +0 -5
- package/http_clients/form-data-like.js.map +0 -1
- package/http_clients/got-scraping-http-client.d.ts +0 -15
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -69
- package/http_clients/got-scraping-http-client.js.map +0 -1
- package/http_clients/index.d.ts +0 -3
- package/http_clients/index.d.ts.map +0 -1
- package/http_clients/index.js +0 -3
- package/http_clients/index.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/log.d.ts.map +0 -1
- package/log.js.map +0 -1
- package/proxy_configuration.d.ts.map +0 -1
- package/proxy_configuration.js.map +0 -1
- package/request.d.ts.map +0 -1
- package/request.js.map +0 -1
- package/router.d.ts +0 -134
- package/router.d.ts.map +0 -1
- package/router.js +0 -164
- package/router.js.map +0 -1
- package/serialization.d.ts.map +0 -1
- package/serialization.js.map +0 -1
- package/session_pool/consts.d.ts +0 -4
- package/session_pool/consts.d.ts.map +0 -1
- package/session_pool/consts.js +0 -4
- package/session_pool/consts.js.map +0 -1
- package/session_pool/errors.d.ts +0 -8
- package/session_pool/errors.d.ts.map +0 -1
- package/session_pool/errors.js +0 -12
- package/session_pool/errors.js.map +0 -1
- package/session_pool/events.d.ts +0 -3
- package/session_pool/events.d.ts.map +0 -1
- package/session_pool/events.js +0 -3
- package/session_pool/events.js.map +0 -1
- package/session_pool/index.d.ts +0 -6
- package/session_pool/index.d.ts.map +0 -1
- package/session_pool/index.js +0 -6
- package/session_pool/index.js.map +0 -1
- package/session_pool/session.d.ts +0 -199
- package/session_pool/session.d.ts.map +0 -1
- package/session_pool/session.js +0 -271
- package/session_pool/session.js.map +0 -1
- package/session_pool/session_pool.d.ts +0 -251
- package/session_pool/session_pool.d.ts.map +0 -1
- package/session_pool/session_pool.js +0 -375
- package/session_pool/session_pool.js.map +0 -1
- package/storages/access_checking.d.ts +0 -13
- package/storages/access_checking.d.ts.map +0 -1
- package/storages/access_checking.js +0 -14
- package/storages/access_checking.js.map +0 -1
- package/storages/dataset.d.ts.map +0 -1
- package/storages/dataset.js.map +0 -1
- package/storages/index.d.ts.map +0 -1
- package/storages/index.js.map +0 -1
- package/storages/key_value_store.d.ts.map +0 -1
- package/storages/key_value_store.js.map +0 -1
- package/storages/request_list.d.ts.map +0 -1
- package/storages/request_list.js.map +0 -1
- package/storages/request_provider.d.ts +0 -307
- package/storages/request_provider.d.ts.map +0 -1
- package/storages/request_provider.js +0 -555
- package/storages/request_provider.js.map +0 -1
- package/storages/request_queue.d.ts.map +0 -1
- package/storages/request_queue.js.map +0 -1
- package/storages/request_queue_v2.d.ts +0 -87
- package/storages/request_queue_v2.d.ts.map +0 -1
- package/storages/request_queue_v2.js +0 -438
- package/storages/request_queue_v2.js.map +0 -1
- package/storages/sitemap_request_list.d.ts +0 -245
- package/storages/sitemap_request_list.d.ts.map +0 -1
- package/storages/sitemap_request_list.js +0 -430
- package/storages/sitemap_request_list.js.map +0 -1
- package/storages/storage_manager.d.ts +0 -58
- package/storages/storage_manager.d.ts.map +0 -1
- package/storages/storage_manager.js +0 -105
- package/storages/storage_manager.js.map +0 -1
- package/storages/utils.d.ts.map +0 -1
- package/storages/utils.js.map +0 -1
- package/tsconfig.build.tsbuildinfo +0 -1
- package/typedefs.d.ts.map +0 -1
- package/typedefs.js.map +0 -1
- package/validators.d.ts.map +0 -1
- package/validators.js.map +0 -1
package/request.js
CHANGED
|
@@ -1,45 +1,33 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { keys } from './typedefs.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { cryptoRandomObjectId, normalizeUrl } from '@apify/utilities';
|
|
4
|
+
import { serviceLocator } from './service_locator.js';
|
|
5
|
+
import { parseArgument, schemas } from './validators.js';
|
|
7
6
|
// new properties on the Request object breaks serialization
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
export var RequestState;
|
|
30
|
-
(function (RequestState) {
|
|
31
|
-
RequestState[RequestState["UNPROCESSED"] = 0] = "UNPROCESSED";
|
|
32
|
-
RequestState[RequestState["BEFORE_NAV"] = 1] = "BEFORE_NAV";
|
|
33
|
-
RequestState[RequestState["AFTER_NAV"] = 2] = "AFTER_NAV";
|
|
34
|
-
RequestState[RequestState["REQUEST_HANDLER"] = 3] = "REQUEST_HANDLER";
|
|
35
|
-
RequestState[RequestState["DONE"] = 4] = "DONE";
|
|
36
|
-
RequestState[RequestState["ERROR_HANDLER"] = 5] = "ERROR_HANDLER";
|
|
37
|
-
RequestState[RequestState["ERROR"] = 6] = "ERROR";
|
|
38
|
-
RequestState[RequestState["SKIPPED"] = 7] = "SKIPPED";
|
|
39
|
-
})(RequestState || (RequestState = {}));
|
|
7
|
+
// Compiled once: every `Request` runs it, and the generated fast path skips zod's interpreter.
|
|
8
|
+
const requestOptionsSchema = z.compile(z.looseObject({
|
|
9
|
+
url: z.string(),
|
|
10
|
+
uniqueKey: z.string().optional(),
|
|
11
|
+
method: z.string().optional(),
|
|
12
|
+
payload: z.union([z.string(), z.instanceof(Uint8Array)]).optional(),
|
|
13
|
+
noRetry: z.boolean().optional(),
|
|
14
|
+
sessionId: z.string().optional(),
|
|
15
|
+
maxRetries: schemas.anyNumber.optional(),
|
|
16
|
+
headers: z.looseObject({}).optional(),
|
|
17
|
+
userData: z.looseObject({}).optional(),
|
|
18
|
+
label: z.string().optional(),
|
|
19
|
+
keepUrlFragment: z.boolean().optional(),
|
|
20
|
+
useExtendedUniqueKey: z.boolean().optional(),
|
|
21
|
+
alwaysEnqueue: z.boolean().optional(),
|
|
22
|
+
skipNavigation: z.boolean().optional(),
|
|
23
|
+
crawlDepth: schemas.anyNumber
|
|
24
|
+
.refine((value) => value >= 0, 'Expected a number greater than or equal to 0')
|
|
25
|
+
.optional(),
|
|
26
|
+
}));
|
|
40
27
|
/**
|
|
41
|
-
* Represents a URL to be crawled, optionally including HTTP method, headers, payload and other metadata
|
|
42
|
-
*
|
|
28
|
+
* Represents a URL to be crawled, optionally including HTTP method, headers, payload and other metadata, together
|
|
29
|
+
* with the processing state a request queue keeps about it (`retryCount`, `errorMessages`, `handledAt`, ...).
|
|
30
|
+
* Inside a crawler, requests are {@link CrawlingRequest}s, which add the crawler's own per-request settings.
|
|
43
31
|
*
|
|
44
32
|
* Each `Request` instance has the `uniqueKey` property, which can be either specified
|
|
45
33
|
* manually in the constructor or generated automatically from the URL. Two requests with the same `uniqueKey`
|
|
@@ -55,21 +43,15 @@ export var RequestState;
|
|
|
55
43
|
* const request = new Request({
|
|
56
44
|
* url: 'http://www.example.com',
|
|
57
45
|
* headers: { Accept: 'application/json' },
|
|
46
|
+
* userData: { foo: 'bar' },
|
|
58
47
|
* });
|
|
59
48
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* request.userData.foo = 'bar';
|
|
63
|
-
* request.pushErrorMessage(new Error('Request failed!'));
|
|
64
|
-
*
|
|
65
|
-
* ...
|
|
66
|
-
*
|
|
67
|
-
* const foo = request.userData.foo;
|
|
49
|
+
* await requestQueue.addRequest(request);
|
|
68
50
|
* ```
|
|
69
51
|
* @category Sources
|
|
70
52
|
*/
|
|
71
|
-
|
|
72
|
-
/**
|
|
53
|
+
class CrawleeRequest {
|
|
54
|
+
/** Storage-assigned request ID. Only present on requests that went through a {@link RequestQueue}. */
|
|
73
55
|
id;
|
|
74
56
|
/** URL of the web page to crawl. */
|
|
75
57
|
url;
|
|
@@ -100,8 +82,13 @@ export class Request {
|
|
|
100
82
|
/** Object with HTTP headers. Key is header name, value is the value. */
|
|
101
83
|
headers;
|
|
102
84
|
/** Private store for the custom user data assigned to the request. */
|
|
103
|
-
|
|
104
|
-
/**
|
|
85
|
+
#userData = {};
|
|
86
|
+
/**
|
|
87
|
+
* Custom user data assigned to the request.
|
|
88
|
+
*
|
|
89
|
+
* All data stored in `userData` must be JSON-serializable.
|
|
90
|
+
* Storing non-serializable values (e.g. functions, symbols) may result in unexpected results.
|
|
91
|
+
*/
|
|
105
92
|
userData = {};
|
|
106
93
|
/**
|
|
107
94
|
* ISO datetime string that indicates the time when the request has been processed.
|
|
@@ -110,117 +97,121 @@ export class Request {
|
|
|
110
97
|
handledAt;
|
|
111
98
|
/**
|
|
112
99
|
* `Request` parameters including the URL, HTTP method and headers, and others.
|
|
100
|
+
*
|
|
101
|
+
* Processing state (`retryCount`, `errorMessages`, `handledAt`, `loadedUrl`, `id`) is not an option;
|
|
102
|
+
* requests coming back from a storage are rebuilt with {@link Request.fromSchema}.
|
|
113
103
|
*/
|
|
114
104
|
constructor(options) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// skip url, because it is validated above
|
|
124
|
-
if (prop === 'url') {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const predicate = requestOptionalPredicates[prop];
|
|
128
|
-
const value = options[prop];
|
|
129
|
-
if (predicate) {
|
|
130
|
-
ow(value, `RequestOptions.${prop}`, predicate);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
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;
|
|
105
|
+
// A bare URL is a common slip — point at the object form instead of a generic type error.
|
|
106
|
+
if (typeof options === 'string') {
|
|
107
|
+
throw new TypeError(`\`Request\` options must be an object, got the string '${options}'. ` +
|
|
108
|
+
'Did you mean `new Request({ url })`?');
|
|
109
|
+
}
|
|
110
|
+
parseArgument(options, schemas.anyObject, 'RequestOptions');
|
|
111
|
+
parseArgument(options, requestOptionsSchema, 'RequestOptions');
|
|
112
|
+
const { url, uniqueKey, payload, noRetry = false, sessionId, maxRetries, headers = {}, userData = {}, label, keepUrlFragment = false, useExtendedUniqueKey = false, alwaysEnqueue = false, skipNavigation, enqueueStrategy, crawlDepth, } = options;
|
|
134
113
|
let { method = 'GET' } = options;
|
|
135
114
|
method = method.toUpperCase();
|
|
136
115
|
if (method === 'GET' && payload)
|
|
137
116
|
throw new Error('Request with GET method cannot have a payload.');
|
|
138
|
-
|
|
117
|
+
if (uniqueKey && alwaysEnqueue) {
|
|
118
|
+
throw new Error('`alwaysEnqueue` cannot be used together with a custom `uniqueKey`.');
|
|
119
|
+
}
|
|
139
120
|
this.url = url;
|
|
140
|
-
this.loadedUrl = loadedUrl;
|
|
141
121
|
this.uniqueKey =
|
|
142
|
-
uniqueKey ||
|
|
122
|
+
uniqueKey ||
|
|
123
|
+
CrawleeRequest.computeUniqueKey({
|
|
124
|
+
url,
|
|
125
|
+
method,
|
|
126
|
+
payload,
|
|
127
|
+
keepUrlFragment,
|
|
128
|
+
useExtendedUniqueKey,
|
|
129
|
+
alwaysEnqueue,
|
|
130
|
+
});
|
|
143
131
|
this.method = method;
|
|
144
132
|
this.payload = payload;
|
|
145
133
|
this.noRetry = noRetry;
|
|
146
|
-
this.retryCount =
|
|
147
|
-
this.
|
|
148
|
-
this.errorMessages = [...errorMessages];
|
|
134
|
+
this.retryCount = 0;
|
|
135
|
+
this.errorMessages = [];
|
|
149
136
|
this.headers = { ...headers };
|
|
150
|
-
this.handledAt = handledAt instanceof Date ? handledAt.toISOString() : handledAt;
|
|
151
137
|
if (label) {
|
|
152
138
|
userData.label = label;
|
|
153
139
|
}
|
|
140
|
+
// Read `__crawlee` explicitly - on a `userData` coming from another Request instance the
|
|
141
|
+
// bag is non-enumerable, so the spread alone would silently drop the internal state
|
|
142
|
+
// (e.g. `skipNavigation`) when a request is re-wrapped after a storage round trip.
|
|
143
|
+
this.#userData = { __crawlee: userData.__crawlee ?? {}, ...userData };
|
|
144
|
+
// `userData` must stay an enumerable own accessor — serialization in the storages relies on it
|
|
154
145
|
Object.defineProperties(this, {
|
|
155
|
-
_userData: {
|
|
156
|
-
value: { __crawlee: {}, ...userData },
|
|
157
|
-
enumerable: false,
|
|
158
|
-
writable: true,
|
|
159
|
-
},
|
|
160
146
|
userData: {
|
|
161
|
-
get: () => this
|
|
147
|
+
get: () => this.#userData,
|
|
162
148
|
set: (value) => {
|
|
163
149
|
Object.defineProperties(value, {
|
|
164
150
|
__crawlee: {
|
|
165
|
-
value: this.
|
|
151
|
+
value: this.#userData.__crawlee,
|
|
166
152
|
enumerable: false,
|
|
167
153
|
writable: true,
|
|
168
154
|
},
|
|
169
155
|
toJSON: {
|
|
170
156
|
value: () => {
|
|
171
|
-
if (Object.keys(this.
|
|
157
|
+
if (Object.keys(this.#userData.__crawlee).length > 0) {
|
|
172
158
|
return {
|
|
173
|
-
...this
|
|
174
|
-
__crawlee: this.
|
|
159
|
+
...this.#userData,
|
|
160
|
+
__crawlee: this.#userData.__crawlee,
|
|
175
161
|
};
|
|
176
162
|
}
|
|
177
|
-
return this
|
|
163
|
+
return this.#userData;
|
|
178
164
|
},
|
|
179
165
|
enumerable: false,
|
|
180
166
|
writable: true,
|
|
181
167
|
},
|
|
182
168
|
});
|
|
183
|
-
this
|
|
169
|
+
this.#userData = value;
|
|
184
170
|
},
|
|
185
171
|
enumerable: true,
|
|
186
172
|
},
|
|
187
173
|
});
|
|
188
174
|
// reassign userData to ensure internal `__crawlee` object is non-enumerable
|
|
189
175
|
this.userData = userData;
|
|
176
|
+
const crawlee = (this.userData.__crawlee ??= {});
|
|
190
177
|
if (skipNavigation != null)
|
|
191
|
-
|
|
178
|
+
crawlee.skipNavigation = skipNavigation;
|
|
192
179
|
if (maxRetries != null)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return this.userData.__crawlee?.skipNavigation ?? false;
|
|
180
|
+
crawlee.maxRetries = maxRetries;
|
|
181
|
+
if (crawlDepth != null)
|
|
182
|
+
crawlee.crawlDepth ??= crawlDepth;
|
|
183
|
+
if (sessionId)
|
|
184
|
+
crawlee.sessionId = sessionId;
|
|
185
|
+
// A stored request keeps the strategy it was enqueued under.
|
|
186
|
+
if (enqueueStrategy)
|
|
187
|
+
crawlee.enqueueStrategy ??= enqueueStrategy;
|
|
202
188
|
}
|
|
203
|
-
/**
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Rebuilds a request from its stored form, including the processing state a
|
|
191
|
+
* {@link RequestOptions} object cannot carry. Subclasses get instances of themselves.
|
|
192
|
+
*/
|
|
193
|
+
static fromSchema(schema) {
|
|
194
|
+
const { id, retryCount = 0, errorMessages = [], handledAt, loadedUrl, ...options } = schema;
|
|
195
|
+
const request = new this(options);
|
|
196
|
+
request.id = id;
|
|
197
|
+
request.retryCount = retryCount;
|
|
198
|
+
request.errorMessages = [...errorMessages];
|
|
199
|
+
request.loadedUrl = loadedUrl;
|
|
200
|
+
// `apify-client` parses `*At` fields into `Date`s, whatever the schema says.
|
|
201
|
+
request.handledAt =
|
|
202
|
+
handledAt instanceof Date ? handledAt.toISOString() : handledAt;
|
|
203
|
+
return request;
|
|
215
204
|
}
|
|
216
|
-
/**
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
this.
|
|
223
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Converts the Crawlee Request object to a `fetch` API Request object.
|
|
207
|
+
* @returns The native `fetch` API Request object.
|
|
208
|
+
*/
|
|
209
|
+
intoFetchAPIRequest() {
|
|
210
|
+
return new Request(this.url, {
|
|
211
|
+
method: this.method,
|
|
212
|
+
headers: this.headers,
|
|
213
|
+
body: this.payload,
|
|
214
|
+
});
|
|
224
215
|
}
|
|
225
216
|
/** shortcut for getting `request.userData.label` */
|
|
226
217
|
get label() {
|
|
@@ -230,119 +221,33 @@ export class Request {
|
|
|
230
221
|
set label(value) {
|
|
231
222
|
this.userData.label = value;
|
|
232
223
|
}
|
|
233
|
-
/** Maximum number of retries for this request. Allows to override the global `maxRequestRetries` option of `BasicCrawler`. */
|
|
234
|
-
get maxRetries() {
|
|
235
|
-
return this.userData.__crawlee?.maxRetries;
|
|
236
|
-
}
|
|
237
|
-
/** Maximum number of retries for this request. Allows to override the global `maxRequestRetries` option of `BasicCrawler`. */
|
|
238
|
-
set maxRetries(value) {
|
|
239
|
-
if (!this.userData.__crawlee) {
|
|
240
|
-
this.userData.__crawlee = { maxRetries: value };
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
this.userData.__crawlee.maxRetries = value;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
/** Describes the request's current lifecycle state. */
|
|
247
|
-
get state() {
|
|
248
|
-
return this.userData.__crawlee?.state ?? RequestState.UNPROCESSED;
|
|
249
|
-
}
|
|
250
|
-
/** Describes the request's current lifecycle state. */
|
|
251
|
-
set state(value) {
|
|
252
|
-
if (!this.userData.__crawlee) {
|
|
253
|
-
this.userData.__crawlee = { state: value };
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
this.userData.__crawlee.state = value;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
get enqueueStrategy() {
|
|
260
|
-
return this.userData.__crawlee?.enqueueStrategy;
|
|
261
|
-
}
|
|
262
|
-
set enqueueStrategy(value) {
|
|
263
|
-
if (!this.userData.__crawlee) {
|
|
264
|
-
this.userData.__crawlee = { enqueueStrategy: value };
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
this.userData.__crawlee.enqueueStrategy = value;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Stores information about an error that occurred during processing of this request.
|
|
272
|
-
*
|
|
273
|
-
* You should always use Error instances when throwing errors in JavaScript.
|
|
274
|
-
*
|
|
275
|
-
* Nevertheless, to improve the debugging experience when using third party libraries
|
|
276
|
-
* that may not always throw an Error instance, the function performs a type
|
|
277
|
-
* inspection of the passed argument and attempts to extract as much information
|
|
278
|
-
* as possible, since just throwing a bad type error makes any debugging rather difficult.
|
|
279
|
-
*
|
|
280
|
-
* @param errorOrMessage Error object or error message to be stored in the request.
|
|
281
|
-
* @param [options]
|
|
282
|
-
*/
|
|
283
|
-
pushErrorMessage(errorOrMessage, options = {}) {
|
|
284
|
-
const { omitStack } = options;
|
|
285
|
-
let message;
|
|
286
|
-
const type = typeof errorOrMessage;
|
|
287
|
-
if (type === 'object') {
|
|
288
|
-
if (!errorOrMessage) {
|
|
289
|
-
message = 'null';
|
|
290
|
-
}
|
|
291
|
-
else if (errorOrMessage instanceof Error) {
|
|
292
|
-
message = omitStack
|
|
293
|
-
? errorOrMessage.message
|
|
294
|
-
: // .stack includes the message
|
|
295
|
-
errorOrMessage.stack;
|
|
296
|
-
}
|
|
297
|
-
else if (Reflect.has(Object(errorOrMessage), 'message')) {
|
|
298
|
-
message = Reflect.get(Object(errorOrMessage), 'message');
|
|
299
|
-
}
|
|
300
|
-
else if (errorOrMessage.toString() !== '[object Object]') {
|
|
301
|
-
message = errorOrMessage.toString();
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
try {
|
|
305
|
-
message = util.inspect(errorOrMessage);
|
|
306
|
-
}
|
|
307
|
-
catch (err) {
|
|
308
|
-
message = 'Unable to extract any message from the received object.';
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
else if (type === 'undefined') {
|
|
313
|
-
message = 'undefined';
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
message = errorOrMessage.toString();
|
|
317
|
-
}
|
|
318
|
-
this.errorMessages.push(message);
|
|
319
|
-
}
|
|
320
|
-
// TODO: only for better BC, remove in v4
|
|
321
|
-
_computeUniqueKey(options) {
|
|
322
|
-
return Request.computeUniqueKey(options);
|
|
323
|
-
}
|
|
324
|
-
// TODO: only for better BC, remove in v4
|
|
325
|
-
_hashPayload(payload) {
|
|
326
|
-
return Request.hashPayload(payload);
|
|
327
|
-
}
|
|
328
224
|
/** @internal */
|
|
329
|
-
static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, }) {
|
|
225
|
+
static computeUniqueKey({ url, method = 'GET', payload, keepUrlFragment = false, useExtendedUniqueKey = false, alwaysEnqueue = false, }) {
|
|
330
226
|
const normalizedMethod = method.toUpperCase();
|
|
331
227
|
const normalizedUrl = normalizeUrl(url, keepUrlFragment) || url; // It returns null when url is invalid, causing weird errors.
|
|
228
|
+
let uniqueKey;
|
|
332
229
|
if (!useExtendedUniqueKey) {
|
|
333
230
|
if (normalizedMethod !== 'GET' && payload) {
|
|
334
|
-
|
|
231
|
+
serviceLocator
|
|
232
|
+
.getLogger()
|
|
233
|
+
.warningOnce(`We've encountered a ${normalizedMethod} Request with a payload. ` +
|
|
335
234
|
'This is fine. Just letting you know that if your requests point to the same URL ' +
|
|
336
235
|
'and differ only in method and payload, you should see the "useExtendedUniqueKey" option of Request constructor.');
|
|
337
236
|
}
|
|
338
|
-
|
|
237
|
+
uniqueKey = normalizedUrl;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
const payloadHash = payload ? CrawleeRequest.hashPayload(payload) : '';
|
|
241
|
+
uniqueKey = `${normalizedMethod}|${payloadHash}|${normalizedUrl}`;
|
|
242
|
+
}
|
|
243
|
+
if (alwaysEnqueue) {
|
|
244
|
+
uniqueKey = `${cryptoRandomObjectId(17)}|${uniqueKey}`;
|
|
339
245
|
}
|
|
340
|
-
|
|
341
|
-
return `${normalizedMethod}(${payloadHash}):${normalizedUrl}`;
|
|
246
|
+
return uniqueKey;
|
|
342
247
|
}
|
|
343
248
|
/** @internal */
|
|
344
249
|
static hashPayload(payload) {
|
|
345
250
|
return crypto.createHash('sha256').update(payload).digest('base64').replace(/[+/=]/g, '').substring(0, 8);
|
|
346
251
|
}
|
|
347
252
|
}
|
|
348
|
-
|
|
253
|
+
export { CrawleeRequest as Request };
|
package/serialization.d.ts
CHANGED
package/serialization.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { pipeline as streamPipeline, Readable, Writable } from 'node:stream';
|
|
2
2
|
import util from 'node:util';
|
|
3
3
|
import zlib from 'node:zlib';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import StreamArray from 'stream-json/streamers/stream-array.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { parseArgument, schemas } from './validators.js';
|
|
6
7
|
const pipeline = util.promisify(streamPipeline);
|
|
8
|
+
const uint8ArraySchema = z.instanceof(Uint8Array);
|
|
7
9
|
/**
|
|
8
10
|
* Transforms an array of items to a JSON in a streaming
|
|
9
11
|
* fashion to save memory. It operates in batches to speed
|
|
@@ -11,32 +13,31 @@ const pipeline = util.promisify(streamPipeline);
|
|
|
11
13
|
* @internal
|
|
12
14
|
*/
|
|
13
15
|
class ArrayToJson extends Readable {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
#offset = 0;
|
|
17
|
+
#batchSize;
|
|
18
|
+
#data;
|
|
17
19
|
constructor(data, options = {}) {
|
|
18
20
|
super({
|
|
19
21
|
...options,
|
|
20
22
|
autoDestroy: true,
|
|
21
23
|
emitClose: true,
|
|
22
24
|
});
|
|
23
|
-
this.data = data;
|
|
24
25
|
const { batchSize = 10000 } = options;
|
|
25
|
-
this
|
|
26
|
-
this
|
|
26
|
+
this.#batchSize = batchSize;
|
|
27
|
+
this.#data = data;
|
|
27
28
|
this.push('[');
|
|
28
29
|
}
|
|
29
30
|
_read() {
|
|
30
31
|
try {
|
|
31
|
-
const items = this
|
|
32
|
+
const items = this.#data.slice(this.#offset, this.#offset + this.#batchSize);
|
|
32
33
|
if (items.length) {
|
|
33
34
|
const json = JSON.stringify(items);
|
|
34
35
|
// Strip brackets to flatten the batch.
|
|
35
36
|
const itemString = json.substring(1, json.length - 1);
|
|
36
|
-
if (this
|
|
37
|
+
if (this.#offset > 0)
|
|
37
38
|
this.push(',', 'utf8');
|
|
38
39
|
this.push(itemString, 'utf8');
|
|
39
|
-
this
|
|
40
|
+
this.#offset += this.#batchSize;
|
|
40
41
|
}
|
|
41
42
|
else {
|
|
42
43
|
this.push(']');
|
|
@@ -58,7 +59,7 @@ class ArrayToJson extends Readable {
|
|
|
58
59
|
* @internal
|
|
59
60
|
*/
|
|
60
61
|
export async function serializeArray(data) {
|
|
61
|
-
|
|
62
|
+
parseArgument(data, schemas.anyArray);
|
|
62
63
|
const { chunks, collector } = createChunkCollector();
|
|
63
64
|
await pipeline(new ArrayToJson(data), zlib.createGzip(), collector);
|
|
64
65
|
return Buffer.concat(chunks);
|
|
@@ -73,9 +74,9 @@ export async function serializeArray(data) {
|
|
|
73
74
|
* @internal
|
|
74
75
|
*/
|
|
75
76
|
export async function deserializeArray(compressedData) {
|
|
76
|
-
|
|
77
|
+
parseArgument(compressedData, uint8ArraySchema);
|
|
77
78
|
const { chunks, collector } = createChunkCollector({ fromValuesStream: true });
|
|
78
|
-
await pipeline(Readable.from([compressedData]), zlib.createGunzip(), StreamArray.
|
|
79
|
+
await pipeline(Readable.from([compressedData]), zlib.createGunzip(), StreamArray.withParserAsStream(), collector);
|
|
79
80
|
return chunks;
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
@@ -88,8 +89,8 @@ export async function deserializeArray(compressedData) {
|
|
|
88
89
|
* @internal
|
|
89
90
|
*/
|
|
90
91
|
export function createDeserialize(compressedData) {
|
|
91
|
-
|
|
92
|
-
const streamArray = StreamArray.
|
|
92
|
+
parseArgument(compressedData, uint8ArraySchema);
|
|
93
|
+
const streamArray = StreamArray.withParserAsStream();
|
|
93
94
|
const destination = pluckValue(streamArray);
|
|
94
95
|
streamPipeline(Readable.from([compressedData]), zlib.createGunzip(), destination, (err) => destination.emit(err));
|
|
95
96
|
return destination;
|
|
@@ -116,7 +117,6 @@ function createChunkCollector(options = {}) {
|
|
|
116
117
|
}
|
|
117
118
|
function pluckValue(streamArray) {
|
|
118
119
|
const realPush = streamArray.push.bind(streamArray);
|
|
119
|
-
streamArray.push = (obj) => realPush(obj
|
|
120
|
+
streamArray.push = (obj) => realPush(obj?.value ?? null);
|
|
120
121
|
return streamArray;
|
|
121
122
|
}
|
|
122
|
-
//# sourceMappingURL=serialization.js.map
|