@crawlee/core 4.0.0-beta.99 → 4.0.0-rc.1
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 +1 -1
- package/configuration.d.ts +16 -47
- package/configuration.js +13 -25
- package/debug.js +4 -4
- package/errors.d.ts +28 -38
- package/errors.js +33 -47
- package/events/event_manager.d.ts +2 -2
- package/events/event_manager.js +7 -6
- package/events/index.d.ts +1 -0
- package/events/local_event_manager.d.ts +1 -8
- package/events/local_event_manager.js +13 -13
- package/events/system_info.d.ts +38 -0
- package/index.d.ts +2 -8
- package/index.js +4 -8
- package/internal.d.ts +8 -0
- package/internal.js +9 -0
- package/log.d.ts +10 -11
- package/log.js +52 -20
- package/memory-storage/memory-storage.d.ts +15 -18
- package/memory-storage/memory-storage.js +80 -58
- package/memory-storage/resource-clients/dataset.d.ts +1 -6
- package/memory-storage/resource-clients/dataset.js +23 -31
- package/memory-storage/resource-clients/key-value-store.d.ts +1 -10
- package/memory-storage/resource-clients/key-value-store.js +43 -67
- package/memory-storage/resource-clients/request-queue.d.ts +1 -42
- package/memory-storage/resource-clients/request-queue.js +109 -117
- package/owned_or_injected.d.ts +1 -3
- package/owned_or_injected.js +17 -17
- package/package.json +17 -20
- package/proxy_configuration.d.ts +21 -26
- package/proxy_configuration.js +35 -25
- package/recoverable_state.d.ts +104 -47
- package/recoverable_state.js +199 -74
- package/request.d.ts +20 -107
- package/request.js +78 -244
- package/serialization.js +17 -16
- package/service_locator.d.ts +22 -10
- package/service_locator.js +59 -48
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +13 -8
- package/storages/dataset.js +149 -40
- package/storages/index.d.ts +4 -4
- package/storages/index.js +2 -4
- package/storages/key_value_store.d.ts +16 -35
- package/storages/key_value_store.js +223 -110
- package/storages/key_value_store_codec.js +6 -11
- package/storages/request_dedup_cache.d.ts +1 -4
- package/storages/request_dedup_cache.js +15 -15
- package/storages/request_list.d.ts +9 -104
- package/storages/request_list.js +236 -233
- package/storages/request_loader.d.ts +49 -18
- package/storages/request_loader.js +36 -1
- package/storages/request_manager.d.ts +86 -0
- package/storages/request_manager_tandem.d.ts +14 -38
- package/storages/request_manager_tandem.js +67 -64
- package/storages/request_queue.d.ts +23 -50
- package/storages/request_queue.js +371 -226
- package/storages/storage_instance_manager.d.ts +2 -4
- package/storages/storage_instance_manager.js +21 -21
- package/storages/storage_stats.d.ts +1 -1
- package/storages/storage_stats.js +4 -4
- package/storages/transaction.d.ts +270 -0
- package/storages/transaction.js +296 -0
- package/storages/utils.d.ts +6 -3
- package/storages/utils.js +11 -2
- package/system-info/runtime.js +7 -7
- package/url.d.ts +9 -0
- package/url.js +11 -0
- package/validators.d.ts +23 -25
- package/validators.js +14 -25
- package/autoscaling/autoscaled_pool.d.ts +0 -213
- package/autoscaling/autoscaled_pool.js +0 -378
- package/autoscaling/client_load_signal.d.ts +0 -59
- package/autoscaling/client_load_signal.js +0 -73
- package/autoscaling/concurrency_system.d.ts +0 -283
- package/autoscaling/concurrency_system.js +0 -350
- package/autoscaling/cpu_load_signal.d.ts +0 -44
- package/autoscaling/cpu_load_signal.js +0 -46
- package/autoscaling/event_loop_load_signal.d.ts +0 -54
- package/autoscaling/event_loop_load_signal.js +0 -60
- package/autoscaling/index.d.ts +0 -9
- package/autoscaling/index.js +0 -9
- package/autoscaling/load_signal.d.ts +0 -99
- package/autoscaling/load_signal.js +0 -103
- package/autoscaling/memory_load_signal.d.ts +0 -56
- package/autoscaling/memory_load_signal.js +0 -106
- package/autoscaling/snapshotter.d.ts +0 -87
- package/autoscaling/snapshotter.js +0 -67
- package/autoscaling/system_status.d.ts +0 -161
- package/autoscaling/system_status.js +0 -139
- package/autoscaling/weighted_avg.d.ts +0 -5
- package/autoscaling/weighted_avg.js +0 -14
- package/cookie_utils.d.ts +0 -44
- package/cookie_utils.js +0 -122
- package/crawlers/context_pipeline.d.ts +0 -70
- package/crawlers/context_pipeline.js +0 -122
- package/crawlers/crawler_commons.d.ts +0 -257
- package/crawlers/crawler_commons.js +0 -107
- package/crawlers/error_snapshotter.d.ts +0 -59
- package/crawlers/error_snapshotter.js +0 -117
- package/crawlers/error_tracker.d.ts +0 -54
- package/crawlers/error_tracker.js +0 -308
- package/crawlers/index.d.ts +0 -5
- package/crawlers/index.js +0 -5
- package/crawlers/internals/types.d.ts +0 -7
- package/crawlers/statistics.d.ts +0 -209
- package/crawlers/statistics.js +0 -350
- package/enqueue_links/enqueue_links.d.ts +0 -264
- package/enqueue_links/enqueue_links.js +0 -271
- package/enqueue_links/index.d.ts +0 -2
- package/enqueue_links/index.js +0 -2
- package/enqueue_links/shared.d.ts +0 -83
- package/enqueue_links/shared.js +0 -221
- package/router.d.ts +0 -309
- package/router.js +0 -309
- package/session_pool/consts.d.ts +0 -3
- package/session_pool/consts.js +0 -3
- package/session_pool/errors.d.ts +0 -7
- package/session_pool/errors.js +0 -11
- package/session_pool/fingerprint.d.ts +0 -9
- package/session_pool/fingerprint.js +0 -30
- package/session_pool/index.d.ts +0 -4
- package/session_pool/index.js +0 -4
- package/session_pool/session.d.ts +0 -161
- package/session_pool/session.js +0 -218
- package/session_pool/session_pool.d.ts +0 -246
- package/session_pool/session_pool.js +0 -386
- package/storages/access_checking.d.ts +0 -12
- package/storages/access_checking.js +0 -17
- package/storages/sitemap_request_loader.d.ts +0 -249
- package/storages/sitemap_request_loader.js +0 -432
- /package/{crawlers/internals/types.js → events/system_info.js} +0 -0
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Crawlee is available as the [`crawlee`](https://www.npmjs.com/package/crawlee) N
|
|
|
34
34
|
|
|
35
35
|
We recommend visiting the [Introduction tutorial](https://crawlee.dev/js/docs/introduction) in Crawlee documentation for more information.
|
|
36
36
|
|
|
37
|
-
> Crawlee requires **Node.js
|
|
37
|
+
> Crawlee requires **Node.js 22.13 or higher**.
|
|
38
38
|
|
|
39
39
|
### With Crawlee CLI
|
|
40
40
|
|
package/configuration.d.ts
CHANGED
|
@@ -6,47 +6,39 @@ export interface ConfigField<T extends z.ZodType = z.ZodType> {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function field<T extends z.ZodType>(schema: T, envVar?: string | string[]): ConfigField<T>;
|
|
8
8
|
/** Zod preprocessor treating `'0'` and `'false'` as falsy. */
|
|
9
|
-
export declare const coerceBoolean: z.
|
|
10
|
-
export declare const coerceNumber: z.
|
|
9
|
+
export declare const coerceBoolean: z.ZodPreprocess<z.ZodBoolean, unknown>;
|
|
10
|
+
export declare const coerceNumber: z.ZodPreprocess<z.ZodNumber, unknown>;
|
|
11
11
|
export declare const crawleeConfigFields: {
|
|
12
|
-
/** @default 'default' */
|
|
13
|
-
defaultDatasetId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
14
12
|
/** @default true */
|
|
15
|
-
purgeOnStart: ConfigField<z.ZodDefault<z.
|
|
16
|
-
/** @default 'default' */
|
|
17
|
-
defaultKeyValueStoreId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
18
|
-
/** @default 'default' */
|
|
19
|
-
defaultRequestQueueId: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
13
|
+
purgeOnStart: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
20
14
|
/** @default 0.95 */
|
|
21
|
-
maxUsedCpuRatio: ConfigField<z.ZodDefault<z.
|
|
15
|
+
maxUsedCpuRatio: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
22
16
|
/** @default 0.25 */
|
|
23
|
-
availableMemoryRatio: ConfigField<z.ZodDefault<z.
|
|
24
|
-
memoryMbytes: ConfigField<z.ZodOptional<z.
|
|
17
|
+
availableMemoryRatio: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
18
|
+
memoryMbytes: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
25
19
|
/** @default 60_000 */
|
|
26
|
-
persistStateIntervalMillis: ConfigField<z.ZodDefault<z.
|
|
20
|
+
persistStateIntervalMillis: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
27
21
|
/**
|
|
28
22
|
* Internal safety-net timeout for a single request, in milliseconds. When unset the crawler derives it from
|
|
29
23
|
* the request handler timeout (twice it, and never below 5 minutes).
|
|
30
24
|
*/
|
|
31
|
-
internalTimeoutMillis: ConfigField<z.ZodOptional<z.
|
|
25
|
+
internalTimeoutMillis: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
32
26
|
/** @default 1_000 */
|
|
33
|
-
systemInfoIntervalMillis: ConfigField<z.ZodDefault<z.
|
|
34
|
-
/** @default 'INPUT' */
|
|
35
|
-
inputKey: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
27
|
+
systemInfoIntervalMillis: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodNumber, unknown>>>;
|
|
36
28
|
/** @default true */
|
|
37
|
-
headless: ConfigField<z.ZodDefault<z.
|
|
29
|
+
headless: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
38
30
|
/** @default false */
|
|
39
|
-
xvfb: ConfigField<z.ZodDefault<z.
|
|
31
|
+
xvfb: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
40
32
|
chromeExecutablePath: ConfigField<z.ZodOptional<z.ZodString>>;
|
|
41
33
|
defaultBrowserPath: ConfigField<z.ZodOptional<z.ZodString>>;
|
|
42
34
|
/** @default false */
|
|
43
|
-
disableBrowserSandbox: ConfigField<z.ZodDefault<z.
|
|
44
|
-
logLevel: ConfigField<z.ZodOptional<z.
|
|
35
|
+
disableBrowserSandbox: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
36
|
+
logLevel: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodEnum<typeof LogLevel>, unknown>>>;
|
|
45
37
|
/** @default true */
|
|
46
|
-
persistStorage: ConfigField<z.ZodDefault<z.
|
|
38
|
+
persistStorage: ConfigField<z.ZodDefault<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
47
39
|
/** @default './storage' */
|
|
48
40
|
storageDir: ConfigField<z.ZodDefault<z.ZodString>>;
|
|
49
|
-
containerized: ConfigField<z.ZodOptional<z.
|
|
41
|
+
containerized: ConfigField<z.ZodOptional<z.ZodPreprocess<z.ZodBoolean, unknown>>>;
|
|
50
42
|
};
|
|
51
43
|
export type FieldsInput<F extends Record<string, ConfigField>> = {
|
|
52
44
|
[K in keyof F]?: z.output<F[K]['schema']>;
|
|
@@ -101,9 +93,6 @@ export interface Configuration extends ResolvedConfigValues {
|
|
|
101
93
|
* `memoryMbytes` | `CRAWLEE_MEMORY_MBYTES` | -
|
|
102
94
|
* `logLevel` | `CRAWLEE_LOG_LEVEL` | -
|
|
103
95
|
* `headless` | `CRAWLEE_HEADLESS` | `true`
|
|
104
|
-
* `defaultDatasetId` | `CRAWLEE_DEFAULT_DATASET_ID` | `'default'`
|
|
105
|
-
* `defaultKeyValueStoreId` | `CRAWLEE_DEFAULT_KEY_VALUE_STORE_ID` | `'default'`
|
|
106
|
-
* `defaultRequestQueueId` | `CRAWLEE_DEFAULT_REQUEST_QUEUE_ID` | `'default'`
|
|
107
96
|
* `persistStateIntervalMillis` | `CRAWLEE_PERSIST_STATE_INTERVAL_MILLIS` | `60_000`
|
|
108
97
|
* `internalTimeoutMillis` | `CRAWLEE_INTERNAL_TIMEOUT` | -
|
|
109
98
|
* `purgeOnStart` | `CRAWLEE_PURGE_ON_START` | `true`
|
|
@@ -114,7 +103,6 @@ export interface Configuration extends ResolvedConfigValues {
|
|
|
114
103
|
*
|
|
115
104
|
* Key | Environment Variable | Default Value
|
|
116
105
|
* ---|---|---
|
|
117
|
-
* `inputKey` | `CRAWLEE_INPUT_KEY` | `'INPUT'`
|
|
118
106
|
* `xvfb` | `CRAWLEE_XVFB` | `false`
|
|
119
107
|
* `chromeExecutablePath` | `CRAWLEE_CHROME_EXECUTABLE_PATH` | -
|
|
120
108
|
* `defaultBrowserPath` | `CRAWLEE_DEFAULT_BROWSER_PATH` | -
|
|
@@ -123,12 +111,12 @@ export interface Configuration extends ResolvedConfigValues {
|
|
|
123
111
|
* `containerized` | `CRAWLEE_CONTAINERIZED` | -
|
|
124
112
|
*/
|
|
125
113
|
export declare class Configuration {
|
|
114
|
+
#private;
|
|
126
115
|
/**
|
|
127
116
|
* Field definitions for this configuration class.
|
|
128
117
|
* Subclasses override this to register additional fields.
|
|
129
118
|
*/
|
|
130
119
|
protected static fields: Record<string, ConfigField>;
|
|
131
|
-
private resolvedValues;
|
|
132
120
|
/**
|
|
133
121
|
* Creates new `Configuration` instance with provided options.
|
|
134
122
|
* Constructor options take precedence over environment variables, which take precedence
|
|
@@ -141,23 +129,4 @@ export declare class Configuration {
|
|
|
141
129
|
* Delegates to the global ServiceLocator, making it the single source of truth for service management.
|
|
142
130
|
*/
|
|
143
131
|
static getGlobalConfiguration(): Configuration;
|
|
144
|
-
/**
|
|
145
|
-
* Resolves all field values once using the priority chain:
|
|
146
|
-
* constructor options > env vars > crawlee.json > schema defaults.
|
|
147
|
-
*/
|
|
148
|
-
private static resolveAll;
|
|
149
|
-
/**
|
|
150
|
-
* Registers getters (and throwing setters) on the instance for each field.
|
|
151
|
-
*/
|
|
152
|
-
private registerAccessors;
|
|
153
|
-
/**
|
|
154
|
-
* Reads the first defined env var value for a field definition.
|
|
155
|
-
* Empty strings are treated as unset, falling through to crawlee.json or schema defaults.
|
|
156
|
-
* (Crawlee v3 coerced `''` to `false`/`0`/`''` per type — v4 drops that for consistency.)
|
|
157
|
-
*/
|
|
158
|
-
private static readEnvVar;
|
|
159
|
-
/**
|
|
160
|
-
* Loads config options from crawlee.json in the current working directory.
|
|
161
|
-
*/
|
|
162
|
-
private static loadFileOptions;
|
|
163
132
|
}
|
package/configuration.js
CHANGED
|
@@ -36,17 +36,11 @@ const logLevelSchema = z.preprocess((val) => {
|
|
|
36
36
|
if (key in LogLevel)
|
|
37
37
|
return LogLevel[key];
|
|
38
38
|
return val;
|
|
39
|
-
}, z.
|
|
39
|
+
}, z.enum(LogLevel));
|
|
40
40
|
// --- Crawlee config field definitions ---
|
|
41
41
|
export const crawleeConfigFields = {
|
|
42
|
-
/** @default 'default' */
|
|
43
|
-
defaultDatasetId: field(z.string().default('default'), 'CRAWLEE_DEFAULT_DATASET_ID'),
|
|
44
42
|
/** @default true */
|
|
45
43
|
purgeOnStart: field(coerceBoolean.default(true), 'CRAWLEE_PURGE_ON_START'),
|
|
46
|
-
/** @default 'default' */
|
|
47
|
-
defaultKeyValueStoreId: field(z.string().default('default'), 'CRAWLEE_DEFAULT_KEY_VALUE_STORE_ID'),
|
|
48
|
-
/** @default 'default' */
|
|
49
|
-
defaultRequestQueueId: field(z.string().default('default'), 'CRAWLEE_DEFAULT_REQUEST_QUEUE_ID'),
|
|
50
44
|
/** @default 0.95 */
|
|
51
45
|
maxUsedCpuRatio: field(coerceNumber.default(0.95)),
|
|
52
46
|
/** @default 0.25 */
|
|
@@ -61,8 +55,6 @@ export const crawleeConfigFields = {
|
|
|
61
55
|
internalTimeoutMillis: field(coerceNumber.optional(), 'CRAWLEE_INTERNAL_TIMEOUT'),
|
|
62
56
|
/** @default 1_000 */
|
|
63
57
|
systemInfoIntervalMillis: field(coerceNumber.default(1_000)),
|
|
64
|
-
/** @default 'INPUT' */
|
|
65
|
-
inputKey: field(z.string().default('INPUT'), 'CRAWLEE_INPUT_KEY'),
|
|
66
58
|
/** @default true */
|
|
67
59
|
headless: field(coerceBoolean.default(true), 'CRAWLEE_HEADLESS'),
|
|
68
60
|
/** @default false */
|
|
@@ -119,9 +111,6 @@ export const crawleeConfigFields = {
|
|
|
119
111
|
* `memoryMbytes` | `CRAWLEE_MEMORY_MBYTES` | -
|
|
120
112
|
* `logLevel` | `CRAWLEE_LOG_LEVEL` | -
|
|
121
113
|
* `headless` | `CRAWLEE_HEADLESS` | `true`
|
|
122
|
-
* `defaultDatasetId` | `CRAWLEE_DEFAULT_DATASET_ID` | `'default'`
|
|
123
|
-
* `defaultKeyValueStoreId` | `CRAWLEE_DEFAULT_KEY_VALUE_STORE_ID` | `'default'`
|
|
124
|
-
* `defaultRequestQueueId` | `CRAWLEE_DEFAULT_REQUEST_QUEUE_ID` | `'default'`
|
|
125
114
|
* `persistStateIntervalMillis` | `CRAWLEE_PERSIST_STATE_INTERVAL_MILLIS` | `60_000`
|
|
126
115
|
* `internalTimeoutMillis` | `CRAWLEE_INTERNAL_TIMEOUT` | -
|
|
127
116
|
* `purgeOnStart` | `CRAWLEE_PURGE_ON_START` | `true`
|
|
@@ -132,7 +121,6 @@ export const crawleeConfigFields = {
|
|
|
132
121
|
*
|
|
133
122
|
* Key | Environment Variable | Default Value
|
|
134
123
|
* ---|---|---
|
|
135
|
-
* `inputKey` | `CRAWLEE_INPUT_KEY` | `'INPUT'`
|
|
136
124
|
* `xvfb` | `CRAWLEE_XVFB` | `false`
|
|
137
125
|
* `chromeExecutablePath` | `CRAWLEE_CHROME_EXECUTABLE_PATH` | -
|
|
138
126
|
* `defaultBrowserPath` | `CRAWLEE_DEFAULT_BROWSER_PATH` | -
|
|
@@ -147,7 +135,7 @@ export class Configuration {
|
|
|
147
135
|
* Subclasses override this to register additional fields.
|
|
148
136
|
*/
|
|
149
137
|
static fields = crawleeConfigFields;
|
|
150
|
-
resolvedValues;
|
|
138
|
+
#resolvedValues;
|
|
151
139
|
/**
|
|
152
140
|
* Creates new `Configuration` instance with provided options.
|
|
153
141
|
* Constructor options take precedence over environment variables, which take precedence
|
|
@@ -155,9 +143,9 @@ export class Configuration {
|
|
|
155
143
|
*/
|
|
156
144
|
constructor(options = {}) {
|
|
157
145
|
const fields = this.constructor.fields;
|
|
158
|
-
const fileOptions = Configuration
|
|
159
|
-
this
|
|
160
|
-
this
|
|
146
|
+
const fileOptions = Configuration.#loadFileOptions();
|
|
147
|
+
this.#resolvedValues = Configuration.#resolveAll(fields, options, fileOptions);
|
|
148
|
+
this.#registerAccessors();
|
|
161
149
|
// Set the log level
|
|
162
150
|
const logLevel = this.logLevel;
|
|
163
151
|
if (logLevel != null) {
|
|
@@ -176,7 +164,7 @@ export class Configuration {
|
|
|
176
164
|
* Resolves all field values once using the priority chain:
|
|
177
165
|
* constructor options > env vars > crawlee.json > schema defaults.
|
|
178
166
|
*/
|
|
179
|
-
static resolveAll(fields, userOptions, fileOptions) {
|
|
167
|
+
static #resolveAll(fields, userOptions, fileOptions) {
|
|
180
168
|
const values = {};
|
|
181
169
|
for (const [key, fieldDef] of Object.entries(fields)) {
|
|
182
170
|
// 1. Constructor options (highest priority)
|
|
@@ -185,7 +173,7 @@ export class Configuration {
|
|
|
185
173
|
continue;
|
|
186
174
|
}
|
|
187
175
|
// 2. Environment variables
|
|
188
|
-
const envValue = Configuration
|
|
176
|
+
const envValue = Configuration.#readEnvVar(fieldDef);
|
|
189
177
|
if (envValue != null) {
|
|
190
178
|
values[key] = fieldDef.schema.parse(envValue);
|
|
191
179
|
continue;
|
|
@@ -196,20 +184,20 @@ export class Configuration {
|
|
|
196
184
|
continue;
|
|
197
185
|
}
|
|
198
186
|
// 4. Schema default (by parsing undefined through the schema)
|
|
199
|
-
const
|
|
200
|
-
values[key] =
|
|
187
|
+
const parsed = fieldDef.schema.safeParse(undefined);
|
|
188
|
+
values[key] = parsed.success ? parsed.data : undefined;
|
|
201
189
|
}
|
|
202
190
|
return values;
|
|
203
191
|
}
|
|
204
192
|
/**
|
|
205
193
|
* Registers getters (and throwing setters) on the instance for each field.
|
|
206
194
|
*/
|
|
207
|
-
registerAccessors() {
|
|
195
|
+
#registerAccessors() {
|
|
208
196
|
const fields = this.constructor.fields;
|
|
209
197
|
const descriptors = {};
|
|
210
198
|
for (const key of Object.keys(fields)) {
|
|
211
199
|
descriptors[key] = {
|
|
212
|
-
get: () => this
|
|
200
|
+
get: () => this.#resolvedValues[key],
|
|
213
201
|
set() {
|
|
214
202
|
throw new TypeError('Configuration is immutable. Pass options via the constructor instead.');
|
|
215
203
|
},
|
|
@@ -224,7 +212,7 @@ export class Configuration {
|
|
|
224
212
|
* Empty strings are treated as unset, falling through to crawlee.json or schema defaults.
|
|
225
213
|
* (Crawlee v3 coerced `''` to `false`/`0`/`''` per type — v4 drops that for consistency.)
|
|
226
214
|
*/
|
|
227
|
-
static readEnvVar(fieldDef) {
|
|
215
|
+
static #readEnvVar(fieldDef) {
|
|
228
216
|
if (!fieldDef.envVar)
|
|
229
217
|
return undefined;
|
|
230
218
|
const envVars = Array.isArray(fieldDef.envVar) ? fieldDef.envVar : [fieldDef.envVar];
|
|
@@ -238,7 +226,7 @@ export class Configuration {
|
|
|
238
226
|
/**
|
|
239
227
|
* Loads config options from crawlee.json in the current working directory.
|
|
240
228
|
*/
|
|
241
|
-
static loadFileOptions() {
|
|
229
|
+
static #loadFileOptions() {
|
|
242
230
|
try {
|
|
243
231
|
const file = readFileSync(join(process.cwd(), 'crawlee.json'));
|
|
244
232
|
return JSON.parse(file.toString());
|
package/debug.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
|
-
import
|
|
2
|
+
import { parseArgument, schemas } from './validators.js';
|
|
3
3
|
/**
|
|
4
4
|
* Creates a standardized debug info from request and response. This info is usually added to dataset under the hidden `#debug` field.
|
|
5
5
|
*
|
|
@@ -12,9 +12,9 @@ import ow from 'ow';
|
|
|
12
12
|
* @internal
|
|
13
13
|
*/
|
|
14
14
|
export function createRequestDebugInfo(request, response = {}, additionalFields = {}) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
parseArgument(request, schemas.anyObject);
|
|
16
|
+
parseArgument(response, schemas.anyObject);
|
|
17
|
+
parseArgument(additionalFields, schemas.anyObject);
|
|
18
18
|
return {
|
|
19
19
|
requestId: request.id,
|
|
20
20
|
url: request.url,
|
package/errors.d.ts
CHANGED
|
@@ -10,9 +10,14 @@ export declare class NonRetryableError extends Error {
|
|
|
10
10
|
export declare class CriticalError extends NonRetryableError {
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* A schema validation issue, structurally compatible with `StandardSchemaV1.Issue`. Declared here so that
|
|
14
|
+
* error types do not have to depend on `@standard-schema/spec`.
|
|
14
15
|
*/
|
|
15
|
-
export
|
|
16
|
+
export interface SchemaIssue {
|
|
17
|
+
readonly message: string;
|
|
18
|
+
readonly path?: readonly (PropertyKey | {
|
|
19
|
+
key: PropertyKey;
|
|
20
|
+
})[];
|
|
16
21
|
}
|
|
17
22
|
/**
|
|
18
23
|
* Thrown when a request's `userData` does not match the {@link RouteSchemas|Standard Schema} registered for its label.
|
|
@@ -21,26 +26,19 @@ export declare class MissingRouteError extends CriticalError {
|
|
|
21
26
|
*/
|
|
22
27
|
export declare class RequestValidationError extends NonRetryableError {
|
|
23
28
|
readonly label: string | symbol;
|
|
24
|
-
readonly issues: readonly
|
|
25
|
-
|
|
26
|
-
readonly path?: readonly (PropertyKey | {
|
|
27
|
-
key: PropertyKey;
|
|
28
|
-
})[];
|
|
29
|
-
}[];
|
|
30
|
-
constructor(label: string | symbol, issues: readonly {
|
|
31
|
-
readonly message: string;
|
|
32
|
-
readonly path?: readonly (PropertyKey | {
|
|
33
|
-
key: PropertyKey;
|
|
34
|
-
})[];
|
|
35
|
-
}[]);
|
|
29
|
+
readonly issues: readonly SchemaIssue[];
|
|
30
|
+
constructor(label: string | symbol, issues: readonly SchemaIssue[]);
|
|
36
31
|
}
|
|
37
32
|
/**
|
|
38
|
-
*
|
|
33
|
+
* Thrown by {@link RecoverableState} when a persisted state record does not match its `stateSchema`.
|
|
39
34
|
*
|
|
40
|
-
*
|
|
35
|
+
* Whether a corrupt record should abort the run or be discarded in favour of the defaults depends on what the
|
|
36
|
+
* state is for, so {@link RecoverableState.initialize} always throws and leaves the choice to the caller.
|
|
41
37
|
*/
|
|
42
|
-
export declare class
|
|
43
|
-
|
|
38
|
+
export declare class StateValidationError extends Error {
|
|
39
|
+
readonly persistStateKey: string;
|
|
40
|
+
readonly issues: readonly SchemaIssue[];
|
|
41
|
+
constructor(persistStateKey: string, issues: readonly SchemaIssue[]);
|
|
44
42
|
}
|
|
45
43
|
/**
|
|
46
44
|
* Errors of `SessionError` type retire the session associated with the request and trigger a regular retry.
|
|
@@ -51,22 +49,20 @@ export declare class SessionError extends Error {
|
|
|
51
49
|
constructor(message?: string);
|
|
52
50
|
}
|
|
53
51
|
/**
|
|
54
|
-
*
|
|
52
|
+
* A {@link SessionError} for a session that finished without being blocked, e.g. by reaching its
|
|
53
|
+
* `maxUsageCount` or `maxAgeSecs`. A plain `SessionError` means the session was blocked.
|
|
55
54
|
*/
|
|
56
|
-
export declare class
|
|
57
|
-
constructor(sessionId?: string);
|
|
58
|
-
}
|
|
59
|
-
export declare class ContextPipelineInterruptedError extends Error {
|
|
60
|
-
constructor(message?: string);
|
|
55
|
+
export declare class SessionRetiredError extends SessionError {
|
|
61
56
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Wraps the failure of a callback registered with {@link StorageTransaction.afterCommit|`afterCommit`}
|
|
59
|
+
* that ran after the request's writes had already been committed.
|
|
60
|
+
*
|
|
61
|
+
* Non-retryable by nature: the writes are durable, so re-running the request handler would duplicate
|
|
62
|
+
* them. A callback that throws a `NonRetryableError` of its own is left alone.
|
|
63
|
+
*/
|
|
64
|
+
export declare class AfterCommitError extends NonRetryableError {
|
|
65
|
+
constructor(cause: unknown);
|
|
70
66
|
}
|
|
71
67
|
/**
|
|
72
68
|
* Thrown when attempting to set a different service instance after one has already been retrieved.
|
|
@@ -74,9 +70,3 @@ export declare class RequestHandlerError extends Error {
|
|
|
74
70
|
export declare class ServiceConflictError extends Error {
|
|
75
71
|
constructor(serviceName: string, newValue: unknown, existingValue: unknown);
|
|
76
72
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Thrown by crawlers when `skipNavigation` is used on a request.
|
|
79
|
-
* Subclasses can catch this error to skip their own navigation-dependent logic.
|
|
80
|
-
*/
|
|
81
|
-
export declare class NavigationSkippedError extends NonRetryableError {
|
|
82
|
-
}
|
package/errors.js
CHANGED
|
@@ -10,10 +10,15 @@ export class NonRetryableError extends Error {
|
|
|
10
10
|
*/
|
|
11
11
|
export class CriticalError extends NonRetryableError {
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
function formatIssues(issues) {
|
|
14
|
+
return issues
|
|
15
|
+
.map((issue) => {
|
|
16
|
+
const path = (issue.path ?? [])
|
|
17
|
+
.map((segment) => (typeof segment === 'object' ? segment.key : segment))
|
|
18
|
+
.join('.');
|
|
19
|
+
return `- ${path ? `${path}: ` : ''}${issue.message}`;
|
|
20
|
+
})
|
|
21
|
+
.join('\n');
|
|
17
22
|
}
|
|
18
23
|
/**
|
|
19
24
|
* Thrown when a request's `userData` does not match the {@link RouteSchemas|Standard Schema} registered for its label.
|
|
@@ -24,27 +29,24 @@ export class RequestValidationError extends NonRetryableError {
|
|
|
24
29
|
label;
|
|
25
30
|
issues;
|
|
26
31
|
constructor(label, issues) {
|
|
27
|
-
|
|
28
|
-
.map((issue) => {
|
|
29
|
-
const path = (issue.path ?? [])
|
|
30
|
-
.map((segment) => (typeof segment === 'object' ? segment.key : segment))
|
|
31
|
-
.join('.');
|
|
32
|
-
return `- ${path ? `${path}: ` : ''}${issue.message}`;
|
|
33
|
-
})
|
|
34
|
-
.join('\n');
|
|
35
|
-
super(`Request userData for label '${String(label)}' failed schema validation:\n${details}`);
|
|
32
|
+
super(`Request userData for label '${String(label)}' failed schema validation:\n${formatIssues(issues)}`);
|
|
36
33
|
this.label = label;
|
|
37
34
|
this.issues = issues;
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
38
|
+
* Thrown by {@link RecoverableState} when a persisted state record does not match its `stateSchema`.
|
|
42
39
|
*
|
|
43
|
-
*
|
|
40
|
+
* Whether a corrupt record should abort the run or be discarded in favour of the defaults depends on what the
|
|
41
|
+
* state is for, so {@link RecoverableState.initialize} always throws and leaves the choice to the caller.
|
|
44
42
|
*/
|
|
45
|
-
export class
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
export class StateValidationError extends Error {
|
|
44
|
+
persistStateKey;
|
|
45
|
+
issues;
|
|
46
|
+
constructor(persistStateKey, issues) {
|
|
47
|
+
super(`State persisted under key '${persistStateKey}' failed schema validation:\n${formatIssues(issues)}`);
|
|
48
|
+
this.persistStateKey = persistStateKey;
|
|
49
|
+
this.issues = issues;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
@@ -58,31 +60,21 @@ export class SessionError extends Error {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
/**
|
|
61
|
-
*
|
|
63
|
+
* A {@link SessionError} for a session that finished without being blocked, e.g. by reaching its
|
|
64
|
+
* `maxUsageCount` or `maxAgeSecs`. A plain `SessionError` means the session was blocked.
|
|
62
65
|
*/
|
|
63
|
-
export class
|
|
64
|
-
constructor(sessionId) {
|
|
65
|
-
super(`The current SessionPool instance couldn't find a valid session${sessionId ? ` for the following id: ${sessionId}.` : '.'}`);
|
|
66
|
-
}
|
|
66
|
+
export class SessionRetiredError extends SessionError {
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
export class ContextPipelineCleanupError extends CriticalError {
|
|
79
|
-
constructor(error, options) {
|
|
80
|
-
super(undefined, { cause: error, ...options });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
export class RequestHandlerError extends Error {
|
|
84
|
-
constructor(error, options) {
|
|
85
|
-
super(undefined, { cause: error, ...options });
|
|
68
|
+
/**
|
|
69
|
+
* Wraps the failure of a callback registered with {@link StorageTransaction.afterCommit|`afterCommit`}
|
|
70
|
+
* that ran after the request's writes had already been committed.
|
|
71
|
+
*
|
|
72
|
+
* Non-retryable by nature: the writes are durable, so re-running the request handler would duplicate
|
|
73
|
+
* them. A callback that throws a `NonRetryableError` of its own is left alone.
|
|
74
|
+
*/
|
|
75
|
+
export class AfterCommitError extends NonRetryableError {
|
|
76
|
+
constructor(cause) {
|
|
77
|
+
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
86
78
|
}
|
|
87
79
|
}
|
|
88
80
|
/**
|
|
@@ -94,9 +86,3 @@ export class ServiceConflictError extends Error {
|
|
|
94
86
|
`Existing value: ${inspectValue(existingValue)}, attempted new value: ${inspectValue(newValue)}.`);
|
|
95
87
|
}
|
|
96
88
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Thrown by crawlers when `skipNavigation` is used on a request.
|
|
99
|
-
* Subclasses can catch this error to skip their own navigation-dependent logic.
|
|
100
|
-
*/
|
|
101
|
-
export class NavigationSkippedError extends NonRetryableError {
|
|
102
|
-
}
|
|
@@ -4,7 +4,7 @@ export interface EventManagerOptions {
|
|
|
4
4
|
/** Interval between emitted `persistState` events in milliseconds. */
|
|
5
5
|
persistStateIntervalMillis: number;
|
|
6
6
|
}
|
|
7
|
-
export declare
|
|
7
|
+
export declare enum EventType {
|
|
8
8
|
PERSIST_STATE = "persistState",
|
|
9
9
|
SYSTEM_INFO = "systemInfo",
|
|
10
10
|
MIGRATING = "migrating",
|
|
@@ -41,12 +41,12 @@ interface Intervals {
|
|
|
41
41
|
systemInfo?: BetterIntervalID;
|
|
42
42
|
}
|
|
43
43
|
export declare abstract class EventManager {
|
|
44
|
+
#private;
|
|
44
45
|
protected events: AsyncEventEmitter<{}>;
|
|
45
46
|
protected initialized: boolean;
|
|
46
47
|
protected intervals: Intervals;
|
|
47
48
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
48
49
|
protected log: import("@crawlee/types").CrawleeLogger;
|
|
49
|
-
private persistStateIntervalMillis;
|
|
50
50
|
constructor(options: EventManagerOptions);
|
|
51
51
|
/**
|
|
52
52
|
* Initializes the event manager by starting the `persistState` event interval.
|
package/events/event_manager.js
CHANGED
|
@@ -15,10 +15,11 @@ export class EventManager {
|
|
|
15
15
|
initialized = false;
|
|
16
16
|
intervals = {};
|
|
17
17
|
log = serviceLocator.getLogger().child({ prefix: 'Events' });
|
|
18
|
-
persistStateIntervalMillis;
|
|
18
|
+
#persistStateIntervalMillis;
|
|
19
19
|
constructor(options) {
|
|
20
|
-
this
|
|
21
|
-
|
|
20
|
+
this.#persistStateIntervalMillis = options.persistStateIntervalMillis;
|
|
21
|
+
// One MIGRATING listener per RequestQueue, and ThrottlingRequestManager opens one per domain.
|
|
22
|
+
this.events.setMaxListeners(150);
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* Initializes the event manager by starting the `persistState` event interval.
|
|
@@ -29,9 +30,9 @@ export class EventManager {
|
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
this.intervals.persistState = betterSetInterval((intervalCallback) => {
|
|
32
|
-
this.emit(
|
|
33
|
+
this.emit(EventType.PERSIST_STATE, { isMigrating: false });
|
|
33
34
|
intervalCallback();
|
|
34
|
-
}, this
|
|
35
|
+
}, this.#persistStateIntervalMillis);
|
|
35
36
|
this.initialized = true;
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
@@ -45,7 +46,7 @@ export class EventManager {
|
|
|
45
46
|
betterClearInterval(this.intervals.persistState);
|
|
46
47
|
this.initialized = false;
|
|
47
48
|
// Emit final PERSIST_STATE event
|
|
48
|
-
this.emit(
|
|
49
|
+
this.emit(EventType.PERSIST_STATE, { isMigrating: false });
|
|
49
50
|
// Wait for PERSIST_STATE to process
|
|
50
51
|
await this.waitForAllListenersToComplete();
|
|
51
52
|
}
|
package/events/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export interface LocalEventManagerOptions extends EventManagerOptions {
|
|
|
5
5
|
systemInfoIntervalMillis: number;
|
|
6
6
|
}
|
|
7
7
|
export declare class LocalEventManager extends EventManager {
|
|
8
|
-
private
|
|
8
|
+
#private;
|
|
9
9
|
constructor(options: LocalEventManagerOptions);
|
|
10
10
|
/**
|
|
11
11
|
* Creates a new `LocalEventManager` based on the provided `Configuration`.
|
|
@@ -29,11 +29,4 @@ export declare class LocalEventManager extends EventManager {
|
|
|
29
29
|
* @internal
|
|
30
30
|
*/
|
|
31
31
|
isContainerizedWrapper(): Promise<boolean>;
|
|
32
|
-
/**
|
|
33
|
-
* Creates a SystemInfo object based on local metrics.
|
|
34
|
-
*/
|
|
35
|
-
private createSystemInfo;
|
|
36
|
-
private createCpuInfo;
|
|
37
|
-
private createMemoryInfo;
|
|
38
|
-
private getMemoryInfo;
|
|
39
32
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { betterClearInterval, betterSetInterval } from '@apify/utilities';
|
|
2
2
|
import { serviceLocator } from '../service_locator.js';
|
|
3
|
-
import { EventManager } from './event_manager.js';
|
|
3
|
+
import { EventManager, EventType } from './event_manager.js';
|
|
4
4
|
export class LocalEventManager extends EventManager {
|
|
5
|
-
systemInfoIntervalMillis;
|
|
5
|
+
#systemInfoIntervalMillis;
|
|
6
6
|
constructor(options) {
|
|
7
7
|
super(options);
|
|
8
|
-
this
|
|
8
|
+
this.#systemInfoIntervalMillis = options.systemInfoIntervalMillis;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Creates a new `LocalEventManager` based on the provided `Configuration`.
|
|
@@ -28,7 +28,7 @@ export class LocalEventManager extends EventManager {
|
|
|
28
28
|
}
|
|
29
29
|
await super.init();
|
|
30
30
|
this.emitSystemInfoEvent = this.emitSystemInfoEvent.bind(this);
|
|
31
|
-
this.intervals.systemInfo = betterSetInterval(this.emitSystemInfoEvent.bind(this), this
|
|
31
|
+
this.intervals.systemInfo = betterSetInterval(this.emitSystemInfoEvent.bind(this), this.#systemInfoIntervalMillis);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* @inheritDoc
|
|
@@ -44,10 +44,10 @@ export class LocalEventManager extends EventManager {
|
|
|
44
44
|
* @internal
|
|
45
45
|
*/
|
|
46
46
|
async emitSystemInfoEvent(intervalCallback) {
|
|
47
|
-
const info = await this
|
|
47
|
+
const info = await this.#createSystemInfo({
|
|
48
48
|
maxUsedCpuRatio: serviceLocator.getConfiguration().maxUsedCpuRatio,
|
|
49
49
|
});
|
|
50
|
-
this.events.emit(
|
|
50
|
+
this.events.emit(EventType.SYSTEM_INFO, info);
|
|
51
51
|
intervalCallback();
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -60,14 +60,14 @@ export class LocalEventManager extends EventManager {
|
|
|
60
60
|
/**
|
|
61
61
|
* Creates a SystemInfo object based on local metrics.
|
|
62
62
|
*/
|
|
63
|
-
async createSystemInfo(options) {
|
|
63
|
+
async #createSystemInfo(options) {
|
|
64
64
|
return {
|
|
65
65
|
createdAt: new Date(),
|
|
66
|
-
...(await this
|
|
67
|
-
...(await this
|
|
66
|
+
...(await this.#createCpuInfo(options)),
|
|
67
|
+
...(await this.#createMemoryInfo()),
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
async createCpuInfo(options) {
|
|
70
|
+
async #createCpuInfo(options) {
|
|
71
71
|
const { getCurrentCpuTicksV2 } = await import('../system-info/cpu-info.js');
|
|
72
72
|
const usedCpuRatio = await getCurrentCpuTicksV2({
|
|
73
73
|
containerized: await this.isContainerizedWrapper(),
|
|
@@ -78,9 +78,9 @@ export class LocalEventManager extends EventManager {
|
|
|
78
78
|
isCpuOverloaded: usedCpuRatio > options.maxUsedCpuRatio,
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
-
async createMemoryInfo() {
|
|
81
|
+
async #createMemoryInfo() {
|
|
82
82
|
try {
|
|
83
|
-
const memInfo = await this
|
|
83
|
+
const memInfo = await this.#getMemoryInfo();
|
|
84
84
|
return {
|
|
85
85
|
memTotalBytes: memInfo.totalBytes,
|
|
86
86
|
memCurrentBytes: memInfo.mainProcessBytes + memInfo.childProcessesBytes,
|
|
@@ -91,7 +91,7 @@ export class LocalEventManager extends EventManager {
|
|
|
91
91
|
return {};
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
async getMemoryInfo() {
|
|
94
|
+
async #getMemoryInfo() {
|
|
95
95
|
const { getMemoryInfo } = await import('../system-info/memory-info.js');
|
|
96
96
|
return getMemoryInfo({
|
|
97
97
|
containerized: await this.isContainerizedWrapper(),
|