@crawlee/core 4.0.0-beta.85 → 4.0.0-beta.86
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/crawlers/crawler_commons.d.ts +54 -1
- package/package.json +5 -5
- package/router.d.ts +38 -14
- package/router.js +3 -2
|
@@ -3,13 +3,65 @@ import type { ReadonlyDeep, SetRequired } from 'type-fest';
|
|
|
3
3
|
import type { Configuration } from '../configuration.js';
|
|
4
4
|
import type { EnqueueLinksOptions } from '../enqueue_links/enqueue_links.js';
|
|
5
5
|
import type { CrawleeLogger } from '../log.js';
|
|
6
|
-
import type { Request, Source } from '../request.js';
|
|
6
|
+
import type { Request, RequestOptions, Source } from '../request.js';
|
|
7
7
|
import type { Dataset } from '../storages/dataset.js';
|
|
8
8
|
import { KeyValueStore, type RecordOptions } from '../storages/key_value_store.js';
|
|
9
9
|
import type { RequestQueueOperationOptions } from '../storages/request_queue.js';
|
|
10
10
|
import type { StorageIdentifier } from '../storages/storage_instance_manager.js';
|
|
11
11
|
/** @internal */
|
|
12
12
|
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
13
|
+
/**
|
|
14
|
+
* A request input (URL string, request-options object, or {@link Request}) whose `userData` is typed
|
|
15
|
+
* according to its `label`, based on a router's route map.
|
|
16
|
+
*
|
|
17
|
+
* When the route map is open (the default `Record<string, ...>`), this is just the regular loose
|
|
18
|
+
* {@link Source} input. When the map declares concrete labels, providing a `label` requires the matching
|
|
19
|
+
* `userData` shape and rejects labels not present in the map; unlabeled requests keep loose `userData`.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export type LabeledSource<Routes extends Record<keyof Routes, Dictionary>> = string extends keyof Routes ? string | Source : string | Request | ({
|
|
23
|
+
requestsFromUrl?: string;
|
|
24
|
+
regex?: RegExp;
|
|
25
|
+
} & ({
|
|
26
|
+
[Label in keyof Routes & string]: Omit<Partial<RequestOptions<Routes[Label]>>, 'label'> & {
|
|
27
|
+
label: Label;
|
|
28
|
+
};
|
|
29
|
+
}[keyof Routes & string] | (Omit<Partial<RequestOptions>, 'label'> & {
|
|
30
|
+
label?: undefined;
|
|
31
|
+
})));
|
|
32
|
+
/**
|
|
33
|
+
* The iterable/array of {@link LabeledSource} inputs accepted by the label-aware `addRequests`/`run`
|
|
34
|
+
* methods of a crawler bound to a typed router.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export type TypedRequestsLike<Routes extends Record<keyof Routes, Dictionary>> = AsyncIterable<LabeledSource<Routes>> | Iterable<LabeledSource<Routes>> | LabeledSource<Routes>[];
|
|
38
|
+
/**
|
|
39
|
+
* The label-aware `addRequests` method signature exposed on a request handler's context when the crawler is
|
|
40
|
+
* bound to a typed router. Mirrors {@link RestrictedCrawlingContext.addRequests} with typed sources.
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export type TypedContextAddRequests<Routes extends Record<keyof Routes, Dictionary>> = (requestsLike: ReadonlyDeep<LabeledSource<Routes>[]>, options?: ReadonlyDeep<RequestQueueOperationOptions>) => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* An `enqueueLinks`-options object with its `label`/`userData` retyped according to a router's route map: a
|
|
46
|
+
* declared `label` requires the matching `userData` shape (unknown labels are rejected), while unlabeled
|
|
47
|
+
* calls keep loose `userData`. Returns the options unchanged when the route map is open (the default).
|
|
48
|
+
*/
|
|
49
|
+
type TypedEnqueueLinksOptions<Options, Routes extends Record<keyof Routes, Dictionary>> = string extends keyof Routes ? Options : Omit<Options, 'label' | 'userData'> & ({
|
|
50
|
+
[Label in keyof Routes & string]: {
|
|
51
|
+
label: Label;
|
|
52
|
+
userData?: Routes[Label];
|
|
53
|
+
};
|
|
54
|
+
}[keyof Routes & string] | {
|
|
55
|
+
label?: undefined;
|
|
56
|
+
userData?: Dictionary;
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Transforms a context's existing `enqueueLinks` method so that the `label`/`userData` in its options follow
|
|
60
|
+
* the router's route map, while preserving everything else about the signature (argument optionality and
|
|
61
|
+
* return type, which differ between crawler types).
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export type TypedContextEnqueueLinks<EnqueueLinks, Routes extends Record<keyof Routes, Dictionary>> = EnqueueLinks extends (options?: infer Options) => infer Result ? (options?: TypedEnqueueLinksOptions<Options, Routes>) => Result : EnqueueLinks extends (options: infer Options) => infer Result ? (options: TypedEnqueueLinksOptions<Options, Routes>) => Result : EnqueueLinks;
|
|
13
65
|
/** @internal */
|
|
14
66
|
export type WithRequired<T, K extends keyof T> = T & {
|
|
15
67
|
[P in K]-?: T[P];
|
|
@@ -187,3 +239,4 @@ export declare class RequestHandlerResult {
|
|
|
187
239
|
private getKeyValueStoreChangedValue;
|
|
188
240
|
private setKeyValueStoreChangedValue;
|
|
189
241
|
}
|
|
242
|
+
export {};
|
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.86",
|
|
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.86",
|
|
57
|
+
"@crawlee/types": "4.0.0-beta.86",
|
|
58
|
+
"@crawlee/utils": "4.0.0-beta.86",
|
|
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": "c2f251426f3ccfcc6efc920e6d492be57beac43b"
|
|
83
83
|
}
|
package/router.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Dictionary } from '@crawlee/types';
|
|
2
2
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
-
import type { CrawlingContext, LoadedRequest, RestrictedCrawlingContext } from './crawlers/crawler_commons.js';
|
|
3
|
+
import type { CrawlingContext, LoadedRequest, RestrictedCrawlingContext, TypedContextAddRequests, TypedContextEnqueueLinks } from './crawlers/crawler_commons.js';
|
|
4
4
|
import type { Request } from './request.js';
|
|
5
5
|
import type { Awaitable } from './typedefs.js';
|
|
6
6
|
/**
|
|
@@ -10,11 +10,18 @@ import type { Awaitable } from './typedefs.js';
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const defaultRoute: unique symbol;
|
|
12
12
|
/**
|
|
13
|
-
* The crawling context received by a route handler, with `request.userData` narrowed to `UserData
|
|
13
|
+
* The crawling context received by a route handler, with `request.userData` narrowed to `UserData`, and
|
|
14
|
+
* `addRequests`/`enqueueLinks` typed according to the router's route map (`Routes`) so that enqueuing a
|
|
15
|
+
* request under a declared label requires the matching `userData` shape.
|
|
14
16
|
*/
|
|
15
|
-
export type RouterHandlerContext<Context, UserData extends Dictionary
|
|
17
|
+
export type RouterHandlerContext<Context, UserData extends Dictionary, Routes extends Record<keyof Routes, Dictionary>> = Omit<Context, 'request' | 'addRequests' | 'enqueueLinks'> & {
|
|
16
18
|
request: LoadedRequest<Request<UserData>>;
|
|
17
|
-
|
|
19
|
+
addRequests: TypedContextAddRequests<Routes>;
|
|
20
|
+
} & (Context extends {
|
|
21
|
+
enqueueLinks: infer EnqueueLinks;
|
|
22
|
+
} ? {
|
|
23
|
+
enqueueLinks: TypedContextEnqueueLinks<EnqueueLinks, Routes>;
|
|
24
|
+
} : {});
|
|
18
25
|
/**
|
|
19
26
|
* A map of request labels to a [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType, …)
|
|
20
27
|
* validating that label's `request.userData`. Pass it to {@link Router.create} or a `createXRouter`
|
|
@@ -24,14 +31,29 @@ export type RouterHandlerContext<Context, UserData extends Dictionary> = Omit<Co
|
|
|
24
31
|
export type RouteSchemas = Record<string, StandardSchemaV1> & {
|
|
25
32
|
[defaultRoute]?: StandardSchemaV1;
|
|
26
33
|
};
|
|
34
|
+
/** Infers a label's `userData` type from its schema, falling back to a plain {@link Dictionary}. */
|
|
35
|
+
type SchemaUserData<Schema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<Schema> extends Dictionary ? StandardSchemaV1.InferOutput<Schema> : Dictionary;
|
|
27
36
|
/**
|
|
28
|
-
* Derives a route map (label → `userData` type) from a {@link RouteSchemas} map by inferring each
|
|
29
|
-
*
|
|
30
|
-
* {@link defaultRoute} schema
|
|
37
|
+
* Derives a route map (label → `userData` type) from a {@link RouteSchemas} map by inferring each schema's
|
|
38
|
+
* output type. Outputs that are not object-shaped fall back to a plain {@link Dictionary}. The
|
|
39
|
+
* {@link defaultRoute} schema is kept under its symbol key so {@link Router.addDefaultHandler} can pick it
|
|
40
|
+
* up; string labels (the ones {@link Router.addHandler} and the crawler-level typing accept) ignore it.
|
|
31
41
|
*/
|
|
32
42
|
export type RoutesFromSchemas<Schemas extends RouteSchemas> = {
|
|
33
|
-
[Label in Extract<keyof Schemas, string>]:
|
|
34
|
-
}
|
|
43
|
+
[Label in Extract<keyof Schemas, string>]: SchemaUserData<Schemas[Label]>;
|
|
44
|
+
} & (Schemas extends {
|
|
45
|
+
[defaultRoute]: StandardSchemaV1;
|
|
46
|
+
} ? {
|
|
47
|
+
[defaultRoute]: SchemaUserData<Schemas[typeof defaultRoute]>;
|
|
48
|
+
} : {});
|
|
49
|
+
/**
|
|
50
|
+
* The `userData` type of the default route: inferred from the {@link defaultRoute} schema when the route map
|
|
51
|
+
* carries one, otherwise the provided `Fallback`.
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export type DefaultRouteUserData<Routes, Fallback extends Dictionary> = Routes extends {
|
|
55
|
+
[defaultRoute]: infer DefaultUserData extends Dictionary;
|
|
56
|
+
} ? DefaultUserData : Fallback;
|
|
35
57
|
/**
|
|
36
58
|
* Validates `userData` against a {@link RouteSchemas|Standard Schema}, returning the parsed (and coerced)
|
|
37
59
|
* value. Throws a {@link RequestValidationError} when validation fails.
|
|
@@ -173,19 +195,20 @@ export declare class Router<Context extends Omit<RestrictedCrawlingContext, 'enq
|
|
|
173
195
|
* Registers new route handler for given label. When the router declares a route map, the
|
|
174
196
|
* `label` is restricted to the declared labels and `request.userData` is typed accordingly.
|
|
175
197
|
*/
|
|
176
|
-
addHandler<Label extends keyof Routes & string>(label: Label, handler: (ctx: RouterHandlerContext<Context, Routes[Label]>) => Awaitable<void>): void;
|
|
198
|
+
addHandler<Label extends keyof Routes & string>(label: Label, handler: (ctx: RouterHandlerContext<Context, Routes[Label], Routes>) => Awaitable<void>): void;
|
|
177
199
|
/**
|
|
178
200
|
* Registers new route handler for given label, explicitly typing `request.userData` via the
|
|
179
201
|
* `UserData` type argument. Useful when the router has no declared route map (the open default)
|
|
180
202
|
* and you want to type a single handler, or to register a handler under a `symbol` label.
|
|
181
203
|
*/
|
|
182
|
-
addHandler<UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(label: RouterLabel<Routes>, handler: (ctx: RouterHandlerContext<Context, UserData>) => Awaitable<void>): void;
|
|
204
|
+
addHandler<UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(label: RouterLabel<Routes>, handler: (ctx: RouterHandlerContext<Context, UserData, Routes>) => Awaitable<void>): void;
|
|
183
205
|
/**
|
|
184
206
|
* Registers default route handler. As a fallback it can receive any request (including labels not
|
|
185
|
-
* declared in the route map)
|
|
186
|
-
*
|
|
207
|
+
* declared in the route map). When the router was created with a {@link defaultRoute} schema,
|
|
208
|
+
* `request.userData` is typed from it; otherwise it defaults to the context's (loosely typed) `userData`.
|
|
209
|
+
* Pass an explicit `UserData` type argument to narrow it.
|
|
187
210
|
*/
|
|
188
|
-
addDefaultHandler<UserData extends Dictionary = GetUserDataFromRequest<Context['request']
|
|
211
|
+
addDefaultHandler<UserData extends Dictionary = DefaultRouteUserData<Routes, GetUserDataFromRequest<Context['request']>>>(handler: (ctx: RouterHandlerContext<Context, UserData, Routes>) => Awaitable<void>): void;
|
|
189
212
|
/**
|
|
190
213
|
* Returns the {@link RouteSchemas|Standard Schema} registered for a label, if any. Used by the crawler
|
|
191
214
|
* to validate `request.userData` when requests are added.
|
|
@@ -234,3 +257,4 @@ export declare class Router<Context extends Omit<RestrictedCrawlingContext, 'enq
|
|
|
234
257
|
static create<Context extends Omit<RestrictedCrawlingContext, 'enqueueLinks'> = CrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;
|
|
235
258
|
static create<Context extends Omit<RestrictedCrawlingContext, 'enqueueLinks'> = CrawlingContext, const Schemas extends RouteSchemas = RouteSchemas>(schemas: Schemas): RouterHandler<Context, RoutesFromSchemas<Schemas>>;
|
|
236
259
|
}
|
|
260
|
+
export {};
|
package/router.js
CHANGED
|
@@ -155,8 +155,9 @@ export class Router {
|
|
|
155
155
|
}
|
|
156
156
|
/**
|
|
157
157
|
* Registers default route handler. As a fallback it can receive any request (including labels not
|
|
158
|
-
* declared in the route map)
|
|
159
|
-
*
|
|
158
|
+
* declared in the route map). When the router was created with a {@link defaultRoute} schema,
|
|
159
|
+
* `request.userData` is typed from it; otherwise it defaults to the context's (loosely typed) `userData`.
|
|
160
|
+
* Pass an explicit `UserData` type argument to narrow it.
|
|
160
161
|
*/
|
|
161
162
|
addDefaultHandler(handler) {
|
|
162
163
|
this.validate(defaultRoute);
|