@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.
- package/README.md +17 -13
- package/autoscaling/autoscaled_pool.d.ts +67 -172
- package/autoscaling/autoscaled_pool.js +182 -329
- package/autoscaling/concurrency_system.d.ts +268 -0
- package/autoscaling/concurrency_system.js +362 -0
- package/autoscaling/cpu_load_signal.d.ts +43 -0
- package/autoscaling/cpu_load_signal.js +47 -0
- package/autoscaling/event_loop_load_signal.d.ts +51 -0
- package/autoscaling/event_loop_load_signal.js +60 -0
- package/autoscaling/index.d.ts +6 -1
- package/autoscaling/index.js +6 -1
- package/autoscaling/load_signal.d.ts +100 -0
- package/autoscaling/load_signal.js +105 -0
- package/autoscaling/memory_load_signal.d.ts +47 -0
- package/autoscaling/memory_load_signal.js +106 -0
- package/autoscaling/snapshotter.d.ts +58 -163
- package/autoscaling/snapshotter.js +45 -263
- package/autoscaling/storage_backend_load_signal.d.ts +56 -0
- package/autoscaling/storage_backend_load_signal.js +73 -0
- package/autoscaling/system_status.d.ts +67 -89
- package/autoscaling/system_status.js +92 -122
- package/autoscaling/weighted_avg.d.ts +5 -0
- package/autoscaling/weighted_avg.js +14 -0
- package/byte_utils.d.ts +17 -0
- package/byte_utils.js +42 -0
- package/configuration.d.ts +96 -223
- package/configuration.js +170 -222
- package/cookie_utils.d.ts +3 -2
- package/cookie_utils.js +18 -7
- package/crawlers/context_pipeline.d.ts +10 -1
- package/crawlers/context_pipeline.js +31 -8
- package/crawlers/crawler_commons.d.ts +90 -129
- package/crawlers/crawler_commons.js +1 -116
- package/crawlers/error_snapshotter.d.ts +2 -5
- package/crawlers/error_snapshotter.js +7 -8
- package/crawlers/error_tracker.d.ts +0 -1
- package/crawlers/error_tracker.js +0 -1
- package/crawlers/index.d.ts +1 -3
- package/crawlers/index.js +0 -3
- package/crawlers/internals/types.d.ts +0 -1
- package/crawlers/internals/types.js +0 -1
- package/crawlers/statistics.d.ts +187 -63
- package/crawlers/statistics.js +354 -164
- package/debug.d.ts +36 -0
- package/debug.js +70 -0
- package/enqueue_links/enqueue_links.d.ts +68 -154
- package/enqueue_links/enqueue_links.js +38 -210
- package/enqueue_links/index.d.ts +0 -1
- package/enqueue_links/index.js +0 -1
- package/enqueue_links/shared.d.ts +52 -26
- package/enqueue_links/shared.js +115 -66
- package/errors.d.ts +72 -4
- package/errors.js +89 -5
- package/events/event_manager.d.ts +35 -9
- package/events/event_manager.js +12 -13
- package/events/index.d.ts +0 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -3
- package/events/local_event_manager.js +39 -13
- package/http.d.ts +9 -0
- package/http.js +28 -0
- package/index.d.ts +7 -4
- package/index.js +6 -3
- package/iterables.d.ts +79 -0
- package/iterables.js +134 -0
- package/log.d.ts +82 -3
- package/log.js +106 -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 +38 -0
- package/memory-storage/memory-storage.js +130 -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 +108 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
- package/memory-storage/resource-clients/key-value-store.js +201 -0
- package/memory-storage/resource-clients/request-queue.d.ts +77 -0
- package/memory-storage/resource-clients/request-queue.js +409 -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 +14 -13
- package/proxy_configuration.d.ts +24 -132
- package/proxy_configuration.js +32 -147
- package/recoverable_state.d.ts +155 -0
- package/recoverable_state.js +231 -0
- package/request.d.ts +80 -16
- package/request.js +147 -68
- package/router.d.ts +193 -21
- package/router.js +188 -43
- package/serialization.d.ts +0 -1
- package/serialization.js +15 -15
- package/service_locator.d.ts +165 -0
- package/service_locator.js +253 -0
- package/session_pool/consts.d.ts +1 -2
- package/session_pool/consts.js +1 -2
- package/session_pool/errors.d.ts +0 -1
- package/session_pool/errors.js +0 -1
- package/session_pool/fingerprint.d.ts +9 -0
- package/session_pool/fingerprint.js +30 -0
- package/session_pool/index.d.ts +0 -2
- package/session_pool/index.js +0 -2
- package/session_pool/session.d.ts +35 -88
- package/session_pool/session.js +101 -159
- package/session_pool/session_pool.d.ts +73 -91
- package/session_pool/session_pool.js +172 -165
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +114 -54
- package/storages/dataset.js +291 -148
- package/storages/index.d.ts +10 -8
- package/storages/index.js +8 -8
- package/storages/key_value_store.d.ts +185 -42
- package/storages/key_value_store.js +445 -169
- 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 +52 -115
- package/storages/request_list.js +183 -152
- package/storages/request_loader.d.ts +101 -0
- package/storages/request_loader.js +1 -0
- package/storages/request_manager.d.ts +33 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +97 -0
- package/storages/request_manager_tandem.js +197 -0
- package/storages/request_queue.d.ts +290 -47
- package/storages/request_queue.js +762 -216
- package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +45 -89
- package/storages/sitemap_request_loader.js +438 -0
- package/storages/storage_instance_manager.d.ts +87 -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/throttling_request_manager.d.ts +239 -0
- package/storages/throttling_request_manager.js +646 -0
- package/storages/transaction.d.ts +252 -0
- package/storages/transaction.js +251 -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 +22 -18
- package/validators.js +13 -18
- package/autoscaling/autoscaled_pool.d.ts.map +0 -1
- package/autoscaling/autoscaled_pool.js.map +0 -1
- package/autoscaling/index.d.ts.map +0 -1
- package/autoscaling/index.js.map +0 -1
- package/autoscaling/snapshotter.d.ts.map +0 -1
- package/autoscaling/snapshotter.js.map +0 -1
- package/autoscaling/system_status.d.ts.map +0 -1
- 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.map +0 -1
- package/cookie_utils.js.map +0 -1
- package/crawlers/context_pipeline.d.ts.map +0 -1
- package/crawlers/context_pipeline.js.map +0 -1
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.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.map +0 -1
- package/crawlers/error_snapshotter.js.map +0 -1
- package/crawlers/error_tracker.d.ts.map +0 -1
- package/crawlers/error_tracker.js.map +0 -1
- package/crawlers/index.d.ts.map +0 -1
- package/crawlers/index.js.map +0 -1
- package/crawlers/internals/types.d.ts.map +0 -1
- package/crawlers/internals/types.js.map +0 -1
- package/crawlers/statistics.d.ts.map +0 -1
- package/crawlers/statistics.js.map +0 -1
- package/enqueue_links/enqueue_links.d.ts.map +0 -1
- package/enqueue_links/enqueue_links.js.map +0 -1
- package/enqueue_links/index.d.ts.map +0 -1
- package/enqueue_links/index.js.map +0 -1
- package/enqueue_links/shared.d.ts.map +0 -1
- 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 -140
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -40
- 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 -20
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -82
- 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.map +0 -1
- 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.map +0 -1
- package/session_pool/consts.js.map +0 -1
- package/session_pool/errors.d.ts.map +0 -1
- 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.map +0 -1
- package/session_pool/index.js.map +0 -1
- package/session_pool/session.d.ts.map +0 -1
- package/session_pool/session.js.map +0 -1
- package/session_pool/session_pool.d.ts.map +0 -1
- 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 -308
- 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.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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical write path for key-value store records.
|
|
3
|
+
*
|
|
4
|
+
* When a content type is provided, the value passes through unchanged — it is the caller's
|
|
5
|
+
* responsibility to supply a String/Buffer/Stream (the frontend validates this).
|
|
6
|
+
*
|
|
7
|
+
* When no content type is provided, it is inferred from the value's shape:
|
|
8
|
+
* - Buffer / typed array / ArrayBuffer / stream → `application/octet-stream` (passthrough)
|
|
9
|
+
* - `string` → `text/plain; charset=utf-8` (passthrough)
|
|
10
|
+
* - anything else → `application/json; charset=utf-8` (serialized via `jsonStringifyExtended`)
|
|
11
|
+
*
|
|
12
|
+
* Does NOT drain streams — that is storage mechanics and stays in the storage backend.
|
|
13
|
+
*
|
|
14
|
+
* Backend-independent.
|
|
15
|
+
*/
|
|
16
|
+
export declare function serializeValue(value: unknown, contentType?: string): {
|
|
17
|
+
value: Buffer | ArrayBuffer | ArrayBufferView | string | NodeJS.ReadableStream | ReadableStream;
|
|
18
|
+
contentType: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Parses a Buffer or ArrayBuffer using the provided content type header.
|
|
22
|
+
*
|
|
23
|
+
* - application/json is returned as a parsed object.
|
|
24
|
+
* - application/*xml and text/* are returned as strings.
|
|
25
|
+
* - everything else is returned as original body.
|
|
26
|
+
*
|
|
27
|
+
* If the header includes a charset, the body will be stringified only
|
|
28
|
+
* if the charset represents a known encoding to Node.js or Browser.
|
|
29
|
+
*
|
|
30
|
+
* Backend-independent — this is the canonical read path for the {@link KeyValueStore} frontend.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseValue(body: Buffer | ArrayBuffer | string, contentTypeHeader: string | null): string | Buffer | ArrayBuffer | Record<string, unknown>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import contentTypeParser from 'content-type';
|
|
2
|
+
import JSON5 from 'json5';
|
|
3
|
+
import { jsonStringifyExtended } from '@apify/utilities';
|
|
4
|
+
import { isBuffer, isStream } from '../byte_utils.js';
|
|
5
|
+
const CONTENT_TYPE_JSON = 'application/json';
|
|
6
|
+
const STRINGIFIABLE_CONTENT_TYPE_RXS = [new RegExp(`^${CONTENT_TYPE_JSON}$`, 'i'), /^application\/.*xml$/i, /^text\//i];
|
|
7
|
+
/**
|
|
8
|
+
* Canonical write path for key-value store records.
|
|
9
|
+
*
|
|
10
|
+
* When a content type is provided, the value passes through unchanged — it is the caller's
|
|
11
|
+
* responsibility to supply a String/Buffer/Stream (the frontend validates this).
|
|
12
|
+
*
|
|
13
|
+
* When no content type is provided, it is inferred from the value's shape:
|
|
14
|
+
* - Buffer / typed array / ArrayBuffer / stream → `application/octet-stream` (passthrough)
|
|
15
|
+
* - `string` → `text/plain; charset=utf-8` (passthrough)
|
|
16
|
+
* - anything else → `application/json; charset=utf-8` (serialized via `jsonStringifyExtended`)
|
|
17
|
+
*
|
|
18
|
+
* Does NOT drain streams — that is storage mechanics and stays in the storage backend.
|
|
19
|
+
*
|
|
20
|
+
* Backend-independent.
|
|
21
|
+
*/
|
|
22
|
+
export function serializeValue(value, contentType) {
|
|
23
|
+
if (contentType !== null && contentType !== undefined) {
|
|
24
|
+
return { value: value, contentType };
|
|
25
|
+
}
|
|
26
|
+
if (isStream(value) || isBuffer(value)) {
|
|
27
|
+
return {
|
|
28
|
+
value,
|
|
29
|
+
contentType: 'application/octet-stream',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
return { value, contentType: 'text/plain; charset=utf-8' };
|
|
34
|
+
}
|
|
35
|
+
let serialized;
|
|
36
|
+
try {
|
|
37
|
+
// Format JSON to simplify debugging, the overheads with compression is negligible
|
|
38
|
+
serialized = jsonStringifyExtended(value, null, 2);
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
const error = e;
|
|
42
|
+
// Give more meaningful error message
|
|
43
|
+
if (error.message?.includes('Invalid string length')) {
|
|
44
|
+
error.message = 'Object is too large';
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`The "value" parameter cannot be stringified to JSON: ${error.message}`);
|
|
47
|
+
}
|
|
48
|
+
if (serialized === undefined) {
|
|
49
|
+
throw new Error('The "value" parameter was stringified to JSON and returned undefined. ' +
|
|
50
|
+
"Make sure you're not trying to stringify an undefined value.");
|
|
51
|
+
}
|
|
52
|
+
return { value: serialized, contentType: 'application/json; charset=utf-8' };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parses a Buffer or ArrayBuffer using the provided content type header.
|
|
56
|
+
*
|
|
57
|
+
* - application/json is returned as a parsed object.
|
|
58
|
+
* - application/*xml and text/* are returned as strings.
|
|
59
|
+
* - everything else is returned as original body.
|
|
60
|
+
*
|
|
61
|
+
* If the header includes a charset, the body will be stringified only
|
|
62
|
+
* if the charset represents a known encoding to Node.js or Browser.
|
|
63
|
+
*
|
|
64
|
+
* Backend-independent — this is the canonical read path for the {@link KeyValueStore} frontend.
|
|
65
|
+
*/
|
|
66
|
+
export function parseValue(body, contentTypeHeader) {
|
|
67
|
+
// No content type at all → we have no basis for interpretation; hand back the raw value.
|
|
68
|
+
if (contentTypeHeader === null)
|
|
69
|
+
return body;
|
|
70
|
+
let contentType;
|
|
71
|
+
let charset;
|
|
72
|
+
try {
|
|
73
|
+
const result = contentTypeParser.parse(contentTypeHeader);
|
|
74
|
+
contentType = result.type;
|
|
75
|
+
charset = result.parameters.charset;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Unparseable header → keep the original value rather than a mangled string.
|
|
79
|
+
return body;
|
|
80
|
+
}
|
|
81
|
+
// If we can't successfully interpret it, we return the original value rather than mangling it.
|
|
82
|
+
if (!areDataStringifiable(contentType, charset))
|
|
83
|
+
return body;
|
|
84
|
+
// Decode raw bytes using the resolved charset. An already-decoded string passes through (callers
|
|
85
|
+
// may hand us one directly), avoiding a needless re-encode round-trip.
|
|
86
|
+
const dataString = typeof body === 'string' ? body : isomorphicBufferToString(body, charset);
|
|
87
|
+
return contentType === CONTENT_TYPE_JSON ? JSON5.parse(dataString) : dataString;
|
|
88
|
+
}
|
|
89
|
+
function isomorphicBufferToString(buffer, encoding) {
|
|
90
|
+
if (buffer.constructor.name !== ArrayBuffer.name) {
|
|
91
|
+
return buffer.toString(encoding);
|
|
92
|
+
}
|
|
93
|
+
// In Node, wrap the ArrayBuffer in a Buffer so the resolved charset is honored (the caller already
|
|
94
|
+
// checked it via `Buffer.isEncoding`). Only the browser, which lacks Buffer, is limited to UTF-8.
|
|
95
|
+
if (typeof Buffer !== 'undefined') {
|
|
96
|
+
return Buffer.from(buffer).toString(encoding);
|
|
97
|
+
}
|
|
98
|
+
const decoder = new TextDecoder(encoding);
|
|
99
|
+
return decoder.decode(new Uint8Array(buffer));
|
|
100
|
+
}
|
|
101
|
+
function isCharsetStringifiable(charset) {
|
|
102
|
+
if (!charset)
|
|
103
|
+
return true; // hope that it's utf-8
|
|
104
|
+
return Buffer.isEncoding(charset);
|
|
105
|
+
}
|
|
106
|
+
function isContentTypeStringifiable(contentType) {
|
|
107
|
+
if (!contentType)
|
|
108
|
+
return false; // keep buffer
|
|
109
|
+
return STRINGIFIABLE_CONTENT_TYPE_RXS.some((rx) => rx.test(contentType));
|
|
110
|
+
}
|
|
111
|
+
function areDataStringifiable(contentType, charset) {
|
|
112
|
+
return isContentTypeStringifiable(contentType) && isCharsetStringifiable(charset);
|
|
113
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-size, direct-mapped cache for `uniqueKey`-based request deduplication.
|
|
3
|
+
*
|
|
4
|
+
* `RequestProvider.requestCache` only remembers the first batch of requests, so repeated
|
|
5
|
+
* `addRequestsBatched()` calls with overlapping URLs re-submit already-enqueued requests
|
|
6
|
+
* (https://github.com/apify/crawlee/issues/3120). This is a separate, cheaper cache we can populate on
|
|
7
|
+
* every batch: a fixed number of slots indexed by a hash of the request's cache key, storing the
|
|
8
|
+
* server-assigned `requestId`. Memory is capped by the slot count regardless of the working set size;
|
|
9
|
+
* a hash collision just overwrites a slot, causing an occasional cache miss (a harmless re-submission)
|
|
10
|
+
* but never a false hit — so a genuinely new request is never dropped.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare class RequestDeduplicationCache {
|
|
15
|
+
#private;
|
|
16
|
+
private readonly size;
|
|
17
|
+
constructor(size?: number);
|
|
18
|
+
get(cacheKey: string): string | null;
|
|
19
|
+
add(cacheKey: string, requestId: string): void;
|
|
20
|
+
clear(): void;
|
|
21
|
+
private indexOf;
|
|
22
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-size, direct-mapped cache for `uniqueKey`-based request deduplication.
|
|
3
|
+
*
|
|
4
|
+
* `RequestProvider.requestCache` only remembers the first batch of requests, so repeated
|
|
5
|
+
* `addRequestsBatched()` calls with overlapping URLs re-submit already-enqueued requests
|
|
6
|
+
* (https://github.com/apify/crawlee/issues/3120). This is a separate, cheaper cache we can populate on
|
|
7
|
+
* every batch: a fixed number of slots indexed by a hash of the request's cache key, storing the
|
|
8
|
+
* server-assigned `requestId`. Memory is capped by the slot count regardless of the working set size;
|
|
9
|
+
* a hash collision just overwrites a slot, causing an occasional cache miss (a harmless re-submission)
|
|
10
|
+
* but never a false hit — so a genuinely new request is never dropped.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export class RequestDeduplicationCache {
|
|
15
|
+
size;
|
|
16
|
+
#keys;
|
|
17
|
+
#ids;
|
|
18
|
+
// The slot count is the same for every queue, so it's a fixed default rather than a per-consumer option.
|
|
19
|
+
constructor(size = 1_000_000) {
|
|
20
|
+
this.size = size;
|
|
21
|
+
this.#keys = new Array(size);
|
|
22
|
+
this.#ids = new Array(size);
|
|
23
|
+
}
|
|
24
|
+
get(cacheKey) {
|
|
25
|
+
const index = this.indexOf(cacheKey);
|
|
26
|
+
return this.#keys[index] === cacheKey ? this.#ids[index] : null;
|
|
27
|
+
}
|
|
28
|
+
add(cacheKey, requestId) {
|
|
29
|
+
const index = this.indexOf(cacheKey);
|
|
30
|
+
this.#keys[index] = cacheKey;
|
|
31
|
+
this.#ids[index] = requestId;
|
|
32
|
+
}
|
|
33
|
+
clear() {
|
|
34
|
+
this.#keys = new Array(this.size);
|
|
35
|
+
this.#ids = new Array(this.size);
|
|
36
|
+
}
|
|
37
|
+
// A cheap FNV-1a hash of the cache key — avoids pulling in a dedicated hashing dependency.
|
|
38
|
+
indexOf(cacheKey) {
|
|
39
|
+
/* eslint-disable no-bitwise */
|
|
40
|
+
let hash = 0x811c9dc5;
|
|
41
|
+
for (let i = 0; i < cacheKey.length; i++) {
|
|
42
|
+
hash ^= cacheKey.charCodeAt(i);
|
|
43
|
+
hash = Math.imul(hash, 0x01000193);
|
|
44
|
+
}
|
|
45
|
+
return (hash >>> 0) % this.size;
|
|
46
|
+
/* eslint-enable no-bitwise */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,75 +1,14 @@
|
|
|
1
|
+
import type { BaseHttpClient } from '@crawlee/http-client';
|
|
1
2
|
import type { Dictionary } from '@crawlee/types';
|
|
2
|
-
import { Configuration } from '../configuration.js';
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
3
|
+
import type { Configuration } from '../configuration.js';
|
|
4
|
+
import type { IProxyConfiguration } from '../proxy_configuration.js';
|
|
5
|
+
import { Request, type RequestOptions, type Source } from '../request.js';
|
|
6
|
+
import type { IRequestLoader } from './request_loader.js';
|
|
7
|
+
import type { IRequestManager } from './request_manager.js';
|
|
5
8
|
/** @internal */
|
|
6
9
|
export declare const STATE_PERSISTENCE_KEY = "REQUEST_LIST_STATE";
|
|
7
10
|
/** @internal */
|
|
8
11
|
export declare const REQUESTS_PERSISTENCE_KEY = "REQUEST_LIST_REQUESTS";
|
|
9
|
-
/**
|
|
10
|
-
* Represents a static list of URLs to crawl.
|
|
11
|
-
*/
|
|
12
|
-
export interface IRequestList {
|
|
13
|
-
/**
|
|
14
|
-
* Returns the total number of unique requests present in the list.
|
|
15
|
-
*/
|
|
16
|
-
length(): number;
|
|
17
|
-
/**
|
|
18
|
-
* Returns `true` if all requests were already handled and there are no more left.
|
|
19
|
-
*/
|
|
20
|
-
isFinished(): Promise<boolean>;
|
|
21
|
-
/**
|
|
22
|
-
* Resolves to `true` if the next call to {@link IRequestList.fetchNextRequest} function
|
|
23
|
-
* would return `null`, otherwise it resolves to `false`.
|
|
24
|
-
* Note that even if the list is empty, there might be some pending requests currently being processed.
|
|
25
|
-
*/
|
|
26
|
-
isEmpty(): Promise<boolean>;
|
|
27
|
-
/**
|
|
28
|
-
* Returns number of handled requests.
|
|
29
|
-
*/
|
|
30
|
-
handledCount(): number;
|
|
31
|
-
/**
|
|
32
|
-
* Persists the current state of the `IRequestList` into the default {@link KeyValueStore}.
|
|
33
|
-
* The state is persisted automatically in regular intervals, but calling this method manually
|
|
34
|
-
* is useful in cases where you want to have the most current state available after you pause
|
|
35
|
-
* or stop fetching its requests. For example after you pause or abort a crawl. Or just before
|
|
36
|
-
* a server migration.
|
|
37
|
-
*/
|
|
38
|
-
persistState(): Promise<void>;
|
|
39
|
-
/**
|
|
40
|
-
* Gets the next {@link Request} to process. First, the function gets a request previously reclaimed
|
|
41
|
-
* using the {@link RequestList.reclaimRequest} function, if there is any.
|
|
42
|
-
* Otherwise it gets the next request from sources.
|
|
43
|
-
*
|
|
44
|
-
* The function's `Promise` resolves to `null` if there are no more
|
|
45
|
-
* requests to process.
|
|
46
|
-
*/
|
|
47
|
-
fetchNextRequest(): Promise<Request | null>;
|
|
48
|
-
/**
|
|
49
|
-
* Gets the next {@link Request} to process. First, the function gets a request previously reclaimed
|
|
50
|
-
* using the {@link RequestList.reclaimRequest} function, if there is any.
|
|
51
|
-
* Otherwise it gets the next request from sources.
|
|
52
|
-
*
|
|
53
|
-
* The function resolves to `null` if there are no more requests to process.
|
|
54
|
-
*
|
|
55
|
-
* Can be used to iterate over the `RequestList` instance in a `for await .. of` loop.
|
|
56
|
-
* Provides an alternative for the repeated use of `fetchNextRequest`.
|
|
57
|
-
*/
|
|
58
|
-
[Symbol.asyncIterator](): AsyncGenerator<Request>;
|
|
59
|
-
/**
|
|
60
|
-
* Reclaims request to the list if its processing failed.
|
|
61
|
-
* The request will become available in the next `this.fetchNextRequest()`.
|
|
62
|
-
*/
|
|
63
|
-
reclaimRequest(request: Request): Promise<void>;
|
|
64
|
-
/**
|
|
65
|
-
* Marks request as handled after successful processing.
|
|
66
|
-
*/
|
|
67
|
-
markRequestHandled(request: Request): Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* @internal
|
|
70
|
-
*/
|
|
71
|
-
inProgress: Set<string>;
|
|
72
|
-
}
|
|
73
12
|
export interface RequestListOptions {
|
|
74
13
|
/**
|
|
75
14
|
* An array of sources of URLs for the {@link RequestList}. It can be either an array of strings,
|
|
@@ -149,7 +88,7 @@ export interface RequestListOptions {
|
|
|
149
88
|
* Takes advantage of the internal address rotation and authentication process.
|
|
150
89
|
* If undefined, the `requestsFromUrl` requests will be made without proxy.
|
|
151
90
|
*/
|
|
152
|
-
proxyConfiguration?:
|
|
91
|
+
proxyConfiguration?: IProxyConfiguration;
|
|
153
92
|
/**
|
|
154
93
|
* Identifies the key in the default key-value store under which `RequestList` periodically stores its
|
|
155
94
|
* state (i.e. which URLs were crawled and which not).
|
|
@@ -208,7 +147,13 @@ export interface RequestListOptions {
|
|
|
208
147
|
*/
|
|
209
148
|
keepDuplicateUrls?: boolean;
|
|
210
149
|
/** @internal */
|
|
211
|
-
|
|
150
|
+
configuration?: Configuration;
|
|
151
|
+
/**
|
|
152
|
+
* The HTTP client to be used to download `requestsFromUrl` URLs.
|
|
153
|
+
*
|
|
154
|
+
* If not specified the `RequestList` will use the default HTTP client.
|
|
155
|
+
*/
|
|
156
|
+
httpClient?: BaseHttpClient;
|
|
212
157
|
}
|
|
213
158
|
/**
|
|
214
159
|
* Represents a static list of URLs to crawl.
|
|
@@ -232,8 +177,8 @@ export interface RequestListOptions {
|
|
|
232
177
|
* > In practical terms, such a combination can be useful when there is a large number of initial URLs,
|
|
233
178
|
* > but more URLs would be added dynamically by the crawler.
|
|
234
179
|
*
|
|
235
|
-
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
236
|
-
* which are in progress
|
|
180
|
+
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
181
|
+
* and which are in progress. The state may be automatically persisted to the default
|
|
237
182
|
* {@link KeyValueStore} by setting the `persistStateKey` option so that if the Node.js process is restarted,
|
|
238
183
|
* the crawling can continue where it left off. The automated persisting is launched upon receiving the `persistState`
|
|
239
184
|
* event that is periodically emitted by {@link EventManager}.
|
|
@@ -271,28 +216,19 @@ export interface RequestListOptions {
|
|
|
271
216
|
* ```
|
|
272
217
|
* @category Sources
|
|
273
218
|
*/
|
|
274
|
-
export declare class RequestList implements
|
|
275
|
-
private
|
|
219
|
+
export declare class RequestList implements IRequestLoader {
|
|
220
|
+
#private;
|
|
276
221
|
/**
|
|
277
222
|
* Array of all requests from all sources, in the order as they appeared in sources.
|
|
278
223
|
* All requests in the array have distinct uniqueKey!
|
|
279
224
|
* @internal
|
|
280
225
|
*/
|
|
281
|
-
requests: (Request | RequestOptions)[];
|
|
282
|
-
/** Index to the next item in requests array to fetch. All previous requests are either handled or in progress. */
|
|
283
|
-
private nextIndex;
|
|
284
|
-
/** Dictionary, key is Request.uniqueKey, value is corresponding index in the requests array. */
|
|
285
|
-
private uniqueKeyToIndex;
|
|
226
|
+
readonly requests: (Request | RequestOptions)[];
|
|
286
227
|
/**
|
|
287
228
|
* Set of `uniqueKey`s of requests that were returned by fetchNextRequest().
|
|
288
229
|
* @internal
|
|
289
230
|
*/
|
|
290
231
|
inProgress: Set<string>;
|
|
291
|
-
/**
|
|
292
|
-
* Set of `uniqueKey`s of requests for which reclaimRequest() was called.
|
|
293
|
-
* @internal
|
|
294
|
-
*/
|
|
295
|
-
reclaimed: Set<string>;
|
|
296
232
|
/**
|
|
297
233
|
* Starts as true because until we handle the first request, the list is effectively persisted by doing nothing.
|
|
298
234
|
* @internal
|
|
@@ -303,17 +239,7 @@ export declare class RequestList implements IRequestList {
|
|
|
303
239
|
* @internal
|
|
304
240
|
*/
|
|
305
241
|
areRequestsPersisted: boolean;
|
|
306
|
-
private isLoading;
|
|
307
|
-
private isInitialized;
|
|
308
|
-
private persistStateKey?;
|
|
309
|
-
private persistRequestsKey?;
|
|
310
|
-
private initialState?;
|
|
311
|
-
private store?;
|
|
312
|
-
private keepDuplicateUrls;
|
|
313
242
|
private sources;
|
|
314
|
-
private sourcesFunction?;
|
|
315
|
-
private proxyConfiguration?;
|
|
316
|
-
private events;
|
|
317
243
|
/**
|
|
318
244
|
* To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
|
|
319
245
|
* @param options All `RequestList` configuration options
|
|
@@ -330,33 +256,39 @@ export declare class RequestList implements IRequestList {
|
|
|
330
256
|
* This needs to be done in a memory efficient way. We should update the input
|
|
331
257
|
* to a Stream once apify-client supports streams.
|
|
332
258
|
*/
|
|
333
|
-
|
|
259
|
+
private addPersistedRequests;
|
|
334
260
|
/**
|
|
335
261
|
* Add Requests from both options.sources and options.sourcesFunction.
|
|
336
262
|
* This function is called only when persisted sources were not loaded.
|
|
337
263
|
* We need to avoid keeping both sources and requests in memory
|
|
338
264
|
* to reduce memory footprint with very large sources.
|
|
339
265
|
*/
|
|
340
|
-
|
|
266
|
+
private addRequestsFromSources;
|
|
341
267
|
/**
|
|
342
268
|
* @inheritDoc
|
|
343
269
|
*/
|
|
344
270
|
persistState(): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Removes the `PERSIST_STATE` event listener registered during initialization and persists
|
|
273
|
+
* the current state one last time. Call this when you are done with the `RequestList` to avoid
|
|
274
|
+
* leaking the listener (and the requests it retains) on the shared event manager.
|
|
275
|
+
*/
|
|
276
|
+
teardown(): Promise<void>;
|
|
345
277
|
/**
|
|
346
278
|
* Unlike persistState(), this is used only internally, since the sources
|
|
347
279
|
* are automatically persisted at RequestList initialization (if the persistRequestsKey is set),
|
|
348
280
|
* but there's no reason to persist it again afterwards, because RequestList is immutable.
|
|
349
281
|
*/
|
|
350
|
-
|
|
282
|
+
private persistRequests;
|
|
351
283
|
/**
|
|
352
284
|
* Restores RequestList state from a state object.
|
|
353
285
|
*/
|
|
354
|
-
|
|
286
|
+
private restoreState;
|
|
355
287
|
/**
|
|
356
288
|
* Attempts to load state and requests using the `RequestList` configuration
|
|
357
289
|
* and returns a tuple of [state, requests] where each may be null if not loaded.
|
|
358
290
|
*/
|
|
359
|
-
|
|
291
|
+
private loadStateAndPersistedRequests;
|
|
360
292
|
/**
|
|
361
293
|
* Returns an object representing the internal state of the `RequestList` instance.
|
|
362
294
|
* Note that the object's fields can change in future releases.
|
|
@@ -382,47 +314,53 @@ export declare class RequestList implements IRequestList {
|
|
|
382
314
|
/**
|
|
383
315
|
* @inheritDoc
|
|
384
316
|
*/
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* @inheritDoc
|
|
388
|
-
*/
|
|
389
|
-
reclaimRequest(request: Request): Promise<void>;
|
|
317
|
+
markRequestAsHandled(request: Request): Promise<void>;
|
|
390
318
|
/**
|
|
391
319
|
* Adds all fetched requests from a URL from a remote resource.
|
|
392
320
|
*/
|
|
393
|
-
|
|
394
|
-
|
|
321
|
+
private addFetchedRequests;
|
|
322
|
+
private getPersistedState;
|
|
395
323
|
/**
|
|
396
324
|
* Fetches URLs from requestsFromUrl and returns them in format of list of requests
|
|
397
325
|
*/
|
|
398
|
-
|
|
326
|
+
private fetchRequestsFromUrl;
|
|
399
327
|
/**
|
|
400
328
|
* Adds given request.
|
|
401
329
|
* If the `source` parameter is a string or plain object and not an instance
|
|
402
330
|
* of a `Request`, then the function creates a `Request` instance.
|
|
403
331
|
*/
|
|
404
|
-
|
|
332
|
+
private addRequest;
|
|
405
333
|
/**
|
|
406
334
|
* Helper function that validates unique key.
|
|
407
335
|
* Throws an error if uniqueKey is not a non-empty string.
|
|
408
336
|
*/
|
|
409
|
-
|
|
337
|
+
private ensureUniqueKeyValid;
|
|
410
338
|
/**
|
|
411
|
-
* Checks that request is
|
|
339
|
+
* Checks that a request is currently being processed and throws an error if not.
|
|
412
340
|
*/
|
|
413
|
-
|
|
341
|
+
private ensureInProgress;
|
|
414
342
|
/**
|
|
415
343
|
* Throws an error if request list wasn't initialized.
|
|
416
344
|
*/
|
|
417
|
-
|
|
345
|
+
private ensureIsInitialized;
|
|
418
346
|
/**
|
|
419
347
|
* Returns the total number of unique requests present in the `RequestList`.
|
|
420
348
|
*/
|
|
421
|
-
|
|
349
|
+
getTotalCount(): Promise<number>;
|
|
350
|
+
/**
|
|
351
|
+
* Returns the number of pending requests in the `RequestList`.
|
|
352
|
+
*/
|
|
353
|
+
getPendingCount(): Promise<number>;
|
|
354
|
+
/**
|
|
355
|
+
* Combines this list with a request manager (a {@link RequestQueue} by default) into a
|
|
356
|
+
* {@link RequestManagerTandem}, allowing requests to be added and reclaimed while still
|
|
357
|
+
* being read from this list first.
|
|
358
|
+
*/
|
|
359
|
+
toTandem(requestManager?: IRequestManager): Promise<IRequestManager>;
|
|
422
360
|
/**
|
|
423
361
|
* @inheritDoc
|
|
424
362
|
*/
|
|
425
|
-
|
|
363
|
+
getHandledCount(): Promise<number>;
|
|
426
364
|
/**
|
|
427
365
|
* Opens a request list and returns a promise resolving to an instance
|
|
428
366
|
* of the {@link RequestList} class that is already initialized.
|
|
@@ -480,7 +418,7 @@ export declare class RequestList implements IRequestList {
|
|
|
480
418
|
/**
|
|
481
419
|
* @internal wraps public utility for mocking purposes
|
|
482
420
|
*/
|
|
483
|
-
private
|
|
421
|
+
private downloadListOfUrls;
|
|
484
422
|
}
|
|
485
423
|
/**
|
|
486
424
|
* Represents state of a {@link RequestList}. It can be used to resume a {@link RequestList} which has been previously processed.
|
|
@@ -509,4 +447,3 @@ export interface RequestListState {
|
|
|
509
447
|
type RequestListSource = string | Source;
|
|
510
448
|
export type RequestListSourcesFunction = () => Promise<RequestListSource[]>;
|
|
511
449
|
export {};
|
|
512
|
-
//# sourceMappingURL=request_list.d.ts.map
|