@crawlee/core 4.0.0-beta.91 → 4.0.0-beta.93
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/autoscaling/autoscaled_pool.d.ts +10 -10
- package/autoscaling/autoscaled_pool.js +4 -3
- package/autoscaling/load_signal.js +1 -1
- 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/memory-storage/utils.d.ts +1 -2
- package/memory-storage/utils.js +1 -2
- package/package.json +5 -5
- package/storages/key_value_store.js +1 -1
- package/storages/key_value_store_codec.js +1 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { ConcurrencyConsumer, IConcurrencySystem } from './concurrency_system.js';
|
|
2
2
|
import type { CrawleeLogger } from '../log.js';
|
|
3
3
|
/**
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
* `runTaskFunction`.
|
|
4
|
+
* The two predicates that steer a task loop: *is there work ready?* and *are we done?* These are the parts of the loop
|
|
5
|
+
* a caller legitimately overrides, as opposed to the task itself (`runTaskFunction`), which the loop's driver owns.
|
|
7
6
|
*/
|
|
8
|
-
export interface
|
|
7
|
+
export interface TaskLoopPredicates {
|
|
9
8
|
/**
|
|
10
9
|
* A function that indicates whether `runTaskFunction` should be called.
|
|
11
10
|
* This function is called every time there is free capacity for a new task and it should
|
|
@@ -15,14 +14,14 @@ export interface AutoscaledPoolPredicateOptions {
|
|
|
15
14
|
isTaskReadyFunction?: () => Promise<boolean>;
|
|
16
15
|
/**
|
|
17
16
|
* A function that is called only when there are no tasks to be processed.
|
|
18
|
-
* If it resolves to `true` then the
|
|
17
|
+
* If it resolves to `true` then the run finishes. Being called only
|
|
19
18
|
* when there are no tasks being processed means that as long as `isTaskReadyFunction()`
|
|
20
19
|
* keeps resolving to `true`, `isFinishedFunction()` will never be called.
|
|
21
|
-
* To abort a run, use the {@link AutoscaledPool.abort} method.
|
|
22
20
|
*/
|
|
23
21
|
isFinishedFunction?: () => Promise<boolean>;
|
|
24
22
|
}
|
|
25
|
-
|
|
23
|
+
/** @internal */
|
|
24
|
+
export interface AutoscaledPoolOptions extends TaskLoopPredicates {
|
|
26
25
|
/**
|
|
27
26
|
* The governor that decides whether there is free compute for one more task. Typically a
|
|
28
27
|
* {@link ConcurrencySystem}, but any {@link IConcurrencySystem} works. Share a single instance across
|
|
@@ -62,8 +61,8 @@ export interface AutoscaledPoolOptions extends AutoscaledPoolPredicateOptions {
|
|
|
62
61
|
*
|
|
63
62
|
* Before running the pool, you need to implement the following three functions:
|
|
64
63
|
* {@link AutoscaledPoolOptions.runTaskFunction|`runTaskFunction`},
|
|
65
|
-
* {@link
|
|
66
|
-
* {@link
|
|
64
|
+
* {@link TaskLoopPredicates.isTaskReadyFunction|`isTaskReadyFunction`} and
|
|
65
|
+
* {@link TaskLoopPredicates.isFinishedFunction|`isFinishedFunction`}.
|
|
67
66
|
*
|
|
68
67
|
* The auto-scaled pool is started by calling the {@link AutoscaledPool.run} function.
|
|
69
68
|
* The pool periodically queries `isTaskReadyFunction` for more tasks, managing optimal concurrency, until the function
|
|
@@ -104,7 +103,8 @@ export interface AutoscaledPoolOptions extends AutoscaledPoolPredicateOptions {
|
|
|
104
103
|
* await concurrencySystem.stop();
|
|
105
104
|
* }
|
|
106
105
|
* ```
|
|
107
|
-
*
|
|
106
|
+
*
|
|
107
|
+
* @internal
|
|
108
108
|
*/
|
|
109
109
|
export declare class AutoscaledPool {
|
|
110
110
|
private readonly log;
|
|
@@ -10,8 +10,8 @@ import { serviceLocator } from '../service_locator.js';
|
|
|
10
10
|
*
|
|
11
11
|
* Before running the pool, you need to implement the following three functions:
|
|
12
12
|
* {@link AutoscaledPoolOptions.runTaskFunction|`runTaskFunction`},
|
|
13
|
-
* {@link
|
|
14
|
-
* {@link
|
|
13
|
+
* {@link TaskLoopPredicates.isTaskReadyFunction|`isTaskReadyFunction`} and
|
|
14
|
+
* {@link TaskLoopPredicates.isFinishedFunction|`isFinishedFunction`}.
|
|
15
15
|
*
|
|
16
16
|
* The auto-scaled pool is started by calling the {@link AutoscaledPool.run} function.
|
|
17
17
|
* The pool periodically queries `isTaskReadyFunction` for more tasks, managing optimal concurrency, until the function
|
|
@@ -52,7 +52,8 @@ import { serviceLocator } from '../service_locator.js';
|
|
|
52
52
|
* await concurrencySystem.stop();
|
|
53
53
|
* }
|
|
54
54
|
* ```
|
|
55
|
-
*
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
56
57
|
*/
|
|
57
58
|
export class AutoscaledPool {
|
|
58
59
|
log;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { weightedAvg } from '
|
|
1
|
+
import { weightedAvg } from './weighted_avg.js';
|
|
2
2
|
/**
|
|
3
3
|
* A time-pruning, time-windowed store for `LoadSnapshot` values. All four built-in signals compose with one of these,
|
|
4
4
|
* and so can yours — it is the only part of their machinery worth reusing.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes a weighted average of an array of numbers, complemented by an array of weights.
|
|
3
|
+
* @ignore
|
|
4
|
+
*/
|
|
5
|
+
export function weightedAvg(arrValues, arrWeights) {
|
|
6
|
+
const result = arrValues
|
|
7
|
+
.map((value, i) => {
|
|
8
|
+
const weight = arrWeights[i];
|
|
9
|
+
const sum = value * weight;
|
|
10
|
+
return [sum, weight];
|
|
11
|
+
})
|
|
12
|
+
.reduce((p, c) => [p[0] + c[0], p[1] + c[1]], [0, 0]);
|
|
13
|
+
return result[0] / result[1];
|
|
14
|
+
}
|
package/byte_utils.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the given value is a Node.js Stream or a Web API ReadableStream.
|
|
3
|
+
* @ignore
|
|
4
|
+
*/
|
|
5
|
+
export declare function isStream(value: unknown): value is NodeJS.ReadableStream | ReadableStream;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if the given value is a Node.js Buffer, ArrayBuffer, or TypedArray.
|
|
8
|
+
* @ignore
|
|
9
|
+
*/
|
|
10
|
+
export declare function isBuffer(value: unknown): value is Buffer | ArrayBuffer | ArrayBufferView;
|
|
11
|
+
/**
|
|
12
|
+
* Converts a byte-like value (Buffer, ArrayBuffer, or any typed-array / DataView) into a Buffer over
|
|
13
|
+
* the exact same bytes, honoring `byteOffset` / `byteLength` for views. Existing Buffers are returned
|
|
14
|
+
* as-is. Used by storage backends, which persist raw bytes regardless of the input's concrete shape.
|
|
15
|
+
* @ignore
|
|
16
|
+
*/
|
|
17
|
+
export declare function toBuffer(value: Buffer | ArrayBuffer | ArrayBufferView): Buffer;
|
package/byte_utils.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the given value is a Node.js Stream or a Web API ReadableStream.
|
|
3
|
+
* @ignore
|
|
4
|
+
*/
|
|
5
|
+
export function isStream(value) {
|
|
6
|
+
if (typeof value !== 'object' || value === null) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
// A Node.js Readable is both pipeable and async-iterable; a Web ReadableStream exposes pipeTo.
|
|
10
|
+
// Requiring async-iterability for the `pipe` branch rejects plain `{ pipe }` ducks that would
|
|
11
|
+
// otherwise blow up later in the storage backends' drain loop with a cryptic TypeError.
|
|
12
|
+
const isNodeStream = typeof value.pipe === 'function' && typeof value[Symbol.asyncIterator] === 'function';
|
|
13
|
+
const isWebStream = typeof value.pipeTo === 'function';
|
|
14
|
+
return isNodeStream || isWebStream;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Checks if the given value is a Node.js Buffer, ArrayBuffer, or TypedArray.
|
|
18
|
+
* @ignore
|
|
19
|
+
*/
|
|
20
|
+
export function isBuffer(value) {
|
|
21
|
+
return (value != null &&
|
|
22
|
+
typeof value === 'object' &&
|
|
23
|
+
(Buffer.isBuffer(value) ||
|
|
24
|
+
value instanceof ArrayBuffer ||
|
|
25
|
+
ArrayBuffer.isView(value) ||
|
|
26
|
+
value.constructor?.name === 'Buffer'));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts a byte-like value (Buffer, ArrayBuffer, or any typed-array / DataView) into a Buffer over
|
|
30
|
+
* the exact same bytes, honoring `byteOffset` / `byteLength` for views. Existing Buffers are returned
|
|
31
|
+
* as-is. Used by storage backends, which persist raw bytes regardless of the input's concrete shape.
|
|
32
|
+
* @ignore
|
|
33
|
+
*/
|
|
34
|
+
export function toBuffer(value) {
|
|
35
|
+
if (Buffer.isBuffer(value)) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
if (value instanceof ArrayBuffer) {
|
|
39
|
+
return Buffer.from(value);
|
|
40
|
+
}
|
|
41
|
+
return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
42
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isBuffer, isStream, toBuffer } from '@crawlee/utils';
|
|
2
1
|
/**
|
|
3
2
|
* Resolves `segment` against `baseDirectory` and ensures the result stays within `baseDirectory`.
|
|
4
3
|
* Storage names and record keys are used as filesystem path components, so a value containing `..`
|
|
@@ -14,4 +13,4 @@ export declare function purgeNullsFromObject<T>(object: T): T;
|
|
|
14
13
|
* Creates a standard request ID (same as Platform).
|
|
15
14
|
*/
|
|
16
15
|
export declare function uniqueKeyToRequestId(uniqueKey: string): string;
|
|
17
|
-
export { isBuffer, isStream, toBuffer };
|
|
16
|
+
export { isBuffer, isStream, toBuffer } from '../byte_utils.js';
|
package/memory-storage/utils.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { resolve, sep } from 'node:path';
|
|
3
|
-
import { isBuffer, isStream, toBuffer } from '@crawlee/utils';
|
|
4
3
|
import { REQUEST_ID_LENGTH } from './consts.js';
|
|
5
4
|
/**
|
|
6
5
|
* Resolves `segment` against `baseDirectory` and ensures the result stays within `baseDirectory`.
|
|
@@ -39,4 +38,4 @@ export function uniqueKeyToRequestId(uniqueKey) {
|
|
|
39
38
|
.replace(/(\+|\/|=)/g, '');
|
|
40
39
|
return str.length > REQUEST_ID_LENGTH ? str.slice(0, REQUEST_ID_LENGTH) : str;
|
|
41
40
|
}
|
|
42
|
-
export { isBuffer, isStream, toBuffer };
|
|
41
|
+
export { isBuffer, isStream, toBuffer } from '../byte_utils.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/core",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.93",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"@apify/pseudo_url": "^2.0.59",
|
|
54
54
|
"@apify/timeout": "^0.3.2",
|
|
55
55
|
"@apify/utilities": "^2.15.5",
|
|
56
|
-
"@crawlee/fs-storage": "4.0.0-beta.
|
|
57
|
-
"@crawlee/types": "4.0.0-beta.
|
|
58
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
56
|
+
"@crawlee/fs-storage": "4.0.0-beta.93",
|
|
57
|
+
"@crawlee/types": "4.0.0-beta.93",
|
|
58
|
+
"@crawlee/utils": "4.0.0-beta.93",
|
|
59
59
|
"@sapphire/async-queue": "^1.5.5",
|
|
60
60
|
"@sapphire/shapeshift": "^4.0.0",
|
|
61
61
|
"@vladfrangu/async_event_emitter": "^2.4.6",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "b9d21e80d94d01e21d4e1c19191610d0157dd172"
|
|
83
83
|
}
|
|
@@ -7,7 +7,7 @@ import { parseValue, serializeValue } from './key_value_store_codec.js';
|
|
|
7
7
|
import { StorageStatsTracker } from './storage_stats.js';
|
|
8
8
|
import { resolveStorageIdentifier } from './storage_instance_manager.js';
|
|
9
9
|
import { createDualIterable, purgeDefaultStorages } from './utils.js';
|
|
10
|
-
import { isBuffer, isStream } from '
|
|
10
|
+
import { isBuffer, isStream } from '../byte_utils.js';
|
|
11
11
|
/** @internal */
|
|
12
12
|
const KVS_KEYS_DEFAULT_LIMIT = 1000;
|
|
13
13
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import contentTypeParser from 'content-type';
|
|
2
|
-
import { isBuffer, isStream } from '@crawlee/utils';
|
|
3
2
|
import JSON5 from 'json5';
|
|
4
3
|
import { jsonStringifyExtended } from '@apify/utilities';
|
|
4
|
+
import { isBuffer, isStream } from '../byte_utils.js';
|
|
5
5
|
const CONTENT_TYPE_JSON = 'application/json';
|
|
6
6
|
const STRINGIFIABLE_CONTENT_TYPE_RXS = [new RegExp(`^${CONTENT_TYPE_JSON}$`, 'i'), /^application\/.*xml$/i, /^text\//i];
|
|
7
7
|
/**
|